Scuse in anticipo Non sarò in grado di accettare una risposta qui immediatamente - ho pensato che mi piacerebbe annotarlo, mentre ho il problema ...Recupero dimensioni buffer/pacchetto/carico utile per trasferimento in scrittura seriale USB in spazio utente Linux C code
In breve: posso osservare tre diverse dimensioni del buffer, quando avvio una scrittura su una porta USB-seriale utilizzando il codice C dello spazio utente sotto Linux - e il problema è che vorrei recuperare tutte queste dimensioni dal codice C dello spazio utente stesso.
Diciamo, ho un Arduino Duemillanove, con un chip FTDI FT232 - programmato per leggere byte in arrivo dalla connessione USB/seriale dal PC, e gettarli. Quando collego il dispositivo nel sistema (fatto questo su Ubunty 11.04 Natty), posso osservare quanto segue 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
...
Questo mi dice prima che i driver (moduli del kernel) usbserial
e ftdi_sio
sono stati agganciati/caricato per gestire il dispositivo; questi creano un file (nodo del dispositivo) chiamato /dev/ttyUSB0
- essenzialmente una porta seriale dal punto di vista del sistema operativo. Mi dice anche che c'è uno MaxPacketSize
di 64 byte attribuito agli endpoint del dispositivo. Posso ottenere il MaxPacketSize anche interrogando 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
Ora, diciamo che voglio scrivere al nodo del dispositivo /dev/ttyUSB0
utilizzando il seguente programma 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;
}
Questo programma scrive deliberatamente una grande porzione di dati in una sola chiamata. Per vedere che cosa sta accadendo, prima cerchiamo di catturare le richieste URB USB tramite impianto di Linux usbmon
- così in un unico terminale, corriamo:
$ sudo cat /sys/kernel/debug/usb/usbmon/2u > testusw.2u.mon
... e in un altro terminale, dopo la compilazione e l'esecuzione testusw, otteniamo:
$ gcc -o testusw -Wall -g testusw.c
$ ./testusw /dev/ttyUSB0
//ª»ÌÝþª»ÌÝþ//
Writing 100000 bytes
bytes written: 4608
$
(Si noti che la chiamata sopra riportata probabilmente ripristinerà Arduino). Dopo il testusw
, possiamo tornare al primo terminale e interrompere il processo cat
con CTRL + C; ci rimane un file di registro, testusw.2u.mon
. Possiamo aprire questo file di log con Virtual USB Analyzer:
$ ./vusb-analyzer testusw.2u.mon
... e avere la seguente visualizzazione:
noti che ci sono 2 richieste * 9 = 18 URB mostrati per "EP2 OUT" che esegue la scrittura, trasportando 0x0100 = 256 byte ciascuno; quindi in totale sono stati scritti 18 * 256 = 4608 byte, come riportato dai "byte scritti" sopra il testusw
. Inoltre, ignora i dati su EP1 IN (che è un po 'di junk che il mio codice Arduino sta inviando - che termina con un errore "Status: -2").
Così, posso osservare quanto segue:
- Dal programma C, avvio la procedura di scrittura di 100000 byte
- Di conseguenza, solo
4608
byte sono scritti - in pratica si comportano come prima dimensione del buffer usbmon
quindi segnala che questo blocco viene sequenziato in 18 richieste URB di256
byte ciascuna- infine, MaxPacketSize mi dice che ogni richiesta URB è (probabilmente) seqenced in (quattro) pacchetti di
64
byte sul filo USB
In effetti, ho tre dimensioni del buffer: 4608
, 256
e 64
byte; simile a quanto riportato nella 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
Quindi, la mia domanda è: come può queste dimensioni di buffer essere recuperate dal codice userspace C stesso - tuttavia, solo dal percorso del nodo dispositivo /dev/ttyUSB0
come unico parametro di input?
Sarei OK con l'esecuzione di programmi esterni tramite un comando di sistema popen
e analizzando l'output. Ad esempio, potrei ottenere MaxPacketSize tramite lsusb -v -d 0403:6001 | grep MaxPacketSize
- ma ciò richiede ID fornitore/prodotto e non so come ottenerlo, se solo una parte dell'informazione è il percorso del nodo dispositivo /dev/ttyUSB0
.
Dato che /dev/ttyUSB0
è essenzialmente trattata come una porta seriale, ho pensato che l'interrogazione tramite stty
fornirebbe qualcosa - tuttavia, non riesco a vedere tutto ciò che riguarda tampone formati lì:
$ 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
so anche che posso usare udevadm
alla query per i dati relativi al percorso del nodo dispositivo /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
... ma ancora, non riesco a vedere molto in rapporto alle dimensioni del buffer incontrati.
Per riaggiustare, la domanda nuovamente: è possibile recuperare le dimensioni del buffer rilevato relative al trasferimento di scrittura seriale USB da un'applicazione C dello spazio utente; e se sì - come?
Molte grazie in anticipo per qualsiasi risposta,
Cheers!
Perché è necessario conoscere le dimensioni del buffer? Qual è il tuo obiettivo? – Hasturkun