启动过程完成后立即进入main_func函数。该函数在进入主循环while(1)之前,只调用了system_init()函数。system_init()函数里面包含了对看门狗、时钟、外设、检查和读取蓝牙物理地址、BLE的初始化等等。BLE初始化部分具体包含init_pwr_and_clk_ble()、rwip_clear_interrupts ()、rwip_init()等。这些函数是固化代码,不对开发者开放。从官方SDK看,尽管BLE协议栈非常庞大,但是BLE的main函数却是非常简单的,不算注释,代码总共只有短短30来行。
int main_func(void)
{
sleep_mode_t sleep_mode;//睡眠模式变量,枚举型
//global initialise
system_init();
/*
************************************************************************************
* Platform initialization
************************************************************************************
*/
while(1)
{
do {
// schedule all pending events
schedule_while_ble_on();
}
while (app_asynch_proc() != GOTO_SLEEP); //grant control to the application, try to go to power down
//if the application returns GOTO_SLEEP
//((STREAMDATA_QUEUE)&& stream_queue_more_data())); //grant control to the streamer, try to go to power down
//if the application returns GOTO_SLEEP
//wait for interrupt and go to sleep if this is allowed
if (((!BLE_APP_PRESENT) && (check_gtl_state())) || (BLE_APP_PRESENT))
{
//Disable the interrupts
GLOBAL_INT_STOP();
app_asynch_sleep_proc();
// get the allowed sleep mode
// time from rwip_power_down() to WFI() must be kept as short as possible!!
sleep_mode = rwip_power_down();
if ((sleep_mode == mode_ext_sleep) || (sleep_mode == mode_deep_sleep))
{
//power down the radio and whatever is allowed
arch_goto_sleep(sleep_mode);
// In extended or deep sleep mode the watchdog timer is disabled
// (power domain PD_SYS is automatically OFF). Although, if the debugger
// is attached the watchdog timer remains enabled and must be explicitly
// disabled.
if ((GetWord16(SYS_STAT_REG) & DBG_IS_UP) == DBG_IS_UP)
{
wdg_freeze(); // Stop watchdog timer
}
//wait for an interrupt to resume operation
WFI();
//resume operation
arch_resume_from_sleep();
}
else if (sleep_mode == mode_idle)
{
if (((!BLE_APP_PRESENT) && check_gtl_state()) || (BLE_APP_PRESENT))
{
//wait for an interrupt to resume operation
WFI();
}
}
// restore interrupts
GLOBAL_INT_START();
}
wdg_reload(WATCHDOG_DEFAULT_PERIOD);
}
}
GAP(Generic Access Profile)通用访问规范层算是BLE协议栈中最顶部的一层,它定义了设备如何广播、扫描、发现和建立连接,以及配置工作角色(Role)、可发现性、广播数据内容和安全相关的参数。
GAP 就绪后,会产生GAP_READY_EVT 消息,该消息会回调gapm_device_ready_ind_handler函数。函数原型如下:
/**
****************************************************************************************
* @brief Handles ready indication from the GAP. - Reset the stack.
* @param[in] msgid Id of the message received.
* @param[in] param Pointer to the parameters of the message.
* @param[in] dest_id ID of the receiving task instance (TASK_GAP).
* @param[in] src_id ID of the sending task instance.
* @return If the message was consumed or not.
****************************************************************************************
*/
static int gapm_device_ready_ind_handler(ke_msg_id_t const msgid,
void const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
if (ke_state_get(dest_id) == APP_DISABLED)//如果TASK_GAP处于APP_DISABLED状态,与if(APP_DISABLED == ke_state_get(TASK_APP)等效
{
// reset the lower layers.
app_gapm_reset_op();//创建并发送一个重置GAP的消息
}
else
{
// APP_DISABLED state is used to wait the GAP_READY_EVT message
ASSERT_ERR(0);//如果不是APP_DISABLED状态,将会触发重启
}
return (KE_MSG_CONSUMED);//返回该消息已经处理
}
该函数判断TASK_GAP如果处于APP_DISABLED状态,就会产生和发送一个GAP 重置堆栈的消息。如果不是APP_DISABLED状态,将会触发重启。判断状态使用了内核提供的ke_state_get()函数。APP task的状态是枚举型,APP_DISABLED是初始的重置状态。APP_DISABLED 状态用于等待 GAP_READY_EVT消息。
APP task有6种状态,具体定义如下:
/*
* ENUMERATIONS
****************************************************************************************
*/
/// States of APP task
enum APP_STATE
{
/// Disabled State
APP_DISABLED,
/// Database Initialization State
APP_DB_INIT,
/// Connectable state
APP_CONNECTABLE,
/**
* CONNECTED STATES
*/
/// Security state,
APP_SECURITY,
/// Connection Parameter Update State
APP_PARAM_UPD,
/// Connected state
APP_CONNECTED,
/// Number of defined states.
APP_STATE_MAX
};
app_gapm_reset_op()函数创建并发送一个重置GAP的消息,其原型如下:
****************************************************************************************
* @brief Send a gap manager reset operation.
* @return void
****************************************************************************************
*/
__INLINE void app_gapm_reset_op (void)
{
struct gapm_reset_cmd* cmd = app_gapm_reset_msg_create();//生成消息
app_gapm_reset_msg_send(cmd);//发送消息
}
重置GAP操作完成后,会产生一个GAPM_CMP_EVT消息,该消息触发回调函数gapm_cmp_evt_handler()。在这个函数里,对GAPM_RESET、GAPM_SET_DEV_CONFIG、GAPM_ADV_NON_CONN、GAPM_ADV_UNDIRECT、GAPM_ADV_DIRECT、GAPM_SCAN_ACTIVE、GAPM_SCAN_PASSIVE、GAPM_CONNECTION_DIRECT、GAPM_CANCEL等各种操作完成的消息进行分类处理。
/**
****************************************************************************************
* @brief Handles GAP manager command complete events.
* @param[in] msgid Id of the message received.
* @param[in] param Pointer to the parameters of the message.
* @param[in] dest_id ID of the receiving task instance (TASK_GAP).
* @param[in] src_id ID of the sending task instance.
* @return If the message was consumed or not.
****************************************************************************************
*/
static int gapm_cmp_evt_handler(ke_msg_id_t const msgid,
struct gapm_cmp_evt const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
switch(param->operation)
{
// reset completed
case GAPM_RESET:
{
if(param->status != GAP_ERR_NO_ERROR)
{
ASSERT_ERR(0); // unexpected error
}
else
{
// set device configuration
app_easy_gap_dev_configure ();
}
}
break;
// device configuration updated
case GAPM_SET_DEV_CONFIG:
{
if(param->status != GAP_ERR_NO_ERROR)
{
ASSERT_ERR(0); // unexpected error
}
else
{
EXECUTE_CALLBACK_VOID(app_on_set_dev_config_complete);
}
}
break;
// Non connectable advertising finished
case GAPM_ADV_NON_CONN:
{
EXECUTE_CALLBACK_PARAM(app_on_adv_nonconn_complete, param->status);
}
break;
// Undirected connectable advertising finished
case GAPM_ADV_UNDIRECT:
{
EXECUTE_CALLBACK_PARAM(app_on_adv_undirect_complete, param->status);
}
break;
// Directed connectable advertising finished
case GAPM_ADV_DIRECT:
{
EXECUTE_CALLBACK_PARAM(app_on_adv_direct_complete, param->status);
}
break;
case GAPM_SCAN_ACTIVE:
case GAPM_SCAN_PASSIVE:
{
EXECUTE_CALLBACK_PARAM(app_on_scanning_completed, param->status);
}
break;
case GAPM_CONNECTION_DIRECT:
if (param->status == GAP_ERR_CANCELED)
{
EXECUTE_CALLBACK_VOID(app_on_connect_failed);
}
break;
case GAPM_CANCEL:
{
if(param->status != GAP_ERR_NO_ERROR)
{
ASSERT_ERR(0); // unexpected error
}
if (app_process_catch_rest_cb != NULL)
{
app_process_catch_rest_cb(msgid, param, dest_id, src_id);
}
}
break;
default:
if (app_process_catch_rest_cb != NULL)
{
app_process_catch_rest_cb(msgid, param, dest_id, src_id);
}
break;
}
return (KE_MSG_CONSUMED);
}
gapm_cmp_evt_handler函数判断消息是GAPM_RESET完成后,会调用app_easy_gap_dev_configure (),来配置GAP参数。dev_configure就是device configuration的缩写。同样,该函数并不是自己去配置GAP,而是产生一个配置GAP的消息并发送出去。函数原型如下:
void app_easy_gap_dev_configure(void)
{
struct gapm_set_dev_config_cmd* cmd = app_easy_gap_dev_config_create_msg();
app_gapm_configure_msg_send(cmd);
set_dev_config_cmd = NULL;
}
GAP配置完成后,会再次产一个GAPM_CMP_EVT消息,该消息的内容则是GAPM_SET_DEV_CONFIG完成,然后会再次触发gapm_cmp_evt_handler函数处理,具体调用EXECUTE_CALLBACK_VOID(app_on_set_dev_config_complete);函数,void (*app_on_set_dev_config_complete)(void)函数时APP回调函数结构体的一个成员。该结构体如下:
struct app_callbacks
{
void (*app_on_connection)(const uint8_t, struct gapc_connection_req_ind const *);
void (*app_on_disconnect)(struct gapc_disconnect_ind const *);
void (*app_on_update_params_rejected)(const uint8_t);
void (*app_on_update_params_complete)(void);
void (*app_on_set_dev_config_complete)(void);
void (*app_on_adv_nonconn_complete)(const uint8_t);
void (*app_on_adv_undirect_complete)(const uint8_t);
void (*app_on_adv_direct_complete)(const uint8_t);
void (*app_on_db_init_complete)(void);
void (*app_on_scanning_completed)(const uint8_t);
void (*app_on_adv_report_ind)(struct gapm_adv_report_ind const *);
void (*app_on_connect_failed)(void);
#if (BLE_APP_SEC)
void (*app_on_pairing_request)(const uint8_t, struct gapc_bond_req_ind const *);
void (*app_on_tk_exch_nomitm)(const uint8_t, struct gapc_bond_req_ind const *);
void (*app_on_irk_exch)(struct gapc_bond_req_ind const *);
void (*app_on_csrk_exch)(const uint8_t, struct gapc_bond_req_ind const *);
void (*app_on_ltk_exch)(const uint8_t, struct gapc_bond_req_ind const *);
void (*app_on_pairing_succeded)(void);
void (*app_on_encrypt_ind)(const uint8_t);
void (*app_on_mitm_passcode_req)(const uint8_t);
void (*app_on_encrypt_req_ind)(const uint8_t, struct gapc_encrypt_req_ind const *);
void (*app_on_security_req_ind)(const uint8_t);
#endif
};
在user_callback_config.h文件里,定义了app_on_set_dev_config_complete = default_app_on_set_dev_config_complete。
static const struct app_callbacks user_app_callbacks = {
.app_on_connection = user_app_connection,
.app_on_disconnect = user_app_disconnect,
.app_on_update_params_rejected = NULL,
.app_on_update_params_complete = NULL,
.app_on_set_dev_config_complete = default_app_on_set_dev_config_complete,
.app_on_adv_nonconn_complete = NULL,
.app_on_adv_undirect_complete = user_app_adv_undirect_complete,
.app_on_adv_direct_complete = NULL,
.app_on_db_init_complete = default_app_on_db_init_complete,
.app_on_scanning_completed = NULL,
.app_on_adv_report_ind = NULL,
#if (BLE_APP_SEC)
.app_on_pairing_request = NULL,
.app_on_tk_exch_nomitm = NULL,
.app_on_irk_exch = NULL,
.app_on_csrk_exch = NULL,
.app_on_ltk_exch = NULL,
.app_on_pairing_succeded = NULL,
.app_on_encrypt_ind = NULL,
.app_on_mitm_passcode_req = NULL,
.app_on_encrypt_req_ind = NULL,
.app_on_security_req_ind = NULL,
#endif // (BLE_APP_SEC)
};
default_app_on_set_dev_config_complete()函数的原型如下,该回调函数里调用了app_db_init_start()函数。
void default_app_on_set_dev_config_complete( void )
{
// Add the first required service in the database
if (app_db_init_start())
{
// No service to add in the DB -> Start Advertising
EXECUTE_DEFAULT_OPERATION_VOID(default_operation_adv);
}
}
app_db_init_start()函数先调用内核ke_state_set()函数,把APP task的状态从APP_DISABLED转换到APP_DB_INIT状态,也就是Database Initialization State。然后调用app_db_init_next(void)函数,为所有包含的配置文件初始化数据库。
bool app_db_init_start(void)
{
// Indicate if more services need to be added in the database
bool end_db_create = false;
// We are now in Initialization State
ke_state_set(TASK_APP, APP_DB_INIT);
end_db_create = app_db_init_next();
return end_db_create;
}
/**
****************************************************************************************
* @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;
}
并在app_db_init_start()完成返回1时调用default_operation_adv回调函数,该函数default_operation_adv = user_app_adv_start。
user_app_adv_start()回调函数开启广播,其原型如下,先是调用了app_easy_timer()开启定时任务,然后调用app_easy_gap_undirected_advertise_get_active(),为可连接的无向事件(ADV_IND)创建广告消息, 然后调用mnf_data_update()加载制造商信息,然后使用app_add_ad_struct()函数加载广播或者扫描回复的具体信息,该信息在GAP开始广播命令结构体gapm_start_advertise_cmd定义。
void user_app_adv_start(void)
{
// Schedule the next advertising data update
app_adv_data_update_timer_used = app_easy_timer(APP_ADV_DATA_UPDATE_TO, adv_data_update_timer_cb);
struct gapm_start_advertise_cmd* cmd;
cmd = app_easy_gap_undirected_advertise_get_active();
// add manufacturer specific data dynamically
mnf_data_update();
app_add_ad_struct(cmd, &mnf_data, sizeof(struct mnf_specific_data_ad_structure));
app_easy_gap_undirected_advertise_start();
}
/// Set advertising mode Command
struct gapm_start_advertise_cmd
{
/// GAPM requested operation:
/// - GAPM_ADV_NON_CONN: Start non connectable advertising 启动不可连接的广播
/// - GAPM_ADV_UNDIRECT: Start undirected connectable advertising 启动无定向可连接的广播
/// - GAPM_ADV_DIRECT: Start directed connectable advertising启动定向连接广播
/// - GAPM_ADV_DIRECT_LDC: Start directed connectable advertising using Low Duty Cycle 使用低占空比的定向连接广播
struct gapm_air_operation op;
/// Minimum interval for advertising 广播最小时间间隔
uint16_t intv_min;
/// Maximum interval for advertising 广播最大时间间隔
uint16_t intv_max;
///Advertising channel map 广播通道map
uint8_t channel_map;
/// Advertising information 广播的信息
union gapm_adv_info
{
/// Host information advertising data (GAPM_ADV_NON_CONN and GAPM_ADV_UNDIRECT) 主机信息广播数据
struct gapm_adv_host host;
/// Direct address information (GAPM_ADV_DIRECT) 直接地址信息
/// (used only if reconnection address isn't set or host privacy is disabled) 仅在未设置重连接地址或禁用主机隐私时使用
struct gap_bdaddr direct;
} info;
};
在gapm_start_advertise_cmd结构体下,还包含一个gapm_air_operation结构体和一个gapm_adv_info联合体。
/// Air operation default parameters 空中默认参数
struct gapm_air_operation
{
/// Operation code.操作码
uint8_t code;
/**
* Own BD address source of the device: 设备自身的BD地址源:
* - GAPM_STATIC_ADDR: Public or Random Static Address according to device address configuration
* - GAPM_GEN_RSLV_ADDR: Generated Random Resolvable Private Address
* - GAPM_GEN_NON_RSLV_ADDR: Generated Random non-Resolvable Private Address
*/
uint8_t addr_src;
/// Dummy data use to retrieve internal operation state (should be set to 0).
//虚拟数据用于检索内部操作状态(应设置为0)。
uint16_t state;
};
gapm_adv_info联合体包含2个结构体:gapm_adv_host host、gap_bdaddr direct。
/// Advertising data that contains information set by host.包含由主机设置的信息的广告数据。
struct gapm_adv_host
{
/// Advertising mode : 广播模式
/// - GAP_NON_DISCOVERABLE: Non discoverable mode 不可发现模式
/// - GAP_GEN_DISCOVERABLE: General discoverable mode 常规可发现模式
/// - GAP_LIM_DISCOVERABLE: Limited discoverable mode 受限的可发现模式
/// - GAP_BROADCASTER_MODE: Broadcaster mode 广播模式
uint8_t mode;
/// Advertising filter policy:
/// - ADV_ALLOW_SCAN_ANY_CON_ANY: Allow both scan and connection requests from anyone
/// - ADV_ALLOW_SCAN_WLST_CON_ANY: Allow both scan req from White List devices only and
/// connection req from anyone
/// - ADV_ALLOW_SCAN_ANY_CON_WLST: Allow both scan req from anyone and connection req
/// from White List devices only
/// - ADV_ALLOW_SCAN_WLST_CON_WLST: Allow scan and connection requests from White List
/// devices only
uint8_t adv_filt_policy;
/// Advertising data length - maximum 28 bytes, 3 bytes are reserved to set
/// Advertising AD type flags, shall not be set in advertising data
uint8_t adv_data_len;
/// Advertising data
uint8_t adv_data[ADV_DATA_LEN];
/// Scan response data length- maximum 31 bytes
uint8_t scan_rsp_data_len;
/// Scan response data
uint8_t scan_rsp_data[SCAN_RSP_DATA_LEN];
/// Peer Info - bdaddr
struct gap_bdaddr peer_info;
};
/// Address information about a device address
struct gap_bdaddr
{
/// BD Address of device蓝牙设备48bit物理地址
struct bd_addr addr;
/// Address type of the device 0=public/1=private random
uint8_t addr_type;
};
所有广播信息准备完成后,调用app_easy_gap_undirected_advertise_start()函数,该函数负责产生一个开始广播的消息并发送出去。具体是通过app_easy_gap_undirected_advertise_start_create_msg()和app_advertise_start_msg_send()函数完成。消息发送完成后,调用了内核的状态切换函数ke_state_set(),把TASK_APP状态更改为 APP_CONNECTABLE状态。函数原型如下:
void app_easy_gap_undirected_advertise_start(void)
{
struct gapm_start_advertise_cmd* cmd;
cmd = app_easy_gap_undirected_advertise_start_create_msg();
// Send the message
app_advertise_start_msg_send(cmd);
adv_cmd = NULL ;
// We are now connectable
ke_state_set(TASK_APP, APP_CONNECTABLE);
}
状态切换完成后,BLE已经开始定时广播了,可以使用手机搜索到该蓝牙的存在,这就是蓝牙BLE协议栈的整个启动过程。
以上内容有点多,但是逻辑时序是很清晰的。期间APP task总共切换了三次状态,从Disabled State( APP_DISABLED)到Database Initialization State(APP_DB_INIT)数据库初始状态,然后到Connectable state( APP_CONNECTABLE)可连接状态,该状态下蓝牙发射机在定时对外广播。