修改
我实际上认为我可能已经弄明白了:有没有人知道如果某个程序在串口上阻塞并且使用控件+ c终止会发生什么,会发生什么?
看起来答案可能是端口无法配置,因为它已被锁定或其他东西。我很感激这个问题的答案,但如果答案是“行为未定义,我不会感到惊讶!”
以下是我提出的原始问题。
我有一些代码,我已经使用了多年来从linux中的串口读取和写入,突然间它正在起作用。我希望我犯了一些相对明显的错误,但是我已经对代码敲了几天而且没有取得任何进展。
代码来自较旧版本的cutecom,然后从minicom获取代码,但在我试图弄清楚为什么cutecom工作时我的横冲直撞导致我只是直接复制例程最新版的cutecom。
基本的失败模式如下:要么我得到一堆空字符(即我发送一个字节并取回三个字节的空),或者我得到其他乱码(即0xff字符,只有两个或三个)更长的字符串)。这发生在多个USB到串行适配器上,并且似乎表明某种波特率不匹配......
提前抱歉关于巨大的代码blob,但我试图留下我认为可能导致问题的部分(文件打开,termios设置和读取)......
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <ctype.h>
// UNIX Includes
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
int main(int argc, char *argv[])
{
int i, baud= 9600, fd_port= -1;
unsigned char in_c, valid= 0;
char *devname= NULL;
unsigned char inbuf[BUFSZ];
/* some code which reads in and parses parameters omitted */
fd_port= open(devname, O_RDWR); //| O_NOCTTY, O_ASYNC); // weird options don't help!
if(fd_port < 0) {
fprintf(stderr, "Failed to open port\"%s\"\n", devname);
exit(-1);
}
setPortOptions(fd_port, baud, 8, 0, 1, false, false);
while(1) {
readb= 0;
while(recvstr[readb] != '\0') {
ret= read(fd_port, &in_c, 1);
if(ret < 0) {
fprintf(stderr, "Error reading from port!\n");
exit(-1);
} else if(ret > 0 && recvstr[readb] != in_c) {
fprintf(stderr, "Discarding \"%02x\" from input\n", in_c);
break;
} else if(ret == 0) {
fprintf(stderr, "Reached EOF\n");
exit(-1);
} else {
readb+= ret;
}
}
/* Some code which does some stuff after getting an init string */
}
// cleanup
}
/* setPortOptions - takes in a set of options and applies it to fd
in - a file descriptor, baud rate, data bits, parity (0, 1, 2),
stop (1 or 2), soft handshake (bool), hardware handshake (bool)
out - nothing
This function was taken and modified from cutecom 1.12, qcppdialogimpl.cpp
This function features some code from minicom 2.0.0, src/sysdep1.c
*/
void setPortOptions(int fd, int baudrate, int databits, int parity, int stop,
bool softwareHandshake, bool hardwareHandshake)
{
struct termios newtio;
// memset(&newtio, 0, sizeof(newtio));
if(tcgetattr(fd, &newtio) != 0) {
fprintf(stderr, "tcgetattr() 3 failed\n");
}
speed_t _baud= -1;
switch (baudrate)
{
#ifdef B0
case 0: _baud= B0; break;
#endif
#ifdef B50
case 50: _baud= B50; break;
#endif
/* This continues for quite a while */
#ifdef B921600
case 921600: _baud= B921600; break;
#endif
default:
fprintf(stderr, "Invalid baud, not changing!\n");
break;
}
if(_baud != -1) {
cfsetospeed(&newtio, _baud);
cfsetispeed(&newtio, _baud);
}
switch(databits) {
case 5:
newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS5;
break;
/* same code for 6 and 7 bits */
case 8:
default:
newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS8;
break;
}
// ignore modem control lines and enable the receiver
newtio.c_cflag |= CLOCAL | CREAD;
// parity (0 == no parity, 1 == odd, 2 == even)
newtio.c_cflag &= ~(PARENB | PARODD);
if(parity == 2) {
newtio.c_cflag |= PARENB;
} else if(parity == 1) {
newtio.c_cflag |= (PARENB | PARODD);
} else if(parity != 0) {
fprintf(stderr, "Invalid parity!\n");
}
// disable hardware handshake
newtio.c_cflag &= ~CRTSCTS;
// Set 1 stopbit
newtio.c_cflag &= ~CSTOPB;
if(stop == 2) {
newtio.c_cflag |= CSTOPB;
} else if(stop != 1) {
fprintf(stderr, "Invalid stop bit selection! Must be 1 or 2\n"
"Defaulting to 1\n");
}
// Ignore "BREAK" condition on input
newtio.c_iflag= IGNBRK;
// software handshake (non-zero == enabled, zero == disabled)
if(softwareHandshake) {
newtio.c_iflag |= IXON | IXOFF;
} else {
newtio.c_iflag &= ~(IXON | IXOFF | IXANY);
}
// clear out the local and output modes
newtio.c_lflag= 0;
newtio.c_oflag= 0;
// Set timeout to 0
newtio.c_cc[VTIME]= 0;
// 1 char minimum for a non-canonical read
newtio.c_cc[VMIN]= 1;
// tcflush(fd, TCIFLUSH);
if(tcsetattr(fd, TCSANOW, &newtio) != 0)
fprintf(stderr, "tcsetattr() 1 failed\n");
int mcs= 0;
ioctl(fd, TIOCMGET, &mcs);
mcs |= TIOCM_RTS;
ioctl(fd, TIOCMSET, &mcs);
if(tcgetattr(fd, &newtio) != 0)
fprintf(stderr, "tcgetattr() 4 failed\n");
// hardware handshake
if(hardwareHandshake) {
newtio.c_cflag |= CRTSCTS;
} else {
newtio.c_cflag &= ~CRTSCTS;
}
if(tcsetattr(fd, TCSANOW, &newtio) != 0)
fprintf(stderr, "tcsetattr() 2 failed\n");
}