1. Mesh beacon


这里关注 0x2B Mesh beacon

hci.h

#define BT_DATA_MESH_BEACON             0x2b /* Mesh Beacon */

2. 接收或者发送 一个 mesh beacon

2.1. 初始化

typedef enum {BT_MESH_PROV_ADV   = BIT(0),BT_MESH_PROV_GATT  = BIT(1),
} bt_mesh_prov_bearer_t;/** @brief Enable specific provisioning bearers**  Enable one or more provisioning bearers.**  @param bearers Bit-wise or of provisioning bearers.**  @return Zero on success or (negative) error code otherwise.*/
int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers)
{if (bt_mesh_is_provisioned()) {return -EALREADY;}if (IS_ENABLED(CONFIG_BT_DEBUG)) {const struct bt_mesh_prov *prov = bt_mesh_prov_get();struct bt_uuid_128 uuid = { .uuid.type = BT_UUID_TYPE_128 };memcpy(uuid.val, prov->uuid, 16);BT_INFO("Device UUID: %s", bt_uuid_str(&uuid.uuid));}if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) &&(bearers & BT_MESH_PROV_ADV)) {/* Make sure we're scanning for provisioning inviations */bt_mesh_scan_enable();/* Enable unprovisioned beacon sending */bt_mesh_beacon_enable();}if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) &&(bearers & BT_MESH_PROV_GATT)) {bt_mesh_proxy_prov_enable();bt_mesh_adv_update();}return 0;
}

这里使能 ADV 和 GATT 两个 bearer。

bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);

2.2. 从 MESH ADV 接收一个 mesh beacon

2.2.1 MESH ADV

bt_mesh_scan_enable 使能广播扫描


int bt_mesh_scan_enable(void)
{struct bt_le_scan_param scan_param = {.type       = BT_HCI_LE_SCAN_PASSIVE,.filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_DISABLE,.interval   = MESH_SCAN_INTERVAL,.window     = MESH_SCAN_WINDOW };int err;BT_DBG("");err = bt_le_scan_start(&scan_param, bt_mesh_scan_cb);if (err && err != -EALREADY) {BT_ERR("starting scan failed (err %d)", err);return err;}return 0;
}

配置扫描参数和回调函数。

/** @brief Start (LE) scanning**  Start LE scanning with given parameters and provide results through*  the specified callback.**  @param param Scan parameters.*  @param cb Callback to notify scan results.**  @return Zero on success or error code otherwise, positive in case*  of protocol error or negative (POSIX) in case of stack internal error*/
int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb)
{int err;if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {return -EAGAIN;}/* Check that the parameters have valid values */if (!valid_le_scan_param(param)) {return -EINVAL;}/* Return if active scan is already enabled */if (atomic_test_and_set_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {return -EALREADY;}if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) {err = set_le_scan_enable(BT_HCI_LE_SCAN_DISABLE);if (err) {atomic_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN);return err;}}atomic_set_bit_to(bt_dev.flags, BT_DEV_SCAN_FILTER_DUP,param->filter_dup);err = start_le_scan(param->type, param->interval, param->window);if (err) {atomic_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN);return err;}scan_dev_found_cb = cb;return 0;
}

获取到广播,通过回调函数回调。


static void le_adv_report(struct net_buf *buf)
{u8_t num_reports = net_buf_pull_u8(buf);struct bt_hci_evt_le_advertising_info *info;BT_DBG("Adv number of reports %u",  num_reports);while (num_reports--) {bt_addr_le_t id_addr;s8_t rssi;if (buf->len < sizeof(*info)) {BT_ERR("Unexpected end of buffer");break;}info = net_buf_pull_mem(buf, sizeof(*info));rssi = info->data[info->length];BT_DBG("%s event %u, len %u, rssi %d dBm",bt_addr_le_str(&info->addr),info->evt_type, info->length, rssi);if (info->addr.type == BT_ADDR_LE_PUBLIC_ID ||info->addr.type == BT_ADDR_LE_RANDOM_ID) {bt_addr_le_copy(&id_addr, &info->addr);id_addr.type -= BT_ADDR_LE_PUBLIC_ID;} else {bt_addr_le_copy(&id_addr,find_id_addr(bt_dev.adv_id,&info->addr));}if (scan_dev_found_cb) {struct net_buf_simple_state state;net_buf_simple_save(&buf->b, &state);buf->len = info->length;scan_dev_found_cb(&id_addr, rssi, info->evt_type,&buf->b);net_buf_simple_restore(&buf->b, &state);}#if defined(CONFIG_BT_CENTRAL)check_pending_conn(&id_addr, &info->addr, info->evt_type);
#endif /* CONFIG_BT_CENTRAL */net_buf_pull(buf, info->length + sizeof(rssi));}
}

扫描结果,根据 AD Type 进行处理,这里关注:BT_DATA_MESH_BEACON 0x2b


static void bt_mesh_scan_cb(const bt_addr_le_t *addr, s8_t rssi,u8_t adv_type, struct net_buf_simple *buf)
{if (adv_type != BT_LE_ADV_NONCONN_IND) {return;}BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len));while (buf->len > 1) {struct net_buf_simple_state state;u8_t len, type;len = net_buf_simple_pull_u8(buf);/* Check for early termination */if (len == 0U) {return;}if (len > buf->len) {BT_WARN("AD malformed");return;}net_buf_simple_save(buf, &state);type = net_buf_simple_pull_u8(buf);buf->len = len - 1;switch (type) {case BT_DATA_MESH_MESSAGE:bt_mesh_net_recv(buf, rssi, BT_MESH_NET_IF_ADV);break;
#if defined(CONFIG_BT_MESH_PB_ADV)case BT_DATA_MESH_PROV:bt_mesh_pb_adv_recv(buf);break;
#endifcase BT_DATA_MESH_BEACON:bt_mesh_beacon_recv(buf);break;default:break;}net_buf_simple_restore(buf, &state);net_buf_simple_pull(buf, len);}
}

处理:BEACON_TYPE_SECURE


#define BEACON_TYPE_UNPROVISIONED  0x00
#define BEACON_TYPE_SECURE         0x01void bt_mesh_beacon_recv(struct net_buf_simple *buf)
{u8_t type;BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len));if (buf->len < 1) {BT_ERR("Too short beacon");return;}type = net_buf_simple_pull_u8(buf);switch (type) {//这里不处理 Unprovidioned beacon 证明没有 Provisionner 角色 case BEACON_TYPE_UNPROVISIONED:BT_DBG("Ignoring unprovisioned device beacon");break;case BEACON_TYPE_SECURE:secure_beacon_recv(buf);break;default:BT_WARN("Unknown beacon type 0x%02x", type);break;}
}

下面的函数是根据这个图片描述的格式来处理的。


static void secure_beacon_recv(struct net_buf_simple *buf)
{u8_t *data, *net_id, *auth;struct bt_mesh_subnet *sub;u32_t iv_index;bool new_key, kr_change, iv_change;u8_t flags;if (buf->len < 21) {BT_ERR("Too short secure beacon (len %u)", buf->len);return;}sub = cache_check(buf->data);if (sub) {/* We've seen this beacon before - just update the stats */goto update_stats;}/* So we can add to the cache if auth matches */data = buf->data;flags = net_buf_simple_pull_u8(buf);net_id = net_buf_simple_pull_mem(buf, 8);iv_index = net_buf_simple_pull_be32(buf);auth = buf->data;BT_DBG("flags 0x%02x id %s iv_index 0x%08x",flags, bt_hex(net_id, 8), iv_index);sub = bt_mesh_subnet_find(net_id, flags, iv_index, auth, &new_key);if (!sub) {BT_DBG("No subnet that matched beacon");return;}//因为我们已收到新密钥,所以可以不处理旧密钥的 beaconif (sub->kr_phase == BT_MESH_KR_PHASE_2 && !new_key) {BT_WARN("Ignoring Phase 2 KR Update secured using old key");return;}cache_add(data, sub);//1. 本设备在主网络中;//2. 与当前beacon 信息匹配的 sub(子网络)不是主网络,本设备也加入到了这个 subnet;//也就是收到了子网络的 beacon, 但为什么要忽略呢?/* If we have NetKey0 accept initiation only from it */if (bt_mesh_subnet_get(BT_MESH_KEY_PRIMARY) &&sub->net_idx != BT_MESH_KEY_PRIMARY) {BT_WARN("Ignoring secure beacon on non-primary subnet");goto update_stats;}BT_DBG("net_idx 0x%04x iv_index 0x%08x, current iv_index 0x%08x",sub->net_idx, iv_index, bt_mesh.iv_index);if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR) &&(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) ==BT_MESH_IV_UPDATE(flags))) {bt_mesh_beacon_ivu_initiator(false);}iv_change = bt_mesh_net_iv_update(iv_index, BT_MESH_IV_UPDATE(flags));kr_change = bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(flags), new_key);if (kr_change) {//更新到对应的 beacon 配置,下次发送bt_mesh_net_beacon_update(sub);}if (iv_change) {//IV Index 更新,需要更新到所有subnet/* Update all subnets */bt_mesh_net_sec_update(NULL);} else if (kr_change) {//Key Refresh Flag = 1,只有对应的subnet 需要更新。/* Key Refresh without IV Update only impacts one subnet */bt_mesh_net_sec_update(sub);}update_stats:if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED &&sub->beacons_cur < 0xff) {sub->beacons_cur++;}
}

struct bt_mesh_subnet *bt_mesh_subnet_find() 函数是查找匹配的子网参数,其中sub->keys[] 大小为 2 是因为在更新密钥过程中需要存储2个密钥。

#define BT_MESH_KR_NORMAL         0x00
#define BT_MESH_KR_PHASE_1        0x01
#define BT_MESH_KR_PHASE_2        0x02
#define BT_MESH_KR_PHASE_3        0x03
//返回一个子网信息
struct bt_mesh_subnet *bt_mesh_subnet_find(const u8_t net_id[8], u8_t flags,u32_t iv_index, const u8_t auth[8],bool *new_key)
{int i;for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {struct bt_mesh_subnet *sub = &bt_mesh.sub[i];if (sub->net_idx == BT_MESH_KEY_UNUSED) {continue;}if (auth_match(&sub->keys[0], net_id, flags, iv_index, auth)) {*new_key = false;return sub;}if (sub->kr_phase == BT_MESH_KR_NORMAL) {continue;}if (auth_match(&sub->keys[1], net_id, flags, iv_index, auth)) {*new_key = true;return sub;}}return NULL;
}

2.2.2 GATT ADV, Proxy provisioning

int bt_mesh_proxy_prov_enable(void)
{int i;BT_DBG("");if (gatt_svc == MESH_GATT_PROV) {return -EALREADY;}if (gatt_svc != MESH_GATT_NONE) {return -EBUSY;}bt_gatt_service_register(&prov_svc);gatt_svc = MESH_GATT_PROV;prov_fast_adv = true;for (i = 0; i < ARRAY_SIZE(clients); i++) {if (clients[i].conn) {clients[i].filter_type = PROV;}}return 0;
}

3. Secure Network beacon

每个加入网络的 Relay and Friend nodes 都应该发送 Secure Network beacon,其他设备可以发。
为了防止网络拥堵,预期的行为是:每个节点大约10秒收到一个本网络的 Secure Network beacon,为了确定信标间隔,节点应连续观察信标,并在给定的观察周期内保持子网信标数量的滚动计数。
信标间隔应使用以下公式确定:
Beacon Interval = Observation Period * (Observed Number of Beacons + 1) / Expected Number of Beacons
信标间隔=观测周期*(观测信标数+1)/预期信标数
如果计算的信标间隔小于10秒,则应将其设置为10秒。如果计算的信标间隔大于600秒,则应将其设置为600秒。
以秒为单位的观察周期通常应为典型信标间隔的两倍(10 x 2 = 20秒)。每个子网都有一个单独的 Secure Network beacon ,因此,每个子网的预期信标数量、观察到的信标数量和观察周期可能不同。

4. Unprovisioned Device beacon

Unprovisioned Device beacon 允许未配置设备被 Provisioner 发现。
该信标的格式如图3.45所示,并在表3.53中定义。

[蓝牙 Mesh Zephyr]-[001]-Mesh beacon相关推荐

  1. 蓝牙Sig Mesh 概念入门④——Mesh的专业术语及其操作流程

    文章目录 一. States 二.Bound states 三.Messages 四.Node & Elements 五.Publish & Subscribe 六.Security ...

  2. unity3d 画弧面mesh,抛物线mesh

    unity3d 画弧面mesh,抛物线mesh 废话不多,直接上图,有图有真相 直接上代码 using UnityEngine; using System.Collections;public cla ...

  3. [蓝牙 Mesh Zephyr]-[003]-加入 Mesh 网络

    1. 基础知识 Provisioning 是将未配置设备添加到网状网络的过程,由 Provisioner 管理. Provisioner 为未配置的设备提供配置数据,使其成为网状节点. 配置数据包括网 ...

  4. 蓝牙Sig Mesh 概念入门⑤——Mesh通信消息格式详解

    文章目录 一.Access Layer 二.Transport layer 三.Network layer 3.1 Address 3.2 Network PDU 3.3 Network transm ...

  5. nRF52 Mesh开发 (3) MESH Sensor Server/Client Models详解与实现

    MESH Sensor Model 实现 MESH Spec规定的 Sensor Model 标准 传感器状态 传感器描述 传感器参数设置 传感器cadence 传感器数据 传感器可发送和接收的消息 ...

  6. Telink BLE MESH开发|ble mesh开发教程《三》telink_sig_mesh串口收发数据

    一.前言 官网资料介绍建议采用DMA传输,串口数据的接收是放到了fifo中,但是串口发送也是采用的DMA,问题在于串口发送并没有建立缓冲器,而是判断当前DMA是否忙,如果忙数据直接丢弃,这样做显然不合 ...

  7. 卡巴斯基 2050.earth 源码分享(完整)

    !function(a){var b=/iPhone/i,c=/iPod/i,d=/iPad/i,e=/(?=.*\bAndroid\b)(?=.*\bMobile\b)/i,f=/Android/i ...

  8. 猜解小米5.99元蓝牙Mesh模组

    ​源文链接: https://mp.weixin.qq.com/s?__biz=MzI3NDE2NDMwNQ==&tempkey=MTAzNl90Z1RhQkZSQ2JxS3dybTFOZDR ...

  9. 蓝牙mesh应用开发笔记

    蓝牙mesh实战 基础协议:蓝牙技术联盟(Bluetooth SIG)在2017年发布的蓝牙Mesh协议. 蓝牙mesh系统分层架构 蓝牙mesh系统分层架构如图2.1所示,可以看到蓝牙mesh是基于 ...

  10. 蓝牙mesh基本概念讲解

    https://blog.csdn.net/JaLLs/article/details/88864829 1.蓝牙MESH基本概念 网状网(mesh) Mesh网络,就是一个多对多网络(Many to ...

最新文章

  1. Yann LeCun:距离“真正的” AI,我们还缺什么?
  2. java nei_NEI 接口管理平台
  3. canvas手机端绘图解决方案
  4. 阅读openjdk源代码
  5. cenos 下的一些常用命令及技巧收集篇
  6. 1过程流程图 3 apqp_为什么过程开发的平面布置图要遵循精益原则?
  7. 创建用户故事地图的步骤
  8. NLP硬核入门-隐马尔科夫模型HMM
  9. Spring【DAO模块】就是这么简单
  10. 说说微信聊天记录收费这件事
  11. KVYcam(网络摄像头软件) v13.0.3.0
  12. unity直播推流方式_干货,抖音无人直播技术(建议收藏)
  13. 使用cloudcompare测量平面之间的距离
  14. Unity Navigation烘焙路面与自动寻路
  15. Codeforces 227E/226C Anniversary 斐波那契数列性质+矩阵快速幂
  16. dtcms表单提交数据,获取表单数据,根据表单查询数据,返回查询条数
  17. 如何添加论文参考文献
  18. mysql table plugin,MySql报错Table mysql.plugin doesn’t exist的解决方法
  19. 用C实现解压缩ZIP文件到内存
  20. iOS extern使用教程

热门文章

  1. Codeforces 863B Kayaking 暴力 水题
  2. LivePlayer H5播放器(实时视频和历史视频)
  3. Unity太空大战游戏-Socket网络通信教学示例
  4. 找到一个数组对象中 '某某某(属性名)'为 ['某某','某某']的值
  5. MySQL海量运维管理如何保障京东大促?
  6. Oracle数据库、实例、用户、表空间、表之间的关系
  7. 新浪低调上线开源镜像站
  8. *TEST 7 for NOIP 玄学解题 (150/300)
  9. cve 爬虫_爬虫技术实践(九)国家信息安全漏洞库基于月份的漏洞收集实战
  10. 时间复杂度和空间复杂度OvO