量产工具——输入系统(学习课程来源百问网后附视频链接)

目录

一、数据结构抽象

1.抽象出数据类型

2.抽象出设备类型

二、触摸屏编程

1.实现抽象出来的设备类型结构体

2.创建实现该结构体所需的函数

2.1触摸屏的初始化函数

2.2触摸屏的退出函数

2.3触摸屏的事件类型获取函数  

3.单元测试

三、网络输入编程

1.实现抽象出来的结构体

2.单元测试

四、输入管理

1.框架

2.实现

1.注册设备

2.初始化输入设备

3.获取输入数据

3.单元测试

五、错误总结

课程链接:


一、数据结构抽象

1.抽象出数据类型

一、你需要有个数据类型,用来辨别他是什么数据类型(网络数据或者触摸屏数据)

二、对于触摸屏数据,需要x坐标和y坐标,对于点击事件,还需要一个压力数据

有时候我们还可以加上时间

三、对于网络数据他是一个字符串

typedef struct InputEvent
{
	struct timeval time;
	int type;
	int x;
	int y;
	int pressure;
	char str[1024];
}InputEvent, *PInputEvent;

2.抽象出设备类型

1.提供一个名字,判断是哪种设备

2.输入设备需要提供一个函数,用来获取数据,将获取到的数据保存到上面的数据结构体中

3.初始化设备函数,用来打开设备节点

4.有初始化,就有退出函数

5.输入设备有多个,需要使用链表将这些设备链在一起

typedef struct InputDevice
{
	char *name;
	int (*GetInputEvent)(PInputEvent pInputEvent);
	int (*InitDevice)(void);
	int (*ExitDevice)(void);
	struct InputDevice *ptnext;
}InputDevice, *PInputDevice;

二、触摸屏编程

1.实现抽象出来的设备类型结构体

2.创建实现该结构体所需的函数

2.1触摸屏的初始化函数

struct tsdev *g_ts;
static int TouchScreenInitDevice(void)
{
	g_ts = ts_setup(NULL, 0);
	if (!g_ts)
	{
		printf("ts_setup err\n");
		return -1;
	}
	return 0;
}

2.2触摸屏的退出函数

static int TouchScreenExitDevice(void)
{
	ts_close(g_ts);
	return 0;
}

2.3触摸屏的事件类型获取函数  

这个读取函数中,需要读取到的数据结构体转换成我们抽象出来的数据结构体类型

这个原用来存储数据的结构体

static int TouchScreenGetInputEvent(PInputEvent ptInputEvent)
{
	struct ts_sample samp;
	int ret;

	ret = ts_read(g_ts, &samp, 1);

	if(ret != 1)
		return -1;

	ptInputEvent->type = INPUT_TYPE_TOUCH;
	ptInputEvent->x = samp.x;
	ptInputEvent->y = samp.y;
	ptInputEvent->pressure = samp.pressure;
	ptInputEvent.time = samp.tv;

	return 0;
}

3.单元测试

int main(int argc, char **argv)
{
	int ret;
	InputEvent event;
	g_tTouchScreenDev.InitDevice();
	while(1)
	{
		ret = g_tTouchScreenDev.GetInputEvent(&event);
		if(ret)
		{
			printf("GetInputEvent error\n");
		}
		else
		{
			printf("type : %d\n",event.type);
			printf("x : %d\n",event.x);
			printf("y : %d\n",event.y);
			printf("pressure : %d\n",event.pressure);
		}
	}
	return 0;
}

三、网络输入编程

1.实现抽象出来的结构体

2.单元测试

需要建立一个客户端给服务器发送消息。

#define SERVER_PORT 8888

int main(int argc, char **argv)
{
	int iSocketClient;
	struct sockaddr_in tSocketServerAddr;
	
	int iRet;
	unsigned char ucSendBuf[1000];
	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);
	
	iAddrLen = sizeof(struct sockaddr);
	iSendLen = sendto(iSocketClient, argv[2], strlen(argv[2]), 0,
			                      (const struct sockaddr *)&tSocketServerAddr, iAddrLen);

	close(iSocketClient);

	
	return 0;
}

在调试的过程中遇到段错误,原因是我在客户端的最后没有加上close()。

四、输入管理

引入输入管理的作用是同时从多个设备输入

1.框架

2.实现

1.注册设备

在管理文件中,首先是为下层提供了一个注册函数

下层可以通过调用这个方法将自己注册进链表中

最后通过InputInit可以管理设备的注册

void InputInit(void)
{
	extern void NetInputDevRegister();
	NetInputDevRegister();
	extern void TouchScreenDevRegister();
	TouchScreenDevRegister();
}

2.初始化输入设备

从链表中将所有设备取出来,调用它们的InitDevic()函数初始化硬件,并且为它创建一个线程

void InputDeviceInit(void)
{
	int ret;
	pthread_t tid;
	PInputDevice ptTmp = g_InputDevs;
	while (ptTmp)
	{
		ret = ptTmp->InitDevice();

		if(!ret)
		{
			ret = pthread_create(&tid, NULL, input_thread_func, ptTmp);
		}
	}
}

线程的功能函数是将获取来的数据存入环形缓冲区

static void *input_thread_func (void *data)
{
	PInputDevice tInputDev = (PInputDevice)data;
	PInputEvent tEvent;
	int ret;
	
	while (1)
	{
		ret = tInputDev->GetInputEvent(&tEvent);

		if(!ret)
		{
			pthread_mutex_lock(&g_tMutex);
			PutEventBuff(&tEvent);
			pthread_cond_signal(&g_tConVar);
			pthread_mutex_unlock(&g_tMutex);
		}
	}

	return NULL;
}

3.获取输入数据

这部分需要用到环形缓冲区,不了解可以先看:

环形缓冲区-CSDN博客

上层的应用程序通过调用GetInputEvent()函数来获取数据

从环形缓冲区里获得数据

int GetInputEvent(PInputEvent pINputEvent)
{
	int ret;
	InputEvent tEvent;
	pthread_mutex_lock(&g_tMutex);
	if(GetEventBuff(&tEvent))
	{
		pthread_mutex_unlock(&g_tMutex);
		return 0;
	}
	else
	{
		pthread_cond_wait(&g_tConVar, &g_tMutex);
		if(GetEventBuff(&tEvent))
		{
			ret = 0;
		}
		else
		{
			ret = -1;
		}
		pthread_mutex_unlock(&g_tMutex);
	}
	return ret;
}

3.单元测试

1.调用初始化函数

2.调用获取输入数据函数

3.判断输入数据类型,选择输出格式

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

五、错误总结

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

上述代码中,在完成一次线程创建后,我将

ptTmp = ptTmp->ptNext

写成

g_InputDevs= ptTmp->ptNext

导致的就是网络创建和绑定失败。

课程链接:

3-8_输入系统_输入管理单元测试_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1it4y1Q75z?p=14&vd_source=3a9afee9fda50350a1c881b4325e007d

  • 20
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值