蓝牙mesh组网实践(常见调试问题整理)
①初始化及配网过程中出错
②发送模型返回错误代码
③发送方成功,接收方丢包
①初始化及配网过程中出错
1.1.返回错误代码-16,表示给dataflash分配的单个扇区的空间不够,需要加大CONFIG_MESH_SECTOR_SIZE_DEF。
1.2.返回错误代码-2,表示重复配网。对于运用到自配网的例程,烧录代码时没有清空dataflash,易见此错误。更改配网信息,直接调用bt_mesh_provision()不能覆盖原有的网络信息,会报错-2;需要调用bt_mesh_reset重置一下节点,再调用bt_mesh_provision()函数来配网;或者擦除datafalsh后,调用SYS_ResetExecute()复位一下从头运行配网。
1.3.配网连接关闭,返回原因9,表示超时。检查一下信号是否正常,若信号良好的情况下必定复现,检查一下配网器与未配网设备在app_mesh_config.h中的CONFIG_MESH_UNSEG_LENGTH_DEF宏是否一致。如果需要兼容标准mesh协议,CONFIG_MESH_UNSEG_LENGTH_DEF需要设置为7。
1.4.启用了flash存储功能后,dataflash中保存的网络信息,会在运行到blemesh_on_sync过程中的settings_load函数时恢复。如果发现代码运行到settings_load时进入了死循环,通常意味着dataflash被篡改,检查一下是否有代码破坏了dataflash中保存的数值。如果dataflash被误修改,排查一下原因后再烧录时清空dataflash或者再代码中擦除datafalsh即可。
在代码中,mesh初始化之前,调用EEPROM_READ函数,可以打印flash中保存的配网信息情况。打印出的是已经解密的内容,可以查看保存的数值是否正确。默认mesh协议栈占用的dataflash首地址从0开始,占用3个扇区,每个扇区大小4K,配网信息只占用最前面的部分,即默认保存在dataflash首地址起往后的200个字节内。
settings_load函数中没有判断配网信息是否合法的过程,可以在运行到settings_load前自行添加判断。比如说对于自配网代码,在codeflash中保存一个数值,如果dataflash中的网络信息与codefalsh中的数值不一致,则清空dataflash,重新配网。再比如说配网时规定好了net key带有奇偶校验(奇偶校验附加数据保存在另外的dataflash区域),那恢复前检查一下net key是否复合原先的奇偶校验。最保险还是用一个定时器来监控,类似看门狗,长时间卡死就清空dataflash然后复位。
②发送模型返回错误代码
常见错误代码可以在《沁恒低功耗蓝牙MESH软件开发参考手册.pdf》中7.1.2小节查到。
2.1.返回错误代码-1,表示找不到发送参数或者参数非法。
如果发送方是非配网器的节点,检查一下模型的app key是否成功绑定。可以在代码中读dataflash打印出来看看数值是否正常,如上,或者利用ISP工具读dataflash查看是否保存网络信息。保存网络信息的数据的起始位置由CONFIG_MESH_NVS_ADDR_DEF这个宏决定,默认是0。可以利用ISP工具读dataflash查看实际写在dataflash中的数值。不过由于涉及加密,实际写的数值与应用层看到的数值不同,右边解密后的ascii码只能看出有没有保存,实际写的的数值是否正确直接看hex是看不出的。
如果发送方是配网器,还需要再关注一下串口打印,或者轮询app_nodes结构体数组的node_addr成员,检查一下有没有给目标地址配网,有可能找不到目标地址。
2.2.返回错误代码-4,表示当前已有一个发包流程正在执行,需要等待其执行完毕。
vendor_model_srv_send函数中:
配置.trans_cnt=1,每一包都会往底层的发包缓存队列填(默认10包的那个队列),可以短时间内调用多次vendor_model_srv_send(本质上是调用的bt_mesh_model_send)。但是多次调用vendor_model_srv_send,用来标志模型层的包编号.tid,每次调用都会+1。当应用层想重发同一个包时,一般将TID配置为相同数值。
配置.trans_cnt>1,每隔.period,会往底层的发包缓存队列填1个包(同一时刻只占用队列中的1包)。但是发包申请的内存内存(srv_trans.buf->__buf = tmos_msg_allocate(len + 8))是在.trans_cnt中最后一包填到底层,才会释放;释放前,再调用vendor_model_srv_send会报错-4。好处是在模型层用于区别是否重发的.tid,都是相同的,可以被接受方识别到“本包为重传包”,不再往应用层上报。
。
2.3.返回错误代码-6,表示还没配网就往外发包了,需要配网之后再发包。常见的情景是配网器那边繁忙,正在被配网的节点已经发到了NET_KEY,但是配网器分发APP_KEY慢了,导致被配网的节点触发超时,自己把自己的配网信息清空了,等待下次配网;清空配网信息和下次配网期间,调用发包接口函数,会报错-6。
2.4.返回错误代码-7,表示发送缓存已满。上层每调用单次发送,会占用一个Net数据缓存,底层发送完成后自动释放。发送参数中的。可以调大app_mesh_config.h中的CONFIG_MESH_ADV_BUF_COUNT_DEF,或者减小send接口函数的发送参数param中的发送次数trans_cnt,或者等待底层发送完成后再发下一则消息,都可以减小发包压力。
2.5.返回错误代码-8,表示根据2字节的app index没有找到16字节的app key。使用函数struct bt_mesh_app_key *bt_mesh_app_key_find( uint16_t app_idx )检索一下发送参数中的app index是否能够检索到对应的key。
2.6.返回错误代码-9,表示内存占用已满,需要扩大给蓝牙库分配的大小即BLE_MEMHEAP_SIZE,注意该值会占用ram,也不宜过大。
③发送方成功,接收方丢包
建议两蓝牙mesh节点的布置距离在100m以内,如果距离太远且没有中继,或者TTL数值不够没有中继到,或者干扰太大,真的没收到包,那没办法在代码层面处理。如果收发双方距离适当,检查接收方是否真的“丢包”,就需要查看一些底层参数。蓝牙mesh不走连接,所有通信数据最终都走广播发出,需要一套机制来过滤消息,故存在有底层能够解析消息包,但被判断无需上报的情况。
3.1.检查一下发送方的seq num是否正常,发消息时的seq num是否在前一则消息的seq num上+1。接收方会记录发送方的历史消息的seq num,若接收方判断此刻收到的消息的seq num不比缓存的历史消息的seq num大,则判断其为过往消息,不再处理,也就不会上报。最新EVT中包含有查询seq num和设置seq num的接口函数。设置目标seq num时,除了要小于0xb0e500外,还要比当前seq num数值大。
3.2.检查一下接收方的tid,与seq num类似,每则消息都需要tid值自+1。如果收到消息时的tid一直解析为同一个数值,该消息会被判断为重复消息而不上报。可以在app_vendor_model_srv.c 中打印tid值。如果一直重复,需要检查一下发送方发消息时的发送参数是否设置有误。
3.3.IV值不同步也会造成接收方不再上报消息。待配网节点,需要配网器为其配网时,设置IV值为正在工作的网络中的IV值;待自配网节点,需要第三方介入,获取一下当前网络中的IV值,传递给自配网节点后进行自配网。最新EVT中包含了获取IV值的接口函数。若发现某一方的IV值与网络中的不一致,需要重新配网以设置IV值。