Last active
July 22, 2023 14:25
-
-
Save DavidEGrayson/5e5bb95ae291cdfdffd4 to your computer and use it in GitHub Desktop.
Simple Windows C program that connects to a serial port and prints out events from it, such as ring signals.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Lots of code was copied from https://msdn.microsoft.com/en-us/library/ff802693.aspx#serial_topic3 | |
#include <assert.h> | |
#include <windows.h> | |
#include <stdio.h> | |
#include <stdbool.h> | |
void ReportStatusEvent(HANDLE port, DWORD s) | |
{ | |
printf("event 0x%lx", s); | |
if (s & EV_ERR) { | |
DWORD errors; | |
COMSTAT stat; | |
printf(" err"); | |
BOOL success = ClearCommError(port, &errors, &stat); | |
if (success) | |
{ | |
if (errors & CE_BREAK) { printf(" break"); } | |
if (errors & CE_FRAME) { printf(" frame"); } | |
if (errors & CE_OVERRUN) { printf(" overrun"); } | |
if (errors & CE_RXOVER) { printf(" rxover"); } | |
if (errors & CE_RXPARITY) { printf(" rxparity"); } | |
assert(0 == (errors & ~(CE_BREAK | CE_FRAME | | |
CE_OVERRUN | CE_RXOVER | CE_RXPARITY))); | |
} | |
} | |
if (s & EV_RING) { printf(" ring"); } | |
if (s & EV_RXCHAR) { printf(" rxchar"); } | |
if (s & EV_BREAK) { printf(" break"); } | |
if (s & EV_CTS) { printf(" cts"); } | |
if (s & EV_DSR) { printf(" dsr"); } | |
if (s & EV_RLSD) { printf(" rlsd"); } | |
if (s & EV_RXCHAR) { printf(" rxchar"); } | |
if (s & EV_RXFLAG) { printf(" rxflag"); } | |
if (s & EV_TXEMPTY) { printf(" txempty"); } | |
printf("\n"); | |
} | |
int main(int argc, char ** argv) | |
{ | |
// Make stdout be synchronous. | |
setvbuf(stdout, NULL, _IONBF, 0); | |
if (argc < 2) | |
{ | |
fprintf(stderr, "Need at least one argument to specify the COM port.\n"); | |
return 1; | |
} | |
HANDLE port = CreateFile(argv[1], GENERIC_READ | GENERIC_WRITE, | |
0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); | |
if (port == INVALID_HANDLE_VALUE) | |
{ | |
DWORD error = GetLastError(); | |
fprintf(stderr, "Could not open port. Error 0x%lx.\n", error); | |
return 1; | |
} | |
DWORD flags = EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | | |
EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY; | |
BOOL success = SetCommMask(port, flags); | |
if (!success) | |
{ | |
fprintf(stderr, "Could not set comm mask.\n"); | |
} | |
OVERLAPPED osStatus = {0}; | |
osStatus.hEvent = CreateEvent(NULL, true, false, NULL); | |
assert(osStatus.hEvent); | |
DWORD dwCommEvent; | |
BOOL fWaitingOnStat = FALSE; | |
while (true) | |
{ | |
// Issue a status event check if one hasn't been issued already. | |
if (!fWaitingOnStat) | |
{ | |
//fprintf(stderr, "Calling WaitCommEvent\n"); | |
if (!WaitCommEvent(port, &dwCommEvent, &osStatus)) | |
{ | |
if (GetLastError() == ERROR_IO_PENDING) | |
{ | |
fWaitingOnStat = TRUE; | |
//fprintf(stderr, "WaitCommEvent result is ERROR_IO_PENDING\n"); | |
} | |
else | |
{ | |
fprintf(stderr, "Error in WaitCommEvent\n"); | |
break; // abort | |
} | |
} | |
else | |
{ | |
// WaitCommEvent returned immediately. | |
// Deal with status event as appropriate. | |
ReportStatusEvent(port, dwCommEvent); | |
} | |
} | |
// Check on overlapped operation. | |
if (fWaitingOnStat) | |
{ | |
DWORD dwOvRes; | |
// Wait a little while for an event to occur. | |
//fprintf(stderr, "Calling WaitForSingleObject\n"); | |
DWORD dwRes = WaitForSingleObject(osStatus.hEvent, 100); | |
switch(dwRes) | |
{ | |
case WAIT_OBJECT_0: | |
// Event occurred. | |
if (!GetOverlappedResult(port, &osStatus, &dwOvRes, FALSE)) | |
{ | |
// An error occurred in the overlapped operation; | |
// call GetLastError to find out what it was | |
// and abort if it is fatal. | |
fprintf(stderr, "Error from GetOverlappedResult\n"); | |
} | |
else | |
{ | |
// Status event is stored in the event flag | |
// specified in the original WaitCommEvent call. | |
// Deal with the status event as appropriate. | |
ReportStatusEvent(port, dwCommEvent); | |
} | |
// Set fWaitingOnStat flag to indicate that a new | |
// WaitCommEvent is to be issued. | |
fWaitingOnStat = FALSE; | |
break; | |
case WAIT_TIMEOUT: | |
// Operation isn't complete yet. fWaitingOnStatusHandle flag | |
// isn't changed since I'll loop back around and I don't want | |
// to issue another WaitCommEvent until the first one finishes. | |
// | |
// This is a good time to do some background work. | |
//fprintf(stderr, "WAIT_TIMEOUT\n"); | |
break; | |
default: | |
// Error in the WaitForSingleObject; abort | |
// This indicates a problem with the OVERLAPPED structure's | |
// event handle. | |
fprintf(stderr, "Error in WaitForSingleObject\n"); | |
CloseHandle(osStatus.hEvent); | |
return 70; | |
} | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment