8052 console (command line) interface for SDCC

Posted by: 邱小新 at 下午2:04 in , , ,
這裏演示一下 8052 console interface 的做法,包含解析 ANSI escape code 的做法。
原始碼下載

全域變數

  1. char g_cmd_line[SZ_CMD_LINE+1];
    記錄指令輸入的暫存字串,SZ_CMD_LINE 不可大於 128。
  2. char g_position;
    記錄游標位置。
  3. char g_ansi_digit;
    記錄 ANSI escape code 的數字部位。
  4. bit g_ansi_mode;
    記錄是否進入 ANSI escape sequence 解析模式。
  5. char (*fp_parse_ansi)(char escape);
    記錄使用 ANSI 解析的函數。

console init

  1. 清除營幕所有東西,並回到左上角的位置,最後顯示提示字元。
void console_init(void) { g_cmd_line[0] = 0; g_ansi_mode = 0; g_position = 0; printf_small("\033[2J"); printf_small("\033[H"); printf_small("\r\n # "); }

console routine process

  1. 讀取輸入字元。
  2. 進入 ANSI escape code parse 或解析輸入字元。
  3. '\r': 輸入完成,解析輸入字串。
  4. 0x07: beep char,輸出錯誤嗚叫聲。
  5. '\t': 忽略定位字元。
  6. '\b', 0x7f: 刪除字元。
  7. '\033': 進入 ANSI escape sequence mode。
  8. default: 記錄字元並顯示在營幕上。
void console_process(void) { char ch=getchar(); if (g_ansi_mode) { ch = fp_parse_ansi(ch); } switch (ch) { case '\r': if (g_position > 0) { console_parse(); g_position = 0; } printf_small("\r\n # "); break; case 0x07: /* beep */ putchar(ch); break; case '\t': /* tab */ break; case '\b': /* backspace */ case 0x7f: /* delete */ delete_char(); break; case '\033':/* escape */ g_ansi_mode = 1; fp_parse_ansi = parse_ansi; break; default: if (isprint(ch)) { putchar(ch); insert_char(ch); } } }

console parse

  1. 取得 command id,並依 command id 執行相關程式。
void console_parse(void) { char cmid; char *next; g_cmd_line[g_position] = 0; next = parse_command(&cmid, g_cmd_line, g_main_command); switch (cmid) { case -1: // null string printf_small(c_return); break; case CMID_HELP: printf_small("\n\r\tHELP\t\t\thelp message"); printf_small("\n\r\tDUMP [addr] [len]\tdump code data"); break; case CMID_DUMP: dump_codedata(next); break; default: printf_small(c_error); break; } }

parse command

  1. 取得 command id,並回傳下一個參數字串指標。
char *parse_command(char *cmid, char *src, struct s_cmd *command) { char i; char *cmd, *next; // check null string cmd = clear_space(src); if (*cmd == 0) { *cmid = -1; return src; } // get command id next = next_string(cmd); for (i=0; command->cmd_id != CMID_MAX; i++) { if (strcmp(cmd, command->cmd_string) == 0) break; command++; } *cmid = command->cmd_id; return next; }

next string

  1. 取得參數字串並補上 \0 字元,並回傳下一個參數字串指標。
char *next_string(char *next) { while (*next) { if (*next == ' ') break; next++; } if (*next == ' ') { *next = 0; next++; } return next; }

clear space

  1. 清除空白字元,並回傳參數字串指標。
char *clear_space(char *src) { while (*src) { if (*src != ' ') break; src++; } return src; }

parse ansi code

  1. 解析 ANSI escape code 第一個字元。
char parse_ansi(char ch) { if (ch == 'O') { fp_parse_ansi = parse_func; } else if (ch == '[') { fp_parse_ansi = parse_bracket; } else { return 0x07; } return 0; }

parse bracket

  1. 解析 ANSI escape code 第二個字元。
char parse_bracket(char ch) { if (isdigit(ch)) { g_ansi_digit = ch - '0'; fp_parse_ansi = parse_digit; return 0; } // parse bracket g_ansi_mode = 0; switch (ch) { case 'A': // move up case 'B': // move down break; case 'C': // move right putchar(' '); insert_char(' '); break; case 'D': // move left delete_char(); break; default: return 0x07; } return 0; }

parse bracket

  1. 解析 ANSI escape code 第二個字元,這一個函數是針對 windows 的超級終端機所做的,標準 ANSI escape code 好像沒有。
char parse_func(char ch) { g_ansi_mode = 0; switch (ch) { case 'P': /* F1 */ case 'Q': /* F2 */ case 'R': /* F3 */ case 'S': /* F4 */ break; default: return 0x07; } return 0; }

parse bracket

  1. 解析 ANSI escape code 數字。
char parse_digit(char ch) { if (ch != 0x7e) { if (isdigit(ch)) { g_ansi_digit = g_ansi_digit * 10 + ch - '0'; return 0; } else { g_ansi_mode = 0; return 0x07; } } // parse digit g_ansi_mode = 0; switch (g_ansi_digit) { case 1: /* home */ g_position = 0; puts("\r # "); puts("\033[K"); break; case 3: /* delete */ delete_char(); break; case 11: /* F1 */ case 24: /* F12 */ break; default: return 0x07; } return 0; }

0 意見

張貼留言