最近调试u-boot的readline,对一些特殊按键键值有些疑惑,比如↑↓←→四个键,在linux的minicom敲下这几个键,串口会输出什么数据。
其实不需要用串口测试,我们可以写个小程序测试一下:
-
#include <stdio.h>
-
#include <curses.h>
-
-
int main(int argc, char **argv)
-
{
-
char a;
-
char b[80];
-
int i;
-
printf("Please input a string
-
:\n");
-
// a = getc(stdin);
-
scanf("%s",b);
-
// printf("The input a string is : 0x%x\n", a);
-
printf("The input char is:\n");
-
-
for(i = 0; b[i] !='\0' && i < 80; i++ )
-
printf("0x%x ",b[i]);
-
printf("\n");
-
return 0;
-
}
测试:
-
richard@richard-H81M-DS2:~/work/driver/test$ ./test
-
Please input a string:
-
^[[A^[[B^[[D^[[C
-
The input char is:
-
0x1b 0x5b 0x41 0x1b 0x5b 0x42 0x1b 0x5b 0x44 0x1b 0x5b 0x43
可以看到,当输入↑键,我们得到3个字节:0x1b 0x5b 0x41。
或者执行cat -v,然后输入
↑↓←→(其他键也可以F1~F12)。
参考知乎一位大侠的说法:
这下就明白了。再联系
cread_line的代码片段:
-
static int cread_line(const char *const prompt, char *buf, unsigned int *len,
-
int timeout)
-
{
-
unsigned long num = 0;
-
unsigned long eol_num = 0;
-
unsigned long wlen;
-
char ichar;
-
int insert = 1;
-
int esc_len = 0;
-
char esc_save[8];
-
int init_len = strlen(buf);
-
int first = 1;
-
-
if (init_len)
-
cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
-
-
while (1) {
-
#ifdef CONFIG_BOOT_RETRY_TIME
-
while (!tstc()) { /* while no incoming data */
-
if (retry_time >= 0 && get_ticks() > endtime)
-
return (-2); /* timed out */
-
WATCHDOG_RESET();
-
}
-
#endif
-
if (first && timeout) {
-
uint64_t etime = endtick(timeout);
-
-
while (!tstc()) { /* while no incoming data */
-
if (get_ticks() >= etime)
-
return -2; /* timed out */
-
WATCHDOG_RESET();
-
}
-
first = 0;
-
}
-
-
ichar = getcmd_getch();
-
-
if ((ichar == '\n') || (ichar == '\r')) {
-
putc('\n');
-
break;
-
}
-
-
/*
-
* handle standard linux xterm esc sequences for arrow key, etc.
-
*/
-
if (esc_len != 0) {
-
if (esc_len == 1) {
-
if (ichar == '[') {
-
esc_save[esc_len] = ichar;
-
esc_len = 2;
-
} else {
-
cread_add_str(esc_save, esc_len, insert,
-
&num, &eol_num, buf, *len);
-
esc_len = 0;
-
}
-
continue;
-
}
-
-
switch (ichar) {
-
-
case 'D': /* <- key */
-
ichar = CTL_CH('b');
-
esc_len = 0;
-
break;
-
case 'C': /* -> key */
-
ichar = CTL_CH('f');
-
esc_len = 0;
-
break; /* pass off to ^F handler */
-
case 'H': /* Home key */
-
ichar = CTL_CH('a');
-
esc_len = 0;
-
break; /* pass off to ^A handler */
-
case 'A': /* up arrow */
-
ichar = CTL_CH('p');
-
esc_len = 0;
-
break; /* pass off to ^P handler */
-
case 'B': /* down arrow */
-
ichar = CTL_CH('n');
-
esc_len = 0;
-
break; /* pass off to ^N handler */
-
default:
-
esc_save[esc_len++] = ichar;
-
cread_add_str(esc_save, esc_len, insert,
-
&num, &eol_num, buf, *len);
-
esc_len = 0;
-
continue;
-
}
-
}
-
-
switch (ichar) {
-
case 0x1b:
-
if (esc_len == 0) {
-
esc_save[esc_len] = ichar;
-
esc_len = 1;
-
} else {
-
puts("impossible condition #876\n");
-
esc_len = 0;
-
}
-
break;
-
-
case CTL_CH('a'):
-
BEGINNING_OF_LINE();
-
break;
-
case CTL_CH('c'): /* ^C - break */
-
*buf = '\0'; /* discard input */
-
return (-1);
-
case CTL_CH('f'):
-
if (num < eol_num) {
-
getcmd_putch(buf[num]);
-
num++;
-
}
-
break;
-
case CTL_CH('b'):
-
if (num) {
-
getcmd_putch(CTL_BACKSPACE);
-
num--;
-
}
-
break;
-
case CTL_CH('d'):
-
if (num < eol_num) {
-
wlen = eol_num - num - 1;
-
if (wlen) {
-
memmove(&buf[num], &buf[num+1], wlen);
-
putnstr(buf + num, wlen);
-
}
-
-
getcmd_putch(' ');
-
do {
-
getcmd_putch(CTL_BACKSPACE);
-
} while (wlen--);
-
eol_num--;
-
}
-
break;
-
case CTL_CH('k'):
-
ERASE_TO_EOL();
-
break;
-
case CTL_CH('e'):
-
REFRESH_TO_EOL();
-
break;
-
case CTL_CH('o'):
-
insert = !insert;
-
break;
-
case CTL_CH('x'):
-
case CTL_CH('u'):
-
BEGINNING_OF_LINE();
-
ERASE_TO_EOL();
-
break;
-
case DEL:
-
case DEL7:
-
case 8:
-
if (num) {
-
wlen = eol_num - num;
-
num--;
-
memmove(&buf[num], &buf[num+1], wlen);
-
getcmd_putch(CTL_BACKSPACE);
-
putnstr(buf + num, wlen);
-
getcmd_putch(' ');
-
do {
-
getcmd_putch(CTL_BACKSPACE);
-
} while (wlen--);
-
eol_num--;
-
}
-
break;
-
case CTL_CH('p'):
-
case CTL_CH('n'):
-
{
-
char * hline;
-
-
esc_len = 0;
-
-
if (ichar == CTL_CH('p'))
-
hline = hist_prev();
-
else
-
hline = hist_next();
-
-
if (!hline) {
-
getcmd_cbeep();
-
continue;
-
}
-
-
/* nuke the current line */
-
/* first, go home */
-
BEGINNING_OF_LINE();
-
-
/* erase to end of line */
-
ERASE_TO_EOL();
-
-
/* copy new line into place and display */
-
strcpy(buf, hline);
-
eol_num = strlen(buf);
-
REFRESH_TO_EOL();
-
continue;
-
}
-
#ifdef CONFIG_AUTO_COMPLETE
-
case '\t': {
-
int num2, col;
-
-
/* do not autocomplete when in the middle */
-
if (num < eol_num) {
-
getcmd_cbeep();
-
break;
-
}
-
-
buf[num] = '\0';
-
col = strlen(prompt) + eol_num;
-
num2 = num;
-
if (cmd_auto_complete(prompt, buf, &num2, &col)) {
-
col = num2 - num;
-
num += col;
-
eol_num += col;
-
}
-
break;
-
}
-
#endif
-
default:
-
cread_add_char(ichar, insert, &num, &eol_num, buf, *len);
-
break;
-
}
-
}
-
*len = eol_num;
-
buf[eol_num] = '\0'; /* lose the newline */
-
-
if (buf[0] && buf[0] != CREAD_HIST_CHAR)
-
cread_add_to_hist(buf);
-
hist_cur = hist_add_idx;
-
-
return 0;
-
}
这些都是ANSI 控制码,以ESC起始为标记,百度就知道了。
在测试这个问题的时候,需要使用virtual box虚拟机中的xp串口进行测试,百度半天也没找到能完全说清楚的文章,下面介绍我个人的试验结果和理解:
第一种是裸文件,这种模式只能让虚拟机串口输出信息到宿主机(我的是ubuntu)的某个文件中,打开可以查看虚拟机串口发来的文字信息,基本没什么用。
第二种是主机管道,这个模式可以让主机和虚拟机进行串口通信,相当于建立一个模拟的串口通道,主机和虚拟机互联,这个模式非常有用,对于测试串口提供了很方便的测试条件,即使你电脑没有真是串口也没关系。再也不需要想办法去破解windows那些收费的虚拟串口软件了。
注意使用主机管道模式时,应在管道路径前加上前缀unix#,例如virtual box中设置了串口位置为/dev/xpserial,那么minicom中应设置Serial Device 为 unix#/dev/xpserial
第三种是主机设备,这个就相当于将真实主机绑定到虚拟机了,这时候真串口只能给虚拟机用,但是有延迟,有时候会丢数据,实际上个人认为如果只是简单数据收发没必要用这个模式,真串口给宿主机用就可以了。
F8:
ASCII 码:^[[19~
十六进制0x1b 0x5b 0x31 0x39 0x7e
第一个字节0x1b是"^[",第
二个字节0x5b是'[',第3个字节是0x31,第4字节就得到'9', 同理,0x39得到'9',最后0x7e是'~'
\033\133\061\071\176
在securecrt做映射时可以使用 "\e[\061\071\176"
↑:
^[[A
^[是第一个字节0x1b,第二个字节0x5b是[,最后的0x41是A
0x1b 0x5b 0x41
\033\133\101
Shift + F8:
^[[19;2~
0x1b 0x5b 0x31 0x39 0x3b 0x32 0x7e
"\e[\061\071\073\062\176"
关于控制码还可以参考:
阅读(3827) | 评论(0) | 转发(0) |