'Serial port becomes unresponsive on Ubuntu 20.04, but works on Ubuntu 18.04

I wrote a C++ program to continuously read data from a device, via serial over USB. The program works flawlessly in Ubuntu 18.04 (Bionic Beaver). I have an identical system running Ubuntu 20.04 (Focal Fossa) and the same program does not work properly. It will read a few KB from the serial port, but then no more data is detected by read().

Here is the code:

#include <iostream>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>

int receive_data(int fd, unsigned char read_buf[], int num_requested_bytes)
{
    int total_received_bytes = 0;
    int num_received_bytes = 0;

    // Continue reading the serial port until the number of requested bytes have been read
    while (total_received_bytes < num_requested_bytes)
    {
        num_received_bytes = read(fd, read_buf + total_received_bytes,
                                  num_requested_bytes - total_received_bytes);
        if (num_received_bytes < 0)
        {
            if (errno == EAGAIN)
            {
                num_received_bytes = 0;
            }
            else
            {
                std::cout << "Encountered error during read(): " << errno << std::endl;
                exit(-1);
            }
        }
        total_received_bytes += num_received_bytes;

        if (total_received_bytes >= num_requested_bytes)
        {
            break;
        }
    }
    return total_received_bytes;
}

int main()
{
    // Open serial port
    int fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY | O_NONBLOCK);
    int flags = fcntl(fd, F_GETFL);
    //fcntl(fd, F_SETFL,  flags | O_ASYNC); // <------------------- SEE NOTE

    // Read in existing settings, and handle any error
    struct termios tty;
    if(tcgetattr(fd, &tty) != 0)
    {
        close(fd);
        printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
        exit(-1);
    }

    // Set flags
    tty.c_cflag |= (CLOCAL | CREAD);
    tty.c_cc[VTIME] = 0;
    tty.c_cc[VMIN] = 0;

    // Raw input mode
    cfmakeraw(&tty);

    // Save tty settings, also checking for error
    if (tcsetattr(fd, TCSANOW, &tty) != 0)
    {
        close(fd);
        printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
        exit(1);
    }

    // Attempt to read from port
    int received_bytes;
    unsigned char read_buf[1024];
    while (true)
    {
        received_bytes = receive_data(fd, read_buf, 1024);
        std::cout << "Received " << received_bytes << " bytes. First 2 numbers in frame: "
                  << ((unsigned int) (read_buf[1] << 8 | read_buf[0])) << ", "
                  << ((unsigned int) (read_buf[3] << 8 | read_buf[2])) << std::endl;
    }
}

Here is example output from the program in Ubuntu 20.04. After 0-3 frames, I no longer receive any data and the program endlessly loops on my read() call.

On Ubuntu 18.04, the program will continue endlessly.

$ ./main
Received 1024 bytes. First 2 numbers in frame: 65535, 2046
Received 1024 bytes. First 2 numbers in frame: 2046, 3338
Received 1024 bytes. First 2 numbers in frame: 2045, 2046

See note:

If I enable the O_ASYNC flag, the program will exit on the first read() with I/O Possible printed in the terminal. If I then comment out the line and recompile, the program runs and fetches frames continuously as expected.

What could be causing this?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source