支持触摸屏和网络输入
100ask电子产品量产工具全部代码:https://github.com/studyalldaya/100ask_project1
上层input_manager
和显示部分一样,设备代码和上层代码分层分离,通过Input_device结构体抽象输入设备,Input_data结构体抽象输入的数据(事件)。
typedef struct Input_data {
struct timeval time;
int type;//touchscreen or net?
int x;
int y;
unsigned int presure;
char str[1024];//from net
} Input_data;
typedef struct Input_device {
char *name;
int (*device_init)(void);//open
int (*device_exit)(void);//close
int (*get_input_data)(Input_data *inputData);
struct Input_device *next;
} Input_device;
各种input设备同样加入到一个设备链表中,底层提供touchscreen_register和net_register函数,上层的register_input提供给底层文件使用。
extern void touchscreen_register(void);
extern void net_register(void);
void register_input(Input_device *dev)
{
dev->next = inputDev;
inputDev = dev;
}
void input_init(void)
{
/*register touchscreen*/
touchscreen_register();
/*register net dev*/
net_register();
}
初始化每个inputdev,对每一个dev,开一个接收线程来执行相关数据的处理。
int input_device_init(void)
{
int ret;
pthread_t tid;
/*对每一个dev , init and pthread_create*/
Input_device *temp = inputDev;
while (temp) {
/*init dev*/
ret = temp->device_init();
/*pthread*/
if (!ret) {
/*所有设备开的线程都使用同一个函数,传入temp用来分辨设备*/
pthread_create(&tid, NULL, input_recv_thread_func, temp);
}
temp = temp->next;
}
return 0;
}
int input_device_exit(void)
{
Input_device *temp = inputDev;
while (temp) {
temp->device_exit();
temp = temp->next;
}
return 0;
}
调用dev->get_input_data函数获取输入的数据,多线程要注意对共享资源的处理,,这里使用互斥锁和条件变量来线程同步。
//recv data thread
static void *input_recv_thread_func(void *data)
{
int ret;
Input_device *dev = (Input_device *) data;
Input_data inputData;
while (1) {
/*读取数据*/
ret = dev->get_input_data(&inputData);
if (!ret) {
/*保存数据*/
pthread_mutex_lock(&mutex);
put_data(&inputData);
pthread_mutex_unlock(&mutex);
/*唤醒等待数据的线程*/
pthread_cond_signal(&cond);
}
}
return NULL;
}
触摸屏可能一下子会上报很多数据,netdev可能同时有多个client发送数据,
所以不能使用单一变量来保存数据,可以使用 --环形缓冲区–。
#define BUFFER_LEN 20
static int r = 0;
static int w = 0;
static Input_data inputDatas[BUFFER_LEN];
static int buffer_full(void)
{
return (r == ((w + 1) % BUFFER_LEN));
}
static int buffer_empty(void)
{
return (r == w);
}
static void put_data(Input_data *data)
{
if (!buffer_full()) {
inputDatas[w] = (*data);
w = ((w + 1) % BUFFER_LEN);
}
}
/*数据放入data*/
static int get_data(Input_data *data)
{
if (!buffer_empty()) {
(*data) = inputDatas[r];
r = ((r + 1) % BUFFER_LEN);
return 0;
}
return -1;
}
底层input设备
触摸屏输入
触摸屏输入使用tslib这个开源库,使用起来非常简单,方便。
同样该文件只提供一个对外的函数touchscreen_register,其实用c++实现起来会比较方便。
#include <stdio.h>
#include <tslib.h>
#include "../include/input_manager.h"
static struct tsdev *ts;
static int touchscreen_device_init(void)
{
ts = ts_setup(NULL, 0);
if (!ts) {
printf("ts_setup err\n");
return -1;
}
return 0;
}
static int touchscreen_device_exit(void)
{
ts_close(ts);
return 0;
}
static int touchscreen_get_input_data(Input_data *inputData)
{
struct ts_sample samp;
int ret;
ret = ts_read(ts, &samp, 1);
if (ret != 1) {
return -1;
}
inputData->type = INPUT_TYPE_TOUCH;
inputData->x = samp.x;
inputData->y = samp.y;
inputData->presure = samp.pressure;
inputData->time = samp.tv;
return 0;
}
static Input_device touchscreen_dev = {
.name = "touchscreen",
.device_init = touchscreen_device_init,
.device_exit = touchscreen_device_exit,
.get_input_data = touchscreen_get_input_data,
};
//向上注册设备,因为本文件内容都是static的
void touchscreen_register(void)
{
register_input(&touchscreen_dev);
}
网络输入
网络输入的话就是写一个udp的服务器端,port为8888。得到网络输入数据后将该数据放入inputData->str中保存,注意添加’\0’结束符。
static int net_get_input_data(Input_data *inputData)
{
struct sockaddr_in socketClientAddr;
unsigned int addrLen;
int recvLen;
char recvBuf[1000];
addrLen = sizeof(struct sockaddr);
recvLen = recvfrom(socketServer, recvBuf, 999, 0, (struct sockaddr *) &socketClientAddr, &addrLen);
if (recvLen > 0) {
recvBuf[recvLen] = '\0';
//printf("Get Msg From %s : %s\n", inet_ntoa(SocketClientAddr.sin_addr), recv_buf);
inputData->type = INPUT_TYPE_NET;
gettimeofday(&inputData->time, NULL);
strncpy(inputData->str, recvBuf, 1000);
inputData->str[999] = '\0';
return 0;
} else {
printf("No client msg!\n");
return -1;
}
}
同样提供一个注册函数给上层manager。
void net_register(void)
{
register_input(&net_dev);
}