Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setting serial port interruption in linux

I am trying to set the interruption for a serial port in ubuntu (in program written in C), but it does not work. I have checked that the serial communication works correctly without the interruption, so I may be setting something wrong. The code is the following:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <fcntl.h>
    #include <sys/signal.h>
    #include <errno.h>
    #include <termios.h>

    void signal_handler_IO (int status);   /* definition of signal handler */

    int n;
    int fd;
    int connected;
    struct termios termAttr;
    struct sigaction saio;

    int main(int argc, char *argv[])
    {
         fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
         if (fd == -1)
         {
            perror("open_port: Unable to open /dev/ttyO1\n");
            exit(1);
         }

         saio.sa_handler = signal_handler_IO;
         saio.sa_flags = 0;
         saio.sa_restorer = NULL; 
         sigaction(SIGIO,&saio,NULL);

         fcntl(fd, F_SETFL, FNDELAY);
         fcntl(fd, F_SETOWN, getpid());

         tcgetattr(fd,&termAttr);
         baudRate = B115200; 
         cfsetispeed(&termAttr,B115200);
         cfsetospeed(&termAttr,B115200);
         termAttr.c_cflag &= ~PARENB;
         termAttr.c_cflag &= ~CSTOPB;
         termAttr.c_cflag &= ~CSIZE;
         termAttr.c_cflag |= CS8;
         termAttr.c_cflag |= (CLOCAL | CREAD);
         termAttr.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
         termAttr.c_iflag &= ~(IXON | IXOFF | IXANY);
         termAttr.c_oflag &= ~OPOST;
         tcsetattr(fd,TCSANOW,&termAttr);
         printf("UART1 configured....\n");

         connected = 1;
         while(connected == 1){
               // some code
         }

         close(fd);
         exit(0);             
    }

    void signal_handler_IO (int status)
    {
         printf("received data from UART.\n");
    }

So anytime time another device send a message through the configured port, the message "received data from UART." is never displayed.

Any suggestion to solve this problem? Also, how does the system relate the interruption with the serial port?, I have read about signal.h but I have not found an answer for that. I got the interruption idea from this page: http://www.faqs.org/docs/Linux-HOWTO/Serial-Programming-HOWTO.html

Thanks in advance for any help. Thanks in advance.

like image 835
gus Avatar asked Feb 27 '13 18:02

gus


2 Answers

I have found that a piece of code is missing for the original code to work as expected. The code below is working on Linux compiled with gcc. The added line of code is the one marked with /**<<<<<<------This line made it work.**/
One line was also commented out : //baudRate = B115200;.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <errno.h>
#include <termios.h>

void signal_handler_IO (int status);   /* definition of signal handler */

int n;
int fd;
int connected;
struct termios termAttr;
struct sigaction saio;

int main(int argc, char *argv[])
{
     fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
     if (fd == -1)
     {
        perror("open_port: Unable to open /dev/ttyO1\n");
        exit(1);
     }

     saio.sa_handler = signal_handler_IO;
     saio.sa_flags = 0;
     saio.sa_restorer = NULL; 
     sigaction(SIGIO,&saio,NULL);

     fcntl(fd, F_SETFL, FNDELAY);
     fcntl(fd, F_SETOWN, getpid());
     fcntl(fd, F_SETFL,  O_ASYNC ); /**<<<<<<------This line made it work.**/

     tcgetattr(fd,&termAttr);
     //baudRate = B115200;          /* Not needed */
     cfsetispeed(&termAttr,B115200);
     cfsetospeed(&termAttr,B115200);
     termAttr.c_cflag &= ~PARENB;
     termAttr.c_cflag &= ~CSTOPB;
     termAttr.c_cflag &= ~CSIZE;
     termAttr.c_cflag |= CS8;
     termAttr.c_cflag |= (CLOCAL | CREAD);
     termAttr.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
     termAttr.c_iflag &= ~(IXON | IXOFF | IXANY);
     termAttr.c_oflag &= ~OPOST;
     tcsetattr(fd,TCSANOW,&termAttr);
     printf("UART1 configured....\n");

     connected = 1;
     while(connected == 1){
           // some code
     }

     close(fd);
     exit(0);             
}

void signal_handler_IO (int status)
{
     printf("received data from UART.\n");
}

The output from the program was:

./a.out 
UART1 configured....
received data from UART.
received data from UART.
received data from UART.
^C

I hope that works for you too.

like image 83
user2178077 Avatar answered Sep 26 '22 01:09

user2178077


The problem is that you're disabling signals from the file descriptor by clearing the FASYNC flag with F_SETFL. You need to set that if you want to get signals:

fcntl(fd, F_SETFL, FNDELAY|FASYNC);

Also, you might want to use the POSIX names for these flags (O_NDELAY and O_ASYNC) rather than the BSD names for more portability, though either will work on Linux.

like image 30
Chris Dodd Avatar answered Sep 26 '22 01:09

Chris Dodd