【OrangePi Zero2 智能家居】代码优化

一、设备类节点直接通过文件配置
二、接收处理代码重新实现

代码优化

上面设备类的代码都是重复设备信息配置, 因此选择非常的冗余,其实这些信息完全可以利用配置文件
进行配置,这样就不需要如此多的设备类节点代码, 也方便后期的添加维护。

一、设备类节点直接通过文件配置

  1. 什么是.ini文件
    ini文件通常以纯文本形式存在,并且包含了一个或多个节(sections)以及每个节下的键值对(keyvalue pairs)。这些键值对用来指定应用程序的各种设置。

比如Linux系统里就有非常多这类格式的文件,如Linux下的打印机服务程序启动配置文件/lib/systemd/system/cups.service:

[Unit]
Description=CUPS Scheduler
Documentation=man:cupsd(8)
After=network.target nss-user-lookup.target nslcd.service
Requires=cups.socket

[Service]
ExecStart=/usr/sbin/cupsd -l
Type=notify
Restart=on-failure

[Install]
Also=cups.socket cups.path
WantedBy=printer.target multi-user.target
  1. inih解析库介绍
    inih是一个轻量级的C库,用于解析INI格式的配置文件。这个库由Ben Hoyt开发,并在GitHub上提供源
    代码(https://github.com/benhoyt/inih)。 inih 库的设计目标是简单易用,同时保持最小的依赖性。

以下是关于inih库的一些特点:

跨平台:inih库是跨平台的,可以在多种操作系统和编译器环境下使用。
体积小:inih库只有几个C文件,非常适合嵌入到其他项目中。
可定制:用户可以通过回调函数来处理读取到的键值对,使得处理方式非常灵活。
易于集成:只需要将ini.c和ini.h两个文件添加到你的项目中即可开始使用。
支持注释:inih库可以正确地处理以分号或哈希字符开头的行作为注释。
错误处理:如果在解析过程中遇到错误,ini_parse()函数会返回一个负数。
要使用inih库,你需要在你的代码中包含ini.h头文件,并调用ini_parse()函数来解析INI文件。ini_parse()函数接受三个参数:要解析的文件名、一个回调函数以及一个用户数据指针。每当找到一个新的键值对时,都会调用回调函数。

例如,以下是一个简单的回调函数示例:

static int handler(void* user, const char* section, const char* name, const char* value)
{
	printf("Section: '%s', Name: '%s', Value: '%s'\n", section, name, value);
	return 1; /* 成功 */
}

然后,你可以像这样调用ini_parse()函数

int error = ini_parse("config.ini", handler, NULL);
if (error < 0) {
	printf("Can't load 'config.ini'\n");
	exit(1);
}

如果你需要更复杂的处理逻辑,你可以在回调函数中实现它。注意,inih库并不直接提供设置的持久化功能,因此你需要自己负责将修改后的设置写回INI文件

  1. 首先定义设备控制ini文件gdevice.ini
[lock]
key=0x44
gpio_pin=8
gpio_mode=OUTPUT
gpio_status=HIGH
check_face_status=1
voice_set_status=1

[beep]
key=0x45
gpio_pin=9
gpio_mode=OUTPUT
gpio_status=HIGH
check_face_status=0
voice_set_status=1

[BR led]
key=0x42
gpio_pin=5
gpio_mode=OUTPUT
gpio_status=HIGH
check_face_status=0
voice_set_status=0

[LV led]
key=0x41
gpio_pin=2
gpio_mode=OUTPUT
gpio_status=HIGH
check_face_status=0
voice_set_status=0

[fan]
key=0x43
gpio_pin=7
gpio_mode=OUTPUT
gpio_status=HIGH
check_face_status=0
voice_set_status=0
  1. 下载libinih1源代码:
apt source libinih1

会下载libinih1d源码, 将libinih-53目录中的ini.cini.h拷贝到项目工程中,同时移除设备类信息文件

pg@pg-Default-string:~/libinih-53$ cp ini.h ../smarthome/inc/
pg@pg-Default-string:~/libinih-53$ cp ini.c ../smarthome/src/
pg@pg-Default-string:~/smarthome$ rm -rf src/*_gdevice.c inc/*_gdevice.h

目录结构如下

pg@pg-Default-string:~/smarthome$ ls
3rd inc ini Makefile src
pg@pg-Default-string:~/smarthome$ tree -I 3rd
.
├── inc
│ ├── control.h
│ ├── face.h
│ ├── gdevice.h
│ ├── global.h
│ ├── ini.h
│ ├── msg_queue.h
│ ├── myoled.h
│ ├── receive_interface.h
│ ├── smoke_interface.h
│ ├── socket.h
│ ├── socket_interface.h
│ ├── uartTool.h
│ └── voice_interface.h
├── ini
│ └── gdevice.ini
├── Makefile
└── src
	├── control.c
	├── face.c
	├── face.py
	├── gdeive.c
	├── ini.c
	├── main.c
	├── msg_queue.c
	├── myoled.c
	├── receive_interface.c
	├── smoke_interface.c
	├── socket.c
	├── socket_interface.c
	├── uartTool.c
	└── voice_interface.c

二、接收处理代码重新实现

修改receive_interface.c代码,实现利用libinih1解析库解析ini文件获取设备类节点

#include <pthread.h>
#include <mqueue.h>
#include <stdlib.h>
#include <stdio.h>

#include "wiringPi.h"
#include "control.h"
#include "receive_interface.h"
#include "msg_queue.h"
#include "global.h"
#include "face.h"
#include "myoled.h"
#include "ini.h"
#include "gdevice.h"

typedef struct {
	int msg_len;
	unsigned char *buffer;
	ctrl_info_t *ctrl_info;
}recv_msg_t;

static int oled_fd = -1;
static struct gdevice *pdevhead = NULL;

#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0

static int handler_gdevice(void* user, const char* section, const char* name, const char* value)
{
	struct gdevice *pdev = NULL;
	
	if (NULL == pdevhead)
	{
		pdevhead = (struct gdevice *)malloc(sizeof(struct gdevice));
		pdevhead->next = NULL;
		memset(pdevhead, 0, sizeof(struct gdevice));
		strcpy(pdevhead->dev_name, section);
	}
	else if (0 != strcmp(section, pdevhead->dev_name))
	{
		pdev = (struct gdevice *)malloc(sizeof(struct gdevice));
		memset(pdev, 0, sizeof(struct gdevice));
		strcpy(pdev->dev_name, section);
		pdev->next = pdevhead;
		pdevhead = pdev;
	}
	
	if (NULL != pdevhead)
	{
		if(MATCH(pdevhead->dev_name, "key"))
		{
			sscanf(value, "%x", &pdevhead->key);
			printf("%d|pdevhead->key=%x\n",__LINE__, pdevhead->key);
		}
		else if(MATCH(pdevhead->dev_name, "gpio_pin"))
		{
			pdevhead->gpio_pin = atoi(value);
		}
		else if(MATCH(pdevhead->dev_name, "gpio_mode"))
		{
			if(strcmp(value, "OUTPUT") == 0)
			{
				pdevhead->gpio_mode = OUTPUT; //OUTPUT
			}
			else if (strcmp(value, "INPUT") == 0)
			{
				pdevhead->gpio_mode = INPUT;
			}
		}
		else if(MATCH(pdevhead->dev_name, "gpio_status"))
		{
			if(strcmp(value, "LOW") == 0)
			{
				pdevhead->gpio_mode = LOW; //OUTPUT
			}
			else if (strcmp(value, "HIGH") == 0)
			{
				pdevhead->gpio_mode = HIGH;
			}
		}
		else if(MATCH(pdevhead->dev_name, "check_face_status"))
		{
			pdevhead->check_face_status = atoi(value);
		}
		else if(MATCH(pdevhead->dev_name, "voice_set_status"))
		{
			pdevhead->voice_set_status = atoi(value);
		}
	}
	return 1;
}

static int receive_init(void)
{
	if (ini_parse("/etc/gdevice.ini", handler_gdevice, NULL) < 0) {
		printf("Can't load 'gdevice.ini'\n");
		return 1;
	}
	
	oled_fd = myoled_init();
	face_init();
	
	return oled_fd;
}

static void receive_final(void)
{
	face_final();
	if(oled_fd != -1)
	{
		close(oled_fd);
		oled_fd = -1;
	}
}

static void *handle_device(void *arg)
{
	recv_msg_t *recv_msg = NULL;
	struct gdevice *cur_gdev = NULL;
	char success_or_failed[20] = "success";
	int ret = -1;
	pthread_t tid = -1;
	int smoke_status = 0;
	double face_result = 0.0;
	
	pthread_detach(pthread_self());
	//do something
	if (NULL != arg)
	{
		recv_msg = (recv_msg_t *)arg;
		printf("recv_msg->msg_len = %d\n", recv_msg->msg_len);
		printf("%s|%s|%d:hanle 0x%x, 0x%x,0x%x, 0x%x, 0x%x,0x%x\n", __FILE__, __func__, __LINE__, recv_msg->buffer[0], recv_msg->buffer[1], recv_msg->buffer[2], recv_msg->buffer[3], recv_msg->buffer[4],recv_msg->buffer[5]);
	}
	
	if (NULL != recv_msg && NULL != recv_msg->buffer)
	{
		cur_gdev = find_device_by_key(pdevhead, recv_msg->buffer[2]);
	}
	
	if (NULL != cur_gdev)
	{
		cur_gdev->gpio_status = recv_msg->buffer[3] == 0 ? LOW : HIGH;
		//special for lock
		printf("%s|%s|%d:cur_gdev->check_face_status=%d\n", __FILE__, __func__, __LINE__, cur_gdev->check_face_status);
		if (1 == cur_gdev->check_face_status)
		{
			face_result = face_category();
			printf("%s|%s|%d:face_result=%f\n", __FILE__, __func__, __LINE__, face_result);
			if (face_result > 0.6)
			{
				ret = set_gpio_gdevice_status(cur_gdev);
				recv_msg->buffer[2] = 0x47;
			}
			else
			{
				recv_msg->buffer[2] = 0x46;
				ret = -1;
			}
		}
		else if (0 == cur_gdev->check_face_status)
		{
			ret = set_gpio_gdevice_status(cur_gdev);
		}
		
		if(1 == cur_gdev->voice_set_status)
		{
			if (NULL != recv_msg && NULL != recv_msg->ctrl_info && NULL != recv_msg->ctrl_info->ctrl_phead)
			{
				struct control *pcontrol = recv_msg->ctrl_info->ctrl_phead;
				while (NULL != pcontrol)
				{
					if (strstr(pcontrol->control_name, "voice"))
					{
						if (0x45 == recv_msg->buffer[2] && 0 == recv_msg->buffer[3])
						{
							smoke_status = 1;
						}
						pthread_create(&tid, NULL, pcontrol->set, (void*)recv_msg->buffer);
						break;
					}
					pcontrol = pcontrol->next;
				}
			}
		}
		
		if (-1 == ret)
		{
			memset(success_or_failed, '\0', sizeof(success_or_failed));
			strncpy(success_or_failed, "failed", 6);
		}
		
		//oled屏显示
		char oled_msg[512];
		memset(oled_msg, 0, sizeof(oled_msg));
		char *change_status = cur_gdev->gpio_status == LOW ? "Open" : "Close";
		sprintf(oled_msg, "%s %s %s!\n", change_status, cur_gdev->dev_name, success_or_failed);
		//special for smoke
		if(smoke_status == 1)
		{
			memset(oled_msg, 0, sizeof(oled_msg));
			strcpy(oled_msg, "A risk of fire!\n");
		}
		
		printf("oled_msg=%s\n", oled_msg);
		oled_show(oled_msg);
		
		//special for lock, close lock
		if (1 == cur_gdev->check_face_status && 0 == ret && face_result > 0.6)
		{
			sleep(5);
			cur_gdev->gpio_status = HIGH;
			set_gpio_gdevice_status(cur_gdev);
		}
	}
	pthread_exit(0);
}

static void* receive_get(void *arg)
{
	recv_msg_t *recv_msg = NULL;
	ssize_t read_len = -1;
	pthread_t tid = -1;
	char *buffer = NULL;
	struct mq_attr attr;
	
	if (NULL != arg)
	{
		recv_msg = (recv_msg_t *)malloc(sizeof(recv_msg_t));
		recv_msg->ctrl_info = (ctrl_info_t *)arg; //获取到mqd 和phead (struct control 链表的头结点)
		recv_msg->msg_len = -1;
		recv_msg->buffer = NULL;
	}
	else
	{
		pthread_exit(0);
	}
	
	if(mq_getattr(recv_msg->ctrl_info->mqd, &attr) == -1)
	{
		pthread_exit(0);
	}
	
	recv_msg->buffer = (unsigned char *)malloc(attr.mq_msgsize);
	buffer = (unsigned char *)malloc(attr.mq_msgsize);
	memset(recv_msg->buffer, 0, attr.mq_msgsize);
	memset(buffer, 0, attr.mq_msgsize);
	pthread_detach(pthread_self());
	struct timespec timeout = { .tv_sec = 5, .tv_nsec = 0 };
	while(1)
	{
		// read_len = mq_receive(recv_msg->ctrl_info->mqd, buffer, attr.mq_msgsize, NULL);
		read_len = mq_timedreceive(recv_msg->ctrl_info->mqd, buffer, attr.mq_msgsize, NULL, &timeout);
		printf("%s|%s|%d:send 0x%x, 0x%x,0x%x, 0x%x, 0x%x,0x%x\n", __FILE__, __func__, __LINE__, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4],buffer[5]);
		printf("%s|%s|%d:read_len=%ld\n", __FILE__, __func__, __LINE__, read_len);
	
		if (-1 == read_len)
		{
			if(errno == EAGAIN)
			{
				printf("queue is empyt\n");
			}
			else if (errno == ETIMEDOUT) {
				printf("timeout\n");
				continue;
			}
			else
			{
				break;
			}
		}
		else if(buffer[0] == 0xAA && buffer[1] == 0x55
			&& buffer[5] == 0xAA && buffer[4] == 0x55)
		{
			recv_msg->msg_len = read_len;
			memcpy(recv_msg->buffer, buffer, read_len);
			pthread_create(&(tid), NULL, handle_device, (void *)recv_msg);
		}
	}
	pthread_exit(0);
}

struct control receive_control = {
	.control_name = "receive",
	.init = receive_init,
	.final = receive_final,
	.get = receive_get,
	.set = NULL,
	.next = NULL
};

struct control *add_receive_to_ctrl_list(struct control *phead)
{//头插法
	return add_interface_to_ctrl_list(phead, &receive_control);
};
  • 15
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咖喱年糕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值