BLE4.0廣播連線過程的底層剖析
一、實驗目的
1、在實驗過程中遇到很多問題,都不知道從何下手,所以決定深入瞭解藍芽協議棧的底層,看是如何執行的,瞭解後,遇到問題就知道從哪裡開始找問題,你懂得;
二、說明
1、由於空間有限,這裡只是貼出部分程式碼,有些不能理解的要配合原始碼來理解,這裡只是大概指向(紅色部分),能讓你大部分明白是怎麼跑起來的,細節上自己去理解,不懂可以提問;
三、實驗平臺
1、藍芽協議棧:1.3.2
2、軟體平臺:IAR For 8051 8.10.3
5、硬體平臺:Smart RF開發板(從機),Android_Lightblue(主機)
四、實驗步驟
1、int main(void)
int main(void)
{
/* Initialize hardware */
HAL_BOARD_INIT();//初始化時鐘和使能快取預取模式
// Initialize board I/O
InitBoard( OB_COLD );//冷啟動,關閉了led燈與中斷,避免接下來的各種初始化受干擾
/* Initialze the HAL driver */
HalDriverInit();//各種驅動的初始化、如按鍵、lcd、adc、usb、uart等8
/* Initialize NV system */
osal_snv_init();//snv 內部用於儲存配對資料或你的使用者自定義資料的一段flash,4kB空間
/* Initialize LL */
/* Initialize the operating system */
osal_init_system();//oasl 作業系統初始化, 包含記憶體分配、訊息佇列、定時器、電源管理和任務等
/* Enable interrupts */
HAL_ENABLE_INTERRUPTS();// 開啟全域性中斷
// Final board initialization
InitBoard( OB_READY ); //設定標誌標示系統初始化完畢
2、osal_init_system()
uint8 osal_init_system( void )
{
// Initialize the Memory Allocation System
osal_mem_init();//初始化記憶體分配系統
// Initialize the message queue
osal_qHead = NULL;//初始化訊息佇列
// Initialize the timers
osalTimerInit();//初始化定時器
// Initialize the Power Management System
osal_pwrmgr_init();//初始化電源管理系統
// Initialize the system tasks.
osalInitTasks();//初始化系統任務, 這一個任務初始花非常關鍵
// Setup efficient search for the first free block of heap.
osal_mem_kick();
return ( SUCCESS );
}
3、osalInitTasks()
void osalInitTasks( void )
{
/* L2CAP Task */
L2CAP_Init( taskID++ );
/* GAP Task */
GAP_Init( taskID++ );
/* GATT Task */
GATT_Init( taskID++ );
/* SM Task */
SM_Init( taskID++ );
/* Profiles */
GAPRole_Init( taskID++ ); //鏈路角色初始化
GAPBondMgr_Init( taskID++ ); //鏈路繫結初始化
GATTServApp_Init( taskID++ );
/* Application */
SimpleBLEPeripheral_Init( taskID );
}
4、GAPRole_Init( taskID++ )
void GAPRole_Init( uint8 task_id )
{
gapRole_TaskID = task_id; //定義任務地址
gapRole_state = GAPROLE_INIT; //鏈路狀態設定為GAPROLE_INIT
gapRole_ConnectionHandle = INVALID_CONNHANDLE; //設定鏈路連線控制代碼為0xFFFF
GAP_RegisterForHCIMsgs( gapRole_TaskID );//註冊控制介面的任務ID
// Initialize the Profile Advertising and Connection Parameters
gapRole_profileRole = GAP_PROFILE_PERIPHERAL; //鏈路配置角色為從機
VOID osal_memset( gapRole_IRK, 0, KEYLEN ); //金鑰緩衝器清零
VOID osal_memset( gapRole_SRK, 0, KEYLEN );
gapRole_signCounter = 0; //金鑰計數標誌位清零
gapRole_AdvEventType = GAP_ADTYPE_ADV_IND; //廣播型別為可連線無定向廣播
gapRole_AdvDirectType = ADDRTYPE_PUBLIC; //廣播方式為通過廣播(可被發現掃描連線)
gapRole_AdvChanMap = GAP_ADVCHAN_ALL ; //廣播所有通道37、38、39
gapRole_AdvFilterPolicy = GAP_FILTER_POLICY_ALL; //允許掃描,允許連線
// Restore Items from NV
VOID osal_snv_read( BLE_NVID_IRK, KEYLEN, gapRole_IRK ); //讀出儲存的金鑰和金鑰計數標誌位
VOID osal_snv_read( BLE_NVID_CSRK, KEYLEN, gapRole_SRK );
VOID osal_snv_read( BLE_NVID_SIGNCOUNTER, sizeof( uint32 ), &gapRole_signCounter );
}
//初始化完成後
5、void SimpleBLEPeripheral_Init( uint8 task_id )
{
osal_set_event( simpleBLEPeripheral_TaskID, SBP_START_DEVICE_EVT ); //啟動裝置開始事件
}
6、uint16 SimpleBLEPeripheral_ProcessEvent( uint8 task_id, uint16 events )
{
if ( events & SBP_START_DEVICE_EVT )// 初始化後就執行這個啦
{
// Start the Device
VOID GAPRole_StartDevice( &simpleBLEPeripheral_PeripheralCBs ); //配置鏈路事件通知回撥函式
// Start Bond Manager
VOID GAPBondMgr_Register( &simpleBLEPeripheral_BondMgrCBs ); //配置配對訊息回撥函式
// Set timer for first periodic event
osal_start_timerEx( simpleBLEPeripheral_TaskID, POWER_DETECT_EVT, DetectPowerPeriod );
return ( events ^ SBP_START_DEVICE_EVT );
}
}
7、bStatus_t GAPRole_StartDevice( gapRolesCBs_t *pAppCallbacks )
{
if ( gapRole_state == GAPROLE_INIT ) //如果鏈路狀態是初始化狀態
{
// Clear all of the Application callbacks
if ( pAppCallbacks )
{
pGapRoles_AppCGs = pAppCallbacks;//設定回撥函式
}
// Start the GAP
gapRole_SetupGAP();//開始建立鏈路
return ( SUCCESS );
}
else //否則返回已經在請求模式狀態
{
return ( bleAlreadyInRequestedMode );
}
}
8、static void gapRole_SetupGAP( void )
{
VOID GAP_DeviceInit( gapRole_TaskID,
gapRole_profileRole, 0,
gapRole_IRK, gapRole_SRK,
&gapRole_signCounter );
}
9、bStatus_t GAP_DeviceInit( uint8 taskID,
uint8 profileRole,
uint8 maxScanResponses,
uint8 *pIRK,
uint8 *pSRK,
uint32 *pSignCounter )
{
// Setup the device configuration parameters
stat = GAP_ParamsInit( taskID, profileRole ); //設定裝置配置引數
#if ( HOST_CONFIG & ( CENTRAL_CFG | PERIPHERAL_CFG ) )
{
GAP_SecParamsInit( pIRK, pSRK, pSignCounter );
}
#endif
#if ( HOST_CONFIG & ( PERIPHERAL_CFG | BROADCASTER_CFG ) )
{
// Initialize GAP Peripheral Device Manager
VOID GAP_PeriDevMgrInit(); //初始化從機裝置管理
#if ( HOST_CONFIG & PERIPHERAL_CFG )
{
// Initialize SM Responder
VOID SM_ResponderInit(); //迴應者初始化
}
#endif
}
#endif
}
10、當GAP_DeviceInit初始化完成後,將產生GAP_DEVICE_INIT_DONE_EVENT事件;
10、uint16 GAPRole_ProcessEvent( uint8 task_id, uint16 events ) //鏈路處理事件
11、static void gapRole_ProcessOSALMsg( osal_event_hdr_t *pMsg ) //鏈路系統訊息事件
12、static void gapRole_ProcessGAPMsg( gapEventHdr_t *pMsg ) //鏈路處理連線訊息
{
uint8 notify = FALSE; // State changed notify the app? (default no)
switch ( pMsg->opcode )
{
case GAP_DEVICE_INIT_DONE_EVENT: //當GAP_DeviceInit初始化完成後,將產生此事件
{
gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *)pMsg;
bStatus_t stat = pPkt->hdr.status;
if ( stat == SUCCESS )
{
// Save off the generated keys
VOID osal_snv_write( BLE_NVID_IRK, KEYLEN, gapRole_IRK );//儲存生成的金鑰
VOID osal_snv_write( BLE_NVID_CSRK, KEYLEN, gapRole_SRK );
// Save off the information
VOID osal_memcpy( gapRole_bdAddr, pPkt->devAddr, B_ADDR_LEN );//儲存裝置地址
gapRole_state = GAPROLE_STARTED; //鏈路開始
// Update the advertising data
stat = GAP_UpdateAdvertisingData( gapRole_TaskID,//更新廣播資料
TRUE, gapRole_AdvertDataLen, gapRole_AdvertData );
}
notify = TRUE; //通知回撥函式鏈路的狀態
}
break;
if ( notify == TRUE )
{
// Notify the application with the new state change
if ( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnStateChange ) //判斷是否設定了回撥函式
{
pGapRoles_AppCGs->pfnStateChange( gapRole_state );//呼叫設定的回撥函式,通知gapRole_state當前狀態
}
}
}
13、stat=GAP_UpdateAdvertisingData( gapRole_TaskID,TRUE, gapRole_AdvertDataLen, gapRole_AdvertData );//更新廣播資料後,將產生GAP_ADV_DATA_UPDATE_DONE_EVENT事件;
14、static void gapRole_ProcessGAPMsg( gapEventHdr_t *pMsg ) //鏈路處理連線訊息
{
uint8 notify = FALSE; // State changed notify the app? (default no)
switch ( pMsg->opcode )
{
case GAP_ADV_DATA_UPDATE_DONE_EVENT:
{
gapAdvDataUpdateEvent_t *pPkt = (gapAdvDataUpdateEvent_t *)pMsg;
if ( pPkt->hdr.status == SUCCESS )
{
if ( pPkt->adType )
{
// Setup the Response Data
pPkt->hdr.status = GAP_UpdateAdvertisingData( gapRole_TaskID,
FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData );//更新掃描迴應資料
}
else
{
// Start advertising
VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); //啟動廣播事件
}
}
if ( pPkt->hdr.status != SUCCESS ) //如果不成功將通知回撥函式,否則不通知
{
// Set into Error state
gapRole_state = GAPROLE_ERROR;
notify = TRUE;
}
}
break;
15、static void gapRole_ProcessGAPMsg( gapEventHdr_t *pMsg ) //鏈路處理連線訊息
{
uint8 notify = FALSE; // State changed notify the app? (default no)
switch ( pMsg->opcode )
{
case GAP_ADV_DATA_UPDATE_DONE_EVENT:
{
gapAdvDataUpdateEvent_t *pPkt = (gapAdvDataUpdateEvent_t *)pMsg;
if ( pPkt->hdr.status == SUCCESS )
{
if ( pPkt->adType )
{
// Setup the Response Data
pPkt->hdr.status = GAP_UpdateAdvertisingData( gapRole_TaskID,
FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData );//更新掃描迴應資料
}
else
{
// Start advertising
VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); //啟動廣播事件
}
}
if ( pPkt->hdr.status != SUCCESS ) //如果不成功將通知回撥函式,否則不通知
{
// Set into Error state
gapRole_state = GAPROLE_ERROR;
notify = TRUE;
}
}
break;
16、執行廣播事件
uint16 GAPRole_ProcessEvent( uint8 task_id, uint16 events )
{
VOID task_id; // OSAL required parameter that isn't used in this function
if ( events & START_ADVERTISING_EVT )
{
if ( gapRole_AdvEnabled )
{
gapAdvertisingParams_t params;
// Setup advertisement parameters
params.eventType = gapRole_AdvEventType; //GAP_ADTYPE_ADV_IND; 廣播型別為可連線無定向廣播
params.initiatorAddrType = gapRole_AdvDirectType; //ADDRTYPE_PUBLIC; 廣播方式為通用廣播
VOID osal_memcpy( params.initiatorAddr, gapRole_AdvDirectAddr, B_ADDR_LEN ); //發起者地址配置
params.channelMap = gapRole_AdvChanMap; //廣播通道配置:廣播所有通道37、38、39
params.filterPolicy = gapRole_AdvFilterPolicy;//過濾策略GAP_FILTER_POLICY_ALL;允許掃描,允許連線
if ( GAP_MakeDiscoverable( gapRole_TaskID, ¶ms ) != SUCCESS ) //配置廣播引數,併產生一個GAP_MakeDiscoverable 訊息事件
{
gapRole_state = GAPROLE_ERROR;//如果不成功將通知回撥函式-鏈路錯誤
// Notify the application with the new state change
if ( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnStateChange )
{
pGapRoles_AppCGs->pfnStateChange( gapRole_state );
}
}
}
return ( events ^ START_ADVERTISING_EVT );
}
17、處理GAP_MakeDiscoverable訊息事件
static void gapRole_ProcessGAPMsg( gapEventHdr_t *pMsg ) //鏈路處理連線訊息
{
uint8 notify = FALSE; // State changed notify the app? (default no)
switch ( pMsg->opcode )
{
case GAP_MAKE_DISCOVERABLE_DONE_EVENT: //使能可被發現完成事件即開始廣播了
case GAP_END_DISCOVERABLE_DONE_EVENT: //結束可被發現完成事件即停止廣播了
{
gapMakeDiscoverableRspEvent_t *pPkt = (gapMakeDiscoverableRspEvent_t *)pMsg;
if ( pPkt->hdr.status == SUCCESS )
{
if ( pMsg->opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT )
{
gapRole_state = GAPROLE_ADVERTISING; //設定當前鏈路狀態
}
else // GAP_END_DISCOVERABLE_DONE_EVENT//結束可被發現完成事件即停止廣播了
{
if ( gapRole_AdvertOffTime != 0 ) //如果gapRole_AdvertOffTime等於0,將不再廣播,否則啟動定時廣播件
{
if ( ( gapRole_AdvEnabled ) )//如果使能廣播
{
VOID osal_start_timerEx( gapRole_TaskID, START_ADVERTISING_EVT, gapRole_AdvertOffTime );//啟動週期廣播事件
}
}
else
{
// Since gapRole_AdvertOffTime is set to 0, the device should not
// automatically become discoverable again after a period of time.
// Set enabler to FALSE; device will become discoverable again when
// this value gets set to TRUE
gapRole_AdvEnabled = FALSE;
}
// In the Advertising Off period
gapRole_state = GAPROLE_WAITING;//如果GAP_END_DISCOVERABLE_DONE_EVENT,鏈路當前狀態為等待狀態
}
}
else
{
gapRole_state = GAPROLE_ERROR;
}
notify = TRUE;//通知回撥函式
}
break;
if ( notify == TRUE )
{
// Notify the application with the new state change
if ( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnStateChange ) //判斷是否設定了回撥函式
{
pGapRoles_AppCGs->pfnStateChange( gapRole_state );//呼叫設定的回撥函式,通知gapRole_state當前狀態
}
}
18、這時候底層已經使能硬體在廣播了,要麼廣播超時產生一個GAP_END_DISCOVERABLE_DONE_EVENT訊息,要麼被連線事件 GAP_LINK_ESTABLISHED_EVENT;
19、廣播超時產生一個GAP_END_DISCOVERABLE_DONE_EVENT訊息
static void gapRole_ProcessGAPMsg( gapEventHdr_t *pMsg ) //鏈路處理連線訊息
{
uint8 notify = FALSE; // State changed notify the app? (default no)
switch ( pMsg->opcode )
{
case GAP_MAKE_DISCOVERABLE_DONE_EVENT: //使能可被發現完成事件即開始廣播了
case GAP_END_DISCOVERABLE_DONE_EVENT: //結束可被發現完成事件即停止廣播了
{
gapMakeDiscoverableRspEvent_t *pPkt = (gapMakeDiscoverableRspEvent_t *)pMsg;
if ( pPkt->hdr.status == SUCCESS )
{
if ( pMsg->opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT )
{
gapRole_state = GAPROLE_ADVERTISING; //設定當前鏈路狀態
}
else // GAP_END_DISCOVERABLE_DONE_EVENT//結束可被發現完成事件即停止廣播了
{
if ( gapRole_AdvertOffTime != 0 ) //如果gapRole_AdvertOffTime不等於0,啟動定時廣播事件,否則將關閉廣播
{
if ( ( gapRole_AdvEnabled ) )//如果使能廣播
{
VOID osal_start_timerEx( gapRole_TaskID, START_ADVERTISING_EVT, gapRole_AdvertOffTime );//啟動週期廣播事件
}
}
else
{
// Since gapRole_AdvertOffTime is set to 0, the device should not
// automatically become discoverable again after a period of time.
// Set enabler to FALSE; device will become discoverable again when
// this value gets set to TRUE
gapRole_AdvEnabled = FALSE; //關閉廣播
}
// In the Advertising Off period
gapRole_state = GAPROLE_WAITING;//如果GAP_END_DISCOVERABLE_DONE_EVENT,鏈路當前狀態為等待狀態,或不再廣播或等待週期廣播
}
}
else
{
gapRole_state = GAPROLE_ERROR;
}
notify = TRUE;//通知回撥函式
}
break;
if ( notify == TRUE )
{
// Notify the application with the new state change
if ( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnStateChange ) //判斷是否設定了回撥函式
{
pGapRoles_AppCGs->pfnStateChange( gapRole_state );//呼叫設定的回撥函式,通知gapRole_state當前狀態
}
}
20、廣播時產生一個GAP_LINK_ESTABLISHED_EVENT訊息
static void gapRole_ProcessGAPMsg( gapEventHdr_t *pMsg ) //鏈路處理連線訊息
{
uint8 notify = FALSE; // State changed notify the app? (default no)
switch ( pMsg->opcode )
{
case GAP_LINK_ESTABLISHED_EVENT:
{
gapEstLinkReqEvent_t *pPkt = (gapEstLinkReqEvent_t *)pMsg;
if ( pPkt->hdr.status == SUCCESS )
{
VOID osal_memcpy( gapRole_ConnectedDevAddr, pPkt->devAddr, B_ADDR_LEN );//儲存主機的地址
gapRole_ConnectionHandle = pPkt->connectionHandle; //儲存主機連線控制代碼
gapRole_state = GAPROLE_CONNECTED; //通知鏈路狀態:連線成功
notify = TRUE;
}
}
}
---------------------
原文:https://blog.csdn.net/zhuangjitongxue/article/details/49658931