3

I am trying to send and receive a string over UART in Raspberry Pi 3. I've connected the TX and RX pin of the Pi, but when the program runs I get an error:

Read failed: Resource temporarily unavailable

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

int main(int argc, char ** argv) {
    int fd;
    // Open the Port. We want read/write, no "controlling tty" status, and open it no matter what state DCD is in
    //fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
    fd = open("/dev/ttyS0", O_RDWR);
    if (fd == -1) {
        perror("open_port: Unable to open /dev/ttyS0 - ");
        return(-1);
    }

    // Turn off blocking for reads, use (fd, F_SETFL, FNDELAY) if you want that
    fcntl(fd, F_SETFL, 0);
    while(1){
        //for(int k=0; k<10; k++){
        // Write to the port
        int n = write(fd,"hello",6);
        if (n < 0) {
            perror("Write failed - ");
            return -1;
        }
        // Read up to 255 characters from the port if they are there
        char buf[256];
        n = read(fd, &buf, 255);
        if (n < 0) {
            perror("Read failed - ");
            return -1;
        }
        else if (n == 0) {
            printf("No data on port\n");
        }
        else {
            buf[n] = '\0';
            printf("%i bytes read : %s", n, buf);
        }
    }
    close(fd);
    return 0;
}
pr0gramist
  • 8,305
  • 2
  • 36
  • 48
Aerluft
  • 41
  • 1
  • 7
  • You should only get a *"Resource temporarily unavailable"* errno for a nonblocking read(). Your code looks like it does blocking read()s. Are you sure you have matched the actual code with its results? Try adding the O_NOCTTY open option. – sawdust Sep 19 '16 at 19:40
  • @sawdust tried the O_NOCTTY option, same result. n has a value of 6 for write and -1 for read. Any other suggestion? – Aerluft Sep 20 '16 at 11:56
  • Study the **man** page for **read(2)**. The EAGAIN error is only supposed to occur for nonblocking reads. When the error happens, add code to check the file status flags: `val = fcntl(fd, F_GETFL, 0); printf("file status = 0x%x\n", val);` – sawdust Sep 20 '16 at 19:22
  • @sawdust the flag status returned "0x802" – Aerluft Sep 21 '16 at 11:57
  • *"the flag status returned "0x802""* -- That's file status, not flag status. The file status indicates that nonblocking mode is active. – sawdust Sep 21 '16 at 20:04

2 Answers2

3

The EAGAIN error is only supposed to occur for nonblocking reads.
When the error happens, you need to add code to check the file status flags:

val = fcntl(fd, F_GETFL, 0);
printf("file status = 0x%x\n", val);

the flag status returned "0x802"

You would expect a file status of 0x002 for blocking mode.
The 0x800 (the value of O_NONBLOCK) in that file status value indicates that nonblocking mode is active.

That's proof that the code you have posted (that shows blocking reads) does not match the executable that you are testing with.

fd = open("/dev/ttyS0", O_RDWR);
  ...
fcntl(fd, F_SETFL, 0);

If you actually had blocking reads as the above posted code represents, then your program would not get the EAGAIN error.
But since your program is performing nonblocking reads (as proven by the file status) (and data is currently not available), your program does get the EAGAIN error.


You should be able to resolve this by desk-checking your code.
Otherwise instrument your code with more checks:

fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);     /* suspect line */
val = fcntl(fd, F_GETFL, 0);
printf("post-open file status = 0x%x\n", val);
  ...
fcntl(fd, F_SETFL, 0);     /* suspect line */
val = fcntl(fd, F_GETFL, 0);
printf("post-fcntl file status = 0x%x\n", val);
sawdust
  • 16,103
  • 3
  • 40
  • 50
  • my bad. I had changed 'fcntl(fd, F_SETFL, 0);' to 'fcntl(fd, F_SETFL, O_NONBLOCK);'(hence the file status:0x802) to get the program to run. If not the programs hangs. Now with O_NONBLOCK removed and the checks you suggested implemented I get the following results 'post-open file status = 0x2 post-fcntl file status = 0x2 n write: 6'. But after this nothing, the program hangs. – Aerluft Sep 23 '16 at 12:05
  • So you have confirmed that this answer solves your original question. Therefore you should "accept" this answer. – sawdust Sep 23 '16 at 21:28
  • *"But after this nothing, the program hangs"* -- Your program does nothing to configure the terminal attributes. Since the default mode is probably canonical, and you wrote ASCII text w/o a line terminator, the read() should block forever. See http://stackoverflow.com/questions/27214759/why-characters-received-in-serial-connection-only-after-pressing-enter/27219333#27219333 and http://stackoverflow.com/questions/25996171/linux-blocking-vs-non-blocking-serial-read/26006680#26006680 IF you append a line terminator to the output string, i.e. "hello\n", then the canonical read() should complete. – sawdust Sep 23 '16 at 21:45
  • by _"to get the program to run"_ i meant that the program terminates with the error "Read Failed: Resource temporarily unavailable". Without 'O_NONBLOCK' the program hangs. Tried the line terminator, dint work either. – Aerluft Sep 26 '16 at 13:37
  • (1) Fix the line `n = read(fd, &buf, 255);` to `n = read(fd, buf, 255);` (2) double check your loopback connection. Your original question has been answered. You're trying to get two different symptioms/questions answered in one post. – sawdust Sep 26 '16 at 15:28
0

I had the exact same problem, trying to connect to: /dev/tty.usbserial-A5026YP3. If I use device /dev/tty.usbserial-A5026YP3 instead, everything works fine. Here is the code related to opening and configuring the device:

rpc_client_uart::rpc_client_uart(const std::string& filename, speed_t speed, size_t usec, const std::string& jsonrpc_version)
    : fd_(-1)
    , timeout_(usec)
    , jsonrpc_version_(jsonrpc_version)
    , serial_(0)
    , cache_head_(cache_)
    , cache_tail_(cache_)
{
    struct termios tio;

    fd_ = ::open(filename.c_str(), O_RDWR | O_NOCTTY);
    if (fd_ < 0)
        throw std::runtime_error(
                std::string("Failed to open file: " + filename));
    if (!::isatty(fd_)) {
        ::close(fd_);
        throw std::runtime_error(std::string(filename + " : Not a tty device"));
    }

    /* Set the funny terminal modes. */
    tcgetattr(fd_, &tio);
    tio.c_lflag &= ~(ECHO | ICANON); /* Clear ICANON and ECHO. */
    tio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR
            | ICRNL | IXON);
    tio.c_oflag &= ~OPOST;
    tio.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
    tio.c_cflag &= ~(CSIZE | PARENB);
    tio.c_cflag &= ~CRTSCTS;
    tio.c_cflag |= (CS8);
    tio.c_cc[VMIN] = 1;
    tio.c_cc[VTIME] = 20;
    cfsetospeed(&tio, speed);
    cfsetispeed(&tio, speed);
    tcsetattr(fd_, TCSANOW, &tio);
    tcflush(fd_, TCIOFLUSH);
}