Я реализовал блокировку чтения из последовательного порта в C. Моя цель - прочитать, какие блоки блокируются до поступления новых данных.
Вот как я реализовал последовательный псевдообъект (я удалил многопоточную защиту для более ясного кода).
typedef struct
{
int fd;
se_serial_speed_t speed;
se_serial_parity_t parity;
bool flow_control;
}se_serial_t;
int se_serial_constructor(se_serial_t** self, char* serial_port)
{
int fd;
if(NULL != *self)
{
return ERR_NNULL_PTR;
}
else if(0 != access(serial_port, F_OK))
{
ERRNO("Serial port is not available");
return ERR_ILLEGAL_PARAM;
}
else
{
if(-1 == (fd = open(serial_port, O_RDWR | O_NOCTTY)))
{
ERRNO("Error opening %s in rw mode", serial_port);
return ERR_OFILE_FAIL;
}
else if(NULL == (*self = malloc(sizeof(se_serial_t))))
{
ERROR("Error allocating memory for Serial");
return ERR_MALLOC_FAIL;
}
(*self)->fd = fd;
}
return ERR_OK;
}
int se_serial_configure_interface(se_serial_t* self, se_serial_speed_t speed, se_serial_parity_t parity, bool flow_control)
{
struct termios options;
if(NULL == self)
{
return ERR_NULL_PTR;
}
else
{
if(0 != tcgetattr(self->fd, &options))
{
ERRNO("Unable to get serial port current configuration");
}
if(0 != cfsetospeed(&options, speed))
{
ERRNO("Unable to set serial port output speed");
}
if(0 != cfsetispeed(&options, speed))
{
ERRNO("Unable to set serial port input speed");
}
switch(parity)
{
case SE_SERIAL_PARITY_8N1:
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
break;
case SE_SERIAL_PARITY_7E1:
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
break;
case SE_SERIAL_PARITY_7O1:
options.c_cflag |= PARENB;
options.c_cflag |= PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
break;
case SE_SERIAL_PARITY_7S1:
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
break;
default:
WARNING("Unable to set serial port parity");
break;
}
if(flow_control)
options.c_cflag |= CRTSCTS;
else
options.c_cflag &= ~CRTSCTS;
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 0;
if(0 != tcsetattr(self->fd, TCSANOW, &options))
{
ERRNO("Error configuring serial port");
return ERR_SERIAL_CONF_FAIL;
}
self->speed = speed;
self->parity = parity;
self->flow_control = flow_control;
}
return ERR_OK;
}
int se_serial_read(se_serial_t* self, uint8_t* buffer, int size)
{
int bytes_read = 0;
int ret;
if(NULL == self)
{
return ERR_NULL_PTR;
}
else
{
while(bytes_read < size)
{
if(0 > (ret = read(self->fd, &(buffer[bytes_read]), size - bytes_read)))
{
ERROR("Error reading from %s : %d\n", self->serial_port, ret);
return ERR_RFILE_FAIL;
}
bytes_read += ret;
}
size = bytes_read;
}
return size;
}
Устройство, с которым я общаюсь, отправляет кадр из 11 байтов каждую секунду после загрузки.
Итак, после инициализации последовательного порта я получаю кадры в бесконечном цикле и затем печатаю их.
se_serial_t* serial = NULL;
uint8_t buffer[1024] = {0};
int ret = 0;
int i;
if(0 > (ret = se_serial_constructor(&serial, "/dev/ttyUSB0")))
{
ERROR("Error creating serial : %d", ret);
return ERR_SERIAL_CREATION_FAIL;
}
else if(0 > (ret = se_serial_configure_interface(serial, SE_SERIAL_SPEED_B115200, SE_SERIAL_PARITY_8N1, false)))
{
ERROR("Error configuring serial interface : %d", ret);
return ERR_SERIAL_CONFIG_FAIL;
}
while(1)
{
if(0 > (ret = se_serial_read(serial, buffer, 11)))
{
ERROR("Error reading from serial : %d", ret);
return ret;
}
else
{
for(i=0;i<ret;i++)
{
printf("%02x ", buffer[i]);
}
printf("\n");
}
}
Что странно в результате, который я получаю, так это то, что чтение блокируется навсегда, даже если я знаю, что устройство отправляет кадры.
Однако, если я открою порт другой программой, такой как minicom, я могу получить кадры внутри него. После того как порт был открыт с помощью minicom и что я вышел из него, моя программа работает до следующей перезагрузки компьютера.
Если я перезагружаю устройство, код блокируется до тех пор, пока оно не начнет отправлять кадры и хорошо их принимать.
Я также попробовал Raspberry Pi 3, чтобы убедиться, что это не проблема конфигурации моего ноутбука, но я получаю тот же результат.
Кто-нибудь знает, почему я так поступаю?