1. 程式人生 > >BLE4.0廣播連線過程的底層剖析

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