Apologies in advance I won't be able to accept an answer here immediately - just thought I'd like to jot this down, while I have the problem...
In brief: I can observe three different buffer sizes, when I initiate a write to an usb-serial port using user-space C code under Linux - and the problem is, I would like to retrieve all these sizes from the user-space C code itself.
Let's say, I have an Arduino Duemillanove, with an FTDI FT232 chip - programmed to read incoming bytes from usb/serial connection from PC, and discard them. When I plug in this device in the system (did this on Ubunty 11.04 Natty), I can observe the following via tail -f /var/log/syslog
:
Mar 21 08:05:05 mypc kernel: [ 679.197982] usbserial: USB Serial Driver core
Mar 21 08:05:05 mypc kernel: [ 679.223954] USB Serial support registered for FTDI USB Serial Device
Mar 21 08:05:05 mypc kernel: [ 679.227354] ftdi_sio 2-2:1.0: FTDI USB Serial Device converter detected
Mar 21 08:05:05 mypc kernel: [ 679.227633] usb 2-2: Detected FT232RL
Mar 21 08:05:05 mypc kernel: [ 679.227644] usb 2-2: Number of endpoints 2
Mar 21 08:05:05 mypc kernel: [ 679.227652] usb 2-2: Endpoint 1 MaxPacketSize 64
Mar 21 08:05:05 mypc kernel: [ 679.227660] usb 2-2: Endpoint 2 MaxPacketSize 64
Mar 21 08:05:05 mypc kernel: [ 679.227667] usb 2-2: Setting MaxPacketSize 64
...
This tells me first that the drivers (kernel modules) usbserial
and ftdi_sio
have been hooked/loaded to handle the device; these create a file (device node) called /dev/ttyUSB0
- essentially a serial port from the OS perspective. It also tells me that there is a MaxPacketSize
of 64 bytes attributed to the device's endpoints. I can get the MaxPacketSize also by querying via lsusb
:
$ lsusb | grep FT
Bus 002 Device 002: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
$ lsusb -t | grep -B1 ft
/: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=uhci_hcd/2p, 12M
|__ Port 2: Dev 2, If 0, Class=vend., Driver=ftdi_sio, 12M
$ sudo lsusb -v -d 0403:6001 | grep 'bEndpointAddress\|wMaxPacketSize\|idVendor\|idProduct'
idVendor 0x0403 Future Technology Devices International, Ltd
idProduct 0x6001 FT232 USB-Serial (UART) IC
bEndpointAddress 0x81 EP 1 IN
wMaxPacketSize 0x0040 1x 64 bytes
bEndpointAddress 0x02 EP 2 OUT
wMaxPacketSize 0x0040 1x 64 bytes
Now, let's say I want to write to the device node /dev/ttyUSB0
using the following C program, testusw.c
:
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
// testusw.c
// build with: gcc -o testusw -Wall -g testusw.c
int main( int argc, char **argv ) {
char *serportdevfile;
int serport_fd;
char writeData[20000*5]; //100000 bytes data
unsigned char snippet[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xFE};
int i;
int bytesWritten;
if( argc != 2 ) {
fprintf(stdout, "Usage:\n");
fprintf(stdout, "%s port baudrate file/string\n", argv[0]);
return 1;
}
//populate write data
for (i=0; i<20000; i++) {
memcpy(&writeData[5*i], &snippet[0], 5);
}
// for strlen, fix (after) last byte to 0
writeData[20000*5] = 0x00;
// show writeData - truncate to 10 bytes (.10):
fprintf(stdout, "//%.10s//\n", writeData);
serportdevfile = argv[1];
serport_fd = open( serportdevfile, O_RDWR | O_NOCTTY | O_NONBLOCK );
if ( serport_fd < 0 ) { perror(serportdevfile); return 1; }
// do a write:
fprintf(stdout, "Writing %d bytes\n", strlen(writeData));
bytesWritten = write( serport_fd, writeData, strlen(writeData) );
fprintf(stdout, " bytes written: %d \n", bytesWritten);
return 0;
}
This program deliberately writes a big chunk of data in one call. To see what is happening, first let's capture USB URB requests via Linux's usbmon
facility - so in one terminal, we run:
$ sudo cat /sys/kernel/debug/usb/usbmon/2u > testusw.2u.mon
... and in another terminal, after compiling and running testusw, we obtain:
$ gcc -o testusw -Wall -g testusw.c
$ ./testusw /dev/ttyUSB0
//ª»ÌÝþª»ÌÝþ//
Writing 100000 bytes
bytes written: 4608
$
(Note that the testusw
call above will likely reset the Arduino). After testusw
, we can go back to the first terminal, and interrupt the cat
process with CTRL+C; we are left with a logfile, testusw.2u.mon
. We can open this logfile with Virtual USB Analyzer:
$ ./vusb-analyzer testusw.2u.mon
... and obtain the following visualization:
Note that there are 2*9 = 18 URB requests shown for "EP2 OUT" that perform the writing, carrying 0x0100 = 256 bytes each; so in total, 18*256 = 4608 bytes were written - as reported by "bytes written" by testusw
above. Also, ignore the data on EP1 IN (that is some junk my Arduino code is sending - which ends with a "Status: -2" error).
Thus, I can observe the following:
4608
bytes are written - effectively acting as a first buffer sizeusbmon
then reports this chunk is sequenced into 18 URB requests of 256
bytes each64
bytes on USB wireIn effect, I have three buffer sizes: 4608
, 256
and 64
bytes; similar to what is mentioned in Serial HOWTO: Serial Port Basics: 4.7 Data Flow Path; Buffers:
application 8k-byte 16-byte 1k-byte tele-
BROWSER ------- MEMORY -------- FIFO --------- MODEM -------- phone
program buffer buffer buffer line
So, my question is: how can these buffer sizes be retrieved from the userspace C code itself - however, only from the device node path /dev/ttyUSB0
as the only input parameter?
I would be OK with running external programs via a system popen
command, and parsing the output. For instance, I could obtain MaxPacketSize via lsusb -v -d 0403:6001 | grep MaxPacketSize
- but that requires vendor/product ID, and I don't know how to obtain that, if only piece of information is the device node path /dev/ttyUSB0
.
Given that /dev/ttyUSB0
is essentially treated as a serial port, I thought querying via stty
would provide something - however, I cannot see anything related to buffer sizes there:
$ stty -a -F /dev/ttyUSB0
speed 115200 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^A; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff
-iuclc -ixany -imaxbel -iutf8
-opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt
-echoctl -echoke
I also know I can use udevadm
to query for data related to the device node path /dev/ttyUSB0
:
$ udevadm info --query=all --name=/dev/ttyUSB0
P: /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/ttyUSB0/tty/ttyUSB0
N: ttyUSB0
S: serial/by-path/pci-0000:00:1d.0-usb-0:2:1.0-port0
S: serial/by-id/usb-FTDI_FT232R_USB_UART_A9007OH3-if00-port0
E: UDEV_LOG=3
E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/ttyUSB0/tty/ttyUSB0
E: MAJOR=188
E: MINOR=0
E: DEVNAME=/dev/ttyUSB0
E: SUBSYSTEM=tty
E: ID_PORT=0
E: ID_PATH=pci-0000:00:1d.0-usb-0:2:1.0
E: ID_VENDOR=FTDI
E: ID_VENDOR_ENC=FTDI
E: ID_VENDOR_ID=0403
E: ID_MODEL=FT232R_USB_UART
E: ID_MODEL_ENC=FT232R\x20USB\x20UART
E: ID_MODEL_ID=6001
E: ID_REVISION=0600
E: ID_SERIAL=FTDI_FT232R_USB_UART_A9007OH3
E: ID_SERIAL_SHORT=A9007OH3
E: ID_TYPE=generic
E: ID_BUS=usb
E: ID_USB_INTERFACES=:ffffff:
E: ID_USB_INTERFACE_NUM=00
E: ID_USB_DRIVER=ftdi_sio
E: ID_IFACE=00
E: ID_VENDOR_FROM_DATABASE=Future Technology Devices International, Ltd
E: ID_MODEL_FROM_DATABASE=FT232 USB-Serial (UART) IC
E: ID_MM_CANDIDATE=1
E: DEVLINKS=/dev/serial/by-path/pci-0000:00:1d.0-usb-0:2:1.0-port0 /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A9007OH3-if00-port0
# the below has huge output, so pipe it to `less`
$ udevadm info --attribute-walk --name=/dev/ttyUSB0 | less
... but again, I cannot see much related to the encountered buffer sizes.
To wrap this up, the question again: can I retrieve the encountered buffer sizes related to the usb-serial write transfer from a user-space C application; and if so - how?
Many thanks in advance for any answers,
Cheers!
Don't see why you'd want to know this. Linux allows you to use the TIOCGSERIAL
ioctl to retrieve a struct serial_struct
which has a xmit_fifo_size
field. Though I'd be surprised if many USB serial driver bother to write something meaningful there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With