Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read from serial device in C++

Tags:

c++

linux

arduino

I'm trying to figure out how I should read/write to my Arduino using serial communication in Linux C++. Currently I'm trying to read a response from my Arudino that I "trigger" with

echo "g" > /dev/ttyACM0"

I've tried looking at the response from my Arduino in my terminal, by using the following command:

tail -f /dev/ttyACM0

This is working as it should. Now I want to do the same thing in a C++ application. So I made this test

void testSerialComm()
{

    std::string port = "/dev/ttyACM0";
    int device = open(port.c_str(), O_RDWR | O_NOCTTY | O_SYNC);

    std::string response;
    char buffer[64];

    do
    {
        int n = read(device, buffer, sizeof buffer);

        if (n > 0) {
            response += std::string(buffer);
            std::cout << buffer;
        }

    } while (buffer[0] != 'X'); // 'X' means end of transmission

    std::cout << "Response is: " << std::endl;
    std::cout << response << std::endl;

    close(device);

}

After a few "messages", the transmission gets a little messed up. My test application writes the response characters in random order and something's not right. I tried configuring the /dev/ttyACM0 device by this command:

stty -F /dev/ttyUSB0 cs8 115200 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts

No dice. Can someone help me understand how to communicate with my Arduino in C++?

like image 544
birgersp Avatar asked Jan 17 '16 18:01

birgersp


People also ask

How do I read serial data on my computer?

In Serial Port Reader go to the “Main menu”, choose “Session -> New session”. Alternately, you can click on the “New” icon on the main toolbar or press “Ctrl + N”. This invokes the “New monitoring session” screen. Terminal view – all received data is displayed in ASCII characters on a text console.

How do I read UART?

Select the UART port on the board from which the block reads data. At each sample time, the Rx port on the block outputs the values read from the UART port using the Rx pin on the port. To specify the Rx pin, go to Configuration Parameters > Hardware Implementation pane > UARTx > Rx Pin.

Can you read and write from the same serial port?

You can indeed simultaneously read and write through the serial port. At the hardware level, the serial port (the UART) is a transmitter and a receiver, which are almost independent. At the software level, they are both handled through interrupts that read from / write to a software buffer.


1 Answers

The shown code opens /dev/ttyACM0, attempts to seek to the end of this "file", and based on the resulting file position allocates an old-fashioned, C-style memory buffer.

The problem with this approach is that you can only seek through regular, plain, garden-variety files. /dev/ttyACM0 is not a regular file. It's a device. Although some devices are seekable, this one isn't. Which, according to the comments, you've discovered independently.

Serial port devices are readable and writable. They are not seekable. There's no such thing as "seek"ing on a serial port. That makes no sense.

To read from the serial port you just read it, that's all. The operating system does maintain an internal buffer of some size, so if some characters were already received over the serial port, the initial read will return them all (provided that the read() buffer size is sufficiently large). If you pass a 1024 character buffer, for example, and five characters were already read from the serial port read() will return 5, to indicate that accordingly.

If no characters have been read, and you opened the serial port as a blocking device, read() will block at least until one character has been read from the serial port, and then return.

So, in order to read from the serial port all you have to do is read from it, until you've decided that you've read all there is to read from it. How do you decide that? That's up to you. You may decide that you want to read only until reading a newline character. Or you may decide that you want to read only until a fixed #n number of characters have been read. That's entirely up to you.

And, of course, if the hardware is suitably arranged, and you make the necessary arrangements with the serial port device to respect the serial port control pins, and, depending on your configuration, the DCD and/or DSR pins are signaled to indicate that the serial port device is no longer available, your read() will immediately return 0, to indicate a pseudo-end of file condition on the serial port device. That's also something that you will need to implement the necessary logic to handle.

P.S. neither C-style stdio, nor C++-style iostreams will work quite well with character devices, due to their own internal buffering algorithms. When working with serial ports, using open(2), read(2), write(2), and close(2) is better. But all of the above still applies.

like image 193
Sam Varshavchik Avatar answered Oct 04 '22 09:10

Sam Varshavchik