Salut a tous ,

Je suis en train d'ameliorer une appli qui sert a coordonner quelques machines entre elles via le port serie. Aujourd'hui la coordination est faite en "pollant" les machines a intervalle regulier. Mis a part le fait que c'est moche, c'est aussi peu performant et peu fiable. J'ai donc entrepris d'utiliser les communications asynchrones et les evenements fournis par l'API win32.

Les status envoyes par les machines sont formates, je voudrais donc que l'appli reagisse lorsqu'elle recoit le caractere indiquant la fin de la reception, et c'est la que je bloque. Pour mes essais j'utilise le petit programme ci-dessous (attention ca pique un peu les yeux, j'ai enleve toute la gestion des erreurs pour raccourcir).

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#define BUF_SIZE 65536
#define PURGE_ALL PURGE_RXABORT|PURGE_TXABORT|PURGE_RXCLEAR|PURGE_TXCLEAR
//#define COMM_EVENTS EV_RXFLAG
#define COMM_EVENTS EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_EVENT1 | EV_EVENT2 | EV_PERR | EV_RING | EV_RLSD | EV_RX80FULL | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY

unsigned long
com_get(HANDLE *dev, char *buf, size_t len) {
    OVERLAPPED io_ov;
    unsigned long ret = 0;
    int err;

    memset(&io_ov, 0, sizeof(io_ov));
    io_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    if (!ReadFile(*dev, buf, len, NULL, &io_ov)) {
        err = GetLastError();
        if (err != ERROR_IO_PENDING) {
            fprintf(stderr,"readfile failed %d\n", err);
        } else if (!GetOverlappedResult(dev, &io_ov, &ret, TRUE)) {
            fprintf(stderr,"overlapped read failed %d\n", GetLastError());
        }
    }

    CloseHandle(io_ov.hEvent);

    return ret;
}

int 
com_nbytes(HANDLE *dev) {
    COMSTAT status;

    ClearCommError(*dev, NULL, &status);

    return status.cbInQue;
}

int
main (void) {
    COMMTIMEOUTS cto;
    DCB dcb;
    HANDLE dev;  
    OVERLAPPED ev_ov;
    char buf[BUF_SIZE];
    int nbytes, rate;
    const char *port;
    unsigned long ev;

    port= "COM2";
    rate = 9600;

    dev = CreateFile(port, 
            GENERIC_READ | GENERIC_WRITE, 
            0, 
            NULL, 
            OPEN_EXISTING, 
            FILE_FLAG_OVERLAPPED, 
            NULL);

    memset(&ev_ov, 0, sizeof(ev_ov));
    ev_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    GetCommState(dev, &dcb);

    dcb.DCBlength = sizeof(DCB);

    dcb.Parity = NOPARITY;
    dcb.fParity = FALSE;
    dcb.BaudRate = rate;
    dcb.ByteSize = 8;

    dcb.fOutX = 0;
    dcb.fInX = 0;
    dcb.fOutxCtsFlow = 0;
    dcb.fRtsControl = 0;
    dcb.fDtrControl = 0;
    dcb.fOutxDsrFlow = 0;
    dcb.fDsrSensitivity = 0;

    dcb.EvtChar = 'a';
    dcb.EofChar = '\0';

    GetCommTimeouts(dev, &cto);
    cto.ReadIntervalTimeout = 400; 
    cto.ReadTotalTimeoutMultiplier = 200;
    cto.ReadTotalTimeoutConstant = 2000;
    cto.WriteTotalTimeoutMultiplier = 200;
    cto.WriteTotalTimeoutConstant = 2000;

    PurgeComm(dev, PURGE_ALL);
    SetCommTimeouts(dev, &cto);
    SetCommState(dev,&dcb);
    SetCommMask(dev, COMM_EVENTS);

    while(1) {
        if (!WaitCommEvent(dev, &ev, &ev_ov)) {
            if (GetLastError() != ERROR_IO_PENDING) {
                fprintf(stderr, "WaitCommEvent(): GetLastError() != ERROR_IO_PENDING\n");
                break;
            }
        }

        switch (WaitForSingleObject(ev_ov.hEvent, INFINITE)) {
            case WAIT_OBJECT_0:
                if (ev & EV_BREAK)
                    fprintf(stderr, "Recv EV_BREAK\n");
                if (ev & EV_CTS)
                    fprintf(stderr, "Recv EV_CTS\n");
                if (ev & EV_DSR)
                    fprintf(stderr, "Recv EV_DSR\n");
                if (ev & EV_ERR)
                    fprintf(stderr, "Recv EV_ERR\n");
                if (ev & EV_EVENT1)
                    fprintf(stderr, "Recv EV_EVENT1\n");
                if (ev & EV_EVENT2)
                    fprintf(stderr, "Recv EV_EVENT2\n");
                if (ev & EV_PERR)
                    fprintf(stderr, "Recv EV_PERR\n");
                if (ev & EV_RING)
                    fprintf(stderr, "Recv EV_RING\n");
                if (ev & EV_RLSD)
                    fprintf(stderr, "Recv EV_RLSD\n");
                if (ev & EV_RX80FULL)
                    fprintf(stderr, "Recv EV_RX80FULL\n");
                if (ev & EV_RXCHAR)
                    fprintf(stderr, "Recv EV_RXCHAR\n");
                if (ev & EV_RXFLAG)
                    fprintf(stderr, "Recv EV_RXFLAG\n");
                if (ev & EV_TXEMPTY)
                    fprintf(stderr, "Recv EV_TXEMPTY\n");

                nbytes = com_nbytes(&dev);
                memset(buf, '\0', 1024);
                com_get(&dev, buf, nbytes < BUF_SIZE ? nbytes : BUF_SIZE);
                fprintf(stderr, "Recv: %s\n", buf);
                break;
            default:
                fprintf(stderr, "WaitForSingleObject error\n");
                break;

        }

    }

    return EXIT_SUCCESS;
}
Je pense que la logique globale est bonne puisque je n'ai aucun probleme a intercepter EV_RXCHAR. Je pourrais en fait en rester la et emuler EV_RXFLAG en utilisant memchr(buf, EvtChar, BUF_SIZE) a chaque EV_RXCHAR mais je prefererais quand meme corriger mon appli