智能家居完結 -- 整體設計

系統框圖

前情提要:

智能家居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_createint 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}; // 初始化 bufferif (-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 ,行號 -  138pthread_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 ,行號 -  138pthread_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 INPUTstatic 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;  // 報警開關 -- 默認設置為不開 -- 0ssize_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(); // 初始化oledface_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 somethingif (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__);// 配置OLEDchar 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;}elsepthread_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-gccSRC := $(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-gnuOBJ := $(subst src/,obj/,$(SRC:.c=.o))TARGET=obj/smarthomeCFLAGS := $(foreach item, $(INC),-I$(item)) # -I./inc -I./3rd/usr/local/includeLIBS_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/libsLIBS := -lwiringPi -lpython3.10 -pthread -lexpat -lz -lcryptobj/%.o:src/%.cmkdir -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/orangepicompile : $(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,來訪問阿里云的接口

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/16456.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/16456.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/16456.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【MySQL】聊聊count的相關操作

在平時的操作中&#xff0c;經常使用count進行操作&#xff0c;計算統計的數據。那么具體的原理是如何的&#xff1f;為什么有時候執行count很慢。 count的實現方式 select count(*) from student;對于MyISAM引擎來說&#xff0c;會把一個表的總行數存儲在磁盤上&#xff0c;…

Linux下Vision Mamba環境配置+多CUDA版本切換

上篇文章大致講了下Vision Mamba的相關知識&#xff0c;網上關于Vision Mamba的配置博客太多&#xff0c;筆者主要用來整合下。 筆者在Win10和Linux下分別嘗試配置相關環境。 Win10下配置 失敗 \textcolor{red}{失敗} 失敗&#xff0c;最后出現的問題如下&#xff1a; https://…

基于物聯網架構的電子小票服務系統

1.電子小票物聯網架構 采用感知層、網絡層和應用層的3層物聯網體系架構模型&#xff0c;電子小票物聯網的架構見圖1。 圖1 電子小票物聯網架構 感知層的小票智能硬件能夠取代傳統的小票打印機&#xff0c;在不改變商家原有收銀系統的前提下&#xff0c;采集收音機待打印的購物…

react中的數據驅動視圖,useState()的使用

前端開發如今有一個很重要的思想就是數據驅動視圖&#xff0c;數據發生變化使ui發生變化&#xff0c;比如一個變量count&#xff0c;為0顯示三個按鈕&#xff0c;為1顯示一個按鈕&#xff0c;為2顯示兩個按鈕。這就是一個簡單的數據驅動視圖。 import { useState } from reactf…

修改 ant design tour 漫游式導航的彈窗邊框樣式

一 說明 應項目要求&#xff0c;調整ant design tour 彈窗邊框的樣式。tour 原本樣式是有遮罩層&#xff0c;因此沒有邊框看起來也不突兀。原圖如下&#xff1a; 但是UI設計是取消遮罩層&#xff0c;并設置邊框樣式。當 取消 了遮罩層&#xff0c;沒有設置邊框樣式的圖片如下&a…

python考試成績管理與分析:從列表到方差

新書上架~&#x1f447;全國包郵奧~ python實用小工具開發教程http://pythontoolsteach.com/3 歡迎關注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目錄 一、考試成績的輸入與列表管理 二、成績的總分與平均成績計算 三、成績方差的計算 四、成…

雙指針用法練習題(2024/5/26)

1三數之和 給你一個整數數組 nums &#xff0c;判斷是否存在三元組 [nums[i], nums[j], nums[k]] 滿足 i ! j、i ! k 且 j ! k &#xff0c;同時還滿足 nums[i] nums[j] nums[k] 0 。請 你返回所有和為 0 且不重復的三元組。 注意&#xff1a;答案中不可以包含重復的三元…

人工智能場景下的網絡負載均衡技術

AI技術驅動智能應用井噴&#xff0c;智能算力增速遠超通用算力。IDC預測&#xff0c;未來五年&#xff0c;我國智能算力規模年復合增長率將超50%&#xff0c;開啟數據中心算力新紀元。隨著需求激增&#xff0c;數據中心或智算網絡亟需擴容、增速、減時延&#xff0c;確保網絡穩…

rockylinux 利用nexus 搭建私服yum倉庫

簡單說下為啥弄這個私服&#xff0c;因為自己要學習一些東西&#xff0c;比如新版的k8s等&#xff0c;其中會涉及到一些yum的安裝&#xff0c;為了防止因網絡問題導致yum安裝失敗&#xff0c;和重復下載&#xff0c;所以弄個私服&#xff0c;當然也有為了意外保障的想法&#x…

【實戰JVM】-基礎篇-01-JVM通識-字節碼詳解

【實戰JVM】-基礎篇-01-JVM通識-字節碼詳解-類的聲明周期-加載器 1 初識JVM1.1 什么是JVM1.2 JVM的功能1.2.1 即時編譯 1.3 常見JVM 2 字節碼文件詳解2.1 Java虛擬機的組成2.2 字節碼文件的組成2.2.1 正確打開字節碼文件2.2.2 字節碼組成2.2.3 基礎信息2.2.3.1 魔數2.2.3.1 主副…

【C++】右值引用 移動語義

目錄 前言一、右值引用與移動語義1.1 左值引用和右值引用1.2 右值引用使用場景和意義1.3 右值引用引用左值及其一些更深入的使用場景分析1.3.1 完美轉發 二、新的類功能三、可變參數模板 前言 本篇文章我們繼續來聊聊C11新增的一些語法——右值引用&#xff0c;我們在之前就已…

進程間通信的方式中,socket和消息隊列的區別

進程間通信的方式中&#xff0c;socket和消息隊列的區別 進程間通信方式中&#xff0c;socket和消息隊列的主要區別在于通信的方式和跨機通信的能力。 socket是通過網絡傳輸的方式來實現進程間通信&#xff0c;并且可以跨主機&#xff1b;而消息隊列是通過內核提供的緩沖區進…

Flutter 中的 AbsorbPointer 小部件:全面指南

Flutter 中的 AbsorbPointer 小部件&#xff1a;全面指南 在Flutter中&#xff0c;AbsorbPointer是一個特殊的小部件&#xff0c;用于吸收&#xff08;或“吞噬”&#xff09;所有傳遞到其子組件的指針事件&#xff08;如觸摸或鼠標點擊&#xff09;。這在某些情況下非常有用&…

民國漫畫雜志《時代漫畫》第22期.PDF

時代漫畫22.PDF: https://url03.ctfile.com/f/1779803-1248634856-2c7010?p9586 (訪問密碼: 9586) 《時代漫畫》的雜志在1934年誕生了&#xff0c;截止1937年6月戰爭來臨被迫停刊共發行了39期。 ps: 資源來源網絡!

Typescript高級: 深入理解Extract類型

概述 在TypeScript這一逐漸成為前端開發首選的靜態類型檢查語言中&#xff0c;類型系統提供了豐富的工具來幫助開發者編寫更加健壯和可維護的代碼。其中&#xff0c;Extract<T, U>是一個強大的內置實用類型&#xff0c;用于從一個聯合類型T中提取出屬于另一個類型U的那些…

AIGC 006-textual-inversion使用文本反轉實現個性化文本到圖像生成!

AIGC 006-textual-inversion使用文本反轉實現個性化文本到圖像生成&#xff01; 文章目錄 0 論文工作1 論文方法2 效果 0 論文工作 這篇論文 (An Image is Worth One Word: Personalizing Text-to-Image Generation using Textual Inversion) 提出了一種新穎的技術&#xff0c…

Modal.method() 不顯示頭部的問題

ant-design中的Modal組件有兩種用法&#xff1a; 第一種是用標簽&#xff1a;<a-modal></a-modal> 第二種是用Api&#xff1a;Modal.info、Modal.warning、Modal.confirm...... 一開始項目中這兩種用法是混用的&#xff0c;后面UI改造&#xff0c;需要統一樣式&…

一個程序員的牢獄生涯(37)任務

星期一 任 務 我走回大鐐面前后,把雙手抱著的衣服遞給大鐐,但我并沒有把手里的東西也遞給他。現在的大鐐坐著,我站著,這個時候要給大鐐的話,肯定能被身邊的棍子或六子看到,甚至被所有號子里的人都看到。因為此時,所有人的目光都盯著我手里的衣服,盯著我和大鐐看。 “鐐…

Shell字符串變量

目標 能夠使用字符串的3種方式 掌握Shell字符串拼接 掌握shell字符串截取的常用格式 能夠定義Shell索引數組和關聯數組 能夠使用內置命令alias,echo,read,exit,declare操作 掌握Shell的運算符操作 Shell字符串變量 介紹 字符串&#xff08;String&#xff09;就是一系…

使用LabVIEW時遇到VISA屬性錯誤 -1073807331的解決方案

在LabVIEW或VeriStand中使用VISA屬性時&#xff0c;可能會遇到錯誤 -1073807331。這一錯誤的具體描述如下&#xff1a; 解決方案 導致VISA屬性出現此錯誤的原因主要有以下四種&#xff1a; 屬性不被使用的串行總線支持 示例 A.1&#xff1a;Is Port Connected VISA屬性僅支持由…