电子量产工具——3-6~~~8输入系统_输入管理
框架——环形缓冲区——代码测试
框架总软件
一、输入管理框架
在input模块增加一个 input_manager.c 进行管理
1.1怎么读取多个设备的数据?
2.核心在于:GetInputEvent
2.1 怎么同时读取多个设备?
读取触摸屏时,可能会休眠,那么网络输入就会丢失;
读取网络数据时,可能会休眠,那么触摸屏数据就会丢失
2.2 所以不能使用“先后轮询的方式”,不能使用下面的代码:
while (1)
{
g_tTouchscreenDev.GetInputEvent(&event1);
g_tInputDev.GetInputEvent(&event2);
}
2.3 要想支持多个输入设备,只能使用线程:
为每个InputDevice都创建一个“读取线程”
二、增加input模块代码(input_manager.c)
input_manager.c
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
#include <input_manager.h>
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)
{
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 tid;
PInputDevice ptTmp = g_InputDevs;
while (ptTmp)
{
ret = ptTmp->DeviceInit();
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.1各个功能
RegisterInputDevice 将各个输入设备加入到链表 InputInit 注册各个输入设备 input_recv_thread_func 线程 InputDeviceInit 初始化所有输入设备 GetInputEvent 获得输入数据
2.2各个模块简单讲解
三、引出 环形缓冲区 概念
3.1怎么避免数据丢失?
3.比如触摸屏,它会一下子上报很多数据
对于网络输入,也有可能同时又多个client发来数据
3.1 所以,不能使用单一的变量来保存数据,而是使用一个数组来保存数据
3.2 使用“环形缓冲区”
3.2增加环形缓冲区代码
#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;
}
}
四、对输入管理框架 进行测试 (input_test.c)
input_test.c
#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);
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;
}
五、总结
要在 netinput.c 和 touchscreen.c 对自身结构体注册到input_manager.c
static InputDevice g_tTouchscreenDev ={
.name = "touchscreen",
.GetInputEvent = TouchscreenGetInputEvent,
.DeviceInit = TouchscreenDeviceInit,
.DeviceExit = TouchscreenDeviceExit,
};
void TouchscreenRegister(void)
{
RegisterInputDevice(&g_tTouchscreenDev);
}
===================================================================
static InputDevice g_tNetinputDev ={
.name = "touchscreen",
.GetInputEvent = NetinputGetInputEvent,
.DeviceInit = NetinputDeviceInit,
.DeviceExit = NetinputDeviceExit,
};
void NetInputRegister(void)
{
RegisterInputDevice(&g_tNetinputDev);
}
input_manager.h/构建两个结构体
①输入设备数据InputEvent ②输入设备 数据结构抽象 例如可抽象出 触摸屏 网络输入 InputDevice
对input_manager.c 声明
void RegisterInputDevice(PInputDevice ptInputDev); void InputInit(void); void InputDeviceInit(void); int GetInputEvent(PInputEvent ptInputEvent);
|