Escape-последовательности прерывания Pyserial клиента

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

0003a0  73 65 20 6c 65 76 65 6c  0d 0a 0d 1b 5b 39 39 39       |se level....[999|
0003b0  39 42 0d 1b 5b 39 39 39  39 42 1b 5a 20 20 1b 5b       |9B..[9999B.Z  .[|
0003c0  36 6e 0d 0d 0d 0d 5b 61  64 6d 69 6e 40 73 77 69       |6n....[admin@swi|
0003d0  74 63 68 5d 20 3e 20 20  20 20 20 20 20 20 20 20       |tch] >          |

Когда используешь screen для подключения к устройству, задержка не отображается как screen отвечает соответствующим образом.

0003a0  73 65 20 6c 65 76 65 6c  0d 0a 0d 1b 5b 39 39 39       |se level....[999|
0003b0  39 42 0d 1b 5b 39 39 39  39 42 1b 5a 20                |9B..[9999B.Z    |

                                ---=== WRITE ===---
000000  1b 5b 3f 31 3b 32 63                                   |.[?1;2c         |

                                ---=== READ ===---
000000  20 1b 5b 36 6e                                         | .[6n           |

                                ---=== WRITE ===---
000000  1b 5b 35 37 3b 33 52                                   |.[57;3R         |

                                ---=== READ ===---
000000  1b 5b 34 6c 1b 5b 32 30  6c 1b 5b 3f 34 37 6c 1b       |.[4l.[20l.[?47l.|
000010  5b 3f 37 68 1b 5b 3f 35  6c 1b 5b 3f 32 35 68 1b       |[?7h.[?5l.[?25h.|
000020  5b 48 1b 5b 39 39 39 39  42 1b 5b 36 6e                |[H.[9999B.[6n   |

                                ---=== WRITE ===---
000000  1b 5b 35 37 3b 31 52                                   |.[57;1R         |

                                ---=== READ ===---
000000  1b 5b 48 1b 5b 39 39 39  39 42 1b 44 1b 5b 39 39       |.[H.[9999B.D.[99|
000010  39 39 41 1b 5b 36 6e                                   |99A.[6n         |

                                ---=== WRITE ===---
000000  1b 5b 31 3b 31 52                                      |.[1;1R          |

                                ---=== READ ===---
000000  1b 5b 48 1b 5b 39 39 39  39 43 1b 5b 36 6e             |.[H.[9999C.[6n  |

                                ---=== WRITE ===---
000000  1b 5b 31 3b 31 34 31 52                                |.[1;141R        |

                                ---=== READ ===---
000000  1b 5b 48 c4 9b 48 1b 5b  36 6e 0d 20 20 20             |.[H..H.[6n.     |

                                ---=== WRITE ===---
000000  1b 5b 31 3b 33 52                                      |.[1;3R          |

                                ---=== READ ===---
000000  1b 5b 48 1b 5b 39 39 39  39 43 1b 5b 36 6e 20 1b       |.[H.[9999C.[6n .|

                                ---=== WRITE ===---
000000  1b 5b 31 3b 31 34 31 52                                |.[1;141R        |

                                ---=== READ ===---
000000  5b 36 6e 20 1b 5b 36 6e                                |[6n .[6n        |

                                ---=== WRITE ===---
000000  1b 5b 31 3b 31 34 32 52  1b 5b 32 3b 32 52             |.[1;142R.[2;2R  |

                                ---=== READ ===---
000000  1b 5b 33 3b 35 72 1b 5b  48 1b 5b 36 6e 0a 0a          |.[3;5r.[H.[6n.. |
                               ---=== WRITE ===---
000000  1b 5b 31 3b 31 52                                      |.[1;1R          |

                                ---=== READ ===---
000000  0a 0a 0a 0a 0a 1b 5b 36  6e 1b 5b                      |......[6n.[     |

                                ---=== WRITE ===---
000000  1b 5b 35 3b 31 52                                      |.[5;1R          |

                                ---=== READ ===---
000000  39 39 39 39 42 1b 5b 36  6e 1b 5b 72                   |9999B.[6n.[r    |

                                ---=== WRITE ===---
000000  1b 5b 35 3b 31 52                                      |.[5;1R          |

                                ---=== READ ===---
000000  1b 5b 31 3b 39 39 39 39  72 0d 0d 0d 1b 5b 39 39       |.[1;9999r....[99|
000010  39 39 42 5b 61 64 6d 69  6e 40 73 77 69 74 63 68       |99B[admin@switch|
000020  5d 20 3e 20                                            |] >             |

Что именно делает эта серия escape-последовательностей, и как лучше всего справиться с этим в моем клиенте?

from asyncio import Protocol, get_event_loop
from serial.aio import create_serial_connection

class Serial(Protocol):

   def connection_made(self, transport):
       self.transport = transport

   def data_received(self, data):
       self.buffer += data.decode("utf-8")
       self.handle()

   def send(self, line):
       self.transport.write("{}\r\n".format(line).encode())

loop = get_event_loop()
coro = create_serial_connection(loop, Serial, "/dev/ttyUSB0")
loop.run_until_complete(coro)
loop.run_forever()

1 ответ

Решение

Этот кусок с [6n (и предшествующий ему escape-символ) просит терминал сообщить ему, где находится курсор, как часть определения размера экрана. По-видимому pyserial не понимает этого, и вам придется немного подождать, пока программа попросит отказаться и продолжить.

В последовательностях управления XTerm:

CSI Ps n  Device Status Report (DSR).
...
            Ps = 6  -> Report Cursor Position (CPR) [row;column].

где CSI - управляющая последовательность инициатора escape [,

Когда ты бежишь screen, он интерпретирует эту последовательность управления (то есть, он читает, понимает и отвечает соответственно):

        case 'n':
            if (a1 == 5) / * Сообщить о состоянии терминала */
                Отчет (победа, "\033[0n", 0, 0);
            иначе, если (a1 == 6)   /* Сообщить о позиции курсора */
                Отчет (победа, "\033[%d;%dR", победа->w_y + 1, победа->w_x + 1);

Последовательность управления отчетом о состоянии используется несколькими программами, такими как resize определить размер экрана вашего терминала. Он работает, перемещая курсор в невозможный крайний правый нижний угол, а затем (поскольку терминалы имеют ограничения), спрашивая, как далеко он ушел. Этот конкретный пример не использует resize, который отправляет 999 для каждой координаты (но это спорно, есть ли реальный сценарий, где необходимы четыре цифры).

Приложение, которое отправляет последовательность контроля состояния устройства, перемещает курсор вниз с помощью escape. [9999B и, очевидно, использует это позже при настройке полей прокрутки с последовательностью, заканчивающейся на r, Это часто используемая функция VT100 не в ECMA-48 (r обозначает частную последовательность использования, т. е. не стандартизирована).

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

Он также пытается с помощью двух разных управляющих последовательностей переместить курсор к дому (вверху слева) в этой последовательности из screen чтения / записи:

1b 5b 48 c4 9b 48

(0x9b является 8-битным эквивалентом 0x1b, 0x5b или убежать [).

Так что ваш выбор невелик:

  • устранить (возможно, ненужный) запрос размера экрана, или
  • измените свой сценарий pyserial для обработки последовательности контроля состояния устройства
Другие вопросы по тегам