Nefunguje ReadFile() pri čítaní z Generic HID USB zariadenia. – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Nefunguje ReadFile() pri čítaní z Generic HID USB zariadenia. – C / C++ – Fórum – Programujte.comNefunguje ReadFile() pri čítaní z Generic HID USB zariadenia. – C / C++ – Fórum – Programujte.com

 

Toto vlákno bylo označeno za vyřešené — příspěvek s řešením.
iridium0
Newbie
6. 6. 2017   #1
-
0
-

Zdravím.

Podarilo sa mi konečne vytvoriť program v assembleri pre PIC16F1454, ktoré sa cez USB hlási v PC ako "zariadenie z rozhraním HID" -> "HID-compilant-device". Stláčaním tlačítka posielam 8 bajtov do PC a táto aplikácia je schopná v okienku "Received" moje čísla zobrazovať. Aplikácia je písaná v jazyku C#, ktorému nerozumiem. Preto som sa pustil do tvorby vlastného programu vo WinApi. Najprv získam HID Guid s využitím funkcie:

HidD_GetHidGuid(&hidGuid);

Potom naplním štruktúru SP_DEVICE_INTERFACE_DATA datami:

SP_DEVICE_INTERFACE_DATA    deviceInfo;
deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);

Potom v cykle plním štruktúru SP_DEVICE_INTERFACE_DETAIL_DATA postupne zo všetkých pripojených zariadení:

SP_DEVICE_INTERFACE_DETAIL_DATA    *deviceDetails = NULL;
deviceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(size);
deviceDetails->cbSize = sizeof(*deviceDetails);
SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo)
SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, deviceDetails, size, &size, NULL);

...kde v položke "deviceDetails->DevicePath" sa postupne nachádza absolútna adresa každého pripojeného USB zariadenia vrátane PID a VID. To svoje PID a VID si vyberiem tak, že najprv naplním štruktúru HIDD_ATTRIBUTES datami:

HIDD_ATTRIBUTES    deviceAttributes;
deviceAttributes.Size = sizeof(deviceAttributes);
HidD_GetAttributes(handle, &deviceAttributes);

...V položkách "deviceAttributes.VendorID" a "deviceAttributes.ProductID" sa nachádzajú čísla PID a VID. (...čísla a tiež DevicePath, si nechávam aj zobrazovať cez printf(), aby som mal spätnú kontrolu...) -To svoje PID a VID dávam do podmienky a vyberiem si iba zariadenie PIC16F1454. Nakoniec získavam jeho handle pomocou:

handle = CreateFile(deviceDetails->DevicePath,
                            GENERIC_READ | GENERIC_WRITE,
                            FILE_SHARE_READ | FILE_SHARE_WRITE,
                            NULL,
                            OPEN_EXISTING,
                            0,
                            NULL);

Handle som si nechal aj preistotu zobraziť. Obyčajné číslo, ktoré sa zobrazí len vtedy, keď mám svoje zariadenie pripojené. Takže mám istotu, že handle získavam. Potom som sa pokúšal v obsluhe správy WM_TIMER nastavených na 10ms čítať data z USB pomocou ReadFile:

DWORD   bytesRead;
BYTE  RXbufer[1000]; (...skúšal som aj TCHAR. Pole je globálne...)
ReadFile(handle, RXbufer, 8, &bytesRead, NULL);

Ale nič sa nenačítava. Žiadne data do RXbufer neprichádzajú. Potom som vyskúšal funkciu:

HidD_GetFeature(handle, RXbufer, 8);

Takisto nič. Ešte som si overil, či dakde nerobím školácku chybu, tak som napísal:
RXbufer[0] = 1;
RXbufer[1] = 2;
.
.
To sa zobrazuje pekne, každých 10ms. Ale z ReadFile() žiadne čísla neprichádzajú. Dokonca návratová hodnota ReadFile je 0. Skúšal som aj WriteFile(). Takisto nič. Vedeli by ste mi prosím poradiť, kde robím chybu? Skúšal som už všetko možné. Hľadal na internete. Ale márne. Robím na tom projekte USB už 3 mesiace takmer v kuse. Postupne sa to učím. Išlo to všetko ako z chlpatej deky. Dobojoval som to až sem a nakoniec nemôžem so zariadením komunikovať cez svoj program.   

Nahlásit jako SPAM
IP: 62.197.243.–
6. 6. 2017   #2
-
0
-

C#  je hodně podobné C++.

Co se týče práce s tvým HID. Zkus u Atmelu nebo nyní Microchipu najít Aplication Notes pro AT89C5131 kde je popsána jak strana MCU tak strana Windows. Jestli si dobře pamatuju, obojí bylo C/C++. Právě způsob jakým Atmel ohnul HID pro tento účel by ti mohl pomoci.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
6. 6. 2017   #3
-
0
-
Nahlásit jako SPAM
IP: 195.178.67.–
gna
~ Anonymní uživatel
1874 příspěvků
6. 6. 2017   #4
-
0
-

Při chybě ReadFile je zjistit kód chyby pomocí GetLastError.

Nahlásit jako SPAM
IP: 213.211.51.–
iridium0
Newbie
7. 6. 2017   #5
-
0
-

#3 hlucheucho
Skúsil som dať 0, ale i tak nefunguje.

Nahlásit jako SPAM
IP: 62.197.243.–
iridium0
Newbie
7. 6. 2017   #6
-
0
-

#4 gna
Kód chyby je 1784.

Na msdn som našiel ku chybe tento popis:

ERROR_INVALID_USER_BUFFER
1784 (0x6F8)
The supplied user buffer is not valid for the requested operation.

...Prečo bufer nie je platný pre požadovanú operáciu?

Pri použití funkcie "HidD_GetFeature(handle, RXbufer, 8);" miesto ReadFile(), píše chybu:
ERROR_CRC
23 (0x17)
Data error (cyclic redundancy check).

Nahlásit jako SPAM
IP: 62.197.243.–
gna
~ Anonymní uživatel
1874 příspěvků
7. 6. 2017   #7
-
0
-

#6 iridium
Buffer je pravděpodobně platný, problém bude v uvedené délce.

Ale jestli tam máš ještě španě CRC, tak nevím, jestli něco načteš.

Nahlásit jako SPAM
IP: 213.211.51.–
iridium0
Newbie
7. 6. 2017   #8
-
0
-

#7 gna
Skúšal som dĺžku meniť. Nepomohlo. Keď som napísal väčšiu dĺžku, ako je uvedená v report deskriptore zariadenia, program spadol. Keď som napísal menšiu, kód chyby bol rovnaký (1784). ...Čiže akési "povedomie" o veľkosto prideleného bufra to má. Rovnako sa to správalo, keď som ponechal v ReadFile() napísanú veľkosť 8, ale v endpoint a report deskriptore v PIC zmenšil počet bajtov na 7. Program spadol.

Čo sa týka CRC, neviem, čo mám robiť. Tento program zachytáva moje čísla z PIC bez problémov. Je to program písaný v C#. Nedokážem ho rozlúštiť. (Skúšal som.)

Nahlásit jako SPAM
IP: 62.197.243.–
7. 6. 2017   #9
-
0
-

Zkoušel jsi větší a menší buffer. Co tam dosazovat hodnotu přečtenou z deskriptoru? Zkusil jsi najít App. Notes od Atmelu, kde HID "ohýbají"?

hu

Nahlásit jako SPAM
IP: 195.178.67.–
7. 6. 2017   #10
-
0
-
Nahlásit jako SPAM
IP: 195.178.67.–
gna
~ Anonymní uživatel
1874 příspěvků
7. 6. 2017   #11
-
0
-

O bufferu to nic neví. Může testovat jestli je [buffer, buffer+velikost) v zapisovatelné paměti. Tam problém asi nebude. Taky to nenačte více, než o kolik sis řekl, takže to nikam jinam nic nezapíše a ani v tom problém nebude (pokud teda nezkoušíš více než těch 1000, co ten buffer teď má).

Ale jinak to "povědomí" má. Přesně zná velikosti reportu a musíš ho načíst celý, jinak to nevrátí nic.

Čtení v timeru je taky super na ladění :)

Jak píše hu, zkus nějakou hotovou knihovnu. A ten C# taky není težký.

Nahlásit jako SPAM
IP: 213.211.51.–
7. 6. 2017   #12
-
0
-

Ještě jedna věc mne napadla: pokud ten ukázkový kód je konzolovka, spustit ho jako proces bez okna s přesměrováním vstupu a výstupu. Hledej CreateProcess function. Tvoje aplikace pak zapisuje odesílaná data do přesměrovaného vstupu a přijatá data čte z přesměrovaného výstupu.

Pokud umíš dobře C++, C# by měl být pro tebe dobře čitelný. Microsoft má k tomu dobrou dokumentaci.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
iridium0
Newbie
7. 6. 2017   #13
-
0
-

#12 hlucheucho

Samozrejme, pôvodne som dosadzoval presnú hodnotu definovanú v deskriptoroch. Z toho som vychádzal. Dosadzovanie iných hodnôt boli len pokusy typu "čo sa stane".

Áno. C++ viem dobre - čiže asi tak na trojku. (Možno s prižmúrenými očami na dvojku.)

...Asi mi nič iné nezostáva, len obuť sa poriadne do C# a preskúmať ten program. Ak by ste mi vedeli s tým pomôcť, bol by som vám veľmi vďačný. V Hid.cs, Kernel32.cs, SetupApi.cs a User32.cs v tom projekte som našiel aj WinApi funkcie. Akú majú však súvislosť s celkovým behom programu je pre mňa zatiaľ neznáme.

Nahlásit jako SPAM
IP: 62.197.243.–
iridium0
Newbie
8. 6. 2017   #14
-
0
-

Našiel som programy v C++ aj so zdrojákmi, ktoré sú tiež schopné čítať tie čísla z PIC. Som zvedavý, kde robím chybu s ReadFile(). Ak sa mi všetko podarí spojazdniť, dám sem obidva zdrojáky - tj PIC program v assemeleri (+schému zapojenia) a PC program WinApi, písaný v DEV C++. Snáď to niekomu padne na úžitok.

Nahlásit jako SPAM
IP: 62.197.243.–
Řešení
iridium0
Newbie
10. 6. 2017   #15
-
0
-
Vyřešeno Nejlepší odpověď

HURÁ podarilo sa DNES!!! -Už som si myslel, že to zabalím. Tak som bol z toho frustrovaný... -Chyba bola v tom, že i keď PIC zariadenie posiela síce 8 bajtov (...tj. počet definovaný v report a endpoint deskriptoroch a potom samozrejme v registroch BD1CNT (IN / OUT)), funkciou ReadFile() treba čítať až 9 bajtov !!! (...to isté platí o funkcii WriteFile()....) Nultý bajt slúži totiž na iný účel. (Ja ho držím na 0x00) -Keď som to predtým skúšal s 9-timi bajtami, program zamrzol. Funkcia totiž čakala dáta, ktoré jej pošlem z PIC. To som ale nikdy neskúsil (stlačiť to tlačítko vtedy). Pretože som videl program zamrznutý - myslel som si, že nemá zmysel nič ďalej skúšať. Avšak stláčaním tlačítka dáta pekne prichádzajú. Program je zamrznutý len keď žiadne dáta z PIC neposielam. -Preto funkciu ReadFile() nie je vhodné volať z obsluhy správy WM_TIMER, ale z procedúry vlákna. To vytvoríme pomocou:

CreateThread(NULL, 0, ThreadProc, NULL, 0, 0);

....ThreadProc je užívateľsky zvolený názov procedúry. Do nej potom napíšeme:

TCHAR   RXbufer[100];
DWORD WINAPI ThreadProc(LPVOID lpParam)
{  OVERLAPPED osRead;
    BOOL  res;
    HANDLE ev = CreateEvent(NULL, FALSE, FALSE, NULL);
    memset(&osRead, 0, sizeof(osRead));
    osRead.Internal = 0x0;
    osRead.InternalHigh = 0x0;
    osRead.Pointer = 0x0;
    osRead.hEvent = ev;
    if(osRead.hEvent==NULL)
     {    CloseHandle(ev);
          return 0;
     }
    
    while(StavPripojeniaUSB)
    {   
        res = ReadFile(handle, RXbufer, 9, &bytesRead, &osRead);                                      
        if (!res)
        {
            if (GetLastError() != ERROR_IO_PENDING)
            {
                CloseHandle(ev);
                break;
            }
        }
                
        res = WaitForSingleObject(ev, INFINITE);    
 
        if (res != WAIT_OBJECT_0)
        {
            CloseHandle(ev);
            CancelIo(handle);
            break;
        }
    }
    CloseHandle(ev); 

   SendMessage(g_hwndDlg, WM_COMMAND, (WPARAM)LOWORD(ID_BUTTON3), 0);
    return 0;
}

Premennú "BOOL StavPripojeniaUSB;" nastavíme do TRUE po úspešnom získaní handle, čo nie je problém:


int usbOpenDevice(HWND hwnd, int vendor, int product)
{
    GUID                                     hidGuid;
    HDEVINFO                            deviceInfoList;
    SP_DEVICE_INTERFACE_DATA                    deviceInfo;
    SP_DEVICE_INTERFACE_DETAIL_DATA     *deviceDetails = NULL;
    DWORD                               size;
    int                                       i, openFlag = 0;
    HIDD_ATTRIBUTES           deviceAttributes;
    BOOL                                vypinac = FALSE;
                
    HidD_GetHidGuid(&hidGuid);
    deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
    deviceInfo.cbSize = sizeof(deviceInfo);

     for(i = 0;; i++)
    {  
        CloseHandle(handle); 
        if(!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo))
            break;  
        SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, NULL, 0, &size, NULL);
        if(deviceDetails != NULL)
             free(deviceDetails);
        deviceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(size);
        deviceDetails->cbSize = sizeof(*deviceDetails);
        SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, deviceDetails, size, &size, NULL);  
        handle = CreateFile(deviceDetails->DevicePath,
                            GENERIC_READ | GENERIC_WRITE,
                            FILE_SHARE_READ | FILE_SHARE_WRITE,
                            NULL,
                            OPEN_EXISTING,
                            FILE_FLAG_OVERLAPPED,
                            NULL);
        deviceAttributes.Size = sizeof(deviceAttributes);
        HidD_GetAttributes(handle, &deviceAttributes);
        if((deviceAttributes.VendorID == vendor) && (deviceAttributes.ProductID == product))
        {
            vypinac = TRUE;
            break;
        }
        CloseHandle(handle);
        handle = NULL;
        vypinac = FALSE;
    }
    SetupDiDestroyDeviceInfoList(deviceInfoList);
    free(deviceDetails);

    return vypinac;
}

.....Potom túto funkciu usbOpenDevice() voláme v obsluhe tlačítka "Pripojiť", ako:
StavPripojeniaUSB = usbOpenDevice(hwndDlg, VendorId, ProductId);

Ja používam VendorId, ProductId takéto:

#define VendorId    0x04D8
#define ProductId   0x01A5

...Program automaticky pozatvára všetky HANDLE buď po náhlom odpojení zariadenia alebo ručne stlačením tlačítka. (..všetko v obsluhe správy WM_COMMAND -> ID_BUTTON3) ...Ku tomu slúži funkcia:

void CloseUSB()
{    
    CloseHandle(ev);
    CancelIo(handle);
    SuspendThread(ghThread);
    CloseHandle(handle); 
    handle = NULL; 
}

...ktorá je v obsluhe ID_BUTTON3.

Nahlásit jako SPAM
IP: 62.197.243.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 11 hostů

Podobná vlákna

Usb-hid — založil lubos

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý