Как Picocom правильно отображает данные?
«Правильность» отображаемого результата - это просто человеческая тенденция воспринимать или приписывать «порядок» (и / или образец) естественным событиям.
Picocom - это просто " минимальная программа эмуляции немого терминала ", которая, как и другие программы эмуляции терминала, просто отображает то, что получено.
Вы можете настроитьповедение завершения строки, например добавление возврата каретки при получении перевода строки (чтобы текстовые файлы Unix / Linux отображались правильно).
Но в противном случае отображается то, что вы получили. picocom .
не обрабатывает и не форматирует, основываясь на опубликованных вами результатах, модуль GPS явно выводит строки текста ASCII, оканчивающиеся переводом строки и возвратом каретки.
Независимо от того, как этот текст читается программой (эмулятора терминала), т.е. байтом за раз или каким-либо случайным числом байтов каждый раз, при условии, что каждый полученный байт отображается в том же порядке, в котором он был получен, дисплей будет отображатьсяупорядоченно, разборчиво и правильно.
Это связано с размером моего буфера или, может быть, с флагами VTIME и VMIN?
Значения VTIME и VMIN не являются оптимальными,но реальная проблема заключается в том, что ваша программа имеет ошибку, из-за которой некоторые из полученных данных отображаются более одного раза.
while(1){
int n = read(serial_port, &read_buf, sizeof(read_buf));
std::cout << read_buf ;
}
Системный вызов read () просто возвращает число в байтах (или индикацию ошибки, т.е. -1) и не возвращает строку.
Ваша программа делаетничего с таким количеством байтов, и просто отображает все (и все), что находится в этом буфере.
Всякий раз, когда последний read () не возвращает достаточное количество байтов для перезаписи того, что уже находится в буфере,тогда старые байты будут отображаться снова.
Вы можете подтвердить эту ошибку, сравнив вывод исходной программы со следующей настройкой:
unsigned char read_buf[80];
while (1) {
memset(read_buf, '\0', sizeof(read_buf)); // clean out buffer
int n = read(serial_port, read_buf, sizeof(read_buf) - 1);
std::cout << read_buf ;
}
Обратите внимание, что размер буфера, передаваемый в read () , необходимбыть на единицу меньше, чем фактический размер буфера, чтобы сохранить хотя бы одно байтовое положение для ограничителя строки.
Неспособность проверить код возврата из read () для условия ошибки - еще одна проблема с вашим кодом.
Таким образом, следующий код является улучшением по сравнению с вашим:
unsigned char read_buf[80];
while (1) {
int n = read(serial_port, read_buf, sizeof(read_buf) - 1);
if (n < 0) {
/* handle errno condition */
return -1;
}
read_buf[n] = '\0';
std::cout << read_buf ;
}
Вам не ясно, пытаетесь ли вы просто эмулировать picocom , или у другой версии вашей программы возникли проблемы с чтением данных из вашего модуля GPS, и вы решили опубликовать этоПроблема XY.
Если вы собираетесь читать и обрабатывать строки текста в вашей программе, то вы не хотите эмулировать picocom и использовать неканоническое чтение.
Вместо этоговы можете и должны использовать канонический ввод-вывод, чтобы read () возвращал полную строку в вашем буфере (при условии, что буфер достаточно большой).
Ваша программа не читает с последовательного интерфейса порт , но с последовательного терминала .Когда принятые данные представляют собой завершенный строкой текст, нет смысла читать необработанные байты, когда оконечное устройство проанализирует полученные для вас данные и обнаружит символы завершения строки.
Вместо выполнения всего дополнительного кодирования, предложенного в другом ответе, используйте возможности, уже встроенные в систему.
Для чтения строк см. Последовательная связь Канонический режим Неблокирующее обнаружение NL и Работа с последовательным портом linux в C, Невозможнополучить полные данные
ADDENDUM
У меня проблемы с пониманием " Вместо этого вы можете и должны использовать канонический I/ O, чтобы read () вернула полную строку в вашем буфере".
Я не знаю, как написать это, чтобы быть более понятным.
Читали ли вы страницу termios man ?
В каноническом режиме:
- Ввод доступен построчно. Строка ввода
доступно, если введен один из разделителей строк (NL, EOL, EOL2; или
EOF в начале
линии). За исключением случая EOF, разделитель строк включается в буфер, возвращаемый read (2).
Должен ли я ожидать, что каждый вызов read () будет возвращать полную строку с $ ... или я должен реализовать некоторую логику для чтения и заполнения буфера полной строкой текста ASCII?
Вам интересно, есть ли разница между моим значением "полный" и вашим использованием "полный" ?
Читали ли вы комментарий, где я уже писал "Если вы пишете свою программу так, как я предлагаю, [тогда], что $
должен быть первым символом в буфере" ?
Так да,
вы должны ожидать "что каждый вызов read () будет возвращать полную строку с $ ..." .
Вы должны изучить то, что я уже написал, а также ссылки, предоставленные.