智能家居1 -- 实现语音模块

项目整体框架: 

监听线程×4:

1. 语音监听线程:用于监听语音指令, 当有语音指令过来后, 通过消息队列的方式给消息处理线程发送指令

2. 网络监听线程:用于监听网络指令,当有网络指令过来后, 通过消息队列的方式给消息处理线程发送指令

3. 火灾检测线程:当存在煤气泄漏或者火灾闲情时, 发送警报指令给消息处理线程

4. 消息监听线程: 用于处理以上3个线程发过来的指令,并根据指令要求配置GPIO引脚状态,OLED屏显示、语音播报,还有人脸识别开门

统一的监听模块接口 -- control:

上述四个线程采用统一个对外接口接口,同时添加到监听链表中

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

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

主要代码: 


-------------------------------------------

Makefile

CC  :=  aarch64-linux-gnu-gcc
# SRC -- 存放所有的 .c 文件
SRC :=  $(shell find src -name "*.c")
# INC --  存放所有的 头文件 (包括自己写的 和 第三方)
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

#  把需要包含的 .c 文件,替换为.o 文件
OBJ := $(subst src/,obj/,$(SRC:.c=.o))


#  创建目标 , 并且指定存放位置
TARGET  =  obj/smarthome

#   -I./inc  -- 存放头文件路径
CFLAGS := $(foreach item,$(INC),-I$(item))


# -I 指定的 第三方 库文件路径
LIBS_PATH := ./3rd/usr/local/lib \
             ./3rd/lib/aarch64-linux-gnu \
             ./3rd/usr/lib/aarch64-linux-gnu \
             ./3rd/usr/lib/python3.10 \
             
             

# -L ./3rd/usr/local/LIBS
LDFLAGS := $(foreach item,$(LIBS_PATH),-L$(item))

#  指定我们要链接的库
LIBS := -lwiringPi -lpython3.10 -pthread -lexpat -lz -lcrypt 


#  生成obj文件夹,里面包含源文件对应的.o文件
obj/%.o:src/%.c
    mkdir -p obj
    $(CC) -o $@ -c $< $(CFLAGS)

#  一来obj 下面的.o文件 编译
$(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 


============================

main.c 

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

#include "control.h"
#include "mq_queue.h"
#include "voice_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; // 统计节点数

    // 创建消息队列
    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;
    }
    
    ctrl_info->ctrl_phead = add_voice_to_ctrl_list(ctrl_info->ctrl_phead);
    //ctrl_info->ctrl_phead = add_socket_to_ctrl_list(ctrl_info->ctrl_phead);
    //ctrl_info->ctrl_phead = add_fire_to_ctrl_list(ctrl_info->ctrl_phead);
  

    pointer = ctrl_info->ctrl_phead;

    while(NULL!=pointer) // 对所有控制结构体初始化,并且统计节点数
    {
        if(NULL != pointer->init)
        {
            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)
          pthread_create(&tid[i],NULL,(void *)pointer->get,(void *)ctrl_info); // 传入这个结构体参数,方便同时调用多组线程里面的API

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

}

实现语言控制模块-- 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)
{

}

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)
{
  //头插法实现 添加链表节点
  struct control *pnew = NULL;
 
  
  if(NULL == phead)
  {
    phead = &voice_control; // 直接传入我们的 voice_control
  }

  else// 头结点非空 - 链表有数据
  {
   voice_control.next = phead; //把新的节点的next指向头结点
   voice_control = *phead; // 让心节点成为头结点
  }

  return phead;

};

编译: 

// 注意我们的Makefile 里面指定了使用交叉编译工具链:  aarch64-linux-gnu-gcc

所以我们生成的文件在×86上是没法运行的,需要scp 传送到arm-64的系统上,

比如我们的orangepi02

编译命令: 

make complie

或者

make

传送


scp obj/smarthome  orangepi@192.168.1.11:/home/orangepi

切换到我们的香橙派上: 

执行

sudo -E ./smarthome

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/596835.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

X 推出 Stories 功能,由 Grok AI 生成新闻摘要

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

OCC笔记:图形可视化的实现方式

注&#xff1a;文中参看的occ的源码版本为7.4.0 1、实现思路概览 整体架构 主要有3大块&#xff1a;AIS&#xff08;Application Interactive Services &#xff0c;直译为&#xff1a;应用程序交互服务&#xff09;、Graphics&#xff08;图形&#xff09;、Geometry & T…

磐石云最版本使用教程

磐石云外呼系统是一款集成了呼叫平台、电话线路和话术系统的软件&#xff0c;旨在提高企业的电话营销效率。以下是磐石云外呼系统的基本操作步骤&#xff1a; 安装和配置&#xff1a; 首先需要在Linux操作系统上安装磐石云外呼系统&#xff0c;通常需要至少4核CPU、8GB内存以及…

MyCat安装

MyCat安装 官网下载地址打不开说明采用站点的方式进行下载基础包 &#xff1a;程序包&#xff1a; 配置原型库数据源root.user.json 配置文件说明&#xff08;默认配置&#xff09; Mycat启动授权启动mycat启动mycat查看mycat日志连接Mycat 官网下载地址打不开说明 官网可能受…

FreeBSD RISCV 在QEME中实践-网络配置

在前一篇文章中&#xff0c;我们一起进行了FreeBSD RISCV 在QEME中实践 现在&#xff0c;让我们配置好网络吧&#xff01; 先上结论&#xff1a;用默认配置启动即可&#xff0c;网络就加载好了&#xff0c;只是不能ping罢了。因为不能ping&#xff0c;以为网络没通&#xff0…

linux文件夹权限查看以及设置

1.linux给文件夹和子文件夹开权限 2.查询当前文件夹权限

java 泛型题目讲解

泛型的知识点 泛型仅存在于编译时期&#xff0c;编译期间JAVA将会使用Object类型代替泛型类型&#xff0c;在运行时期不存在泛型&#xff1b;且所有泛型实例共享一个泛型类 public class Main{public static void main(String[] args){ArrayList<String> list1new Arra…

ASP.NET网上图书订阅系统的设计

摘 要 网上图书订阅系统基于 Microsoft SQL Server 2000和ASP.NET平台&#xff0c;以C#为编程语言开发,实现了网上图书预订和借阅&#xff0c;订阅信息查询&#xff0c;图书和用户信息的修改&#xff0c;借阅排行和新到图书的查询等功能&#xff0c;这样不但可将管理员从繁重…

Linux基础之makefile/make

目录 一、背景 二、makefile和make的讲解 2.1 使用方法 2.2 伪目标文件 2.3 文件的属性以及属性的更新 2.4 makefile的自动推导 一、背景 这里会提及为什么要使用makefile和make&#xff0c;以及他们是什么和作用。 会不会写makefile&#xff0c;从一个侧面说明了一个人是…

宝兰德通过广东教育行业信创适配认证,拓展教育信创生态圈

近日&#xff0c;由宝兰德自主研发的多款中间件产品通过广东省教育行业信创适配中心的适配测试。测试表明&#xff0c;宝兰德四款中间件产品&#xff08;分布式缓存软件V3.0、应用服务器软件V9.5、消息中间件软件 V2.1、Web服务器软件V3.1&#xff09; 与当前主流国产操作系统统…

memory consistency

memory consistency model 定义了对于programmer和implementor来说&#xff0c;访问shared memory system的行为&#xff1b; 对于programmer而言&#xff0c;他知道期望值是什么&#xff0c; 知道会返回什么样的数据&#xff1b;&#xff1b; 对于implementro而言&#xff0c;…

数据结构——链表专题1

文章目录 一、移除链表元素二、反转链表三、合并两个有序链表四、链表的中间节点五、环形链表的约瑟夫问题六、分割链表 一、移除链表元素 原题链接&#xff1a;移除链表元素 一个解法是遍历原链表&#xff0c;将与val相等的结点抛弃&#xff0c;链接后一个结点 另一个解法是…

corefBERT论文阅读

CorefBERT是清华大学团队发表的&#xff0c;继SpanBERT之后另一针对共指消解的BERT模型。共指消解任务对于文本理解、智能问答等其他NLP子任务起到至关重要的作用。 为了提高语言模型的共指推理能力&#xff0c;一个简单的解决方案是使用有监督的共指解析数据在bert等模型进行…

论文笔记ColdDTA:利用数据增强和基于注意力的特征融合进行药物靶标结合亲和力预测

ColdDTA发表在Computers in Biology and Medicine 的一篇一区文章 突出 • 数据增强和基于注意力的特征融合用于药物靶点结合亲和力预测。 • 与其他方法相比&#xff0c;它在 Davis、KIBA 和 BindingDB 数据集上显示出竞争性能。 • 可视化模型权重可以获得可解释的见解。 …

Linux网络部分——DNS域名解析服务

目录 1. 域名结构 2. 系统根据域名查找IP地址的过程 3.DNS域名解析方式 4.DNS域名解析的工作原理【☆】 5.域名解析查询方式 6.搭建主从DNS域名服务器 ①初始化操作主服务器和从服务器&#xff0c;安装BIND软件 ②修改主服务器的主配置文件、区域配置文件、区域数…

【c1】数据类型,运算符/循环,数组/指针,结构体,main参数,static/extern,typedef

文章目录 1.数据类型&#xff1a;编译器&#xff08;compiler&#xff09;与解释器&#xff08;interpreter&#xff09;&#xff0c;中文里的汉字和标点符号是两个字节&#xff0c;不能算一个字符&#xff08;单引号&#xff09;2.运算符/循环&#xff1a;sizeof/size_t3.数组…

基于java的CRM客户关系管理系统的设计与实现(论文 + 源码 )

【免费】基于Java的CRM客户关系管理系统的设计和实现.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89273409 基于Java的CRM客户关系管理系统的设计与实现 摘 要 随着互联网的高速发展&#xff0c;市场经济的信息化&#xff0c;让企业之间的竞争变得&#xff0…

复写零(双指针)

下面的解法需要手动画图&#xff0c;举例去体会&#xff0c;只有自己手动去做了&#xff0c;才会有所收获。 class Solution {public void duplicateZeros(int[] arr) {int n arr.length;//先找到最后一个元素的位置;//至于为什么要直接先设dest 为-1&#xff0c;这是经过研究…

CNN笔记详解

CNN(卷积神经网络) 计算机视觉&#xff0c;当你们听到这一概念的是否好奇计算机到底是怎样知道这个图片是什么的呢&#xff1f;为此提出了卷积神经网络&#xff0c;通过卷积神经网络&#xff0c;计算机就可以识别出图片中的特征&#xff0c;从而识别出图片中的物体。看到这里充…

分布式与一致性协议之ZAB协议(四)

ZAB协议 ZooKeeper是如何选举领导者的。 首先我们来看看ZooKeeper是如何实现成员身份的&#xff1f; 在ZooKeeper中&#xff0c;成员状态是在QuorumPeer.java中实现的&#xff0c;为枚举型变量 public enum ServerState { LOOKING, FOLLOWING, LEADING, OBSERVING }其实&…