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

前言:

前面我们已经实现了显示系统,现在我们来实现输入系统,与显示系统类似,下面让我们一起来对输入系统进行学习搭建吧

目录

一、数据结构抽象

1. 数据本身

2. 设备本身:

3. input_manager.h

二、触摸屏编程 

touchscreen.c 

三、触摸屏单元测试 

1.touchscreen.c 

2.上机测试

四、网络编程 

netiput.c 

五、网络单元测试

1.netiput.c 

2.client.c

3.上机测试 

六、 输入系统的框架

1.框架思路:

 2.input_manager.c

 3.环形缓冲区

4.input_manager.c 

七、输入管理单元测试

1.input_test.c

 2.input下的Makefile

 3.unittest下的Makefile

4.顶层Makefile

5.上板测试 


、数据结构抽象

        对于每一个设备,每一个模块,都用一个结构体来表示它,以后就会很方便的替换这些模块,所以对于设备本身我们需要抽象出一个结构体,所以对于输入系统我们需要抽象出两个结构体,这两个结构分别是: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   2typedef 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 1int 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)nmSTRIP		= $(CROSS_COMPILE)strip
OBJCOPY		= $(CROSS_COMPILE)objcopy
OBJDUMP		= $(CROSS_COMPILE)objdumpexport AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMPCFLAGS := -Wall -O2 -g
CFLAGS += -I $(shell pwd)/includeLDFLAGS := -ltsexport CFLAGS LDFLAGSTOPDIR := $(shell pwd)
export TOPDIRTARGET := testobj-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 8888static 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;}elsereturn -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 1int 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 8888int 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 0iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));	if (-1 == iRet){printf("connect error!\n");return -1;}
#endifiAddrLen = 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)nmSTRIP		= $(CROSS_COMPILE)strip
OBJCOPY		= $(CROSS_COMPILE)objcopy
OBJDUMP		= $(CROSS_COMPILE)objdumpexport AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMPCFLAGS := -Wall -O2 -g
CFLAGS += -I $(shell pwd)/includeLDFLAGS := -lts -lpthreadexport CFLAGS LDFLAGSTOPDIR := $(shell pwd)
export TOPDIRTARGET := testobj-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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/211272.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Presto基础学习--学习笔记

1&#xff0c;Presto背景 2011年&#xff0c;FaceBook的数据仓库存储在少量大型hadoop/hdfs集群&#xff0c;在这之前&#xff0c;FaceBook的科学家和分析师一直靠hive进行数据分析&#xff0c;但hive使用MR作为底层计算框架&#xff0c;是专为批处理设计的&#xff0c;但是随…

亿胜盈科ATR2037 无限射频前端低噪声放大器

亿胜盈科ATR2037 是一款应用于无线通信射频前端&#xff0c;工作频段为 0.7 到 6GHz 的超低噪声放大器。 ATR2037 低噪声放大器采用先进的 GaAs pHEMT 工艺设计和制作&#xff0c;ATR2037 低噪声放大器在整个工作频段内可以获得非常好的射频性能超低噪声系数。 亿胜盈科ATR203…

abapgit 安装及使用

abapgit 需求 SA[ BASIS 版本 702 及以上 版本查看路径如下&#xff1a; 安装步骤如下&#xff1a; 1. 下载abapgit 独立版本 程序 链接如下&#xff1a;raw.githubusercontent.com/abapGit/build/main/zabapgit_standalone.prog.abap 2.安装开发版本 2.1 在线安装 前置条…

揭秘:软件测试中Web请求的完整流程!

在软件开发的过程中&#xff0c;测试是一个至关重要的环节。而在现代互联网应用中&#xff0c;Web请求是很常见的一个测试需求。本文将介绍Web请求的完整测试流程&#xff0c;帮助读者更好地理解软件测试的关键步骤。 一、测试准备阶段 在进行Web请求测试之前&#xff0c;测试团…

Could not resolve all files for configuration ‘:app:debugCompileClasspath‘.

修改前 修改后 maven {url https://developer.huawei.com/repo/}

Scrum敏捷开发流程及支撑工具

Scrum是一种敏捷开发框架&#xff0c;用于管理复杂的项目。以下这些步骤构成了Scrum敏捷开发流程的核心。通过不断迭代、灵活应对变化和持续反馈&#xff0c;Scrum框架帮助团队快速交付高质量的产品。 以下是Scrum敏捷开发流程的基本步骤&#xff1a; 产品Backlog创建&#xf…

idea通过remote远程调试云服务器

引用了第三方的包&#xff0c;调试是看不到运行流程&#xff0c;于是想到了idea的remote方法 -agentlib:jdwptransportdt_socket,servery,suspendn,address9002 写一个.sh文件并启动 nohup java -jar -agentlib:jdwptransportdt_socket,servery,suspendn,address9002 ./demo.j…

Nacos多数据源插件

Nacos从2.2.0版本开始,可通过SPI机制注入多数据源实现插件,并在引入对应数据源实现后,便可在Nacos启动时通过读取application.properties配置文件中spring.datasource.platform配置项选择加载对应多数据源插件.本文档详细介绍一个多数据源插件如何实现以及如何使其生效。 注意:…

MYSQL练题笔记-高级查询和连接-连续出现的数字

一、题目相关内容 1&#xff09;相关的表和题目 2&#xff09;帮助理解题目的示例&#xff0c;提供返回结果的格式 二、自己初步的理解 其实这一部分的题目很简单&#xff0c;但是没啥思路啊&#xff0c;怎么想都想不通&#xff0c;还是看题解吧&#xff0c;中等题就是中等题…

【虚拟机】Docker基础 【二】【数据卷和挂载本地目录】

2.2.数据卷 容器是隔离环境&#xff0c;容器内程序的文件、配置、运行时产生的容器都在容器内部&#xff0c;我们要读写容器内的文件非常不方便。大家思考几个问题&#xff1a; 如果要升级MySQL版本&#xff0c;需要销毁旧容器&#xff0c;那么数据岂不是跟着被销毁了&#x…

机器学习---线性回归算法

1、什么是回归&#xff1f; 从大量的函数结果和自变量反推回函数表达式的过程就是回归。线性回归是利用数理统计中回归分析来确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法。 2、一元线性回归 3、多元线性回归 如果回归分析中包括两个或两个以上的自变量&a…

详解前后端交互时PO,DTO,VO模型类的应用场景

前后端交互时的数据传输模型 前后端交互流程 前后端交互的流程: 前端与后端开发人员之间主要依据接口进行开发 前端通过Http协议请求后端服务提供的接口后端服务的控制层Controller接收前端的请求Contorller层调用Service层进行业务处理Service层调用Dao持久层对数据持久化 …

Android : AndroidStudio开发工具优化

1.开启 gradle 单独的守护进程 Windows: 进入目录 C:\Users\Administrator\.gradle 创建文件&#xff1a; gradle.properties # Project-wide Gradle settings. # IDE (e.g. Android Studio) users: # Settings specified in this file will override any Gradle s…

MySQL安全最佳实践指南(2024版)

MySQL以其可靠性和效率在各种可用的数据库系统中脱颖而出。然而&#xff0c;与任何保存有价值数据的技术一样&#xff0c;MySQL数据库也是网络罪犯有利可图的目标。 这使得MySQL的安全性不再仅是一种选择&#xff0c;而是一种必要。这份全面的指南将深入研究保护MySQL数据库的…

集成开发环境 PyCharm 的安装【侯小啾python基础领航计划 系列(二)】

集成开发环境PyCharm的安装【侯小啾python基础领航计划 系列(二)】 大家好,我是博主侯小啾, 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔…

AI - FlowField(流场寻路)

FlowField流场寻路&#xff0c;利用网格存储每个点对目标点的推力&#xff0c;网格上的单位根据对于推力进行移动。用于大量单位进行寻路对于同一目的地的寻路&#xff0c;常用于rts游戏等。 对应一张网格地图(图中黑块是不可行走区域) 生成热度图 计算所有网格对于目标点(…

Java零基础——docker篇

1.【熟悉】docker简介 1.1 什么是docker Docker是一个开源项目&#xff0c;诞生于2013年初&#xff0c;最初是dotCloud公司内部的一个业余项目。它基于Google公司推出的Go语言实现。项目后来加入了Linux基金会&#xff0c;遵从了Apache2.0协议&#xff0c;项目代码在GitHub上进…

iptables防火墙之SNAT与DNET

NAT 1.SNAT&#xff1a;让内网可以访问外网 2.DNAT&#xff1a;让外网可以访问到内网的机器 网关服务器&#xff0c;要开启路由功能 内核功能&#xff1a; sysctl -a 列出所有参数 内核参数&#xff0c;然后grep可以查看到默认的内核参数 内核参数配置文件 /etc/sysctl.…

TLS、对称/非对称加密、CA认证

1. SSL与TLS SSL/TLS是一种密码通信框架&#xff0c;他是世界上使用最广泛的密码通信方法。SSL/TLS综合运用了密码学中的对称密码&#xff0c;消息认证码&#xff0c;公钥密码&#xff0c;数字签名&#xff0c;伪随机数生成器等&#xff0c;可以说是密码学中的集大成者。 TLS…

【android开发-16】android中文件和sharedpreferences数据存储详解

1&#xff0c;文件读写方式的数据存储 下面是一个简单的示例&#xff0c;演示如何在Android中使用内部存储来保存和读取文件&#xff1a; 保存文件&#xff1a; try { String data "这是要保存的数据"; FileOutputStream fos openFileOutput("myFile"…