KW38 定制型材 此自定义配置文件示例使用温度传感器和温度收集器示例作为基础,因此可以轻松修改。这两个示例都在SDK中,因此本文档解释了如何添加湿度配置文件,以及如何修改代码以使湿度传感器和收集器工作。
简介
通用属性配置文件 (GATT) 详细规定了如何通过 BLE 连接交换所有配置文件和用户数据。GATT 仅处理实际的数据传输程序和格式。所有标准 BLE 配置文件均基于 GATT,并且必须遵守它才能正常运行。这使得 GATT 成为 BLE 规范的关键部分,因为与应用程序和用户相关的每一项数据都必须按照规则进行格式化、打包和发送。
GATT定义了两个角色:服务器和客户端。
GATT 服务器存储通过属性协议 (ATT) 传输的数据,并接受来自 GATT 客户端的属性协议请求、命令和确认。
GATT 客户端通过读取、写入、通知或指示操作访问远程 GATT 服务器上的数据。通知和指示操作由客户端启用但由服务器发起,提供一种向客户端推送数据的方法。通知未被确认,而指示已被确认。因此,通知速度更快,但可靠性较低。
Snagit Custom Profile Client Server.png
GATT 数据库建立了一个层次结构来组织属性。这些属性包括配置文件、服务、特性和描述符。配置文件是高级定义,用于定义如何使用服务来启用应用程序;服务是特性的集合。描述符定义了描述特性值的属性。
Snagit Custom Profile Levels.png
为了定义 GATT 数据库,Freescale BLE Stack 中的 GATT_DB API 提供了几个宏,它是 KW38 SDK 的一部分。
服务器(传感器)
首先,我们需要使用温度传感器项目作为基础,创建我们的湿度自定义配置文件服务器(传感器)。
BLE SIG profiles
要知道配置文件或服务是否已在规范中定义,您必须在蓝牙 SIG 配置文件中查找并检查ble_sig_defines.h如果代码中已经声明了该文件( ${workspace_loc:/ ${ProjName} /bluetooth/host/interface )。在我们的案例中,没有声明服务,但是规范中声明了湿度的特性。然后,我们需要检查该特性是否已经包含在ble_sig_defines.h中。由于未包含该特征,我们需要按如下所示定义它:
/*! Humidity Charactristic UUID */
#define gBleSig_Humidity_d 0x2A6F
GATT Database
湿度传感器将作为 GATT 服务器,因为它将拥有供 GATT 客户端使用的所有信息。
在温度传感器演示中有电池服务和设备信息,因此您只需将温度服务更改为湿度服务
Snagit Custom Profile Humidity.png
为了创建演示,我们需要定义或开发一个与 GATT 客户端相同的服务,该服务在 gatt_uuid128.h 中声明。如果新服务与 GATT 客户端不同,它们将无法相互通信。SDK 中的所有宏、函数或结构都有一个通用模板,可帮助应用程序相应地执行操作。因此,我们需要在gatt_uuid128.h中定义此服务,如下所示:
/* Humidity */
UUID128(uuid_service_humidity, 0xfe ,0x34 ,0x9b ,0x5f ,0x80 ,0x00 ,0x00 ,0x80 ,0x00 ,0x10 ,0x00 ,0x02 ,0x00 ,0xfa ,0x10 ,0x10)
所有服务和特性均在gattdb.h中声明。描述符在特征值声明之后但在下一个特征声明之前声明。在这种情况下,权限是具有标准具体描述的 CharPresFormatDescriptor。湿度特征的单位是百分比,即0x27AD 。
客户端特性配置描述符 (CCCD) 是客户端写入一些位来激活服务器通知和/或指示的描述符。
PRIMARY_SERVICE_UUID128(service_humidity, uuid_service_humidity)
CHARACTERISTIC(char_humidity, gBleSig_Humidity_d, (gGattCharPropNotify_c))
VALUE(value_humidity, gBleSig_Humidity_d, (gPermissionNone_c), 2, 0x00, 0x25)
DESCRIPTOR(desc_humidity, gBleSig_CharPresFormatDescriptor_d, (gPermissionFlagReadable_c), 7, 0x0E, 0x00, 0xAD, 0x27, 0x00, 0x00, 0x00)
CCCD(cccd_humidity)
之后,在下一个路径${workspace_loc:/ ${ProjName} /bluetooth/profiles中创建一个文件夹humidity。找到温度文件夹,复制温度服务.c并将其粘贴到湿度文件夹内,并使用另一个名称(湿度服务.c )。然后回去寻找interface文件夹,复制temporary_interface.h并在同一路径中更改名称( humidity_interface.h )。
您需要包含所创建文件夹的路径。项目属性>C/C+ 构建>设置>工具设置>MCU C 编译器>包括:
Ricardo_Zamora_0-1619646619427.png
湿度接口
moisture_interface.h文件应该有以下代码。
服务结构具有服务句柄和初始化值。
/*! Humidity Service - Configuration */
typedef struct humsConfig_tag {
uint16_t serviceHandle;
int16_t initialHumidity;
} humsConfig_t;
/*! Humidity Client - Configuration */
typedef struct humcConfig_tag {
uint16_t hService;
uint16_t hHumidity;
uint16_t hHumCccd;
uint16_t hHumDesc;
gattDbCharPresFormat_t humFormat;
} humcConfig_t;
湿度服务
至少在humidity_service.c上文件,应该有以下代码。
该服务存储已连接客户端的设备标识。此值在订阅和非订阅事件时更改。
/*! Humidity Service - Subscribed Client*/
static deviceId_t mHums_SubscribedClientId;
通过调用启动过程来完成服务的初始化。该函数通常在应用程序初始化时调用。在这种情况下,是在 BleApp_Config() 上。
bleResult_t Hums_Start(humsConfig_t *pServiceConfig)
{
mHums_SubscribedClientId = gInvalidDeviceId_c;
/* Set the initial value of the humidity characteristic */
return Hums_RecordHumidityMeasurement(pServiceConfig->serviceHandle,
pServiceConfig->initialHumidity);
}
在停止功能时,将调用取消订阅功能。
bleResult_t Hums_Stop(humsConfig_t *pServiceConfig)
{
/* Stop functionality by unsubscribing */
return Hums_Unsubscribe();
}
bleResult_t Hums_Unsubscribe(void)
{
/* Unsubscribe by invalidating the client ID */
mHums_SubscribedClientId = gInvalidDeviceId_c;
return gBleSuccess_c;
}
订阅功能将在主文件中使用,以便 GATT 客户端订阅湿度服务。
bleResult_t Hums_Subscribe(deviceId_t clientDeviceId)
{
/* Subscribe by saving the client ID */
mHums_SubscribedClientId = clientDeviceId;
return gBleSuccess_c;
}
根据服务的复杂程度,API 将实现额外的功能。对于湿度传感器只有一个特性。
测量值将保存到 GATT 数据库中,并向客户端发送通知。此函数需要服务句柄和新值作为输入参数。
bleResult_t Hums_RecordHumidityMeasurement(uint16_t serviceHandle, int16_t humidity)
{
uint16_t handle;
bleResult_t result;
bleUuid_t uuid = Uuid16(gBleSig_Humidity_d);
/* Get handle of Humidity characteristic */
result = GattDb_FindCharValueHandleInService(serviceHandle,
gBleUuidType16_c, &uuid, &handle);
if (result != gBleSuccess_c)
return result;
/* Update characteristic value */
result = GattDb_WriteAttribute(handle, sizeof(uint16_t), (uint8_t*) &humidity);
if (result != gBleSuccess_c)
return result;
Hts_SendHumidityMeasurementNotification(handle);
return gBleSuccess_c;
}
使用 GattDb_WriteAttribute 函数将测量结果保存在 GATT 数据库后,我们发送通知。
要发送通知,首先需要获取CCCD,然后检查通知是否处于活跃状态。如果通知处于活跃状态,则发送通知。
static void Hts_SendHumidityMeasurementNotification
(
uint16_t handle
)
{
uint16_t hCccd;
bool_t isNotificationActive;
/* Get handle of CCCD */
if (GattDb_FindCccdHandleForCharValueHandle(handle, &hCccd)
!= gBleSuccess_c)
return;
if (gBleSuccess_c == Gap_CheckNotificationStatus
(mHums_SubscribedClientId, hCccd, &isNotificationActive) &&
TRUE == isNotificationActive)
{
GattServer_SendNotification(mHums_SubscribedClientId, handle);
}
}
湿度传感器主文件
为了在我们的传感器示例中使用新的湿度曲线,必须进行一些修改。
首先,我们需要声明湿度服务:
Ricardo_Zamora_1-1619647031739.png
static humsConfig_t humsServiceConfig = {(uint16_t)service_humidity, 0};
然后,我们需要添加或者修改以下函数:
BlApp_启动
您需要修改此行:
Ricardo_Zamora_2-1619647129208.png
/* Device is connected, send humidity value */
BleApp_SendHumidity();
BleApp_Config
您需要启动湿度服务,并修改 PrintString 行:
Ricardo_Zamora_3-1619647184184.png
humsServiceConfig.initialHumidity = 0;
(void)Hums_Start(&humsServiceConfig);
AppPrintString("\r\nHumidity sensor -> Press switch to start advertising.\r\n");
BleApp_连接回调
两个连接事件需要进行一些修改。
连接
Ricardo_Zamora_4-1619647250926.png
(void)Hums_Subscribe(peerDeviceId);
gConnEvtDisconnected_c
gConnEvtDisconnected_c
Ricardo_Zamora_0-1619647637262.png
(void)Hums_Unsubscribe();
BleApp_GattServerCallback
Ricardo_Zamora_1-1619647701427.png
/* Notify the humidity value when CCCD is written */
BleApp_SendHumidity()
BleApp_发送湿度
并且,我们需要添加这个函数:
Ricardo_Zamora_2-1619647746232.png
static void BleApp_SendHumidity(void)
{
(void)TMR_StopTimer(appTimerId);
/* Update with initial humidity */
(void)Hums_RecordHumidityMeasurement((uint16_t)service_humidity,
(int16_t)(BOARD_GetTemperature()));
#if defined(cPWR_UsePowerDownMode) && (cPWR_UsePowerDownMode)
/* Start Sleep After Data timer */
(void)TMR_StartLowPowerTimer(appTimerId,
gTmrLowPowerSecondTimer_c,
TmrSeconds(gGoToSleepAfterDataTime_c),
DisconnectTimerCallback, NULL);
#endif
}
在此示例中,记录湿度使用 BOARD_GetTemperature,使用没有任何外部传感器的示例并能够看到收集器中的变化,但是,在本节中将使用 GetHumidity 函数。
客户(收藏家)
首先,我们需要使用温度收集器项目作为基础,创建我们的湿度自定义配置文件客户端(收集器)。
BLE SIG profiles
这同样适用于客户。要知道配置文件或服务是否已在规范中定义,您必须在蓝牙 SIG 配置文件中查找并检查ble_sig_defines.h如果代码中已经声明了该文件( ${workspace_loc:/ ${ProjName} /bluetooth/host/interface )。在我们的案例中,没有声明服务,但是规范中声明了湿度的特性。然后,我们需要检查该特性是否已经包含在ble_sig_defines.h中。由于未包含该特征,我们需要按如下所示定义它:
/*! Humidity Charactristic UUID */
#define gBleSig_Humidity_d 0x2A6F
GATT Database
湿度收集器将配备 GATT 客户端;该设备将从 GATT 服务器接收所有信息。
本文提供的演示的工作原理类似于温度收集器。当收集器启用来自传感器的通知时,收到的通知将打印在串行终端上。
为了创建演示,我们需要定义或开发一个必须与 GATT 服务器相同的服务,这在 gatt_uuid128.h 中声明。如果新服务不一样,它们将永远无法相互通信。SDK 中的所有宏、函数或结构都有一个通用模板,可帮助应用程序采取相应的行动。因此,我们需要在gatt_uuid128.h中定义此服务如下所示:
/* Humidity */
UUID128(uuid_service_humidity, 0xfe ,0x34 ,0x9b ,0x5f ,0x80 ,0x00 ,0x00 ,0x80 ,0x00 ,0x10 ,0x00 ,0x02 ,0x00 ,0xfa ,0x10 ,0x10)
之后,将湿度配置文件文件夹从传感器项目复制到收集器项目${workspace_loc:/ ${ProjName} /bluetooth/profiles 。对于这个项目,还包括新文件夹的路径。项目属性>C/C+ 构建>设置>工具设置>MCU C 编译器>包括:
Ricardo_Zamora_3-1619647932968.png
湿度收集器主文件
在收集器源文件中,我们还需要做一些修改,以使用湿度配置文件。
首先我们需要修改Peer设备的自定义信息:
Ricardo_Zamora_0-1619720069736.png
humcConfig_t humsClientConfig;
BleApp_StoreServiceHandles
Ricardo_Zamora_1-1619720107622.png
static void BleApp_StoreServiceHandles
(
gattService_t *pService
)
{
uint8_t i,j;
if ((pService->uuidType == gBleUuidType128_c) &&
FLib_MemCmp(pService->uuid.uuid128, uuid_service_humidity, 16))
{
/* Found Humidity Service */
mPeerInformation.customInfo.humsClientConfig.hService = pService->startHandle;
for (i = 0; i < pService->cNumCharacteristics; i++)
{
if ((pService->aCharacteristics[i].value.uuidType == gBleUuidType16_c) &&
(pService->aCharacteristics[i].value.uuid.uuid16 == gBleSig_Humidity_d))
{
/* Found Humudity Char */
mPeerInformation.customInfo.humsClientConfig.hHumidity = pService->aCharacteristics[i].value.handle;
for (j = 0; j < pService->aCharacteristics[i].cNumDescriptors; j++)
{
if (pService->aCharacteristics[i].aDescriptors[j].uuidType == gBleUuidType16_c)
{
switch (pService->aCharacteristics[i].aDescriptors[j].uuid.uuid16)
{
/* Found Humidity Char Presentation Format Descriptor */
case gBleSig_CharPresFormatDescriptor_d:
{
mPeerInformation.customInfo.humsClientConfig.hHumDesc = pService->aCharacteristics[i].aDescriptors[j].handle;
break;
}
/* Found Humidity Char CCCD */
case gBleSig_CCCD_d:
{
mPeerInformation.customInfo.humsClientConfig.hHumCccd = pService->aCharacteristics[i].aDescriptors[j].handle;
break;
}
default:
; /* No action required */
break;
}
}
}
}
}
}
}
BleApp_StoreDescValues
Ricardo_Zamora_3-1619720232121.png
if (pDesc->handle == mPeerInformation.customInfo.humsClientConfig.hHumDesc)
{
/* Store Humidity format*/
FLib_MemCpy(&mPeerInformation.customInfo.humsClientConfig.humFormat,
pDesc->paValue,
pDesc->valueLength);
}
BleApp_打印湿度
Ricardo_Zamora_4-1619720253851.png
/*www.bluetooth.com/specifications/assigned-numbers/units */
if (mPeerInformation.customInfo.humsClientConfig.humFormat.unitUuid16 == 0x27ADU)
{
AppPrintString(" %\r\n");
}
else
{
AppPrintString("\r\n");
}
BleApp_GattNotification回调
Ricardo_Zamora_5-1619720342076.png
if (characteristicValueHandle == mPeerInformation.customInfo.humsClientConfig.hHumidity)
{
BleApp_PrintHumidity(Utils_ExtractTwoByteValue(aValue));
}
检查扫描事件
Ricardo_Zamora_6-1619720374078.png
foundMatch = MatchDataInAdvElementList(&adElement, &uuid_service_humidity, 16);
BleApp_StateMachineHandler
mAppIdle_c
Ricardo_Zamora_7-1619720411241.png
if (mPeerInformation.customInfo.humsClientConfig.hHumidity != gGattDbInvalidHandle_d)
mAppServiceDisc_c
Ricardo_Zamora_8-1619720466660.png
if (mPeerInformation.customInfo.humsClientConfig.hHumDesc != 0U) mpCharProcBuffer->handle = mPeerInformation.customInfo.humsClientConfig.hHumDesc;
mAppReadDescriptor_c
Ricardo_Zamora_9-1619720517344.png
if (mPeerInformation.customInfo.humsClientConfig.hHumCccd != 0U)
BleApp_配置通知
Ricardo_Zamora_10-1619720543249.png
mpCharProcBuffer->handle = mPeerInformation.customInfo.humsClientConfig.hHumCccd;
演示
现在,连接后,每次按下 KW38 湿度传感器上的 SW3 都会将值发送到 KW38 湿度收集器。
Ricardo_Zamora_14-1619720689734.png Ricardo_Zamora_13-1619720681169.png BLE软件 千瓦
View full article