Определите причину \ r артефактов при чтении с последовательного терминала? - PullRequest
0 голосов
/ 19 февраля 2019

Я пытаюсь диагностировать причину возникновения артефактов \r при чтении с последовательного терминала.

Следующий код может спровоцировать проблему.Существует встроенное устройство Linux, подключенное к физическому концу кабеля UART

import serial                      

ser = serial.Serial( 
    port='/dev/ttyUSB0', 
    baudrate=115200,  
    timeout=5) 

ser.reset_input_buffer()
ser.reset_output_buffer()

b_NEW_LINE_WRITTEN = b'\n'
b_alphabet = b'A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q R r S s T t U u V v W w X x Y y Z z'
ser.write(b_alphabet + b_NEW_LINE_WRITTEN)

raw_line = ser.readline()
print(raw_line)                                                                                  
# b'A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q\rq R r S s T t U u V v W w X x Y y Z z\r\n'

На распечатке прочитанные данные имеют \r вокруг буквы q.

При запускеэмулятор терминала поверх /dev/ttyUSB0 строка начинает обтекать себя после 80 символов, аналогично этот вопрос .Это перенос строки выглядит как проявление /r, которое я получаю при непосредственном чтении с примером кода Python.

При подключении к эмулятору терминала (picocom) эта проблема решается запуском:

shopt -s checkwinsize
resize

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

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

  • настройки драйвера для /dev/ttyUSB0 на снимке ps
  • настройки драйвера для /dev/S0 на целевом встроенном устройстве
  • оболочка на целевом устройстве

Настройка /dev/ttyUSB0

Попытка изменить /dev/ttyUSB0 в отдельном терминале, пока устройство используетсяСценарий python не показывает никаких изменений.

# Separate terminal on the host
stty -F /dev/ttyUSB0  cols 100
stty -F /dev/ttyUSB0 raw
stty -F /dev/ttyUSB0  -a
speed 115200 baud; rows 80; columns 100; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^A; eol = <undef>; eol2 = <undef>; swtch = <undef>;
start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O;
min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany
-imaxbel -iutf8
-opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke
-flusho -extproc


#ipython
...
ser.write(b_alphabet + b_NEW_LINE_WRITTEN)
raw_line = ser.readline()
print(raw_line)                                                                                  
# b'A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q\rq R r S s T t U u V v W w X x Y y Z z\r\n'

Настройка /dev/S0

Установка целевого устройства tty также не влияет на существование артефактов.

stty_cmd_set = b'stty cols 200'
ser.write(stty_cmd_set + b_NEW_LINE_WRITTEN)
ser.reset_input_buffer()
ser.reset_output_buffer()
stty_cmd_confirm = b'stty -a'
ser.write(stty_cmd_confirm + b_NEW_LINE_WRITTEN)

# After reading a few lines there is a confirmation that the tty device on the target has indeed been set to 200 
print(ser.readline())                           
b'speed 115200 baud; rows 56; columns 200; line = 0;\r\n'
ser.reset_input_buffer()
ser.reset_output_buffer()

ser.write(b_alphabet + b_NEW_LINE_WRITTEN)

raw_line = ser.readline()
print(raw_line)                                                                                  
# b'A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q\rq R r S s T t U u V v W w X x Y y Z z\r\n'

Например, обходной путь может заключаться в том, чтобы каким-то образом установить фиксированное количество 200 столбцов перед чтением, чтобы последовательный терминал прекратил попытки быть умным.

Ответы [ 3 ]

0 голосов
/ 28 февраля 2019

\ rq происходит, потому что ваш экран заканчивается рядом с q, поэтому он перемещается на следующую строку, возвращая каретку Unix.В качестве новой строки можно использовать возврат каретки unix, переходите к концу следующей строки.Замените \ r на пустое.Попробуйте автоматическую переноску

\ r (возврат каретки) → перемещает курсор в начало строки без перехода на следующую строку \ n (перевод строки) → перемещает курсор вниз на следующую строку без возврата кначало строки - в среде * nix \ n перемещается в начало строки.\ r \ n (Конец строки) → комбинация \ r и \ n

0 голосов
/ 01 марта 2019

Читая между строк, вы запускаете что-то вроде оболочки Linux на встроенном устройстве.

Это будет иметь тот же набор иерархии приложений Linux / TTY / драйвера, что и ваш хост, и по умолчанию будет обработан режим обработки ввода, который он получает от вашего приложения.Вот почему работает команда для изменения количества столбцов (во встроенном приложении).Это говорит о том, что дисциплина линий в этом устройстве должна обрабатывать экран шириной 200 столбцов (и поэтому логике редактирования строки не нужно разбивать строку).

Переключение на необработанный ввод на обоих хостахи встроенная оболочка должна это исправить.

Если вы хотите узнать больше деталей о том, как терминалы Linux обрабатывают ввод (и отображение ввода обратно в выходной поток), см. https://www.linusakesson.net/programming/tty/

0 голосов
/ 23 февраля 2019

Непонятно, что на самом деле происходит, но похоже, что это решение работает.

Это зависит от наличия shopt -s checkwinsize и resize на целевой плате, поэтому оно не является достаточно универсальным.решение должно быть принятым ответом.

Кроме того, оно не дает представление о том, как применить исправление, не выполняемое во время выполнения (установив значения по умолчанию для драйвера или некоторые настройки в bash).

import serial             
import time         

ser = serial.Serial( 
    port='/dev/ttyUSB0', 
    baudrate=115200,  
    timeout=5) 

b_NEW_LINE_WRITTEN = b'\n'
b_NEW_LINE_READ = b'\r\n'
b_alphabet = b'A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q R r S s T t U u V v W w X x Y y Z z'

ser.write(b_alphabet + b_NEW_LINE_WRITTEN) 
print(ser.readline())
# b'A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q\rq R r S s T t U u V v W w X x Y y Z z\r\n'

shopt_cmd = b'shopt -s checkwinsize' 
ser.write(shopt_cmd + b_NEW_LINE_WRITTEN)
ser.readline()
ser.readline()

resize_cmd = b'resize' 
ser.write(resize_cmd + b_NEW_LINE_WRITTEN)
ser.readline()
ser.readline()

stty_cmd_set = b'stty cols 200'
ser.write(stty_cmd_set + b_NEW_LINE_WRITTEN)
ser.readline()
ser.readline()

ser.write(b_alphabet + b_NEW_LINE_WRITTEN) 
print(ser.readline())
# b'A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q R r S s T t U u V v W w X x Y y Z z\r\n'

ser.reset_output_buffer()
stty_cmd_set = b'stty cols 5'
ser.write(stty_cmd_set + b_NEW_LINE_WRITTEN)
ser.readline()
ser.readline()


ser.write(b_alphabet + b_NEW_LINE_WRITTEN) 
print(ser.readline())
# A a B \r b C c\rc D d \r E e F\rF f G \r g H h\rh I i \r J j K\rK k L \r l M m\rm N n \r O o P\rP p Q \r q R r\rr S s \r T t U\rU u V \r v W w\rw X x \r Y y Z\rZ z\r\n'
...