Программирование AVR Коды терминала Linux, состоящие из нескольких байт Mon, September 16 2019  

Поделиться

нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

Коды терминала Linux, состоящие из нескольких байт Печать
Добавил(а) microsin   

Для организации консоли управления встраиваемыми устройствами через последовательный терминал необходимо обрабатывать специальные символы терминала и последовательности специальных символов. Ниже приведены основные управляющие коды (байтовые последовательности), которые посылает терминал SecureCRT в режиме эмуляции терминала Linux при нажатии на клавиши.

SecureCRT Linux Terminal Emulation

Таблица кодов специальных клавиш (в HEX-формате):

Код Клавиша
08 Backspace
09 Tab
0D Enter(1)
1B Esc(2)
1B 5B 41 Стрелка вверх
1B 5B 42 Стрелка вниз
1B 5B 43 Стрелка вправо
1B 5B 44 Стрелка влево
1B 5B 31 7E Home
1B 5B 32 7E Insert
1B 5B 33 7E Delete
1B 5B 34 7E End
1B 5B 35 7E Page Up
1B 5B 36 7E Page Down
1B 5B 5B 41 F1
1B 5B 5B 42 F2
1B 5B 5B 43 F3
1B 5B 5B 44 F4
1B 5B 5B 45 F5
1B 5B 31 37 7E F6
1B 5B 31 38 7E F7
1B 5B 31 39 7E F8
1B 5B 32 30 7E F9
1B 5B 32 31 7E F10
1B 5B 32 33 7E F11
1B 5B 32 34 7E F12

Примечания:

(1) По умолчанию нажатие Enter приводит к появлению в буфере символа CR (0x0D, \r). Если в свойствах сессии SecureCRT поставить галочку "New line mode" в разделе Emulation -> Modes, то нажатие на Enter приведет к появлению в буфере последовательности CRLF (0x0D0x0A, \r\n).
(2) Последовательности байт, начинающиеся на код 0x1B, называют Esc-последовательностями.

Настройка SecureCRT "New line mode" (передача двух символов CRLF вместо одного символа CR):

SecureCRT Linux Terminal Emulation CRLF mode

[Пример декодирования команд]

Алгоритм обработки символов, которые вводит пользователь в терминале, на псевдокоде:

// Переменная, определяющая декодированное действие:
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) в ответ на ввод символа '?'.

SecureCRT decode RX output example

[Ссылки]

1. Terminal codes (ANSI/VT100) introduction site:wiki.bash-hackers.org.
2. Работа с кольцевым буфером.

 

Добавить комментарий


Защитный код
Обновить

Top of Page