Search code examples
c++clinuxlinux-device-driverftdi

opening a usb-serial port using the device VID/PID


In Linux usb-serial converters usually show up as a node in the /dev directory: /dev/ttyUSBx.

To use the serial converter the first step it to open the port, then configure it and so on.

port = open("/dev/ttyUSB0", O_RDWR);

If you want to use a serial device (I2C or SPI), ftdi offers devices (like FT4232 or FT232h) which can be used either as a normal UART port or i2c/spi.

For i2c/spi operation you have to use a separate driver - I use the open source libmpsse. This is a library you have to install so it will work in parallel with the standard FTDI driver since it's build on top of that.

So now, if I want o open a port as UART I use the normal open function (mentioned above). And if I want to connect a i2c/spi device I use the libmpsse open function which opens the port based on VID/PID:

struct mpsse_context *Open(int vid, int pid, enum modes mode, int freq, int endianess, int interface, const char *description, const char *serial)  

Now for the question - can I open the port as UART by using the device vid/pid instead of the path to it's dev mode? It all comes down to ftdi function calls but I can't seem to find an example.

Why I need to do it this way? I don't want to have to know the node path. I should be able to use just the VID/PID and interface number - it's a lot more flexible.

Any help is appreciated!


Solution

  • I eventually found a solution so I'm posting for anyone that might need this.

    You can open the serial port by using one of the ftdi_usb_open_xxx() functions. For me, ftdi_usb_open_desc_indexdid the trick; index is useful in case you have more than one chip of the same kind connected.

    Then you configure the port with ftdi_set_baudrate and ftdi_set_line_property. And read/write with ftdi_read_data()/ftdi_write_data().

    Here's a short example:

        struct ftdi_context ftdic;
    
        // ftdilib initialization 
        if(ftdi_init(&ftdic) == 0)
        {
    
            ftdi_set_interface(&ftdic, IFACE_C);//this is where my serial device is connected
    
    
            if(ftdi_usb_open_desc_index(&ftdic, vid, pid, NULL, NULL, 0) == 0)
            {
                printf("serial port open\n");
    
                if(ftdi_set_baudrate(&ftdic, 9600) < 0)
                {
                    printf("baudrate incorrect\n");
                }
    
    
                if(ftdi_set_line_property(&ftdic, BITS_8, STOP_BIT_1, NONE)<0)
                {
                    printf("line settings incorrect");
                }
    
                for(;;)
                {
                    unsigned char c;
                    ftdi_read_data(&ftdic, &c, 1);                  
                    printf("0x%2x ",c);             
                }               
            }
            else
            {
                printf("could not open serial port \n");
            }
        }
        else
        {
            printf("init failed\n");
        }
    

    This way you don't seem to have to wait for data to be available so you won't have to deal with blocking ports.