📄 comport.c
字号:
FD_ZERO(&rfds); FD_SET(com->read_fd, &rfds); tv.tv_sec = timeoutMS / 1000L; tv.tv_usec = (timeoutMS % 1000L) * 1000L; select(com->read_fd + 1, &rfds, 0, 0, &tv); if (!FD_ISSET(com->read_fd, &rfds)) { return 0; } // timeout /* return number of available bytes */ // since the above did not timeout, we will have at least 1 byte available.#ifdef BYTES_AVAIL_IOCTL int nBytesAvail; int request = BYTES_AVAIL_IOCTIL_REQUEST; int status = ioctl(com->read_fd, request, &nBytesAvail); return (status >= 0)? nBytesAvail : 1;#else return 1;#endif }#endif // defined(TARGET_WINCE)// ----------------------------------------------------------------------------/* read specified number of bytes from ComPort */#if defined(TARGET_WINCE)// not yet implemented#else#define MAX_VTIME_MS 25500Lint comPortRead(ComPort_t *com, UInt8 *buf, int len, long timeoutMS){ // Possible (non-exclusive) 'errno' values: // EIO [ 5] input/output error // ENODEV [19] no such device // ETIME [63] timeout /* read nothing? */ if (len <= 0) { logINFO(LOGSRC,"Empty read buffer"); return 0; } /* valid com port? */ if (!comPortIsOpen(com)) { if (buf) { buf[0] = 0; } errno = ENODEV; logINFO(LOGSRC,"ComPort not open"); return -1; } /* starting timestamp */ struct timeval startTime; utcGetTimestamp(&startTime); /* read bytes */ int n = 0; for (;n < len;) { /* timeout? */ long tms = timeoutMS; if (tms >= 0L) { tms -= utcGetDeltaMillis(0, &startTime); // subtract elapsed time if ((tms <= 0L) && (com->push <= 0) && (com->avail <= 0)) { // timeout if (buf) { buf[n] = 0; } errno = ETIME; // not necessary, since we're returning a value >= 0 com->error = COMERR_TIMEOUT; return n; } } /* poll/read */ if (com->push > 0) { /* use previously pushed char */ com->last = (UInt8)com->push; com->push = -1; // clear push if (buf) { buf[n] = com->last; } n++; } else { /* poll (check for available data) */ //logDEBUG(LOGSRC,FTN, "avail=%d, tms=%ld", com->avail, tms); if ((com->avail <= 0) && (tms > 0L)) { if (COMOPT_IsVTimeout(com)) { // Note: 'tms' will be rounded up to the next highest 100ms, and // will be clipped at 25500 ms (max value for VTIME). if (!_comPortSetVtimeMS(com, tms)) { // ENODEV/EIO is likely here (for 'rfcomm0') int sv_errno = errno; logWARNING(LOGSRC,"ComPort error %s : [%d] %s", com->dev, sv_errno, strerror(sv_errno)); if (buf) { buf[n] = 0; } errno = sv_errno; return -1; } } else { // wait for available data int avail = comPortGetAvail(com, tms); if (avail <= 0) { // timeout/error if (buf) { buf[n] = 0; } errno = ETIME; com->error = COMERR_TIMEOUT; // may be EOF return n; } com->avail = avail; } } else { if (COMOPT_IsVTimeout(com)) { // Either data is available for reading (without blocking), or the // caller wishes this function to block forever (ie. no timeout) // However, set a minimum timeout anyway to allow us to keep track // of when the port is closed (externally). We'll still not return // until the number of requested bytes have been read. if (!_comPortSetVtimeMS(com, MAX_VTIME_MS)) { // ENODEV/EIO is likely here (for 'rfcomm0') int sv_errno = errno; logWARNING(LOGSRC,"ComPort error %s : [%d] %s", com->dev, sv_errno, strerror(sv_errno)); if (buf) { buf[n] = 0; } errno = sv_errno; return -1; } } else { //logDEBUG(LOGSRC,FTN, "blocking wait (avail = %d)", com->avail); } } /* read 1 byte */ // Either ... // - VTIME is in effect and we'll possibly be timing out, or // - a character available (avail > 0) and it will be returned, or // - we will be blocking here until a character becomes available, or // - we will get an error. struct timeval readTS; utcGetTimestamp(&readTS); errno = 0; // clear 'errno' int r = read(com->read_fd, &com->last, 1); // VTIME may be in effect if (r < 0) { // error: com port closed? if (buf) { buf[n] = 0; } // terminate buffer com->avail = 0; com->error = COMERR_EOF; // error already in 'errno' logWARNING(LOGSRC,"ComPort error %s : [%d] %s", com->dev, com->error, strerror(com->error)); return -1; } else if (r == 0) { // A read length of 0 can mean an EOF, or a TIMEOUT if VTIME is in effect. //int readErrno = errno; //logDEBUG(LOGSRC,"Read EOF/TIMEOUT? %s: [%d]%s", com->dev, readErrno, strerror(readErrno)); com->avail = 0; // in any case nothing is available if (COMOPT_IsVTimeout(com)) { long vtimeMS = _comPortGetVtimeMS(com); long deltaMS = utcGetDeltaMillis(0, &readTS) + 50L; // allow 50ms window // Allow a margin on the timeout window when checking for EOF. // If the elapsed time is less than what the timeout was set for, then // an EOF is likely, but lets be sure of it by setting a wide enough // time window. The worst case is that the EOF occurred close enough // to the expired timeout that we may try to read of a closed file // descriptor again. Hopefully, however, the next time around we will // again get an EOF error right away and return accordingly. if (deltaMS < vtimeMS) { // this means that we were interrupted before timeout occured, EOF likely. //logDEBUG(LOGSRC,"VTIME (%ld<%ld) ... [%s]", deltaMS, vtimeMS, com->dev); if (buf) { buf[n] = 0; } com->error = COMERR_EOF; errno = ENODEV; return -1; } else { // assume timeout, continue loop } } else { // assume an EOF if (buf) { buf[n] = 0; } com->error = COMERR_EOF; errno = ENODEV; logWARNING(LOGSRC,"ComPort error %s (EOF?) : [%d] %s", com->dev, com->error, strerror(com->error)); return -1; } } else if (r == 1) { if (buf) { buf[n] = com->last; } n++; if (com->avail > 0) { com->avail--; } // decrement available if (COMOPT_IsEcho(com)) { // perform the following iff ECHO is on if (com->last == KEY_RETURN) { // follow CR with LF comPortWrite(com, "\r\n", 2); } else if (KEY_IsBackspace(com->last) && COMOPT_IsBackspace(com)) { // single character backspace comPortWrite(com, "\b \b", 3); } else if ((com->last == KEY_CONTROL_D) && COMOPT_IsBackspace(com)) { // backspace over all that we've just entered for (; n > 1; n--) { comPortWrite(com, "\b \b", 3); } if (buf) { buf[0] = com->last; } n = 1; } else if (com->last == KEY_ESCAPE) { if (!COMOPT_IgnoreEscape(com)) { // echo escape character comPortWrite(com, &com->last, 1); } } else { // echo simple character comPortWrite(com, &com->last, 1); } } if (COMOPT_IsLogDebug(com) && com->logger) { (*com->logger)(&com->last,1); } } } } // 'len' bytes read return n;}#endif // defined(TARGET_WINCE)/* read single character */#if defined(TARGET_WINCE)int comPortReadChar(ComPort_t *com, long timeoutMS){ // currently, 'timeoutMS' is ignored if (com) { if (com->push >= 0) { int ch = com->push; com->push = -1; return ch; } else { DWORD readCnt; unsigned char ch; BOOL ok = ReadFile(com->portId, &ch, 1, &readCnt, NULL); if (!ok) { // error/timeout? errno = GetLastError(); com->error = COMERR_EOF; logERROR(LOGSRC,"ReadFile error[timeout?]: %d", errno); return -1; } else if (readCnt != 1) { // eof/timeout? errno = GetLastError(); // will probably always be ERROR_SUCCESS if (errno == ERROR_SUCCESS) { // assume timeout com->error = COMERR_TIMEOUT; return -1; } else if (errno == ERROR_INVALID_PARAMETER) { logWARNING(LOGSRC,"ReadFile error[ERROR_INVALID_PARAMETER]: %d", errno); com->error = COMERR_GENERAL; return -1; } else { // assume eof logWARNING(LOGSRC,"ReadFile error: %d", errno); com->error = COMERR_EOF; return -1; } } else { return (int)ch & 0xFF; } } } else { return -1; }}#else// Use of this function is discouraged because examination of 'errno' is// required to differentiate between an EOF and TIMEOUT.int comPortReadChar(ComPort_t *com, long timeoutMS){ UInt8 ch; int len = comPortRead(com, &ch, 1, timeoutMS); if (len < 0) { // error (error in 'errno') return -1; } else if (len == 0) { // timeout errno = ETIME; return -1; } else { return (int)ch; }}#endif // defined(TARGET_WINCE)/* read a single byte (return '0' if error) */UInt8 comPortGetByte(ComPort_t *com, long timeoutMS){ int ch = comPortReadChar(com, timeoutMS); return (ch < 0)? 0 : (UInt8)ch;}// ----------------------------------------------------------------------------/* read bytes from ComPort until '\n', '\r', or until 'maxLen' reached */#if defined(TARGET_WINCE)int comPortReadLine(ComPort_t *com, char *buf, int maxLen, long timeoutMS){ if (maxLen <= 0) { return 0; } else if (comPortIsOpen(com)) { int i; errno = ERROR_SUCCESS; com->error = COMERR_NONE; for (i = 0; i < (maxLen - 1);) { DWORD readCnt; char ch = 0; BOOL ok; if (com->push >= 0) { ch = (char)com->push; com->push = -1; readCnt = 1; ok = TRUE; } else { ok = ReadFile(com->portId, &ch, 1, &readCnt, NULL); } if (!ok) { // error/timeout? errno = GetLastError(); com->error = COMERR_EOF; logERROR(LOGSRC,"ReadFile error(timeout?): %d", errno); if (buf) { buf[i] = 0; } return -1; } else if (readCnt == 1) { ch &= 0x7F; // mask to ASCII //*DEBUG*/fprintf(stderr, "%c", (char)ch); // logging: ignore returned error code if ((ch == '\n') || (ch == '\r')) { if (i > 0) { if (buf) { buf[i] = 0; } return i; } else { // The buffer is curently empty // just ignore this character and continue } } else if (ch > ' ') { if (buf) { buf[i] = ch; } i++; } else if (ch == ' ') { // special handling for spaces? if (buf) { buf[i] = ch; } i++; } else { // everything else is ignore for readLine } } else { // eof/timeout? if (buf) { buf[i] = 0; } errno = GetLastError(); // will probably always be ERROR_SUCCESS if (errno == ERROR_SUCCESS) { // assume timeout com->error = COMERR_TIMEOUT; return 0; } else { // assume eof logWARNING(LOGSRC,"ReadFile error: %d", errno); com->error = COMERR_EOF; return -1; } } } // should not reach here if (buf) { buf[maxLen - 1] = 0; } return maxLen - 1; } else { if (buf) { buf[0] = 0; } com->error = COMERR_GENERAL; return -1; }}#elseint comPortReadLine(ComPort_t *com, char *buf, int maxLen, long timeoutMS){ return _comPortReadLine(com, buf, 0, maxLen, timeoutMS);}#endif // defined(TARGET_WINCE)#if defined(TARGET_WINCE)// not sup
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -