系统框图
前情提要:
智能家居1 -- 实现语音模块-CSDN博客
智能家居2 -- 实现网络控制模块-CSDN博客
智能家居3 - 实现烟雾报警模块-CSDN博客
智能家居4 -- 添加接收消息的初步处理-CSDN博客
智能家居5 - 实现处理线程-CSDN博客
智能家居6 -- 配置 ini文件优化设备添加-CSDN博客
实现主要程序:
main.c
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <wiringPi.h>
#include "control.h"
#include "mq_queue.h"
#include "voice_interface.h"
#include "socket_interface.h"
#include "smoke_interface.h"
#include "receive_interface.h"
#include "global.h"
// msg_queue_create
int main() {
pthread_t thread_id;
struct control *control_phead = NULL;
struct control *pointer = NULL;
ctrl_info_t *ctrl_info = NULL;
ctrl_info = (ctrl_info_t *)malloc(sizeof(ctrl_info_t));
ctrl_info->ctrl_phead = NULL;
ctrl_info->mqd = -1;
int node_num = 0; // 统计节点数
if(-1 == wiringPiSetup())// 初始化 wiringPi 库
{
perror("wiringPi Init");
return -1;
}
// 创建消息队列
ctrl_info->mqd = msg_queue_create();
if(-1 == ctrl_info->mqd)// 创建消息队列失败
{
printf("%s|%s|%d, mqd= %d\n",__FILE__,__func__,__LINE__,ctrl_info->mqd);
return -1;
}
// 头插法插入 , so 头一直在变化
ctrl_info->ctrl_phead = add_voice_to_ctrl_list(ctrl_info->ctrl_phead);
ctrl_info->ctrl_phead = add_tcpsocket_to_ctrl_list(ctrl_info->ctrl_phead);
ctrl_info->ctrl_phead = add_smoke_to_ctrl_list(ctrl_info->ctrl_phead);
ctrl_info->ctrl_phead = add_receive_to_ctrl_list(ctrl_info->ctrl_phead);
pointer = ctrl_info->ctrl_phead;
while(NULL!=pointer) // 对所有控制结构体初始化,并且统计节点数
{
if(NULL != pointer->init)
{
printf("%s|%s|%d control_name = %s\n",__FILE__,__func__,__LINE__,pointer->control_name);
pointer->init();
}
pointer = pointer->next;
node_num++; // 统计节点数
}
// 根据节点的总数 --> 创建对应数目的线程
pthread_t *tid = (pthread_t *)malloc(sizeof(int) *node_num);
pointer = ctrl_info->ctrl_phead;
for(int i=0;i<node_num;++i)//遍历所有节点
{
if(NULL != pointer->get){
printf("%s|%s|%d control_name = %s\n",__FILE__,__func__,__LINE__,pointer->control_name);
pthread_create(&tid[i],NULL,(void *)pointer->get,(void *)ctrl_info); // 传入这个结构体参数,方便同时调用多组线程里面的API
}
pointer = pointer->next;
}
for(int i=0;i<node_num;++i)
{
pthread_join(tid[i],NULL);
}
for(int i=0;i<node_num;++i)
{
if(NULL != pointer->final)
pointer->final(); // 接打开的使用接口关闭
pointer = pointer->next;
}
msq_queue_final(ctrl_info->mqd);
if(NULL != ctrl_info)
free(ctrl_info); // 这个是malloc 堆区申请的内存 --> 需要手动的释放
if(NULL != tid)
free(tid);
return 0;
}
语言控制模块 - voice_interface.c
#if 0
struct control
{
char control_name[128]; //监听模块名称
int (*init)(void); //初始化函数
void (*final)(void);//结束释放函数
void *(*get)(void *arg);//监听函数,如语音监听
void *(*set)(void *arg); //设置函数,如语音播报
struct control *next;
};
#endif
#include <pthread.h>
#include <stdio.h>
#include "voice_interface.h"
#include "mq_queue.h"
#include "uartTool.h"
#include "global.h"
static int serial_fd = -1; // static 这个 变量只在当前文件有效
static int voice_init(void )
{
serial_fd = myserialOpen(SERIAL_DEV,BAUD); // 初始化并且打开串口
printf("%s|%s|%d serial_fd = %d\n",__FILE__,__func__,__LINE__,serial_fd);
return serial_fd;
}
static void voice_final(void)
{
if(-1 != serial_fd) // 打开串口成功
{
close(serial_fd); // 关闭我们打开的串口
serial_fd = -1; // 复位
}
}
// 接收语言指令
static void* voice_get(void *arg)// mqd 通过arg 传参获得
{
int len = 0;
mqd_t mqd = -1;
ctrl_info_t * ctrl_info = NULL;
if(NULL != arg)
ctrl_info = (ctrl_info_t*)arg;
unsigned char buffer[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // 初始化 buffer
if (-1 == serial_fd)
{
//打开串口
serial_fd = voice_init();// 尝试打开串口
if (-1 == serial_fd){ //还是打开失败
printf("%s | %s | %d:open serial failed\n", __FILE__, __func__, __LINE__); // 三个宏的含义: 文件名 - main.c,函数名 - pget_voice ,行号 - 138
pthread_exit(0);
} // 串口打开失败 -->退出
}
mqd = ctrl_info->mqd;
if((mqd_t)-1 == mqd)
{
pthread_exit(0);
}
pthread_detach(pthread_self());// 与父线程分离
printf("%s thread start\n",__func__);
while (1)
{
len = serialGetstring(serial_fd, buffer); // 通过串口获得语言输入
printf("%s|%s|%d, 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:len = %d\n",__FILE__,__func__,__LINE__,len);
if (len > 0) // 判断是否 接到识别指令
{
if(buffer[0] == 0xAA && buffer[1] == 0x55
&&buffer[4]==0x55 && buffer[5]==0xAA)
{
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]);
send_msg(mqd,buffer,len); // 注意获取len长度不能使用strlen() --> 0x00 会识别为截止位-->只能读取到三个字节(但不是我们实际的截止位(0x55 0xAA ))
}
memset(buffer,0,sizeof(buffer)); // 复位buffer
}
}
pthread_exit(0);
}
// 语音播报
static void* voice_set(void *arg)
{
pthread_detach(pthread_self());// 与父线程分离
unsigned char *buffer = (unsigned char*)arg;
if (-1 == serial_fd)
{
//打开串口
serial_fd = voice_init();// 尝试打开串口
if (-1 == serial_fd){ //还是打开失败
printf("%s | %s | %d:open serial failed\n", __FILE__, __func__, __LINE__); // 三个宏的含义: 文件名 - main.c,函数名 - pget_voice ,行号 - 138
pthread_exit(0);
} // 串口打开失败 -->退出
}
if(NULL != buffer){ // 接收到数据
serialSendstring(serial_fd,buffer,6); // 向串口发送接收到的数据
// 语言模块识别到串口发送的数据后就,进行相应的语言输出
}
pthread_exit(0);
}
struct control voice_control ={
.control_name = "voice",
.init = voice_init,
.final = voice_final,
.get = voice_get,
.set = voice_set,
.next = NULL
};
struct control *add_voice_to_ctrl_list(struct control *phead)
{
//头插法实现 添加链表节点
return add_interface_to_ctrl_list(phead,&voice_control);
};
网络控制模块 - socket_interface.c
#include <pthread.h>
#include "socket_interface.h"
#include "control.h"
#include "socket.h"
#include "mq_queue.h"
#include "global.h"
#include <netinet/tcp.h> // 设置 tcp 心跳 的参数
static int s_fd = -1;
static int tcpsocket_init(void)
{
s_fd = socket_init(IPADDR,IPPORT);
//return s_fd;
return -1;
}
static void tcpsocket_final(void)
{
close(s_fd);
s_fd = -1;
}
static void* tcpsocket_get(void *arg)
{
int c_fd = -1;
unsigned char buffer[BUF_SIZE];
int ret = -1;
struct sockaddr_in c_addr;
mqd_t mqd = -1;
ctrl_info_t * ctrl_info = NULL;
int keepalive = 1; // 开启TCP_KEEPALIVE选项
int keepidle = 10; // 设置探测时间间隔为10秒
int keepinterval = 5; // 设置探测包发送间隔为5秒
int keepcount = 3; // 设置探测包发送次数为3次
pthread_detach(pthread_self()); // 和主线程(他的父线程)分离
printf("%s|%s|%d s_fd = %d\n", __FILE__, __func__, __LINE__, s_fd);
if(-1 == s_fd) // 判断是否初始化成功
{
s_fd = tcpsocket_init();
if(-1 == s_fd)
{
printf("tcpsocket_init error\n");
pthread_exit(0);
}
}
if(NULL != arg)
ctrl_info = (ctrl_info_t*)arg;
if(NULL != ctrl_info)
mqd = ctrl_info->mqd;
if((mqd_t)-1 == mqd)
{
pthread_exit(0);
}
memset(&c_addr, 0, sizeof(struct sockaddr_in));
int clen = sizeof(struct sockaddr_in);
printf("%s thread start\n", __func__);
while (1) // 一直等待接收
{
c_fd = accept(s_fd, (struct sockaddr *)&c_addr, &clen); // 获得新的客户端 描述符
if (c_fd == -1)
{
continue;
}
ret = setsockopt(c_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive,sizeof(keepalive));
if(-1 == ret){
perror("setsockopt");
break;
}
ret = setsockopt(c_fd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&keepidle, sizeof(keepidle));
if(-1 == ret){
perror("setsockopt");
break;
}
ret = setsockopt(c_fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepinterval,
sizeof(keepinterval));
if(-1 == ret){
perror("setsockopt");
break;
}
ret = setsockopt(c_fd, IPPROTO_TCP, TCP_KEEPCNT, &keepcount,
sizeof(keepcount));
if(-1 == ret){
perror("setsockopt");
break;
}
// 打印调试信息
printf("%s | %s | %d: Access a connection from %s:%d\n", __FILE__, __func__, __LINE__, inet_ntoa(c_addr.sin_addr), ntohs(c_addr.sin_port));
while (1)
{
memset(buffer, 0, BUF_SIZE);
ret = recv(c_fd, buffer, BUF_SIZE, 0); // 等待接收
// 将接收到数据打印出来
printf("%s|%s|%d, 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]);
if (ret > 0)
{
if(buffer[0] == 0xAA && buffer[1] == 0x55
&&buffer[4]==0x55 && buffer[5]==0xAA)
{
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]);
send_msg(mqd,buffer,ret);
}
}
else if (0 == ret || -1 == ret) // 没读到,or 读到空
{
break;
}
}
}
pthread_exit(0);
}
struct control tcpsocket_control ={
.control_name = "tcpsocket",
.init = tcpsocket_init,
.final = tcpsocket_final,
.get = tcpsocket_get,
.set = NULL, //不需要实现 设置
.next = NULL
};
struct control *add_tcpsocket_to_ctrl_list(struct control *phead)
{
//头插法实现 添加链表节点
return add_interface_to_ctrl_list(phead,&tcpsocket_control);
};
烟雾报警模块 - smoke_interfac.c
#include <pthread.h>
#include <wiringPi.h>
#include <stdio.h>
#include "smoke_interface.h"
#include "control.h"
#include "mq_queue.h"
#include "global.h"
#include <netinet/tcp.h> // 设置 tcp 心跳 的参数
#define SMOKE_PIN 6 // 烟雾报警模块接的引脚
#define SMOKE_MODE INPUT
static int s_fd = -1;
static int smoke_init(void)
{
printf("%s|%s|%d\n",__FILE__,__func__,__LINE__);
pinMode(SMOKE_PIN, SMOKE_MODE); // 引脚 和 模式配置
return 0;
}
static void smoke_final(void)
{
// do nothing
}
static void* smoke_get(void *arg)
{
// AA 55 45 00 55 AA --> 45 00 -->触发警报
int status = HIGH; //低电平有效 -- 默认设置为高电平
int switch_status = 0; // 报警开关 -- 默认设置为不开 -- 0
ssize_t byte_send = -1;
unsigned char buffer[6] = {0xAA,0x55,0x00,0x00,0x55,0xAA};
mqd_t mqd = -1;
ctrl_info_t * ctrl_info = NULL;
if(NULL != arg)
ctrl_info = (ctrl_info_t*)arg;
if(NULL != ctrl_info)
mqd = ctrl_info->mqd;
if((mqd_t)-1 == mqd)
{
pthread_exit(0);
}
pthread_detach(pthread_self()); // 父子线程分离
printf("%s thread start.\n",__func__);
while(1)
{
status = digitalRead(SMOKE_PIN); // 读取当前引脚状态
if(LOW == status) // 探测到烟雾 -- 发生报警
{
switch_status = 1; // 打开报警器开关
buffer[2] = 0x45;
buffer[3] = 0x00;// 低电平触发警报 --
//蜂鸣器是低电平触发 --> 我们这里把buffer 修改得与beep匹配,方便与他产生联系
printf("%s|%s|%d, 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]);
byte_send = mq_send(mqd, buffer, 6,0); // 向消息队列里面发送数据 -- 接收到后语言模块会识别播报 - 火灾警报
if (-1 == byte_send)
{
continue;
}
}
else if(HIGH == status && 1 == switch_status) // 未探测到烟雾,并且报警器开关还没关闭 -- 关闭报警器开关
{
switch_status = 0; // 关闭报警器开关
buffer[2] = 0x45;
buffer[3] = 0x01;//警报结束
printf("%s|%s|%d, 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]);
byte_send = mq_send(mqd, buffer, 6,0);
if (-1 == byte_send)
{
continue;
}
}
sleep(5);
}
pthread_exit(0); // 退出线程
}
struct control smoke_control ={
.control_name = "smoke",
.init = smoke_init,
.final = smoke_final,
.get = smoke_get,
.set = NULL, //不需要实现 设置
.next = NULL
};
struct control *add_smoke_to_ctrl_list(struct control *phead)
{
return add_interface_to_ctrl_list(phead,&smoke_control);
}
接收处理线程 - receive_interface.c
#include <pthread.h>
#include <mqueue.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <wiringPi.h>
#include "receive_interface.h"
#include "control.h"
#include "mq_queue.h"
#include "global.h"
#include "face.h"
#include "myoled.h"
//#include "lrled_gdevice.h"
#include "gdevice.h"
// #include "fan_gdevice.h"
// #include "bled_gdevice.h"
// #include "beep_gdevice.h"
// #include "lock_gdevice.h"
#include "ini.h"
#include "face.h"
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
/*
接收模块:
对接收到消息做出相应处理
包括 oled 人脸识别 语言播报 GPIO 引脚状态配置
*/
static int oled_fd = -1;
static struct gdevice *pdevhead = NULL;
typedef struct
{
int msg_len;
unsigned char *buffer;
ctrl_info_t *ctrl_info;
} recv_msg_t;
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));
memset(pdevhead, 0, sizeof(struct gdevice));
pdevhead->next = NULL;
strcpy(pdevhead->dev_name, section);
}
// printf("section = %s, name = %s, value = %s\n", section, name, value);
else if (0 != strcmp(section, pdevhead->dev_name)) // 当section对不上的时候,表示到了下一个设备
{
// 把新节点(设备)使用头插法插入
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); // 把value(string)的值 转为int类型 16进行格式 传递给 pdevhead->key)
printf("%d pdevhead->key = 0x%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;
}
else if (strcmp(value, "INPUT") == 0)
{
pdevhead->gpio_mode = INPUT;
}
else
{
printf("gpio_mode error\n");
}
}
else if (MATCH(pdevhead->dev_name, "gpio_status"))
{
if (strcmp(value, "LOW") == 0)
{
pdevhead->gpio_mode = LOW;
}
else if (strcmp(value, "HIGH") == 0)
{
pdevhead->gpio_mode = HIGH;
}
else
{
printf("gpio_status error\n");
}
}
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)
{
// pdevhead = add_lrled_to_gdevice_list(pdevhead); // 头插法加入 客厅灯
// pdevhead = add_bled_to_gdevice_list(pdevhead); // 加入卧室灯
// pdevhead = add_fan_to_gdevice_list(pdevhead); // 加入风扇
// pdevhead = add_beep_to_gdevice_list(pdevhead); // 蜂鸣器
// pdevhead = add_lock_to_gdevice_list(pdevhead); // 开锁
if (ini_parse("/etc/gdevice.ini", handler_gdevice, NULL) < 0) {
printf("Can't load 'gdevice.ini'\n");
return 1;
}
struct gdevice *pdev = NULL;
pdev = pdevhead;
while (pdev != NULL)
{
// printf("inside %d",__LINE__);
printf("dev_name:%s\n", pdev->dev_name);
printf("key:%x\n", pdev->key);
printf("gpio_pin:%d\n", pdev->gpio_pin);
printf("gpio_mode:%d\n", pdev->gpio_mode);
printf("gpio_status:%d\n", pdev->gpio_status);
printf("check_face_status:%d\n", pdev->check_face_status);
printf("voice_set_status:%d\n", pdev->voice_set_status);
pdev = pdev->next;
}
// 设备类链表添加
oled_fd = myoled_init(); // 初始化oled
face_init(); // 初始化人脸识别
return oled_fd;
}
static void receive_final(void)
{
face_final();
if (-1 != oled_fd)
{
close(oled_fd); // 关闭oled 打开的文件
oled_fd = -1; // 复位
}
}
// 处理设备 -- 比如打开灯 和风扇等
static void *handler_device(void *arg)
{
pthread_detach(pthread_self()); // 和主线程(他的父线程)分离
recv_msg_t *recv_msg = NULL;
struct gdevice *cur_gdev = NULL;
char success_or_failed[20] = "success";
pthread_t tid = -1;
int smoke_status = 0;
double face_result = 0.0; //存放人脸匹配度
int ret = -1;
if (NULL != arg) // 有参数
{
recv_msg = (recv_msg_t *)arg; // 获取参数
printf("recv_len = %d\n", recv_msg->msg_len);
printf("%s|%s|%d, handler: 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]);
}
// need to do something
if (NULL != recv_msg && NULL != recv_msg->buffer) // if 消息队列非空,并且buffer 里面接收到数据
{
// recv_msg->buffer[2] --> 第三位 用于存放设备类型
cur_gdev = find_device_by_key(pdevhead, recv_msg->buffer[2]);
printf("%s|%s|%d,find success buffer[2] = 0x%x \n", __FILE__, __func__, __LINE__, recv_msg->buffer[2]);
}
if (NULL != cur_gdev) // if 能找到的这设备 --> 设备存在
{
printf("%s|%s|%d, cur_gdev \n", __FILE__, __func__, __LINE__);
// BUFFER 的第四个参数 用于 存放开关状态 0 表示开, 1 表示关
cur_gdev->gpio_status = recv_msg->buffer[3] == 0 ? LOW : HIGH; // 获取状态存入cur_gdev中
//人脸识别
if(1 == cur_gdev->check_face_status){
face_result = face_status(); //得到人脸识别的匹配度
if(face_result > 0.6){ //匹配成功
ret = set_gpio_device_status(cur_gdev); // 设置电平 --> 开锁
recv_msg->buffer[2] = 0x47; //识别成功的语音播报
}
else{
recv_msg->buffer[2] = 0x46;
}
}
else if( 0 == cur_gdev->check_face_status){
// printf("%s|%s|%d,Set before set_gpio_device_status\n",__FILE__,__func__,__LINE__);
ret = set_gpio_device_status(cur_gdev); // 将获取到的状态真正赋值给引脚
// printf("%s|%s|%d, after set_gpio_device_status \n",__FILE__,__func__,__LINE__);
}
printf("%s|%s|%d, = %d\n", __FILE__, __func__, __LINE__,cur_gdev->voice_set_status);
// 需要语言播报
if (1 == cur_gdev->voice_set_status)
{
printf("%s|%s|%d,2\n", __FILE__, __func__, __LINE__);
if (NULL != recv_msg && NULL != recv_msg->ctrl_info && NULL != recv_msg->ctrl_info->ctrl_phead)
{
printf("%s|%s|%d,2\n", __FILE__, __func__, __LINE__);
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;
}
}
}
printf("%s|%s|%d,2\n", __FILE__, __func__, __LINE__);
if (-1 == ret) // 设置失败
{
printf("%s|%s|%d,2\n", __FILE__, __func__, __LINE__);
memset(success_or_failed, '\0', sizeof(success_or_failed));
strncpy(success_or_failed, "failed", 6);
}
printf("%s|%s|%d,2\n", __FILE__, __func__, __LINE__);
// 配置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);
if(smoke_status == 1)
{
memset(oled_msg, 0, sizeof(oled_msg));
sprintf(oled_msg, "A risk of fire!\n");
}
myoled_show(oled_msg);
//让门打开5s自动关闭
if(1 == cur_gdev->check_face_status && 0 == ret && face_result >0.6){
sleep(5); //开门5s后关门
cur_gdev->gpio_status = HIGH; //设置高电平(低电平有效)
ret = set_gpio_device_status(cur_gdev); //关门
}
}
pthread_exit(0);
}
static void *receive_get(void *arg) // 接收消息队列里面的 数据
{
printf("enter receive_get\n");
// 通过参数 初始化我们 定义的recv_msg_t 结构体
recv_msg_t *recv_msg = NULL;
unsigned char *buffer = NULL;
struct mq_attr attr;
pthread_t tid = -1;
ssize_t read_len = -1;
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 = 0;
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);
// mq_msgsize -- 每条消息的大小
memset(recv_msg->buffer, 0, attr.mq_msgsize); // 初始化
memset(buffer, 0, attr.mq_msgsize); // 初始化
pthread_detach(pthread_self()); // 和主线程(他的父线程)分离
while (1)
{
read_len = mq_receive(recv_msg->ctrl_info->mqd, buffer, attr.mq_msgsize, NULL);
printf("%s|%s|%d, recv: 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 empty\n");
}
else
{
break;
}
}
// 以下是接收到正常数据的情况
else if (buffer[0] == 0xAA && buffer[1] == 0x55 && buffer[4] == 0x55 && buffer[5] == 0xAA)
{
recv_msg->msg_len = read_len;
memcpy(recv_msg->buffer, buffer, read_len);
// 创建线程去 处理我们的接收到的信号
pthread_create(&tid, NULL, handler_device, (void *)recv_msg);
}
}
if (NULL != recv_msg)
free(recv_msg);
if (NULL != buffer)
free(buffer);
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);
};
编译运行
环境配置:
// 我们人脸识别开门模块调用了阿里云的sdk,请确保arm设上已经安装了对应SDK,和阿里云服务配置,请去这里安装指示配置(按照指示下载SDK,添加阿里云AccessKey)
人脸识别_身份验证识别_客流分析系统_人脸门禁闸机-阿里云 (aliyun.com)
编译
由于文件众多,我们采用Makefile,来编译
Makefile
CC := aarch64-linux-gnu-gcc
SRC := $(shell find src -name "*.c")
INC := ./inc \
./3rd/usr/local/include \
./3rd/usr/include \
./3rd/usr/include/python3.10 \
./3rd/usr/include/aarch64-linux-gnu/python3.10 \
./3rd/usr/include/aarch64-linux-gnu
OBJ := $(subst src/,obj/,$(SRC:.c=.o))
TARGET=obj/smarthome
CFLAGS := $(foreach item, $(INC),-I$(item)) # -I./inc -I./3rd/usr/local/include
LIBS_PATH := ./3rd/usr/local/lib \
./3rd/lib/aarch64-linux-gnu \
./3rd/usr/lib/aarch64-linux-gnu \
./3rd/usr/lib/python3.10 \
#L
LDFLAGS := $(foreach item, $(LIBS_PATH),-L$(item)) # -L./3rd/usr/local/libs
LIBS := -lwiringPi -lpython3.10 -pthread -lexpat -lz -lcrypt
obj/%.o:src/%.c
mkdir -p obj
$(CC) -o $@ -c $< $(CFLAGS)
$(TARGET) :$(OBJ)
$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) $(LIBS)
scp obj/smarthome ini/gdevice.ini orangepi@192.168.1.18:/home/orangepi
compile : $(TARGET)
clean:
rm $(TARGET) obj $(OBJ) -rf
debug:
echo $(CC)
echo $(SRC)
echo $(INC)
echo $(OBJ)
echo $(TARGET)
echo $(CFLAGS)
echo $(LDFLAGS)
echo $(LIBS)
.PHONY: clean compile debug
可以看到我的Makefile 里面添加了scp传送,请根据自己的派的ip进行修改
运行:
sudo -E ./smarthome
sudo -- 因为我们调用了wiringpi库来调节电平,需要访问到系统文件
-E 保持环境,即我们可以使用root用户里面配置的AccessKey,来访问阿里云的接口