Created
April 28, 2022 06:34
-
-
Save KunYi/7ce3a76ced820d29fdb957411bc39a3d to your computer and use it in GitHub Desktop.
Monitor Two Serial Port for Windows
This file contains hidden or 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
// 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