任务:在之前的框架上编写 使用按键和触摸屏 的代码(select方式)
1、介绍select
int select (int maxfd + 1, fd_set* readset, fd_set* writeset, fd_set* exceptset, const struct timeval* timeout);
监测多个文件,只要有一个文件可读/可写/异常或超时,即返回。
休眠检测,CPU占用率低,适用于简单的场合。
头文件:
#include <sys/select.h>
参数:
int maxfd | 最大文件句柄 |
---|---|
fd_set* readset | 被监测是否可读的文件 |
fd_set* writeset | 被检测是否可写的文件 |
fd_set* exceptset | 被检测是否有异常的文件 |
const struct timeval* timeout | 超时时间 |
timeval结构的定义:
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
轮询方式:在input_manager.c里的GetInputEvent,不管有没有数据不停去调用stdin.c里的StdinGetInputEvent获取输入事件,去调用touchscreen.c里的TouchScreenGetInputEvent获取输入事件。
select方式:在input_manager.c里用select监测数据,得到数据了才去调用stdin.c里的StdinGetInputEvent获取输入事件,去调用touchscreen.c里的TouchScreenGetInputEvent获取输入事件。没有数据就休眠,有数据内核去唤醒。
参考:UNIX高级编程——I/O多路转接
2、在Input_manager.h里
修改 结构体InputOpr, 添加文件句柄
typedef struct InputOpr {
char *name;
int iFd;
int (*DeviceInit)(void);
int (*DeviceExit)(void);
int (*GetInputEvent)(PT_InputEvent ptInputEvent);
struct InputOpr *ptNext;
}T_InputOpr, *PT_InputOpr;
3、在stdin.c里
3.1、修改StdinDevInit():
g_tstdinOpr.iFd = STDIN_FILEON;
完整代码:
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);
g_tStdinOpr.iFd = STDIN_FILENO;
return 0;
}
4、在touchscreen.c里
4.1、修改TouchScreenDevInit():
g_tTouchScreenOpr.iFd = ts_fd(g_tTSDev); //获得文件句柄
完整代码:
/* 注意: 由于要用到LCD的分辨率, 此函数要在SelectAndInitDisplay之后调用 */
static int TouchScreenDevInit(void)
{
char *pcTSName = NULL;
if ((pcTSName = getenv("TSLIB_TSDEVICE")) != NULL )
{
g_tTSDev = ts_open(pcTSName, 1);
}
else
{
g_tTSDev = ts_open("/dev/event0", 1);
}
if (!g_tTSDev) {
DBG_PRINTF("ts_open error!\n");
return -1;
}
if (ts_config(g_tTSDev)) {
DBG_PRINTF("ts_config error!\n");
return -1;
}
if (GetDispResolution(&giXres, &giYres))
{
return -1;
}
g_tTouchScreenOpr.iFd = ts_fd(g_tTSDev); //获得文件句柄
return 0;
}
5、在input_manager.c 里
static fd_set g_tRFds;
static int g_iMaxFd = -1;
int AllInputDevicesInit(void)
{
PT_InputOpr ptTmp = g_ptInputOprHead;
int iError = -1;
FD_ZERO(&g_tRFds); //全清零
while (ptTmp)
{
if (0 == ptTmp->DeviceInit())
{
FD_SET(ptTmp->iFd, &g_tRFds); //设置检测对象, 设置g_tRFds里的某一位给ptTmp->iFd
if (g_iMaxFd < ptTmp->iFd) //记录最大文件句柄
g_iMaxFd = ptTmp->iFd;
iError = 0;
}
ptTmp = ptTmp->ptNext;
}
g_iMaxFd++; //因为select是最大文件句柄+1
return iError;
}
select 方式
int GetInputEvent(PT_InputEvent ptInputEvent)
{
/* 用select函数监测stdin,touchscreen,
有数据时再调用它们的GetInputEvent或获得具体事件
*/
PT_InputOpr ptTmp = g_ptInputOprHead;
fd_set tRFds;
int iRet;
tRFds = g_tRFds;
iRet = select(g_iMaxFd, &tRFds, NULL, NULL, NULL); //超时时间设为NULL,有输入事件的数据再返回
if (iRet > 0) //大于0表示有数据
{
while (ptTmp)
{
if (FD_ISSET(ptTmp->iFd, &tRFds)) //是否可读
{
if(0 == ptTmp->GetInputEvent(ptInputEvent))
{
return 0;
}
}
ptTmp = ptTmp->ptNext;
}
}
return -1;
}