Overview
BASS 分爲兩部分。一部分爲Profile,另一部分爲Application。
同樣初始化也是分爲兩部分,一部分是BASS Profile初始化,另一部分是 BASS Application初始化。
BASS APP 初始化
在BASS Application不是單獨的一個任務,它是APP_TASK這個任務中的一個APP。
類似的還有app_diss、app_findme、app_proxr、app_sec、app_custs等。可見\sdk\app_modules\src目錄
這些APP是系統自帶的,可以通過宏控開啓或者關閉。
從初始化的過程就可以看出來,當系統初始化時,將會調用void default_app_on_init(void)
函數。
void default_app_on_init(void)
{
#if BLE_PROX_REPORTER
app_proxr_init();
#endif
#if BLE_FINDME_LOCATOR
app_findl_init();
#endif
#if BLE_BAS_SERVER
app_batt_init();
#endif
#if BLE_DIS_SERVER
app_dis_init();
#endif
#if BLE_SPOTA_RECEIVER
app_spotar_init();
#endif
// Initialize service access write permissions for all the included profiles
prf_init_srv_perm();
// Set sleep mode
arch_set_sleep_mode(app_default_sleep_mode);
}
從中我們不難看出app_batt_init();就是在這時被調用的。
app_batt_init()
app_batt_init()函數主要是調用battery_get_lv();
函數,得到開機時的電池電量。並沒有什麼實質上完成 battery service的初始化。
void app_batt_init(void)
{
// called from app.c::app_init() when chip boots
#ifdef USED_BATTERY_TYPE
cur_batt_level = battery_get_lvl(USED_BATTERY_TYPE);
#else
cur_batt_level = battery_get_lvl(BATT_CR2032);
#endif
}
app_bass_create_db()
真正的初始化(DataBase初始化)是由app_bass_create_db()
函數完成。
我們來看一下TASK_APP中關於DataBase初始化的過程。
從圖中我們可以看到user_prf_funcs[k++].db_create_func();
這個函數就是callback app_bass_create_db()的傢伙。
調用app_bass_create_db()函數之後,它就結束退出了。
而根源上這都是gapm_cmp_evt_handler函數的一個case。
gapm_cmp_evt_handler這個函數是一個比較底層的處理函數,我們不會去改動它。
當執行GAPM_SET_DEV_CONFIG這個case時就會去Create 各種DB。當然他只是開了一個頭,很快就結束了。
後續通過內核消息,在TASK_APP中各個APP互相調用,最終會完成所有的DB的初始化。
註冊app_bass_create_db()函數
我們來看下如何註冊app_bass_create_db()函數的。同時一同註冊還有一個很重要的函數app_bass_enable(),這個函數下面也會講。
這兩個函數是一起被註冊到TASK_APP。具體見下面的結構體數組。
該結構體數組被定義在app.c文件中。
const struct prf_func_callbacks prf_funcs[] =
{
#if BLE_PROX_REPORTER
{TASK_PROXR, app_proxr_create_db, app_proxr_enable},
#endif
#if BLE_BAS_SERVER
{TASK_BASS, app_bass_create_db, app_bass_enable},
#endif
#if BLE_FINDME_TARGET
{TASK_FINDT, NULL, app_findt_enable},
#endif
#if BLE_FINDME_LOCATOR
{TASK_FINDL, NULL, app_findl_enable},
#endif
#if BLE_DIS_SERVER
{TASK_DISS, app_diss_create_db, app_diss_enable},
#endif
#if BLE_SPOTA_RECEIVER
{TASK_SPOTAR, app_spotar_create_db, app_spotar_enable},
#endif
{TASK_NONE, NULL, NULL}, // DO NOT MOVE. Must always be last
};
prf_funcs這個數組被誰調用呢?下面的函數揭曉答案:
/**
****************************************************************************************
* @brief Initialize the database for all the included profiles.
* @return true if succeeded, else false
****************************************************************************************
*/
static bool app_db_init_next(void)
{
static uint8_t i __attribute__((section("retention_mem_area0"),zero_init)); //@RETENTION MEMORY;
static uint8_t k __attribute__((section("retention_mem_area0"),zero_init)); //@RETENTION MEMORY;
// initialise the databases for all the included profiles
while( user_prf_funcs[k].task_id != TASK_NONE )
{
if ( user_prf_funcs[k].db_create_func != NULL )
{
user_prf_funcs[k++].db_create_func();
return false;
}
else k++;
}
// initialise the databases for all the included profiles
while( prf_funcs[i].task_id != TASK_NONE )
{
if (( prf_funcs[i].db_create_func != NULL )
&& (!app_task_in_user_app(prf_funcs[i].task_id))) //case that the this task has an entry in the user_prf as well
{
prf_funcs[i++].db_create_func();
return false;
}
else i++;
}
#if BLE_CUSTOM_SERVER
{
static uint8_t j __attribute__((section("retention_mem_area0"),zero_init)); //@RETENTION MEMORY;
while( cust_prf_funcs[j].task_id != TASK_NONE )
{
if( cust_prf_funcs[j].db_create_func != NULL )
{
cust_prf_funcs[j++].db_create_func();
return false;
}
else j++;
}
j = 0;
}
#endif
k = 0;
i = 0;
return true;
}
是不是俄兒妹賊應,像prf_funcs這麼吊的還有兩個。
user_prf_funcs、prf_funcs、cust_prf_funcs這三個從名字就可以很清晰的看出是依照書序一次調用和初始化的。
prf_funcs初始化的是DISS、BASS、FINDME、PORX、SPOTA這幾個。CUST自然是由cust_prf_funcs來搞,其餘的就是USER。
prf_funcs調用完就退出了,那是怎麼循環完畢的呢?這就是我們下面研究的問題。各位看官請看下節。
APP DataBase初始化流程
上個小節中,我們看到app_db_init_next函數調用了一個callback就退出了,例如prf_funcs,那麼他是怎麼把所有APP Database全部初始化完的呢?
我們可以先看下app_db_init_next函數定義的兩個奇怪的i和k
static uint8_t i __attribute__((section("retention_mem_area0"),zero_init)); //@RETENTION MEMORY;
static uint8_t k __attribute__((section("retention_mem_area0"),zero_init)); //@RETENTION MEMORY;
這兩個變量不僅是靜態的局部變量還是存放在retention_mem_area0端的。啓動時會被初始化爲0。
所以,函數中的循環遍歷不是一次完成的而是這個函數被反覆調用後完成的。
我們先看下圖,這是我總結的以app_bass爲例的database初始化流程圖。