您的位置:首页 > 编程语言

蓝牙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.总结

通过对整个回调函数的定义和调用过程分析,对回调函数的使用有了明确的理解。这一设计允许了底层代码调用在高层定义的子程序,有利于整个程序的分层设计。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: