蓝牙4.0协议编程之回调函数

来源:互联网 发布:专卖店软件泰安 编辑:程序博客网 时间:2024/05/17 07:23

蓝牙4.0协议编程之回调函数

基于TI公司蓝牙4.0协议
转载出处:http://blog.csdn.net/zhcx2011/article/details/9010541

1.回调函数概念

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

2.回调函数实现的机制

⑴定义一个回调函数;
⑵提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;
⑶当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。

3.代码实例分析

实现第一步,定义结构和函数体:

在gapbondmgr.h文件中定义

Passcode回调函数

[html] view plaincopy
  1. /**  
  2.  * Passcode Callback Function  
  3.  */  
  4. typedef void (*pfnPasscodeCB_t)  
  5. (     
  6.   uint8  *deviceAddr,                   //!< address of device to pair with, and could be either public or random.  
  7.   uint16 connectionHandle,              //!< Connection handle  
  8.   uint8  uiInputs,                      //!< Pairing User Interface Inputs - Ask user to input passcode  
  9.   uint8  uiOutputs                      //!< Pairing User Interface Outputs - Display passcode  
  10.  );  

绑定状态回调函数

[html] view plaincopy
  1. /**  
  2.  * Pairing State Callback Function  
  3.  */  
  4. typedef void (*pfnPairStateCB_t)  
  5. (  
  6.   uint16 connectionHandle,              //!< Connection handle  
  7.   uint8  state,                         //!< Pairing state @ref GAPBOND_PAIRING_STATE_DEFINES  
  8.   uint8  status                         //!< Pairing status  
  9. );  

定义回调函数结构体

[html] view plaincopy
  1. /**  
  2.  * Callback Registration Structure  
  3.  */  
  4. typedef struct  
  5. {  
  6.   pfnPasscodeCB_t     passcodeCB;       //!< Passcode callback  
  7.   pfnPairStateCB_t    pairStateCB;      //!< Pairing state callback  
  8. } gapBondCBs_t;  

在simpleBLECentral.c文件中定义

回调函数结构体实例:
[cpp] view plaincopy
  1. // Bond Manager Callbacks  
  2. static const gapBondCBs_t simpleBLEBondCB =  
  3. {  
  4.   simpleBLECentralPasscodeCB,  
  5.   simpleBLECentralPairStateCB  
  6. };  
函数体:
[cpp] view plaincopy
  1. static void simpleBLECentralPasscodeCB( uint8 *deviceAddr, uint16 connectionHandle,  
  2.                                         uint8 uiInputs, uint8 uiOutputs )  
  3. {  
  4. #if (HAL_LCD == TRUE)  
  5.   
  6.   uint32  passcode;  
  7.   uint8   str[7];  
  8.   
  9.   // Create random passcode  
  10.   LL_Rand( ((uint8 *) &passcode), sizeof( uint32 ));  
  11.   passcode %= 1000000;  
  12.     
  13.   // Display passcode to user  
  14.   if ( uiOutputs != 0 )  
  15.   {  
  16.     LCD_WRITE_STRING( "Passcode:",  HAL_LCD_LINE_1 );  
  17.     LCD_WRITE_STRING( (char *) _ltoa(passcode, str, 10),  HAL_LCD_LINE_2 );  
  18.   }  
  19.     
  20.   // Send passcode response  
  21.   GAPBondMgr_PasscodeRsp( connectionHandle, SUCCESS, passcode );  
  22. #endif  
  23. }  

[html] view plaincopy
  1. static void simpleBLECentralPairStateCB( uint16 connHandle, uint8 state, uint8 status )  
  2. {  
  3.   if ( state == GAPBOND_PAIRING_STATE_STARTED )  
  4.   {  
  5.     LCD_WRITE_STRING( "Pairing started", HAL_LCD_LINE_1 );  
  6.   }  
  7.   else if ( state == GAPBOND_PAIRING_STATE_COMPLETE )  
  8.   {  
  9.     if ( status == SUCCESS )  
  10.     {  
  11.       LCD_WRITE_STRING( "Pairing success", HAL_LCD_LINE_1 );  
  12.     }  
  13.     else  
  14.     {  
  15.       LCD_WRITE_STRING_VALUE( "Pairing fail", status, 10, HAL_LCD_LINE_1 );  
  16.     }  
  17.   }  
  18.   else if ( state == GAPBOND_PAIRING_STATE_BONDED )  
  19.   {  
  20.     if ( status == SUCCESS )  
  21.     {  
  22.       LCD_WRITE_STRING( "Bonding success", HAL_LCD_LINE_1 );  
  23.     }  
  24.   }  
  25. }  

实现第二步:实现一个初始化函数,将回调函数的函数指针注册给调用者

初始化函数为:
[html] view plaincopy
  1. GAPBondMgr_Register( (gapBondCBs_t *) &simpleBLEBondCB );  
其函数体为:
[html] view plaincopy
  1. void GAPBondMgr_Register( gapBondCBs_t *pCB )  
  2. {  
  3.   pGapBondCB = pCB;  
  4.   
  5.   // Take over the processing of Authentication messages  
  6.   VOID GAP_SetParamValue( TGAP_AUTH_TASK_ID, gapBondMgr_TaskID );  
  7.   
  8.   // Register with GATT Server App for event messages  
  9.   GATTServApp_RegisterForMsg( gapBondMgr_TaskID );  
  10. }  
在函数中把先前定义的结构体地址赋值给pGapBondCB。
其定义为:
[html] view plaincopy
  1. static const gapBondCBs_t *pGapBondCB = NULL;  

实现第三步,使用函数指针调用回调函数

在文件gapbondmgr.c文件中有事件处理函数如下:
[html] view plaincopy
  1. void GAPBondMgr_ProcessGAPMsg( gapEventHdr_t *pMsg )  
  2. {  
  3.   switch ( pMsg->opcode )  
  4.   {  
  5.     case GAP_PASSKEY_NEEDED_EVENT:  
  6.       {  
  7.         gapPasskeyNeededEvent_t *pPkt = (gapPasskeyNeededEvent_t *)pMsg;  
  8.   
  9.         if ( pGapBondCB && pGapBondCB->passcodeCB )  
  10.         {  
  11.           // Ask app for a passcode  
  12.           <span style="color:#ff0000;">pGapBondCB->passcodeCB( pPkt->deviceAddr, pPkt->connectionHandle, pPkt->uiInputs, pPkt->uiOutputs );</span>  
  13.         }  
  14.         else  
  15.         {  
  16.           // No app support, use the default passcode  
  17.           if ( GAP_PasscodeUpdate( gapBond_Passcode, pPkt->connectionHandle ) != SUCCESS )  
  18.           {  
  19.             VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED );  
  20.           }  
  21.         }  
  22.       }  
  23.       break;  
  24.   
  25.     case GAP_AUTHENTICATION_COMPLETE_EVENT:  
  26.       {  
  27.         gapAuthCompleteEvent_t *pPkt = (gapAuthCompleteEvent_t *)pMsg;  
  28.   
  29.         // Should we save bonding information  
  30.         if ( (pPkt->hdr.status == SUCCESS) && (pPkt->authState & SM_AUTH_STATE_BONDING) )  
  31.         {  
  32.           gapBondRec_t bondRec;  
  33.   
  34.           VOID osal_memset( &bondRec, 0, sizeof ( gapBondRec_t ) ) ;  
  35.   
  36.           // Do we have a public address in the data?  
  37.           if ( pPkt->pIdentityInfo )  
  38.           {  
  39.             VOID osal_memcpy( bondRec.publicAddr, pPkt->pIdentityInfo->bd_addr, B_ADDR_LEN );  
  40.           }  
  41.           else  
  42.           {  
  43.             linkDBItem_t *pLinkItem = linkDB_Find( pPkt->connectionHandle );  
  44.             if ( pLinkItem )  
  45.             {  
  46.               VOID osal_memcpy( bondRec.publicAddr, pLinkItem->addr, B_ADDR_LEN );  
  47.             }  
  48.             else  
  49.             {  
  50.               // We don't have an address, so ignore the message.  
  51.               break;  
  52.             }  
  53.           }  
  54.   
  55.           // Save off of the authentication state  
  56.           bondRec.stateFlags |= (pPkt->authState & SM_AUTH_STATE_AUTHENTICATED) ? GAP_BONDED_STATE_AUTHENTICATED : 0;  
  57.   
  58.           VOID gapBondMgrAddBond( &bondRec,  
  59.                              (gapBondLTK_t *)pPkt->pSecurityInfo,  
  60.                              (gapBondLTK_t *)pPkt->pDevSecInfo,  
  61.                              ((uint8 *)((pPkt->pIdentityInfo) ? pPkt->pIdentityInfo->irk : NULL )),  
  62.                              ((uint8 *)((pPkt->pSigningInfo) ? pPkt->pSigningInfo->srk : NULL )),  
  63.                              ((uint32)((pPkt->pSigningInfo) ? pPkt->pSigningInfo->signCounter : GAP_INIT_SIGN_COUNTER )) );  
  64.   
  65.           // Update NV to have same CCC values as GATT database  
  66.           gapBondMgr_SyncCharCfg( pPkt->connectionHandle );  
  67.         }  
  68.   
  69.         // Call app state callback  
  70.         if ( pGapBondCB && pGapBondCB->pairStateCB )  
  71.         {  
  72.           <span style="color:#ff0000;">pGapBondCB->pairStateCB( pPkt->connectionHandle, GAPBOND_PAIRING_STATE_COMPLETE, pPkt->hdr.status );</span>  
  73.         }  
  74.       }  
  75.       break;  
  76.   
  77.     case GAP_BOND_COMPLETE_EVENT:  
  78.       // This message is received when the bonding is complete.  If hdr.status is SUCCESS  
  79.       // then call app state callback.  If hdr.status is NOT SUCCESS, the connection will be  
  80.       // dropped at the LL because of a MIC failure, so again nothing to do.  
  81.       {  
  82.         gapBondCompleteEvent_t *pPkt = (gapBondCompleteEvent_t *)pMsg;  
  83.   
  84.         // Update NV to have same CCC values as GATT database  
  85.         gapBondMgr_SyncCharCfg( pPkt->connectionHandle );  
  86.   
  87.         if ( pGapBondCB && pGapBondCB->pairStateCB )  
  88.         {  
  89.           <span style="color:#ff0000;">pGapBondCB->pairStateCB( pPkt->connectionHandle, GAPBOND_PAIRING_STATE_BONDED, pMsg->hdr.status );</span>  
  90.         }  
  91.       }  
  92.       break;  
  93.   
  94.     case GAP_SIGNATURE_UPDATED_EVENT:  
  95.       {  
  96.         uint8 idx;  
  97.         gapSignUpdateEvent_t *pPkt = (gapSignUpdateEvent_t *)pMsg;  
  98.   
  99.         idx = GAPBondMgr_ResolveAddr( pPkt->addrType, pPkt->devAddr, NULL );  
  100.         if ( idx < GAP_BONDINGS_MAX )  
  101.         {  
  102.           // Save the sign counter  
  103.           VOID osal_snv_write( devSignCounterNvID(idx), sizeof ( uint32 ), &(pPkt->signCounter) );  
  104.         }  
  105.       }  
[html] view plaincopy
  1. break;  
在上面函数中红色部分为底层调用回调函数的实现,这样通过回调函数把事件处理的过程送到上层应用层序进行处理。

4.总结

通过对整个回调函数的定义和调用过程分析,对回调函数的使用有了明确的理解。这一设计允许了底层代码调用在高层定义的子程序,有利于整个程序的分层设计。
0 0
原创粉丝点击