为什么串行端口read()返回零而不是数据



目标:

在Linux 18 Jetson NANO上配置一个串行端口/dev/ttyTHS1,带有中断器和Sbus的非标准波特率。有趣的是,它一直完美地工作到今天。备份没有效果。

附言:出于测试目的,代码是从几个文件中组合而来的,所以我可能会犯一些错误。


#include <iostream>
#include <asm/termios.h>
#include <asm/ioctls.h>
#include <sys/signal.h>
#include <stropts.h>
#include <unistd.h>

using namespace std;

bool Ports::setup_port_Sbus(Info* port)
{
//> check descriptor
if (!isatty(fd)) { throw "File description is NOT a serial port!"; }

//> read fole descriptor config
struct termios2 config = { 0 };

//> for interrupt
struct sigaction saio;
sigset_t mskvar;
sigfillset(&mskvar);
sigprocmask(SIG_SETMASK, &mskvar, NULL);
sigdelset(&mskvar, SIGIO);
saio.sa_handler = signal_io_handler;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO, &saio, NULL);

if (ioctl(fd, TCGETS2, &config) < 0) { throw "Could not read config of FD!"; }

config.c_cflag |= PARENB;  // enable parity
config.c_cflag &= ~PARODD; // even parity
config.c_cflag |= CSTOPB;  // enable 2 stop bits
config.c_cflag &= ~CSIZE;  // clear character size mask
config.c_cflag |= CS8;     // 8 bit characters
config.c_cflag &= ~CRTSCTS;  // disable hardware flow control
config.c_cflag |= CREAD;   // enable receiver
config.c_cflag |= CLOCAL;  // ignore modem lines

config.c_lflag &= ~ICANON;  // receive characters as they come in
config.c_lflag &= ~ECHO;    // do not echo
config.c_lflag &= ~ISIG;    // do not generate signals
config.c_lflag &= ~IEXTEN;  // disable implementation-defined processing

config.c_iflag &= ~(IXON | IXOFF | IXANY);  // disable XON/XOFF flow control
config.c_iflag |= IGNBRK;   // ignore BREAK condition
config.c_iflag |= INPCK;    // enable parity checking
config.c_iflag |= IGNPAR;   // ignore framing and parity errors
config.c_iflag &= ~ISTRIP;  // do not strip off 8th bit
config.c_iflag &= ~INLCR;   // do not translate NL to CR
config.c_iflag &= ~ICRNL;   // do not translate CR to NL
config.c_iflag &= ~IGNCR;   // do not ignore CR

config.c_oflag &= ~OPOST;  // disable implementation-defined processing
config.c_oflag &= ~ONLCR;  // do not map NL to CR-NL
config.c_oflag &= ~OCRNL;  // do not map CR to NL
config.c_oflag &= ~(ONOCR | ONLRET);  // output CR like a normal person
config.c_oflag &= ~OFILL;  // no fill characters

// Apply baudrate
speed_t br = 100000;
config.c_ispeed = br;
config.c_ospeed = br;
config.c_cc[VMIN] = 0;
config.c_cc[VTIME] = 0;

//> Finally, apply the configuration
if (ioctl(fd, TCSETS2, &config) < 0) { throw "Could not set configuration of fd!"; }

// Done!
return true;
}

void port_init(){

const char* _name = "/dev/ttyTHS1";
int fd = -1;

fd = open(_name, O_RDWR | O_NOCTTY );
if (fd < 0) { throw "File is not open!"; }
else{
fcntl(fd, F_SETFL, O_NONBLOCK|O_ASYNC);
}

bool setup = setup_port_Sbus(fd);

if (!setup) { throw "Could not configure port"; }
if (fd <= 0) { throw "Connection attempt to port failed, exiting"; }

}

struct Sbus_data{
bool    lost_frame;
int failsafe;
bool    ch17;
bool    ch18;
static int8_t   SBUS_NUM_CH             = 16;
int     last_ch[SBUS_NUM_CH]    = {};
int     ch[SBUS_NUM_CH]     = {};
};

int main(){

try{
port_init();
}
catch(const char* err){
cout << "ERR: " << err << endl;
}

uint8_t byte;
uint8_t sb_buf[SBUS_PACKET_LEN] = {};
const int8_t SBUS_PACKET_LEN    = 25;
const int8_t SBUS_NUM_SBUS_CH   = 16;
const uint8_t SBUS_HEADER   = 0x0F;
const uint8_t SBUS_FOOTER   = 0x00;
const uint8_t SBUS_FOOTER2  = 0x04;
const uint8_t SBUS_CH17_MASK    = 0x01;
const uint8_t SBUS_CH18_MASK    = 0x02;
const uint8_t SBUS_LOST_FRAME_MASK = 0x04;
const uint8_t SBUS_FAILSAFE_MASK = 0x08;
Sbus_data           sb_data;
int sb_state                    = 0;

do{
count_read_symb = read(port->file_descriptor, &byte, 1);
if(count_read_symb <= 0)
{
cout << "byte: " << byte << " | errno: "<< errno << endl;
continue;
}

//> wrong start
if(sb_state == 0 && byte != SBUS_HEADER)
{
continue;
}

sb_buf[sb_state++] = byte;

//> index done
if(sb_state == SBUS_PACKET_LEN)
{
sb_state = 0;
if(sb_buf[24] != SBUS_FOOTER)
{
continue;
}

sb_data.ch[0]  = ((sb_buf[1]    |sb_buf[2]<<8)                 & 0x07FF);
sb_data.ch[1]  = ((sb_buf[2]>>3 |sb_buf[3]<<5)                 & 0x07FF);
sb_data.ch[2]  = ((sb_buf[3]>>6 |sb_buf[4]<<2 |sb_buf[5]<<10)  & 0x07FF);
sb_data.ch[3]  = ((sb_buf[5]>>1 |sb_buf[6]<<7)                 & 0x07FF);
sb_data.ch[4]  = ((sb_buf[6]>>4 |sb_buf[7]<<4)                 & 0x07FF);
sb_data.ch[5]  = ((sb_buf[7]>>7 |sb_buf[8]<<1 |sb_buf[9]<<9)   & 0x07FF);
sb_data.ch[6]  = ((sb_buf[9]>>2 |sb_buf[10]<<6)                & 0x07FF);
sb_data.ch[7]  = ((sb_buf[10]>>5|sb_buf[11]<<3)                & 0x07FF);
sb_data.ch[8]  = ((sb_buf[12]   |sb_buf[13]<<8)                & 0x07FF);
sb_data.ch[9]  = ((sb_buf[13]>>3|sb_buf[14]<<5)                & 0x07FF);
sb_data.ch[10] = ((sb_buf[14]>>6|sb_buf[15]<<2|sb_buf[16]<<10) & 0x07FF);
sb_data.ch[11] = ((sb_buf[16]>>1|sb_buf[17]<<7)                & 0x07FF);
sb_data.ch[12] = ((sb_buf[17]>>4|sb_buf[18]<<4)                & 0x07FF);
sb_data.ch[13] = ((sb_buf[18]>>7|sb_buf[19]<<1|sb_buf[20]<<9)  & 0x07FF);
sb_data.ch[14] = ((sb_buf[20]>>2|sb_buf[21]<<6)                & 0x07FF);
sb_data.ch[15] = ((sb_buf[21]>>5|sb_buf[22]<<3)                & 0x07FF);

((sb_buf[23])      & 0x0001) ? sb_data.ch[16] = 2047: sb_data.ch[16] = 0;
((sb_buf[23] >> 1) & 0x0001) ? sb_data.ch[17] = 2047: sb_data.ch[17] = 0;

if ((sb_buf[23] >> 3) & 0x0001) { sb_data.failsafe = 1; }
else { sb_data.failsafe = 0; }

cout << "DONE!" << endl;
}
}
while(count_read_symb > 0);
}
  • 我用sudo sh‘cat检查了端口缓冲区<dev/tytyTHS1'Putty,所有数据都在那里,但read((返回零
  • 端口在我有权访问的dialout组中,它被配置为-rw-,并且在端口初始化阶段没有发现错误

此外,我有/dev/ttyUSB1和/ttyUSB0的TTL标志略有不同(无奇偶校验/br=115200/1停止位(,但它们工作得很好。

感谢@SKi,我检查了这些标志。

解决方案:

// Apply baudrate
speed_t br = 100000;
config.c_ispeed = br;
config.c_ospeed = br;
config.c_cflag &= ~CBAUD; // !!!!!
config.c_cflag |= BOTHER; // !!!!!
config.c_cc[VMIN] = 0;
config.c_cc[VTIME] = 0;

出于某种原因,代码过去没有这两行代码。它们现在是必需的。

最新更新