Последовательная связь в Linux с включенным управлением потоком - плохое поведение
Я написал общие функции для управления последовательными портами, основываясь на следующей структуре:
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 секунд).
Однако, если функция setuart() вызывается с flowControl == 0, тест не блокируется и возвращает ожидаемый код ошибки без задержки.
Я, наверное, что-то неправильно понял, особенно в конфигурации порта. Это хороший способ сделать?
1 ответ
Проблема, с которой вы сталкиваетесь, - это правильное поведение.
Если CTS не подключен с включенным управлением потоком, это означает, что DTE (AKA PC) не может отправлять данные в DCE (подчиненное устройство).
Когда вы пытаетесь записать в выходной буфер UART, он, вероятно, переполнен, и приложение временно прекращает работу и ждет, пока освободится некоторое пространство буфера.