I’m trying to setup a communication with an Arduino Nano. The arduino sends a single character every seconds.
In this question I was trying to read data from a serial port.
I thought I was out of the woods with the bit of code I found on the internet, but it actually doesn’t work as expected.
For instance, in this code, if the arduino sends more than one character then ReadFile
returns FALSE
and GetLastError()
returns ERROR_IO_PENDING
Here the arduino is sending 3 ‘p’ characters every second.
It goes well the first time and then I have the error and I can get only 2 characters.
Here is the console output :
event 0x1 rxchar
ppp
event 0x1 rxchar
-ReadFile returned ERROR_IO_PENDING
event 0x1 rxchar
pp
event 0x1 rxchar
-ReadFile returned ERROR_IO_PENDING
event 0x1 rxchar
pp
event 0x1 rxchar
-ReadFile returned ERROR_IO_PENDING
And the program :
#include <Windows.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <csignal>
#include <assert.h>
#include <stdbool.h>
#define EXIT_ON_ERROR(hres, line)
if (FAILED(hres)) {
std::cout << "error line " << line << std::endl;
}
#define SAFE_RELEASE(punk)
if ((punk) != NULL)
{ (punk)->Release(); (punk) = NULL; }
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_RXFLAG) { printf(" rxflag"); }
if (s & EV_TXEMPTY) { printf(" txempty"); }
printf("n");
}
void readAndDisplayByteByByte(HANDLE port, OVERLAPPED osStatus) {
char read[100] = { 0 };
DWORD numberRead;
if (!ReadFile(port, read, sizeof(read), &numberRead, &osStatus)) {
if (GetLastError() == ERROR_IO_PENDING) {
printf("Trying to read when still ERROR_IO_PENDINGn");
}
else {
printf("--error no ERROR_IO_PENDINGn");
}
}
else {
printf("lu %lu bytesn", numberRead);
for (unsigned long i = 0; i < numberRead; i++) {
printf("%c", read[i]);
}
printf("n");
}
}
void readAndDisplay(HANDLE hComm, OVERLAPPED o, DWORD dwEvtMask) {
char read[100] = { 0 };
DWORD numberRead;
BOOL Status;
if (dwEvtMask & EV_RXCHAR) {
if (!ReadFile(hComm, read, sizeof(read), &numberRead, &o)) {
if (GetLastError() == ERROR_IO_PENDING) {
printf("-ReadFile returned ERROR_IO_PENDINGn");
}
else {
printf("-readfile failed with code %dn", GetLastError());
}
}
else {
if (numberRead > 0) {
for (int i = 0; i < 100; i++) {
printf("%c", read[i]);
}
printf("n");
}
}
}
ResetEvent(o.hEvent);
}
int main() {
HANDLE hComm = CreateFile(L"\\.\COM4", GENERIC_READ | GENERIC_WRITE,
0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (hComm == INVALID_HANDLE_VALUE) {
DWORD error = GetLastError();
fprintf(stderr, "Could not open port. Error %dn", error);
return 1;
}
OVERLAPPED osReader = { 0 }; // Overlapped structure
DWORD dwEvtMask;
BOOL fWaitingOnMask = FALSE;
// Initialize the OVERLAPPED structure
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
// Set device parameters (9600 baud, 1 start bit, 1 stop bit, no parity)
DCB dcbSerialParams = { 0 };
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (!GetCommState(hComm, &dcbSerialParams)) {
printf("Error getting device staten");
CloseHandle(hComm);
return 1;
}
dcbSerialParams.BaudRate = CBR_9600;
//dcbSerialParams.ByteSize = 8;
//dcbSerialParams.StopBits = ONESTOPBIT;
//dcbSerialParams.Parity = NOPARITY;
if (!SetCommState(hComm, &dcbSerialParams)) {
printf("Error setting device parametersn");
CloseHandle(hComm);
return 1;
}
//Setting Timeouts
//COMMTIMEOUTS timeouts = { 0 }; //Initializing timeouts structure
//timeouts.ReadIntervalTimeout = 50;
//timeouts.ReadTotalTimeoutConstant = 50;
//timeouts.ReadTotalTimeoutMultiplier = 10;
//timeouts.WriteTotalTimeoutConstant = 50;
//timeouts.WriteTotalTimeoutMultiplier = 10;
//if (SetCommTimeouts(hComm, &timeouts) == FALSE)
//{
// printf_s("nError to Setting Time outs");
// CloseHandle(hComm);
//}
// Set the event mask to wait for a character to be received
if (!SetCommMask(hComm, EV_RXCHAR)) {
printf("error mask %dn", GetLastError());
}
DWORD lpErrors;
COMSTAT lpStat;
BOOL waitingOnMask = FALSE;
ClearCommError(hComm, &lpErrors, &lpStat);
while (1) {
if (!waitingOnMask) {
// Wait for an event to occur
if (WaitCommEvent(hComm, &dwEvtMask, &osReader)) {
ReportStatusEvent(hComm, dwEvtMask);
readAndDisplay(hComm, osReader, dwEvtMask);
//readAndDisplayByteByByte(hComm, osReader);
}
else {
if (GetLastError() == ERROR_IO_PENDING) {
waitingOnMask = TRUE;
}
else {
printf("Fatal error %dn", GetLastError());
}
}
}
if (waitingOnMask) {
DWORD res = WaitForSingleObject(osReader.hEvent, INFINITE);
switch (res) {
case WAIT_OBJECT_0:
waitingOnMask = FALSE;
if (dwEvtMask & EV_RXCHAR) {
ReportStatusEvent(hComm, dwEvtMask);
readAndDisplay(hComm, osReader, dwEvtMask);
//readAndDisplayByteByByte(hComm, osReader);
}
break;
default:
printf("error waiting %dn", GetLastError());
break;
}
}
}
// Clean up
CloseHandle(osReader.hEvent);
return 0;
}
I tryied to fiddle with this quite a lot, to no avail.
1