1 软硬件准备
这里使用一块Mesh Node节点进行私有广播数据的发送,一块网关节点进行私有 广播数据的接收与解析,测试使用的软硬件环境如下:
SDK 版本
| 1.0.0
|
| mesh_light_node_demo
|
网关节点Solution
| ble_mesh_gateway_demo
|
Node节点硬件
|
|
网关节点硬件
| W800网关开发板
|
网关及节点的SDK下载/使用,这里不再做介绍,具体可参考蓝牙网关SDK
2 开发步骤
2.1 发送端开发
2.1.1 协议栈修改
发送端用于发送自定义非Mesh数据,若发送端没有跑Mesh协议栈的需求,则可跳过该部分,直接看2.2,为了实现私有数据的发送,需要对现有Mesh协议栈进行适当修改,这里不建议通过关闭Mesh协议栈的方法进行广播数据发送,推荐使用本文的方法(通过Mesh底层的发送调度进行私有广播数据发送), 实现方法如下:
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,
};
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 {
.....
#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
.....
};
/*私有广播数据重传次数和重传间隔,用户可以根据实际需要修改,这里设置为重传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函数类型定义
|
无
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 注意事项
文章转载自:平头哥芯片开放社区 作者:钦峰