Linux基础项目开发1:量产工具——输入系统(三)

简介: Linux基础项目开发1:量产工具——输入系统(三)

、数据结构抽象

       对于每一个设备,每一个模块,都用一个结构体来表示它,以后就会很方便的替换这些模块,所以对于设备本身我们需要抽象出一个结构体,所以对于输入系统我们需要抽象出两个结构体,这两个结构分别是: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 *)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行:网络事件

第14~21行:抽象出数据本身结构体InputEvent

      第14行:定义出一个时间

第24~30行:抽象出设备本身结构体InputDevice

第33行:用于输入系统管理,提供一个注册函数,下面的各个设备进行引用它

第34行:用注册函数进行引用

第35行:对于每个设备初始化它,并且创建线程

第36行:最上层的代码只要调用这个函数就可以得到这些设备的数据

二、触摸屏编程

设备结构体的实现如下结构体:使用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,
};
 
 
void TouchscreenRegister(void)
{
  RegisterInputDevice(&g_tTouchscreenDev);
}

第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行:关闭设备

void TouchscreenRegister(void)

第52~55行:将结构体g_tTouchscreenDev注册到上一层,上一层就是输入管理器,用注册函数进行引用

三、触摸屏单元测试

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,
};
 
 
void NetInputRegister(void)
{
  RegisterInputDevice(&g_tNetinputDev);
}
 

第29行:端口

第22行:获得的数据  

第28行:获得的数据保存到ucRecvBuf里面

static int NetinputGetInputEvent(PInputEvent ptInputEvent)

  第24~45行:获得输入事件

static int NetinputDeviceInit(void)

  第47~74行:初始化socket

static int NetinputDeviceExit(void)

第76~80行:关闭设备

void NetInputRegister(void)

第88~91行:将结构体g_tNetinputDev注册到上一层,上一层就是输入管理器,用注册函数进行引用

五、网络单元测试

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/

3.上机测试

六、 输入系统的框架

        如果只有一个输入设备,那么我们只需要写一个main函数即可,但是我们需要好几个设备输入,那么要想统一管理,那么就需要设计一个输入管理系统进行管理选择到底哪个设备进行输入。

       在输入管理器中我们需要初始化触摸屏,并且为触摸屏提供一个线程,初始化网络设备,为网络设备提供一个线程,上层应用程序提供一些函数就可以方便的得到各类的输入事件,线程的创建线程的管理都由输入管理器进行设置。

1.框架思路:

1.输入管理器input_manager实现的函数有:

       (1).InputInit  (2).IntpuDeviceInit    (3).GetInputEvent

2.输入管理器支持多个设备,这多个设备怎么管理起来呢?

       使用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)
{
  /* 无数据则休眠 */
 
  /* 返回数据 */
}
 
 
 

第7行:这一层要接受下一层传输上来的注册信息 ,所以要定义一个 g_InputDevs的链表头

g_InputDevs这个链表中存放设备。

void RegisterInputDevice(PInputDevice ptInputDev)

第9~13行:提供一个注册函数

void InputInit(void)

第16~25行:向上提供一个InputInit(void) 函数

       第19、20行:注册触摸屏设备

       第23、24行:注册网络设备

注意:其中extern是外部函数的意思

void IntpuDeviceInit(void)

第54~74行:对于每个设备初始化它,并且创建线程

       第57行:定义一个临时变量的线程id

       第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行:最重要的一个函数 ,最上层的代码只要调用这个函数就可以得到这些设备的数据

        无数据则休眠,有数据则返回数据

怎么避免数据丢失 ?

比如触摸屏,它会一下子上报很多数据

对于网络输入,也有可能同时又多个client发来数据

所以,不能使用单一的变量来保存数据,而是使用一个数组来保存数据

使用“环形缓冲区

3.环形缓冲区

环形缓冲区也是一个一维数组,并不是一个环形的数组

例:chat buf[5];

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

第14行:buffer数组的长度

第15、16行:设置读写

第9~10行:定义一个互斥锁,用于环形缓冲区的访问

第17行:定义一个buffer

static int isInputBufferFull(void)
 
static int isInputBufferEmpty(void)

第20~23行和25~28行:判断是空还是满

       第20行的函数是判断满的

       第25行的函数是判断空的

static void PutInputEventToBuffer(PInputEvent ptInputEvent)

第30~37行:往这个buffer数组里面存放数据

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

第16行:读到的输入事件存到event

第18行:调用InputInit进行初始化

第19行:调用IntpuDeviceInit从链表里面把每一个设备取出来

第34~40行:如果设备是触摸屏的话就把触点打印出来

第41~45行:如果设备是网络的话就把字符串打印出来

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


目录
相关文章
|
4月前
|
Ubuntu Linux Anolis
Linux系统禁用swap
本文介绍了在新版本Linux系统(如Ubuntu 20.04+、CentOS Stream、openEuler等)中禁用swap的两种方法。传统通过注释/etc/fstab中swap行的方式已失效,现需使用systemd管理swap.target服务或在/etc/fstab中添加noauto参数实现禁用。方法1通过屏蔽swap.target适用于新版系统,方法2通过修改fstab挂载选项更通用,兼容所有系统。
349 3
Linux系统禁用swap
|
4月前
|
安全 Linux Shell
四、Linux核心工具:Vim, 文件链接与SSH
要想在Linux世界里游刃有余,光会“走路”还不够,还得配上几样“高级装备”。首先是Vim编辑器,它像一把瑞士军刀,让你能在命令行里高效地修改文件。然后要懂“软硬链接”,软链接像个快捷方式,硬链接则是给文件起了个别名。最后,SSH是你的“传送门”,不仅能让你安全地远程登录服务器,还能用scp轻松传输文件,设置好密钥更能实现免-密登录,极大提升效率。
419 4
|
4月前
|
Linux
Linux系统修改网卡名为eth0、eth1
在Linux系统中,可通过修改GRUB配置和创建Udev规则或使用systemd链接文件,将网卡名改为`eth0`、`eth1`等传统命名方式,适用于多种发行版并支持多网卡配置。
690 3
|
Ubuntu Linux 网络安全
Linux系统初始化脚本
一款支持Rocky、CentOS、Ubuntu、Debian、openEuler等主流Linux发行版的系统初始化Shell脚本,涵盖网络配置、主机名设置、镜像源更换、安全加固等多项功能,适配单/双网卡环境,支持UEFI引导,提供多版本下载与持续更新。
457 0
Linux系统初始化脚本
|
4月前
|
Unix Linux 程序员
Linux文本搜索工具grep命令使用指南
以上就是对Linux环境下强大工具 `grep` 的基础到进阶功能介绍。它不仅能够执行简单文字查询任务还能够处理复杂文字处理任务,并且支持强大而灵活地正则表达规范来增加查询精度与效率。无论您是程序员、数据分析师还是系统管理员,在日常工作中熟练运用该命令都将极大提升您处理和分析数据效率。
357 16
|
4月前
|
安全 Linux iOS开发
SonarQube Server 2025 Release 5 (macOS, Linux, Windows) - 代码质量、安全与静态分析工具
SonarQube Server 2025 Release 5 (macOS, Linux, Windows) - 代码质量、安全与静态分析工具
239 0
SonarQube Server 2025 Release 5 (macOS, Linux, Windows) - 代码质量、安全与静态分析工具
|
4月前
|
安全 Linux Shell
Linux系统提权方式全面总结:从基础到高级攻防技术
本文全面总结Linux系统提权技术,涵盖权限体系、配置错误、漏洞利用、密码攻击等方法,帮助安全研究人员掌握攻防技术,提升系统防护能力。
397 1
|
4月前
|
Linux 应用服务中间件 Shell
二、Linux文本处理与文件操作核心命令
熟悉了Linux的基本“行走”后,就该拿起真正的“工具”干活了。用grep这个“放大镜”在文件里搜索内容,用find这个“探测器”在系统中寻找文件,再用tar把东西打包带走。最关键的是要学会使用管道符|,它像一条流水线,能把这些命令串联起来,让简单工具组合出强大的功能,比如 ps -ef | grep 'nginx' 就能快速找出nginx进程。
504 1
二、Linux文本处理与文件操作核心命令
|
4月前
|
Linux
linux命令—stat
`stat` 是 Linux 系统中用于查看文件或文件系统详细状态信息的命令。相比 `ls -l`,它提供更全面的信息,包括文件大小、权限、所有者、时间戳(最后访问、修改、状态变更时间)、inode 号、设备信息等。其常用选项包括 `-f` 查看文件系统状态、`-t` 以简洁格式输出、`-L` 跟踪符号链接,以及 `-c` 或 `--format` 自定义输出格式。通过这些选项,用户可以灵活获取所需信息,适用于系统调试、权限检查、磁盘管理等场景。
347 137
|
4月前
|
安全 Ubuntu Unix
一、初识 Linux 与基本命令
玩转Linux命令行,就像探索一座新城市。首先要熟悉它的“地图”,也就是/根目录下/etc(放配置)、/home(住家)这些核心区域。然后掌握几个“生存口令”:用ls看周围,cd去别处,mkdir建新房,cp/mv搬东西,再用cat或tail看文件内容。最后,别忘了随时按Tab键,它能帮你自动补全命令和路径,是提高效率的第一神器。
792 57