Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien
Toon posts:

[C++] COM-poort uitlezen met readfile()

Pagina: 1
Acties:

Verwijderd

Topicstarter
Hoi,

Al een tijdje ben ik aan het proberen een programma te schrijven om een simpele string van HEX characters uit te lezen. Daarvoor gebruik ik de volgende functie:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int ReadUart(char *buf, int len){
    BOOL ret;
    unsigned long retlen;
 
    ret = ReadFile (hCom,        // handle of file to read
                buf,        // pointer to buffer that receives data
                len,        // number of bytes to read
                &retlen,    // pointer to number of bytes read
                NULL    // pointer to structure for data
            );

    if(retlen > 0)          // data
        return 1;     
    
    else
               return 0;                    // no data
}


Nu probeer ik de data uit te lezen door middel van het volgende:

C++:
1
2
3
4
5
6
7
8
9
10
11
while(1){
    int BytesRead = 0;
    char inBuffer[3];
    while (BytesRead == 0){
            BytesRead = ReadUart(inBuffer,3);
        }

    cout << hex << (int)inBuffer[0] << "\n";
    cout << hex << (int)inBuffer[1] << "\n";
    cout << hex << (int)inBuffer[2] << "\n";
}


D.m.v. een microcontroller-schakeling stuur ik naar de COM port de volgende string:
0102FF

De output op het scherm van bovenstaande code is echter:
1
0
0
2
ffffffff
0

Als ik d.m.v. debuggen de inhoud van inBuffer bekijk zie ik ook gebeuren dat eerst de 01 wordt ingelezen, en de tweede ronde pas de rest.

Hoe kan dit gebeuren als ik aan de readfile doorgeef dat ik 3 bytes verwacht?

alvast bedankt!

  • Sendy
  • Registratie: September 2001
  • Niet online
Die len parameter is in de documentatie "maximum number of bytes to read."

Ik denk dat je er niet vanuit kan gaan dat dat ook altijd gelezen wordt.

Verwijderd

Topicstarter
Oke, dat klopt. Maar dat verklaart dan nog niet waarom de readfile() niet de hele string inleest...

  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

Omdat de eerste keer de hele string nog niet beschikbaar is. Je moet seriele poorten altijd per karakter uitlezen want je kunt niet uitgaan van de beschikbaarheid van meerdere karakters in de buffer. In dit geval lees je 2 karakters en terwijl je daar mee bezig bent komt de volgende set pas beschikbaar, die je dus de volgende iteratie pas uitleest.

Die 3 is inderdaad het maximum, niet hoeveel je er verwacht te lezen. Hij houdt de 1e keer na eerder op want meer zit er nou eenmaal niet in de buffer.

Plus, als jij een string stuurt "0102FF" dan stuur je zes karakters en niet drie. (Stuur je 0x01, 0x02, 0xff echter heb ik wat dat betreft niks gezegd en moet je hierboven '1 karakter' lezen.)

[ Voor 33% gewijzigd door CyBeR op 30-12-2012 18:12 ]

All my posts are provided as-is. They come with NO WARRANTY at all.


  • Sendy
  • Registratie: September 2001
  • Niet online
En je hebt denk ik een bug op regel 13. Zal return retlen moeten zijn? Ohnee is ook niet wat je wil.

[ Voor 20% gewijzigd door Sendy op 30-12-2012 18:18 ]


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23-11 13:12
Controleer eens wat ret is en wat retlen is dan. Als je call failed can retlen vanalles zijn, maar je mag sowieso niet verder in je buffer kijken dan retlen zegt, als ret aangeeft dat alles goed gaat.

En als je dat dan doet, gebruik dan retlen als return waarde en niet 0/1 want dat geeft niet het aantal gelezen karakters aan, zoals de naam BytesRead doet vermoeden.

Verder vraag ik me af wat je precies verstuurt, ASCII codes voor de string "0102FF" of echt de waarden 110, 210 en 25510.

Overigens wil je hoogstwaarschijnlijk iets van een timeout op dit verhaal hebben om te voorkomen dat je programma blijft hangen als er maar 2.5 characters binnenkomen omdat de kat op je communicatiekabel zit te knagen.

[ Voor 17% gewijzigd door farlane op 30-12-2012 21:07 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Als je altijd fixed-length buffer hebt, kan je loopen tot je die hoeveelheid verwachtte bytes hebt.

Bekijk anders eens de documentatie (en specifiek, check je return-value EN lpNumberOfBytesRead om te zien WAT je volgende actie moet zijn)

Jouw functie zou ik herschrijven als iets als:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
int ReadUart(char *buf, int len)
{ 
  BOOL ret; 
  DWORD retlen; 
  do
  {   
    ret = ReadFile (hCom,        // handle of file to read 
                buf,        // pointer to buffer that receives data 
                len,        // number of bytes to read 
                &retlen,    // pointer to number of bytes read 
                NULL    // pointer to structure for data 
            ); 
    if(!(ret && retlen)) return 0;
    len -= retlen;
    buf += retlen;
  }
  while(len);
  return 1;
}

[ Voor 46% gewijzigd door MLM op 30-12-2012 21:53 ]

-niks-


Verwijderd

Topicstarter
@farlane: een dergelijke beveiliging kan ik er later altijd nog tussen zetten. Wil eerst de communicatie opzich werkend krijgen. Ik stuur geen ASCII waarden, met RealTerm zie ik dat echt de HEX waarden binnen komen.

@MLM bedankt, zal er even naar kijken!

Ondertussen was ik bezig met het programma zo te maken dat er maar één bit tegelijk wordt ingelezen, dit werkt prima als ik ga debuggen, met een aantal breakpoints, maar werkt niet zodra ik de breakpoints weghaal:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
while(1){
    char inBuffer[1];
    char inputBuffer[3];
    char *aanwijs = inputBuffer;
    int BytesRead = 0;
    int lengte = 0;

    while (BytesRead == 0){
    lengte = sizeof(inBuffer);
    BytesRead = ReadUart(inBuffer,1);
    }

     *aanwijs = inBuffer[0];
     aanwijs ++;
     
     char eindbit = 0xFF;
     while(inBuffer[0] != eindbit){
            BytesRead = ReadUart(inBuffer,1);
        *aanwijs = inBuffer[0];
            aanwijs ++;
      }

    char instructieBit = inputBuffer[0];
    char dataBit = inputBuffer[1];
    cout << hex << (int)instructieBit << "\n";
    cout << hex << (int)dataBit << "\n";


Iemand enig idee? Het zou toch niet uit moeten maken of er breakpoints staan of niet...

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23-11 13:12
Wat is nou *het* verschil tussen wel en niet in een breakpoint komen tussendoor? ( hint : ook wel de 4e dimensie genoemd door sommigen )

Overigens rep je in je code en posts telkens over 'bits', dat zijn de dingen die je bedoelt niet.

[ Voor 26% gewijzigd door farlane op 31-12-2012 00:21 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Verwijderd

Topicstarter
De enige functie van een breakpoint is toch het 'pauzeren' van het programma om je de gelegenheid te geven de variabelen te bekijken en het programma stap voor stap te doorlopen?

Wat dus betekend dat ik op de plaats van de breakpoints een korte pauze moet inlassen?

edit:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
while(1){ 
    char inBuffer[1]; 
    char inputBuffer[3]; 
    char *aanwijs = inputBuffer; 
    int BytesRead = 0; 
    int lengte = 0; 

    while (BytesRead == 0){ 
    lengte = sizeof(inBuffer); 
    BytesRead = ReadUart(inBuffer,1); 
    } 
    Sleep(100);
     *aanwijs = inBuffer[0]; 
     aanwijs ++; 
      
     char eindbit = 0xFF; 
     while(inBuffer[0] != eindbit){ 
            BytesRead = ReadUart(inBuffer,1); 
            Sleep(100);
        *aanwijs = inBuffer[0]; 
            aanwijs ++; 
            
      } 

    char instructieBit = inputBuffer[0]; 
    char dataBit = inputBuffer[1]; 
    cout << hex << (int)instructieBit << "\n"; 
    cout << hex << (int)dataBit << "\n";
}


Op deze manier werkt het, kan nu eindelijk verder, bedankt!

[ Voor 60% gewijzigd door Verwijderd op 31-12-2012 00:35 ]


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23-11 13:12
Verwijderd schreef op maandag 31 december 2012 @ 00:28:
Wat dus betekend dat ik op de plaats van de breakpoints een korte pauze moet inlassen?
Nee, alhoewel dat wel de reflex is die ik meestal voorbij zie komen. Het probleem daaran is nl dat er geen garanties bestaan dat na die korte pauze wel alles binnen is.

De enige goede methode is de data die je binnenkrijgt bekijken en aan de hand daarvan bepalen of alles binnen is, of dat wat je hebt binnen gekregen ook geldige data is en of het niet te lang duurt voordat alles binnen is ( de kat, je weet wel ).

Overigens kan ik je deze link aanraden: Oud, maar nog altijd relevant voor dit soort zaken.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Verwijderd

Topicstarter
farlane schreef op maandag 31 december 2012 @ 00:35:
[...]
De enige goede methode is de data die je binnenkrijgt bekijken en aan de hand daarvan bepalen of alles binnen is, of dat wat je hebt binnen gekregen ook geldige data is en of het niet te lang duurt voordat alles binnen is ( de kat, je weet wel ).
Okee, dus dan is een vergelijkbare functie als die MLM al opperde een betere oplossing...

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23-11 13:12
Verwijderd schreef op maandag 31 december 2012 @ 00:40:
Okee, dus dan is een vergelijkbare functie als die MLM al opperde een betere oplossing...
Nee want het enige dat die functie doet is in een hele strakke loop ReadFile aanroepen; als ReadFile failed op de poort zal hij waarschijnlijk 3 nanoseconden later ook wel failen.

Bovendien kan ReadFile prima het totaal aantal karakters in een keer lezen als je blocking wilt werken. Kijk daarvoor eens naar de documentatie van SetCommTimeouts en COMMTIMEOUTS

Het lijkt er overigens op dat jij je poort in overlapped modus opent, kunt je je CreateFile aanroep eens posten?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

farlane schreef op maandag 31 december 2012 @ 08:58:
[...]

Nee want het enige dat die functie doet is in een hele strakke loop ReadFile aanroepen; als ReadFile failed op de poort zal hij waarschijnlijk 3 nanoseconden later ook wel failen.

Bovendien kan ReadFile prima het totaal aantal karakters in een keer lezen als je blocking wilt werken. Kijk daarvoor eens naar de documentatie van SetCommTimeouts en COMMTIMEOUTS

Het lijkt er overigens op dat jij je poort in overlapped modus opent, kunt je je CreateFile aanroep eens posten?
Mijn functie breekt de loop als ReadFile failed, hoe dat verder afgehandeld word is niet mijn probleem :P Ik ging uit van een blocking filehandle trouwens, gezien de NULL argument voor lpOverlapped in het origineel, als er async I/O gewenst is, dan is mijn functie incompleet (dan ga je toch ERR_IO_PENDING moeten vangen als ReadFile failed)

-niks-


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23-11 13:12
MLM schreef op maandag 31 december 2012 @ 16:33:
Mijn functie breekt de loop als ReadFile failed, hoe dat verder afgehandeld word is niet mijn probleem :P Ik ging uit van een blocking filehandle trouwens, gezien de NULL argument voor lpOverlapped in het origineel, als er async I/O gewenst is, dan is mijn functie incompleet (dan ga je toch ERR_IO_PENDING moeten vangen als ReadFile failed)
Je slikt de foutsituatie in door een 0 te retouneren die je vervolgens niet meer kunt onderscheiden van 'niets gelezen' als de timeouts als zodanig werden ingesteld

Als de port blocking wordt geopend heeft het bovendien weinig zin om in een zo'n strakke loop te gaan lezen; lees alle verwachte bytes gewoon in 1 keer. Als ReadFile een fout retouneert is de kans klein dat het nog goed gaat komen zonder verdere acties van de gebruiker.

@TS: Uit de docs van ReadFile:
Unpredictable results can occur if you fail to set the time-out values. For more information about communication time-outs, see COMMTIMEOUTS.
Als je de poort non-overlapped hebt geopend, zie je waarschijnlijk het effect waar deze opmerking het over heeft.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Verwijderd

Topicstarter
farlane schreef op maandag 31 december 2012 @ 08:58:
[...]
Het lijkt er overigens op dat jij je poort in overlapped modus opent, kunt je je CreateFile aanroep eens posten?
Nee ik open de poort niet overlapped hoor. De CreateFile aanroep ziet er als volgt uit:
C++:
1
2
3
4
5
6
7
hCom = CreateFile( pcCommPort,
                 GENERIC_READ | GENERIC_WRITE,
                             0,                           //  exclusive-access
                             NULL,                    //  default security
                            OPEN_EXISTING,  //  OPEN_EXISTING
                            0,                           //  not overlapped I/O
                            NULL );                  //  hTemplate

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23-11 13:12
Welke waarden gebruik je bij je call naar SetCommTimeouts dan?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

farlane schreef op dinsdag 01 januari 2013 @ 11:52:
[...]

Je slikt de foutsituatie in door een 0 te retouneren die je vervolgens niet meer kunt onderscheiden van 'niets gelezen' als de timeouts als zodanig werden ingesteld
Nope, de return value is (net als de functie van de TS) een boolean (0 = error, 1 = alle gevraagde bytes gelezen). Er is geen mogelijkheid dat een gedeeltelijke read uitgevoerd kan worden door de functie, maar dat is wat (zodanig als ik begreep) de bedoeling was van de TS.

-niks-


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23-11 13:12
MLM schreef op donderdag 03 januari 2013 @ 20:11:
Nope, de return value is (net als de functie van de TS) een boolean (0 = error, 1 = alle gevraagde bytes gelezen). Er is geen mogelijkheid dat een gedeeltelijke read uitgevoerd kan worden door de functie, maar dat is wat (zodanig als ik begreep) de bedoeling was van de TS.
Al je de documentatie van COMMTIMEOUTS leest is er een mogelijkheid om deze zo in te stellen dat een read direct retourneert zonder te blocken met eventueel ontvangen bytes in de buffer. Deze kan dus de combinatie ret == 1 en retlen == 0 veroorzaken.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

OK, mocht dat het geval zijn dan kan de conditie misschien niet retlen == 0 afvangen (maar ik weet niet of ReadFile in dat geval niet ook retlen == 0 + return TRUE kan opleveren (zoals bv EOF in een file), dan moet je met GetLastError gaan kijken ofzo, dat is ook sub-optimaal). Anyway, als de TS wilt blocken tot een fixed-size buffer vol is, zou hij ook niet SetCommTimeouts moeten instellen met instant-return, dat is echt onnodige verspilling :)

-niks-


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23-11 13:12
MLM schreef op vrijdag 04 januari 2013 @ 19:14:
Anyway, als de TS wilt blocken tot een fixed-size buffer vol is, zou hij ook niet SetCommTimeouts moeten instellen met instant-return, dat is echt onnodige verspilling :)
Dat klopt, in een post ergens hierboven probeerde ik de TS ook te wijzen op het feit dat het gedrag dat hij ziet waarschijnlijk veroorzaakt wordt doordat hij geen of verkeerde timeouts instelt.

Overigens is een dergelijke timeout instelling erg handig in een superloop applicatie waarbij je niet wilt blocken op communicatie, maar waarbij je je complexiteit van MT of overlapped IO wilt vermijden.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.

Pagina: 1