一、简介
本篇以SimpleBLECentral工程中simpleBLECentralEventCB函数,来简要说明回调函数的定义和调用过程。
二、版权声明
博主:甜甜的大香瓜
声明:喝水不忘挖井人,转载请注明出处。
原文地址:http://blog.csdn.net/feilusia
联系方式:[email protected]
技术交流QQ群:127442605
三、回调函数简介
TI的BLE协议栈使用到大量的回调函数,函数名末尾带“CB”的通常都是回调函数,它是指“call back”,在状态有改变时会调用此函数。
四、解析代码
1、定义一个“成员为函数指针”的结构体
1)定义一个函数指针
/** * Central Event Callback Function */ typedef void (*pfnGapCentralRoleEventCB_t) ( gapCentralRoleEvent_t *pEvent //!< Pointer to event structure. );它的参数是一个gapCentralRoleEvent_t类型的消息指针*pEvent。
其中,gapCentralRoleEvent_t的类型如下
/** * Central Event Structure */ typedef union { gapEventHdr_t gap; //!< GAP_MSG_EVENT and status. gapDeviceInitDoneEvent_t initDone; //!< GAP initialization done. gapDeviceInfoEvent_t deviceInfo; //!< Discovery device information event structure. gapDevDiscEvent_t discCmpl; //!< Discovery complete event structure. gapEstLinkReqEvent_t linkCmpl; //!< Link complete event structure. gapLinkUpdateEvent_t linkUpdate; //!< Link update event structure. gapTerminateLinkEvent_t linkTerminate; //!< Link terminated event structure. } gapCentralRoleEvent_t;
2)定义一个结构体
/** * Central Callback Structure */ typedef struct { pfnGapCentralRoleRssiCB_t rssiCB; //!< RSSI callback. pfnGapCentralRoleEventCB_t eventCB; //!< Event callback. } gapCentralRoleCB_t;
gapCentralRoleCB_t结构体有两个成员,一个是pfnGapCentralRoleRssiCB_t类型的成员,一个是pfnGapCentralRoleEventCB_t类型的成员。
2、写一个回调函数,并完成注册
1)定义一个函数simpleBLECentralEventCB
/********************************************************************* * @fn simpleBLECentralEventCB * * @brief Central event callback function. * * @param pEvent - pointer to event structure * * @return none */ static void simpleBLECentralEventCB( gapCentralRoleEvent_t *pEvent ) { switch ( pEvent->gap.opcode ) { case GAP_DEVICE_INIT_DONE_EVENT: { LCD_WRITE_STRING( "BLE Central", HAL_LCD_LINE_1 ); LCD_WRITE_STRING( bdAddr2Str( pEvent->initDone.devAddr ), HAL_LCD_LINE_2 ); } break; case GAP_DEVICE_INFO_EVENT: { // if filtering device discovery results based on service UUID if ( DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE ) { if ( simpleBLEFindSvcUuid( SIMPLEPROFILE_SERV_UUID, pEvent->deviceInfo.pEvtData, pEvent->deviceInfo.dataLen ) ) { simpleBLEAddDeviceInfo( pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType ); } } } break; case GAP_DEVICE_DISCOVERY_EVENT: { // discovery complete simpleBLEScanning = FALSE; // if not filtering device discovery results based on service UUID if ( DEFAULT_DEV_DISC_BY_SVC_UUID == FALSE ) { // Copy results simpleBLEScanRes = pEvent->discCmpl.numDevs; osal_memcpy( simpleBLEDevList, pEvent->discCmpl.pDevList, (sizeof( gapDevRec_t ) * pEvent->discCmpl.numDevs) ); } LCD_WRITE_STRING_VALUE( "Devices Found", simpleBLEScanRes, 10, HAL_LCD_LINE_1 ); if ( simpleBLEScanRes > 0 ) { LCD_WRITE_STRING( "<- To Select", HAL_LCD_LINE_2 ); } // initialize scan index to last device simpleBLEScanIdx = simpleBLEScanRes; } break; case GAP_LINK_ESTABLISHED_EVENT: { if ( pEvent->gap.hdr.status == SUCCESS ) { simpleBLEState = BLE_STATE_CONNECTED; simpleBLEConnHandle = pEvent->linkCmpl.connectionHandle; simpleBLEProcedureInProgress = TRUE; // If service discovery not performed initiate service discovery if ( simpleBLECharHdl == 0 ) { osal_start_timerEx( simpleBLETaskId, START_DISCOVERY_EVT, DEFAULT_SVC_DISCOVERY_DELAY ); } LCD_WRITE_STRING( "Connected", HAL_LCD_LINE_1 ); LCD_WRITE_STRING( bdAddr2Str( pEvent->linkCmpl.devAddr ), HAL_LCD_LINE_2 ); } else { simpleBLEState = BLE_STATE_IDLE; simpleBLEConnHandle = GAP_CONNHANDLE_INIT; simpleBLERssi = FALSE; simpleBLEDiscState = BLE_DISC_STATE_IDLE; LCD_WRITE_STRING( "Connect Failed", HAL_LCD_LINE_1 ); LCD_WRITE_STRING_VALUE( "Reason:", pEvent->gap.hdr.status, 10, HAL_LCD_LINE_2 ); } } break; case GAP_LINK_TERMINATED_EVENT: { simpleBLEState = BLE_STATE_IDLE; simpleBLEConnHandle = GAP_CONNHANDLE_INIT; simpleBLERssi = FALSE; simpleBLEDiscState = BLE_DISC_STATE_IDLE; simpleBLECharHdl = 0; simpleBLEProcedureInProgress = FALSE; LCD_WRITE_STRING( "Disconnected", HAL_LCD_LINE_1 ); LCD_WRITE_STRING_VALUE( "Reason:", pEvent->linkTerminate.reason, 10, HAL_LCD_LINE_2 ); } break; case GAP_LINK_PARAM_UPDATE_EVENT: { LCD_WRITE_STRING( "Param Update", HAL_LCD_LINE_1 ); } break; default: break; } }
static void simpleBLECentralEventCB( gapCentralRoleEvent_t *pEvent );
// GAP Role Callbacks static const gapCentralRoleCB_t simpleBLERoleCB = { simpleBLECentralRssiCB, // RSSI callback simpleBLECentralEventCB // Event callback };
3、调用回调函数
1)定义一个新的函数指针变量pGapCentralRoleCB(central.c)
// App callbacks static gapCentralRoleCB_t *pGapCentralRoleCB;
2)将pGapCentralRoleCB指向回调函数simpleBLECentralEventCB,也就是注册回调函数。
/** * @brief Start the device in Central role. This function is typically * called once during system startup. * * Public function defined in central.h. */ bStatus_t GAPCentralRole_StartDevice( gapCentralRoleCB_t *pAppCallbacks ) { if ( pAppCallbacks ) { pGapCentralRoleCB = pAppCallbacks; } return GAP_DeviceInit( gapCentralRoleTaskId, GAP_PROFILE_CENTRAL, gapCentralRoleMaxScanRes, gapCentralRoleIRK, gapCentralRoleSRK, &gapCentralRoleSignCounter ); }
3)调用回调函数
// Pass event to app if ( pGapCentralRoleCB && pGapCentralRoleCB->eventCB ) { pGapCentralRoleCB->eventCB( (gapCentralRoleEvent_t *) pMsg ); } }
注:实际上此时simpleBLECentralEventCB在第二步结束时,即可直接通过操作结构体来调用这个回调函数了。
但是之所以要将结构体中的simpleBLECentralEventCB函数首地址再传给simpleBLECentralEventCB(即第三点的1、2两个步骤),我认为是出于底层的profiles——central分层的考虑。