Последовательная связь в Ubuntu: сбой при чтении, а затем все сразу - PullRequest
0 голосов
/ 05 июля 2018

Я пишу программу, которая работает на одноплатном компьютере MIO-3260 с сервером Ubuntu 14.04 и взаимодействует с диском AMC DPRANIE C100A400. Программа отправляет строку шестнадцатеричных кодов на диск и должна получать ответ на каждое отправленное сообщение. Когда я пробую это в realTerm на Windows, это работает хорошо, поэтому я не думаю, что это проблема с дисководом. Однако, когда я пытаюсь читать с последовательного порта, read () возвращает -1 почти все время, пока внезапно в, казалось бы, случайной точке я не получаю массивный дамп сообщений одновременно.

Я использую termios для настройки последовательного порта. Вот мой код для этого. Я попытался настроить его в конфигурации блокировки, но если я это сделаю, код просто зависает на неопределенное время при первом чтении ().

int fd;
fd = open("/dev/ttyS0",O_RDWR | O_NOCTTY | O_NDELAY);
struct termios SerialPortSettings;

tcgetattr(fd, &SerialPortSettings); //get current settings of serial port
cfsetispeed(&SerialPortSettings,B115200);//set input baud rate
cfsetospeed(&SerialPortSettings,B115200);//set output baud rate
SerialPortSettings.c_cflag &= ~PARENB;//clear parity bit (no parity)
SerialPortSettings.c_cflag &= ~CSTOPB;//Stop bits = 1
SerialPortSettings.c_cflag &= ~CSIZE;//clears the mask
SerialPortSettings.c_cflag |= CS8; //set data bits = 8
SerialPortSettings.c_cflag &= ~CRTSCTS; //turn off hardwar based flow ctrl
SerialPortSettings.c_cflag |= CREAD | CLOCAL;//Turn on the reciever

SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY); //Turn off software
//based flow control
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);//Non-canonical mode
SerialPortSettings.c_oflag &= ~OPOST;//no output processing
//set the termios struct now
if(tcsetattr(fd,TCSANOW,&SerialPortSettings) != 0)
    printf("\n ERROR: setting attributes");
else
    printf("\n Baudrate = 115200 \t Stopbits = 1 \t Parity = none");

Для чтения с последовательного порта мой код выглядит следующим образом:

uint8_t buf[1024];//Rx buffer
int bytes_read;
bytes_read = read(fd,&buf,1024);
if(bytes_read != -1){
        for(int i=0;i<bytes_read;i++)    /*printing only the received characters*/
                printf("%02X\t",buf[i]);
        puts("\n");
}

Вот пример сообщения, которое я должен получить {0xA5 0xFF 0x10 0x01 0x00 0x00 0xD4 0x11}. Это должно быть около 8-14 байт. Вместо этого я получаю огромное количество сразу и ни одного в другое время (например, я только что получил 810 байтов сразу после отправки 946 команд без ответа).

Я устранял неисправности в течение последних нескольких дней и понятия не имею, что происходит. Иногда я запускаю его, и он отвечает большую часть времени, а затем загадочным образом просто останавливается, а затем периодически возвращается.

Дайте мне знать, если есть больше информации, которую я могу предоставить.

Любая помощь будет очень признательна!

UPDATE: Я также подключил свой ноутбук к последовательному порту, чтобы я мог следить за передачей данных с помощью RealTerm, и я убедился, что MIO-3260 правильно отправляет команды и корректно отвечает на них приводом. Таким образом, проблема, кажется, когда я пытаюсь читать с порта.

1 Ответ

0 голосов
/ 06 июля 2018

Я пытался настроить его в конфигурации блокировки, но если я это сделаю, код просто зависает на неопределенное время при первом чтении ().

Результаты, которые вы описываете, аналогичны блокированию канонического режима (когда вы действительно хотите (блокирование) необработанного режима).
read () должен блокироваться, пока не будет получен символ EOL (конец строки).

Однако, когда я пытаюсь читать с последовательного порта, read () возвращает -1 почти все время, пока внезапно в кажущейся случайной точке я не получаю массивный дамп сообщений одновременно.

Результаты, которые вы описываете, аналогичны неблокирующему каноническому режиму (когда вам действительно нужен (блокирующий) необработанный режим).
Если в буфере нет данных (т. Е. Полной строки), read () вернет -1 и errno (что вам не нужно проверить) установлено на -EAGAIN.
Но когда двоичные данные совпадают по совпадению с символом EOL (конец строки), условие канонического read () удовлетворяется, и буферизованные данные возвращаются.

Причина, по которой последовательный терминал фактически не настроен на неканонический режим, заключается в том, что ICANON и связанные с ним флаги очищаются от неправильного члена.

SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);//Non-canonical mode 

ICANON является членом c_lflag, а не c_iflag.
Таким образом, заявление должно быть

SerialPortSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Non-canonical mode 

Предположительно, что последовательный терминал по умолчанию перешел в канонический режим, и ваша программа никогда не меняла режим на что-либо другое.


Кроме того, для необработанного режима необходимо определить элементы VMIN и VTIME.
Например:

SerialPortSettings.c_cc[VMIN]  = 1;
SerialPortSettings.c_cc[VTIME] = 1;

Другая ошибка в вашем коде - это использование указателя на адрес массива (т.е. адрес адреса), когда адреса массива будет достаточно.

bytes_read = read(fd,&buf,1024);

должно быть просто

bytes_read = read(fd, buf, 1024);

ДОПОЛНЕНИЕ

Код OP замечательно похож на этот вопрос , в котором есть то же неверное утверждение termios.
Этот плакат в конечном итоге решил свою собственную проблему, но по ошибке приписал исправление добавлению (не относящемуся к делу) флага ECHONL и не осознавая, что он на самом деле исправляет имя члена структуры.


ADDENDUM 2

Источником этой c_iflag и ICANON , по-видимому, является это руководство по последовательному порту от xanthium.in . Автор был уведомлен более двух лет назад об ошибке, но не исправил ее.

...