InEnglish
Friday, 01 December 2017
|
Écrit par
Grégory Soutadé

Tux, the Linux mascot

For some projects I have to work inside Linux kernel code and, as a developer, I have my own preferences for coding rules (not stable for variable/function naming in facts...) . Especially, I prefer 4 spaces for indentation, curly brackets at a newline. But, the kernel is full of narcissists dictatorscoders and a strict set of coding rules has been determined some years ago. It can be found in Documentation/CodingStyle. Linux is a big project with thousands of people working on it, so I agree that it requires some code normalization for all contribution. Even if you don't plan to verse your patches into upstream, it's good to follow these rules. Here is some tips to comply with it.

First, as an emacs user I have my own rules in my ~/.emacs configuration file. But, when I work on Linux kernel, I want "linux" rules to be applied. A tip from emacswiki allows to automatically switch when a file with "linux" in its path name is found :

(defun maybe-linux-style ()
  (when (and buffer-file-name
         (string-match "linux" buffer-file-name))
    (c-set-style "Linux")
    (c-set-indentation-style "linux")
    (indent-tabs-mode t)
    ))
(add-hook 'c-mode-hook 'maybe-linux-style)
(add-hook 'before-save-hook 'delete-trailing-whitespace)

Another tip I use is a modified pre-commit hook that will checks my modifications before validate the commit. Edit you .git/hooks/pre-commit with the following lines :

#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments.  The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".

temp_file=`mktemp`
files=`git diff --name-only`
to_diff=""
for file in ${files} ; do
    # Filter .c and .h files
    echo ${file} | grep ".h$" > /dev/null 2>&1
    if [ $? -ne 0 ] ; then
    echo ${file} | grep ".c$" > /dev/null 2>&1
    if [ $? -ne 0 ] ; then
        continue
    fi
    fi
    # Add not deleted file
    if [ -f ${file} ] ; then
    to_diff="${to_diff} ${file}"
    fi
done
git diff --no-color -u --summary ${to_diff} > ${temp_file}
./scripts/checkpatch.pl --no-signoff --min-conf-desc-length=0 --no-summary --mailback ${temp_file}
ret=$?
rm -f ${temp_file}
exit $ret

Don't forget chmod +x .git/hooks/pre-commit

Unfortunately, this hook can't be stored into the central repository and have to be copied each time you clone it (or install a server hook). If you want to bypass it (for some reasons), just commit with "--no-verify" option.

Finally, when you already have a custom codebase ready and commited, you can use some scripts provided by the kernel team to check for coding rules. The first is scripts/Lindent that will indent your file following the kernel coding rules via indent util (needs to be installed). The second is scripts/cleanfile which remove unnecessary whitespaces. The third is scripts/checkpatch.pl -f that will checks the whole file (and not just a patch).

Wednesday, 27 September 2017
|
Écrit par
Grégory Soutadé

For a human, it's pretty simple to divide a number by ten because we used to calculate in ten base everyday. But ... a computer handle numbers in base 2. It doesn't means that it can't compute a division with a number that is not a power of 2, but operations are really faster in this base. Especially if you don't have floating point unit.

At work, I had to re implement the function "printf". To display decimal integers, I use an algorithm like :

while (value)
{
    *cur_ptr = '0' + (value%10);
    value = value/10;
    ...
}

This works fine, but two GCC builtin functions udivdi3 and umoddi3 are called which represent an amount of 3.5kB of code. So, I was looking for a code size optimized implementation on the Internet and didn't found my way.

Finally, I wrote my own. It's a basic one inspired from child learning method :

01. void div10(unsigned value, unsigned* _res, unsigned* _mod)
02. {
03.    unsigned res = value / 8;
04.    unsigned mod = value - (res*10);
05.
06.    while (mod > 10)
07.    {
08.        res -= 1;
09.        mod += 10;
10.    }
11.
12.    *_res = res;
13.    *_mod = mod;
14. }

This algorithm is a basic approach to division. It tries all numbers until it find the good one.

First thing : why I use variables instead of directly write values to pointers ? It's to indicate to GCC that they are temporary values which can be kept into registers and not written every loop into the memory (save instructions and memory accesses).

Line 3 is the begining. We will start at value / 8 which can be easily done by the computer because it is equivalent to a right shift of 3 bits (only one instruction). Note that 8 is the closest power of two to 10 and x/8 is greater than x/10 .

Line 4 is the computation of difference (distance) between my result multiplied by 10 and the current value. For the final result, this difference must be less than 10 (which correspond to the modulo).

Line 6 : while its not the case, we decrement result and increment modulo. Why incrementing modulo ? It's an optimization of the re computation of :

mod = value - (res*10);

If res is decremented, modulo is incremented as value is fixed. So, a simple addition is sufficient here.

There is another big trick in this code : the substract line 4 is done with UNSIGNED values and the result of line 4 is most of the time negative ! Which corresponds to big unsigned value (> 2147483648) that also implies > 10. We have to wait an integer overflow for mod to become positive and when it's done, we get the current modulo value (at least MAXLONGINT+10 = 9) !

If we does opposite operation ((res*10) - value), we have to decrement mod until it becomes less or equals to 0. But, in this case, all operations must be done in signed mode and the final modulo must be inverted at the end (more instructions) :

void div10(unsigned long value, unsigned long* _res, unsigned long* _mod)
{
    unsigned long res = value / 8;
    unsigned long mod = (res*10) - value;

    while (((signed long)mod) > 0)
    {
        res -= 1;
        mod -= 10;
    }

    *_res = res;
    *_mod = (unsigned long)-(signed long)mod;
}

Facts : the unsigned version of my algorithm is 15 instructions while udivdi3 + umoddi3 is 881 instructions. Wonderful !

Beware : this algorithm is slow. For small numbers it's not import because x/8 =~ x/10, but when x becomes bigger, the difference can be huge and requires one decrement, one increment and one test multiplied (x/8 - x/10)/10 times. For 32 bits numbers, it's 10 737 418 loops...

This algorithm can be extended to any divisor by replacing hardcoded divisor with a parameter and a function that finds the nearest and inferior power of 2.

void div(unsigned long value, unsigned long divisor, unsigned long* _res, unsigned long* _mod)
{
    unsigned long res, mod, tmp = divisor, power2 = 0;

    /* Nearest inferior power of 2 */
    while (tmp > 1)
    {
        tmp >>=1;
        power2++;
    }

    res = value >> power2;
    mod = value - (res*divisor);

    while (mod > divisor)
    {
        res -= 1;
        mod += divisor;
    }

    *_res = res;
    *_mod = mod;
}
Friday, 26 May 2017
|
Écrit par
Grégory Soutadé

Update : Finally it seems that the GPU is dead. I installed Debian testing with XFCE UI which is very smooth even n software rendering

The last week I was given an iMac 27" to repair, with Yosemite installed on it. It boots fine but was stuck at about 1/3 of the progress bar. Booting in safe mode works (left shift key pressed at startup), so it's not an hardware issue. After trying a lot of things (booting in verbose mode (command + V), reset SMC/PRAM, reinstalling system in recovery mode (command + R)), I found the solution thanks to this thread.

You have to boot in single user mode (command + S), then type :

# mount - uw /
# system_profiler SPExtensionsDataType > /tmp/a
# less a

Then search for "Not Signed" with "/" comamnd and goto next found iteration with "n" command.

We can see "EPSONUSBPrinter" and "hp_fax_io" are not signed, so delete these extensions and reboot like this :

# cd /System/Library/Extensions
# rm -rf name_of_the_kext.kext
# rm -rf /System/Library/Caches/*
# reboot

Be careful to not delete some other non signed core extensions (JMicronATA...). Select only external peripherals drivers. A blocking module was my first diagnostic, but impossible to know which is responsible until there is no really verbose boot mode (thanks Apple).

Update

There is one way to have access to logs during boot :

  • Go in recovery mode
  • Launch a terminal
  • Type "resetpassword"
  • Reset root password
  • Reboot in safe mode
  • Login as root (other)
  • Enable SSH access
  • Reboot
  • Connect to your mac in SSH (ssh root@XXX)
  • Read the log in /var/log/system.log
Monday, 25 July 2016
|
Écrit par
Grégory Soutadé

Do It Yourself, make your own objects, this is in vogue. Since the first version RaspberryPI, we can see a lot of little boards with GPIO connections that handles basic sensors/connectors. Even if some prefer to use wireless communications to communicate with these little devices, USB is still there !

Today I'll show an example of a basic raw bulk USB communication. We could setup our device with the serial line gadget (/dev/ttyGS0), but if you need performance or you want to handle specific USB feature, it's interesting to use raw transfers. Plus, all of this is done in userspace thanks to GadgetFS.

I waste a lot of time due to a buggy USB driver (dwc2), but, finally, the right code is simple.

1. USB keywords

All technical details about USB can be found within usb.org or linux-usb.org, it's quite heavy. Basically, USB communication use a master/slave schema : host side (mainly a PC) sends requests to device side (device). Device never asks questions, it only replies.

Configuration of USB port can be static (host or device) or dynamic. This is the case for DRD (Dual Role Device) configurations, which was previously called OTG (On The Go : who is the first to talk ?).

On the device, we have endpoints grouped into interfaces. Each endpoint contains a hardware buffer (memory) to deal with requests. An endpoint is setup (hardcoded) to be in or out, meaning, it can do only "in" or "out" operation.

In addition to direction, the type of endpoint is important (it's assigned during endpoint configuration). It can be :

  • control for configuration/control requests
  • bulk for bulk transfers
  • isochronous for periodic transfers with a reserved bandwidth
  • int for transfers by interruption

A special endpoint called ep0 (the first one) is always present. It's an in and out endpoint with control attribute. It allows to read/write configuration of other endpoints.

All these information are described in descriptors. You can look at them with

lsusb -v

The low level command sent to controller is called an URB (USB Request Block).

A picture to sum up :

USB host/device schema

2. Enable and mount GadgetFS

First thing to do is to enable GadgetFS in the kernel you're running (if it's not already the case).

Run make menuconfig [ARCH=XXX] in the kernel build directory. Then, enable

Device Drivers -> USB support -> USB Gadget Support -> USB Gadget Drivers -> Gadget Filesystem

In the same section (or in the section above depending on your controller), select the right Peripheral Controller.

You can now rebuild your Linux kernel.

Once booted, mount GadgetFS (in /dev for example)

mkdir /dev/gadget
mount -t gadgetfs gadgetfs /dev/gadget

3. Device side

There is a reference code that can be found in linux-usb.org which manage everything and can use aio for asynchronous requests management. Mine is simpler, full code link can be found in Conclusion part. I'll explain each parts in details.

Let's start. Do includes. usbtring.c is copied from linux-usb.org (strings sent back to host must be encoded in UTF-16). Most of structures and defines are referenced in ch9.h (which corresponds to chapter 9 of the USB norm) and gadgetfs.h

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>

#include <linux/types.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadgetfs.h>

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <pthread.h>

#include <errno.h>

#include "usbstring.c"

Then, defines

#define FETCH(_var_)                            \
    memcpy(cp, &_var_, _var_.bLength);          \
    cp += _var_.bLength;

#define CONFIG_VALUE 2

// Specific to controller
#define USB_DEV "/dev/gadget/dwc2"
#define USB_EPIN "/dev/gadget/ep1in"
#define USB_EPOUT "/dev/gadget/ep2out"

enum {
    STRINGID_MANUFACTURER = 1,
    STRINGID_PRODUCT,
    STRINGID_SERIAL,
    STRINGID_CONFIG_HS,
    STRINGID_CONFIG_LS,
    STRINGID_INTERFACE,
    STRINGID_MAX
};

Config value is the number of endpoints. After that, we have paths relative to GadgetFS. When mounted, there is only USB_DEV, endpoints appears after the first configuration (ep0). Name of endpoints is dependent of the driver implementation.

Structures and static variables :

struct io_thread_args {
    unsigned stop;
    int fd_in, fd_out;
};

static struct io_thread_args thread_args;

static struct usb_string stringtab [] = {
    { STRINGID_MANUFACTURER, "MyOwnGadget", },
    { STRINGID_PRODUCT,      "Custom gadget", },
    { STRINGID_SERIAL,       "0001", },
    { STRINGID_CONFIG_HS,    "High speed configuration", },
    { STRINGID_CONFIG_LS,    "Low speed configuration", },
    { STRINGID_INTERFACE,    "Custom interface", },
    { STRINGID_MAX, NULL},
};

static struct usb_gadget_strings strings = {
    .language = 0x0409, /* en-us */
    .strings = stringtab,
};

static struct usb_endpoint_descriptor ep_descriptor_in;
static struct usb_endpoint_descriptor ep_descriptor_out;

The main thing here is the description of strings inside stringtag that will be parsed by usbstring functions.

int main()
{
    int fd=-1, ret, err=-1;
    uint32_t send_size;
    struct usb_config_descriptor config;
    struct usb_config_descriptor config_hs;
    struct usb_device_descriptor device_descriptor;
    struct usb_interface_descriptor if_descriptor;
    uint8_t init_config[2048];
    uint8_t* cp;

    fd = open(USB_DEV, O_RDWR|O_SYNC);

    if (fd <= 0)
    {
        printf("Unable to open %s (%m)\n", USB_DEV);
        return 1;
    }

    *(uint32_t*)init_config = 0;
    cp = &init_config[4];

    device_descriptor.bLength = USB_DT_DEVICE_SIZE;
    device_descriptor.bDescriptorType = USB_DT_DEVICE;
    device_descriptor.bDeviceClass = USB_CLASS_COMM;
    device_descriptor.bDeviceSubClass = 0;
    device_descriptor.bDeviceProtocol = 0;
    //device_descriptor.bMaxPacketSize0 = 255; Set by driver
    device_descriptor.idVendor = 0xAA; // My own id
    device_descriptor.idProduct = 0xBB; // My own id
    device_descriptor.bcdDevice = 0x0200; // Version
    // Strings
    device_descriptor.iManufacturer = STRINGID_MANUFACTURER;
    device_descriptor.iProduct = STRINGID_PRODUCT;
    device_descriptor.iSerialNumber = STRINGID_SERIAL;
    device_descriptor.bNumConfigurations = 1; // Only one configuration

    ep_descriptor_in.bLength = USB_DT_ENDPOINT_SIZE;
    ep_descriptor_in.bDescriptorType = USB_DT_ENDPOINT;
    ep_descriptor_in.bEndpointAddress = USB_DIR_IN | 1;
    ep_descriptor_in.bmAttributes = USB_ENDPOINT_XFER_BULK;
    ep_descriptor_in.wMaxPacketSize = 512; // HS size

    ep_descriptor_out.bLength = USB_DT_ENDPOINT_SIZE;
    ep_descriptor_out.bDescriptorType = USB_DT_ENDPOINT;
    ep_descriptor_out.bEndpointAddress = USB_DIR_OUT | 2;
    ep_descriptor_out.bmAttributes = USB_ENDPOINT_XFER_BULK;
    ep_descriptor_out.wMaxPacketSize = 512; // HS size

    if_descriptor.bLength = sizeof(if_descriptor);
    if_descriptor.bDescriptorType = USB_DT_INTERFACE;
    if_descriptor.bInterfaceNumber = 0;
    if_descriptor.bAlternateSetting = 0;
    if_descriptor.bNumEndpoints = 2;
    if_descriptor.bInterfaceClass = USB_CLASS_COMM;
    if_descriptor.bInterfaceSubClass = 0;
    if_descriptor.bInterfaceProtocol = 0;
    if_descriptor.iInterface = STRINGID_INTERFACE;

    config_hs.bLength = sizeof(config_hs);
    config_hs.bDescriptorType = USB_DT_CONFIG;
    config_hs.wTotalLength = config_hs.bLength +
        if_descriptor.bLength + ep_descriptor_in.bLength + ep_descriptor_out.bLength;
    config_hs.bNumInterfaces = 1;
    config_hs.bConfigurationValue = CONFIG_VALUE;
    config_hs.iConfiguration = STRINGID_CONFIG_HS;
    config_hs.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER;
    config_hs.bMaxPower = 1;

    config.bLength = sizeof(config);
    config.bDescriptorType = USB_DT_CONFIG;
    config.wTotalLength = config.bLength +
        if_descriptor.bLength + ep_descriptor_in.bLength + ep_descriptor_out.bLength;
    config.bNumInterfaces = 1;
    config.bConfigurationValue = CONFIG_VALUE;
    config.iConfiguration = STRINGID_CONFIG_LS;
    config.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER;
    config.bMaxPower = 1;

    FETCH(config);
    FETCH(if_descriptor);
    FETCH(ep_descriptor_in);
    FETCH(ep_descriptor_out);

    FETCH(config_hs);
    FETCH(if_descriptor);
    FETCH(ep_descriptor_in);
    FETCH(ep_descriptor_out);

    FETCH(device_descriptor);

    // Configure ep0
    send_size = (uint32_t)cp-(uint32_t)init_config;
    ret = write(fd, init_config, send_size);

    if (ret != send_size)
    {
        printf("Write error %d (%m)\n", ret);
        goto end;
    }

    printf("ep0 configured\n");

    handle_ep0(fd);

end:
    if (fd != -1) close(fd);

    return err;
}

The main function. We build the descriptors and send them to ep0. It's needed to send both low/full speed (USB 1) and high speed (USB 2) configurations. Here, they are quite the same. We have only one interface with two endpoints, one for in, and one for out. Descriptors are sent as a big char array that must starts by an uint32_t tag set to 0. All values are expressed in little endian.

ep0 function :

static void handle_ep0(int fd)
{
    int ret, nevents, i;
    fd_set read_set;
    struct usb_gadgetfs_event events[5];

    while (1)
    {
        FD_ZERO(&read_set);
        FD_SET(fd, &read_set);

        select(fd+1, &read_set, NULL, NULL, NULL);

        ret = read(fd, &events, sizeof(events));

        if (ret < 0)
        {
            printf("Read error %d (%m)\n", ret);
            goto end;        
        }

        nevents = ret / sizeof(events[0]);

        printf("%d event(s)\n", nevents);

        for (i=0; i<nevents; i++)
        {
            switch (events[i].type)
            {
            case GADGETFS_CONNECT:
                printf("EP0 CONNECT\n");
                break;
            case GADGETFS_DISCONNECT:
                printf("EP0 DISCONNECT\n");
                break;
            case GADGETFS_SETUP:
                printf("EP0 SETUP\n");
                handle_setup_request(fd, &events[i].u.setup);
                break;
            case GADGETFS_NOP:
            case GADGETFS_SUSPEND:
                break;
            }
        }
    }

end:
    return;
}

This one receives events and handle them. The most important are setup requests, which are requests that kernel cannot full handle by itself (or notice userspace).

static void handle_setup_request(int fd, struct usb_ctrlrequest* setup)
{
    int status;
    uint8_t buffer[512];
    pthread_t thread;

    printf("Setup request %d\n", setup->bRequest);

    switch (setup->bRequest)
    {
    case USB_REQ_GET_DESCRIPTOR:
        if (setup->bRequestType != USB_DIR_IN)
            goto stall;
        switch (setup->wValue >> 8)
        {
            case USB_DT_STRING:
                printf("Get string id #%d (max length %d)\n", setup->wValue & 0xff,
                    setup->wLength);
                status = usb_gadget_get_string (&strings, setup->wValue & 0xff, buffer);
                // Error 
                if (status < 0)
                {
                    printf("String not found !!\n");
                    break;
                }
                else
                {
                    printf("Found %d bytes\n", status);
                }
                write (fd, buffer, status);
                return;
        default:
            printf("Cannot return descriptor %d\n", (setup->wValue >> 8));
        }
        break;
    case USB_REQ_SET_CONFIGURATION:
        if (setup->bRequestType != USB_DIR_OUT)
        {
            printf("Bad dir\n");
            goto stall;
        }
        switch (setup->wValue) {
        case CONFIG_VALUE:
            printf("Set config value\n");
            if (!thread_args.stop)
            {
                thread_args.stop = 1;
                usleep(200000); // Wait for termination
            }
            if (thread_args.fd_in <= 0)
            {
                status = init_ep (&thread_args.fd_in, &thread_args.fd_out);
            }
            else
                status = 0;
            if (!status)
            {
                thread_args.stop = 0;
                pthread_create(&thread, NULL, io_thread, &thread_args);
            }
            break;
        case 0:
            printf("Disable threads\n");
            thread_args.stop = 1;
            break;
        default:
            printf("Unhandled configuration value %d\n", setup->wValue);
            break;
        }        
        // Just ACK
        status = read (fd, &status, 0);
        return;
    case USB_REQ_GET_INTERFACE:
        printf("GET_INTERFACE\n");
        buffer[0] = 0;
        write (fd, buffer, 1);
        return;
    case USB_REQ_SET_INTERFACE:
        printf("SET_INTERFACE\n");
        ioctl (thread_args.fd_in, GADGETFS_CLEAR_HALT);
        ioctl (thread_args.fd_out, GADGETFS_CLEAR_HALT);
        // ACK
        status = read (fd, &status, 0);
        return;
    }

stall:
    printf("Stalled\n");
    // Error
    if (setup->bRequestType & USB_DIR_IN)
        read (fd, &status, 0);
    else
        write (fd, &status, 0);
}

A bad response within this function can stall the endpoint. Two principle functions are to send back strings (not managed by driver) and starts/stop io_thread().

The init_ep() function is pretty simple. It justs sends endpoint descriptors (in low/full and high speed configuration). Like ep0, it must starts with an uint32_t tag of value 1 :

static int init_ep(int* fd_in, int* fd_out)
{
    uint8_t init_config[2048];
    uint8_t* cp;
    int ret = -1;
    uint32_t send_size;

    // Configure ep1 (low/full speed + high speed)
    *fd_in = open(USB_EPIN, O_RDWR);

    if (*fd_in <= 0)
    {
        printf("Unable to open %s (%m)\n", USB_EPIN);
        goto end;
    }

    *(uint32_t*)init_config = 1;
    cp = &init_config[4];

    FETCH(ep_descriptor_in);
    FETCH(ep_descriptor_in);

    send_size = (uint32_t)cp-(uint32_t)init_config;
    ret = write(*fd_in, init_config, send_size);

    if (ret != send_size)
    {
        printf("Write error %d (%m)\n", ret);
        goto end;
    }

    printf("ep1 configured\n");

    // Configure ep2 (low/full speed + high speed)
    *fd_out = open(USB_EPOUT, O_RDWR);

    if (*fd_out <= 0)
    {
        printf("Unable to open %s (%m)\n", USB_EPOUT);
        goto end;
    }

    *(uint32_t*)init_config = 1;
    cp = &init_config[4];

    FETCH(ep_descriptor_out);
    FETCH(ep_descriptor_out);

    send_size = (uint32_t)cp-(uint32_t)init_config;
    ret = write(*fd_out, init_config, send_size);

    if (ret != send_size)
    {
        printf("Write error %d (%m)\n", ret);
        goto end;
    }

    printf("ep2 configured\n");

    ret = 0;

end:
    return ret;
}

Finally, the io_thread() that responds to host requests. Here, I use select, but it seems not to be handled by driver, I/Os are just blocking, but it could be necessary if we want to stop thread.

/*
 * Respond to host requests
 */
static void* io_thread(void* arg)
{
    struct io_thread_args* thread_args = (struct io_thread_args*)arg;
    fd_set read_set, write_set;
    struct timeval timeout;
    int ret, max_read_fd, max_write_fd;
    char buffer[512];

    max_read_fd = max_write_fd = 0;

    if (thread_args->fd_in > max_write_fd) max_write_fd = thread_args->fd_in;
    if (thread_args->fd_out > max_read_fd) max_read_fd  = thread_args->fd_out;

    while (!thread_args->stop)
    {
        FD_ZERO(&read_set);
        FD_SET(thread_args->fd_out, &read_set);
        timeout.tv_sec = 0;
        timeout.tv_usec = 10000; // 10ms

        memset(buffer, 0, sizeof(buffer));
        ret = select(max_read_fd+1, &read_set, NULL, NULL, &timeout);

        // Timeout
        if (ret == 0)
            continue;

        // Error
        if (ret < 0)
            break;

        ret = read (thread_args->fd_out, buffer, sizeof(buffer));

        if (ret > 0)
            printf("Read %d bytes : %s\n", ret, buffer);
        else
            printf("Read error %d(%m)\n", ret);

        FD_ZERO(&write_set);
        FD_SET(thread_args->fd_in, &write_set);

        memset(buffer, 0, sizeof(buffer));
        ret = select(max_write_fd+1, NULL, &write_set, NULL, NULL);

        // Error
        if (ret < 0)
            break;

        strcpy(buffer, "My name is USBond !");

        ret = write (thread_args->fd_in, buffer, strlen(buffer)+1);

        printf("Write status %d (%m)\n", ret);
    }

    close (thread_args->fd_in);
    close (thread_args->fd_out);

    thread_args->fd_in = -1;
    thread_args->fd_out = -1;

    return NULL;
}

4. host side

Host part is very easy to implement. This part can be handled by libusb for a more complete and generic code.

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <linux/usbdevice_fs.h>
#include <linux/usb/ch9.h>

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>

#define USB_DEV "/proc/bus/usb/001/002"

int main()
{
    int fd, ret, err=-1;
    struct usbdevfs_connectinfo connectinfo;
    struct usbdevfs_bulktransfer transfert;
    uint32_t val;
    char buffer[512];

    printf("Build %s @ %s\n", __DATE__, __TIME__);

    fd = open(USB_DEV, O_RDWR);

    if (fd <= 0)
    {
        printf("Unable to open %s (%m)\n", USB_DEV);
        return 1;
    }

    printf("Device opened\n");

    // Optional get information
    ret = ioctl(fd, USBDEVFS_CONNECTINFO, &connectinfo);
    if (ret)
    {
        printf("USBDEVFS_CONNECTINFO error %d (%m)\n", ret);
        goto end;
    }

    printf("devnum %d, slow %d\n",
           connectinfo.devnum, connectinfo.slow);

    // Claim interface 0
    val = 0;
    ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &val);
    if (ret)
    {
        printf("USBDEVFS_CLAIMINTERFACE error %d (%m)\n", ret);
        goto end;
    }
    else
        printf("Interface claimed\n");

    // Send data on ep2out
    strcpy(buffer, "What is your name ?");

    transfert.ep = USB_DIR_OUT + 2;
    transfert.len = strlen(buffer)+1;
    transfert.timeout = 200;
    transfert.data = buffer;

    ret = ioctl(fd, USBDEVFS_BULK, &transfert);
    if (ret < 0)
    {
        printf("USBDEVFS_BULK 1 error %d (%m)\n", ret);
        goto end;
    }
    else
        printf("Transfert 1 OK %d\n", ret);

    // Receive data on ep1in
    transfert.ep = USB_DIR_IN + 1;
    transfert.len = sizeof(buffer);
    transfert.timeout = 200;
    transfert.data = buffer;

    ret = ioctl(fd, USBDEVFS_BULK, &transfert);
    if (ret < 0)
    {
        printf("USBDEVFS_BULK 2 error %d (%m)\n", ret);
        goto end;
    }
    else
        printf("Transfert 2 OK %d %s\n", ret, buffer);

    // Release interface 0
    val = 0;
    ret = ioctl(fd, USBDEVFS_RELEASEINTERFACE, &val);
    if (ret)
    {
        printf("USBDEVFS_RELEASEINTERFACE error %d (%m)\n", ret);
        goto end;
    }

    printf("Interface released\n");

    err = 0;

end:
    close(fd);

    return err;
}

To start, we claim an interface. This ioctl fully handled in host side driver (nothing is send to device). After that, a simple send/receive protocol. Finally we release interface. be carreful, USB_DEV path change when the device is disconnected.

5. Conclusion

The full code can be found on my server. This basic example can be extended a lot : isochronous, asynch requests, streams (USB 3). Enjoy !

Monday, 04 July 2016
|
Écrit par
Grégory Soutadé

This was my problem for Dynastie (a static blog generator). I have a main super class Post and a derived class Draft that directly inherit from the first one.

class Post(models.Model):
    title = models.CharField(max_length=255)
    category = models.ForeignKey(Category, blank=True, null=True, on_delete=models.SET_NULL)
    creation_date = models.DateTimeField()
    modification_date = models.DateTimeField()
    author = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
    description = models.TextField(max_length=255, blank=True)
    ...

class Draft(Post):
    pass

A draft is a note that will not be published soon. When it's published, the creation date is reset. Using POO and inheritance, it's quick and easy to model this behavior. Nevertheless, there is one problem. When I do Post.objects.all() I get all Post objects + all Draft objects, which is not what I want !!

The trick to obtain only Post is a mix with Python and Django mechanisms called Managers. Managers are at the top level of QuerySet construction. To solve our problem, we'll override the models.Model attribute objects (which is a models.Manager).

Inside inheritance

To find a solution, we need to know what exactly happens when we do inheritance. The best thing to do, is to inspect the database.

CREATE TABLE "dynastie_post" (
    "id" integer NOT NULL PRIMARY KEY,
    "title" varchar(255) NOT NULL,
    "category_id" integer REFERENCES "dynastie_category" ("id"),
    "creation_date" datetime NOT NULL,
    "modification_date" datetime NOT NULL,
    "author_id" integer REFERENCES "auth_user" ("id"),
    "description" text NOT NULL);

CREATE TABLE "dynastie_draft" (
    "post_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "dynastie_post" ("id")
);

We can see that dynastie_draft has a reference to the dynastie_post table. So, doing Post.objects.all() is like writing "SELECT * from dynastie_post" that includes Post part of drafts.

Solution 1 : Without altering base class

The first solution is to create a Manager that will exclude draft id from the request. It has the advantage to keep base class as is, but it's not efficient (especially if there is a lot of child objects).

class PostOnlyManager(models.Manager):
    def get_queryset(self):
        query_set = super(PostOnlyManager, self).get_queryset()
        drafts = Draft.objects.all().only("id")
        return query_set.exclude(id__in=[draft.id for draft in drafts])

class Post(models.Model):
    objects = PostOnlyManager()

class Draft(Post):
    objects = models.Manager()

With this solution, we do two requests at each access. Plus, it's necessary to know every sub class we want to exclude. We have to keep the BaseManager for all subclasses. You can note the use of only method to limit the query and de serialization to minimum required.

Solution 2 : With altering base class

The solution here is to add a field called type that will be filtered in the query set. It's the recommended one in the Django documentation.

class PostOnlyManager(models.Manager):
    def get_query_set(self):
        return super(PostOnlyManager, self).get_queryset().filter(post_type='P')

class Post(models.Model):
    objects = PostOnlyManager()
    post_type = models.CharField(max_length=1, default='P')

class Draft(Post):
    objects = models.Manager()

@receiver(pre_save, sender=Draft)
def pre_save_draft_signal(sender, **kwargs):
    kwargs['instance'].post_type = 'D'

The problem here is the add of one field which increase database size, but filtering is easier and is done in the initial query. Plus, it's more flexible with many classes. I used a signal to setup post_type value, didn't found a better solution for now.

Conclusion

Depending on your constraints you can use the solution 1 or 2. These solutions can also be extended to a more complex filtering mechanism by dividing your class tree in different families.