#c #serial-port #usb #ubuntu-18.04 #ubuntu-20.04
Вопрос:
Я написал программу на C для непрерывного считывания данных с устройства через последовательный порт USB. Программа безупречно работает в Ubuntu 18.04. У меня идентичная система под управлением Ubuntu 20.04, и та же программа работает неправильно. Он будет считывать несколько КБ с последовательного порта, после чего read () больше не обнаружит никаких данных.
Вот код:
#include <iostream>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
int receive_data(int fd, unsigned char read_buf[], int num_requested_bytes)
{
int total_received_bytes = 0;
int num_received_bytes = 0;
// Continue reading the serial port until the number of requested bytes have been read
while (total_received_bytes < num_requested_bytes)
{
num_received_bytes = read(fd, read_buf total_received_bytes,
num_requested_bytes - total_received_bytes);
if (num_received_bytes < 0)
{
if (errno == EAGAIN)
{
num_received_bytes = 0;
}
else
{
std::cout << "Encountered error during read(): " << errno << std::endl;
exit(-1);
}
}
total_received_bytes = num_received_bytes;
if (total_received_bytes >= num_requested_bytes)
{
break;
}
}
return total_received_bytes;
}
int main()
{
// Open serial port
int fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY | O_NONBLOCK);
int flags = fcntl(fd, F_GETFL);
//fcntl(fd, F_SETFL, flags | O_ASYNC); // <------------------- SEE NOTE
// Read in existing settings, and handle any error
struct termios tty;
if(tcgetattr(fd, amp;tty) != 0)
{
close(fd);
printf("Error %i from tcgetattr: %sn", errno, strerror(errno));
exit(-1);
}
// Set flags
tty.c_cflag |= (CLOCAL | CREAD);
tty.c_cc[VTIME] = 0;
tty.c_cc[VMIN] = 0;
// Raw input mode
cfmakeraw(amp;tty);
// Save tty settings, also checking for error
if (tcsetattr(fd, TCSANOW, amp;tty) != 0)
{
close(fd);
printf("Error %i from tcsetattr: %sn", errno, strerror(errno));
exit(1);
}
// Attempt to read from port
int received_bytes;
unsigned char read_buf[1024];
while (true)
{
received_bytes = receive_data(fd, read_buf, 1024);
std::cout << "Received " << received_bytes << " bytes. First 2 numbers in frame: "
<< ((unsigned int) (read_buf[1] << 8 | read_buf[0])) << ", "
<< ((unsigned int) (read_buf[3] << 8 | read_buf[2])) << std::endl;
}
}
Вот пример вывода из программы в Ubuntu 20.04. После 0-3 кадров я больше не получаю никаких данных, и программа бесконечно повторяет мой вызов read ().
В Ubuntu 18.04 программа будет продолжаться бесконечно.
$ ./main
Received 1024 bytes. First 2 numbers in frame: 65535, 2046
Received 1024 bytes. First 2 numbers in frame: 2046, 3338
Received 1024 bytes. First 2 numbers in frame: 2045, 2046
SEE NOTE
:
Если я включу флаг O_ASYNC, программа завершит работу на первом read()
с I/O Possible
печатью в терминале. Если я затем закомментирую строку и перекомпилирую, программа будет работать и непрерывно извлекать кадры, как и ожидалось.
Есть какие-нибудь идеи о том, что может быть причиной этого?
Комментарии:
1. Вы перепрограммируете неблокирующий ввод-вывод, но ваша программа просто тратит циклы процессора на поиск данных. Как вы убедились, что эти две системы «идентичны» ? Вы тестировали прием данных (с вашего таинственного устройства) с помощью стандартной утилиты, например, minicom? Кстати, в receive_data ()
if () break
это избыточный тест сwhile ()
циклом.2. Используя вашу опубликованную программу, я не могу воспроизвести ни одного сбоя, о котором вы сообщили, используя Lubuntu 20.04. Программа загружает процессор и отображает сообщения столько минут, сколько я позволяю программе работать. Проблема не может быть дублирована.
3. Спасибо за ответ! Системы настолько идентичны, насколько могут быть идентичны две альфы Латте Панда. Я изучил связь с minicom и считаю, что есть проблема с прошивкой на устройстве. Я получил новую версию, надеюсь, это исправит проблемы.