启动过程完成后立即进入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)可连接状态,该状态下蓝牙发射机在定时对外广播。