芯片开放社区
直播中

jsqueh

8年用户 1138经验值
私信 关注
[技术讨论]

基于平头哥蓝牙Mesh协议栈开发私有广播数据收发功能

1 软硬件准备

这里使用一块Mesh Node节点进行私有广播数据的发送,一块网关节点进行私有 广播数据的接收与解析,测试使用的软硬件环境如下:

SDK 版本

1.0.0

Node节点Solution

mesh_light_node_demo

网关节点Solution

ble_mesh_gateway_demo

Node节点硬件

PHY6220开发板

网关节点硬件

W800网关开发板

网关及节点的SDK下载/使用,这里不再做介绍,具体可参考蓝牙网关SDK

2 开发步骤

2.1 发送端开发

2.1.1 协议栈修改

发送端用于发送自定义非Mesh数据,若发送端没有跑Mesh协议栈的需求,则可跳过该部分,直接看2.2,为了实现私有数据的发送,需要对现有Mesh协议栈进行适当修改,这里不建议通过关闭Mesh协议栈的方法进行广播数据发送,推荐使用本文的方法(通过Mesh底层的发送调度进行私有广播数据发送), 实现方法如下:

  • 增加 BT_MESH_ADV_VENDOR广播类型,该广播类型的定义在adv.h文件中实现,如下:

enum bt_mesh_adv_type {
    BT_MESH_ADV_PROV,
    BT_MESH_ADV_DATA,
    BT_MESH_ADV_BEACON,
    BT_MESH_ADV_URI,
    /*新增加的私有广播类型*/
    BT_MESH_ADV_VENDOR,
};
  • 添加加adv_type数组成员,用于底层发送接口设置AD data类型,该数组在adv.c中实现,如下:

static const u8_t adv_type[] = {
    [BT_MESH_ADV_PROV]   = BT_DATA_MESH_PROV,
    [BT_MESH_ADV_DATA]   = BT_DATA_MESH_MESSAGE,
    [BT_MESH_ADV_BEACON] = BT_DATA_MESH_BEACON,
    [BT_MESH_ADV_URI]    = BT_DATA_URI,
    /*根据上层设置的BT_MESH_ADV_VENDOR flag,将ADV数据的类型设置为BT_DATA_MANUFACTURER_DATA*/
    [BT_MESH_ADV_VENDOR] = BT_DATA_MANUFACTURER_DATA,
};
  • 修改struct bt_mesh_adv type成员的定义,该结构体在adv.h文件中实现,如下:

struct bt_mesh_adv {
    .....
#if  defined(CONFIG_MESH_LPM) && defined(CONFIG_BT_MESH_PROVISIONER)
              /*将type设置成3位,否则会发生截断*/
    u8_t      type:3,
              busy:1,
              lpm_flag:1,
              /*trans位数可减小*/
              trans:3;
#else
              /*将type设置成3位,否则会发生截断*/
    u8_t      type:3,
              busy:1,
              /*trans位数可减小*/
              trans:4;
#endif
    .....
};
  • 增加以下私有广播数据发送函数,该函数在adv.c中实现, 如下:

/*私有广播数据重传次数和重传间隔,用户可以根据实际需要修改,这里设置为重传3次,重传间隔为20ms*/
/* 3 transmissions, 20ms interval */
#define VENDOR_XMIT                BT_MESH_TRANSMIT(4, 20)

/*私有广播数据发送接口*/
int bt_mesh_adv_ven_data_send(const u8_t *data, u8_t len)
{
    struct net_buf *buf;

    BT_DBG("");
   
    if(!data || !len) {
        BT_ERR("No vendor data set");
        return -EINVAL;
    }
    /*数据长度超过29个字节认为非法(Legacy广播除去广播地址、类型等数据后,最大能装下29个字节)*/
    if(len > 29) {
        BT_ERR("Vendor data length should not exceed 29");
        return -EINVAL;   
    }
    /*从Adv buffer里面申请广播buffer,类型为BT_MESH_ADV_VENDOR*/
    buf = bt_mesh_adv_create(BT_MESH_ADV_VENDOR, VENDOR_XMIT, K_NO_WAIT);
    if (!buf) {
        BT_ERR("Unable to allocate beacon buffer");
        return -ENOBUFS;
    }
    /*添加广播数据*/
    net_buf_add_mem(buf, data, len);
    /*发送广播数据*/
    bt_mesh_adv_send(buf, NULL, NULL);
    net_buf_unref(buf);

    return 0;
}2.1.2 应用层使用

这里使用mesh_light_node_demo进行改造,用户可以根据自己的实际需求进行开发,使用方法如下:

/*设置发送数据的长度*/
#define VENDOR_DATA_LEN 29
/*设置Vendor数据的CID,用户可以根据实际需求选择是否要发送CID数据以及对应的CID数据*/
#define CONFIG_CID_TAOBAO 0x01A8

int main()
{
    ....

    while (1) {
        /*设置2S发送一次,实际应用中,发送行为可能是按键等触发,这里不推荐发送数据过于频繁*/
        aos_sem_wait(&sync_sem, 2000);
        /*发送CID数据*/
        vendor_data[0] = CONFIG_CID_TAOBAO & 0x00FF;
        vendor_data[1] = (CONFIG_CID_TAOBAO >> 8) & 0x00FF;
        /*发送TID数据,由于每个包在底层都有重传,为了避免接收端重复处理相应数据,这里推荐加一个TID数据,当然如果有其它去重方法或者对数据重复不敏感也可以不加*/
        vendor_data[2] = vendor_tid++;
        /*这里设置设备入网后才可以发送私有数据,用户可以根据自己的实际需求进行开发*/
        if(bt_mesh_is_provisioned()){
            /*调用发送私有广播数据接口*/
            ret = bt_mesh_adv_ven_data_send(vendor_data, sizeof(vendor_data));
            if(ret) {
                LOGE(TAG,"vendor data send faild");
            }
        }
    }
    return 0;
}2.2 接收端开发

2.2.1 协议栈修改

MESH SDK 1.0.0版本已经具有接收私有广播数据的功能,这里主要对相应的接口及其使用进行介绍:

bt_mesh_adv_vnd_scan_register

  • 函数原型

int bt_mesh_adv_vnd_scan_register(vendor_beacon_cb bacon_cb)
  • 功能描述

注册Mesh私有广播接收回调函数
  • 参数描述

IN/OUT

NAME

DESC

[in]

vendor_beacon_cb bacon_cb

回调函数指针,参见vendor_beacon_cb函数类型定义


  • 返回值

返回值


0

成功

非0

失败


  • 注意事项



vendor_beacon_cb

  • 函数类型原型

typedef void (*vendor_beacon_cb)(const bt_addr_le_t *addr, s8_t rssi,u8_t adv_type,void *user_data, uint16_t len)
  • 功能描述

广播接收回调函数类型
  • 参数描述

IN/OUT

NAME

DESC

[in]

const bt_addr_le_t *addr

对端广播地址

[in]

s8_t rssi

接收数据信号强度

[in]

u8_t adv_type

接收数据广播类型

[in]

void *user_data

接收数据,应该转换为struct net_buf_simple类型进行处理

[in]

uint16_t len

接收数据长度


  • 返回值


  • 注意事项


2.2.2 应用层使用

这里使用ble_mesh_gateway_demo进行数据接收和解析,用户可以根据自己的实际需求进行开发,使用方法如下:

/*待接收私有广播数据CID*/
#define CONFIG_CID_TAOBAO 0x01A8

static void vendor_data_cb(const struct adv_addr_t *addr, s8_t rssi, u8_t adv_type, void *user_data, uint16_t len)
{
    if (!user_data || !len) {
        return;
    }

    struct net_buf_simple *buf = (struct net_buf_simple *)user_data;
    static u8_t tid_last = 0;
    /*获取CID数据*/
    uint16_t cid = net_buf_simple_pull_le16(buf);
    /*获取TID数据*/
    u8_t     tid = net_buf_simple_pull_u8(buf);
    /*过滤CID不为CONFIG_CID_TAOBAO的数据以及重复数据*/
    if(cid == CONFIG_CID_TAOBAO && (tid_last != tid || !tid_last)) {
        tid_last = tid;
        LOGD(TAG,"Addr:%s type:%s rssi: %d adv_type:%02x",bt_hex_real(addr->val,6),(addr->type == 0x01) ? "Random" : "Public",rssi,adv_type);
        LOGD(TAG,"Vendor data: %s",bt_hex_real(buf->data,len));
    }
}

.....
   

int main()
{
.....
    app_rpt_fwver(CONFIG_SDK_VERSION);
/*注册回调处理函数*/
    err = bt_mesh_adv_vnd_scan_register(vendor_data_cb);
    if(err) {
        LOGE(TAG,"Adv scan cb register faild %d",err);
    }
.....
    return 0;
}

3 执行

3.1 编译/运行

编译、烧录和运行方法参考网关/节点侧SDK相应文档,烧录完成后重启网关和节点,可以看到网关数据有如下打印:

/*每隔2S接收一组数据*/
[18:38:34.212]收←◆[ 273.195]app Addr:010000000001 type:Public rssi: -29 adv_type:03
[ 273.197]app Vendor data: 0000000000000000000000000000000000000000000000000000000000

[18:38:36.316]收←◆[ 275.298]app Addr:010000000001 type:Public rssi: -29 adv_type:03
[ 275.300]app Vendor data: 0000000000000000000000000000000000000000000000000000000000

[18:38:38.351]收←◆[ 277.328]app Addr:010000000001 type:Public rssi: -29 adv_type:03
[ 277.330]app Vendor data: 0000000000000000000000000000000000000000000000000000000000

[18:38:40.393]收←◆[ 279.375]app Addr:010000000001 type:Public rssi: -29 adv_type:03
[ 279.377]app Vendor data: 0000000000000000000000000000000000000000000000000000000000

[18:38:42.476]收←◆[ 281.456]app Addr:010000000001 type:Public rssi: -29 adv_type:03
[ 281.457]app Vendor data: 0000000000000000000000000000000000000000000000000000000000

[18:38:44.529]收←◆[ 283.508]app Addr:010000000001 type:Public rssi: -29 adv_type:03
[ 283.511]app Vendor data: 0000000000000000000000000000000000000000000000000000000000

[18:38:46.716]收←◆[ 285.697]app Addr:010000000001 type:Public rssi: -27 adv_type:03
[ 285.699]app Vendor data: 0000000000000000000000000000000000000000000000000000000000

[18:38:48.648]收←◆[ 287.630]app Addr:010000000001 type:Public rssi: -28 adv_type:03
[ 287.632]app Vendor data: 0000000000000000000000000000000000000000000000000000000000

[18:38:50.738]收←◆[ 289.721]app Addr:010000000001 type:Public rssi: -29 adv_type:03
[ 289.724]app Vendor data: 0000000000000000000000000000000000000000000000000000000000
3.2 注意事项

  • 节点侧发送数据不宜过于频繁,特别是节点较多的时候,否则可能会干扰正常Mesh数据
  • 网关侧最好有类似本文的TID去重策略/CID过滤策略,否则频繁接收广播数据可能会干扰正常Mesh数据的处理

文章转载自:平头哥芯片开放社区 作者:钦峰

更多回帖

发帖
×
20
完善资料,
赚取积分