Hallo, ich versuche mit der usb_bulk_read Funktion von libusb Daten auf meinen Rechner von einem USB-Controller zu übertragen. Der Transfer funktioniert zwar, jedoch scheint es so, als ob die Usb_bulk_read funktion nicht wieder schnell genug aufgerufen wird, da Daten (welche kontinulierlich vom Controller versendet werden) zwischen dem mehrmaligen aufrufen verloren gehen.(also ein Neuaufruf immer wenn das Buffer-Array voll ist). Macht man das Array jedoch "unendlich " groß gehen während dem Lesen der 64Byte Blöcke vom Controller keine Daten verloren - an Bandbreite kann es also nicht mangeln. Daher meine Frage: Ist diese Funktion überhaupt geeignet um eine quasi Echtzeitkommunikation zu ermöglichen (der Endpoint sollte alle 128µs voll sein). Falls nicht, gibt es andere freie Bibliotheken? Anbei der Quellcode (Ein Thread holt die Daten, der andere Schreibt sie in ein Datei. //SOURCE CODE #include <time.h> #include <stdio.h> #include <time.h> #include <stdlib.h> #include <windows.h> #include "usb.h" #define AVR_VID 0x03eb #define AVR_PID 0x2022 #define EP_IN 0x81 //in Firmware definiert #define EP_OUT 0x02 //in Firmware definiert #define BUF_SIZE 64*16 #define BUF_IN_SIZE 64*8 FILE *datei; static char wert[BUF_SIZE]; static char *pread=wert; static char *pwrite=wert; static char *start=wert; int byteread=0; int bytewritten=0; int durch1=0; float durch2=0; int w1=0; clock_t clock(); long t1=clock(); long t2=clock(); long t3=clock(); static int count=0; DWORD thread0id=0; DWORD thread1id=1; static HANDLE hThread[2]; CRITICAL_SECTION cs; usb_dev_handle *open_dev(void) { struct usb_bus *bus; struct usb_device *dev; for(bus = usb_get_busses(); bus; bus = bus->next) //alle vorhandenn Busse durchgehen... { for(dev = bus->devices; dev; dev = dev->next) //alle Geräte durchgehen... { if(dev->descriptor.idVendor == AVR_VID //überprüfe aktuelles Gerät unserer VID/PID entspricht && dev->descriptor.idProduct == AVR_PID) { return usb_open(dev); //Gerät öffnen falls erfolgreich } } } return NULL; } DWORD WINAPI readthread(LPVOID lpParam) { int i; usb_dev_handle *dev = NULL; usb_init(); usb_find_busses(); usb_find_devices(); if(!(dev = open_dev())) //überprüfen ob Gerät gefunden wurde {printf(">> AVR USB KEY nicht gefunden\n\n"); system("PAUSE"); return 0; } else {printf(">> AVR USB KEY gefunden\n\n");} if(usb_set_configuration(dev, 1) < 0) //1. Konfiguration auswählen (gibt nur 0 bei erfolg zurück, sonst <0, hier nur eine Konfiguration { printf(">> error: Konfiguration konnte nicht geladen werden\n\n"); usb_close(dev); system("PAUSE"); return 0; } if(usb_claim_interface(dev, 0) < 0) { printf(">> error: Interface 0 anfordern fehlgeschlagen\n\n"); usb_close(dev); system("PAUSE"); return 0; } while(1) { durch1++; int byte_empfangen; char buffer_in[BUF_IN_SIZE]; usb_bulk_read(dev, EP_IN, buffer_in, sizeof(buffer_in),20); if ((byte_empfangen)!= sizeof(buffer_in)) { printf(">> error: bulk read timeout\n Error: returned: %i\n",byte_empfangen); system("PAUSE"); return 0; } */ EnterCriticalSection(&cs); memcpy(pread,buffer_in,BUF_IN_SIZE); LeaveCriticalSection(&cs); free(buffer_in); if ((pread-start) >= BUF_SIZE) { EnterCriticalSection(&cs); pread=start; // Falls Buffer voll -> von Anfang an beschreiben LeaveCriticalSection(&cs); } else { EnterCriticalSection(&cs); pread+=BUF_IN_SIZE; //Lesezeiger verschieben LeaveCriticalSection(&cs); byteread+=BUF_IN_SIZE; } if ( (pread+64)==pwrite ) { printf("Buffer überschrieben! !"); } } return 1; } DWORD WINAPI writethread(LPVOID lpParam) { int i=0; int tmp,tmp2; while(1) { durch2++; if(pread!=pwrite) { if ( (pwrite-wert)>=BUF_SIZE) { EnterCriticalSection(&cs); pwrite=start; LeaveCriticalSection(&cs); } else { //Anschlüsse auf Board verkehrt herum -> Wert drehen tmp=0x00; tmp|=0x80&( (*pwrite)<<7); tmp|=0x40&( (*pwrite)<<5); tmp|=0x20&( (*pwrite)<<3); tmp|=0x10&( (*pwrite)<<1); tmp|=0x08&( (*pwrite)>>1); tmp|=0x04&( (*pwrite)>>3); tmp|=0x02&( (*pwrite)>>5); tmp|=0x01&( (*pwrite)>>7); EnterCriticalSection(&cs); pwrite++; LeaveCriticalSection(&cs); tmp|=(*pwrite<<8); if(i>=64) {i=0;} // fprintf(datei,"%i:\t%i\t%i\n",i,tmp,tmp-tmp2-1); // fprintf(datei,"%i\n",tmp); i++; bytewritten+=2; EnterCriticalSection(&cs); pwrite++; LeaveCriticalSection(&cs); fprintf(datei,"%i",tmp); tmp2=tmp; } } } return 0; } int main(void) { datei=fopen("daten.txt","w+"); if (!InitializeCriticalSectionAndSpinCount(&cs,0x80000400) ) return 0; hThread[0]=CreateThread(NULL,0,readthread,0,0,&thread0id); hThread[1]=CreateThread(NULL,0,writethread,0,0,&thread1id); SetThreadPriority(hThread[0], 31) ; WaitForMultipleObjects(2,hThread,TRUE,2000); CloseHandle(hThread[0]); CloseHandle(hThread[1]); DeleteCriticalSection(&cs); if (fclose(datei)!=0) printf("Fehler fclose()"); return 0; }
USB ist nicht echtzeitfähig, da ist es die LibUSB und alle anderen Treiber natürlich auch nicht. Wieso geht da was verloren? Wo ist denn die Fluss-Steuerung auf der Controllerseite? Die muss doch warten, bis der Puffer wieder gefüllt werden kann. Wir verwenden ja hier den FX2 von Cypress in unseren Designs, hohe Geschwindigkeiten und niedrige Latenzen sind nur mit großem Puffer vor dem USB Controller zu schaffen. Wir kommen auf kontinuierliche 40MB/s, mit 256kByte FIFO auf der Controllerseite und dem Anfordern großer Blöcke. Wenn du immer nur so kleine Stücke anforderst, erreichst du nix, der Kernel ist dann viel zu sehr mit dem Anfragen beschäftigt.
Hi, ich hab mir deinen Code nicht ganz durchgelesen, aber ich weiß was du willst. Es gibt halbdokumentierte Funktionen, die das Lesen übernehemen. es sind die Funktionen:
1 | usb_bulk_setup_async(this->fd_dev, &context0, EP_IN); |
2 | usb_submit_async(context0, this->buf, sizeof(this->buf)); |
1 | #include "allmyincludes_usb.h" |
2 | |
3 | |
4 | struct usb_bus *bus; |
5 | struct usb_device *dev; |
6 | |
7 | |
8 | function open() |
9 | {
|
10 | for(bus = usb_get_busses(); bus; bus = bus->next) |
11 | {
|
12 | for(dev = bus->devices; dev; dev = dev->next) |
13 | {
|
14 | printf("USB device found [%s][%ld]: %s %d\r\n", bus->dirname, bus->location, dev->filename, dev->devnum); |
15 | }
|
16 | }
|
17 | |
18 | printf("Enumeration of Devices done\r\n"); |
19 | |
20 | for(bus = usb_get_busses(); bus; bus = bus->next) |
21 | {
|
22 | for(dev = bus->devices; dev; dev = dev->next) |
23 | {
|
24 | if(dev->descriptor.idVendor == MY_VID && dev->descriptor.idProduct == MY_PID) |
25 | {
|
26 | printf("\r\nDevice found\r\n"); |
27 | return usb_open(dev); |
28 | }
|
29 | }
|
30 | }
|
31 | return NULL; |
32 | }
|
33 | |
34 | int main() |
35 | {
|
36 | |
37 | usb_init(); /* initialize the library */ |
38 | usb_find_busses(); /* find all busses */ |
39 | usb_find_devices(); /* find all connected devices */ |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | if(!(fd_dev = open())) |
46 | {
|
47 | printf("Error: device not found!\r\n"); |
48 | return(false); |
49 | }
|
50 | |
51 | if(usb_set_configuration(fd_dev, 1) < 0) |
52 | {
|
53 | printf("Error: setting config 0 failed\n"); |
54 | printf("Error: %s\r\n", usb_strerror()); |
55 | usb_close(this->fd_dev); |
56 | return(false); |
57 | }
|
58 | |
59 | if(usb_claim_interface(fd_dev, 0) < 0) |
60 | {
|
61 | }
|
62 | |
63 | |
64 | // als thread ausführen
|
65 | |
66 | |
67 | while(this->isrunning) |
68 | {
|
69 | usb_bulk_setup_async(this->fd_dev, &context0, EP_IN); |
70 | usb_submit_async(context0, this->buf, sizeof(this->buf)); |
71 | |
72 | bytesread = 0; |
73 | |
74 | bytesread = usb_reap_async(context0, 500); |
75 | |
76 | if(bytesread < 0) |
77 | {
|
78 | if(bytesread != -116) // nothing read |
79 | {
|
80 | printf("code: %d error:%s\n", bytesread, usb_strerror()); |
81 | }
|
82 | }
|
83 | else
|
84 | {
|
85 | printf("%d bytes read\n\r", bytesread); |
86 | }
|
87 | }
|
88 | }
|
Im Thread kannst du die Daten dann weiterschicken. Habe ich für meine Diplomarbeit verwendet. Wenn dann melde dich. Gruß Benjamin PS.: Der Code ist zusammenkopiert, alle Variablen müssen noch deklariert werden und es kann sein, dass C++ Code drinnen ist!
Hallo, danke für die Antworten. Ich habe nun die undokumentierten Funktionen eingebau... Leider hat sich an dem Problem nichts geändert :(
Naja, ob du nun synchron oder asynchron liest, ändert nix an der Tatsache, dass du auf Controller-Seite eine Fluss-Steuerung benötigst, wenn keine Daten verloren gehen dürfen. Du musst abfragen, ob der Buffer geleert wurde, und kannst erst dann neue Daten schreiben. Wenn du eine konstante Datenrate benötigst, musst du eventuell mal auf isochronen Datentransfer gehen, da wird die Bandbreite garantiert, allerdings gibts keine Wiederholungen, falls wirklich mal was verloren geht. Konstante Datenrate bei BULK geht nur mit riesigen Puffern, denn BULK ist am niedrigsten priorisiert, das findet nur statt, wenn sonst nix auf dem USB los ist. Wir haben Messungen gemacht, und herausgefunden, dass Windows XP auf einem aktuellen Rechner bis zu 30ms lang einfach mal gar nix von USB abholt....diese Zeit musst du durch Puffer überbrücken können.
Wie groß ist dein Puffer auf der Clientseite also dem Slave. Der sollte so groß sein, wie der am Host.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.