多输入之轮询


title: 多输入之轮询
date: 2019/3/19 19:27:18
toc: true

多输入之轮询

代码仓库

方式一

https://gitee.com/layty/project_for_linux/tree/master/03-ebook/02_input_by_query

方式二

https://gitee.com/layty/project_for_linux/tree/master/03-ebook/03_input_by_query_select

引入

这里我们采用两种方式的输入,使用查询的方式来读取具体的输入,轮询的前提就是所有输入设备都是非阻塞的

  • 触摸屏
  • 标准输入

关于这里的io模型,select参考《嵌入式Linux应用程序开发标准教程》里面的第六章

触摸屏

对于触摸屏的库tslib,支持非阻塞打开,也就是传递参数1即可

struct tsdev *ts_open(const char *name, int nonblock)
{
	if (nonblock)
		flags |= O_NONBLOCK;
}

O_NONBLOCK (non-blocking) 它在读取不到数据时会回传-1,并且设置errno为 EAGAIN

具体的使用代码可以参考tslib-1.4.tar.gz/tests/ts_print.c

标准输入

标准输入这里可以有两种方式:

方式一 设置终端输入为非阻塞

struct termios tTTYState;
//get the terminal state
tcgetattr(STDIN_FILENO, &tTTYState);
//turn off canonical mode
tTTYState.c_lflag &= ~ICANON;
//minimum of number input read.
tTTYState.c_cc[VMIN] = 0; 
// 立即返回
tTTYState.c_cc[TIME] = 0;   
//set the terminal attributes.
tcsetattr(STDIN_FILENO, TCSANOW, &tTTYState);

然后从流中读取

int num_read,ch;
char  buf_read[10];
num_read = fread(buf_read, 1, 1, stdin);
if(num_read)
{
	ch=buf_read[0];
    ....
}

方式二 :使用阻塞一个字符,然后使用select的超时为0来达到非阻塞的效果

static int StdinDevInit(void)
{
    struct termios tTTYState;
    //get the terminal state
    tcgetattr(STDIN_FILENO, &tTTYState);
    //turn off canonical mode
    tTTYState.c_lflag &= ~ICANON;
    //minimum of number input read.
    tTTYState.c_cc[VMIN] = 1;   			/* 这里其实是阻塞的有一个数据时就立刻返回 */
    //set the terminal attributes.
    tcsetattr(STDIN_FILENO, TCSANOW, &tTTYState);
	return 0;
}

然后读取输入的时候用select来监视读取的流,select的超时为0也就是没有数据就马上退出

int StdGet(T_InputEvent* out_input_event)
{
	struct timeval time_out;
	//这里的串口读取是阻塞的,select可以设置出一个超时时间,如果设置超时为0,则也就是非阻塞的了
	fd_set uart_fd_set;
	time_out.tv_sec = 0;
    time_out.tv_usec = 0;
    
	FD_ZERO(&uart_fd_set);
	FD_SET(STDIN_FILENO, &uart_fd_set); //注意这里使用的文件句柄,而不是File*	
	/*		fd+1,readfds,writefds,exceptfds,timeout		*/
	select(STDIN_FILENO+1, &uart_fd_set, NULL, NULL, &time_out);//这里就是监控 STDIN_FILENO 下的读的操作

	// 有数据返回
	if(FD_ISSET(STDIN_FILENO,&uart_fd_set))
	{
		char ch;
		ch=fgetc(stdin);
		if(ch)
            ....
    }
}

BUGS

在老师的视频处理触摸屏的时候,代码如下,这里判断的iRet=0的时候也去返回数据,这里应该是有问题的,但是老师在使用select机制来使终端的时候触摸屏不会有问题,而使用我的直接设置终端不阻塞就有问题,希望高手帮忙分析一下

iRet = ts_read(g_tTSDev, &tSamp, 1);

if (iRet < 0) {					//这里应该是 if (iRet <= 0)  0也是没有有效数据的
    return -1;
}

还有就是判断超时,没有判断大小,所以应该先判断大小先,这里应该没什么关系

static int isOutOf500ms(struct timeval *ptPreTime, struct timeval *ptNowTime)
{
	int iPreMs;
	int iNowMs;
	
	iPreMs = ptPreTime->tv_sec * 1000 + ptPreTime->tv_usec / 1000;
	iNowMs = ptNowTime->tv_sec * 1000 + ptNowTime->tv_usec / 1000;

	return (iNowMs > iPreMs + 500);
}

static int isOutOf500ms(struct timeval *ptPreTime, struct timeval *ptNowTime)
{
	int iPreMs;
	int iNowMs;
	int ret;
	
	iPreMs = ptPreTime->tv_sec * 1000 + ptPreTime->tv_usec / 1000;
	iNowMs = ptNowTime->tv_sec * 1000 + ptNowTime->tv_usec / 1000;

	ret=iPreMs-iNowMs;
	if(ret>500 || ret <-500)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

实验

  1. tslib库,这里如果有问题看之前的触摸屏驱动文章

    1. 修改 /etc/ts.conf第1行(去掉#号和第一个空格),# module_raw input改为module_raw input

    2. 设置环境变量

      export TSLIB_TSDEVICE=/dev/event0
      export TSLIB_CALIBFILE=/etc/pointercal
      export TSLIB_CONFFILE=/etc/ts.conf
      export TSLIB_PLUGINDIR=/lib/ts
      export TSLIB_CONSOLEDEVICE=none
      export TSLIB_FBDEVICE=/dev/fb0
      

    3.校准 ts_calibrate

  2. 开启telnettelnetd -l /bin/sh

  3. 运行程序./show_file -f simsun1.ttc -s 12 main.c

  4. pc上可以使用telnet再登录开发板查看cpu

原文地址:https://www.cnblogs.com/zongzi10010/p/10561132.html