第十五节 BLE蓝牙4.0协议栈启动分析

第十五节  BLE蓝牙4.0协议栈启动分析
TI的这款CC2540/CC2541器件可以单芯片实现BLE蓝牙协议栈结构图的所有组件,包括应用程序。从这章开始我们来剖析协议栈源码,我们选用SimpleBLEPeripheral工程开刀,这是一个从机的例程,基本的工作是对外广播,等待主机来连接,读写展示的属性。


首先打开工程文件,打开后可以看到整个工程的结构。


 我们按照系统的启动顺序来一步一步走,我们都知道在C代码中,一般启动的首个函数为main,这个函数在SimpleBLEPeripheral_Main.c中,打开文件,可以看到这个文件只有一个main函数和一个函数的申明,我们暂时不理会那个申明的函数,先看main都做了些什么工作:
Int  main(void)
{
  /* Initialize hardware */
  HAL_BOARD_INIT();          // 硬件初始化

  // Initialize board I/O
  InitBoard( OB_COLD );         // 板级初始化

  /* Initialze the HAL driver */
  HalDriverInit();              // Hal驱动初始化

  /* Initialize NV system */
  osal_snv_init();              // Flash存储SNV初始化

  /* Initialize LL */

  /* Initialize the operating system */
  osal_init_system();           // OSAL初始化

  /* Enable interrupts */
  HAL_ENABLE_INTERRUPTS();      // 使能总中断

  // Final board initialization
  InitBoard( OB_READY );        // 板级初始化

  #if defined ( POWER_SAVING )
    osal_pwrmgr_device( PWRMGR_BATTERY );   // 低功耗管理
  #endif

  /* Start OSAL */
  osal_start_system(); // No Return from here  启动OSAL

  return 0;
}

void osal_start_system( void )
{
#if !defined ( ZBIT ) && !defined ( UBIT )
  for(;;)  // Forever Loop
#endif
  {
    osal_run_system();
  }
}

 这里看到我们进入了一个死循环,并且一直调用osal_run_system(),那我们再进入此函数。

</blockquote></div><div style="text-align: left;"><div class="blockcode"><blockquote>
void osal_run_system( void )
{
  uint8 idx = 0;

#ifndef HAL_BOARD_CC2538
  osalTimeUpdate();     // 定时器更新
#endif

  Hal_ProcessPoll();    // Hal层信息处理

  do {
    if (tasksEvents[idx])  // Task is highest priority that is ready.
    {
      break;
    }
  } while (++idx < tasksCnt);   // 检查每个人任务是否有事件

  if (idx < tasksCnt)   // 有事件发生
  {
    uint16 events;
    halIntState_t intState;

    HAL_ENTER_CRITICAL_SECTION(intState);   // 进入临界区
    events = tasksEvents[idx];
    tasksEvents[idx] = 0;  // Clear the Events for this task. 清除事件标志
    HAL_EXIT_CRITICAL_SECTION(intState);    // 退出临界区

    activeTaskID = idx;
    events = (tasksArr[idx])( idx, events );    // 执行事件处理函数
    activeTaskID = TASK_NO_TASK;

    HAL_ENTER_CRITICAL_SECTION(intState);   // 进入临界区
    tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.
    HAL_EXIT_CRITICAL_SECTION(intState);    // 退出临界区
  }
#if defined( POWER_SAVING )         // 没有事件发生,并且开启了低功耗模式
  else  // Complete pass through all task events with no activity?
  { // 系统进入低功耗模式
    osal_pwrmgr_powerconserve();  // Put the processor/system into sleep
  }
#endif

  /* Yield in case cooperative scheduling is being used. */
#if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)
  {
    osal_task_yield();
  }
#endif
}

在这里可以看到这个OSAL的核心,整个OSAL通过检测每个任务是否有事件发生,如果有则执行相应的任务,处理相应的事件。如果没有事件需要处理并且开启了低功耗模式,则系统就会进入低功耗模式。
    这里有一个很关键的地方,OSAL是如何知道哪个事件需要哪个任务来处理呢?
events = (tasksArr[idx])( idx, events );    // 执行事件处理函数
我们看这里有一个很关键的数组tasksArr,很显然,这是一个函数指针数组,我们看看它的定义。
const pTaskEventHandlerFn tasksArr[] =
{
  LL_ProcessEvent,                                                  // task 0
  Hal_ProcessEvent,                                                 // task 1
  HCI_ProcessEvent,                                                 // task 2
#if defined ( OSAL_CBTIMER_NUM_TASKS )
  OSAL_CBTIMER_PROCESS_EVENT( osal_CbTimerProcessEvent ),       // task 3
#endif
  L2CAP_ProcessEvent,                                               // task 4
  GAP_ProcessEvent,                                                 // task 5
  GATT_ProcessEvent,                                                // task 6
  SM_ProcessEvent,                                                  // task 7
  GAPRole_ProcessEvent,                                             // task 8
  GAPBondMgr_ProcessEvent,                                         // task 9
  GATTServApp_ProcessEvent,                                         // task 10
  SimpleBLEPeripheral_ProcessEvent                                    // task 11
};

可以看到在这个数组的定义中,每个成员都是任务的执行函数,按照任务的优先级排序,并且在osalInitTasks中初始化的时候,我们可以看到每个任务都有一个对应的初始化函数,并且传递了一个taskID,此ID从0开始自增,这里有一点非常重要,初始化的顺序和任务数组的定义顺序是一样的,这就保证了我们给任务发生消息或事件时能够准确的传递到相应的任务处理函数。
void osalInitTasks( void )
{
  uint8 taskID = 0;

  tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
  osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));

  /* LL Task */
  LL_Init( taskID++ );

  /* Hal Task */
  Hal_Init( taskID++ );

  /* HCI Task */
  HCI_Init( taskID++ );

#if defined ( OSAL_CBTIMER_NUM_TASKS )
  /* Callback Timer Tasks */
  osal_CbTimerInit( taskID );
  taskID += OSAL_CBTIMER_NUM_TASKS;
#endif

  /* 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 );
}

应用层的初始化SimpleBLEPeripheral_Init,SimpleBLEPeripheral_Init( uint8task_id )主要对 GAP 和 GATT 进行配置,最后调用osal_set_event(simpleBLEPeripheral_TaskID, SBP_START_DEVICE_EVT )启动设备。
    设备启动后应用层就能接收到这个设置的事件并进行处理,可以看到设备启动中主要是启动设备,注册绑定管理,并且启动了一个定时器,这个定时器是一个周期事件的第一次启动。


周期事件中每次都会重启这个定时器,并且处理周期事件。


在初始化的时候我们注册了一个很重要的函数,设备状态改变时的回调函数,这个函数在设备的状态改变时会被底层的协议栈回调,我们可以从这个回调函数中看的设备的状态的改变。
    static void peripheralStateNotificationCB( gaprole_States_t newState);
    从函数的定义可以看出,设备的状态类型都在数据类型gaprole_States_t中定义了,我们看一下这个数据类型的定义:
typedef enum
{
  GAPROLE_INIT = 0,                       //!< Waiting to be started
  GAPROLE_STARTED,                        //!< Started but not advertising
  GAPROLE_ADVERTISING,                    //!< Currently Advertising
  GAPROLE_WAITING,           //!< Device is started but not advertising, is in waiting period before advertising again
  GAPROLE_WAITING_AFTER_TIMEOUT,          //!< Device just timed out from a connection but is not yet advertising, is in waiting period before advertising again
  GAPROLE_CONNECTED,                      //!< In a connection
  GAPROLE_CONNECTED_ADV,                  //!< In a connection + advertising
  GAPROLE_ERROR                           //!< Error occurred - invalid state
} gaprole_States_t;

看到这个定义就很明确了,设备的状态就在这几种状态间切换。

本文章转载自
http://www.deyisupport.com/question_answer/wireless_connectivity/bluetooth/f/103/t/69222.aspx
请勿用于商业

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值