0

I am using fgets in a small C program - running under Ubuntu - to read data coming from Arduino via its FTDI USB/Serial converter. I am using low level I/O function from GNU libc (since I want - in the future - be able to control baud rate etc) and then promoting from descriptor to stream in order to use higher leve I/O functions. The observed behaviour of my program suggests that the fgets function does not block until the line terminator is acquired (as in my opinion it should do).

Any explanation?

The codes of my programs are here -> PC side:

#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */

#define bufLen 81

int main(void) {
    int fd;    /* File descriptor for the port */
    FILE * f;  /* port will be identified also as stream 'f'*/
    char buf[bufLen];
    fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY);
    if (fd == -1) {perror(""); return errno;}
    else {
        f = fdopen(fd, "r+t");
        while (1) {
            if (fgets(buf,bufLen,f)) {
                printf("{%s}\n",buf);
                sleep(1);
            } else {
                {perror("ahhhh! ");}
            }
        }
    }
    return 0;
}

-> Arduino side:

char ar[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
int k1 = 0, k2 = 0;

void setup() {
  // initialize serial:
  Serial.begin(9600);
}

void loop() {
  Serial.print(ar[k1]);
  k1 = (++k1) % 26;
  k2 = (++k2) % 5;
  if (k2==0) {Serial.println();}
  delay(300);
}

And the result of run..

xxx@RevoR3600:~/CProg$ ./SerialPort
ahhhh! : Success
ahhhh! : Success
ahhhh! : Success
...
... (many identical lines...)
...
ahhhh! : Success
ahhhh! : Success
{AP}
{A}
{BCD}
{E
}
{FGHIJ
}
^C
xxx@RevoR3600:~/CProg$
ginsi
  • 11
  • 1
  • Why do you expect serial input to block? Nothing special about `\n` on serial input. Maybe open in a different fashion. – chux - Reinstate Monica Feb 23 '14 at 00:24
  • My reference is [this](http://www.gnu.org/software/libc/manual/html_mono/libc.html#Streams-and-File-Descriptors), which says "You must also use file descriptors if your program needs to do input or output in special modes, such as nonblocking"; as for \n, the fgets description (in the same section) says "The fgets function reads characters from the stream stream up to and including a newline character and stores them in the string s". Anyway, refgormulating the question: which is the right way to read a line from a serial connection in a blocking way? I was not able to find.. – ginsi Feb 23 '14 at 07:38

1 Answers1

1

After sleeping one night on it and two more hours of digging this site (and testing) I finally came across a solution right here; sorry I was not able to find it before posting (I can't figure out why); now it is matter for me to study exactly why the found solution is working (and why there is still a minor problem: some strange characters acquired on starting). Thanks (and apology) to everybody has read my post.

Here is the working (test) code:

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

#define bufLen 81

int main() {    

    char buf[bufLen];
    struct termios tty;
    FILE * f;
    int fd=open("/dev/ttyACM0",O_RDWR | O_NOCTTY);
    if(fd == -1) {
            perror("Unable to open /dev/ttyACM1\n");
            return -1;
    } else {
        if(tcgetattr(fd, &tty)!=0) {perror("tcgetatt() error"); return -1;}
        else {
            cfsetospeed(&tty, B9600);
            cfsetispeed(&tty, B9600);

            tty.c_cflag &= ~PARENB;
            tty.c_cflag &= ~CSTOPB;
            tty.c_cflag &= ~CSIZE;
            tty.c_cflag |= CS8;
            tty.c_cflag &= ~CRTSCTS; 
            tty.c_cflag |= CLOCAL | CREAD;

            tty.c_iflag |= IGNPAR | IGNCR;
            tty.c_iflag &= ~(IXON | IXOFF | IXANY);
            tty.c_lflag |= ICANON;
            tty.c_oflag &= ~OPOST;
            tcsetattr(fd, TCSANOW, &tty);

            if (!(f = fdopen(fd, "r+t"))) {perror("fdopen() error"); return -1;}

            while (1) {
                fgets(buf,bufLen,f);
                printf("%s--\n",buf);
            }   
        }
    }
    close(fd);
    return 0;
}
ginsi
  • 11
  • 1