Bonjour,
Je travaille dans le domaine des transaction électronique et je cherche à résoudre un problème de communication entre un terminal de paiement et une caisse.
Cette communication se fait au travers soit d'un port COM soit au travers d'un port USB et fonctionne la plupart du temps. Sauf que parfois et de façon appartement aléatoire le PC semble devenir incapable de recevoir la reponse du terminal ( Je tiens à préciser que je travaille sur le terminal et sur le PC , car j'ai participer au développement de l'application du terminal et de la DLL PC qui gère les coms ).
Voici le code utiliser :
- Pour ouvrir le port
- La fonction de 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
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 int OpenCom (unsigned char Com, unsigned long Baud, unsigned char Parity, unsigned char StopBits, unsigned char DataBits) { int Retour; BOOL fRet; DCB dcb ; DWORD cr; char NomEvenement[15]; Retour=CZT_ERREUR; if ((Com<0) || (Com>20)) return Retour; sprintf(NomEvenement,"%s","EVENT_EPOS"); EvenementCom = CreateEvent(0,TRUE,FALSE,NomEvenement); if (!(cr=GetLastError())) { Overlapped.hEvent = EvenementCom; Overlapped.Offset = 0; Overlapped.OffsetHigh = 0; idComDev[Com]=CreateFile( (LPCTSTR)tCom[Com], GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE , 0, // exclusive access NULL, // no security attrs OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // overlapped I/O NULL ); if ( idComDev[Com] != INVALID_HANDLE_VALUE ) { // get any early notifications // setup device buffers SetupComm( idComDev[Com] , 4096, 4096 ) ; // purge any information in the buffer PurgeComm( idComDev[Com], PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ; // set up for overlapped I/O CommTimeOuts[Com].ReadIntervalTimeout = 0 ; CommTimeOuts[Com].ReadTotalTimeoutMultiplier = 0 ; CommTimeOuts[Com].ReadTotalTimeoutConstant = 1000 ; CommTimeOuts[Com].WriteTotalTimeoutMultiplier = 0; CommTimeOuts[Com].WriteTotalTimeoutConstant = 0; fRet=SetCommTimeouts( idComDev[Com], &CommTimeOuts[Com] ) ; if (Com<8) { dcb.DCBlength = sizeof( DCB ) ; fRet=GetCommState( idComDev[Com], &dcb ) ; dcb.BaudRate = Baud; dcb.ByteSize = DataBits ; dcb.Parity = Parity; dcb.StopBits = StopBits; dcb.fOutxCtsFlow = FALSE; dcb.fOutxDsrFlow = FALSE; dcb.fDtrControl = DTR_CONTROL_DISABLE; dcb.fTXContinueOnXoff = TRUE; dcb.fOutX = FALSE; //Enable output X-ON/X-OFF dcb.fInX = FALSE; // Enable input X-ON/X-OFF dcb.fRtsControl = RTS_CONTROL_DISABLE; // setup hardware flow control fRet=SetCommState( idComDev[Com], &dcb ); } else { // Configuration .... // Omit the call to SetupComm to use the default queue sizes....???... fRet=GetCommState( idComDev[Com], &dcb ) ; dcb.ByteSize = 8; // setup hardware flow control fRet=SetCommState( idComDev[Com], &dcb ); } if (fRet==TRUE) { Retour=CZT_OK; } else { ConcertLog_AddEvent("fRet incorrect"); CloseHandle(EvenementCom); } } else { CloseHandle(EvenementCom); ConcertLog_AddEvent("Invalid handle"); } } else { ConcertLog_AddEvent("Get last error found"); } return Retour; }
et la fonction d'écriture
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 unsigned short PCharIn(unsigned char Com,unsigned char *CarLu,unsigned long Timeout) { unsigned short Retour; DWORD nBytesRead; DWORD ret=0; CommTimeOuts[Com].ReadTotalTimeoutConstant = Timeout; SetCommTimeouts( idComDev[Com], &CommTimeOuts[Com] ) ; Overlapped.hEvent = EvenementCom; Overlapped.Offset = 0; Overlapped.OffsetHigh = 0; ReadFile(idComDev[Com],CarLu,1,&nBytesRead , &Overlapped); do { } while ((ret=WaitForSingleObject(EvenementCom,100)) != WAIT_OBJECT_0); if (GetOverlappedResult(idComDev[Com],&Overlapped,&nBytesRead,TRUE)==TRUE) { if (nBytesRead==0) { Retour = CZT_TIMEOUT; } else { Retour=CZT_OK; } } else { Retour=CZT_ERREUR; } ResetEvent(EvenementCom); return(Retour); }
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 unsigned short PCharOut(unsigned char Com,unsigned char CarEcrit) { unsigned short Retour; DWORD nBytesWritten; Overlapped.hEvent = EvenementCom; Overlapped.Offset = 0; Overlapped.OffsetHigh = 0; WriteFile(idComDev[Com], &CarEcrit, 1, &nBytesWritten, &Overlapped); while (WaitForSingleObject(EvenementCom,100) != WAIT_OBJECT_0) if (GetOverlappedResult(idComDev[Com],&Overlapped,&nBytesWritten,TRUE)==TRUE) { Retour=CZT_OK; } else { PurgeComm( idComDev[Com], PURGE_TXABORT | PURGE_TXCLEAR ) ; Retour = CZT_ERREUR; } ResetEvent(EvenementCom); return(Retour); }
De façon simplifiée, le protocole entre les deux fonctionne ainsi :
Émission d'une requête par la caisse :
Caisse ----> Terminal : ENQ
Caisse <---- Terminal : ACK
Caisse ------> Terminal : Requete
Caisse <---- Terminal : ACK
Caisse ----> Terminal : EOT
À ce moment le terminal fait son travail et la caisse se met dans un delay d'attente de 90s
Normalement , la réponse du terminal doit fonctionner comme ça
Caisse <---- Terminal : ENQ
Caisse ----> Terminal : QCK
Caisse <----- Terminal : Reponse
Caisse -----> Terminal : ACK
Caisse <---- Terminal : EOT
Tous fonctionne dans plus de 90% des cas , sauf parfois ou le terminal envoie le ENQ mais la DLL ne semble pas le recevoir ( La logique est d'envoyer un ENQ puis au bout de 600 ms en absence
de réponse envoyer un EOT , attendre un peu puis recommence la séquence et cela 3 fois) , ce qui finit par provoquer un échec.
Le pire c'est que quelque seconde après si la caisse tente d'envoyer une nouvelle requête , je trouve tous la séquence dans le buffer de réponse ( ENQ , EOT , ENQ, EOT, ENQ, EOT)
Après des jours de rechercher et d'analyse de log sans le moindre résultat , j’espère que quelqu'un pourra m'aider a résoudre ce casse tête
Il semble que pour une raison ou une autre mes octets venant du terminal soit bloquer avant d'arriver a la DLL et cela de façon aléatoire. Pour information , si on tente une nouvelle requête sans attendre après un échec , elle choura aussi mais cette fois dans l'autre sens , la DLL indiquant l'envoie et le terminal la non réception. Ce qui me fait penser que c'est peut etre lier au driver Windows ou a un problème Hardware
Est-ce que quelqu'un aurait déjà vu un truc semblable ou aurez une piste ou une idée car la moi je commence a manquer d’idée
Merci D'avance
Partager