I am trying to write a simple serial port library that has the same lowest-common-denominator interface under both Windows and Linux. I developed it under wine using mingw32 - i want my apps that use it to work under both windows and linux (these are command-line apps only).
i noticed that wine does not seem to report errors from GetOverLapped.. and Wait..Object in a way that makes sense. By ignoring errors, and just looking at the dwRead result, i got it to work.
my attempt at a posix-like read function is below (the linux version follows further down)
best wishes
-paul
---------
int serial_port_read (struct serial_port *p, unsigned char *buf, int buf_len, int milli_timeout) { static int c = 0; DWORD dwStart, dwRead, r; int l, total = 0; dwStart = GetTickCount (); while (buf_len > 0) { l = serial_port_chars_avail (p); if (l < 0) return total > 0 ? total : SERIAL_PORT_ERROR; if (l == 0 && GetTickCount () - dwStart >= milli_timeout) return total > 0 ? total : SERIAL_PORT_TIMEOUT; /* Like POSIX read(), we return without blocking if we have read at least one character: */ if (l == 0 && total >= 1) return total; /* Read minimum of one character, and a maximum of buf_len characters: */ CLIP (l, 1, buf_len); dwRead = 0; if (!ReadFile (p->hComm, buf, l, &dwRead, &p->osRead)) { if ((r = GetLastError ()) == ERROR_IO_PENDING) { dwRead = 0; GetOverlappedResult (p->hComm, &p->osRead, &dwRead, TRUE); } } total += dwRead; buf_len -= dwRead; buf += dwRead; } return total; }
------------
int serial_port_read (struct serial_port *p, unsigned char *buf, int buf_len, int milli_timeout) { int c; struct timeval tv; fd_set rd; if (!buf_len) return 0; FD_ZERO (&rd); FD_SET (p->fd, &rd); switch (select (p->fd + 1, &rd, NULL, NULL, milli_timeout < 0 ? NULL : (tv.tv_sec = milli_timeout / 1000, tv.tv_usec = milli_timeout % 1000, &tv))) { case 1: c = read (p->fd, buf, buf_len); if (!c) { p->error = 0; return SERIAL_PORT_HANGUP; } if (c < 0) { p->error = errno; return SERIAL_PORT_ERROR; } return c; case 0: return SERIAL_PORT_TIMEOUT; default: p->error = errno; return SERIAL_PORT_ERROR; } }