#include #include #include #include "..\com0com\include\cncext.h" /////////////////////////////////////////////////////////////// static void TraceLastError(const char *pFmt, ...) { DWORD err = GetLastError(); va_list va; va_start(va, pFmt); vfprintf(stderr, pFmt, va); va_end(va); fprintf(stderr, " ERROR %s (%lu)\n", strerror(err), (unsigned long)err); } /////////////////////////////////////////////////////////////// static BOOL myGetCommState(HANDLE hC0C, DCB *dcb) { dcb->DCBlength = sizeof(*dcb); if (!GetCommState(hC0C, dcb)) { TraceLastError("GetCommState()"); return FALSE; } return TRUE; } static BOOL mySetCommState(HANDLE hC0C, DCB *dcb) { if (!SetCommState(hC0C, dcb)) { TraceLastError("SetCommState()"); return FALSE; } return TRUE; } /////////////////////////////////////////////////////////////// static HANDLE OpenC0C(LPCTSTR path) { HANDLE hC0C = CreateFile(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (hC0C == INVALID_HANDLE_VALUE) { printf("CreateFile('%s') ERROR\n", path); return INVALID_HANDLE_VALUE; } DCB dcb; if (!myGetCommState(hC0C, &dcb)) { CloseHandle(hC0C); return INVALID_HANDLE_VALUE; } dcb.BaudRate = CBR_19200; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; dcb.fOutxCtsFlow = TRUE; dcb.fOutxDsrFlow = FALSE; dcb.fDsrSensitivity = TRUE; dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fOutX = FALSE; dcb.fInX = FALSE; dcb.XonChar = 0x11; dcb.XoffChar = 0x13; dcb.fParity = FALSE; dcb.fNull = FALSE; dcb.fAbortOnError = FALSE; dcb.fErrorChar = FALSE; if (!mySetCommState(hC0C, &dcb)) { CloseHandle(hC0C); return INVALID_HANDLE_VALUE; } COMMTIMEOUTS timeouts; if (!GetCommTimeouts(hC0C, &timeouts)) { printf("GetCommTimeouts() ERROR\n"); CloseHandle(hC0C); return INVALID_HANDLE_VALUE; } timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; timeouts.ReadTotalTimeoutConstant = MAXDWORD - 1; timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = 0; if (!SetCommTimeouts(hC0C, &timeouts)) { printf("SetCommTimeouts() ERROR\n"); CloseHandle(hC0C); return INVALID_HANDLE_VALUE; } printf("Open '%s' - OK\n", path); return hC0C; } /////////////////////////////////////////////////////////////// struct LsrMstEscape { LsrMstEscape(BYTE _escapeChar) : escapeChar(_escapeChar) { Reset(); } void Do(const char *pBuf, DWORD len); int State() const { return state; } private: void Reset() { state = subState = 0; } void Print(char ch); BYTE escapeChar; int state; BYTE code; int subState; UCHAR data[sizeof(ULONG)]; }; void LsrMstEscape::Print(char ch) { int chr = ch & 0xFF; if (isprint(chr) && chr != '\\' && chr != '<' && chr != '>') printf("%c", chr); else printf("\\x%2.2X", chr); } void LsrMstEscape::Do(const char *pBuf, DWORD len) { for (; len ; len--) { char ch = *pBuf++; switch (state) { case 0: break; case 1: code = ch; state++; case 2: switch (code) { case SERIAL_LSRMST_ESCAPE: Print(escapeChar); Reset(); break; case SERIAL_LSRMST_LSR_DATA: if (subState == 0) { subState++; } else if (subState == 1) { printf("", ch & 0xFF); Reset(); } else { printf("", subState); Reset(); } break; case SERIAL_LSRMST_LSR_NODATA: if (subState == 0) { subState++; } else if (subState == 1) { printf("", ch & 0xFF); Reset(); } else { printf("", subState); Reset(); } break; case SERIAL_LSRMST_MST: if (subState == 0) { subState++; } else if (subState == 1) { printf("", ch & 0xFF); Reset(); } else { printf("", subState); Reset(); } break; case C0CE_INSERT_RBR: if (subState == 0) { subState++; } else if (subState >= 1 && subState < (sizeof(ULONG) + 1)) { data[subState - 1] = ch; if (subState < sizeof(ULONG)) { subState++; } else { printf("", (long)*(ULONG *)data); Reset(); } } else { printf("", subState); Reset(); } break; case C0CE_INSERT_RLC: if (subState == 0) { subState++; } else if (subState == 1) { printf("", ch & 0xFF); Reset(); } else { printf("", subState); Reset(); } break; default: printf("", ch & 0xFF, subState); Reset(); break; } continue; default: printf("", state); Reset(); } if (ch == escapeChar) { state = 1; continue; } Print(ch); } } /////////////////////////////////////////////////////////////// BOOL GetLsrMstExtCaps(HANDLE hC0C, ULONG *pCaps) { BYTE inBufIoctl[sizeof(UCHAR) + C0CE_SIGNATURE_SIZE + sizeof(ULONG)]; inBufIoctl[0] = 0; // disable inserting memcpy(inBufIoctl + sizeof(UCHAR), C0CE_SIGNATURE, C0CE_SIGNATURE_SIZE); *(ULONG *)(inBufIoctl + sizeof(UCHAR) + C0CE_SIGNATURE_SIZE) = C0CE_INSERT_IOCTL_CAPS; BYTE outBuf[C0CE_SIGNATURE_SIZE + sizeof(ULONG)]; DWORD returned; if (!DeviceIoControl(hC0C, IOCTL_SERIAL_LSRMST_INSERT, inBufIoctl, sizeof(inBufIoctl), outBuf, sizeof(outBuf), &returned, NULL)) { TraceLastError("IOCTL_SERIAL_LSRMST_INSERT"); return FALSE; } if (returned >= (C0CE_SIGNATURE_SIZE + sizeof(ULONG)) && memcmp(outBuf, C0CE_SIGNATURE, C0CE_SIGNATURE_SIZE) == 0) { *pCaps = *(ULONG *)(outBuf + C0CE_SIGNATURE_SIZE); printf("The driver supports 0x%lX extended LSRMST_INSERT capabilities.\n", (long)*pCaps); return TRUE; } printf("The driver does not support extended LSRMST_INSERT capabilities.\n"); return FALSE; } /////////////////////////////////////////////////////////////// void InC0C(HANDLE hC0C) { Sleep(5000); // for testing C0CE_INSERT_IOCTL_RXCLEAR ULONG optsWanted = (C0CE_INSERT_IOCTL_GET| C0CE_INSERT_IOCTL_RXCLEAR| C0CE_INSERT_ENABLE_LSR| C0CE_INSERT_ENABLE_MST| C0CE_INSERT_ENABLE_RBR| C0CE_INSERT_ENABLE_RLC); ULONG opts; ULONG caps; if (GetLsrMstExtCaps(hC0C, &caps)) { opts = (caps & optsWanted); } else { opts = C0CE_INSERT_ENABLE_LSR|C0CE_INSERT_ENABLE_MST; // standard functionality } if (opts == optsWanted) printf("OK, will do 0x%lX.\n", (long)opts); else printf("FAIL, will do 0x%lX instead 0x%lX.\n", (long)opts, (long)optsWanted); char escapeChar = 'a'; BYTE inBufIoctl[sizeof(UCHAR) + C0CE_SIGNATURE_SIZE + sizeof(ULONG)]; inBufIoctl[0] = escapeChar; memcpy(inBufIoctl + sizeof(UCHAR), C0CE_SIGNATURE, C0CE_SIGNATURE_SIZE); *(ULONG *)(inBufIoctl + sizeof(UCHAR) + C0CE_SIGNATURE_SIZE) = opts; DWORD lenOutBufIoctl = 0; BYTE *pOutBufIoctl = NULL; if (opts & C0CE_INSERT_IOCTL_GET) { if (opts & C0CE_INSERT_ENABLE_LSR) lenOutBufIoctl += sizeof(UCHAR)*2 + sizeof(UCHAR); if (opts & C0CE_INSERT_ENABLE_MST) lenOutBufIoctl += sizeof(UCHAR)*2 + sizeof(UCHAR); if (opts & C0CE_INSERT_ENABLE_RBR) lenOutBufIoctl += sizeof(UCHAR)*2 + sizeof(ULONG); if (opts & C0CE_INSERT_ENABLE_RLC) lenOutBufIoctl += sizeof(UCHAR)*2 + sizeof(UCHAR)*3; if (lenOutBufIoctl) pOutBufIoctl = new BYTE[lenOutBufIoctl]; } DWORD returned; if (!DeviceIoControl(hC0C, IOCTL_SERIAL_LSRMST_INSERT, inBufIoctl, sizeof(inBufIoctl), pOutBufIoctl, lenOutBufIoctl, &returned, NULL)) { TraceLastError("IOCTL_SERIAL_LSRMST_INSERT"); return; } LsrMstEscape escape(escapeChar); escape.Do((char *)pOutBufIoctl, returned); if (pOutBufIoctl) delete [] pOutBufIoctl; printf("\n"); if (escape.State() != 0) printf("ERROR: returned=%lu escape=%u\n", (long)returned, escape.State()); printf("---\n"); for (;;) { char cbuf[123]; DWORD done; if (!ReadFile(hC0C, cbuf, sizeof(cbuf), &done, NULL)) { TraceLastError("ReadFile()"); return; } escape.Do(cbuf, done); } } /////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { if (argc < 2) { printf("Usage:\n"); printf(" %s \\\\.\\\n", argv[1]); return 1; } HANDLE hC0C = OpenC0C(argv[1]); if (hC0C == INVALID_HANDLE_VALUE) return 2; InC0C(hC0C); CloseHandle(hC0C); return 0; }