Probleme communication sur port COM (Overlapped I/O)
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 :( :bug: (les questions sont en bas du post :P )
Edit: Je code avec Code::Blocks / OS: Windows XP
le .h
Code:
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); |
Je vous colle ici les parties de code du .c
Ouverture/Configuration du port:
Code:
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;
} |
Fermeture
Code:
1 2 3 4 5 6 7 8 9 10 11
| /********************************************************************/
/* Fermeture du port COM */
/********************************************************************/
void CloseSerialPort()
{
if(hPort!=NULL)
{
CloseHandle(hPort);
hPort=NULL;
}
} |
Ecriture
Code:
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;
} |
Lecture :( :bug:
Code:
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;
} |
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.
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 :oops:
Merci d'avance pour votre aide et conseils ;)