Skip to content

Instantly share code, notes, and snippets.

@DavidEGrayson
Last active July 22, 2023 14:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save DavidEGrayson/5e5bb95ae291cdfdffd4 to your computer and use it in GitHub Desktop.
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.
// 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