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.
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.
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.
Any suggestion to solve this problem? Also, how does the system relate the interruption with the serial port?
The serial port interrupt is written inside the device part of the serial driver in linux kernel. The interrupt is handled by the driver itself , so you can have not control over it.
What the above program is doing is , notifying you through a signal , when a receive interrupt
of the serial part device is triggered.
The above signal handling is not related to interrupts , it is more of even handling.
First you register , your program , to get a signal when an io interrupt occours , the signal handler in your program will then display the printf message.
I think the signal handling in your program , is not implemented properly
Just correct the signal parts of your program
sigset_t mskvar_1 //Variable of signal bitfieldtype
struct sigaction sigio_action //Structure which describes signal handler
void sio_handler(void); //Signal handler function
int main()
{
sigfillset(&mskvar_1); //set all mask bits of maskbit variable
sigprocmask(SIG_SETMASK,&mskvar_1,NULL); //write the mask info present in mskvar_1 to the pd
sigdelset(&mskvar_1,SIGIO); //Unmask SIGIO , to register for IO Interrupt Events
sigio_action.sa_handler = sio_handler; //Configure Signal Handler
sigio_action.sa_flags = 0;
sigfillset(&sigio_action.sa_mask);
sigaction(SIGIO,&sigio_action,NULL); //Install Signal handler
// Serial port initializtion here
// Set Serial port parameters , Baud Rate and flags
while(1);
return 0;
}
void sio_handler()
{
printf("\nSIGIO RECEIVED , I/O interrupt signalled?\n");
return;
}