在 Linux 上启用流控制的串行通信 - 不良行为
Serial communication on Linux with flow control enabled - bad behaviour
我为了管理串口写了常用函数,基于以下结构:
typedef struct
{
int PHandle;
unsigned int Port;
unsigned int BaudRate;
unsigned char Parity;
unsigned char FlowControl;
char Device[MAX_SIZE];
} Tst_SPort;
我在另一个文件中调用这些函数(见下文)以测试 RS232 串口。需要开启流量控制。
int iInit(Tst_SPort *port, const char *device, int baudRate, unsigned char parity, unsigned char flowControl)
{
strncpy(port->Device, device, MAX_SIZE);
port->PHandle = iOpen(port);
port->Port = -1;
port->BaudRate = baudRate;
port->Parity = parity;
port->FlowControl = flowControl;
if(port->PHandle > 0)
{
setuart(port, port->BaudRate);
}
return port->PHandle;
}
int iOpen(Tst_SPort *port)
{
port->PHandle = open(port->Device, O_RDWR | O_NOCTTY);
if(port->PHandle < 0)
{
perror("open:");
return (-1);
}
return (port->PHandle);
}
void setuart(Tst_SPort *port, int baudRate)
{
struct termios opt, optCmp;
struct serial_struct info;
if(port->PHandle > 0)
{
bzero(&opt, sizeof(opt));
bzero(&optCmp, sizeof(optCmp));
if(ioctl(port->PHandle, TIOCGSERIAL, &info) == 0)
port->Port = info.port;
fcntl(port->PHandle, F_SETFL, O_NONBLOCK);
if (tcgetattr(port->PHandle, &opt) < 0)
perror("tcgetattr Get:");
if(baudRate > 0)
{
cfsetospeed (&opt, baudRate);
cfsetispeed (&opt, baudRate);
}
opt.c_iflag = IGNPAR;
opt.c_oflag &= ~OPOST
opt.c_oflag &= ~ONLCR;
opt.c_lflag = 0;
opt.c_cflag |= (CLOCAL | CREAD);
opt.c_cflag &= ~(PARENB | PARODD);
opt.c_cflag |= port->Parity;
opt.c_cflag &= ~CSTOPB;
opt.c_cflag &= ~CSIZE;
opt.c_cflag |= CS8;
if(!port->FlowControl)
opt.c_cflag &= ~CRTSCTS;
else
opt.c_cflag |= CRTSCTS;
opt.c_cc[VMIN] = 0;
opt.c_cc[VTIME] = 50;
if(tcsetattr(opt->PHandle, TCSANOW, &opt) < 0)
perror("tcgetattr Update :");
if (tcgetattr(opt->PHandle, &optCmp) < 0)
perror("tcgetattr Read:");
/* Compare */
if (memcmp((void *)&opt, (void *)&optCmp, sizeof(opt)) != 0)
printf("Conf failed");
tcflush(port->PHandle, TCIFLUSH);
}
}
int iRead(Tst_SPort *port, char *buffer, unsigned long buffLength)
{
struct timeval tv;
fd_set recv;
int s32Read = 0;
int s32Offset = 0;
int s32SRes = 0;
tv.tv_sec = 0;
tv.tv_usec = 100000; /* 100ms */
if ((port) && (port->PHandle > 0))
{
while (s32Offset < buffLength)
{
FD_ZERO(&recv);
FD_SET(port->PHandle, &recv);
s32SRes = select(port->PHandle + 1, &recv, NULL, NULL, &tv);
if ((s32SRes == -1) && (errno == EINTR))
{
continue;
}
else if(s32SRes > 0)
{
if (FD_ISSET(port->PHandle, &recv))
{
s32Read = read(port->PHandle, buffer + s32Offset, buffLength - s32Offset);
if(s32Read > 0)
{
tv.tv_sec = 0;
tv.tv_usec = 5000;
s32Offset += s32Read;
continue;
}
}
}
break;
}
}
return s32Offset;
}
int iClose(Tst_SPort *port)
{
return (close(port->Phandle));
}
为了验证实施,引脚 Tx 和 Rx 已连接在一起,CTS 和 RTS 同上。一切正常,可以正确读取发送的消息。此外,当 Tx 与 Rx 断开连接时,没有任何内容按预期读取。
但是,当 CTS 从 RTS 上拔下时,测试会在端口关闭步骤(约 20 秒)后阻塞。
但是,如果在 flowControl == 0 的情况下调用函数 setuart(),则测试不会阻塞并且 returns 预期的错误代码不会延迟。
我可能理解有误,尤其是在端口配置方面。这是做事的好方法吗?
您遇到的问题是正确的行为。
在启用流控制的情况下保持 CTS 未连接,意味着 DTE(又名 PC)无法向 DCE(从设备)发送数据。
当您尝试写入 UART 输出缓冲区时,它可能已满,应用程序暂时停止 运行 并等待缓冲区 space 可用。
我为了管理串口写了常用函数,基于以下结构:
typedef struct
{
int PHandle;
unsigned int Port;
unsigned int BaudRate;
unsigned char Parity;
unsigned char FlowControl;
char Device[MAX_SIZE];
} Tst_SPort;
我在另一个文件中调用这些函数(见下文)以测试 RS232 串口。需要开启流量控制。
int iInit(Tst_SPort *port, const char *device, int baudRate, unsigned char parity, unsigned char flowControl)
{
strncpy(port->Device, device, MAX_SIZE);
port->PHandle = iOpen(port);
port->Port = -1;
port->BaudRate = baudRate;
port->Parity = parity;
port->FlowControl = flowControl;
if(port->PHandle > 0)
{
setuart(port, port->BaudRate);
}
return port->PHandle;
}
int iOpen(Tst_SPort *port)
{
port->PHandle = open(port->Device, O_RDWR | O_NOCTTY);
if(port->PHandle < 0)
{
perror("open:");
return (-1);
}
return (port->PHandle);
}
void setuart(Tst_SPort *port, int baudRate)
{
struct termios opt, optCmp;
struct serial_struct info;
if(port->PHandle > 0)
{
bzero(&opt, sizeof(opt));
bzero(&optCmp, sizeof(optCmp));
if(ioctl(port->PHandle, TIOCGSERIAL, &info) == 0)
port->Port = info.port;
fcntl(port->PHandle, F_SETFL, O_NONBLOCK);
if (tcgetattr(port->PHandle, &opt) < 0)
perror("tcgetattr Get:");
if(baudRate > 0)
{
cfsetospeed (&opt, baudRate);
cfsetispeed (&opt, baudRate);
}
opt.c_iflag = IGNPAR;
opt.c_oflag &= ~OPOST
opt.c_oflag &= ~ONLCR;
opt.c_lflag = 0;
opt.c_cflag |= (CLOCAL | CREAD);
opt.c_cflag &= ~(PARENB | PARODD);
opt.c_cflag |= port->Parity;
opt.c_cflag &= ~CSTOPB;
opt.c_cflag &= ~CSIZE;
opt.c_cflag |= CS8;
if(!port->FlowControl)
opt.c_cflag &= ~CRTSCTS;
else
opt.c_cflag |= CRTSCTS;
opt.c_cc[VMIN] = 0;
opt.c_cc[VTIME] = 50;
if(tcsetattr(opt->PHandle, TCSANOW, &opt) < 0)
perror("tcgetattr Update :");
if (tcgetattr(opt->PHandle, &optCmp) < 0)
perror("tcgetattr Read:");
/* Compare */
if (memcmp((void *)&opt, (void *)&optCmp, sizeof(opt)) != 0)
printf("Conf failed");
tcflush(port->PHandle, TCIFLUSH);
}
}
int iRead(Tst_SPort *port, char *buffer, unsigned long buffLength)
{
struct timeval tv;
fd_set recv;
int s32Read = 0;
int s32Offset = 0;
int s32SRes = 0;
tv.tv_sec = 0;
tv.tv_usec = 100000; /* 100ms */
if ((port) && (port->PHandle > 0))
{
while (s32Offset < buffLength)
{
FD_ZERO(&recv);
FD_SET(port->PHandle, &recv);
s32SRes = select(port->PHandle + 1, &recv, NULL, NULL, &tv);
if ((s32SRes == -1) && (errno == EINTR))
{
continue;
}
else if(s32SRes > 0)
{
if (FD_ISSET(port->PHandle, &recv))
{
s32Read = read(port->PHandle, buffer + s32Offset, buffLength - s32Offset);
if(s32Read > 0)
{
tv.tv_sec = 0;
tv.tv_usec = 5000;
s32Offset += s32Read;
continue;
}
}
}
break;
}
}
return s32Offset;
}
int iClose(Tst_SPort *port)
{
return (close(port->Phandle));
}
为了验证实施,引脚 Tx 和 Rx 已连接在一起,CTS 和 RTS 同上。一切正常,可以正确读取发送的消息。此外,当 Tx 与 Rx 断开连接时,没有任何内容按预期读取。
但是,当 CTS 从 RTS 上拔下时,测试会在端口关闭步骤(约 20 秒)后阻塞。
但是,如果在 flowControl == 0 的情况下调用函数 setuart(),则测试不会阻塞并且 returns 预期的错误代码不会延迟。
我可能理解有误,尤其是在端口配置方面。这是做事的好方法吗?
您遇到的问题是正确的行为。
在启用流控制的情况下保持 CTS 未连接,意味着 DTE(又名 PC)无法向 DCE(从设备)发送数据。
当您尝试写入 UART 输出缓冲区时,它可能已满,应用程序暂时停止 运行 并等待缓冲区 space 可用。