蓝牙4.0协议编程之回调函数
2015-07-14 15:12
295 查看
蓝牙4.0协议编程之回调函数
基于TI公司蓝牙4.0协议转载出处:http://blog.csdn.net/zhcx2011/article/details/9010541
1.回调函数概念
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。2.回调函数实现的机制
⑴定义一个回调函数;⑵提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;
⑶当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。
3.代码实例分析
实现第一步,定义结构和函数体:
在gapbondmgr.h文件中定义
Passcode回调函数
[html] view
plaincopy
/**
* Passcode Callback Function
*/
typedef void (*pfnPasscodeCB_t)
(
uint8 *deviceAddr, //!< address of device to pair with, and could be either public or random.
uint16 connectionHandle, //!< Connection handle
uint8 uiInputs, //!< Pairing User Interface Inputs - Ask user to input passcode
uint8 uiOutputs //!< Pairing User Interface Outputs - Display passcode
);
绑定状态回调函数
[html] view
plaincopy
/**
* Pairing State Callback Function
*/
typedef void (*pfnPairStateCB_t)
(
uint16 connectionHandle, //!< Connection handle
uint8 state, //!< Pairing state @ref GAPBOND_PAIRING_STATE_DEFINES
uint8 status //!< Pairing status
);
定义回调函数结构体
[html] view
plaincopy
/**
* Callback Registration Structure
*/
typedef struct
{
pfnPasscodeCB_t passcodeCB; //!< Passcode callback
pfnPairStateCB_t pairStateCB; //!< Pairing state callback
} gapBondCBs_t;
在simpleBLECentral.c文件中定义
回调函数结构体实例:[cpp] view
plaincopy
// Bond Manager Callbacks
static const gapBondCBs_t simpleBLEBondCB =
{
simpleBLECentralPasscodeCB,
simpleBLECentralPairStateCB
};
函数体:
[cpp] view
plaincopy
static void simpleBLECentralPasscodeCB( uint8 *deviceAddr, uint16 connectionHandle,
uint8 uiInputs, uint8 uiOutputs )
{
#if (HAL_LCD == TRUE)
uint32 passcode;
uint8 str[7];
// Create random passcode
LL_Rand( ((uint8 *) &passcode), sizeof( uint32 ));
passcode %= 1000000;
// Display passcode to user
if ( uiOutputs != 0 )
{
LCD_WRITE_STRING( "Passcode:", HAL_LCD_LINE_1 );
LCD_WRITE_STRING( (char *) _ltoa(passcode, str, 10), HAL_LCD_LINE_2 );
}
// Send passcode response
GAPBondMgr_PasscodeRsp( connectionHandle, SUCCESS, passcode );
#endif
}
[html] view
plaincopy
static void simpleBLECentralPairStateCB( uint16 connHandle, uint8 state, uint8 status )
{
if ( state == GAPBOND_PAIRING_STATE_STARTED )
{
LCD_WRITE_STRING( "Pairing started", HAL_LCD_LINE_1 );
}
else if ( state == GAPBOND_PAIRING_STATE_COMPLETE )
{
if ( status == SUCCESS )
{
LCD_WRITE_STRING( "Pairing success", HAL_LCD_LINE_1 );
}
else
{
LCD_WRITE_STRING_VALUE( "Pairing fail", status, 10, HAL_LCD_LINE_1 );
}
}
else if ( state == GAPBOND_PAIRING_STATE_BONDED )
{
if ( status == SUCCESS )
{
LCD_WRITE_STRING( "Bonding success", HAL_LCD_LINE_1 );
}
}
}
实现第二步:实现一个初始化函数,将回调函数的函数指针注册给调用者
初始化函数为:[html] view
plaincopy
GAPBondMgr_Register( (gapBondCBs_t *) &simpleBLEBondCB );
其函数体为:
[html] view
plaincopy
void GAPBondMgr_Register( gapBondCBs_t *pCB )
{
pGapBondCB = pCB;
// Take over the processing of Authentication messages
VOID GAP_SetParamValue( TGAP_AUTH_TASK_ID, gapBondMgr_TaskID );
// Register with GATT Server App for event messages
GATTServApp_RegisterForMsg( gapBondMgr_TaskID );
}
在函数中把先前定义的结构体地址赋值给pGapBondCB。
其定义为:
[html] view
plaincopy
static const gapBondCBs_t *pGapBondCB = NULL;
实现第三步,使用函数指针调用回调函数
在文件gapbondmgr.c文件中有事件处理函数如下:[html] view
plaincopy
void GAPBondMgr_ProcessGAPMsg( gapEventHdr_t *pMsg )
{
switch ( pMsg->opcode )
{
case GAP_PASSKEY_NEEDED_EVENT:
{
gapPasskeyNeededEvent_t *pPkt = (gapPasskeyNeededEvent_t *)pMsg;
if ( pGapBondCB && pGapBondCB->passcodeCB )
{
// Ask app for a passcode
<span style="color:#ff0000;">pGapBondCB->passcodeCB( pPkt->deviceAddr, pPkt->connectionHandle, pPkt->uiInputs, pPkt->uiOutputs );</span>
}
else
{
// No app support, use the default passcode
if ( GAP_PasscodeUpdate( gapBond_Passcode, pPkt->connectionHandle ) != SUCCESS )
{
VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED );
}
}
}
break;
case GAP_AUTHENTICATION_COMPLETE_EVENT:
{
gapAuthCompleteEvent_t *pPkt = (gapAuthCompleteEvent_t *)pMsg;
// Should we save bonding information
if ( (pPkt->hdr.status == SUCCESS) && (pPkt->authState & SM_AUTH_STATE_BONDING) )
{
gapBondRec_t bondRec;
VOID osal_memset( &bondRec, 0, sizeof ( gapBondRec_t ) ) ;
// Do we have a public address in the data?
if ( pPkt->pIdentityInfo )
{
VOID osal_memcpy( bondRec.publicAddr, pPkt->pIdentityInfo->bd_addr, B_ADDR_LEN );
}
else
{
linkDBItem_t *pLinkItem = linkDB_Find( pPkt->connectionHandle );
if ( pLinkItem )
{
VOID osal_memcpy( bondRec.publicAddr, pLinkItem->addr, B_ADDR_LEN );
}
else
{
// We don't have an address, so ignore the message.
break;
}
}
// Save off of the authentication state
bondRec.stateFlags |= (pPkt->authState & SM_AUTH_STATE_AUTHENTICATED) ? GAP_BONDED_STATE_AUTHENTICATED : 0;
VOID gapBondMgrAddBond( &bondRec,
(gapBondLTK_t *)pPkt->pSecurityInfo,
(gapBondLTK_t *)pPkt->pDevSecInfo,
((uint8 *)((pPkt->pIdentityInfo) ? pPkt->pIdentityInfo->irk : NULL )),
((uint8 *)((pPkt->pSigningInfo) ? pPkt->pSigningInfo->srk : NULL )),
((uint32)((pPkt->pSigningInfo) ? pPkt->pSigningInfo->signCounter : GAP_INIT_SIGN_COUNTER )) );
// Update NV to have same CCC values as GATT database
gapBondMgr_SyncCharCfg( pPkt->connectionHandle );
}
// Call app state callback
if ( pGapBondCB && pGapBondCB->pairStateCB )
{
<span style="color:#ff0000;">pGapBondCB->pairStateCB( pPkt->connectionHandle, GAPBOND_PAIRING_STATE_COMPLETE, pPkt->hdr.status );</span>
}
}
break;
case GAP_BOND_COMPLETE_EVENT:
// This message is received when the bonding is complete. If hdr.status is SUCCESS
// then call app state callback. If hdr.status is NOT SUCCESS, the connection will be
// dropped at the LL because of a MIC failure, so again nothing to do.
{
gapBondCompleteEvent_t *pPkt = (gapBondCompleteEvent_t *)pMsg;
// Update NV to have same CCC values as GATT database
gapBondMgr_SyncCharCfg( pPkt->connectionHandle );
if ( pGapBondCB && pGapBondCB->pairStateCB )
{
<span style="color:#ff0000;">pGapBondCB->pairStateCB( pPkt->connectionHandle, GAPBOND_PAIRING_STATE_BONDED, pMsg->hdr.status );</span>
}
}
break;
case GAP_SIGNATURE_UPDATED_EVENT:
{
uint8 idx;
gapSignUpdateEvent_t *pPkt = (gapSignUpdateEvent_t *)pMsg;
idx = GAPBondMgr_ResolveAddr( pPkt->addrType, pPkt->devAddr, NULL );
if ( idx < GAP_BONDINGS_MAX )
{
// Save the sign counter
VOID osal_snv_write( devSignCounterNvID(idx), sizeof ( uint32 ), &(pPkt->signCounter) );
}
}
[html] view
plaincopy
break;
在上面函数中红色部分为底层调用回调函数的实现,这样通过回调函数把事件处理的过程送到上层应用层序进行处理。
4.总结
通过对整个回调函数的定义和调用过程分析,对回调函数的使用有了明确的理解。这一设计允许了底层代码调用在高层定义的子程序,有利于整个程序的分层设计。相关文章推荐
- 【Java】给定一个有序整数数组,元素各不相同且按照升序排列,编写一个算法,创建一个高度最小的二叉查找树
- Java Spring AOP的两种配置方式
- editplus安装汉化激活
- Java Hibernate之Session状态
- C#异步编程的实现方式(4)——Task任务
- 如何制作装机启动盘及重装系统; 如何利用百度云盘下载MATLAB等资料软件 ;如何安装镜像ISO文件
- Python 之字节转换
- java线程安全总结
- 关于MyEclipse不停报错multiple problems have occurred 或者是内存不足 的解决办法
- Ubuntu 12 用vsftpd 配置FTP服务器
- java + struts2 分页技术
- php安装错误
- C++学习笔记——函数
- java 路径相关问题
- Spark编程指南V1.4.0(翻译)
- qt工程中Pro文件
- java调用中国天气网api获得天气预报信息的方法
- Lucene常用查询器——代码
- spring websocket服务器遇到问题记录1
- Java注解 Annotation