蓝牙协议栈主从机之间发送数据,先讲主机给从机发送数据。然后是从机给主机发送数据。
1.Initialize GATT attributes (初始化GATT属性表)
SimpleProfile_AddService( GATT_ALL_SERVICES ); // Simple GATT Profile
---->
2.注册属性列表 and 回调函数 simpleProfileCBs。 这是GATT Server App干的事。
// Register GATT attribute list and CBs with GATT Server App
status = GATTServApp_RegisterService( simpleProfileAttrTbl,
GATT_NUM_ATTRS( simpleProfileAttrTbl ),
&simpleProfileCBs );
---->
3.属性表simpleProfileAttrTbl,根据自己需要自己添加需要的UUID,及修改具体项的值。
---->
4.simpleProfileCBs
// Simple Profile Service Callbacks
CONST gattServiceCBs_t simpleProfileCBs =
{
simpleProfile_ReadAttrCB, // Read callback function pointer
simpleProfile_WriteAttrCB, // Write callback function pointer
NULL // Authorization callback function pointer
};
---->
5.simpleProfile_WriteAttrCB,主机给从机发送数据,会进入这个函数。通过不同的特征值通道发送数据,会进入switch下,不同的uuid,做不同处理。
特别注意的是:GATT_CLIENT_CHAR_CFG_UUID。当从机给主机发送数据之前,要先打开通知,而这个GATT_CLIENT_CHAR_CFG_UUID,就是主机打开通知进入的通道。
ble tool软件,有一个选择要通知/读的。。按钮,一单击这个按钮,主机就会给从机发送,打开通知的数据,就会进入GATT_CLIENT_CHAR_CFG_UUID。
simpleProfile_WriteAttrCB函数里面,最后一段代码,是通知APP层pfnSimpleProfileChange,某个uuid通道有值过来了。
// If a charactersitic value changed then callback function to notify application of change
if ( (notifyApp != 0xFF ) && simpleProfile_AppCBs && simpleProfile_AppCBs->pfnSimpleProfileChange )
{
simpleProfile_AppCBs->pfnSimpleProfileChange( notifyApp );
}
{
// If attribute permissions require authorization to write, return error
if ( gattPermitAuthorWrite( pAttr->permissions ) )
{
// Insufficient authorization
return ( ATT_ERR_INSUFFICIENT_AUTHOR );
}
if ( pAttr->type.len == ATT_BT_UUID_SIZE )
{
// 16-bit UUID
uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
switch ( uuid )
{
case SIMPLEPROFILE_CHAR1_UUID:
...
break;
case SIMPLEPROFILE_CHAR2_UUID:
...
break;
case SIMPLEPROFILE_CHAR3_UUID:
...
break;
case SIMPLEPROFILE_CHAR4_UUID:
...
break;
case SIMPLEPROFILE_CHAR5_UUID:
...
break;
case SIMPLEPROFILE_CHAR6_UUID:
...
break;
case GATT_CLIENT_CHAR_CFG_UUID:
{
//status = ATT_ERR_INVALID_HANDLE;
status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,
offset, GATT_CLIENT_CFG_NOTIFY );
}
break;
default:
// Should never get here! (characteristics 2 and 4 do not have write permissions)
status = ATT_ERR_ATTR_NOT_FOUND;
break;
}
}
else
{
// 128-bit UUID
status = ATT_ERR_INVALID_HANDLE;
}
// If a charactersitic value changed then callback function to notify application of change
if ( (notifyApp != 0xFF ) && simpleProfile_AppCBs && simpleProfile_AppCBs->pfnSimpleProfileChange )
{
simpleProfile_AppCBs->pfnSimpleProfileChange( notifyApp );
}
}
---->
6.simpleProfileChangeCB,就是上面的回调函数,看这个函数的代码。
上层(APP层)收到数据后的操作,是把接受到的数据再发送回去,即从机接受到主机发送过来的数据,再把数据,发送给主机。
我们知道从机发送给主机的函数调用的是GATT_Notification()。这个函数GUA_SimpleGATTprofile_Char6_Notify(nGUA_ConnHandle, nbGUA_Char6, 20);是经过封装过的。它里面有函数GATT_Notification()。
static void simpleProfileChangeCB( uint8 paramID )
{
uint8 newValue;
uint16 nGUA_ConnHandle;
uint8 nbGUA_Char6[20] = {0};
switch( paramID )
{
case SIMPLEPROFILE_CHAR1:
SimpleProfile_GetParameter( SIMPLEPROFILE_CHAR1, &newValue );
//获取连接句柄
GAPRole_GetParameter(GAPROLE_CONNHANDLE, &nGUA_ConnHandle);
//读取char6的数值
SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR1, &newValue);
//发送数据
GUA_SimpleGATTprofile_Char1_Notify(nGUA_ConnHandle, &newValue, 1);
#if (defined HAL_LCD) && (HAL_LCD == TRUE)
HalLcdWriteStringValue( "Char 1:", (uint16)(newValue), 10, HAL_LCD_LINE_3 );
#endif // (defined HAL_LCD) && (HAL_LCD == TRUE)
break;
case SIMPLEPROFILE_CHAR3:
SimpleProfile_GetParameter( SIMPLEPROFILE_CHAR3, &newValue );
#if (defined HAL_LCD) && (HAL_LCD == TRUE)
HalLcdWriteStringValue( "Char 3:", (uint16)(newValue), 10, HAL_LCD_LINE_3 );
#endif // (defined HAL_LCD) && (HAL_LCD == TRUE)
break;
//char6
case SIMPLEPROFILE_CHAR6:
{
//获取连接句柄
GAPRole_GetParameter(GAPROLE_CONNHANDLE, &nGUA_ConnHandle);
//读取char6的数值
SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR6, &nbGUA_Char6);
//发送数据
GUA_SimpleGATTprofile_Char6_Notify(nGUA_ConnHandle, nbGUA_Char6, 20);
break;
}
default:
// should not reach here!
break;
}
}
--->
--->
总结:
主机给从机发送数据,调用的是函数simpleProfile_WriteAttrCB(),从机给主机发送数据,调用的是函数GATT_Notification()。当然从机在给主机发送数据的时候,要填充数据。GUA_SimpleGATTprofile_Char6_Notify()实现过程如下:
void GUA_SimpleGATTprofile_Char6_Notify(uint16 nGUA_ConnHandle, uint8 *pGUA_Value, uint8 nGUA_Len)
{
attHandleValueNoti_t stGUA_Noti;
uint16 nGUA_Return;
//读出CCC的值
nGUA_Return = GATTServApp_ReadCharCfg(nGUA_ConnHandle, simpleProfileChar6Config);
//判断是否打开通知开关,打开了则发送数据
if (nGUA_Return & GATT_CLIENT_CFG_NOTIFY)
{
//填充数据
stGUA_Noti.handle = simpleProfileAttrTbl[20].handle;
aa_tmp = simpleProfileAttrTbl[20].handle;
stGUA_Noti.len = nGUA_Len;
osal_memcpy(stGUA_Noti.value, pGUA_Value, nGUA_Len);
//发送数据
GATT_Notification(nGUA_ConnHandle, &stGUA_Noti, FALSE);
}
}
还没有评论,来说两句吧...