NRF52系列多个 base uuid 的问题,以client为例。

news2024/11/24 6:37:58

基础uuid知识

nordic的nrf sdk希望我们设置uuid的方式跟蓝牙技术联盟SIG的方式一样,也就是服务和特性的uuid是基于同一个base uuid修改产生的,比如base uuid是0x0000xxxx-0000-1000-8000-00805F9B34FB,那么服务和特性的128bit uuid就要基于此base uuid通过修改其中的xxxx而生成,这里的xxxx称为16bit的uuid。一般来说,base uuid和16bit的xxxx都是自定义的,但是xxxx的位置一定是在128bit uuid的第三和第四个字节,这就是标准的限制。

在nus_c的例程里,有这样一段代码:

#define NUS_BASE_UUID                   {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor-specific UUID. */

#define BLE_UUID_NUS_SERVICE            0x0001                      /**< The UUID of the Nordic UART Service. */
#define BLE_UUID_NUS_RX_CHARACTERISTIC  0x0002                      /**< The UUID of the RX Characteristic. */
#define BLE_UUID_NUS_TX_CHARACTERISTIC  0x0003                      /**< The UUID of the TX Characteristic. */

这段代码自定义了一个BASE_UUID,注意它是按小端模式存储的(跟一般顺序反过来的),数组里面的第13和第14个字节对应到128bit uuid的第4和第3个字节,也就是对应到xxxx这两个字节共16bit,数组里面设置为0了。

由以上代码可以知道,三个uuid分别为:

6E400001-B5A3-F393-E0A9-E50E24DCCA9E(16bit uuid为0x0001 )
6E400002-B5A3-F393-E0A9-E50E24DCCA9E(16bit uuid为0x0002 )
6E400003-B5A3-F393-E0A9-E50E24DCCA9E(16bit uuid为0x0002 )

然后,在ble_nus_c.c里面的ble_nus_c_init()函数里面,调用sd_ble_uuid_vs_add()函数将base uuid添加到协议栈:

ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;    
err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_ble_nus_c->uuid_type);

其中p_ble_nus_c->uuid_type是协议栈返回的uuid类型,0为非法,1为sig的base uuid,往后的数字就是咱们自己添加到协议栈的uuid编号,也就是说,如果我们只添加了一个base uuid到协议栈,那么uuid_type就会被协议栈设置为2。

接下来是特征的发现,在ble_nus_c_on_db_disc_evt()里面。

void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt)
{
    ble_nus_c_evt_t nus_c_evt;
    memset(&nus_c_evt,0,sizeof(ble_nus_c_evt_t));

    ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;

    // Check if the NUS was discovered.
    if (    (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
        &&  (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_NUS_SERVICE)
        &&  (p_evt->params.discovered_db.srv_uuid.type == p_ble_nus_c->uuid_type))
    {
        for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
        {
            switch (p_chars[i].characteristic.uuid.uuid)
            {
                case BLE_UUID_NUS_RX_CHARACTERISTIC:
                    nus_c_evt.handles.nus_rx_handle = p_chars[i].characteristic.handle_value;
                    break;

                case BLE_UUID_NUS_TX_CHARACTERISTIC:
                    nus_c_evt.handles.nus_tx_handle = p_chars[i].characteristic.handle_value;
                    nus_c_evt.handles.nus_tx_cccd_handle = p_chars[i].cccd_handle;
                    break;

                default:
                    break;
            }
        }
        if (p_ble_nus_c->evt_handler != NULL)
        {
            nus_c_evt.conn_handle = p_evt->conn_handle;
            nus_c_evt.evt_type    = BLE_NUS_C_EVT_DISCOVERY_COMPLETE;
            p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
        }
    }
}

在服务的if判断中,它判断了uuid_type以及16位的uuid是否和我们想要的一致,实际上由于一个uuid_type对应一个base uuid,由base uuid和16位uuid是可以得到完整的128bit uuid的,所以可以认为是进行了完整的服务uuid的对比,也就是:

  • uuid_type 唯一对应一个 uuid base
  • uuid_base + 16bit uuid  可以得到 128bit uuid

接下来看swtich,这里是遍历属性表,并把需要用到的特性handle记录下来,注意看这里只对16bit uuid作了比较,这是因为nrf sdk认为特性的base uuid 应该是要和服务的 base uuid 相同,所以就省去了uuid_type的对比。

多个base uuid的问题

那么问题来了,有的厂商的设备不是按照上面的方式定义uuid,服务和特性的base uuid不同可咋办。比如说,有一个设备,它的uuid如下:

Service:                   49535343-FE7D-4AE5-8FA9-9FAFD205E455
data Characteristic: 49535343-1E4D-4BD9-BA61-23C647249616
cmd Characteristic: 49535343-8841-43F4-A8D4-ECBE34729BB3

看着真的挺离谱的,不按标准来真的麻烦。那么如果要连接这个设备,并发现服务和特性,应该咋搞呢,那还能咋搞,那就认为有多个base uuid呗。

首先还是按照xxxx在第3和4字节的标准来定义三个base uuid和三个16bit uuid,注意base uuid是小端存储的,因此数组第14和13字节都设置为0.

#define SERVICE_UUID_BASE     {{0x55,0xe4,0x05,0xd2,0xaf,0x9f,0xa9,0x8f,0xe5,0x4a,0x7d,0xfe,0x00,0x00,0x53,0x49}}
#define DATA_UUID_BASE 		  {{0x16,0x96,0x24,0x47,0xC6,0x23,0x61,0xBA,0xD9,0x4B,0x4d,0x1e,0x00,0x00,0x53,0x49}}
#define CMD_UUID_BASE 		  {{0xb3,0x9b,0x72,0x34,0xbe,0xec,0xd4,0xa8,0xf4,0x43,0x41,0x88,0x00,0x00,0x53,0x49}}

#define BLE_UUID_SERVICE                0x5343
#define BLE_UUID_DATA_CHARACTERISTIC    0x5343
#define BLE_UUID_CMD_CHARACTERISTIC     0x5343

然后到ble_nus_c_init()里面,把三个uuid全注册到协议栈里面。一个base uuid对应一个uuid_type,uuid_type实际上就是协议栈分配的编号,为了保存对应的uuid_type,设置了一些全局变量。

static ble_uuid_t data_uuid;   //用于存储特性1的uuid_type
static ble_uuid_t cmd_uuid;    //用于存储特性2的uuid_type
//服务的uuid_type记录在p_ble_nus_c里面了,而这本来就是个全局变量,所以不另外存储服务的uuid_type

****** 以上两个全局变量是在ble_nus_c_init()之外定义的 *****
*********************************************************
******** 以下语句是在ble_nus_c_init()内的语句 ************

ble_uuid128_t service_base_uuid  =  SERVICE_UUID_BASE;
ble_uuid128_t data_base_uuid     =  DATA_UUID_BASE;
ble_uuid128_t cmd_base_uuid      =  CMD_UUID_BASE;

err_code = sd_ble_uuid_vs_add(&service_base_uuid , &p_ble_nus_c->uuid_type);
VERIFY_SUCCESS(err_code);
err_code = sd_ble_uuid_vs_add(&data_base_uuid , &data_uuid.type);
VERIFY_SUCCESS(err_code);
err_code = sd_ble_uuid_vs_add(&cmd_base_uuid , &cmd_uuid.type);
VERIFY_SUCCESS(err_code);

data_uuid.uuid = BLE_UUID_DATA_CHARACTERISTIC;
cmd_uuid.uuid  = BLE_UUID_CMD_CHARACTERISTIC;

以上语句向协议栈注册了三个base uuid,需要在sdk_config.h里面修改uuid的数量,如下图所示:

同时,这样操作会增大协议栈所需的RAM,因此如果出现报错,应该把 log level 提升到dubug级别,观察协议栈的log输出是否提示说内存不足,并根据log输出的建议修改app ram的起始大小和总大小。下图为修改log level的截图。

根据log的提示去修改IRAM1:

 在向协议栈注册base uuid之后,接下来看服务和特性的发现函数,在ble_nus_c_on_db_disc_evt()里面。

void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt)
{
    ble_nus_c_evt_t nus_c_evt;
    memset(&nus_c_evt,0,sizeof(ble_nus_c_evt_t));

    ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;

    if (  (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE) &&
          (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_SERVICE) &&
          (p_evt->params.discovered_db.srv_uuid.type == p_ble_nus_c->uuid_type) )
    {
        for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
        {
			if(p_chars[i].characteristic.uuid.uuid == BLE_UUID_CMD_CHARACTERISTIC && p_chars[i].characteristic.uuid.type == cmd_uuid.type){
                    nus_c_evt.handles.cmd_handle = p_chars[i].characteristic.handle_value;
			}else if(p_chars[i].characteristic.uuid.uuid == BLE_UUID_DATA_CHARACTERISTIC && p_chars[i].characteristic.uuid.type == data_uuid.type){
                    nus_c_evt.handles.data_handle = p_chars[i].characteristic.handle_value;
                    nus_c_evt.handles.cccd_handle = p_chars[i].cccd_handle;
			}
         }
				
        if (p_ble_nus_c->evt_handler != NULL)
        {
            nus_c_evt.conn_handle = p_evt->conn_handle;
            nus_c_evt.evt_type    = BLE_NUS_C_EVT_DISCOVERY_COMPLETE;
            p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
        }
    }
}

以上函数跟之前的唯一变化就是,在遍历属性库的时候,需要同时对比特性的uuid_type和16bit uuid,而之前是仅对比16bit uuid的。多做了uuid_type的对比判断,其实就是多做了uuid base的对比判断,有了uuid base的对比判断,就能准确识别处所需要特性的handle,哪怕本案例中所有16bit uuid是一样的。

总结:

1. 16bit uuid一定是在128bit uuid的第三和第四个字节,这是标准、是规范。

2. 按照规范来设置uuid,那么当只有一个base uuid 时,在对服务的uuid_type和16bit uuid进行对比之后,特性只需要对比16bit uuid即可。

3. 如果不按照规范,即服务和特性的base uuid不同时,就需要向协议栈注册多个base uuid,并记录下对应的uuid_type(可以认为是该base uuid在协议栈中的编号)。

4. 需要修改sdk_config.h中uuid的个数,修改应用的RAM起始地址和大小。

5. 遍历属性表时,无论是服务和特性,都需要同时对16bit uuid和uuid type进行对比判断。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/588390.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java8内部调用无法引用值的问题

问题&#xff1a;Variable used in lambda expression should be final or effectively final 具体原因&#xff1a; 这段代码试图将 20 赋给一个局部变量&#xff0c;它无法通过编译&#xff0c;但绝非编写错误。 这实际上是语言的设计者有意为之&#xff0c;用以鼓励用户使用…

优化版本 穿越火线(CF) FPS AI 自瞄 代码 权重 数据集(下面有链接)

更新初衷 本人在制作过程中&#xff0c;有一些爱钻研的朋友来问以及提出增加一些新的功能点回会更好&#xff0c;本着学习研究态度&#xff0c;在第一个版本上进行优化&#xff0c;增加一些内容 不喜欢看过程的小伙伴直接看最下面 界面 解决问题&#xff1a; 1、进入慢 2、无…

PyTorch-完整的模型训练套路

目录 1. 准备 1.1 使用Cifar10 1.2 item的用法 1.3 model的搭建 1.4 数据集、参数设置以及训练开始 1.5 测试集 1.6 使用tensorboard 1.7 保存每一轮的训练结果 2. 计算整体的正确率 3. 其他 3.1 train与eval 3.2 使用GPU训练 1. 准备 1.1 使用Cifar10 1.2 item的…

微信小程序授权登录

微信小程序—授权登录 一、小程序登录 登录流程时序 说明: 1.小程序端调用 wx.login() 获取临时登录凭证code &#xff0c;并回传到开发者服务器。 2.服务器调用 code2Session 接口&#xff0c;换取 用户唯一标识 OpenID 和 会话密钥 session_key。 之后开发者服务器可以根…

2021年长三角高校数学建模竞赛A题Go!Fun游长三角解题全过程文档及程序

2021年长三角高校数学建模竞赛 A题 Go!Fun游长三角 原题再现&#xff1a; 又到一年毕业季&#xff0c;来自浙江杭州的一位大学生小李同学&#xff0c;家境良好&#xff0c;平时学习刻苦&#xff0c;在即将毕业之际&#xff0c;准备给自己安排一个毕业旅行&#xff0c;同时帮助…

Java 高级应用-多线程-实现 Runnable 接口与继承 Thread 类

1.1 程序、进程与线程 • 程序&#xff08;program&#xff09;&#xff1a;为完成特定任务&#xff0c;用某种语言编写的一组指令的集合。即指一段 静态的代码&#xff0c;静态对象。 • 进程&#xff08;process&#xff09;&#xff1a;程序的一次执行过程&#xff0c;或是正…

转变范式:如何使用 5 种新模式重塑 2023 年的实体店体验

在电商盛行的当下&#xff0c;线上购物已成为新零售的重要组成部分&#xff0c;实体零售业正处于两难境地。一方面&#xff0c;实体零售是绝对有必要的&#xff1a;美国约 85% 的销售额来自实体商店。 另一方面&#xff0c;尽管增长放缓&#xff0c;但电商收入占销售总额的比例…

chatgpt赋能python:Python中图形怎么整体下移?

Python中图形怎么整体下移&#xff1f; 在Python中&#xff0c;我们常常需要处理各种各样的图形&#xff0c;但是有时候我们需要将图形进行整体调整&#xff0c;比如将所有图形下移一定距离。那么在Python中&#xff0c;我们该如何实现这个操作呢&#xff1f; 介绍 在Python…

【Linux】3、iptables

文章目录 一、设置其他机器均无法访问 a、b、c 机器的 5432 端口二、设置 d、e 可访问 a、b、c 的 5432 端口三、检查业务是否受到影响 iptables 可在 tcp 协议栈层面限制访问&#xff0c;常用于解决现场的各漏洞。 场景&#xff1a;现场有 a、b、c 三个机器组成的 postgres 集…

经纬恒润AUTOSAR成功适配智芯科技国产车规级芯片

近日&#xff0c;经纬恒润AUTOSAR基础软件产品INTEWORK-EAS-CP成功适配智芯半导体的Z20K14x产品家族。同时&#xff0c;经纬恒润完成了对智芯半导体Z20K14X 产品MCAL软件适配和工程集成&#xff0c;为智芯半导体提供了全套AUTOSAR解决方案。 左图&#xff1a;经纬恒润AUTOSAR E…

iOS 创建组件库

索引库 repo 索引文件(.podspec文件) 1.搭建私有库之前必须要先创建索引库 1&#xff09;首先检查当前电脑的索引库 pod repo 2&#xff09;在gitlab上创建一个新的库&#xff0c;这个库用来保存私有库的podspec文件&#xff0c;所以我们一般起名字最好是 xxxSpec用以区分…

回归预测 | MATLAB实现SSA-CNN-BiLSTM麻雀算法优化卷积双向长短期记忆神经网络多输入单输出回归预测

回归预测 | MATLAB实现SSA-CNN-BiLSTM麻雀算法优化卷积双向长短期记忆神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现SSA-CNN-BiLSTM麻雀算法优化卷积双向长短期记忆神经网络多输入单输出回归预测预测效果基本介绍模型描述程序设计学习总结参考资料 预测效果 基本介…

在虚拟机上部署hadoop集群(全流程)

一、单节点部署前置准备 这里一直下一步就好了 接下来需要为该节点固定ip并配置相关网关还有dns解析 这里配置了一个本机dns解析,也配置了一个公网dns解析(主要目的还是为了固定ip

知识变现:知识付费产品,怎么定价?

知识变现&#xff1a;知识付费产品&#xff0c;怎么定价&#xff1f; 定价&#xff0c;是知识博主或者培训机构、用户、竞争对手间博弈平衡后的结果。 200元以下: 只有产品&#xff0c;没有服务。 产品的特征是标准化、大批量。这样的知识产品&#xff0c;要卖给几千、几万…

CSS 实现一个动态水形波浪蒙版层

需求的最终实现效果&#xff0c;如下图&#xff0c;在盒子表面&#xff0c;绘制一个波浪形状的蒙版层&#xff08;动态的&#xff09;。 先定义一个&#xff0c;主体盒子块&#xff0c;等会儿的蒙版图层会覆盖到它的上面。 <div></div>图层采用&#xff0c;SVG进…

Spring Boot 如何自定义异常处理器

Spring Boot自定义异常处理器 在Spring Boot应用程序中&#xff0c;异常处理是一个非常重要的方面。如果您不处理异常&#xff0c;应用程序可能会崩溃或出现不可预料的行为。默认情况下&#xff0c;Spring Boot将未捕获的异常返回给客户端。这通常不是期望的行为&#xff0c;因…

【Java基础】注解与反射

一、学习笔记 &#xff08;本文内容基本源自参考链接1视频教程&#xff09; 1、注解的含义 1&#xff09;注解&#xff08;annotation)是从jdk5.0开始引入的新技术&#xff0c;其作用&#xff1a;不是程序本身&#xff0c;可对程序作解释&#xff08;该作用与注释comment相同…

iOS 性能优化方案-弱网优化

一、iPhone手机弱网环境配置 选择现有网络状态 或自定义网络状态 设置参数: 每个参数的含义大致如下: in bandwidth &#xff1a;下行带宽 in packet loss &#xff1a;下行丢包率 in delay &#xff1a;下行延迟(ms) out bandwidth &#xff1a;上行带宽 out packet los…

【解决】升级g++到8版本

升级g到8版本 g不提高到最新版本在一些操作会头文件报错&#xff0c;因此下面我们配置g编译器 要升级g编译器到版本8&#xff0c;您可以尝试以下步骤&#xff1a; 添加Developer Toolset存储库&#xff1a;在CentOS上&#xff0c;可以使用Red Hat Developer Toolset存储库来获…

PMP课堂模拟题目及解析(第15期)

141. 在新项目的干系人会议中&#xff0c;项目经理发现一名干系人对项目有抵触。项目经理记录这个问题&#xff0c;并对该干系人的参与程度评级。项目经理使用了哪项工具或技术来为干系人的参与程度评级&#xff1f; A. 干系人参与评估矩阵 B. 风险概率和影响评估 C. 人际关…