1

Overview: I'm trying to trigger an Overrun error indication, by issuing long delays between each byte read from the serial port. To make long story short - I don't get this event.

The test: The DTE is configured to work at 920000BPS 8N1, no flow control. The DTE is connected to my Windows10 host via "Silicon Labs CP210x USB to UART Bridge" device.

The provided code fragment opens the port, calls the SetCommMask function. A delay of 10 seconds was inserted between each call to ReadFile within a loop. The DTE continuously sends data at a stable rate.

The problem: I don't get any Overrun signal from WaitCommEvent.

Question: Is there a problem with my code? is there some known limitation with the USB driver? Do I need to use flow control to get noticed about overrun events?

#include <Windows.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
    HANDLE hComm;  // Handle to the Serial port
    BOOL   Status; // Status
    DCB dcbSerialParams = { 0 };  // Initializing DCB structure
    COMMTIMEOUTS timeouts = { 0 };  //Initializing timeouts structure
    char SerialBuffer[64] = { 0 }; //Buffer to send and receive data
    DWORD BytesWritten = 0;          // No of bytes written to the port
    DWORD dwEventMask;     // Event mask to trigger
    char  ReadData;        //temperory Character
    DWORD NoBytesRead;     // Bytes read by ReadFile()
    unsigned char loop = 0;
    wchar_t pszPortName[10] = { 0 }; //com port id
    wchar_t PortNo[20] = { 0 }; //contain friendly name
    //Enter the com port id
    do
    {
        printf_s("Enter the Com Port: ");
        wscanf_s(L"%s", pszPortName, (unsigned)_countof(pszPortName));
        swprintf_s(PortNo, 20, L"\\\\.\\%s", pszPortName);
        //Open the serial com port
        hComm = CreateFile(PortNo, //friendly name
            GENERIC_READ | GENERIC_WRITE,      // Read/Write Access
            0,                                 // No Sharing, ports cant be shared
            NULL,                              // No Security
            OPEN_EXISTING,                     // Open existing port only
            0,                                 // Non Overlapped I/O
            NULL);                             // Null for Comm Devices
        if (hComm == INVALID_HANDLE_VALUE)
        {
            printf_s("\n Port can't be opened\n\n");
            break;
        }
        //Setting the Parameters for the SerialPort
        dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
        Status = GetCommState(hComm, &dcbSerialParams); //retreives  the current settings
        if (Status == FALSE)
        {
            printf_s("\nError to Get the Com state\n\n");
            break;
        }
        dcbSerialParams.BaudRate = 920000;//CBR_9600;      //BaudRate = 9600
        dcbSerialParams.ByteSize = 8;             //ByteSize = 8
        dcbSerialParams.StopBits = ONESTOPBIT;    //StopBits = 1
        dcbSerialParams.Parity = NOPARITY;      //Parity = None
        Status = SetCommState(hComm, &dcbSerialParams);
        if (Status == FALSE)
        {
            printf_s("\nError to Setting DCB Structure\n\n");
            break;
        }
        //Setting Timeouts
        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");
            break;
        }

        //Setting Receive Mask
        Status = SetCommMask(hComm, EV_ERR| EV_RX80FULL| EV_BREAK/*EV_RXCHAR*/);
        if (Status == FALSE)
        {
            printf_s("\nError to in Setting CommMask\n\n");
            break;
        }
        //Read data and store in a buffer
        do
        {
            Status = ReadFile(hComm, &ReadData, sizeof(ReadData), &NoBytesRead, NULL);
            //Setting WaitComm() Event
            Sleep(10000); /* Ten seconds */
            Status = WaitCommEvent(hComm, &dwEventMask, NULL); //Wait for the character to be received
            if (Status == FALSE)
            {
                printf_s("\nError! in Setting WaitCommEvent()\n\n");
                break;
            }

            SerialBuffer[loop] = ReadData;
            ++loop;
        } while (NoBytesRead > 0);
        --loop; //Get Actual length of received data
        printf_s("\nNumber of bytes received = %d\n\n", loop);
        //print receive data on console
        printf_s("\n\n");
        int index = 0;
        for (index = 0; index < loop; ++index)
        {
            printf_s("%c", SerialBuffer[index]);
        }
        printf_s("\n\n");
    } while (0);

    CloseHandle(hComm);//Closing the Serial Port
    system("pause");
    return 0;
}


yoav Segal
  • 11
  • 2

1 Answers1

0

Serial port overrun errors should occur as data is sent even after the interface chip and device driver buffers are full.
And a narrow definition overrun will only signal what the interface chip(8250/16550/etc) has detected.

So it's unclear if it will occur even if you take a long interval to call ReadFile.

Please try the following.

However, no matter what you do, it may not occur if you are using a USB serial conversion chip.

At the same time as trying the above, please ask the chip vendor if there is an overrun error or if it may be detected, and if so, how to try it.

kunif
  • 4,060
  • 2
  • 10
  • 30
  • From the `SetupComm` documentation page: "The device driver receives the recommended buffer sizes, but is free to use any input and output (I/O) buffering scheme, as long as it provides reasonable performance and data is not lost due to overrun (except under extreme circumstances). " Basically seeing an overrun condition is very unusual because the driver stack is going to do its best to avoid it. – Ben Voigt Oct 20 '21 at 15:22
  • @Ben Voigt, I didn't pay attention to that information. However, OP may be able to see it with `GetCommProperties()` after setting the buffer size. It is a suggestion that OP should try including such various things. – kunif Oct 20 '21 at 15:33
  • Thank you guys. Anyway, I just noticed that there was no need to use a loop inside the code, since the code is waiting infinitely for the event. I do agree that a the device driver may use different buffing schemes, which reduce the occurrence frequency of this event. – yoav Segal Oct 20 '21 at 15:54