ReadFile always returns false. GetLastError reoprts ERROR_IO_PENDING. Waitforsingleobject passes

153 views Asked by At

What I am trying to do is to get frames of data from a COM port. The data frames are 258 bytes each, and are constantly coming in at a rate of about 8.5 per second.

I need to receive the data frames and then I will do some other processing on them, but for now I am trying to just print them out to the console. Each data frame starts with '/' and ends with '?'.

Here is the code I wrote (yes I'm a noob at this):

#include <iostream>
#include <time.h>
#include <string>

#include "windows.h"
#pragma comment (lib, "OneCore.lib")

int main()
{
    int portnum = 0;

    ULONG ptNums[300];
    ULONG some = 300;
    ULONG ptsFound[20];
    LPCSTR fName = "COM4";

    ULONG status = GetCommPorts(ptNums, 100, ptsFound);
    if (status == ERROR_SUCCESS) {
        std::cout << "ports found:" << ptsFound[0] << "\n";
        for (int i = 0; i < ptsFound[0]; i++) {
            portnum = ptNums[i];
            std::cout << "COM" << portnum << "\n";
        }
    }

    HANDLE port = CreateFileA(fName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
    if (port == INVALID_HANDLE_VALUE) {
        std::cout << "unable to open port\n";

    }

    DCB dcb;
    dcb = { 0 };
    //this is the default, use 8N1
    dcb.DCBlength = sizeof(DCB);
    dcb.fBinary = TRUE;
    dcb.BaudRate = 250000;
    dcb.fParity = FALSE;
    dcb.ByteSize = 8;
    dcb.Parity = NOPARITY;
    dcb.StopBits = ONESTOPBIT;

    DWORD eventMask;

    SetCommState(port, &dcb);
    SetCommMask(port,EV_TXEMPTY|EV_RXCHAR);

    bool exitloop = false;
    char arduBuf[258];

    OVERLAPPED ov;
    ov.Offset = 0;
    ov.OffsetHigh = 0;
    ov.hEvent = CreateEvent(0, TRUE, 0, 0);
    SetupComm(port, 300, 300);

    while (!exitloop) {
        
        GetCommMask(port, &eventMask);
        BOOL dataRet = WaitCommEvent(port, &eventMask, &ov);
        DWORD dwait = WaitForSingleObject(ov.hEvent, INFINITE);
        
        if (eventMask & EV_TXEMPTY) {
            std::cout << "all data was sent\n";
            exitloop = true;
        }

        if (dwait == WAIT_OBJECT_0) {
            GetCommMask(port, &eventMask);
            std::cout << "some random stuff was received\n";

            BOOL status = ReadFile(port, arduBuf, sizeof(arduBuf), NULL, &ov);
            std::cout << "status:" << status << "\nerror is:" << GetLastError() << "\n";
            PurgeComm(port, PURGE_RXCLEAR);
            if (status) {
                std::cout << arduBuf << "\n";
            }
            ResetEvent(ov.hEvent);
            //exitloop = true;
        }

        if (dwait == WAIT_TIMEOUT) {
            std::cout << "timeout\n";
        }
    }
}

The code compiles and runs, and WaitForSingleObject() returns WAIT_OBJECT_0, but the status is always 0 and GetLastError() returns ERROR_IO_PENDING. If I print out the data buffer regardless, then I can see my data, but its on a few jumbled lines and very inconsistent:

screenshot

I think this is because although EV_RXCHAR is satisfied, EV_TXEMPTY never is. If I set the mask to EV_TXEMPTY only, then the code hangs at WaitForSingleObject(). I think this is because before the data gets read, there is new data already filling the input buffer.

My questions:

  • There is obviously something wrong here. Can someone point it out?
  • I am not sure if stuffing the reading into a while loop is a good idea. I know I should stuff it into a thread that terminates once a read has failed or was successful, but is the while loop actually causing problems?
  • I get a warning on the WaitForSingleObject() line that ov.hEvent could be 0. Why is this so, and can it also be an issue?
  • When do I need to reset the event?

As you can tell, I am new to COM port I/O. I've spent over a day on this and decided it was time to ask someone that knows what they are doing.

1

There are 1 answers

0
Torrecto - MSFT On

As @tevemadar said, ERROR_IO_PENDING is not a failure; it designates the read operation is pending completion asynchronously.

If the overlapped operation cannot be completed immediately, the function returns FALSE and the GetLastError function returns ERROR_IO_PENDING, indicating that the operation is executing in the background. When this happens, the system sets the hEvent member of the OVERLAPPED structure to the not-signaled state before WaitCommEvent returns, and then it sets it to the signaled state when one of the specified events or an error occurs.

Using the GetOverlappedResult function to determine the results of the WaitCommEvent operation can get some updates.