Skip to content

Instantly share code, notes, and snippets.

@KunYi
Created April 28, 2022 06:34
Show Gist options
  • Save KunYi/7ce3a76ced820d29fdb957411bc39a3d to your computer and use it in GitHub Desktop.
Save KunYi/7ce3a76ced820d29fdb957411bc39a3d to your computer and use it in GitHub Desktop.
Monitor Two Serial Port for Windows
// MonitorSerialPort.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <windows.h>
#include <iostream>
#include <conio.h>
#include <iomanip>
// Want to open communcation port
#define HOST_COMPORT L"COM4"
#define PLC_COMPORT L"COM5"
// For FX PLC
#define BAUDRATE CBR_19200
#define DATALENGTH 7
#define PARITY EVENPARITY
#define STOPBITS ONESTOPBIT
HANDLE OpenPort(const WCHAR* name, DWORD baudrate)
{
HANDLE hComm;
BOOL bSuccess = TRUE;
DCB dcb;
DWORD dwError = 0;
COMMTIMEOUTS timeout = { 0 };
COMSTAT comState = { 0 };
const DWORD dwCommEvent = EV_TXEMPTY | EV_RXCHAR | EV_ERR | EV_BREAK;
do {
hComm = CreateFileW(name, //port name
GENERIC_READ | GENERIC_WRITE, //Read/Write
0, // No Sharing
NULL, // No Security
OPEN_EXISTING, // Open existing port only
FILE_FLAG_OVERLAPPED, // Non Overlapped I/O
NULL); // Null for Comm Devices
if (hComm == INVALID_HANDLE_VALUE) {
std::cout << "Error in opening serial port" << std::endl;
bSuccess = FALSE;
break;
}
else
std::cout << "opening serial port successful" << std::endl;
dcb.DCBlength = sizeof dcb;
if (GetCommState(hComm, &dcb)) {
dcb.BaudRate = baudrate;
dcb.Parity = PARITY;
dcb.ByteSize = DATALENGTH;
dcb.StopBits = STOPBITS;
dcb.fParity = TRUE;
dcb.fBinary = TRUE;
dcb.fInX = FALSE;
dcb.fOutX = FALSE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
if (FALSE == SetCommState(hComm, &dcb)) {
std::cout << "Error in configuration of serial port" << std::endl;
bSuccess = FALSE;
break;
}
else
std::cout << "configuration " << baudrate << ",E,7,1 successful" << std::endl;
}
if (FALSE == SetupComm(hComm, 1024, 1024)) {
std::cout << "Error in setting buffer length of serial port" << std::endl;
bSuccess = FALSE;
break;
}
timeout.ReadIntervalTimeout = 100; // 100 milliseconds
timeout.ReadTotalTimeoutMultiplier = 50; // 50 milliseconds
timeout.ReadTotalTimeoutConstant = 200;
if (FALSE == SetCommTimeouts(hComm, &timeout)) {
std::cout << "Error in setting timeout of serial port" << std::endl;
bSuccess = FALSE;
break;
}
if (FALSE == PurgeComm(hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR)) {
std::cout << "Error in purge buffer of serial port" << std::endl;
bSuccess = FALSE;
break;
}
if (FALSE == SetCommMask(hComm, dwCommEvent)) {
std::cout << "Error in SetCommMask of serial port" << std::endl;
bSuccess = FALSE;
break;
}
if (FALSE == ClearCommError(hComm, &dwError, &comState)) {
}
} while (0);
// when setting failed to release handle
if ((bSuccess == FALSE) && (hComm != INVALID_HANDLE_VALUE)) {
CloseHandle(hComm);
hComm = INVALID_HANDLE_VALUE;
}
return hComm;
}
int main()
{
std::cout << "Monitor Application\n";
HANDLE hHostComm = INVALID_HANDLE_VALUE;
HANDLE hPlcComm = INVALID_HANDLE_VALUE;
const WCHAR HostCOM[] = L"\\\\.\\" HOST_COMPORT;
const WCHAR PlcCOM[] = L"\\\\.\\" PLC_COMPORT;
COMSTAT comState = { 0 };
HANDLE hArray[4];
OVERLAPPED osReader = { 0 };
OVERLAPPED osEvent = { 0 };
OVERLAPPED osWrite = { 0 };
OVERLAPPED plcReader = { 0 };
OVERLAPPED plcEvent = { 0 };
OVERLAPPED plcWrite = { 0 };
BOOL bWaitingHostOnRead = FALSE;
BOOL bWaitingHostOnStat = FALSE;
BOOL bWaitingPlcOnRead = FALSE;
BOOL bWaitingPlcOnStat = FALSE;
do {
hHostComm = OpenPort(HostCOM, BAUDRATE);
if (hHostComm == INVALID_HANDLE_VALUE)
break;
hPlcComm = OpenPort(PlcCOM, BAUDRATE);
if (hPlcComm == INVALID_HANDLE_VALUE)
break;
// Create an event object for use by WaitCommEvent.
osEvent.hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);
if (osEvent.hEvent == NULL) {
std::cout << "Error in CreateEvent for osEvent" << std::endl;
break;
}
osReader.hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);
if (osReader.hEvent == NULL) {
std::cout << "Error in CreateEvent for osReader" << std::endl;
break;
}
osWrite.hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);
if (osWrite.hEvent == NULL) {
std::cout << "Error in CreateEvent for osReader" << std::endl;
break;
}
plcEvent.hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);
if (plcEvent.hEvent == NULL) {
std::cout << "Error in CreateEvent for osReader" << std::endl;
break;
}
plcReader.hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);
if (plcReader.hEvent == NULL) {
std::cout << "Error in CreateEvent for osReader" << std::endl;
break;
}
plcWrite.hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);
if (plcWrite.hEvent == NULL) {
std::cout << "Error in CreateEvent for osReader" << std::endl;
break;
}
hArray[0] = osReader.hEvent;
hArray[1] = osEvent.hEvent;
hArray[2] = plcReader.hEvent;
hArray[3] = plcEvent.hEvent;
do {
BYTE hostBuffer[1024];
BYTE writePlcBuffer[1024];
BYTE plcBuffer[1024];
BYTE writeHostBuffer[1024];
BOOL bExit = FALSE;
DWORD dwHostError = 0;
DWORD dwHostRead = 0;
DWORD dwHostEvent = 0;
DWORD dwPlcError;
DWORD dwPlcRead = 0;
DWORD dwPlcEvent = 0;
DWORD dwEvent = 0;
if (bWaitingHostOnStat == FALSE)
{
if (WaitCommEvent(hHostComm, &dwHostEvent, &osEvent))
{
if (dwHostEvent != 0x01)
std::cout << "got Host event 0x" << std::hex << std::setfill('0') << std::setw(4) << dwHostEvent << std::endl;
if (dwHostEvent & EV_BREAK)
ClearCommBreak(hHostComm);
if (dwHostEvent & EV_ERR)
ClearCommError(hHostComm, &dwHostError, &comState);
}
else
{
DWORD error = GetLastError();
if (error != ERROR_IO_PENDING) {
}
bWaitingHostOnStat = TRUE;
}
}
if (bWaitingPlcOnStat == FALSE)
{
if (WaitCommEvent(hPlcComm, &dwPlcEvent, &osEvent))
{
if (dwPlcEvent != 0x01)
std::cout << "got Plc event 0x" << std::hex << std::setfill('0') << std::setw(4) << dwPlcEvent << std::endl;
if (dwPlcEvent & EV_BREAK)
ClearCommBreak(hPlcComm);
if (dwPlcEvent & EV_ERR)
ClearCommError(hPlcComm, &dwPlcError, &comState);
}
else
{
DWORD error = GetLastError();
if (error != ERROR_IO_PENDING) {
}
bWaitingPlcOnStat = TRUE;
}
}
if (bWaitingHostOnRead == FALSE)
{
if (FALSE == ReadFile(hHostComm, hostBuffer, sizeof(hostBuffer), &dwHostRead, &osReader))
{
bWaitingHostOnRead = TRUE;
}
else {
}
}
if (bWaitingPlcOnRead == FALSE)
{
if (FALSE == ReadFile(hPlcComm, plcBuffer, sizeof(plcBuffer), &dwPlcRead, &plcReader))
{
bWaitingPlcOnRead = TRUE;
}
else {
}
}
if (bWaitingHostOnRead && bWaitingHostOnStat && bWaitingPlcOnRead && bWaitingPlcOnStat)
{
dwEvent = WaitForMultipleObjects(4, hArray, FALSE, 50);
switch (dwEvent) {
case WAIT_OBJECT_0:
bWaitingHostOnRead = FALSE;
if (GetOverlappedResult(hHostComm, &osReader, &dwHostRead, FALSE))
{
}
else
{
DWORD error = GetLastError();
if (error != ERROR_IO_INCOMPLETE) {
std::cout << "GetOverlappedResult(), got error code:" << std::hex << error << std::endl;
}
}
break;
case (WAIT_OBJECT_0 + 1):
bWaitingHostOnStat = FALSE;
#if 0
if (dwHostEvent != 0x01)
std::cout << "got Host event 0x" << std::hex << std::setfill('0') << std::setw(4) << dwHostEvent << std::endl;
#endif
break;
case (WAIT_OBJECT_0 + 2):
bWaitingPlcOnRead = FALSE;
if (GetOverlappedResult(hPlcComm, &plcReader, &dwPlcRead, FALSE))
{
}
else
{
DWORD error = GetLastError();
if (error != ERROR_IO_INCOMPLETE) {
std::cout << "GetOverlappedResult(), got error code:" << std::hex << error << std::endl;
}
}
break;
case (WAIT_OBJECT_0 + 3):
bWaitingPlcOnStat = FALSE;
#if 0
if (dwPlcEvent != 0x01)
std::cout << "got Plc event 0x" << std::hex << std::setfill('0') << std::setw(4) << dwPlcEvent << std::endl;
#endif
break;
case WAIT_TIMEOUT:
break;
default: {
std::cout << "got error 0x" << std::hex << std::setfill('0') << std::setw(4) << GetLastError() << std::endl;
bExit = TRUE;
}
break;
}
}
if (dwHostRead) {
DWORD dwWriteHost;
const DWORD dwWriteBytes = dwHostRead;
memcpy_s(writePlcBuffer, sizeof(writePlcBuffer), hostBuffer, dwWriteBytes);
WriteFile(hPlcComm, writePlcBuffer, dwWriteBytes, &dwWriteHost, &plcWrite);
std::cout << ">>>";
for (DWORD i = 0; i < dwWriteBytes; i++) {
if (i == 0) {
if (writePlcBuffer[i] == 0x05) std::cout << "ENQ";
if (writePlcBuffer[i] == 0x02) std::cout << "STX,";
}
else {
if (writePlcBuffer[i] == 0x03) std::cout << ",ETX,";
else
std::cout << writePlcBuffer[i];
}
}
std::cout << std::endl;
}
if (dwPlcRead) {
DWORD dwWritePlc;
const DWORD dwWriteBytes = dwPlcRead;
memcpy_s(writeHostBuffer, sizeof(writeHostBuffer), plcBuffer, dwWriteBytes);
WriteFile(hHostComm, writeHostBuffer, dwWriteBytes, &dwWritePlc, &osWrite);
std::cout << "<<<";
for (DWORD i = 0; i < dwWriteBytes; i++) {
if (i == 0) {
if (writeHostBuffer[i] == 0x06) std::cout << "ACK";
else if (writeHostBuffer[i] == 0x02) std::cout << "STX,";
else if (writeHostBuffer[i] == 0x15) std::cout << "NACK";
}
else {
if (writeHostBuffer[i] == 0x03) std::cout << ",ETX,";
else
std::cout << writeHostBuffer[i];
}
}
std::cout << std::endl;
}
if (bExit == TRUE) {
std::cout << "exit program" << std::endl;
break;
}
if (_kbhit()) {
int ch;
switch ((ch = _getch()))
{
case 27:
std::cout << "got ESC key" << std::endl;
bExit = TRUE;
break;
case '\r':
// bExit = TRUE;
break;
case '\n':
break;
}
if (bExit == TRUE)
break;
}
if (bExit == TRUE) {
std::cout << "exit program" << std::endl;
break;
}
} while (1);
} while (0);
if (osWrite.hEvent)
CloseHandle(osWrite.hEvent);
if (osReader.hEvent)
CloseHandle(osReader.hEvent);
if (osEvent.hEvent)
CloseHandle(osEvent.hEvent);
if (plcWrite.hEvent)
CloseHandle(plcWrite.hEvent);
if (plcReader.hEvent)
CloseHandle(plcReader.hEvent);
if (plcEvent.hEvent)
CloseHandle(plcEvent.hEvent);
if (hHostComm != INVALID_HANDLE_VALUE)
CloseHandle(hHostComm);//Closing the Serial Port
if (hPlcComm != INVALID_HANDLE_VALUE)
CloseHandle(hPlcComm);//Closing the Serial Port
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment