一、项目整体设计 二、项目代码的前期准备 三、实现语音监听接口 四、实现socket监听接口 五、实现烟雾报警监听接口 六、实现设备节点代码 七、实现接收消息处理接口

一、项目整体设计

整体的软件框架大致如下: 整个项目开启4个监听线程, 分别是:

语音监听线程:用于监听语音指令, 当有语音指令过来后, 通过消息队列的方式给消息处理线程发 送指令网络监听线程:用于监听网络指令,当有网络指令过来后, 通过消息队列的方式给消息处理线程发 送指令火灾检测线程:当存在煤气泄漏或者火灾闲情时, 发送警报指令给消息处理线程消息监听线程: 用于处理以上3个线程发过来的指令,并根据指令要求配置GPIO引脚状态,OLED 屏显示、语音播报,还有人脸识别开门 上述四个线程采用统一个对外接口接口,同时添加到监听链表中。

统一的监听模块接口如下:

struct control

{

char control_name[128]; //监听模块名称

int (*init)(void); //初始化函数

void (*final)(void);//结束释放函数

void *(*get)(void *arg);//监听函数,如语音监听

void *(*set)(void *arg); //设置函数,如语音播报

struct control *next;

};

struct control *add_device_to_ctrl_list(struct control *phead, struct control *device);

另外,被控制的设备类也统一配置接口,同时添加到设备链表中。

统一的设备类接口如下:

struct gdevice

{

char dev_name[128]; //设备名称

int key; //key值,用于匹配控制指令的值

int gpio_pin; //控制的gpio引脚

int gpio_mode; //输入输出模式

int gpio_status; //高低电平状态

int check_face_status; //是否进行人脸检测状态

int voice_set_status; //是否语音语音播报

struct gdevice *next;

};

struct gdevice *add_device_to_gdevice_list(struct gdevice *phead, struct gdevice *device);

struct gdevice *find_gdevice_by_key(struct gdevice *pdev, unsigned char key);

int set_gpio_gdevice_status(struct gdevice *pdev);

二、项目代码的前期准备

之前讲过智能分类的项目,因为会用到语音模块、OLED显示、网络模块、这些代码都可以从智能分类的项目中直接拷贝过来使用,另外添加之前准备好的人脸识别的代码 。 另外根据《项目整体设计》。再定义gdevice.h和control.h的头文件。整个目录结构如下:

pg@pg-Default-string:~/smarthome$ tree -I 3rd/ #3rd目录直接从garbage工程拷贝过来, 主要是一些依赖库和头文件, 这里就不显示

.

├── inc

│ ├── control.h

│ ├── face.h

│ ├── gdevice.h

│ ├── myoled.h

│ ├── socket.h

│ └── uartTool.h

├── Makefile

└── src

├── face.c

├── face.py

├── myoled.c

├── socket.c

└── uartTool.c

其中 control.h代码如下:

#ifndef __CONTROL__H

#define __CONTROL__H

#include

struct control

{

char control_name[128];

int (*init)(void);

void (*final)(void);

void *(*get)(void *arg);

void *(*set)(void *arg);

struct control *next;

};

//头插法,用于control类链表的创建

struct control *add_device_to_ctrl_list(struct control *phead, struct control *device);

#endif

// /dev/ttyS5 115200 ip port buffer pin /dev/I2C-3

control.c 代码如下:

#include "control.h"

//头插法

struct control *add_device_to_ctrl_list(struct control *phead, struct control *device)

{

struct control *pcontrol;

if(NULL == phead){

pcontrol = device;

return pcontrol;

}else{

device->next = phead;

phead = device;

return phead;

}

}

gdevice.h 代码如下:

#ifndef __GDEVICE_H

#define __GDEVICE_H

struct gdevice

{

char dev_name[128]; //设备名称

int key; //key值,用于匹配控制指令的值

int gpio_pin; //控制的gpio引脚

int gpio_mode; //输入输出模式

int gpio_status; //高低电平状态

int check_face_status; //是否进行人脸检测状态

int voice_set_status; //是否语音语音播报

struct gdevice *next;

};

#endif

gdevice.c 代码如下:

#include

#include "gdevice.h"

//根据key值(buffer[2])查找设备节点

struct gdevice *find_gdevice_by_key(struct gdevice *pdev, unsigned char key)

{

struct gdevice *p = NULL;

if (NULL == pdev)

{

return NULL;

}

p = pdev;

while (NULL != p)

{

if(p->key == key)

{

return p;

}

p = p->next;

}

return NULL;

}

//设置GPIO引脚状态,输入输出和高低电平

int set_gpio_gdevice_status(struct gdevice *pdev)

{

if (NULL == pdev)

{

return -1;

}

if (-1 != pdev->gpio_pin)

{

if (-1 != pdev->gpio_mode)

{

pinMode(pdev->gpio_pin, pdev->gpio_mode);

}

if (-1 != pdev->gpio_status)

{

digitalWrite(pdev->gpio_pin, pdev->gpio_status);

}

}

return 0;

}

//链表头插法

struct gdevice *add_device_to_gdevice_list(struct gdevice *phead, struct gdevice *device)

{

struct gdevice *pgdevice;

if(NULL == phead){

pgdevice = device;

return pgdevice;

}else{

device->next = phead;

phead = device;

return phead;

}

}

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)

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

三、实现语音监听接口

语音监听模块会借助消息队列进行消息的传递,因此先实现消息队列的接口 msg_queque.c:

#include

#include "msg_queue.h"

#define QUEQUE_NAME "/mq_queue"

mqd_t msg_queue_create(void)

{

//创建消息队列

mqd_t mqd = -1;

struct mq_attr attr;

attr.mq_flags = 0;

attr.mq_maxmsg = 10;

attr.mq_msgsize = 256;

attr.mq_curmsgs = 0;

mqd = mq_open(QUEQUE_NAME, O_CREAT | O_RDWR, 0666, &attr);

printf("%s| %s |%d: mqd = %d\n",__FILE__, __func__, __LINE__, mqd);

return mqd;

}

void msg_queue_final(mqd_t mqd)

{

if (-1 != mqd){

mq_close(mqd);

mq_unlink(QUEQUE_NAME);

mqd = -1;

}

}

int send_message(mqd_t mqd, void *msg, int msg_len)

{

int byte_send = -1;

byte_send = mq_send(mqd, (char *)msg, msg_len, 0);

return byte_send;

}

msg_queue.h 头文件定义:

#ifndef __MSG_QUEQUE_H

#define __MSG_QUEQUE_H

#include

#include

#include

#include

mqd_t msg_queue_create(void);

void msg_queue_final(mqd_t mqd);

int send_message(mqd_t mqd, void *msg, int msg_len);

#endif

根据control.h头文件的定义,实现语音监听接口

首先定义全局变量用于mqd句柄和struct control链表的传递 global.h 代码:

#ifndef __GLOBAL__H

#define __GLOBAL__H

typedef struct {

mqd_t mqd;

struct control *ctrl_phead;

}ctrl_info_t;

#endif

紧接着语音监听接口 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

#include

#include "voice_interface.h"

#include "uartTool.h"

#include "msg_queue.h"

#include "global.h"

static int serial_fd = -1;

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传参

{

unsigned char buffer[6] = {0x00, 0x00, 0x00, 0x00, 0X00, 0x00};

int len = 0;

mqd_t mqd = -1;

ctrl_info_t *ctrl_info= NULL;

if (NULL != arg)

ctrl_info = (ctrl_info_t *)arg;

if (-1 == serial_fd)

{

serial_fd = voice_init();

if (-1 == serial_fd)

{

pthread_exit(0);

}

}

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)

{

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[5] == 0xAA && buffer[4] == 0x55)

{

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_message(mqd, buffer, len);//注意,不要用strlen去计算实际的长度

}

memset(buffer, 0, sizeof(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)

{

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

};

voice_interface.h代码:

#ifndef ___VOICE_INTERFACE_H___

#define ___VOICE_INTERFACE_H___

#include "control.h"

struct control *add_voice_to_ctrl_list(struct control *phead);

#endif

四、实现socket监听接口

参考voice接口实现socket 接口socket_interface.c代码:

#include

#include "socket.h"

#include "control.h"

#include "socket_interface.h"

#include "msg_queue.h"

#include "global.h"

static int s_fd = -1;

static int tcpsocket_init(void)

{

s_fd = socket_init(IPADDR, IPPORT);

return -1;

}

static void tcpsocket_final(void)

{

close(s_fd);

s_fd = -1;

}

static void* tcpsocket_get(void *arg)

{

int c_fd = -1;

int ret = -1;

struct sockaddr_in c_addr;

unsigned char buffer[BUF_SIZE];

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 failed\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));

//4. accept

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 (-1 == c_fd)

{

continue;

}

ret = setsockopt(c_fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)); // 设置TCP_KEEPALIVE选项

if (ret == -1) { // 如果设置失败,打印错误信息并跳出循环

perror("setsockopt");

break;

}

ret = setsockopt(c_fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle)); // 设置探测时间间隔选项

if (ret == -1) { // 如果设置失败,打印错误信息并跳出循环

perror("setsockopt");

break;

}

ret = setsockopt(c_fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepinterval,

sizeof(keepinterval)); // 设置探测包发送间隔选项

if (ret == -1) { // 如果设置失败,打印错误信息并跳出循环

perror("setsockopt");

break;

}

ret = setsockopt(c_fd, IPPROTO_TCP, TCP_KEEPCNT, &keepcount,

sizeof(keepcount)); // 设置探测包发送次数选项

if (ret == -1) { // 如果设置失败,打印错误信息并跳出循环

perror("setsockopt");

break;

}

printf("Accepted a connection from %s:%d\n", inet_ntoa(c_addr.sin_addr),

ntohs(c_addr.sin_port)); // 打印客户端的IP地址和端口号

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[5] == 0xAA && buffer[4] == 0x55)

{

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_message(mqd, buffer, ret);//注意,不要用strlen去计算实际的长度

}

}

else if ( -1 == ret || 0 == ret)

{

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

};

socket.h 代码:

#ifndef ___SOCKET_INTERFACE_H___

#define ___SOCKET_INTERFACE_H___

#include "control.h"

struct control *add_tcpsocket_to_ctrl_list(struct control *phead);

#endif

五、实现烟雾报警监听接口

同样参考voice接口实现smoke 接口smoke_interface.c代码:

#include

#include

#include

#include "control.h"

#include "smoke_interface.h"

#include "msg_queue.h"

#include "global.h"

#define SMOKE_PIN 6

#define SMOKE_MODE INPUT

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)

{

int status = HIGH;

int switch_status = 0;

unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0x55, 0xAA};

ssize_t byte_send = -1;

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)

{

buffer[2] = 0x45;

buffer[3] = 0x00;

switch_status = 1;

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]);

byte_send = mq_send(mqd, buffer, 6, 0);

if (-1 == byte_send)

{

continue;

}

}

else if (HIGH == status && 1 == switch_status)

{

buffer[2] = 0x45;

buffer[3] = 0x01;

switch_status = 0;

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]);

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

};

smoke_interface.h 代码:

#ifndef ___SMOKE_INTERFACE_H___

#define ___SMOKE_INTERFACE_H___

#include "control.h"

struct control *add_smoke_to_ctrl_list(struct control *phead);

#endif

六、实现设备节点代码

客厅灯设备节点 由于消息接收处理线程需要处理各设备类外设,因此先根据gdevice.h定义,实现客厅灯设备节点代码 lrled_gdevice.c:

#include "gdevice.h"

struct gdevice lrled_gdev = {

.dev_name = "LV led",

.key = 0x41,

.gpio_pin = 2,

.gpio_mode = OUTPUT,

.gpio_status = HIGH,

.check_face_status = 0,

.voice_set_status = 0,

};

struct gdevice *add_lrled_to_gdevice_list(struct gdevice *pgdevhead)

{//头插法

return add_device_to_gdevice_list(pgdevhead, &lrled_gdev);

};

lrled_gdevice.h 代码如下:

#ifndef __LRLED_GDEVICE_H

#define __LRLED_GDEVICE_H

struct gdevice *add_lrled_to_gdevice_list(struct gdevice *pgdevhead);

#endif

卧室灯设备节点 卧室灯设备节点代码bled_gdevice.c:

#include "gdevice.h"

struct gdevice bled_gdev = {

.dev_name = "BR led",

.key = 0x42,

.gpio_pin = 5,

.gpio_mode = OUTPUT,

.gpio_status = HIGH,

.check_face_status = 0,

.voice_set_status = 0,

};

struct gdevice *add_bled_to_gdevice_list(struct gdevice *pgdevhead)

{//头插法

return add_device_to_gdevice_list(pgdevhead, &bled_gdev);

};

bled_gdevice.h 代码如下:

#ifndef __BLED_GDEVICE_H

#define __BLED_GDEVICE_H

struct gdevice *add_bled_to_gdevice_list(struct gdevice *pgdevhead);

#endif

实现风扇设备节点代码 实现风扇设备节点代码fan_gdevice.c:

#include "gdevice.h"

struct gdevice gdevice_fan = {

.dev_name = "fan",

.key = 0x43,

.gpio_pin = 7,

.gpio_mode = OUTPUT,

.gpio_status = LOW,

.check_face_status = 0,

.voice_set_status = 0,

.next = NULL

};

struct gdevice *add_fan_to_gdevice_list(struct gdevice *phead)

{

return add_device_to_gdevice_list(phead, &gdevice_fan);

}

fan_gdevice.h 代码如下:

#ifndef __FAN_GDEVICE_H

#define __FAN_GDEVICE_H

struct gdevice *add_fan_to_gdevice_list(struct gdevice *pgdevhead);

#endif

蜂鸣器设备节点 蜂鸣器设备节点代码beep_gdevice.c:

#include "gdevice.h"

struct gdevice beep_gdev = {

.dev_name = "beep",

.key = 0x45,

.gpio_pin = 9,

.gpio_mode = OUTPUT,

.gpio_status = HIGH,

.check_face_status = 0,

.voice_set_status = 1,

};

struct gdevice *add_beep_to_gdevice_list(struct gdevice *pgdevhead)

{//头插法

return add_device_to_gdevice_list(pgdevhead, &beep_gdev);

};

beep_gdevice.h 代码如下:

#ifndef __BEEP_GDEVICE_H

#define __BEEP_GDEVICE_H

struct gdevice *add_beep_to_gdevice_list(struct gdevice *pgdevhead);

#endif

七、实现接收消息处理接口

同样参考voice接口实现receive 接口receive_interface.c代码:

#include "gdevice.h"

struct gdevice lock_gdev = {

.dev_name = "lock",

.key = 0x44,

.gpio_pin = 8,

.gpio_mode = OUTPUT,

.gpio_status = HIGH,

.check_face_status = 1,

.voice_set_status = 1,

};

struct gdevice *add_lock_to_gdevice_list(struct gdevice *pgdevhead)

{//头插法

return add_device_to_gdevice_list(pgdevhead, &lock_gdev);

};

receive.h 头文件代码:

#ifndef ___RECEIVE_INTERFACE_H___

#define ___RECEIVE_INTERFACE_H___

#include "control.h"

struct control *add_receive_to_ctrl_list(struct control *phead);

#endif

推荐文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: