/* Serial sending application */ /* Written by Mike Miller */ #include #include #include #include #include typedef struct _LOGSER_CFG { int port; DWORD baudRate; BYTE parity; BYTE byteSize; BYTE stopBits; } LOGSER_CFG; void usage(_TCHAR * argv[]); void print_header(LOGSER_CFG cfg); int parse_arguments(int argc, _TCHAR * argv[], LOGSER_CFG * cfg); void error(HANDLE hCom, const char *fmt, ...); int _tmain(int argc, _TCHAR* argv[]) { HANDLE hCom = INVALID_HANDLE_VALUE; char com_name[11] /* \\.\.COMXX plus a null */ ; DCB dcb; DWORD bytesWritten; LOGSER_CFG cfg; int stat; stat = parse_arguments(argc, argv, &cfg); if (stat != 0) { return stat; } print_header(cfg); sprintf(com_name, "\\\\.\\COM%d", cfg.port); /* Actual string should be \\.\COM */ printf("| Opening port %d (as %s)...\t|\n", cfg.port, com_name); hCom = CreateFile(com_name, GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, NULL, NULL); if (hCom == INVALID_HANDLE_VALUE) { error(hCom, "| Error opening %s!\t\t|\n", com_name); return 1; } printf("| handle=0x%02X\t\t\t\t|\n", (INT_PTR) hCom); /* Configure the serial port */ memset(&dcb, 0, sizeof(dcb)); dcb.DCBlength = sizeof(dcb); GetCommState(hCom, &dcb); dcb.BaudRate = cfg.baudRate; dcb.ByteSize = cfg.byteSize; dcb.Parity = cfg.parity; dcb.StopBits = cfg.stopBits; dcb.fBinary = FALSE; dcb.fParity = TRUE; if (!SetCommState(hCom, &dcb)) { error(hCom, "| Unable to set Comm Port config.\t|\n| Error was 0x%08X\t\t\t|\n", GetLastError()); return 1; } /* Configure timeouts */ COMMTIMEOUTS timeouts; /* No timeouts */ timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; timeouts.ReadTotalTimeoutConstant = MAXDWORD - 1; timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = 0; if (!SetCommTimeouts(hCom, &timeouts)) { printf("| Unable to set Comm Port timeouts.\t|\n| Error was 0x%08X\t\t\t|\n", GetLastError()); return 1; } printf("\\=======================================/\n"); /* Everyone's ready. Let's roll */ /* Read byte-by-byte, and print */ /* We do a flush once per line. Not sure how much it helps... */ /* This sounds inefficient, but it seems to work relatively well (<1% CPU on my test PC) */ char * byte; char bytes[255]; while (byte = fgets(bytes,sizeof(bytes),stdin)) { WriteFile(hCom,byte,strlen(byte),&bytesWritten, NULL); } /* We never reach this point, and so we rely on windows to close the COM port & output file */ /* The code is here, just in case, but is commented out to remove the warning */ CloseHandle(hCom); return 0; } void usage(_TCHAR * argv[]) { printf("Serial Sender by Mike Miller\n"); printf("Sends stdin to the serial port\n\n"); printf("Usage:\t%s \n", argv[0]); printf("\tCOMM port should be specified in decimal (Supported ports: 1-32)\n"); printf("\tTo configure the baud rate, use -b (default is 115200)\n"); printf("\tTo configure parity, use -p followed by the config (default is 8N1)\n"); return; } int parse_arguments(int argc, _TCHAR * argv[], LOGSER_CFG * cfg) { if (argc < 2) { usage(argv); return 1; } /* The first argument must be the port. Flags can come in any order after that */ sscanf(argv[1], "%d", &(cfg->port)); if ((cfg->port < 1) || (cfg->port > 32)) { usage(argv); return 1; } cfg->baudRate = CBR_115200; cfg->byteSize = 8; cfg->parity = NOPARITY; cfg->stopBits = ONESTOPBIT; // __asm int 3h; if (argc != 2) /* We have flags */ for (int cur_arg = 2; cur_arg < argc; cur_arg++) { if (0 == strncmp(argv[cur_arg], "-b", 2)) { /* baudRate */ if (!sscanf(argv[++cur_arg], "%d", &(cfg->baudRate))) { printf("Invalid baud rate %s\n",argv[cur_arg]); return 1; } } else if (0 == strncmp(argv[cur_arg], "-p", 2)) { /* baudRate */ int foo; char p; char s; char bs; foo = sscanf(argv[++cur_arg], "%c%c%c",&bs,&p,&s); cfg->byteSize = (BYTE) atoi(&bs); if (foo == 3) { switch (p) { case 'N': case 'n': cfg->parity=(BYTE) NOPARITY; break; case 'E': case 'e': cfg->parity=(BYTE) EVENPARITY; break; case 'O': case 'o': cfg->parity=(BYTE) ODDPARITY; break; case 'M': case 'm': cfg->parity=(BYTE) MARKPARITY; break; case 'S': case 's': cfg->parity=(BYTE) SPACEPARITY; break; default: printf("Unknown Parity type: %c\n",p); usage(argv); return 1; } switch (s) { case '1': cfg->stopBits=(BYTE) ONESTOPBIT; break; case '2': cfg->stopBits=(BYTE) TWOSTOPBITS; break; default: printf("Unknown Stop Bits: %d\n",s); usage(argv); return 1; } } else { printf("Unknown parity value: %s\n",argv[cur_arg]); usage(argv); return 1; } } } return 0; } void print_header(LOGSER_CFG cfg) { char parity = '?'; char stopbits = '?'; switch (cfg.parity) { case NOPARITY: parity = 'N'; break; case EVENPARITY: parity = 'E'; break; case ODDPARITY: parity = 'O'; break; case MARKPARITY: parity = 'M'; break; case SPACEPARITY: parity = 'S'; break; } switch (cfg.stopBits) { case ONESTOPBIT: stopbits = '1'; break; case TWOSTOPBITS: stopbits = '2'; break; } printf("/=======================================\\\n"); printf("| Serial Sender by Mike Miller |\n"); printf("| Easily send data to a serial port |\n"); printf("| Bitrate: %-6d Parity: %d%c%c |\n",cfg.baudRate, cfg.byteSize, parity,stopbits); printf("|=======================================|\n"); return; } void error(HANDLE hCom, const char *fmt, ...) { va_list argp; va_start(argp, fmt); vprintf(fmt, argp); va_end(argp); printf("\\=======================================/\n"); CloseHandle(hCom); }