前言:
前面我们已经实现了显示系统,现在我们来实现输入系统,与显示系统类似,下面让我们一起来对输入系统进行学习搭建吧
目录
一、数据结构抽象
1. 数据本身
2. 设备本身:
3. input_manager.h
二、触摸屏编程
touchscreen.c
三、触摸屏单元测试
1.touchscreen.c
2.上机测试
四、网络编程
netiput.c
五、网络单元测试
1.netiput.c
2.client.c
3.上机测试
一、数据结构抽象
对于每一个设备,每一个模块,都用一个结构体来表示它,以后就会很方便的替换这些模块,所以对于设备本身我们需要抽象出一个结构体,所以对于输入系统我们需要抽象出两个结构体,这两个结构分别是:1.数据本身、2.设备本身。
输入来源:1.网络数据输入 2.点击事件输入
1. 数据本身
通过这个数据抽象,就可以既表示出触摸屏本身的数据也能表示出网络本身的数据
触摸屏数据:
int iType : 判断是什么数据,是触摸屏数据还是网络数据
int iX、int iY: 判断具体坐标
int iPressure: 压力值
网络数据:
char str[1024]: 网络数据
2. 设备本身:
*name: 设备名字
(*GetInputEvent)(PInputEvent ptInputEvent): 上层代码通过这个函数得到数据,返回值判断数据是否成功,如果成功数据保存至PInputEvent ptInputEvent中
(*DeviceInit): 提供初始化函数,比如打开设备节点等
(*DeviceExit): 提供退出函数
InputDevice *ptNext : 如果想支持多个设备,就应该将这些设备列到一起,所以需要一个链表指针
3. input_manager.h
#ifndef _INPUT_MANAGER_H
#define _INPUT_MANAGER_H
#include <sys/time.h>
#ifndef NULL
#define NULL (void *)8#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;
#endif
第9行:触摸屏事件
第10行:网络事件
第13~20行:抽象出数据本身结构体InputEvent
第14行:定义出一个时间
第23~29行:抽象出设备本身结构体InputDevice
二、触摸屏编程
设备结构体的实现如下结构体:使用tslib
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 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,
};
第4行:初始化结果放到全局变量g_ts中
第8行:定义一个ts_sample 的结构体samp
static int TouchscreenGetInputEvent(PInputEvent ptInputEvent)
第6~23行:获得输入事件
static int TouchscreenDeviceInit(void)
第25~35行:对设备的初始化
static int TouchscreenDeviceExit(void)
第37~41行:关闭设备
三、触摸屏单元测试
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 : %d\n", event.iType);
printf("iX : %d\n", event.iX);
printf("iY : %d\n", event.iY);
printf("iPressure : %d\n", event.iPressure);
}
}
return 0;
}
#endif
注意:#if 1则执行,# if 0则不执行
第5行:定义一个InputEvent 结构体 event 获取数据本身传给GetInputEvent()
第8行:调用g_tTouchscreenDev结构体中的DeviceInit()进行初始化
第12行:调用g_tTouchscreenDev结构体中的GetInputEvent(&event)进行获取输入事件
第17~23行:如果返回值ret=0的话,则将数据信息打印出来
EXTRA_CFLAGS :=
CFLAGS_file.o :=
#obj-y += disp_test.o
将unittest文件夹中的Makefile中的main函数部分注释掉,因为一个程序只能允许有一个main
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y += touchscreen.o
input目录下的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
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)
需要修改顶层目录下的Makefile
第20行:LDFLAGS := -lts 设置链接
第31行:打开input目录下的文件
2.上机测试
进行make编译,如果出现以下情况,则重新译一下tslib
上板效果如下:点击开发板会将点击的信息显示出来
四、网络编程
对网络输入构造出同触摸屏编程中一样的结构体
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] = '\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;
}
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,
};
第29行:端口
第22行:获得的数据
第28行:获得的数据保存到ucRecvBuf里面
static int NetinputGetInputEvent(PInputEvent ptInputEvent)
第24~45行:获得输入事件
static int NetinputDeviceInit(void)
第47~74行:初始化socket
static int NetinputDeviceExit(void)
第76~80行:关闭设备
五、网络单元测试
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 : %d\n", event.iType);
printf("str : %s\n", event.str);
}
}
return 0;
}
#endif
注意:需要把触摸屏里面的main函数注释掉
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_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;
}
arm-buildroot-linux-gnueabihf-gcc -o client unittest/client.c
make
cp test ~/nfs_rootfs/
[root@100ask:~]# cd /mnt/