所学来自百问网
目录
1.输入系统
2. 数据结构的抽象
input_manager.h:该文件对触摸屏和网络输入设备进行数据结构的抽象
#ifndef _INPUT_MANAGER_H
#define _INPUT_MANAGER_H
#include <sys/time.h>
#ifndef NULL
#define NULL (void *)0
#endif
#define INPUT_TYPE_TOUCH 1 // 触摸屏
#define INPUT_TYPE_NET 2 // 网络
// 表示事件本身
typedef struct InputEvent{
// 结构体 表时间
struct timeval tTime;
int iType; // 表示的是触摸屏还是网络数据
// 触摸屏数据
int iX;
int iY;
int iPressure;
// 存储网络数据
char str[1024];
}InputEvent,*PInputEvent;
// 表输入设备
typedef struct InputDevice{
// 设备名字 表示那种设备
char *name;
// 获取输入设备数据
int (*GetInputEvent)(PInputEvent ptInputEvent);
// 输入设备初始化函数和退出函数
int (*DeviceInit)(void);
int (*DeviceExit)(void);
// 链表 可支持多个设备
struct InputDevice *ptNext;
}InputDevice,*PInputDevice;
void RegisterInputDevice(PInputDevice ptInputDev);
void InputInit(void);
int GetInputEvent(PInputEvent ptInputEvent);
void InputDeviceInit(void);
#endif
3. 底层的管理
input_manager.c:此文件作为上层app和底层驱动的中间层,通过环形缓存区对设备数据进行存储,每个设备创建线程对环形缓冲区进行操作,读写锁和条件变量保证了线程同步
/* 此文件作为上层app和底层驱动的中间层,即中间件*/
#include <input_manager.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
static PInputDevice g_InputDevs = NULL;
// 初始化读写锁
static pthread_mutex_t g_tMutex = PTHREAD_MUTEX_INITIALIZER;
// 初始化条件变量
static pthread_cond_t g_tConVar = PTHREAD_COND_INITIALIZER;
/* start of 实现环形buffer */
#define BUFFER_LEN 20
static int g_iRead = 0;
static int g_iWrite = 0;
static InputEvent g_atInputEvents[BUFFER_LEN];
// 判断环形缓存区是否满
static int isInputBufferFull(void)
{
// 判断条件 下一个写位置等于读位置
return (g_iRead == ((g_iWrite + 1) % BUFFER_LEN));
}
// 判断环形缓存区是否空
static int isInputBufferEmpty(void)
{
// 判断条件 写位置等于读位置
return (g_iRead == g_iWrite);
}
// 往环形buffer里面加数据
static void PutInputEventToBuffer(PInputEvent ptInputEvent)
{
if(!isInputBufferFull())
{
g_atInputEvents[g_iWrite] = *ptInputEvent;
g_iWrite = (g_iWrite + 1) % BUFFER_LEN;
}
}
// 往环形buffer获取数据
static int GetInputEventFromBuffer(PInputEvent ptInputEvent)
{
if(!isInputBufferEmpty())
{
*ptInputEvent = g_atInputEvents[g_iRead] ;
g_iRead = (g_iRead + 1) % BUFFER_LEN;
return 1;
}else
return 0;
}
/* end of 实现环形buffer */
// 将设备加入链表
void RegisterInputDevice(PInputDevice ptInputDev)
{
ptInputDev->ptNext = g_InputDevs;
g_InputDevs = ptInputDev;
}
// 上层app 注册设备
void InputInit(void)
{
//注册触摸屏设备
extern void TouchscreenRegister(void);
TouchscreenRegister();
//注册网络输入设备
extern void NetinputRegister(void);
NetinputRegister();
}
static void *input_recv_thread_func(void *data)
{
PInputDevice ptInputDev = (PInputDevice)data;
InputEvent tEvent;
int ret;
while(1)
{
// 读数据
ret = ptInputDev->GetInputEvent(&tEvent);
if(!ret)
{
// 保存数据
pthread_mutex_lock(&g_tMutex);
PutInputEventToBuffer(&tEvent); //将数据存入环形缓存区
// 唤醒等待数据的线程
pthread_cond_signal(&g_tConVar);
pthread_mutex_unlock(&g_tMutex);
}
}
return NULL;
}
// 底层设备驱动 选择设备
void InputDeviceInit(void)
{
int ret;
pthread_t pid;
// 初始化每个设备 创建线程
PInputDevice ptTmp = g_InputDevs;// 指向链表头
while(ptTmp) // 设备存在
{
// 初始化设备
ret = ptTmp->DeviceInit();
// 创建线程
if(ret == 0)
{
ret = pthread_create(&pid,NULL,input_recv_thread_func,ptTmp);
}
// 指向下一个链表
ptTmp = ptTmp->ptNext;
}
}
// 获取APP的数据
int GetInputEvent(PInputEvent ptInputEvent)
{
InputEvent tEvent;
int ret;
// 无数据则休眠 否则返回数据
pthread_mutex_lock(&g_tMutex); // 上锁
if(GetInputEventFromBuffer(&tEvent))
{
*ptInputEvent = tEvent;
pthread_mutex_unlock(&g_tMutex); // 解锁
return 0;
}else
{
pthread_cond_wait(&g_tConVar,&g_tMutex); //等待
if(GetInputEventFromBuffer(&tEvent))
{
*ptInputEvent = tEvent;
ret = 0;
}else
{
ret = -1;
}
pthread_mutex_unlock(&g_tMutex);
}
return ret;
}
4. 触摸屏编程
#include <input_manager.h>
#include <tslib.h> //使用tslib库
#include <stdio.h>
static struct tsdev *g_ts;
// 获取触摸屏事件
static int TouchscreenGetInputEvent(PInputEvent ptInputEvent)
{
struct ts_sample samp;
int ret;
ret = ts_read(g_ts,&samp,1);
if(ret != 1)
return -1;
ptInputEvent->iType = INPUT_TYPE_TOUCH; //表示触摸屏
ptInputEvent->iX = samp.x;
ptInputEvent->iY = samp.y;
ptInputEvent->iPressure = samp.pressure;
ptInputEvent->tTime = samp.tv;
return 0;
}
// 对触摸屏进行初始化
static int TouchscreenDeviceInit(void)
{
g_ts = ts_setup(NULL, 0);
if (!g_ts)
{
printf("ts_setup err\n");
return -1;
}
return 0;
}
// 释放资源
static int TouchscreenDeviceExit(void)
{
ts_close(g_ts);
return 0;
}
// 抽象的实现
static InputDevice g_tTouchscreenDev ={
.name = "touchscreen",
.GetInputEvent = TouchscreenGetInputEvent,
.DeviceInit = TouchscreenDeviceInit,
.DeviceExit = TouchscreenDeviceExit,
};
// 注册设备
void TouchscreenRegister(void)
{
RegisterInputDevice(&g_tTouchscreenDev);
}
5. 触摸屏单元测试
int main(int argc, char * * argv)
{
InputEvent event;
int ret;
g_tTouchscreenDev.DeviceInit();
while(1)
{
ret = g_tTouchscreenDev.GetInputEvent(&event);
if(ret){
printf("GetInputEvent err\n");
return -1;
}else{
printf("Type: %d\n",event.iType);
printf("iX: %d\n",event.iX);
printf("iY: %d\n",event.iY);
printf("iPressure: %d\n",event.iPressure);
}
}
return 0;
}
6. 网络输入编程
net_input.c:该文件主要是对网络编程服务端进行实现,同时对设备进行初始化
#include <input_manager.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#define SERVER_PORT 8888
static int g_iSocketServer;
static int NetinputGetInputEvent(PInputEvent ptInputEvent)
{
struct sockaddr_in tSocketClientAddr;
int iRecvLen;
char aRecvBuf[1000];
unsigned int iAddrLen;
iAddrLen = sizeof(struct sockaddr);
// 接收客户端数据
iRecvLen = recvfrom(g_iSocketServer, aRecvBuf, 999, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
if (iRecvLen > 0)
{
aRecvBuf[iRecvLen] = '\0';
//printf("Get Msg From %s : %s\n", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf);
ptInputEvent->iType = INPUT_TYPE_NET;
gettimeofday(&ptInputEvent->tTime, NULL);
strncpy(ptInputEvent->str,aRecvBuf,1000);
ptInputEvent->str[999] = '\0';
return 0;
}else{
return -1;
}
return 0;
}
// 网络设备初始化
static int NetinputDeviceInit(void)
{
struct sockaddr_in tSocketServerAddr;
int iRet;
// 创建套接字
g_iSocketServer = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == g_iSocketServer)
{
printf("socket error!\n");
return -1;
}
tSocketServerAddr.sin_family = AF_INET;
tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
memset(tSocketServerAddr.sin_zero, 0, 8);
// 绑定端口和IP
iRet = bind(g_iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
if (-1 == iRet)
{
printf("bind error!\n");
return -1;
}
return 0;
}
// 释放资源
static int NetinputDeviceExit(void)
{
close(g_iSocketServer);
return 0;
}
// 抽象的实现
static InputDevice g_tNetinputDev ={
.name = "touchscreen",
.GetInputEvent = NetinputGetInputEvent,
.DeviceInit = NetinputDeviceInit,
.DeviceExit = NetinputDeviceExit,
};
// 网络设备注册
void NetinputRegister(void)
{
RegisterInputDevice(&g_tNetinputDev);
}
7. 客户端
clinet.c:对客户端的编写
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
/* socket
* connect
* send/recv
*/
#define SERVER_PORT 8888
int main(int argc, char **argv)
{
int iSocketClient;
struct sockaddr_in tSocketServerAddr;
int iRet;
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);
#if 0
iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
if (-1 == iRet)
{
printf("connect error!\n");
return -1;
}
#endif
iAddrLen = sizeof(struct sockaddr);
iSendLen = sendto(iSocketClient, argv[2], strlen(argv[2]), 0,
(const struct sockaddr *)&tSocketServerAddr, iAddrLen);
close(iSocketClient);
return 0;
}
8. 网络单元测试
int main(int argc, char * * argv)
{
InputEvent event;
int ret;
g_tNetinputDev.DeviceInit();
while(1)
{
ret = g_tNetinputDev.GetInputEvent(&event);
if(ret){
printf("GetInputEvent err\n");
return -1;
}else{
printf("Type: %d\n",event.iType);
printf("str: %s\n",event.str);
}
}
return 0;
}
9. 综合测试
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <input_manager.h>
int main(int argc, char **argv)
{
int ret;
InputEvent event;
InputInit();
InputDeviceInit();
while (1)
{
printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
ret = GetInputEvent(&event);
if (ret) {
printf("GetInputEvent err!\n");
return -1;
}
else
{
if (event.iType == INPUT_TYPE_TOUCH)
{
printf("Type : %d\n", event.iType);
printf("iX : %d\n", event.iX);
printf("iY : %d\n", event.iY);
printf("iPressure : %d\n", event.iPressure);
}
else if (event.iType == INPUT_TYPE_NET)
{
printf("Type : %d\n", event.iType);
printf("str : %s\n", event.str);
}
}
}
return 0;
}
点击屏幕
获取网络信息