第十五節(jié) BLE藍(lán)牙4.0協(xié)議棧啟動(dòng)分析
TI的這款CC2540/CC2541器件可以單芯片實(shí)現(xiàn)BLE藍(lán)牙協(xié)議棧結(jié)構(gòu)圖的所有組件,包括應(yīng)用程序。從這章開(kāi)始我們來(lái)剖析協(xié)議棧源碼,我們選用 SimpleBLEPeripheral工程開(kāi)刀,這是一個(gè)從機(jī)的例程,基本的工作是對(duì)外廣播,等待主機(jī)來(lái)連接,讀寫(xiě)展示的屬性。
首先打開(kāi)工程文件,打開(kāi)后可以看到整個(gè)工程的結(jié)構(gòu)。
我們按照系統(tǒng)的啟動(dòng)順序來(lái)一步一步走,我們都知道在C代碼中,一般啟動(dòng)的首個(gè)函數(shù)為main,這個(gè)函數(shù)在 SimpleBLEPeripheral_Main.c中,打開(kāi)文件,可以看到這個(gè)文件只有一個(gè)main函數(shù)和一個(gè)函數(shù)的申明,我們暫時(shí)不理會(huì)那個(gè)申明的函數(shù),先看main都做了些什么工作:
Int main(void)
{
/* Initialize hardware */
HAL_BOARD_INIT(); // 硬件初始化
// Initialize board I/O
InitBoard( OB_COLD ); // 板級(jí)初始化
/* Initialze the HAL driver */
HalDriverInit(); // Hal驅(qū)動(dòng)初始化
/* Initialize NV system */
osal_snv_init(); // Flash存儲(chǔ)SNV初始化
/* Initialize LL */
/* Initialize the operating system */
osal_init_system(); // OSAL初始化
/* Enable interrupts */
HAL_ENABLE_INTERRUPTS(); // 使能總中斷
// Final board initialization
InitBoard( OB_READY ); // 板級(jí)初始化
#if defined ( POWER_SAVING )
osal_pwrmgr_device( PWRMGR_BATTERY ); // 低功耗管理
#endif
/* Start OSAL */
osal_start_system(); // No Return from here 啟動(dòng)OSAL
return 0;
}
通過(guò)代碼我們可以看到,系統(tǒng)啟動(dòng)的過(guò)程,主要是做了一些初始化,如果開(kāi)啟了低功耗,則還需要開(kāi)啟低功耗管理。我們先不去理會(huì)初始化做了什么,但是我們知道在main函數(shù)的最后啟動(dòng)了OSAL,那么我們就進(jìn)去看看OSAL是如何運(yùn)作的。
在IAR中如果需要跳轉(zhuǎn)到某個(gè)函數(shù)或變量的定義,可以在此函數(shù)名中右擊然后選擇Go To Definition……就可以調(diào)到相應(yīng)的定義。
void osal_start_system( void )
{
#if !defined ( ZBIT ) && !defined ( UBIT )
for(;;) // Forever Loop
#endif
{
osal_run_system();
}
}
這里看到我們進(jìn)入了一個(gè)死循環(huán),并且一直調(diào)用osal_run_system(),那我們?cè)龠M(jìn)入此函數(shù)。
void osal_run_system( void ){
uint8 idx = 0;
#ifndef HAL_BOARD_CC2538
osalTimeUpdate(); // 定時(shí)器更新
#endif
Hal_ProcessPoll(); // Hal層信息處理
do {
if (tasksEvents[idx]) // Task is highest priority that is ready.
{
break;
}
} while (++idx < tasksCnt); // 檢查每個(gè)人任務(wù)是否有事件
if (idx < tasksCnt) // 有事件發(fā)生
{
uint16 events;
halIntState_t intState;
HAL_ENTER_CRITICAL_SECTION(intState); // 進(jìn)入臨界區(qū)
events = tasksEvents[idx];
tasksEvents[idx] = 0; // Clear the Events for this task. 清除事件標(biāo)志
HAL_EXIT_CRITICAL_SECTION(intState); // 退出臨界區(qū)
activeTaskID = idx;
events = (tasksArr[idx])( idx, events ); // 執(zhí)行事件處理函數(shù)
activeTaskID = TASK_NO_TASK;
HAL_ENTER_CRITICAL_SECTION(intState); // 進(jìn)入臨界區(qū)
tasksEvents[idx] |= events; // Add back unprocessed events to the current task.
HAL_EXIT_CRITICAL_SECTION(intState); // 退出臨界區(qū)
}
#if defined( POWER_SAVING ) // 沒(méi)有事件發(fā)生,并且開(kāi)啟了低功耗模式
else // Complete pass through all task events with no activity?
{ // 系統(tǒng)進(jìn)入低功耗模式
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
}
在這里可以看到這個(gè)OSAL的核心,整個(gè)OSAL通過(guò)檢測(cè)每個(gè)任務(wù)是否有事件發(fā)生,如果有則執(zhí)行相應(yīng)的任務(wù),處理相應(yīng)的事件。如果沒(méi)有事件需要處理并且開(kāi)啟了低功耗模式,則系統(tǒng)就會(huì)進(jìn)入低功耗模式。
這里有一個(gè)很關(guān)鍵的地方,OSAL是如何知道哪個(gè)事件需要哪個(gè)任務(wù)來(lái)處理呢?
events = (tasksArr[idx])( idx, events ); // 執(zhí)行事件處理函數(shù)
我們看這里有一個(gè)很關(guān)鍵的數(shù)組tasksArr,很顯然,這是一個(gè)函數(shù)指針數(shù)組,我們看看它的定義。
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
};
可以看到在這個(gè)數(shù)組的定義中,每個(gè)成員都是任務(wù)的執(zhí)行函數(shù),按照任務(wù)的優(yōu)先級(jí)排序,并且在osalInitTasks中初始化的時(shí)候,我們可以看到每個(gè)任務(wù)都有一個(gè)對(duì)應(yīng)的初始化函數(shù),并且傳遞了一個(gè)taskID,此ID從0開(kāi)始自增,這里有一點(diǎn)非常重要,初始化的順序和任務(wù)數(shù)組的定義順序是一樣的,這就保證了我們給任務(wù)發(fā)生消息或事件時(shí)能夠準(zhǔn)確的傳遞到相應(yīng)的任務(wù)處理函數(shù)。
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 );
}
應(yīng)用層的初始化SimpleBLEPeripheral_Init,SimpleBLEPeripheral_Init( uint8task_id )主要對(duì) GAP 和 GATT 進(jìn)行配置,最后調(diào)用osal_set_event(simpleBLEPeripheral_TaskID, SBP_START_DEVICE_EVT )啟動(dòng)設(shè)備。
設(shè)備啟動(dòng)后應(yīng)用層就能接收到這個(gè)設(shè)置的事件并進(jìn)行處理,可以看到設(shè)備啟動(dòng)中主要是啟動(dòng)設(shè)備,注冊(cè)綁定管理,并且啟動(dòng)了一個(gè)定時(shí)器,這個(gè)定時(shí)器是一個(gè)周期事件的第一次啟動(dòng)。
周期事件中每次都會(huì)重啟這個(gè)定時(shí)器,并且處理周期事件。
在初始化的時(shí)候我們注冊(cè)了一個(gè)很重要的函數(shù),設(shè)備狀態(tài)改變時(shí)的回調(diào)函數(shù),這個(gè)函數(shù)在設(shè)備的狀態(tài)改變時(shí)會(huì)被底層的協(xié)議?;卣{(diào),我們可以從這個(gè)回調(diào)函數(shù)中看的設(shè)備的狀態(tài)的改變。
static void peripheralStateNotificationCB( gaprole_States_t newState);
從函數(shù)的定義可以看出,設(shè)備的狀態(tài)類型都在數(shù)據(jù)類型gaprole_States_t中定義了,我們看一下這個(gè)數(shù)據(jù)類型的定義:
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;
看到這個(gè)定義就很明確了,設(shè)備的狀態(tài)就在這幾種狀態(tài)間切換。
本文導(dǎo)航
- 第 1 頁(yè):由淺入深,藍(lán)牙4.0/BLE協(xié)議棧開(kāi)發(fā)攻略大全(3)
- 第 2 頁(yè):第十二節(jié) Flash的讀寫(xiě)
- 第 3 頁(yè):第十三節(jié) BLE協(xié)議棧簡(jiǎn)介
- 第 4 頁(yè):第十四節(jié) OSAL工作原理
- 第 5 頁(yè):第十五節(jié) BLE藍(lán)牙4.0協(xié)議棧啟動(dòng)分析
- TI公司(73141)
- 協(xié)議棧(33351)
- 藍(lán)牙BLE(23960)
評(píng)論
查看更多