简体   繁体   English

非规范(原始)模式下的异步串行通信,以及在linux / osx中生成SIGIO

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

To start off, I'm having trouble getting my serial device to generate a SIGIO when data is ready to be read. 首先,当数据准备好被读取时,我无法让我的串行设备生成SIGIO。

I am trying to write a simple serial interface to communicate to a micro using a usb to serial adapter. 我正在尝试编写一个简单的串行接口,使用usb到串行适配器与micro进行通信。 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. 我想保持这个接口类似于你在micro(中断驱动,使用回调)中找到的接口,所以我决定采用捕获SIGIO信号的方式而不是使用单独的线程或常量非阻塞串行读取。 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. byteCallback是我的信号处理程序。 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. 我怀疑这是因为SIGIO仅在收到CR或行尾字符时生成。 Since this is completely raw mode and no such character is being sent, no SIGIO is being generated. 由于这是完全原始模式并且没有发送此类字符,因此不会生成SIGIO。 At the moment I have only tried this on OSX, but ideally the same code would work on linux as well. 目前我只在OSX上试过这个,但理想情况下相同的代码也可以在linux上运行。

Any help would be appreciated. 任何帮助,将不胜感激。 I've searched quite a bit and people always end up suggesting to just use select() or another method. 我搜索了很多,人们总是建议只使用select()或其他方法。 It's become almost a challenge and I'm not ready to give up just yet. 这几乎是一个挑战,我还没准备好放弃。

Thanks. 谢谢。

Generation of SIGIO definitely has nothing to do with CR/NL. SIGIO生成肯定与CR / NL无关。 Your problem is that right after you set the FASYNC flag, you cleared it: 您的问题是,在您设置FASYNC标志后,您清除它:

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. 请注意,我还冒昧地使用相应的标准名称替换您使用的奇怪的非标准标志名称。 :-) :-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM