read port COM non bloquant sous win :-( comment faire ?

read port COM non bloquant sous win :-( comment faire ? - C++ - Programmation

Marsh Posté le 15-04-2003 à 15:32:02    

bonjour,
 
J ai un gros probleme a cause d un port COM . je dois lire en continu des donnees sur celui-ci , ces donnees arrivent aleatoirement (c un bus de donnees ) donc j ai une procedure (un thread) qui lit en continu sur le port.
 
Mon programme tourne sous linux et ca marche nickel ... en effet le read sur un port COM sous linux est bloquant et donc mon thread reste bloqué sur le read jusqu a ce que je recoive des donnees.
 
Par contre je dois faire une version de ce programme sous windows et la :( pas possibilité de mettre ReadFile (l equivalent) en mode  bloquant.
 
Mais alors que faire ?
 
sachant que je recois les donnees aleatoirement je suis obligé de faire une boucle qui lit le port :

Code :
  1. while (1){
  2.    ReadFile(...);
  3. }

 
en non bloquant, si je ne recois rien ca boucle a l infini et c pas bon car le thread lit en permanence sur le port et du coup comme on ne peut pas ecrire quand on lit lorsque je veux faire un write dessus ca ne passe pas.
 
J ai donc pensé a mettre dans ma boucle un sleep(50) pour  endormir pendant 50ms le process avant chaque lecture. du coup ca marche mieux mais cela signifie que je ne lis des donnees que tous les 50 ms (il s agit de trames de 16 octets a traiter rapidement), donc ce n est pas la bonne solution.
 
 
Quelqu un a t il une solution a me proposer car je ne vois pas comment faire ? d ailleurs apparemment il parait que la solution non bloquante est la meilleure mais je ne vois pas comment on peut fonctionner comme ca.
 
 
merci d avance

Reply

Marsh Posté le 15-04-2003 à 15:32:02   

Reply

Marsh Posté le 15-04-2003 à 16:52:16    

:??:

Reply

Marsh Posté le 15-04-2003 à 17:03:55    

Ayant déjà eu un problème similaire, j'ai utilisé le port COM en mode Overlapped (voir http://msdn.microsoft.com/library/ [...] ions.asp). Cela permet d'être prévenu quand des infos sont présentes en lecture et quand une écriture est terminée.


---------------
each day I don't die is cheating
Reply

Marsh Posté le 15-04-2003 à 17:15:46    

ok merci je vais regarder ca ...

Reply

Marsh Posté le 16-04-2003 à 11:12:55    

j ai regardé un peu plus en profondeur l histoire du readfile .... en fait en mode overlapped (comme tu me proposes de faire) c est un mode asynchrone c est a dire que la fonction quitte meme si rien n a été lu ... or ca ne m interesse pas. Par contre la fonction ReadFile si le parametre OVERLAPPED n a pas ete specifié, est censé etre en mode sunchrone c est a dire qu elle ne quitte pas tant qu elle n a pas lu les octets demandés.... mais ca ne marche pas , la fonction quitte quand meme sans retourner d erreur et avec un nombre d octets lus egal a 0.
 
Or, dans l aide MSDN, il disent que ce n est pas possible que la fonction retourne true (pas d erreur) avec le membre OVERLAPPED a NULL (c le cas) et un nombre d octets lus a 0 (c le cas aussi )
 
Donc je comprends pas ... ca ne bloque pas.
 
J ai donc regardé du coté du timeout (SetCommTimeOut) et j ai mis mon totalreadconstant et totalreadmultiplier a 0. Dans ce cas la fonction lit et quitte tout de suite si rien n est lu.. c est le seul cas ou ca marche (et ca ne me gene pas l ecriture) ..par contre du coup mes trames sont fragmentes et je dois les reassembler.
 
Si je mets des valeurs differentes de 0 a totalreadconstant et totalreadmultiplier , c censé attendre nboctet*multiplier + constant a chaque appel de read... du coup ca attend bien ce temps mais ca me bloque mon ecriture (pire , ca ne la met pas en attente ca la perd ???? comprend pas)
 
Est ce une bonne chose de faire une boucle  
 
while(1)
  ReadFile(...);
   if (nboctetslu >0)  
       faire traitement
fin while
 
avec les parametres de timeout a 0 comme je l ai dit ci dessus ou y a t il une methode plus "propre" ?
 
merci

Reply

Marsh Posté le 16-04-2003 à 15:21:49    

L'avantage du mode Overlapped c'est qu'il te prévient quand tu as des données présentes sur le port COM. C'est à dire que ça va appeler une fonction callback ou déclencher un event.
En fait ça fonctionne comme les sockets non bloquantes, c'est à dire que tu appelles une fois la fonction ReadFile ou WriteFile et si tu n'as rien lu ou écris cette fois ci, ça va déclencher ta fonction (ou ton event) la prochaine fois que tu pourras lire ou écrire. L'avantage c'est que tu n'as pas besoin de scanner en permanence le port COM en attendant des informations et que tu n'écriras sur le port que quand ce sera vraiment possible.
 
Pour la boucle que tu cherches à faire, ce n'est pas forcemment mauvais. Cependant, tu dois garder en tête que ton ReadFile ne lira que ce qu'il y a dans le buffer d'entrée. Donc même si ton message fait 8 octets, tu peut très bien ne les lire que 2 par 2. Dans le même ordre d'idée essaie de penser au cas où ton interlocuteur est très lent (du genre 1 octet toutes les minutes par exemple), il faut que ton programme continue à fonctionner.


---------------
each day I don't die is cheating
Reply

Marsh Posté le 16-04-2003 à 15:32:01    

pourrais tu me donner un exemple de code ... je comprends a peu pres mais  c est encore flou :D. En fait c est la phase d initialisation que je ne comprends pas. Je dois faire un premier ReadFile pour initialiser et ensuite je fais mes ReadFile suivant dans la fonction callback ??
 
Mais ca a l'air d etre un peu plus propre, en effet mon code "fonctionne" mais ca ne me plait pas. Notamment au niveau du temps CPU. Du fait que mon programme (enfin mon thread) boucle sans cesse en faisant un ReadFile, le temps CPU est à 100% et ce n est pas tres bon (pire : il est a 100 % si je ne fais rien et baisse quand j'ai recu des donnees ...)
 
 
merci de m'aider en tout cas.
 

Reply

Marsh Posté le 16-04-2003 à 15:42:49    

gatorette a écrit :

L'avantage du mode Overlapped c'est qu'il te prévient quand tu as des données présentes sur le port COM. C'est à dire que ça va appeler une fonction callback ou déclencher un event.
En fait ça fonctionne comme les sockets non bloquantes, c'est à dire que tu appelles une fois la fonction ReadFile ou WriteFile et si tu n'as rien lu ou écris cette fois ci, ça va déclencher ta fonction (ou ton event) la prochaine fois que tu pourras lire ou écrire. L'avantage c'est que tu n'as pas besoin de scanner en permanence le port COM en attendant des informations et que tu n'écriras sur le port que quand ce sera vraiment possible.
 
Pour la boucle que tu cherches à faire, ce n'est pas forcemment mauvais. Cependant, tu dois garder en tête que ton ReadFile ne lira que ce qu'il y a dans le buffer d'entrée. Donc même si ton message fait 8 octets, tu peut très bien ne les lire que 2 par 2. Dans le même ordre d'idée essaie de penser au cas où ton interlocuteur est très lent (du genre 1 octet toutes les minutes par exemple), il faut que ton programme continue à fonctionner.


 
Est ce que la meme chose peut marcher pour un port série et une liaison RS232, le port étant sur une carte à part (marque AD-LINK) ???

Reply

Marsh Posté le 16-04-2003 à 16:03:26    

xilebo a écrit :

pourrais tu me donner un exemple de code ... je comprends a peu pres mais  c est encore flou :D. En fait c est la phase d initialisation que je ne comprends pas. Je dois faire un premier ReadFile pour initialiser et ensuite je fais mes ReadFile suivant dans la fonction callback ??


 
Bon, ça fait quelques temps que j'ai pas retouché au prog donc je me souviens pas de tous les détails. Voici quelques extraits du soft. J'ai essayé de mettre quelques commentaires, mais il va falloir que tu te penches un peu dessus tout de même (je me souviens pas de tout).

Code :
  1. void Init()
  2. {
  3. hCom = CreateFile( COMPORT, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL ); // ouvre le port
  4. oRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); // crée l'évenement "des données ont été lues"
  5. oWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); // crée l'évenement "des données ont été écrites"
  6. oReady.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); // crée l'évenement "il y a des données à lire"
  7. COMMTIMEOUTS commTimeOuts;
  8. commTimeOuts.ReadIntervalTimeout = MAXDWORD; // this makes a timeout occur when what is in the buffer has been read
  9. commTimeOuts.ReadTotalTimeoutConstant = 0;
  10. commTimeOuts.ReadTotalTimeoutMultiplier = 0;
  11. commTimeOuts.WriteTotalTimeoutConstant = 10;  // 10 ms added to the timeout of the whole packet
  12. commTimeOuts.WriteTotalTimeoutMultiplier = 2;  // 2 ms for each byte sent
  13. SetCommTimeouts( hCom, &commTimeOuts );
  14. SetCommMask( hCom, EV_RXCHAR ); // on ne s'intéresse qu'à l'événement "il y a des données à lire"
  15. DWORD dwEvtMask = 0;
  16. WaitCommEvent( hCom, &dwEvtMask, &oReady );
  17. }
  18. void boucle()
  19. {
  20. for(;;) // infinite loop
  21. {
  22. iHandle = WaitForMultipleObjects( 3, hArray, FALSE, dwTimeout );
  23. if( iHandle == WAIT_OBJECT_0 ) // Ready event
  24. {
  25. ResetEvent( oReady.hEvent );
  26. ReceiveBuffer();
  27. }
  28. if( iHandle == WAIT_OBJECT_0 + 1 ) // Read event (indicates that data have been read on port)
  29. {
  30. ResetEvent( oRead.hEvent );
  31. DWORD dwBytesRcvd = 0;
  32. if( GetOverlappedResult( hCom, &oRead, &dwBytesRcvd, TRUE ) )
  33. {
  34. dwRecvBufferSize += dwBytesRcvd;
  35. lpRecvBuffer = (LPBYTE)realloc( lpRecvBuffer, dwRecvBufferSize );
  36. ProcessCommand();
  37. if( dwBytesRcvd == READANDWRITEBUFFSIZE )  // if we filled our buffer
  38. ReceiveBuffer(); // try to read more (because we might not have received the event)
  39. else
  40. {
  41. DWORD dwEvtMask = 0;
  42. WaitCommEvent( hCom, &dwEvtMask, &oReady );
  43. }
  44. }
  45. else
  46. {
  47. ReceiveBuffer();
  48. }
  49. }
  50. if( iHandle == WAIT_OBJECT_0 + 5 ) // Write event (indicates that data have been written on port)
  51. {
  52. ResetEvent( oWrite.hEvent );
  53. DWORD dwBytesSent = 0;
  54. if( GetOverlappedResult( hCom, &oWrite, &dwBytesSent, TRUE ) )
  55. {
  56. dwSendBufferSize -= dwBytesSent;
  57. if( dwSendBufferSize > 0 )
  58. {
  59. LPBYTE lpTemp = (LPBYTE)malloc( dwSendBufferSize );
  60. memcpy( lpTemp, lpSendBuffer + dwBytesSent, dwSendBufferSize );
  61. free( lpSendBuffer );
  62. lpSendBuffer = lpTemp;
  63. SendBuffer();
  64. }
  65. else
  66. {
  67. free( lpSendBuffer );
  68. lpSendBuffer = NULL;
  69. }
  70. }
  71. else
  72. {
  73. SendBuffer();
  74. }
  75. }
  76. }
  77. void SendBuffer()
  78. {
  79. if( lpSendBuffer != NULL )
  80. {
  81. DWORD dwBytesSent = 0;
  82. DWORD dwBytesToSend = dwSendBufferSize > READANDWRITEBUFFSIZE ? READANDWRITEBUFFSIZE :  dwSendBufferSize;
  83. if( WriteFile( hCom, lpSendBuffer, dwBytesToSend, &dwBytesSent, &oWrite ) )
  84. {
  85. SetEvent( oWrite.hEvent );
  86. }
  87. else
  88. {
  89. DWORD dwErr = GetLastError();
  90. if( dwErr != ERROR_IO_PENDING )
  91. {
  92. Sleep(0); // à mon avis, c'est juste pour pouvoir placer un point d'arrêt pour examiner l'erreur
  93. }
  94. }
  95. }
  96. }
  97. void ReceiveBuffer()
  98. {
  99. DWORD dwBytesRcvd = 0;
  100. lpRecvBuffer = (LPBYTE)realloc( lpRecvBuffer, dwRecvBufferSize + READANDWRITEBUFFSIZE );
  101. if( ReadFile( hCom, lpRecvBuffer + dwRecvBufferSize, READANDWRITEBUFFSIZE, &dwBytesRcvd, &oRead ) )
  102. {
  103. SetEvent( oRead.hEvent );
  104. }
  105. else
  106. {
  107. if( GetLastError() != ERROR_IO_PENDING )
  108. {
  109. SetEvent( oReady.hEvent );
  110. }
  111. }
  112. }


 

xilebo a écrit :

Mais ca a l'air d etre un peu plus propre, en effet mon code "fonctionne" mais ca ne me plait pas. Notamment au niveau du temps CPU. Du fait que mon programme (enfin mon thread) boucle sans cesse en faisant un ReadFile, le temps CPU est à 100% et ce n est pas tres bon (pire : il est a 100 % si je ne fais rien et baisse quand j'ai recu des donnees ...)


C'est pour ça que je n'aime pas ces boucles infinies (même si ça n'a pas forcemment une influence majeure sur le comportement du PC).
 

backdafuckup a écrit a écrit :

Est ce que la meme chose peut marcher pour un port série et une liaison RS232, le port étant sur une carte à part (marque AD-LINK) ???



Pourquoi pas, ce qu'il faut c'est que la carte soit reconnue par Windows.


---------------
each day I don't die is cheating
Reply

Marsh Posté le 16-04-2003 à 16:15:13    

gatorette a écrit :


Pourquoi pas, ce qu'il faut c'est que la carte soit reconnue par Windows.


 
 
Elle est reconnue en tant que périphérique de type NuDAQ Boards, PCI7300A-revB device(ref de la carte).
 
Et dernière question.
Qu'est ce qu'il vaut mieux faire :  
- la solution de l'overlapped
- ou un thread qui ferait listener du port
 ?

Reply

Marsh Posté le 16-04-2003 à 16:15:13   

Reply

Marsh Posté le 16-04-2003 à 16:20:06    

hum j'ai essayé le mode overlapped mais ca ne marche pas du tout :(
 
voila mon code (au tout demarrage du programme ..rien avant)
 

Code :
  1. hSerial = CreateFile("COM1:",GENERIC_READ / GENERIC_WRITE,0,NULL,OPEN_EXISTING / FILE_FLAG_OVERLAPPED,0,NULL);
  2. if (hSerial == INVALID_HANDLE_VALUE) {
  3. DWORD ret = GetLastError();
  4. Log("Erreur %d",ret);
  5. return false;
  6. }


 
 
l erreur retournée est 87 soit "parametre incorrect"
 
mon code fonctionne bien par contre si je ne mets pas FILE_FLAG_OVERLAPPED
 
 
aurais-je oublié quelque chose ? ou je suis contraint d utiliser ma vieille (et bourrine) méthode ?
 
 
edit : je mets des / car je suis sous mac (berk) et je n ai pas trouvéé la barre verticale.


Message édité par xilebo le 16-04-2003 à 16:21:08
Reply

Marsh Posté le 16-04-2003 à 16:23:57    

ouuuupppsss , j ai mis FILE_FLAG_OVERLAPPED dans le mauvais parametre ... oublie le message precedent (g pas l air con la)
 
sinon pour les boucles infinies : j aime pas trop non plus mais pour moi un processeur travaille toujours ...rien qu un programme sous windows quand "il ne fait rien" y a quand meme la boucle d evenement qui tourne. Par contre, il me semble qu on peut passer en idle time mais comment faire je ne sais point .
 
edit : Merci pour ton bout de code .. c est sympa de ta part ;)


Message édité par xilebo le 16-04-2003 à 16:26:02
Reply

Marsh Posté le 16-04-2003 à 16:59:07    

backdafuckup a écrit :

Elle est reconnue en tant que périphérique de type NuDAQ Boards, PCI7300A-revB device(ref de la carte).


Ce qu'il faut savoir c'est si le port COM est référencé par Windows dans la rubrique "port" du gestionnaire de périphérique. Si c'est le cas, tu peux t'en servir comme n'importe quel port COM. A mon avis, ça ne doit pas poser de problèmes.
 

backdafuckup a écrit :

Qu'est ce qu'il vaut mieux faire :  
- la solution de l'overlapped
- ou un thread qui ferait listener du port ?


Il me semble que le mieux est la solution de l'overlapped mais elle est assez compliquée à mettre en place (et peut être pas adaptée à toutes les applications).
 

xilebo a écrit :

sinon pour les boucles infinies : j aime pas trop non plus mais pour moi un processeur travaille toujours ...rien qu un programme sous windows quand "il ne fait rien" y a quand meme la boucle d evenement qui tourne. Par contre, il me semble qu on peut passer en idle time mais comment faire je ne sais point .


C'est pour ça que ce n'est pas trop grave de faire une boucle infinie dans une thread. Je crois que ça vient du fait que Windows fonctionne en multitâche préemptif, c'est à dire que c'est lui qui attribue le temps aux applications et pas les applis qui abandonnent du temps. Oui, tu peux faire passer ton programme en Idle (notamment dans le Gestionnaire des Tâches onglet processus), mais je ne pense pas que dans ce cas cela change grand chose.
 

xilebo a écrit :

Merci pour ton bout de code .. c est sympa de ta part ;)


Je ne suis pas sûr que ça t'aide beaucoup, mais ça peut tout de même te mettre sur la voie. Si vraiment tu galères de trop, je peux t'envoyer tout le soft (mais il n'y a pas vraiment de docs ni de commentaires).


---------------
each day I don't die is cheating
Reply

Marsh Posté le 16-04-2003 à 17:03:23    

Mon port n'est pas dans "ports" du gestionnaire de périphs...
Ce port se trouve sur la carte....
On peut pas utiliser l'adresse de la carte au lieu de l'adresse d'un port COM ??

Reply

Marsh Posté le 16-04-2003 à 17:11:30    

backdafuckup a écrit :

On peut pas utiliser l'adresse de la carte au lieu de l'adresse d'un port COM ??


 
C'est à dire ???
Sous Windows, tu te sers d'un port COM comme d'un fichier, tu l'ouvres avec CreateFile, tu le lis avec ReadFile, etc.. C'est juste que c'est un fichier particulier qui s'appelle "COM1", "COM2"... Donc si ta carte ne te sort pas un port COM standard (pour Windows), je doute que tu puisses t'en servir comme ça. Le mieux est encore de regarder la documentation fournie avec la carte.
 
EDIT: Je viens de trouver la documentation de ta carte (NuDAQ Boards PCI7300A) et en fait, il faut se servir de la DLL qui est livrée avec. Donc apparemment pas question de s'en servir comme d'un port COM.


Message édité par gatorette le 16-04-2003 à 17:17:53

---------------
each day I don't die is cheating
Reply

Marsh Posté le 16-04-2003 à 17:16:48    

gatorette a écrit :


 
C'est à dire ???
Sous Windows, tu te sers d'un port COM comme d'un fichier, tu l'ouvres avec CreateFile, tu le lis avec ReadFile, etc.. C'est juste que c'est un fichier particulier qui s'appelle "COM1", "COM2"... Donc si ta carte ne te sort pas un port COM standard (pour Windows), je doute que tu puisses t'en servir comme ça. Le mieux est encore de regarder la documentation fournie avec la carte.


 
C tout en anglais incompréhensible (pourtant d'habitude je comprends l'anglais mais la :/) et plein de schémas d'électronique... Mais tu as raison, je vais continuer à bucher la doc, même si c'est chiant...
 
Merci d'avoir essayé en tout cas

Reply

Marsh Posté le 17-04-2003 à 16:05:26    

gatorette :
 
J ai etudié le source que tu m as passé, il me semble interessant... je pense par contre que je n'ai pas forcement besoin des evenements "des donnees ont étés lues" et "des donnees ont ete ecrites" ce qui me fait un seul evenement a creer.
 
Par contre j ai un probleme dans mon code , en effet lors du premier appel a WaitForSingleObject( j utilise plus WaitForMultipleObjects vu que j ai qu un evenement), ca se passe bien, j ai mis un timeout de 1000 et il wait bien mon evenement toutes les 1000 ms. Et des qu il y a une lecture sur le port, je recois bien un evenement, mon WaitForSingleObject passe bien et je peux lire mes donnees sur le port... seulement apres , il me renvoie toujours 0 (qui correspond a WAIT_OBJECT_0 autrement dit ca signifie qu il a toujours des donnees sur le port alors que j ai bien tout lu)
 
Je mets mon code :
 
Initialisation :
 

Code :
  1. COMMTIMEOUTS ct;
  2. DCB    dcb;
  3. CString   buf;
  4. buf.Format("COM%d:",m_dwComPort+1);
  5. hSerial = CreateFile(buf, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING , FILE_FLAG_OVERLAPPED  , NULL);
  6. if (hSerial == INVALID_HANDLE_VALUE) {
  7.  DWORD d = GetLastError();
  8.  buf.Format("Unable to open port COM .. error n?%d",d);
  9.  Log(LOG_ERROR,buf);
  10.  return ShutEngine();
  11. }
  12.     ct.ReadIntervalTimeout = MAXDWORD;          /* Maximum time between read chars. */
  13.     ct.ReadTotalTimeoutMultiplier = 0;   /* Multiplier of characters.        */
  14.     ct.ReadTotalTimeoutConstant = 0;     /* Constant in milliseconds.        */
  15.     ct.WriteTotalTimeoutMultiplier = 2;  /* Multiplier of characters.        */
  16.     ct.WriteTotalTimeoutConstant = 10;    /* Constant in milliseconds.        */
  17. if (!SetCommTimeouts(hSerial, &ct)) {
  18.  Log(LOG_ERROR,"Unable to set COM timeouts" );
  19.  return ShutEngine();
  20. }
  21. ZeroMemory(&dcb, sizeof(dcb));
  22. dcb.DCBlength = sizeof(dcb);
  23. if (!GetCommState(hSerial, &dcb)) {
  24.  Log(LOG_ERROR,"Unable to get COM state" );
  25.  return ShutEngine();
  26. }
  27. dcb.BaudRate = CBR_38400;
  28. dcb.fBinary = TRUE;
  29. dcb.fParity = FALSE;
  30. dcb.fOutxCtsFlow = FALSE;
  31. dcb.fOutxDsrFlow = FALSE;
  32. dcb.fDtrControl = DTR_CONTROL_DISABLE;
  33. dcb.fDsrSensitivity = FALSE;
  34. dcb.fTXContinueOnXoff = FALSE;
  35. dcb.fOutX = FALSE;
  36. dcb.fInX = FALSE;
  37. dcb.fErrorChar = FALSE;
  38. dcb.fNull = FALSE;
  39. dcb.fRtsControl = RTS_CONTROL_DISABLE;
  40. dcb.fAbortOnError = FALSE;
  41. dcb.ByteSize = 8;
  42. dcb.Parity = NOPARITY;
  43. dcb.StopBits = ONESTOPBIT;
  44. if (!SetCommState(hSerial, &dcb)) {
  45.  Log(LOG_ERROR,"Unable to set COM state" );
  46.  return ShutEngine();
  47. }
  48. if (!SetCommMask(hSerial, EV_RXCHAR)) {
  49.  Log(LOG_ERROR,"Unable to set COM mask" );
  50.  return ShutEngine();
  51. }
  52. oReady.Offset = 0;
  53. oReady.OffsetHigh =0;
  54. oReady.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
  55. DWORD dwEventMask = 0;
  56. WaitCommEvent(hSerial,&dwEventMask,&oReady);
  57. // apres je cree mon thread ...


 
code de mon thread :
 

Code :
  1. DWORD WINAPI SerialThreadFunc(LPVOID pParam) {
  2. CTCPIP2CANEngine *pEngine = (CTCPIP2CANEngine *)pParam;
  3. char buffer[CAN_MSGLEN];
  4. DWORD bufferlen = CAN_MSGLEN;
  5. DWORD bufferread = 0;
  6. CString buf;
  7. OVERLAPPED overlapped;
  8. memset(&overlapped,0,sizeof(overlapped));
  9. while (pEngine->m_dwStart) {
  10.  int ret;
  11.  // ReadFile is not a blocking call ... :-(
  12.  ret = WaitForSingleObject(pEngine->oReady.hEvent,1000);
  13.  buf.Format("RET :%d",ret);
  14.  pEngine->Log(LOG_SYSTEM,buf);
  15.  switch (ret) {
  16.  case WAIT_TIMEOUT :
  17.   {
  18.    //pEngine->Log(LOG_SYSTEM,"Timeout occured" );
  19.   }
  20.   break;
  21.  case WAIT_OBJECT_0:
  22.   {
  23.    ResetEvent(pEngine->oReady.hEvent);
  24.    if (pEngine->m_dwConnection) {
  25.     if ((ret = ReadFile(pEngine->hSerial,buffer,bufferlen,&bufferread,&pEngine->oReady)) == 0) {
  26.      pEngine->Log(LOG_ERROR,"A serial error has occured ... shutting down engine" );
  27.      pEngine->ShutEngine();
  28.      return 0;
  29.     }
  30.     if (bufferread > 0) { // on a recu une trame, empiler
  31.      memcpy(pEngine->m_szSerialStack+pEngine->m_dwSerialStack,buffer,bufferread);
  32.      buf.Format("Read %d bytes on COM port",bufferread);
  33.      pEngine->Log(LOG_SYSTEM,buf);
  34.      pEngine->m_dwSerialStack+=bufferread;
  35.      if (pEngine->m_dwSerialStack >= CAN_MSGLEN) { //on a une trame complete, l envoyer    
  36.       pEngine->SendMsg(MSG_TRAME,pEngine->m_szSerialStack,CAN_MSGLEN);
  37.       pEngine->m_dwSerialStack -= CAN_MSGLEN;
  38.       // on peut faire ca car m_dwSerialStack ne sera jamais plus grand que 2*CAN_MSGLEN = 32
  39.       memcpy(pEngine->m_szSerialStack,pEngine->m_szSerialStack+CAN_MSGLEN,pEngine->m_dwSerialStack);
  40.      }
  41.     }
  42.    }
  43.   }
  44.   break;
  45.  default :
  46.   {
  47.    buf.Format("RET :%d",ret);
  48.    pEngine->Log(LOG_SYSTEM,buf);
  49.   }
  50.   break;
  51.  }
  52. }
  53. pEngine->Log(LOG_INFO,"Closing serial" );
  54. return 1;
  55. }


 
 
ai je fait une erreur ou non ? je n ai pas bien compris l utilité de la fonction SetEvent, ni le fait de devoir repeter WaitCommEvent.
 
 
Merci

Reply

Marsh Posté le 17-04-2003 à 16:46:16    

xilebo a écrit :

je pense par contre que je n'ai pas forcement besoin des evenements "des donnees ont étés lues" et "des donnees ont ete ecrites" ce qui me fait un seul evenement a creer.


Je pense que j'ai eu besoin de ces événements afin de savoir combien d'octets ont été lus ou écrits. En effet, même si tu as des octets présents dans le buffer d'entrée, il n'est pas garanti que ton ReadFile va lire tout de suite ce qu'il y a dedans.
 

xilebo a écrit :

j utilise plus WaitForMultipleObjects vu que j ai qu un evenement


Je pense que tu devras tout de même créer au moins un événement "quitter la thread", non ?
 

xilebo a écrit :

seulement apres , il me renvoie toujours 0 (qui correspond a WAIT_OBJECT_0 autrement dit ca signifie qu il a toujours des donnees sur le port alors que j ai bien tout lu)


Il semble que dans ton code, tu reset bien l'event, donc ça ne semble pas être ça. Après je ne vois pas d'erreurs flagrantes dans ton code donc ça me semble étrange. C'est peut être pour cette raison que je refais un WaitCommEvent à la fin de ma lecture.
 

xilebo a écrit :

ai je fait une erreur ou non ? je n ai pas bien compris l utilité de la fonction SetEvent, ni le fait de devoir repeter WaitCommEvent.


Il me semble que je fais le SetEvent quand j'arrive à lire ou écrire directement des données (quand je n'ai pas l'erreur IO_PENDING) car sinon l'évenement n'est pas envoyé (il n'est envoyé que si l'écriture ou la lecture se font en differé).
Concernant la répetition de WaitCommEvent, je suppose que j'ai dû penser qu'il fallait le refaire. Soit parce que je l'ai lu quelque part soit parce que je l'ai constaté à l'execution. Il est vrai que ce n'est peut être pas du tout nécessaire.


---------------
each day I don't die is cheating
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed