Извиняюсь заранее, я не смогу сразу принять ответ здесь - просто подумал, что хочу записать это, пока у меня есть проблема...
Вкратце: я могу наблюдать три разных размера буфера, когда я запускаю запись в USB-последовательный порт с использованием кода пользователя в C под Linux - и проблема в том, что я хотел бы получить все эти размеры от пользователя -пространственный C-код.
Скажем, у меня есть Arduino Duemillanove с чипом FTDI FT232, запрограммированным на считывание входящих байтов из USB/последовательного соединения с ПК и их отбрасывание. Когда я подключаю это устройство в системе (это делалось на Ubunty 11.04 Natty), я могу наблюдать следующее через 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
...
Это сначала говорит мне, что драйверы (модули ядра) usbserial
и ftdi_sio
были подключены/загружены для управления устройством; они создают файл (устройство node), называемый /dev/ttyUSB0
- по существу последовательный порт с точки зрения ОС. Он также говорит мне, что есть MaxPacketSize
из 64 байтов, приписываемых конечным точкам устройства. Я могу получить MaxPacketSize также путем запроса через 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
Теперь скажем, что я хочу записать на устройство node /dev/ttyUSB0
с помощью следующей программы на C, 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;
}
Эта программа намеренно записывает большой фрагмент данных за один вызов. Чтобы увидеть, что происходит, сначала разрешите захват запросов USB URB через Linux usbmon
объект - поэтому в одном терминале мы запускаем:
$ sudo cat /sys/kernel/debug/usb/usbmon/2u > testusw.2u.mon
... и в другом терминале после компиляции и запуска testusw получаем:
$ gcc -o testusw -Wall -g testusw.c
$ ./testusw /dev/ttyUSB0
//ª»ÌÝþª»ÌÝþ//
Writing 100000 bytes
bytes written: 4608
$
(Обратите внимание, что вызов testusw
выше, скорее всего, reset Arduino). После testusw
мы можем вернуться к первому терминалу и прервать процесс cat
с помощью CTRL + C; мы остаемся с logfile, testusw.2u.mon
. Мы можем открыть этот файл журнала с помощью Virtual USB Analyzer:
$ ./vusb-analyzer testusw.2u.mon
... и получить следующую визуализацию:
Обратите внимание, что есть 2 * 9 = 18 запросов URB, показанных для "EP2 OUT", которые выполняют запись, несущую 0x0100 = 256 байт каждый; так что в общей сложности было записано 18 * 256 = 4608 байт - как сообщается "байтами, написанными" на testusw
выше. Кроме того, игнорируйте данные на EP1 IN (это какой-то барахл, который отправляет мой код Arduino, который заканчивается ошибкой "Status: -2" ).
Таким образом, я могу заметить следующее:
- В программе C я начинаю писать 100000 байт
- В результате записываются только
4608
байты - эффективно действуют как первый размер буфера -
usbmon
затем сообщает, что этот фрагмент секвенирован в 18 запросов URB256
байтов каждый - наконец, MaxPacketSize сообщает мне, что каждый запрос URB (возможно) помещен в (четыре) пакеты из
64
байт на проводе USB
Фактически у меня есть три размера буфера: 4608
, 256
и 64
байты; аналогично тому, что упоминается в Serial HOWTO: Основы последовательного порта: 4.7 Путь потока данных; Буферы:
application 8k-byte 16-byte 1k-byte tele-
BROWSER ------- MEMORY -------- FIFO --------- MODEM -------- phone
program buffer buffer buffer line
Итак, мой вопрос: как эти размеры буфера могут извлекаться из самого кода C пользовательского пространства - однако, только с устройства node path /dev/ttyUSB0
в качестве единственного входного параметра?
Мне было бы хорошо работать с внешними программами с помощью команды popen
и анализировать вывод. Например, я могу получить MaxPacketSize через lsusb -v -d 0403:6001 | grep MaxPacketSize
- но для этого требуется идентификатор поставщика/продукта, и я не знаю, как его получить, если только часть информации является устройством node path /dev/ttyUSB0
.
Учитывая, что /dev/ttyUSB0
по существу рассматривается как последовательный порт, я думал, что запрос через stty
предоставит что-то, однако я не вижу ничего, связанного с размерами буфера:
$ 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
Я также знаю, что я могу использовать udevadm
для запроса данных, связанных с устройством 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
... но опять же, я не вижу многого, связанного с размерами найденных буферов.
Чтобы обернуть это, снова задайте вопрос: могу ли я получить найденные размеры буфера, связанные с переносом записи usb-serial из приложения C-пространства пользователя? и если да - как?
Большое спасибо заранее за любые ответы,
Ура!