avatar

松果工作室

欢迎光临

  • 首页
  • freeRTOS
  • ESP
  • 开发手册
  • 快速笔记
  • 个人收藏
  • 工具
Home BLE MESH (二)
文章

BLE MESH (二)

Posted 2024-10-4 Updated 2024-10- 4
By YCP
22~29 min read

来自沁恒低功耗蓝牙MESH软件开发参考手册.pdf

WCH BLE MESH 常识

  • 所有节点均带有中继功能
  • 所有例程均带有app_mesh_config.h,可以修改所有 mesh 协议栈内使用的参数
  • MESH 节点层级结构:
    设备 -> 元素 -> 模型
    设备:mac 地址 + 广播UUID
    元素:拥有独立的网络地址
    模型:应用密钥 + 订阅地址

几种模型

  • ROOT模型:SIG MESH 协议规范中已经定义的模型,在WCH中,定义了CONFIG 模型、HEALTH 模型、通用开关模型。
    CONFIG 模型:用于完成配网过程和维护监测网络状态
    HEALTH 模型:用于指示配网状态
    通用开关模型:可以点灯
  • 厂商自定义模型:这里看看沁恒的透传模型
    struct bt_mesh_model vnd_models[] = {
          BLE_MESH_MODEL_VND_CB(CID_WCH,                //公司ID
                                BLE_MESH_MODEL_ID_WCH_SRV, //模型ID,沁恒自定义透传服务模型
                                vnd_model_srv_op,          //服务模型的操作函数,读写之类
                                NULL,
                                vnd_model_srv_keys,        //应用密钥
                                vnd_model_srv_groups,      //订阅地址
                                &vendor_model_srv,         //模型配置字
                                NULL),
    };
    

WCH BLE MESH 配网流程

待配网设备

1、初始化与广播
普通节点初始化完成后,调用prov_enable函数,会进入未配网广播模式,并开启扫描,期望收到对应配网命令。未配网广播会包含设备的 16 字节uuid信息,可以通过修改dev_uuid数组改变广播内容。
2、配网回调处理
待配网设备有多种配网相关回调函数,用于处理配网过程中的不同事件:

  • link_open回调:当收到配网命令时,首先进入link_open回调。Link是配网时建立的临时连接,用于提供一个数据通道给配网者和待配网设备通信。
  • link_close回调:当link连接关闭时会进入link_close回调,同时通过参数获取关闭的原因。出现配网成功、配网数据交互错误、接收超时、用户主动取消等情况时会关闭link。
  • prov_complete回调:只有在link连接过程中才会进入此回调,意味着当前配网已完成,设备可以进行正常通信。在配网完成回调中,可以获取当前网络的网络密钥序号、自身网络地址、当前网络中网络密钥更新标志以及当前网络IV序号。
  • prov_reset回调:配网信息重置回调,会在收到重置节点命令后上报或者用户自行调用清除配网信息API后上报。可在此回调中重新使能配网,回到未配网广播状态。
  • HEALTH模型回调:此模型回调有两种,分别是注意开启回调和注意关闭回调。配网开始后便会进入注意开启回调,用户可在此时用灯光闪烁、震动、蜂鸣等方式,辨认当前进入配网模式的设备,随后在配网命令中包含的超时时间后,会进入注意关闭回调,用户可在此时关闭之前打开的用于辨认的功能。

配网器

1、发现待配网设备

  • 中心节点(配网者)在使能配网功能后,会解析未配网节点发送的广播,并通过unprov_recv回调上报应用层。例程默认会在此回调中发送配网请求。回调的参数里包含未配网设备的信息,通常只关心 16 字节uuid,通过uuid判断该设备是否为需要配网的设备,随后调用bt_mesh_provision_adv向未配网设备发送配网请求,进入配网流程。

2、建立连接与配网操作

  • 当调用发起配网请求函数后,如果正确接收到未配网设备的应答,将会进入link_open回调,表示当前link建立完毕,开始进行配网数据交互。
  • 在配网过程中,配网者会给设备分配网络地址、网络密钥等信息。例如,配网者会为设备分配一个合适的网络地址(范围通常为 0x0001 - 0x7FFF),并下发网络密钥。同时,配网者还会执行一系列配置命令,如添加应用密钥、绑定应用密钥到指定模型、添加订阅地址到指定模型等。相关命令函数如下:
    • 添加应用密钥:int bt_mesh_cfg_app_key_add( uint16_t net_idx, uint16_t addr, uint16_t key_net_ idx, uint16_t key_app_idx, const uint8_t app_key[16] );
    • 绑定应用密钥到指定模型:对于标准模型int bt_mesh_cfg_mod_app_bind( uint16_t net_idx, uint16_t addr, uint16_t elem_ad dr, uint16_t mod_app_idx, uint16_t mod_id );,对于厂商自定义模型int bt_mesh_cfg_mod_app_bind_vnd( uint16_t net_idx, uint16_t addr, uint16_t ele m_addr, uint16_t mod_app_idx, uint16_t mod_id, uint16_t cid );
    • 添加订阅地址到指定模型:对于标准模型int bt_mesh_cfg_mod_sub_add( uint16_t net_idx, uint16_t addr, uint16_t elem_add r, uint16_t sub_addr, uint16_t mod_id );,对于厂商自定义模型int bt_mesh_cfg_mod_sub_add_vnd( uint16_t net_idx, uint16_t addr, uint16_t elem _addr, uint16_t sub_addr, uint16_t mod_id, uint16_t cid );

3、配网完成处理

  • 当配网完成后,会进入prov_complete回调。在这个回调中,配网者会进行一些后续操作,例程默认在此回调内使能配网者角色功能,随后将自身添加进用户管理的节点结构体数组内,并开始配置自身模型流程。同时,当把一个新设备配网完成后,协议栈会保存该节点的信息,并将其存入NVS中(如果使能了NVS功能),随后会通过node_added回调告知应用层节点已添加。node_added回调参数包含该节点所属的网络序号、节点网络地址、以及节点拥有的元素数量。

点灯实例

发送端

  1. 模型选择与初始化
    首先需要确定使用的模型,例如使用通用开关模型(GEN_ONOFF 模型)来控制灯的开关。在初始化模型时,需要定义模型的相关参数,包括操作码及其对应处理函数等。
    以初始化 ROOT 模型中的 GEN_ONOFF 模型为例,代码可能如下:

    static struct bt_mesh_model root_models[] = {
        // 其他模型配置...
        BLE_MESH_MODEL(BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_op, NULL, gen_ono
    ff_srv_keys, gen_onoff_srv_groups, NULL), 
    };
    

    其中gen_onoff_op是操作码结构体数组指针,定义了模型的操作码和对应的处理函数,例如:

  2. 应用密钥和订阅地址
    模型需要绑定应用密钥(APP_KEY)才能发送数据。应用密钥可以由配网者下发并绑定到模型,也可以自行添加绑定。例如,在 ROOT 模型中,gen_onoff_srv_keys可能是 GEN_ONOFF 模型绑定的应用密钥数组。
    订阅地址(SUB_ADDR)用于分组管理模型,如果发送的消息是针对特定分组的设备,需要设置正确的订阅地址。例如,gen_onoff_srv_groups可能是 GEN_ONOFF 模型添加的订阅地址数组。

  3. 发送数据函数调用
    当要发送点灯信号时,需要调用相应的发送数据函数。以沁恒自定义透传模型为例,发送函数原型可能如下:

    int vendor_message_srv_send_trans(struct send_param *param, uint8_t *pData, uin
    t16_t len);
    

    在调用这个函数时,需要设置正确的参数:
    param结构体包含了网络密钥序号(net_idx)、应用密钥序号(app_idx)、目标设备的网络地址(addr)、包序号(tid)、重传次数(tran_cnt)、重传间隔(period)、发送延迟(rand)、生存次数(send_ttl)等信息。
    pData是要发送的数据指针,对于点灯信号,可能是一个特定的指令值,表示开灯或关灯。
    len是要发送的数据长度。

  4. 发送的数据内容
    对于点灯信号,发送的数据可能是一个简单的指令值。例如,如果约定 1 表示开灯,0 表示关灯,那么发送的数据可能是一个字节的值为 1 或 0。
    同时,数据还可能包含一些其他的信息,如发送节点的地址、消息的序号等,这些信息可能会被封装在发送的数据结构中,以便接收节点能够正确解析和处理。

接收端

  1. 模型初始化与配置
    接收节点同样需要初始化相关模型,以便能够正确接收和处理发送节点发来的数据。例如,如果发送节点使用通用开关模型(GEN_ONOFF 模型)发送点灯信号,接收节点也需要对该模型进行正确初始化。
    初始化过程包括定义模型的操作码及其对应处理函数等,与发送节点类似。例如:

    static struct bt_mesh_model root_models[] = {
        // 其他模型配置...
        BLE_MESH_MODEL(BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_op, NULL, gen_ono
    ff_srv_keys, gen_onoff_srv_groups, NULL), 
    };
    

    其中gen_onoff_op包含了模型操作码和对应的处理函数定义。

  2. 应用密钥和订阅地址绑定
    接收模型需要绑定正确的应用密钥(APP_KEY),应用密钥的获取和绑定方式与发送节点类似,可以由配网者下发并绑定,也可以自行绑定。例如,gen_onoff_srv_keys数组可能存储了接收模型绑定的应用密钥。
    订阅地址(SUB_ADDR)也需要正确设置,如果发送节点是针对特定订阅地址发送的点灯信号,接收节点的模型需要绑定到相应的订阅地址才能接收该消息。例如,gen_onoff_srv_groups数组可能存储了接收模型的订阅地址。

  3. 接收数据处理
    当接收节点收到数据时,首先会进入初始化模型的操作码对应处理函数。以沁恒自定义透传模型为例,如果是无应答传输操作码的处理函数,会进行如下处理:

    static void vendor_message_srv_trans(struct bt_mesh_model *model, struct
    bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) 
    {
        vendor_model_srv_status_t vendor_model_srv_status; 
        uint8_t *pData = buf->data;
        uint16_t len = buf->len;
    
        // 判断数据tid序号是否重复,不重复则进行后续处理
        if(pData[0]!= vendor_model_srv->srv_tid.trans_tid) 
        {
            vendor_model_srv->srv_tid.trans_tid = pData[0]; 
            // 去掉开头一字节的tid
            pData++; 
            len--; 
        }
        vendor_model_srv_status.vendor_model_srv_Hdr.opcode = 
            OP_VENDOR_MESSAGE_TRANSPARENT_MSG; 
        vendor_model_srv_status.vendor_model_srv_Hdr.status = 0; 
        vendor_model_srv_status.vendor_model_srv_Event.trans.pdata = pData; 
        vendor_model_srv_status.vendor_model_srv_Event.trans.len = len; 
        vendor_model_srv_status.vendor_model_srv_Event.trans.addr = ctx-
            >addr; 
        if(vendor_model_srv->handler) 
        {
            vendor_model_srv->handler(&vendor_model_srv_status); 
        }
    }
    

    在这个处理函数中,会对收到的数据进行解析,包括判断数据的序号是否重复,提取数据内容(去掉开头可能存在的序号字节),并将相关信息填充到回调参数结构体中,最后调用回调函数将数据信息上报给应用层。

  4. 回调函数处理
    接收节点的回调函数会在处理函数中被调用,用于将接收到的数据信息进一步上报给应用层。例如,对于沁恒自定义透传服务模型,回调函数定义可能如下:

    static void vendor_model_srv_rsp_handler(const vendor_model_srv_status_t 
    *val) 
    {
        if(val->vendor_model_srv_Hdr.status) 
        {
            // 有应答数据传输超时未收到应答处理
        }
        else if(val->vendor_model_srv_Hdr.opcode == OP_VENDOR_MESSAGE_TRANSPARENT_MSG)
        {
            // 收到透传数据处理,例如打印相关信息
            APP_DBG("len %d, data 0x%02x from 0x%04x", val-
                >vendor_model_srv_Event.trans.len, val-
                >vendor_model_srv_Event.trans.pdata[0], val-
                >vendor_model_srv_Event.trans.addr); 
        }
        // 其他操作码处理...
    }
    

    回调函数会根据接收到的数据的操作码类型进行相应的处理,例如对于点灯信号对应的操作码,可能会在应用层进行相应的操作,如控制灯的实际开关状态。

疑问补充


1、配网器给待配网节点配网时,待配网节点会被配置哪些?

  • 网络地址:普通节点本身没有网络地址,由中心节点(配网者)分配。如果是自配网方式,则需用户自行确保同一网络中所有设备的网络地址各不相同,或者通过使能特定配置,所有设备使用相同网络地址,并通过应用层添加判断来区分消息来源和目的地。
  • 网络密钥:所有设备只能与有相同网络密钥的设备互相通信。网络密钥由配网者下发,新入网的设备只有 CONFIG 模型可以通信,其他模型则必需绑定应用密钥才可以使用,应用密钥也是在网络密钥基础上再次加密。最终所有的模型都要配上应用密钥。
  • 应用密钥:设备的模型需要绑定应用密钥才可以进行数据的收发。应用密钥一般由配网者下发给设备,并可绑定到指定模型上。
  • 订阅地址:可用于分组管理模型,当给多个模型添加相同的订阅地址后,如果向此订阅地址发送消息,则所有添加此订阅地址的模型都将收到消息。订阅地址可由配网者下发添加到模型。

2、我有很多个待配网节点,我只想配置一些节点,不想配置全部,我应该怎么办?

  • 利用设备自身的配置功能
    • 设备区分:可以通过设备自身的一些特性或设置来区分哪些节点需要配置,哪些不需要。例如,某些设备可能有特定的硬件开关或按钮,按下特定按钮的设备才进入配网模式等待配置;或者设备可以通过内部的配置寄存器或设置菜单,设置是否允许配网。
    • 应用层判断:在节点的软件设计中,通过应用层的逻辑判断来决定是否接受配网。比如,节点可以在接收到配网命令时,根据自身的一些预设条件(如设备编号、设备类型等)来决定是否响应配网流程。
  • 配网器端的控制
    • 配网器设置:配网器本身可能具有一些设置选项,可以用来选择需要配网的节点。例如,配网器可以设置配网的范围,只有在这个范围内的节点才会被配网;或者配网器可以根据节点的蓝牙信号强度、设备名称等信息来筛选需要配网的节点。
    • 配网流程控制:在配网流程中,可以通过一些条件判断来决定是否继续对某个节点进行配网。例如,在配网者解析未配网节点发送的广播信息时,可以根据广播内容中的某些特定字段(如设备的特定标识、设备所属的群组标识等)来决定是否对该节点发送配网请求。

3、待配网设备会广播什么内容?

  • 设备的 16 字节 uuid 信息:普通节点初始化完成后,调用 prov_enable 函数,会进入未配网广播模式,并开启扫描,期望收到对应配网命令。未配网广播会包含设备的 16 字节 uuid 信息,可以通过修改 dev_uuid 数组改变广播内容。
  • 可能包含特定标识或群组标识等特定字段:这些字段可用于配网者在解析广播信息时,决定是否对该节点发送配网请求,以实现有选择性地对节点进行配网。

4、不同的待配网设备用什么区分?

  • 网络地址
    • 配网者分配:在由配网者进行配网的情况下,配网者会给每个入网的设备分配一个唯一的网络地址。这个网络地址在整个网络中是唯一的,用于区分不同的设备。例如,中心节点(配网者)在将普通节点加入网络时,会为其分配一个合适的网络地址,地址范围通常为 0x0001 - 0x7FFF。
    • 自配网情况:如果是设备自配网,且不使用允许同地址的特殊配置时,设备需要自行确保其网络地址在网络中是唯一的。可以通过内部的算法或设置来生成一个唯一的网络地址。
  • 设备的唯一标识(如 UUID)
    • 广播信息中的 UUID:待配网设备在发送未配网广播时,会包含设备的 16 字节 uuid 信息。配网者可以根据这个 UUID 来区分不同的设备。例如,普通节点初始化完成后,调用 prov_enable 函数进入未配网广播模式,其广播内容中的 UUID 可以作为设备的一个重要标识。
  • 应用层自定义的标识或参数
    • 设备类型标识:在应用层,可以为不同类型的设备定义特定的标识。例如,对于智能灯泡和智能插座,可以分别定义不同的设备类型标识,在配网过程中或网络通信中,通过这个标识来区分设备。
    • 用户自定义参数:用户可以根据自己的需求,在设备中设置一些自定义的参数用于区分设备。比如,为不同房间的设备设置不同的房间编号参数,或者为同一类型但不同批次的设备设置批次编号等。
  • 硬件相关的区分方式
    • MAC 地址:设备的 MAC 地址是全球唯一的,可以作为区分不同设备的一种方式。虽然在蓝牙 mesh 网络中可能不直接使用 MAC 地址进行设备区分,但在一些底层的通信或识别过程中,MAC 地址可以提供一种额外的区分手段。
    • 硬件版本或序列号:不同版本的设备可能具有不同的硬件特性或功能,其硬件版本号或序列号也可以作为区分设备的依据。例如,新批次的设备可能在硬件上进行了一些改进,通过硬件版本号可以区分不同批次的设备。

WCH
License:  CC BY 4.0
Share

Further Reading

OLDER

(四) 两种乙类放大电路

NEWER

Lora

Recently Updated

  • ESP32(八) 简单的webserver
  • ESP32(七) NVS
  • ESP32(四) STA & AP
  • 多级菜单
  • ESP32(五) ESP32 OTA

Trending Tags

WCH Linux Elec freeRTOS STM ESP Flutter Others SwiftUI

Contents

©2025 松果工作室. Some rights reserved.

Using the Halo theme Chirpy