Chinaunix首页 | 论坛 | 博客
  • 博客访问: 316554
  • 博文数量: 66
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 509
  • 用 户 组: 普通用户
  • 注册时间: 2015-04-29 13:56
文章分类
文章存档

2018年(2)

2017年(6)

2016年(34)

2015年(24)

我的朋友

分类: 嵌入式

2016-10-19 15:52:24

在写终端控制的代码时候,会碰到ascii和hex string 两种格式的协议:
1. ascii协议以\r\n结束
   同时ascii协议,要求支持退格,delete,历史命令
2. hex string则通过消息头里面的消息长度字段来判断本条命令是否结束,协议结尾没有\r\n标准。

如果只是支持ascii协议,可以将终端的term属性设置为ICANON标准模式,并用fgets一次读一行数据,
如下设置支持退格,delete, 但不能支持历史命令。
new_flags.c_lflag |= ICANON;    // it makes ECHOE works
new_flags.c_lflag |= ECHOE;     // it makes ERASE character setting works, not print 'ERASE character' itself
new_flags.c_lflag &= ~ECHOPRT;  // NOT print the deleted character

new_flags.c_lflag = 0x8a3b;  // this value is the total setting, but for porting, we shall use macro in preference
new_flags.c_cc[VERASE] = 0x8;   //delete one character, set ERASE to backspace(0x08), also can set to DEL or ctrl-H
new_flags.c_cc[VWERASE] = 0x7f; //delete one word, set WERASE to delete(0x7f), also can set to DEL or ctrl-W
new_flags.c_cc[VKILL] = 0x4;    //delete one line, set KILL to ctrl+d(0x4), also can set to ctrl-U


为了能够支持最开始的ascii命令和hex命令,需要用到非ICanon模式
new_flags.c_lflag &= ~(ICANON | ISIG);  
此时就不能使用fgets或者readline等函数,因为string的结尾没有了\r\n, 而fgets等是通过\r\n来判断结束标志的。
因此想到用read函数,一次读一个字符处理。
如果是ascii,则读到\n,\r\n之一就结束。
如果是hex,则读到指定长度则停止。这里需要考虑一个问题,如果hex string 没输入完成,则需要timeout结束本次输入等待,不然会和下一次读
耦合。比如hex string内容如下ef 0a 01 00 01 01 00 25 36 66, 其中第二个字节0a为消息长度,表明本次长度是10. 如果用户输入的命令是
ef 0a 01 00 01 01 25 36 66, 少了一个字节,则程序需要timeout, 不能一直等最后一个字节。由于fd默认是阻塞的,所有此时read会一直等待
最后一个字节,这样当用户想丢弃上次输入,重新输入内容的时候,第一个字节会被认为是上一次的最后一个字节。为了解决这个问题,需要将fd
设置为非阻塞的,然后判断uptime和上次时间是否超时,如果超时,就丢弃上次的数据。
#include      
#include      
#include      
#include      
   
#define     COUNT  10  
int  
main()  
{  
    char    buf[COUNT];  
    size_t  nbytes;  
    int     n, flags;  
    int     fd;  
  
    fd = 0;  
    if ( (flags = fcntl(STDIN_FILENO, F_GETFL, 0)) < 0)  
    {  
        printf("F_GETFL error");  
        exit(0);  
    }     
    printf("flags old:%d\n", flags);  
 
    flags |= O_NONBLOCK;  
    if (fcntl(STDIN_FILENO, F_SETFL, flags) < 0)  
    {  
        printf("F_SETFL error");  
        exit(0);  
    }    
    printf("flags new:%d\n", flags);  
    nbytes = 10;  
    read(STDIN_FILENO, buf, nbytes);   //如果没有设置非阻塞,下面的printf代码不会执行
    printf("hello\n");  
   return 0;
}

  



阅读(2413) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~