小编相信通过前面序列章节的理论知识基础的铺垫,大体上应该知道整个Mesh的运作流程了吧。然而,小编经常看到有网友迫切希望能用自己手上的开发板去对接天猫精灵来装逼;
正所谓基础不牢地动山摇,如果有读者看了前面章节的内容,尤其是PB-GATT入网过程、 PB-ADV入网过程以及SIG MESH第一个实例---Generic On Off Model;我相信但凡不是太懒的工程师,基本上都能成功地对接上天猫精灵,既然天猫精灵采用的是SIG MESH,那么入网的方式肯定也是符合SIG MESH规范规定的,唯一可能地方就是认证的方式或者密钥的交互会些许不同,其他的入网步骤以及标准模型的操作均是有序可循的;接下来,跟随着小编的节奏让我们看看如何利用红旭的开发板进行天猫精灵对接。
在开始真正的天猫精灵对接之前,我们可以先在天猫精灵官网查看对接的协议规范,以下是小编整理出来的重点:
看过我们红旭PB-GATT入网过程和PB-ADV入网过程的读者应该知道,一个未加入SIG Mesh网络的设备想要加入SIG Mesh网络就必须发送出Unprovisioned Device Beacon,至于该信标的数据帧格式,小编已经在SIG MESH的简介中介绍了,那么天猫精灵对Unprovisioned Device Beacon有什么要求呢?
蓝牙mesh设备上电后如处于未配网状态,需要广播Unprovisioned Device Beacon,每次广播时长40ms,广播间隔100ms,广播持续时间默认10分钟,具体产品的广播启动方式和广播持续时间以产品需求为准。超时后仍未被配网则进入静默广播状态(请参见3.2.1.2 ),低功耗设备不需要进入静默广播状态。
小编其实对这段话的描述是很迷惑的,让我们先来看看一个广播事件是怎么样的:
其中,37、38、39三个广播通道各广播一次数据则称为一个广播事件,而上一个广播事件与下一个广播事件的时间间隔则称为广播间隔;因此,我对广播时长这个概念相当的陌生,甚至怀疑这是天猫精灵对接协议规范的笔误😄(待考证);但是,就算有疑惑也不影响入网,小编就直接使用100ms的广播间隔,因为连接规范还提到了这句话:具体产品的广播启动方式和广播持续时间以产品需求为准;
众所周知,Unprovisioned Device Beacon帧数据包括Device UUID字段,通过天猫精灵的连接协议规范可知,其对该字段是有要求的,具体如下:
Field | Size(Octets) | Notes |
---|---|---|
CID | 2 | 公司ID,设置为0x01A8:Taobao(不可改变) |
PID | 1 | Bit0-3:蓝牙广播包版本号,目前是 0x01 Bit4为1:一机一密 Bit5为1:支持OTA Bit6~7: 00:BLE4.0 01:BLE4.2 10:BLE5.0 11:BLE5.0以上 |
ProductID | 4 | 阿里巴巴平台颁发,一型一号 |
MAC地址 | 6 | 阿里巴巴平台颁发,一型一号 |
FeatureFlag | 1 | Bit7-1:uuid版本号,目前版本为1 Bit0: 0:处于未配网广播状态 1:处于静默广播状态 |
RFU | 2 | 0x00 Reserved for future use |
其中ProductID和MAC地址是三元组中的其中两个由阿里巴巴平台提供的信息,但是有一点比较容易让人混淆的是:虽然阿里巴巴平台提供了Mac地址给你,但是你不要傻傻地去修改自己本机的MAC地址,因为天猫精灵它是根本不理芯片本身自带的MAC地址的,其想要知道的是Device UUID的内容;除了这两个字段之外,还有另外一个FeatureFLag字段,其含义如下表所示:
UUID版本号 | 特性 | 名字待定 |
---|---|---|
0b0000000 | 1.该版本配网流程遵循蓝牙mesh标准规范 | V1.0 |
0b0000001 | 1.该版本优化了配网流程,具体参见3.3.4 2.该版本需要支持vendor model V2.0(参见《蓝牙mesh扩展协议》) | V2.0 |
这里我们只需要使用V1.0的版本即可,因为我们暂时不涉及Vendor Model,如果是使用到Vendor Model则应该使用V2.0,至于如何创建自己的Vendor Model可以参考我们的创建红旭Model;至此,我想信读者们应该知道如何填充自己的Device UUID了吧?这里小编举一个实例:
其中,各字段的解析如下:
CID
0xA801,阿里巴巴的公司ID
PID
0xB1,即10110001,由于红旭的开发板使用的是Nordic 52840只支持到BLE 5.0,所以最高两位数为10
Product ID
由阿里巴巴提供的三元组信息中的一个,这里为0x7D350000
Mac地址
由阿里巴巴提供的三元组信息中的一个,这里为0x9B505C7AFA28
FeatureFlag
0x00,由于我们这里没有使用到Vendor Model,所以UUID版本号为1,
RFU
0x0000,保留为以后使用
但是要切记的是:Device UUID的所有字段都是小端模式,上述提及到的三元组数据从哪里获取得到呢?这个直接在天猫精灵官网申请 (至于怎么申请,小编不再此细述),下图是小编申请得到的三元组信息:
阿里巴巴平台会提供10组三元组用于调试时使用,如果后续产品要量产的话,则需要向阿里巴巴平台购买三元组,下图就是小编申请到的其中一组三元组信息:
在天猫精灵的连接协议规范中,提及到Auth Value的计算,原文如下:
关于OOB的认证方式,小编在SIG MESH第一个实例---Generic On Off Model中就已经提及,Mesh Specification共支持Static、Input、Output三种认证方式,具体如下图所示:
根据上述的描述,间接地说明天猫精灵的入网只支持Static OOB的Authentication方式;对于该值的计算,小编以自己申请到的一个三元组信息为例:
AuthValue = SHA256(0000357d,28fa7a5c509b,9b73f697bc7252f1ba3616c721b17a40) = 4c01a92f1b747b4695d1acc3eddcc854d1f31025c01203c355e848bd1dadf14f
至于SHA256加密,小编直接用在线的加解密工具来计算AuthValue,需要注意的是:计算的内容如果有带字母的话,则一定要是小写;但是,这里指的AuthValue并不是Mesh入网时的AuthValue,而是Mesh中的16字节Static OOB信息,用于计算得到Mesh的AuthValue;
由上述的Device UUID以及AuthValue可知,天猫精灵的Mesh入网对接只需要更改这两个内容即可,是不是很简单?不怕你们说小编装逼,从查看天猫精灵资料到成功对接上天猫精灵,小编花了三个多小时,这全归功于前面打下的Mesh基础;
其中,Device UUID的修改如下所示:
xstatic void mesh_init(void)
{
const uint8_t custom_device_uuid[] = {0xA8,0x01,\ /* CID,阿里巴巴公司名 */
0xB1,\ /* PID,产品ID */
0x7D,0x35,0x00,0x00,\ /* Product ID,由阿里巴巴平台提供 */
0x9b,0x50,0x5c,0x7a,0xfa,0x28,\ /* MAC,由阿里巴巴平台提供 */
0x00,\ /* Feature Flag */
0x00,0x00 /* RFU */
};
mesh_stack_init_params_t init_params =
{
.core.irq_priority = NRF_MESH_IRQ_PRIORITY_LOWEST,
.core.lfclksrc = DEV_BOARD_LF_CLK_CFG,
.core.p_uuid = custom_device_uuid,//NULL,
.models.models_init_cb = models_init_cb,
.models.config_server_cb = config_server_evt_cb
};
uint32_t status = mesh_stack_init(&init_params, &m_device_provisioned);
switch (status)
{
case NRF_ERROR_INVALID_DATA:
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Data in the persistent memory was corrupted. Device starts as unprovisioned.\n");
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Reset device before start provisioning.\n");
break;
case NRF_SUCCESS:
break;
default:
ERROR_CHECK(status);
}
}
其中custom_device_uuid就是我们的Device UUID,而天猫精灵的AuthValue则更简单了,具体的修改如下:
xxxxxxxxxx
static void start(void)
{
rtt_input_enable(app_rtt_input_handler, RTT_INPUT_POLL_PERIOD_MS);
if (!m_device_provisioned)
{
//0000357d,28fa7a5c509b,9b73f697bc7252f1ba3616c721b17a40
static const uint8_t static_auth_data[NRF_MESH_KEY_SIZE] = CUSTOM_STATIC_AUTH_DATA; /* 天猫精灵的AuthValue */
mesh_provisionee_start_params_t prov_start_params =
{
.p_static_data = static_auth_data,
.prov_sd_ble_opt_set_cb = NULL,
.prov_complete_cb = provisioning_complete_cb,
.prov_device_identification_start_cb = device_identification_start_cb,
.prov_device_identification_stop_cb = NULL,
.prov_abort_cb = provisioning_aborted_cb,
.p_device_uri = NULL//EX_URI_LS_SERVER
};
ERROR_CHECK(mesh_provisionee_prov_start(&prov_start_params));
}
else
{
unicast_address_print();
}
mesh_app_uuid_print(nrf_mesh_configure_device_uuid_get());
ERROR_CHECK(mesh_stack_start());
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, m_usage_string);
hal_led_mask_set(LEDS_MASK, LED_MASK_STATE_OFF);
hal_led_blink_ms(LEDS_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_START);
}
其中p_device_uri的内容不需要赋值,NULL即可。
注意事项:
从上图的描述可知:
当UUID版本为0时,天猫精灵只会向首元素发送Mesh Config Model Appkey Bind以及Mesh Config Model Subscription Add消息,其余的则需要用户自己行绑定及地址订阅
当UUID版本为1时,天猫精灵只会向首元素发送Mesh Config Model Appkey Add以及Mesh Config Model Subscription Add消息,其余的则需要用户自己行绑定及地址订阅;但是,小编在实际捉包的时候,仍然会向首元素发送Mesh Config Model Subscription Add
至于,需要自行绑定Appkey或订阅地址,则可以调用以下API函数实现:
如果是用的红旭的无线开发板V2.0,则还需要修改一处地方,否则在配置入网的过程中会出现协议栈断言错误:
app_error_weak.c, 96, Softdevice assert: xxxxxx:0
这是因为V2.0用的外部的低速晶振是+-10ppm的,而官方例程的默认配置是+-20ppm,具体的修改如下:
xxxxxxxxxx
/ <o> NRF_SDH_CLOCK_LF_ACCURACY - External clock accuracy used in the LL to compute timing.
// <0=> NRF_CLOCK_LF_ACCURACY_250_PPM
// <1=> NRF_CLOCK_LF_ACCURACY_500_PPM
// <2=> NRF_CLOCK_LF_ACCURACY_150_PPM
// <3=> NRF_CLOCK_LF_ACCURACY_100_PPM
// <4=> NRF_CLOCK_LF_ACCURACY_75_PPM
// <5=> NRF_CLOCK_LF_ACCURACY_50_PPM
// <6=> NRF_CLOCK_LF_ACCURACY_30_PPM
// <7=> NRF_CLOCK_LF_ACCURACY_20_PPM
// <8=> NRF_CLOCK_LF_ACCURACY_10_PPM
// <9=> NRF_CLOCK_LF_ACCURACY_5_PPM
// <10=> NRF_CLOCK_LF_ACCURACY_2_PPM
// <11=> NRF_CLOCK_LF_ACCURACY_1_PPM
当然,如果是用的红旭的无线开发板V1.0,则无须做任何的变更。