Salut a tous
Je souhaite ecrire des fonctions de communications utilisant un des port COM du PC, aucun soucis pour ouvrir le port, le configurer et le fermer. Pas de soucis non plus pour envoyer des datas, par contre impossible de recevoir (les questions sont en bas du post )
Edit: Je code avec Code::Blocks / OS: Windows XP
le .h
Je vous colle ici les parties de code du .c
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
30
31
32
33
34
35
36 /* Definition des codes d'erreurs port Serie */ typedef enum { _ErrorNone, // Pas d'erreur _ErrorCreate, // Erreur lors de l'ouverture du port (déja utilisé) _ErrorInexistant, // Port COM n'existe pas _ErrorConfigPort, // Erreur lors de la configuration du PORT _ErrorConfigTimeout,// Erreur lors de la configuration des Timeouts _ErrorFrameDef, // Erreur de définition de la trame _ErrorTx, // Erreur lors de l'emission _ErrorParamEventRx, // Erreur de parametrage de l'evenement "RX char" _ErrorRx, // Erreur lors de la reception _ErrorTimeout, // Delais depasse pour la reponse progger _ErrorNack, // Demande non prise en compte _ErrorChecksum // Erreur de Checksum }enSerialError; /* Definition de la structure de configuration du port serie */ typedef struct SerialParam SerialParam; struct SerialParam { char ComPort[5]; // Nom du PORT selectionné long BaudRate; // Débit long DataBitsNumber; // Nombre de bits de donnée }; enSerialError OpenSerialPort(SerialParam *pSerialConfig); void CloseSerialPort(); enSerialError ReadSerialPortOverlapped(char* pcharBuffer, long* plgNbBytesRead, long lgNbBytesToRead); enSerialError WriteSerialPortOverlapped(const char* pcharBuffer, long lgNbBytes);
Ouverture/Configuration du port:
Fermeture
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 /********************************************************************/ /* Ouverture et Initialisation du port COM */ /********************************************************************/ /* - PARAMETRE - */ /********************************************************************/ /* .Pointeur sur la structure SerialParam */ /********************************************************************/ /* - SORTIE - */ /********************************************************************/ /* .Code d'erreur */ /* ==> _ErrorNone si tout c'est bien passe */ /* ==> _ErrorCreate si impossible d'ouvrir le port */ /* ==> _ErrorConfig si impossible de configurer le port */ /* ==> _ErrorTimeout si impossible de configurer les timeouts */ /********************************************************************/ enSerialError OpenSerialPort(SerialParam *pSerialConfig) { DCB dcbPort; // Déclaration d'une structure DCB COMMTIMEOUTS ComTimeouts; // Structure COMMTIMEOUTS enSerialError ComError=_ErrorNone; /****************************************************/ /* Ouverture Port */ /****************************************************/ hPort=CreateFile(pSerialConfig->ComPort, // Nom du port ouvert GENERIC_READ|GENERIC_WRITE, // Acces en Lecture/Ecriture 0, // Pas de partage possible du Port une fois ouvert NULL, // Pas d'heritage OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); /* Test si ouverture a réussi*/ if(hPort==INVALID_HANDLE_VALUE) { /* erreur lors de la création, port utilise par une autre ressource*/ ComError=_ErrorCreate; // if(GetLastError()==ERROR_FILE_NOT_FOUND) { /* Le port n'existe pas */ ComError=_ErrorInexistant; } } else { /* On vide les buffers d'entree/sortie */ PurgeComm(hPort, PURGE_RXABORT|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_TXCLEAR); /****************************************************/ /* Parametrage du Port */ /****************************************************/ dcbPort.DCBlength=sizeof(DCB); GetCommState(hPort,&dcbPort); // Config Actuelle dcbPort.BaudRate=pSerialConfig->BaudRate; // Débit dcbPort.fBinary=TRUE; // binary mode, no EOF check (obligatoire pour appli windows) dcbPort.fParity=FALSE; // disable parity checking dcbPort.ByteSize=pSerialConfig->DataBitsNumber;// number of bits/byte, 4-8 dcbPort.Parity=NOPARITY; // 0-4=no,odd,even,mark,space dcbPort.StopBits=ONESTOPBIT; // 0,1,2 = 1, 1.5, 2 /* Configuration du port en fonction des parametres de la struct DCB */ if(!SetCommState(hPort,&dcbPort)) { ComError=_ErrorConfigPort; } /****************************************************/ /* Parametrage des Timeouts */ /****************************************************/ GetCommTimeouts(hPort,&ComTimeouts); ComTimeouts.ReadIntervalTimeout=MAXDWORD; ComTimeouts.ReadTotalTimeoutMultiplier=0; ComTimeouts.ReadTotalTimeoutConstant=0; ComTimeouts.WriteTotalTimeoutMultiplier=10; // 10ms de timeout par octet (@1200bds 1 octet=8.33ms) ComTimeouts.WriteTotalTimeoutConstant=1000; // 500ms de timeout pour une trame (@1200bds, 1000ms = 120 octets) if(!SetCommTimeouts(hPort,&ComTimeouts)) { ComError=_ErrorConfigTimeout; } } return ComError; }
Ecriture
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 /********************************************************************/ /* Fermeture du port COM */ /********************************************************************/ void CloseSerialPort() { if(hPort!=NULL) { CloseHandle(hPort); hPort=NULL; } }
Lecture
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 enSerialError WriteSerialPortOverlapped(const char* pcharBuffer, long lgNbBytes) { enSerialError ComError=_ErrorNone; // Pas d'erreur au demarrage OVERLAPPED osWrite = {0}; DWORD dwWritten; // Create this writes OVERLAPPED structure hEvent. osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (osWrite.hEvent == NULL) { printf("// Error creating overlapped event handle."); ComError=_ErrorTx; CloseSerialPort(); } else { // Issue write. if (!WriteFile(hPort,pcharBuffer,lgNbBytes,&dwWritten,&osWrite)) { if (GetLastError()!=ERROR_IO_PENDING) { // WriteFile failed, but it isn't delayed. Report error and abort. ComError=_ErrorTx; CloseSerialPort(); } else { // Write is pending. if (!GetOverlappedResult(hPort, &osWrite, &dwWritten, TRUE)) { ComError=_ErrorTx; CloseSerialPort(); } else // Write operation completed successfully. ComError=_ErrorNone; } } else // WriteFile completed immediately. ComError=_ErrorNone; } CloseHandle(osWrite.hEvent); return ComError; }
Donc j'ai créé 2 ports virtuels connectés l'un a l'autre pour tester la communication entre mon soft et un autre de type hyperterminal. Je recois donc bien sur le terminal les trames envoyées par mon soft, par contre aucune data envoyée par le terminal n'est recue par mon soft, pourtant je resors de ma fonction Read sans code d'erreur.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 enSerialError ReadSerialPortOverlapped(char* pcharBuffer, long* plgNbBytesRead, long lgNbBytesToRead) { DWORD dwRes; BOOL fWaitingOnRead = FALSE; OVERLAPPED osReader = {0}; enSerialError ComError=_ErrorNone; // Pas d'erreur au demarrage // Create the overlapped event. Must be closed before exiting // to avoid a handle leak. osReader.hEvent=CreateEvent(NULL, // Handle cannot be inherited by child TRUE, // Create a Manual Reset FALSE, // Event Initial state = "non signaled" NULL); // Event object has no name if (osReader.hEvent == NULL) { printf("// Error creating overlapped event; abort."); return _ErrorRx; } if (!fWaitingOnRead) { // Issue read operation. if(!ReadFile(hPort,pcharBuffer,lgNbBytesToRead,plgNbBytesRead,&osReader)) { // If ReadFile return FALSE: if(GetLastError()!=ERROR_IO_PENDING) { // read not delayed by OS? ComError=_ErrorRx; // Error in communications; report it. CloseSerialPort(); } else fWaitingOnRead = TRUE; } else // ReadFile return TRUE { // read completed immediately //HandleASuccessfulRead(pcharBuffer,*plgNbBytesRead); // fonction a ecrire ComError=_ErrorNone; } } if (fWaitingOnRead) { dwRes=WaitForSingleObject(osReader.hEvent,READ_TIMEOUT); switch(dwRes) { /* Read completed. */ case WAIT_OBJECT_0: if(!GetOverlappedResult(hPort,&osReader,plgNbBytesRead,FALSE)) { // Error in communications; report it. ComError=_ErrorRx; CloseSerialPort(); } else // Read completed successfully. //HandleASuccessfulRead(pcharBuffer,*plgNbBytesRead); // fonction a ecrire ComError=_ErrorNone; // Reset flag so that another operation can be issued. fWaitingOnRead=FALSE; break; /* Read not completed, Timeout occured. */ case WAIT_TIMEOUT: // Operation isn't complete yet. fWaitingOnRead flag isn't // changed since I'll loop back around, and I don't want // to issue another read until the first one finishes. ComError=_ErrorTimeout; CloseSerialPort(); fWaitingOnRead=FALSE; break; default: // Error in the WaitForSingleObject; abort. // This indicates a problem with the OVERLAPPED structure's // event handle. ComError=_ErrorRx; CloseSerialPort(); fWaitingOnRead=FALSE; break; } } CloseHandle(osReader.hEvent); return ComError; }
J'ai donc testé en debug pour voir ce qui se passe, donc lorsque je rentre dans la fonction Read le flag "fWaitingOnRead" est a FALSE, on rentre donc dans le IF pour executer "ReadFile(hPort,pcharBuffer,lgNbBytesToRead,plgNbBytesRead,&osReader)", cette fonction renvoie toujours TRUE, que je simule l'envoi d'une trame ou non depuis l'hyperterminal avant de passer sur ReadFile. Et c'est la le probleme, lorsque je lis l'aide MSDN (ICI) il est marqué qu'en mode Overlapped, la fonction Read renvoie FALSE, ce qui permet alors de passer dans la seconde partie et de tester si oui ou non la trame a été recue avant la fin du Timeout parametré par "READ_TIMEOUT" (GetOverlappedResult(hPort,&osReader,plgNbBytesRead,FALSE)).
J'ai besoin d'utiliser ce timeout, car dans un premier temps j'avais mis en place un mode "non overlapped" qui fonctionne bien pour lecture/ecriture, sauf dans le cas ou la cible ne repondait pas (cible HS ou OFF, etc...), ce qui bloquait completement l'execution de mon programme (attente d'un octet indefiniment sur le port COM).
Depuis le debut de la semaine j'essaie en vain d'ecrire des fonctions d'ecriture/lecture operationnelles a 100%, je m'en remets donc a vous
Merci d'avance pour votre aide et conseils
Partager