电子产品量产工具(2)- 输入系统实现

电子产品量产工具

  • 2 输入系统设计
    • 2.1 输入系统头文件input_manager.h
      • 2.1.1 数据上报格式InputEvent
      • 2.1.2 输入设备InputDevice
      • 2.1.3 输入设备InputDevice input_manager.h完整代码如下
    • 2.2 触摸屏线程touchscreen.c
      • 2.2.1 触摸屏线程结构体g_tTouchscreenDev
      • 2.2.2 设备初始化函数TouchscreenDeviceInit
      • 2.2.3 数据上报函数TouchscreenDeviceInit
      • 2.2.4 设备退出函数TouchscreenDeviceInit
      • 2.2.5 注册函数TouchscreenRegister
      • 2.2.6 触摸屏线程touchscreen.c完整代码如下
    • 2.3 网络输入线程netinput.c
      • 2.3.1 网络输入线程结构体g_tNetinputDev
      • 2.3.2 设备初始化函数NetinputDeviceInit
      • 2.3.3 数据上报函数NetinputGetInputEvent
      • 2.3.4 设备退出函数NetinputDeviceExit
      • 2.3.5 注册函数NetInputRegister
      • 2.3.6 触摸屏线程netinput.c完整代码如下
    • 2.4 输入管理input_manager.c
      • 2.4.1 初始化函数InputInit
      • 2.4.2 设备初始化函数IntpuDeviceInit
      • 2.4.3 环形缓冲区g_atInputEvents[BUFFER_LEN ]
      • 2.4.4 缓冲区事件存储函数PutInputEventToBuffer
      • 2.4.5 缓冲区事件获取函数GetInputEventFromBuffer
      • 2.4.5 事件获取函数GetInputEvent
      • 2.4.6 线程函数input_recv_thread_func
      • 2.4.7 输入管理input_manager.c完整代码如下
    • 2.5 测试程序完整代码如下
    • 2.6 客户端程序完整代码如下

2 输入系统设计

在这里插入图片描述

2.1 输入系统头文件input_manager.h

在头文件中构建触摸屏线程和网络线程统一的数据结构体和设备结构体

2.1.1 数据上报格式InputEvent

上报的数据可由触摸屏线程和网络线程产生

#define INPUT_TYPE_TOUCH 1
#define INPUT_TYPE_NET   2
....
typedef struct InputEvent {struct timeval	tTime; /*时间*/int iType;        /*数据上报类型 1为触摸屏线程数据 2为网络输入线程数据*/int iX;           /*对触摸屏线程的触点x坐标*/int iY;           /*对触摸屏线程的触点y坐标*/int iPressure;    /*对触摸屏线程的触点压力值*/char str[1024];   /*网络输入线程发送的字符串*/
}InputEvent, *PInputEvent;

2.1.2 输入设备InputDevice

对触摸屏线程和网络线程构建统一的结构体类型

typedef struct InputDevice {char *name;          /*设备名*/int (*GetInputEvent)(PInputEvent ptInputEvent);  /*接口函数,上层通过调用此函数得到数据*/int (*DeviceInit)(void);    /*设备初始化函数*/int (*DeviceExit)(void);    /*退出函数*/struct InputDevice *ptNext; /*支持多个设备,链表便于管理*/
}InputDevice, *PInputDevice;

2.1.3 输入设备InputDevice input_manager.h完整代码如下

#ifndef _INPUT_MANAGER_H
#define _INPUT_MANAGER_H
#include 
#ifndef NULL
#define NULL (void *)0
#endif
#define INPUT_TYPE_TOUCH 1
#define INPUT_TYPE_NET   2typedef 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);
void IntpuDeviceInit(void);
int GetInputEvent(PInputEvent ptInputEvent);
#endif

2.2 触摸屏线程touchscreen.c

构建触摸屏线程对应的设备结构体,并实现对应函数

2.2.1 触摸屏线程结构体g_tTouchscreenDev

构建触摸屏线程对应的设备结构体

static InputDevice g_tTouchscreenDev ={.name = "touchscreen",            /*设备名*/.GetInputEvent  = TouchscreenGetInputEvent, /*接口函数,上层通过调用此函数得到数据*/.DeviceInit     = TouchscreenDeviceInit,     /*设备初始化函数*/.DeviceExit     = TouchscreenDeviceExit,     /*退出函数*/
};

2.2.2 设备初始化函数TouchscreenDeviceInit

static struct tsdev *g_ts;
....
static int TouchscreenDeviceInit(void)
{g_ts = ts_setup(NULL, 0);  /*ts_setup由tslib提供*/if (!g_ts){printf("ts_setup err\n");return -1;}return 0;
}

2.2.3 数据上报函数TouchscreenDeviceInit

static int TouchscreenGetInputEvent(PInputEvent ptInputEvent)
{struct ts_sample samp;int ret;ret = ts_read(g_ts, &samp, 1);	/*1表示支持读取单点触摸数据*/if (ret != 1)return -1;/*数据读取成功,将ts_sample类型数据处理为前文所述的数据类型*/ptInputEvent->iType     = INPUT_TYPE_TOUCH;ptInputEvent->iX        = samp.x;ptInputEvent->iY        = samp.y;ptInputEvent->iPressure = samp.pressure;ptInputEvent->tTime     = samp.tv;return 0;
}

2.2.4 设备退出函数TouchscreenDeviceInit

static int TouchscreenDeviceExit(void)
{ts_close(g_ts);return 0;
}

2.2.5 注册函数TouchscreenRegister

将设备结构体注册进上层链表TouchscreenRegister

void TouchscreenRegister(void)
{RegisterInputDevice(&g_tTouchscreenDev);
}

2.2.6 触摸屏线程touchscreen.c完整代码如下

#include 
#include 
#include 
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);
}

2.3 网络输入线程netinput.c

构建网络输入线程对应的设备结构体,并实现对应函数
Server端:socket----bind ----recvfrom/sendto----close

2.3.1 网络输入线程结构体g_tNetinputDev

构建触摸屏线程对应的设备结构体

static InputDevice g_tNetinputDev ={.name = "netinput", /*设备名*/.GetInputEvent  = NetinputGetInputEvent,  /*接口函数,上层通过调用此函数得到数据*/.DeviceInit     = NetinputDeviceInit,    /*设备初始化函数*/.DeviceExit     = NetinputDeviceExit,     /*退出函数*/
};

2.3.2 设备初始化函数NetinputDeviceInit

#define SERVER_PORT 8888
static int g_iSocketServer;
....
static int NetinputDeviceInit(void)
{struct sockaddr_in tSocketServerAddr;int iRet;g_iSocketServer = socket(AF_INET, SOCK_DGRAM, 0); /*创建一个套接字,AF_INET是针对Internet的,因而可以允许远程通信使用。SOCK_DGRAM 表明用的是UDP协议,这样只会提供不可靠,无连接的通信。*/if (-1 == g_iSocketServer){printf("socket error!\n");return -1;}/*设置要监视的IP端口*/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);iRet = bind(g_iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr)); /*将套接字与要监视的ip端口绑定*/if (-1 == iRet){printf("bind error!\n");return -1;}return 0;
}

2.3.3 数据上报函数NetinputGetInputEvent

static int NetinputGetInputEvent(PInputEvent ptInputEvent)
{struct sockaddr_in tSocketClientAddr;int iRecvLen;char aRecvBuf[1000];unsigned int iAddrLen = sizeof(struct sockaddr);iRecvLen = recvfrom(g_iSocketServer, aRecvBuf, 999, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);/*argument1-服务器套接字  argument2-缓存区存放recvfrom函数接收到的数据 argument3-接收数据长度 argument4-一般置0 argument5-存放客户端IP地址及端口 argument6-地址长度*/if (iRecvLen > 0){aRecvBuf[iRecvLen] = '\0';//printf("Get Msg From %s : %s\n", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf);/*接收到的数据放入ptInputEvent*/ptInputEvent->iType 	= INPUT_TYPE_NET;gettimeofday(&ptInputEvent->tTime, NULL);strncpy(ptInputEvent->str, aRecvBuf, 1000);ptInputEvent->str[999] = '\0';return 0;}elsereturn -1;
}

2.3.4 设备退出函数NetinputDeviceExit

static int NetinputDeviceExit(void)
{close(g_iSocketServer);	return 0;
}

2.3.5 注册函数NetInputRegister

void NetInputRegister(void)
{RegisterInputDevice(&g_tNetinputDev);
}

2.3.6 触摸屏线程netinput.c完整代码如下

#include 
#include           /* See NOTES */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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 = 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;}elsereturn -1;
}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);	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);
}

2.4 输入管理input_manager.c

在这里插入图片描述
输入管理为上层提供接口函数用以获取数据、实现触摸屏输入与网络输入的初始化,并分别为其创建线程,实现触摸屏输入数据与网络输入数据的同时接收

2.4.1 初始化函数InputInit

将触摸屏结构体和网络输入结构体注册进链表g_InputDevs

static PInputDevice g_InputDevs  = NULL;
....
void RegisterInputDevice(PInputDevice ptInputDev)
{ptInputDev->ptNext = g_InputDevs;g_InputDevs = ptInputDev;
}void InputInit(void)
{/* regiseter touchscreen */extern void TouchscreenRegister(void);TouchscreenRegister();/* regiseter netinput */extern void NetInputRegister(void);NetInputRegister();
}

2.4.2 设备初始化函数IntpuDeviceInit

从链表中依次取出设备结构体,并为其创建线程

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); /*创建线程,argument3为线程函数 argument4为传入线程函数的参数*/}ptTmp= ptTmp->ptNext;}
}

2.4.3 环形缓冲区g_atInputEvents[BUFFER_LEN ]

实现环形缓冲区用以存储输入事件

#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);
}

2.4.4 缓冲区事件存储函数PutInputEventToBuffer

static void PutInputEventToBuffer(PInputEvent ptInputEvent)
{if (!isInputBufferFull()){g_atInputEvents[g_iWrite] = *ptInputEvent;g_iWrite = (g_iWrite + 1) % BUFFER_LEN;}
}

2.4.5 缓冲区事件获取函数GetInputEventFromBuffer

static int GetInputEventFromBuffer(PInputEvent ptInputEvent)
{if (!isInputBufferEmpty()){*ptInputEvent = g_atInputEvents[g_iRead];g_iRead = (g_iRead + 1) % BUFFER_LEN;return 1;}else{return 0;}
}

2.4.5 事件获取函数GetInputEvent

static pthread_mutex_t g_tMutex  = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  g_tConVar = PTHREAD_COND_INITIALIZER;
....
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;

2.4.6 线程函数input_recv_thread_func

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;
}

2.4.7 输入管理input_manager.c完整代码如下

#include 
#include 
#include 
#include 
#include 
#include 
static PInputDevice g_InputDevs  = NULL;
static pthread_mutex_t g_tMutex  = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  g_tConVar = PTHREAD_COND_INITIALIZER;
#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);
}static void PutInputEventToBuffer(PInputEvent ptInputEvent)
{if (!isInputBufferFull()){g_atInputEvents[g_iWrite] = *ptInputEvent;g_iWrite = (g_iWrite + 1) % BUFFER_LEN;}
}static int GetInputEventFromBuffer(PInputEvent ptInputEvent)
{if (!isInputBufferEmpty()){*ptInputEvent = g_atInputEvents[g_iRead];g_iRead = (g_iRead + 1) % BUFFER_LEN;return 1;}else{return 0;}
}void RegisterInputDevice(PInputDevice ptInputDev)
{ptInputDev->ptNext = g_InputDevs;g_InputDevs = ptInputDev;
}void InputInit(void)
{/* regiseter touchscreen */extern void TouchscreenRegister(void);TouchscreenRegister();/* regiseter netinput */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 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;}
}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;
}

2.5 测试程序完整代码如下

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include int main(int argc, char **argv)
{int ret;InputEvent event;InputInit();IntpuDeviceInit();while (1){printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);ret = GetInputEvent(&event);printf("%s %s %d, ret = %d\n", __FILE__, __FUNCTION__, __LINE__, ret);if (ret) {printf("GetInputEvent err!\n");return -1;}else{printf("%s %s %d, event.iType = %d\n", __FILE__, __FUNCTION__, __LINE__, event.iType );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;	
}

2.6 客户端程序完整代码如下

#include           /* See NOTES */
#include 
#include 
#include 
#include 
#include 
#include 
#include /* socket* connect* send/recv*/#define SERVER_PORT 8888int 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  \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;
}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部