目录
一、实现原理
控制LED灯亮灭是作为一个BLE的服务,通过修改该服务的特征值来实现开关的控制。
实现对特征值的读写要有服务、特征声明、特征值声明。首先在gattprofile.c文件中建立属性表,表中包含服务、特征声明、特征值声明、特征用户描述(非必须);服务、特征声明、特征值声明、特征用户描述,都属于属性每个属性都有其对应的UUID;UUID又包含不同属性类型的UUID值。
》属性表定义
//定义一个服务
static const gattAttrType_t ledProfileService = {ATT_BT_UUID_SIZE, ledProfileServUUID};
//特征值初始化
// 特征值属性,读或者写
static uint8_t ledProfileCharProps = GATT_PROP_READ | GATT_PROP_WRITE;
// 值,可以向其写入数据,也可以读出数据。这里是一个字符数组
static uint8_t ledProfileChar[LEDPROFILE_CHAR_LEN] = {0};
// 用户描述,展现给用户的名字
static uint8_t ledProfileCharUserDesp[] = "Led_Contral\0";
//属性表
static gattAttribute_t ledProfileAttrTb[]=
{
//led priofile service
{
{ATT_BT_UUID_SIZE,primaryServiceUUID}, //type(属性类型) 属性类型:主服务primaryServiceUUIDd为0x2800即主服务类型。
GATT_PERMIT_READ, //permissions(GATT客户端对于该属性的权限) 即客户端对于该服务的权限,GATT_PERMIT_READ客户端可以发现这个服务。
0, //handle(表中属性的索引) 即在这个属性表中的位置指明这是在这个数组中的第几个数组元素,因为这个句柄是协议栈自动分配的,因此默认初始化为0
(uint8 *)&ledProfileService //pValue(指向属性值的指针) 用自己定义的UUID值0xFFF0来指向这个服务
},
//characteristic Declaration
{
{ATT_BT_UUID_SIZE,characterUUID}, //属性类型:特征值 characterUUID为0x2803即特征值类型
GATT_PERMIT_READ, //数组这个元素权限为可读
0,
&ledProfileCharProps //ledProfileCharProps描述的是特征值具有的属性(指读写属性),一个是权限一个是属性。
},
//characteristic Value
{
{ATT_BT_UUID_SIZE,ledProfilecharUUID}, //特征值的自定义UUID
GATT_PERMIT_READ | GATT_PERMIT_WRITE, //权限为可读可写,要与特征值类型描述里的ledProfileCharProps特征值属性一致。
0,
ledProfileChar //特征值存放地方,就是修改里面的内容实现特征值的读写
},
//charateristic User Description
{
{ATT_BT_UUID_SIZE,charUserDescUUID}, //特征描述的UUID
GATT_PERMIT_READ,
0,
ledProfileCharUserDesp //描述的内容
},
};
》注册服务
主要通过BLE的库函数GATTServApp_RegisterService(),将GATT表注册到BLE STACK里,以及设置读写回调函数。
//读写回调设置
gattServiceCBs_t ledProfileCBs = {
ledProfile_ReadAttrCB, // Read callback function pointer
ledProfile_WriteAttrCB, // Write callback function pointer
NULL // Authorization callback function pointer
};
//注册服务函数
bStatus_t LedProfile_Addservice(uint32 services)
{
uint8 status = SUCCESS;
if(services & LEDPROFILE_SERVICE)
{
status = GATTServApp_RegisterService(ledProfileAttrTb, //属性表
GATT_NUM_ATTRS(ledProfileAttrTb),
GATT_MAX_ENCRYPT_KEY_SIZE,
&ledProfileCBs); //读写回调函数有数据读写时调到读写函数中
}
return (status);
}
》属性读回调
//读写回调
static bStatus_t ledProfile_ReadAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t *pLen, uint16_t offset, uint16_t maxLen, uint8_t method)
{
bStatus_t status =SUCCESS;
if(gattPermitAuthenRead(pAttr->permissions))
{
return(ATT_ERR_INSUFFICIENT_AUTHOR);
}
if( offset > 0)
{
return(ATT_ERR_ATTR_NOT_LONG);
}
if(pAttr->type.len == ATT_BT_UUID_SIZE)
{
uint16 uuid = BUILD_UINT16(pAttr->type.uuid[0],pAttr->type.uuid[1]);
switch(uuid)
{
case LEDPROFILE_CHAR_UUID:
*pLen = LEDPROFILE_CHAR_LEN;
tmos_memcpy(pValue, pAttr->pValue, LEDPROFILE_CHAR_LEN);
printf("Led_read\r\n");
break;
default:
*pLen = 0;
status = ATT_ERR_ATTR_NOT_FOUND;
break;
}
}
else {
*pLen = 0;
status = ATT_ERR_INVALID_HANDLE;
}
return(status);
}
static bStatus_t ledProfile_WriteAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t len, uint16_t offset, uint8_t method)
{
bStatus_t status =SUCCESS;
uint8 notifyApp = 0xFF;
if(gattPermitAuthenWrite(pAttr->permissions))
{
return(ATT_ERR_INSUFFICIENT_AUTHOR);
}
if(pAttr->type.len == ATT_BT_UUID_SIZE)
{
uint16 uuid = BUILD_UINT16(pAttr->type.uuid[0],pAttr->type.uuid[1]);
switch(uuid)
{
case LEDPROFILE_CHAR_UUID:
if(offset == 0)
{
if(len > LEDPROFILE_CHAR_LEN)
{
status = ATT_ERR_INVALID_VALUE_SIZE;
}
}
else {
status = ATT_ERR_ATTR_NOT_LONG;
}
if(status == SUCCESS)
{
tmos_memcpy(pAttr->pValue, pValue, LEDPROFILE_CHAR_LEN);
notifyApp = LEDPROFILE_CHAR;
}
printf("LED_write\r\n");
break;
default:
status = ATT_ERR_ATTR_NOT_FOUND;
break;
}
}
else {
status = ATT_ERR_INVALID_HANDLE;
}
// If a charactersitic value changed then callback function to notify application of change
if ( (notifyApp != 0xFF ) && ledProfile_AppCBs && ledProfile_AppCBs->pfnledProfileChange )
{
ledProfile_AppCBs->pfnledProfileChange( notifyApp, pValue, len );
}
return ( status );
}
上述内容参考文章:
【BLE 5.3无线MCU CH582】11、手机app控制led亮灭 - 国产芯片交流 - 电子工程世界-论坛
二、写回调函数的学习理解
//在peripheral.c 中调用注册服务函数
LedProfile_Addservice(GATT_ALL_SERVICES);
将ledProfileAttrTb,和回调函数ledProfileCBs注册GATT服务中。
/*****************************************************************/
//在peripheral.c 注册回调函数
LedProfile_RegisterAppCBs(&Peripheral_ledProfileCBs);
bStatus_t LedProfile_RegisterAppCBs(ledProfileCBs_t *appCallbacks)
{
if(appCallbacks)
{
ledProfile_AppCBs = appCallbacks;
return (SUCCESS);
}
else
{
return (bleAlreadyInRequestedMode);
}
}
执行完这个函数 相当于ledProfile_AppCBs这个函数指针指向接收数据的函数
ledProfileChangeCB(uint8 paramID,uint8 *pValue,uint16 len)
/*****************************************************************/
//对应写回调函数中的这一段
If a charactersitic value changed then callback function to notify application of change
if ( (notifyApp != 0xFF ) && ledProfile_AppCBs && ledProfile_AppCBs->pfnledProfileChange )
{
ledProfile_AppCBs->pfnledProfileChange( notifyApp, pValue, len );
}
//即在写回调函数最后跳转到 ledProfile_AppCBs指向的 ledProfileChangeCB
中对APP写入到BLE的数据进行处理
//接收主机数据进行处理
static void ledProfileChangeCB(uint8 paramID,uint8 *pValue,uint16 len)
{
switch(paramID)
{
case LEDPROFILE_CHAR:
{
uint8 newValue[LEDPROFILE_CHAR_LEN];
tmos_memcpy(newValue, pValue, len);
if(newValue[0])
{
printf("led_on\r\n");
GPIOB_SetBits(GPIO_Pin_6);
}
else {
printf("led_off\r\n");
GPIOB_ResetBits(GPIO_Pin_6);
}
break;
}
default:
break;
}