Async serial communication in non-canonical (raw) mode and generating SIGIO in linux/osx

别来无恙 提交于 2019-12-25 08:34:15

问题


To start off, I'm having trouble getting my serial device to generate a SIGIO when data is ready to be read.

I am trying to write a simple serial interface to communicate to a micro using a usb to serial adapter. I'd like to keep this interface as similar to one you would find in a micro (interrupt driven, using callbacks) and so I decided to go the way of catching a SIGIO signal instead of using a separate thread or constant non-blocking serial reads. Here is my initialization code (most of it will look familiar from the various asynchronous serial tutorials):

int mcs = TIOCM_RTS;
ttyDev = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK);

if (!ttyDev)
{
  printf("couldn't open serial device");
  return NULL;
}

//create signal handler
byteAction.sa_handler = byteCallback;
sigemptyset(&byteAction.sa_mask); //sa_mask = 0
byteAction.sa_flags = SA_RESTART;
sigaction(SIGPOLL, &byteAction, NULL);

//Allow process to detect SIGIO
fcntl(ttyDev, F_SETOWN, getpid());
fcntl(ttyDev, F_SETFL, FASYNC); //make async
fcntl(ttyDev, F_SETFL, FNDELAY);  //non blocking reads


tcgetattr(ttyDev, &oldtio); //backup current settings
newtio.c_cflag = getBaud(baudrate) | CS8 | CLOCAL | CREAD;
newtio.c_cflag &= ~CRTSCTS; //disable hw flow control
newtio.c_iflag &= ~(IXON | IXOFF | IXANY); //disable flow control
newtio.c_iflag |= IGNPAR; //ignore parity
newtio.c_oflag = 0;
newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //raw mode
newtio.c_cc[VMIN] = 1; 
newtio.c_cc[VTIME] = 0;
cfsetspeed(&newtio, getBaud(baudrate));
tcflush(ttyDev, TCIFLUSH);
tcsetattr(ttyDev, TCSANOW, &newtio);

//clear RTS
ioctl(ttyDev, TIOCMBIC, &mcs);

byteCallback is my signal handler. I already verified that it works by sending the process a signal manually. The micro I am communicating with does not support any sort of flow control, so that is disabled. I've verified that I can read and write from the device by using the standard read/write system calls.

The problem is that when data comes in, the signal handler doesn't get called. I suspect it is because SIGIO is only generated when a CR or end of line character is received. Since this is completely raw mode and no such character is being sent, no SIGIO is being generated. At the moment I have only tried this on OSX, but ideally the same code would work on linux as well.

Any help would be appreciated. I've searched quite a bit and people always end up suggesting to just use select() or another method. It's become almost a challenge and I'm not ready to give up just yet.

Thanks.


回答1:


Generation of SIGIO definitely has nothing to do with CR/NL. Your problem is that right after you set the FASYNC flag, you cleared it:

fcntl(ttyDev, F_SETFL, FASYNC); //make async
fcntl(ttyDev, F_SETFL, FNDELAY);  //non blocking reads AND CLEAR FASYNC FLAG

What you should be doing is:

fcntl(ttyDev, F_SETFL, O_ASYNC|O_NONBLOCK);

or preferably (to avoid clearing any other flags that may have already been set):

fcntl(ttyDev, F_SETFL, O_ASYNC|O_NONBLOCK|fcntl(ttyDev, F_GETFL));

Note that I also took the liberty of replacing the weird nonstandard flag names you were using with the corresponding standard names. :-)



来源:https://stackoverflow.com/questions/10134369/async-serial-communication-in-non-canonical-raw-mode-and-generating-sigio-in-l

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!