所有代码都已通过测试跑通,其中代码结构如下:
#ifndef _INPUT_MANAGER_H //防止头文件重复包含,只要右边的出现过,就不会再往下编译
#define _INPUT_MANAGER_H
#include
#define INPUT_TYPE_TOUCH 1
#define INPUT_TYPE_NET 2
/* 上报的数据格式 */
typedef struct InputEvent
{
struct timeval tTime; //加入时间管理
int iType; //网络事件或者触摸事件类型
int iX; //触摸事件x坐标
int iY; //触摸事件y坐标
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
#ifndef _TSLIB_H_
#define _TSLIB_H_
/*
* tslib/src/tslib.h
*
* Copyright (C) 2016 Martin Kepplinger
* Copyright (C) 2001 Russell King.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*
* SPDX-License-Identifier: LGPL-2.1
*
*
* Touch screen library interface definitions.
*/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include
#include
#ifdef WIN32
#define TSIMPORT __declspec(dllimport)
#define TSEXPORT __declspec(dllexport)
#define TSLOCAL
#else
#define TSIMPORT
#ifdef GCC_HASCLASSVISIBILITY
#define TSEXPORT __attribute__ ((visibility("default")))
#define TSLOCAL __attribute__ ((visibility("hidden")))
#else
#define TSEXPORT
#define TSLOCAL
#endif
#endif
#ifdef TSLIB_INTERNAL
#define TSAPI TSEXPORT
#else
#define TSAPI TSIMPORT
#endif /* TSLIB_INTERNAL */
struct tsdev;
struct ts_sample {
int x;
int y;
unsigned int pressure;
struct timeval tv;
};
struct ts_sample_mt {
/* ABS_MT_* event codes. linux/include/uapi/linux/input-event-codes.h
* has the definitions.
*/
int x;
int y;
unsigned int pressure;
int slot;
int tracking_id;
int tool_type;
int tool_x;
int tool_y;
unsigned int touch_major;
unsigned int width_major;
unsigned int touch_minor;
unsigned int width_minor;
int orientation;
int distance;
int blob_id;
struct timeval tv;
/* BTN_TOUCH state */
short pen_down;
/* valid is set != 0 if this sample
* contains new data; see below for the
* bits that get set.
* valid is set to 0 otherwise
*/
short valid;
};
#define TSLIB_MT_VALID (1 << 0) /* any new data */
#define TSLIB_MT_VALID_TOOL (1 << 1) /* new tool_x or tool_y data */
struct ts_lib_version_data {
const char *package_version;
int version_num;
unsigned int features; /* bitmask, see below */
};
#define TSLIB_VERSION_MT (1 << 0) /* multitouch support */
#define TSLIB_VERSION_OPEN_RESTRICTED (1 << 1) /* ts_open_restricted() */
#define TSLIB_VERSION_EVENTPATH (1 << 2) /* ts_get_eventpath() */
#define TSLIB_VERSION_VERSION (1 << 3) /* tslib_version() */
enum ts_param {
TS_SCREEN_RES = 0, /* 2 integer args, x and y */
TS_SCREEN_ROT /* 1 integer arg, 1 = rotate */
};
struct ts_module_conf {
char *name;
char *params;
int raw;
int nr;
struct ts_module_conf *next;
struct ts_module_conf *prev;
};
/*
* Close the touchscreen device, free all resources.
*/
TSAPI int ts_close(struct tsdev *);
/*
* Reloads all modules - useful to reload calibration data.
*/
TSAPI int ts_reconfig(struct tsdev *);
/*
* Configure the touchscreen device.
*/
TSAPI int ts_config(struct tsdev *);
/*
* Changes a setting.
*/
TSAPI int ts_option(struct tsdev *, enum ts_param, ...);
/*
* Change this hook to point to your custom error handling function.
*/
extern TSAPI int (*ts_error_fn)(const char *fmt, va_list ap);
/*
* Implement this to override open() for the input device and return the fd.
*/
extern TSAPI int (*ts_open_restricted)(const char *path, int flags, void *user_data);
/*
* Implement this to override close().
*/
extern TSAPI void (*ts_close_restricted)(int fd, void *user_data);
/*
* Returns the file descriptor in use for the touchscreen device.
*/
TSAPI int ts_fd(struct tsdev *);
/*
* Load a filter/scaling module
*/
TSAPI int ts_load_module(struct tsdev *, const char *mod, const char *params);
/*
* Open the touchscreen device.
*/
TSAPI struct tsdev *ts_open(const char *dev_name, int nonblock);
/*
* Find, open and configure the touchscreen device.
*/
TSAPI struct tsdev *ts_setup(const char *dev_name, int nonblock);
/*
* Return a scaled touchscreen sample.
*/
TSAPI int ts_read(struct tsdev *, struct ts_sample *, int);
/*
* Returns a raw, unscaled sample from the touchscreen.
*/
TSAPI int ts_read_raw(struct tsdev *, struct ts_sample *, int);
/*
* Return a scaled touchscreen multitouch sample.
*/
TSAPI int ts_read_mt(struct tsdev *, struct ts_sample_mt **, int slots, int nr);
/*
* Return a raw, unscaled touchscreen multitouch sample.
*/
TSAPI int ts_read_raw_mt(struct tsdev *, struct ts_sample_mt **, int slots, int nr);
/*
* This function returns a pointer to a static copy of the version info struct.
*/
TSAPI struct ts_lib_version_data *ts_libversion(void);
/*
* Get the list of (commented-in) ts.conf module lines (as structs)
*/
TSAPI struct ts_module_conf *ts_conf_get(struct tsdev *ts);
/*
* Write the list of modules to ts.conf
*/
TSAPI int ts_conf_set(struct ts_module_conf *conf);
/*
* This function returns the path to the opened touchscreen input device file.
*/
TSAPI char *ts_get_eventpath(struct tsdev *tsdev);
/*
* This simply returns tslib's version string
*/
TSAPI char *tslib_version(void);
/*
* This prints tslib's logo to stdout, with pos preceding spaces
*/
TSAPI void ts_print_ascii_logo(unsigned int pos);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _TSLIB_H_ */
#include "input_manager.h"
#include
#include
#include
#include
#include
static pthread_mutex_t g_tMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t g_tConVar = PTHREAD_COND_INITIALIZER;
static PInputDevice g_InputDevs = NULL;
/************环形缓冲区开******************/
#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;
}
}
// 事件获取函数
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;
}
//线程函数
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 RegisterInputDevice(PInputDevice ptInputDev)
{
ptInputDev->ptNext = g_InputDevs;//指向链表头
g_InputDevs = ptInputDev;
}
void InputInit(void)
{
/* 注册按键输入 */
extern void TouchscreenRegister(void);
TouchscreenRegister();//在touchscreen.c中
/* 注册网络输入 */
extern void NetInputRegister(void);
NetInputRegister();//在netinput.c中
}
void InputDeviceInit(void)
{
int ret;
pthread_t tid;
/* for each device ,init,pthread_create */
PInputDevice ptTmp = g_InputDevs;
while (ptTmp)
{
ret = ptTmp->DeviceInit();
if (!ret)
{
ret = pthread_create(&tid, NULL, input_recv_thread_func, ptTmp);
}
ptTmp = ptTmp->ptNext;
}
}
#include /* See NOTES */
#include
#include
#include
#include
#include
#include
#include
#include
#include "input_manager.h"
#define SERVER_PORT 8888
static int g_iSocketServer;
static int NetinputGetInputEvent(PInputEvent ptInputEvent)
{
char ucRecvBuf[1000];
int iRecvLen;
struct sockaddr_in tSocketClientAddr;
unsigned int iAddrLen = sizeof(struct sockaddr);
/* 接收客户端数据报文,返回的为接收到的字节数 */
iRecvLen = recvfrom(g_iSocketServer, ucRecvBuf, sizeof(ucRecvBuf), 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
if (iRecvLen > 0)
{
ucRecvBuf[iRecvLen] = '\0';
//printf("Get Msg from %s : %s\n", inet_ntoa(socket_client_addr.sin_addr), buf);
ptInputEvent->iType = INPUT_TYPE_NET;
gettimeofday(&ptInputEvent->tTime, NULL);
strncpy(ptInputEvent->str, ucRecvBuf, 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 (g_iSocketServer == -1)
{
printf("socket error");
return -1;
}
/* 服务器端填充 sockaddr_in结构 */
tSocketServerAddr.sin_family = AF_INET;
tSocketServerAddr.sin_port = htons(SERVER_PORT);
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 (iRet == -1)
{
printf("bind error!\n");
return -1;
}
return 0;
}
static int NetinputDeviceExit(void)
{
close(g_iSocketServer);
return 0;
}
static InputDevice g_tNetinputDev = {
.name = "netinput",
.GetInputEvent = NetinputGetInputEvent,
.DeviceInit = NetinputDeviceInit,
.DeviceExit = NetinputDeviceExit,
};
void NetInputRegister(void)
{
RegisterInputDevice(&g_tNetinputDev);
}
#if 0
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\r\n");
return -1;
}
else
{
printf("iType =%d\r\n", event.iType);
printf("str =%s\r\n", event.str);
}
}
return 0;
}
#endif
#include "input_manager.h"
#include
#include
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);
}
#if 0
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\r\n");
return -1;
}
else
{
printf("iType =%d\r\n", event.iType);
printf("iX =%d\r\n", event.iX);
printf("iY =%d\r\n", event.iY);
printf("iPressure =%d\r\n", event.iPressure);
}
}
return 0;
}
#endif
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y +=netinput.o
obj-y +=touchscreen.o
obj-y +=input_manager.o
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;
}
注意:该代码不通过makefile编译,而是直接通过arm-linux-gnueabihf-gcc client.c -o all_client命令编译
#include /* See NOTES */
#include
#include
#include
#include
#include
#include
#include
#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 \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;
}
这里很明显可以看到只编译test.c
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y +=test.o
注意LDFLAGS 设置链接库,需要线程库和触摸屏库支持,其中-lts要求在指定路径下寻找,我的tslib交叉编译在/home/alexius/Downloads/tslib-1.21/install文件夹下。故LDFLAGS设置如下:
LDFLAGS := -L/home/alexius/Downloads/tslib-1.21/install/lib -lts -lpthread
#指定交叉编译工具链
COSS_COMPLE ?=arm-linux-gnueabihf-
AS = $(COSS_COMPLE)as
LD = $(COSS_COMPLE)ld
CC = $(COSS_COMPLE)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导出的变量是给子目录下的Makefile使用的
export AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP
# 编译器在编译时的参数设置
CFLAGS := -Wall -O2 -g -DDEBUG
# 添加头文件路径,不添加的话include目录下的头文件编译时找不到
CFLAGS += -I $(shell pwd)/include
# 链接器的链接参数设置,链接库
LDFLAGS := -L/home/alexius/Downloads/tslib-1.21/install/lib -lts -lpthread#触摸屏库链接
export CFLAGS LDFLAGS
TOPDIR := $(shell pwd)
export TOPDIR
# 定义将来编译生成的可执行程序的名字
TARGET := all_test
# 添加项目中所有用到的源文件,有顶层目录下的.c文件,和子文件夹
# 添加顶层目录下的.c文件
#obj-y += main.o
# 添加顶层目录下的子文件夹(注意目录名后面加一个/)
#obj-y += main.o
obj-y += input/
obj-y += uiontest/
# 第一个目标
all : start_recursive_build $(TARGET)
@echo $(TARGET) has been built!
# 处理第一个依赖,**转到 Makefile.build 执行**
start_recursive_build:
make -C ./ -f $(TOPDIR)/Makefile.build
# 处理最终目标,把前期处理得出的 built-in.o 用上
$(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)
# 将__build定义为伪目标
PHONY := __build
__build:
# 这里初值为空,下面引入Makefile文件后会被覆盖
obj-y :=
subdir-y :=
# 包含同级目录的Makefile
include Makefile
# 从obj-y变量中,将"/"结尾的字符串提取出来,也就是包含的子文件夹目录
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y += $(__subdir-y)
# 将subdir-y变量中的字符串依次赋值给f变量,形成新的$(f)/built-in.o字符串
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o)
# 筛选出obj-y中不以"/"结尾的字符串,也就是普通文件,一般是.o结尾
cur_objs := $(filter-out %/, $(obj-y))
# 为每个.o文件生成.d文件
# 注意.$(f).d是隐藏文件,需要ls -a查看
dep_files := $(foreach f,$(cur_objs),.$(f).d)
dep_files := $(wildcard $(dep_files))
# 如果.d文件不是空,则将.d文件都包含进来
ifneq ($(dep_files),)
include $(dep_files)
endif
PHONY += $(subdir-y)
# __build是Makefile的目标
__build : $(subdir-y) built-in.o
# 依次跳转到子目录中,执行Makefile.build文件
$(subdir-y):
make -C $@ -f $(TOPDIR)/Makefile.build
# 生成当前目录的built-in.o,依赖当前目录的.o文件和子目录下的built-in.o文件
built-in.o : $(cur_objs) $(subdir_objs)
$(LD) -r -o $@ $^
# dep_file变量是用来生成.d文件的
dep_file = [email protected]
# Makefile中的规则,把.c文件编译成.o文件
%.o : %.c
$(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $<
# 重新定义 .PHONY的依赖
.PHONY : $(PHONY)
此时编译client.c
先查开发板ip
运行测试程序
再运行clien程序
此时滑动屏幕,显示如下:
采用tslib-1.21.tar.bz2,步骤如下:
#ubuntu 工具安装
sudo apt-get install autoconf
sudo apt-get install automake
sudo apt-get install libtool
#git下载
git clone https://github.com/libts/tslib
#加入文件夹
cd tslib/
mkdir install
./autogen.sh
./configure --host=arm-linux-gnueabihf --prefix=$(pwd)/install
make //编译
sudo make install //安装
交叉编译后的文件如下:
将install文件夹拷贝到IMX6ull开发板上,并重命名为arm-tslib。这里不建议向正点一样直接将lib下文件拷贝到开发板lib下,因为做其他类似移植时,存在使用同一个库但不同版本的问题。如移植wpa_supplicant和mqtt时候存在两个openssl库冲突问题,故移植直接打包过去就好,省时还清晰明了。
由于是整个打包到开发板,所以直接在开发板上把包里的库和可执行程序告诉profile环境就行,执行 vi /etc/profile ,添加如下:
#tslib
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_TSDEVICE=/dev/input/event1
export TSLIB_ROOT=/arm-tslib
export TSLIB_CONFFILE=$TSLIB_ROOT/etc/ts.conf
export TSLIB_PLUGINDIR=$TSLIB_ROOT/lib/ts
export TSLIB_CALIBFILE=/etc/pointercal #TSLIB_CALIBFILE指定了触摸屏的校准文件路径
#export LD_PRELOAD=$TSLIB_ROOT/lib/libts.so
export PATH=$PATH:$TSLIB_ROOT/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$TSLIB_ROOT/lib
#再次激活环境
source /etc/profile