目录
一、数据结构抽象
1.抽象出数据类型
一、你需要有个数据类型,用来辨别他是什么数据类型(网络数据或者触摸屏数据)
二、对于触摸屏数据,需要x坐标和y坐标,对于点击事件,还需要一个压力数据
有时候我们还可以加上时间
三、对于网络数据他是一个字符串
typedef struct InputEvent
{
struct timeval time;
int type;
int x;
int y;
int pressure;
char str[1024];
}InputEvent, *PInputEvent;
2.抽象出设备类型
1.提供一个名字,判断是哪种设备
2.输入设备需要提供一个函数,用来获取数据,将获取到的数据保存到上面的数据结构体中
3.初始化设备函数,用来打开设备节点
4.有初始化,就有退出函数
5.输入设备有多个,需要使用链表将这些设备链在一起
typedef struct InputDevice
{
char *name;
int (*GetInputEvent)(PInputEvent pInputEvent);
int (*InitDevice)(void);
int (*ExitDevice)(void);
struct InputDevice *ptnext;
}InputDevice, *PInputDevice;
二、触摸屏编程
1.实现抽象出来的设备类型结构体
2.创建实现该结构体所需的函数
2.1触摸屏的初始化函数
struct tsdev *g_ts;
static int TouchScreenInitDevice(void)
{
g_ts = ts_setup(NULL, 0);
if (!g_ts)
{
printf("ts_setup err\n");
return -1;
}
return 0;
}
2.2触摸屏的退出函数
static int TouchScreenExitDevice(void)
{
ts_close(g_ts);
return 0;
}
2.3触摸屏的事件类型获取函数
这个读取函数中,需要读取到的数据结构体转换成我们抽象出来的数据结构体类型
![](https://i-blog.csdnimg.cn/direct/067b3149edf440508f1a9f022e8aaa05.png)
static int TouchScreenGetInputEvent(PInputEvent ptInputEvent)
{
struct ts_sample samp;
int ret;
ret = ts_read(g_ts, &samp, 1);
if(ret != 1)
return -1;
ptInputEvent->type = INPUT_TYPE_TOUCH;
ptInputEvent->x = samp.x;
ptInputEvent->y = samp.y;
ptInputEvent->pressure = samp.pressure;
ptInputEvent.time = samp.tv;
return 0;
}
3.单元测试
int main(int argc, char **argv)
{
int ret;
InputEvent event;
g_tTouchScreenDev.InitDevice();
while(1)
{
ret = g_tTouchScreenDev.GetInputEvent(&event);
if(ret)
{
printf("GetInputEvent error\n");
}
else
{
printf("type : %d\n",event.type);
printf("x : %d\n",event.x);
printf("y : %d\n",event.y);
printf("pressure : %d\n",event.pressure);
}
}
return 0;
}
三、网络输入编程
1.实现抽象出来的结构体
2.单元测试
需要建立一个客户端给服务器发送消息。
#define SERVER_PORT 8888
int main(int argc, char **argv)
{
int iSocketClient;
struct sockaddr_in tSocketServerAddr;
int iRet;
unsigned char ucSendBuf[1000];
int iSendLen;
int iAddrLen;
if (argc != 3)
{
printf("Usage:\n");
printf("%s <server_ip> <str>\n", argv[0]);
return -1;
}
iSocketClient = socket(AF_INET, SOCK_DGRAM, 0);
tSocketServerAddr.sin_family = AF_INET;
tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
//tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
{
printf("invalid server_ip\n");
return -1;
}
memset(tSocketServerAddr.sin_zero, 0, 8);
iAddrLen = sizeof(struct sockaddr);
iSendLen = sendto(iSocketClient, argv[2], strlen(argv[2]), 0,
(const struct sockaddr *)&tSocketServerAddr, iAddrLen);
close(iSocketClient);
return 0;
}
在调试的过程中遇到段错误,原因是我在客户端的最后没有加上close()。
四、输入管理
引入输入管理的作用是同时从多个设备输入
1.框架
2.实现
1.注册设备
在管理文件中,首先是为下层提供了一个注册函数
下层可以通过调用这个方法将自己注册进链表中
最后通过InputInit可以管理设备的注册
void InputInit(void)
{
extern void NetInputDevRegister();
NetInputDevRegister();
extern void TouchScreenDevRegister();
TouchScreenDevRegister();
}
2.初始化输入设备
从链表中将所有设备取出来,调用它们的InitDevic()函数初始化硬件,并且为它创建一个线程
void InputDeviceInit(void)
{
int ret;
pthread_t tid;
PInputDevice ptTmp = g_InputDevs;
while (ptTmp)
{
ret = ptTmp->InitDevice();
if(!ret)
{
ret = pthread_create(&tid, NULL, input_thread_func, ptTmp);
}
}
}
线程的功能函数是将获取来的数据存入环形缓冲区
static void *input_thread_func (void *data)
{
PInputDevice tInputDev = (PInputDevice)data;
PInputEvent tEvent;
int ret;
while (1)
{
ret = tInputDev->GetInputEvent(&tEvent);
if(!ret)
{
pthread_mutex_lock(&g_tMutex);
PutEventBuff(&tEvent);
pthread_cond_signal(&g_tConVar);
pthread_mutex_unlock(&g_tMutex);
}
}
return NULL;
}
3.获取输入数据
这部分需要用到环形缓冲区,不了解可以先看:
上层的应用程序通过调用GetInputEvent()函数来获取数据
从环形缓冲区里获得数据
int GetInputEvent(PInputEvent pINputEvent)
{
int ret;
InputEvent tEvent;
pthread_mutex_lock(&g_tMutex);
if(GetEventBuff(&tEvent))
{
pthread_mutex_unlock(&g_tMutex);
return 0;
}
else
{
pthread_cond_wait(&g_tConVar, &g_tMutex);
if(GetEventBuff(&tEvent))
{
ret = 0;
}
else
{
ret = -1;
}
pthread_mutex_unlock(&g_tMutex);
}
return ret;
}
3.单元测试
1.调用初始化函数
2.调用获取输入数据函数
3.判断输入数据类型,选择输出格式
void IntpuDeviceInit(void)
{
int ret;
pthread_t tid;
/* for each inputdevice, init, pthread_create */
PInputDevice ptTmp = g_InputDevs;
while (ptTmp)
{
/* init device */
ret = ptTmp->DeviceInit();
/* pthread create */
if (!ret)
{
ret = pthread_create(&tid, NULL, input_recv_thread_func, ptTmp);
}
ptTmp= ptTmp->ptNext;
}
}
五、错误总结
void IntpuDeviceInit(void)
{
int ret;
pthread_t tid;
/* for each inputdevice, init, pthread_create */
PInputDevice ptTmp = g_InputDevs;
while (ptTmp)
{
/* init device */
ret = ptTmp->DeviceInit();
/* pthread create */
if (!ret)
{
ret = pthread_create(&tid, NULL, input_recv_thread_func, ptTmp);
}
ptTmp= ptTmp->ptNext;
}
}
上述代码中,在完成一次线程创建后,我将
ptTmp = ptTmp->ptNext
写成
g_InputDevs= ptTmp->ptNext
导致的就是网络创建和绑定失败。