Коды терминала Linux, состоящие из нескольких байт |
![]() |
Добавил(а) microsin | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Для организации консоли управления встраиваемыми устройствами через последовательный терминал необходимо обрабатывать специальные символы терминала и последовательности специальных символов. Ниже приведены основные управляющие коды (байтовые последовательности), которые посылает терминал SecureCRT в режиме эмуляции терминала Linux при нажатии на клавиши. Таблица кодов специальных клавиш (в HEX-формате):
Примечания: (1) По умолчанию нажатие Enter приводит к появлению в буфере символа CR (0x0D, \r). Если в свойствах сессии SecureCRT поставить галочку "New line mode" в разделе Emulation -> Modes, то нажатие на Enter приведет к появлению в буфере последовательности CRLF (0x0D0x0A, \r\n). Настройка SecureCRT "New line mode" (передача двух символов CRLF вместо одного символа CR): [Пример декодирования команд] Алгоритм обработки символов, которые вводит пользователь в терминале, на псевдокоде: // Переменная, определяющая декодированное действие:
u8 action = ACTION_NONE;
// Возможные значения для переменной action: ACTION_NONE // ничего не делать, ожидание команды ACTION_BACKSPACE // удаление символа слева от курсора ACTION_TAB // действие по клавише Tab (пока ничего не делать) ACTION_ENTER // обработка введенной команды ACTION_SHOW_HELP // показать подсказку по командной строке // Текущее состояние обработки приема:
u8 decodemode = SYM_SINGLE;
// Возможные значения для переменной decodemode: SYM_SINGLE // ожидание ввода пользователя по одному символу SYM_1B // начало Esc-последовательности Появился символ? Да: сброс счетчика таймаута Нет: продолжаем отсчет таймаута switch(decodemode)
{
SYM_SINGLE: Если появившийся символ O8, то action = ACTION_BACKSPACE Очистка буфера Если появившийся символ 09, то action = ACTION_TAB Очистка буфера Если появившийся символ 0D, то action = ACTION_ENTER Взять данные команды из буфера Очистка буфера Если появившийся символ ?, то action = ACTION_SHOW_HELP Очистка буфера Если появившийся символ 1B, то decodemode = SYM_1B break; SYM_1B: Если таймаут вышел, то чтение кодов из буфера (коды в таблице выше) По результату декодирования кодов присвоение значения для action Очистка буфера decodemode = SYM_SINGLE; break; } switch(action)
{
ACTION_NONE: break; ACTION_BACKSPACE: удалить последний символ из буфера приема передать CR для возврата курсора в начало строки передать то, что уже есть в буфере приема action = ACTION_NONE break; ACTION_TAB: action = ACTION_NONE break; ACTION_ENTER: передать CR для возврата курсора в начало строки передать LF для перехода на следующую строку декодировать данные буфера как команду выполнить команду action = ACTION_NONE break; ACTION_SHOW_HELP: передать CR для возврата курсора в начало строки передать LF для перехода на следующую строку вывести подсказку action = ACTION_NONE break; } Этот пример кода обрабатывает содержимое кольцевого буфера [2] bufRX с указателями inRX и outRX. Не существенные с точки зрения обработки ввода пользователя куски кода не показны. Заголовочный файл decodeRX.h: #ifndef __DECODERX__
#define __DECODERX__
typedef enum {// Возможные значения для переменной action: ACTION_NONE, // ничего не делать, ожидание команды ACTION_BACKSPACE, // удаление символа слева от курсора ACTION_TAB, // действие по клавише Tab (пока ничего не делать) ACTION_ENTER, // обработка введенной команды ACTION_SHOW_HELP, // показать подсказку по командной строке }TCmdAction; typedef enum { SYM_SINGLE, // ожидание ввода пользователя по одному символу SYM_1B // начало Esc-последовательности }TDecodeMode; void DecodeConsoleCommands (void); #endif
Модуль decodeRX.c: #include < string.h>
#include "decodeRX.h"
#include "UARTconsole.h"
#include "miscell.h"
#include "umsg.h"
static TCmdAction action = ACTION_NONE; static TDecodeMode decodemode = SYM_SINGLE; static const char trimsymbols [] = { 0x08, 0x09, 0x0D, 0x0A, 0 }; // Таймаут приема (ввод символов в консоли)
// в единицах 10 мс:
#define RX_TIMEOUT 10
static char cmddata[MAX_CMD_LEN]; static void GetCmdData (u16 idxstart, u16 idxend) { u16 idx = 0; while ((idxstart != idxend) && (idx < sizeof(cmddata)-1)) { cmddata[idx++] = bufRX[idxstart]; idxstart++; idxstart &= UART_RXBUFMASK; } cmddata[idx] = 0; ltrim ((char*)cmddata, (char*)trimsymbols); rtrim ((char*)cmddata, (char*)trimsymbols); } // Функция обработки получаемых по UART символов (команды
// пользователя, вводимые в консоли). Рассчитана на вызов
// с интервалом 10 мс (из бесконечного цикла main).
void DecodeConsoleCommands (void) { // Счетчик таймаута между повлениями символов // (нажатиями клавиш пользователя в терминале): static u16 timeoutcnt = RX_TIMEOUT; // Индекс начала команды: static u16 idxStart = 0; u8 sym; int cmdlen; u16 idx; if (inRX == outRX) { // Символов на приеме нет, декремент счетчика таймаута. if (timeoutcnt) { // Таймаут не истек, декремент таймаута: timeoutcnt--; } else { // Таймаут истек, проверка ESC-последовательности: if (SYM_1B == decodemode) { umsg("Esc-коды: "); GetCmdData(idxStart, outRX); cmdlen = strlen((char*)cmddata); for (idx=0; idx < cmdlen; idx++) { umsg("%02X ", cmddata[idx]); } umsg("\n"); idxStart = outRX; decodemode = SYM_SINGLE; } } } else { // Были обработаны символы, сброс таймаута timeoutcnt = RX_TIMEOUT; } while (inRX != outRX) { // Выборка символа: sym = bufRX[outRX]; outRX++; outRX &= UART_RXBUFMASK; switch(decodemode) { case SYM_SINGLE: if (0x08 == sym) { action = ACTION_BACKSPACE; idxStart = outRX; } else if (0x09 == sym) { action = ACTION_TAB; idxStart = outRX; } else if ('?' == sym) { action = ACTION_SHOW_HELP; idxStart = outRX; } else if (0x1B == sym) { decodemode = SYM_1B; } else if (0x0D == sym) { GetCmdData(idxStart, outRX); action = ACTION_ENTER; idxStart = outRX; } else { umsg("%c", sym); } break; case SYM_1B: break; } } switch(action) { case ACTION_NONE: break; case ACTION_BACKSPACE: umsg("BACKSPACE\n"); action = ACTION_NONE; break; case ACTION_TAB: umsg("TAB\n"); action = ACTION_NONE; break; case ACTION_ENTER: umsg("Введена команда %s\n", cmddata); action = ACTION_NONE; break; case ACTION_SHOW_HELP: umsg("HELP\n"); action = ACTION_NONE; break; } } Ниже на скриншоте показан результат обработки ввода пользователя в окне терминала. Нажимались клавиши Backspace, Tab, Esc и т. д. (клавиши, показанные в таблице выше). Также демонструется ввод команд и вывод подсказки (HELP) в ответ на ввод символа '?'. [Ссылки] 1. Terminal codes (ANSI/VT100) introduction site:wiki.bash-hackers.org. |