【WCH蓝牙系列芯片】-基于CH592开发板—修改应用蓝牙从机的Indicate属性
-------------------------------------------------------------------------------------------------------------------------------------
1、Notify(通知)方式
一种单向通信机制,蓝牙从机向蓝牙主机发送数据,但不需要主机设备对这些数据进行确认响应。意味着一旦蓝牙从机设备发送了Notify数据,它就不再关心蓝牙主机设备是否已经接收到这些数据。
适用于传感器数据更新使用,比如温度传感器,需要实时更新数据,但对数据丢失的容忍度较高。如:当服务器(从机设备)的特征值(温度传感器数据)发生变化,并且该特征配置了通知属性(GATT_PROP_NOTIFY),服务器(从机设备)可以发送一个通知数据包给客户端(主机设备)。客户端(主机设备)接收到通知数据后,无需发送任何确认响应。服务器(从机设备)发送数据后,不会等待客户端(主机设备)的确认,直接认为数据已经成功发送。

一种双向通信机制,
-
服务器(从机设备)发送数据:当服务器(从机设备)的某个特征值发生变化,并且该特征配置了指示属性(
GATT_PROP_INDICATE),服务器(从机设备)可以发送一个指示数据包给客户端(主机设备)。 -
客户端(主机设备)接收并确认:客户端(主机设备)接收到指示数据后,必须发送一个确认响应(Confirmation)给服务器(从机设备)。服务器(从机设备)在收到确认响应后,才能发送下一条指示数据。
适用于设备的蓝牙控制命令或者重要状态信息,需要确保数据要被主机设备接收到。需要确保数据完整性和可靠性。适用于可靠性要求较高的场景

在基于CH592芯片在Peripheral(从机程序)上添加实现Indication功能。
一、将特征指4属性修改,将原先的Notify属性改为indication属性

在特征定义表格中,特征值4的读写属性中,与Notify的配置的属性表一样

二、在特征值4中修改indication属性数据发送函数
在gattprofile.c中,仿造simpleProfile_Notify改写一个simpleProfile_Indicate函数,先是取客户端特征配置,判断是否启用了指示功能,然后设置数据句柄,发送indication数据。

bStatus_t simpleProfile_Indicate(uint16_t connHandle, attHandleValueInd_t *pInd, uint8_t taskId) { uint16_t value = GATTServApp_ReadCharCfg(connHandle, simpleProfileChar4Config); // 读取客户端特征配置,以确定是否启用了指示 printf(" value = %02x \r\n",value); // If notifications enabled if(value & GATT_CLIENT_CFG_INDICATE) // 如果指示已启用 { // Set the handle pInd->handle = simpleProfileAttrTbl[SIMPLEPROFILE_CHAR4_VALUE_POS].handle; // 设置指示数据的句柄 // Send the notification return GATT_Indication(connHandle, pInd, FALSE, taskId); // 发送指示 } return bleIncorrectMode; // 如果指示未启用,返回错误状态 }
在gattprofile.c中simpleProfile_WriteAttrCB写操作中进行修改,改为GATT_CLIENT_CFG_INDICATE

三、在peripheral.c文件中,添加修改indication属性数据函数,根据peripheralChar4Notify函数重新添加一个peripheralChar4Indicate函数
这里是原本notify的功能修改为Indication。Indication和Notification的区别之处,就是在进行参数传递的时候多传递了一个taskId,这是蓝牙协议规定Indication发送后,对方必须发送一个确认响应(Confirmation)返回。这个确认必须要有一个对应的实体也就是task去接收并且处理(也可以不处理,只是当作一个Indication成功的通知,接收这个动作是必须的)。所以Indication发送的时候必须要提前制定确认消息的接收task ID。这里就会通过simpleProfile_Indicate() 被应用层调用来指定发送的Indication的值和接收确认消息的task ID,一般就由应用层task本身接收,这里taskId的含义是即将被Indication响应的任务。

//修改为Indication static void peripheralChar4Indicate(uint8_t *pValue, uint16_t len) { bStatus_t rs; // 定义一个状态变量,用于存储函数返回值 attHandleValueInd_t indi; // 定义一个 attHandleValueInd_t 结构体,用于指示消息 indi.len = len; // 设置指示数据的长度 indi.pValue = GATT_bm_alloc( peripheralConnList.connHandle, ATT_HANDLE_VALUE_IND, indi.len, NULL,0); // 分配内存用于存储指示数据 if(indi.pValue) // 如果内存分配成功 { tmos_memcpy(indi.pValue, pValue, indi.len); // 将要发送的数据复制到分配的内存中 if(simpleProfile_Indicate(peripheralConnList.connHandle, &indi, Peripheral_TaskID) != SUCCESS) // 调用 simpleProfile_Indicate 函数发送指示 { GATT_bm_free((gattMsg_t *)&indi, ATT_HANDLE_VALUE_IND); // 如果发送指示失败,释放分配的内存 } } }
在利用TMOS任务,通过发送performPeriodicTask()函数,将peripheralChar4Indicate(notiData, SIMPLEPROFILE_CHAR4_LEN)函数,把notiData定义的数值的数发送出去。实现1秒一次通过Indication发送数据。


4、将手机作为蓝牙主机,通过蓝牙调试助手去连接蓝牙从机,接收Indication属性发送的数据,验证Indication属性的功能。
将修改好的从机程序烧录程序在芯片中,用NRF_CONNECT调试工具连接,在UUID为0xFFE4上,可以看到具有Indication属性,并且能够获取到从机Indication属性发送的数据(0x11,0x22,0x33,0x44)

在主机程序中,连接从机之后,进行枚举服务,使能启动写入CCCD操作


在TMOS事件中,对CCCD写入操作中,按照接收NOTIFY的程序改造一下,其中更具协议规定, 将req.pValue的值得更改。
req.pValue[0] = 2;
req.pValue[1] = 0;
这样就可以使能Indication的属性,来接收从机发来的Indication数据

在centralProcessGATTMsg函数中,添加接收Indication数据,并打印每一个字节,接收完数据之后,由于Indication属性在发送完数据之后,就得进行回应确认状态,所以调用 ATT_HandleValueCfm 函数发送确认响应。函数返回 Confirmation_status 状态值,0 表示确认发送成功。
如果不进行状态回复确认,就无法发送下一次的Indication属性数据。

在从机程序中, 也可以添加函数,进行接收主机已经接收到Indication属性数据的应答操作,从而从机进行下一包的数据的发送。
添加传递任务消息函数,主机Confirmation应答回复后,从机会进入peripheralProcessGATTMsg函数,进行确认。


通过串口打印的方式,观察整个主机和从机的运行情况,交互数据,并且看应答过程

浙公网安备 33010602011771号