2

I am opening serial port using following function

int open_port (unsigned char * port)
{
    int fd = open(port,O_RDWR | O_NOCTTY | O_NDELAY);

    if(fd == -1)
    {
            return PORT_ERR;
    }
    else
    {

            struct termios new_termios;
            struct termios orig_termios;

            tcgetattr(0, &orig_termios);
            memcpy(&new_termios, &orig_termios, sizeof(new_termios));

            cfmakeraw(&new_termios);

            cfsetispeed(&new_termios,B9600);
            cfsetospeed(&new_termios,B9600);

            tcsetattr(fd, TCSANOW, &new_termios);

            return fd;
    }
}

I am running the program on Cubieboard2 with Debian (raspberrypi) distribution. When I run the program manually, it works fine. But when the program is launched on boot by init.d script, it runs properly and performs other tasks (reading and writing files) well but it does not read any data sent on serial port.

lsof /dev/ttyUSB1

also shows that the port is being used by my program. Any ideas?

Arshan
  • 736
  • 6
  • 19

1 Answers1

1

You should initialize the termios structure more completely, e.g. cflags, VMIN and VTIME, as in this working code, or like this using the perror() syscall:

    rc = tcgetattr(sfd, &tty);
    if (rc < 0) {
        perror("failed to get attr");
        exit (-2);
    }
    savetty = tty;    /* preserve original settings for restoration */

    spd = B115200;
    cfsetospeed(&tty, (speed_t)spd);
    cfsetispeed(&tty, (speed_t)spd);

    cfmakeraw(&tty);

    tty.c_cc[VMIN] = 1;    /* wait for at least 1 char */
    tty.c_cc[VTIME] = 10;  /* or 1 sec after a char */

    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CRTSCTS;    /* no HW flow control */
    tty.c_cflag |= CLOCAL | CREAD;

    rc = tcsetattr(sfd, TCSANOW, &tty);
    if (rc < 0) {
        perror("failed to set attr");
        exit (-3);
    }

You should also be testing every return code from all syscalls, especially when you encounter issues.


Looking over your code again, the first argument to tcgetattr() is obviously incorrect:

        tcgetattr(0, &orig_termios);

Defensive coding (e.g. validating parameters and checking return calls) is helpful in catching these types of silly mistakes that can consume a lot of debugging time.


ADDENDUM

I think I understand why the code seemed to work in the first situation, when started "manually" from the shell.
The file descriptor value of 0 is the value of STDIN_FILENO.
So the tcgetattr(0, &orig_termios) statement would retrieve the termios values for stdin. (Initially I assumed you always got an undetected error return, so the structure would be returned unmodified.) Presumably you executed this on an embedded system, where the console is a serial port (and the returned values for stdin are a serial port's).

When I ran this code on a PC, cflags is provided with the CREAD flag disabled, and that should have caused a problem later. Note that setting cflags was one of my recommendations. VMIN and VTIME are returned as 8 and 4 respectively, but those unusual values would not have been fatal like the CREAD flag. There are other unusual termios values from the stdin video console, and a few would be corrected by your (minimal) initialization code or, since non-canonical mode is used, most of the unusual values are irrelevant.

Community
  • 1
  • 1
sawdust
  • 16,103
  • 3
  • 40
  • 50
  • Thanks alot @sawdust. Testing return codes from syscalls revealed the cause of error. Changing first argument of tcgetattr() to my port fd resolved error. – Arshan Dec 29 '14 at 09:37
  • You're welcome. Glad to see a generic advice that I've written over a dozen times to actually help. But it's scary to think that random or garbage data in the termios structure would "work" in your first situation. You were unlucky because it seemed to work at first; you probably would have found the typo sooner if the code never worked at all. – sawdust Dec 29 '14 at 22:18
  • I think tcgetattr(0, &orig_termios) was returning me the parameters set by linux for pseudoterminal. Thats why structure didnt contain garbage in that case. – Arshan Dec 30 '14 at 07:12
  • 1
    You're correct, zero can be a valid file descriptor value. See above for results of my curiosity. – sawdust Dec 31 '14 at 07:26