前言:
一、数据结构抽象
对于每一个设备,每一个模块,都用一个结构体来表示它,以后就会很方便的替换这些模块,所以对于设备本身我们需要抽象出一个结构体,所以对于输入系统我们需要抽象出两个结构体,这两个结构分别是:1.数据本身、2.设备本身。
1. 数据本身
通过这个数据抽象,就可以既表示出触摸屏本身的数据也能表示出网络本身的数据
触摸屏数据:
网络数据:
2. 设备本身:
(*GetInputEvent)(PInputEvent ptInputEvent): 上层代码通过这个函数得到数据,返回值判断数据是否成功,如果成功数据保存至PInputEvent ptInputEvent中
3. 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);
void IntpuDeviceInit(void);
int GetInputEvent(PInputEvent ptInputEvent);
#endif
第10行:触摸屏事件
第11行:网络事件
二、触摸屏编程
touchscreen.c
#include <input_manager.h>
#include <tslib.h>
#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 errn");
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);
}
static int TouchscreenGetInputEvent(PInputEvent ptInputEvent)
第6~23行:获得输入事件
static int TouchscreenDeviceInit(void)
第25~35行:对设备的初始化
static int TouchscreenDeviceExit(void)
第37~41行:关闭设备
void TouchscreenRegister(void)
三、触摸屏单元测试
1.touchscreen.c
在touchscreen.c 代码下面加一个main函数进行触摸屏的单元测试
#if 1
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 : %dn", event.iType);
printf("iX : %dn", event.iX);
printf("iY : %dn", event.iY);
printf("iPressure : %dn", event.iPressure);
}
}
return 0;
}
#endif
第5行:定义一个InputEvent 结构体 event 获取数据本身传给GetInputEvent()
第8行:调用g_tTouchscreenDev结构体中的DeviceInit()进行初始化
第12行:调用g_tTouchscreenDev结构体中的GetInputEvent(&event)进行获取输入事件
EXTRA_CFLAGS :=
CFLAGS_file.o :=
#obj-y += disp_test.o
将unittest文件夹中的Makefile中的main函数部分注释掉,因为一个程序只能允许有一个main
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y += touchscreen.o
CROSS_COMPILE ?=
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
export AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP
CFLAGS := -Wall -O2 -g
CFLAGS += -I $(shell pwd)/include
LDFLAGS := -lts
export CFLAGS LDFLAGS
TOPDIR := $(shell pwd)
export TOPDIR
TARGET := test
obj-y += display/
obj-y += input/
all : start_recursive_build $(TARGET)
@echo $(TARGET) has been built!
start_recursive_build:
make -C ./ -f $(TOPDIR)/Makefile.build
$(TARGET) : built-in.o
$(CC) -o $(TARGET) built-in.o $(LDFLAGS)
clean:
rm -f $(shell find -name "*.o")
rm -f $(TARGET)
distclean:
rm -f $(shell find -name "*.o")
rm -f $(shell find -name "*.d")
rm -f $(TARGET)
2.上机测试
四、网络编程
netiput.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 <string.h>
/* socket
* bind
* sendto/recvfrom
*/
#define SERVER_PORT 8888
static int g_iSocketServer;
static int NetinputGetInputEvent(PInputEvent ptInputEvent)
{
struct sockaddr_in tSocketClientAddr;
struct int iRecvLen;
char aRecvBuf[1000];
int iAddrLen = sizeof(struct sockaddr);
iRecvLen = recvfrom(g_iSocketServer, aRecvBuf, 999, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
if (iRecvLen > 0)
{
aRecvBuf[iRecvLen] = '';
//printf("Get Msg From %s : %sn", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf);
ptInputEvent->iType = INPUT_TYPE_NET;
gettimeofday(&ptInputEvent->tTime, NULL);
strncpy(ptInputEvent->str, aRecvBuf, 1000);
ptInputEvent->str[999] = '';
return 0;
}
else
return -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);
}
第29行:端口
第22行:获得的数据
static int NetinputGetInputEvent(PInputEvent ptInputEvent)
第24~45行:获得输入事件
static int NetinputDeviceInit(void)
第47~74行:初始化socket
static int NetinputDeviceExit(void)
第76~80行:关闭设备
void NetInputRegister(void)
五、网络单元测试
1.netiput.c
#if 1
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 : %dn", event.iType);
printf("str : %sn", event.str);
}
}
return 0;
}
#endif
Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y += touchscreen.o
obj-y += netinput.o
2.client.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_ipn");
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;
}
arm-buildroot-linux-gnueabihf-gcc -o client unittest/client.c
make
cp test ~/nfs_rootfs/
[root@100ask:~]# cd /mnt/
3.上机测试
六、 输入系统的框架
如果只有一个输入设备,那么我们只需要写一个main函数即可,但是我们需要好几个设备输入,那么要想统一管理,那么就需要设计一个输入管理系统进行管理选择到底哪个设备进行输入。
在输入管理器中我们需要初始化触摸屏,并且为触摸屏提供一个线程,初始化网络设备,为网络设备提供一个线程,上层应用程序提供一些函数就可以方便的得到各类的输入事件,线程的创建线程的管理都由输入管理器进行设置。
1.框架思路:
(1).InputInit (2).IntpuDeviceInit (3).GetInputEvent
使用InputInit 创建一个链表,链表指向触摸屏设备本身和网络设备本身,通过链表就可以找到所有的输入设备
3.对于每一个设备都可以调用里面的 GetInputEvent 来获得数据,如果想同时获得多个设备的输入数据的话,那么该怎么获得?
调用IntpuDeviceInit从链表里面把每一个设备取出来,调用里面的DeviceInit 初始化,并且为每一个输入设备创造一个线程thread,线程不断调用设备里面的GetInputEvent 等待数据,一旦得到数据,就可以将获得的数据放到某个buffer
4.上层的应用程序调用GetInputEvent 时候就会去某个buffer里面查看是否有数据,有数据则返回,没数据则休眠
2.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;
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 tInputDev = (PInputDevice)data;
InputEvent tEvent;
int ret;
while (1)
{
/* 读数据 */
ret = tInputDev->GetInputEvent(&tEvent);
if (!ret)
{
/* 保存数据 */
/* 唤醒等待数据的线程 */
pthread_mutex_lock(&g_tMutex);
pthread_cond_wait(&g_tConVar, &g_tMutex);
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(PT_InputEvent ptInputEvent)
{
/* 无数据则休眠 */
/* 返回数据 */
}
void RegisterInputDevice(PInputDevice ptInputDev)
第9~13行:提供一个注册函数
void InputInit(void)
第16~25行:向上提供一个InputInit(void) 函数
第19、20行:注册触摸屏设备
第23、24行:注册网络设备
注意:其中extern是外部函数的意思
void IntpuDeviceInit(void)
第60行:将g_InputDevs链表中的每个设备都取出来,ptTmp就是对应的每一个设备
第64行:调用 DeviceInit() 进行初始化
第69行:创造子线程
第67~70行:为每个设备创造线程
第72行:指向下一个设备
static void *input_recv_thread_func (void *data)
第27~52行:线程启动以后需要提供一个函数
对于不同的设备使用同一个函数,这个函数需要使用某个参数来区分这些设备 ,
第29行:一开始要从data里面得到传进来的ptTmp结构体
第36行:不断的读数据,得到的数据放到 InputEvent 下的 tEvent
第38行:判断是否有数据,如果有数据保存数据和唤醒等待数据线程
int GetInputEvent(PT_InputEvent ptInputEvent)
第76行:最重要的一个函数 ,最上层的代码只要调用这个函数就可以得到这些设备的数据
怎么避免数据丢失 ?
所以,不能使用单一的变量来保存数据,而是使用一个数组来保存数据
3.环形缓冲区
4.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;
/* 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);
}
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;
}
}
/* end of 实现环形buffer */
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;
}
第15、16行:设置读写
static int isInputBufferFull(void) static int isInputBufferEmpty(void)
第20~23行和25~28行:判断是空还是满
第20行的函数是判断满的
第25行的函数是判断空的
static void PutInputEventToBuffer(PInputEvent ptInputEvent)
第32行:如果不满的话往进放数据
static int GetInputEventFromBuffer(PInputEvent ptInputEvent)
第40~47行:得到数据
第42行:如果不空读数据
static void *input_recv_thread_func (void *data)
第76~100行:线程启动以后需要提供一个函数
对于不同的设备使用同一个函数,这个函数需要使用某个参数来区分这些设备 ,
第78行:一开始要从data里面得到传进来的ptTmp结构体
第79行:不断的读数据,得到的数据放到 InputEvent 下的 tEvent
第85行:判断是否有数据,如果有数据保存数据和唤醒等待数据线程
第90、91行:上锁,保存数据,放入到环形缓冲区内
第91行:唤醒等待数据的线程
第92行:释放锁
int GetInputEvent(PT_InputEvent ptInputEvent)
第124~153行:将从输入设备得到的数据放入到缓冲区
触摸屏和网络设备,上层线程都要去访问环形缓冲区,那么访问环形缓冲区时应该给它加上一个锁。
第129行:加锁
第132、142行:进行数据传输
第133行:如果获得数据则释放锁
第136~151行:否则休眠等待,直到获得数据,ret = 0 表示成功,ret = -1表示失败
第149行:释放锁
七、输入管理单元测试
1.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();
IntpuDeviceInit();
while (1)
{
printf("%s %s %dn", __FILE__, __FUNCTION__, __LINE__);
ret = GetInputEvent(&event);
printf("%s %s %d, ret = %dn", __FILE__, __FUNCTION__, __LINE__, ret);
if (ret) {
printf("GetInputEvent err!n");
return -1;
}
else
{
printf("%s %s %d, event.iType = %dn", __FILE__, __FUNCTION__, __LINE__, event.iType );
if (event.iType == INPUT_TYPE_TOUCH)
{
printf("Type : %dn", event.iType);
printf("iX : %dn", event.iX);
printf("iY : %dn", event.iY);
printf("iPressure : %dn", event.iPressure);
}
else if (event.iType == INPUT_TYPE_NET)
{
printf("Type : %dn", event.iType);
printf("str : %sn", event.str);
}
}
}
return 0;
}
第16行:读到的输入事件存到event中
第18行:调用InputInit进行初始化
第19行:调用IntpuDeviceInit从链表里面把每一个设备取出来
第34~40行:如果设备是触摸屏的话就把触点打印出来
2.input下的Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y += touchscreen.o
obj-y += netinput.o
obj-y += input_manager.o
3.unittest下的Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
#obj-y += disp_test.o
obj-y += input_test.o
4.顶层Makefile
CROSS_COMPILE ?=
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
export AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP
CFLAGS := -Wall -O2 -g
CFLAGS += -I $(shell pwd)/include
LDFLAGS := -lts -lpthread
export CFLAGS LDFLAGS
TOPDIR := $(shell pwd)
export TOPDIR
TARGET := test
obj-y += display/
obj-y += input/
obj-y += unittest/
all : start_recursive_build $(TARGET)
@echo $(TARGET) has been built!
start_recursive_build:
make -C ./ -f $(TOPDIR)/Makefile.build
$(TARGET) : built-in.o
$(CC) -o $(TARGET) built-in.o $(LDFLAGS)
clean:
rm -f $(shell find -name "*.o")
rm -f $(TARGET)
distclean:
rm -f $(shell find -name "*.o")
rm -f $(shell find -name "*.d")
rm -f $(TARGET)
第20行:LDFLAGS := -lts -lpthread
第31行:obj-y += unittest/
5.上板测试
book@100ask:~/12_input_manager_unittest$ arm-buildroot-linux-gnueabihf-gcc -o client unittest/client.c
book@100ask:~/12_input_manager_unittest$ make
book@100ask:~/12_input_manager_unittest$ cp client test ~/nfs_rootfs/
[root@100ask:/mnt]# input_test.c main 23
原文地址:https://blog.csdn.net/m0_63168877/article/details/134689327
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_29636.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!