启动过程完成后立即进入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 initialisesystem_init();/************************************************************************************** Platform initialization*************************************************************************************/while(1){do {// schedule all pending eventsschedule_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 allowedif (((!BLE_APP_PRESENT) && (check_gtl_state())) || (BLE_APP_PRESENT)){//Disable the interruptsGLOBAL_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 allowedarch_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 operationWFI();//resume operationarch_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 operationWFI();}}// restore interruptsGLOBAL_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 messageASSERT_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 StateAPP_DISABLED,/// Database Initialization StateAPP_DB_INIT,/// Connectable stateAPP_CONNECTABLE,/*** CONNECTED STATES*//// Security state,APP_SECURITY,/// Connection Parameter Update StateAPP_PARAM_UPD,/// Connected stateAPP_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 completedcase GAPM_RESET:{if(param->status != GAP_ERR_NO_ERROR){ASSERT_ERR(0); // unexpected error}else{// set device configurationapp_easy_gap_dev_configure ();}}break;// device configuration updatedcase 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 finishedcase GAPM_ADV_NON_CONN:{EXECUTE_CALLBACK_PARAM(app_on_adv_nonconn_complete, param->status);}break;// Undirected connectable advertising finishedcase GAPM_ADV_UNDIRECT:{EXECUTE_CALLBACK_PARAM(app_on_adv_undirect_complete, param->status);}break;// Directed connectable advertising finishedcase 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 databaseif (app_db_init_start()){// No service to add in the DB -> Start AdvertisingEXECUTE_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 databasebool end_db_create = false;// We are now in Initialization Stateke_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 profileswhile( 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 profileswhile( 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;}#endifk = 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 updateapp_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 dynamicallymnf_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  广播通道mapuint8_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 onlyuint8_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 datauint8_t              adv_data_len;/// Advertising datauint8_t              adv_data[ADV_DATA_LEN];/// Scan response data length- maximum 31 bytesuint8_t              scan_rsp_data_len;/// Scan response datauint8_t              scan_rsp_data[SCAN_RSP_DATA_LEN];/// Peer Info - bdaddrstruct 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 randomuint8_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 messageapp_advertise_start_msg_send(cmd);adv_cmd = NULL ;// We are now connectableke_state_set(TASK_APP, APP_CONNECTABLE);
}

状态切换完成后,BLE已经开始定时广播了,可以使用手机搜索到该蓝牙的存在,这就是蓝牙BLE协议栈的整个启动过程。

以上内容有点多,但是逻辑时序是很清晰的。期间APP task总共切换了三次状态,从Disabled State( APP_DISABLED)到Database Initialization State(APP_DB_INIT)数据库初始状态,然后到Connectable state( APP_CONNECTABLE)可连接状态,该状态下蓝牙发射机在定时对外广播。

DA14580BLE协议栈启动分析(含代码)相关推荐

  1. LL1分析构造法_数学建模算法--最优赋权法(含代码)

    数学建模算法--最优赋权法(含代码) 作者:郑铿城 本次介绍数学建模和科研写作的方法--最优赋权法最优赋权法经常用于分析评价类问题,从该算法的名称就可以看到,该算法首先要体现"最优" ...

  2. 动图图解C语言插入排序算法,含代码分析

    C语言文章更新目录 C语言学习资源汇总,史上最全面总结,没有之一 C/C++学习资源(百度云盘链接) 计算机二级资料(过级专用) C语言学习路线(从入门到实战) 编写C语言程序的7个步骤和编程机制 C ...

  3. 动图图解C语言选择排序算法,含代码分析

    C语言文章更新目录 C语言学习资源汇总,史上最全面总结,没有之一 C/C++学习资源(百度云盘链接) 计算机二级资料(过级专用) C语言学习路线(从入门到实战) 编写C语言程序的7个步骤和编程机制 C ...

  4. OpenCV与图像处理学习九——连通区域分析算法(含代码)

    OpenCV与图像处理学习九--连通区域分析算法(含代码) 一.连通区域概要 二.Two-Pass算法 三.代码实现 一.连通区域概要 连通区域(Connected Component)一般是指图像中 ...

  5. 【小白入门】超详细的OCRnet详解(含代码分析)

    [小白入门]超详细的OCRnet详解(含代码分析) OCRnet 简介 网络结构 具体实现(含代码分析) 实验结果 本文仅梳理总结自己在学习过程中的一些理解和思路,不保证绝对正确,请酌情参考.如果各位 ...

  6. 富芮坤FR801xH蓝牙协议栈启动流程和notify实现温度数据主动上传

    文章目录 一.蓝牙协议栈启动流程 1.1 初始化代码 1.2 初始化流程 1.3 回调函数里的初始化 二.notify实现 2.1 notify介绍 2.2 notify实现 2.3.1 定义数据 2 ...

  7. 使用python和pyqt5轻松上手人脸识别系统(含代码)

    使用python和pyqt5轻松上手人脸识别系统(含代码) 一. 环境配置 1.1 python环境配置 1.1.1 安装 anaconda 1.1.2 安装pycharm 1.1.3 配置pip源 ...

  8. BCM VOIP 启动分析

    VOIP进程启动后,用户线程涉及如下: 1. 和外界通讯的主线程2. Callmgr模块线程3. Endpt驱动事件处理线程4. Endpt驱动RTP/T38/RTCP数据包发送线程5. 几个RTP数 ...

  9. 物流信息管理系统MySQL设计,物流管理系统的SQL数据库设计(含代码)

    物流管理系统的SQL数据库设计(含代码) 物流管理信息系统的数据库设计班级xxx系统名称:物流管理信息系统一.需求分析物流管理系统是为制造商和零售商设计的管理系统数据库系统,目的是:1.实现上游制造商 ...

最新文章

  1. mysql 存储过程 排序_更改MySQL存储过程“数据库排序规则”的名称
  2. C#类型转换 (非原创)
  3. SpringBoot 路径处理
  4. 对象中multipartfile 空报错_Python 为什么会有个奇怪的“...”对象?
  5. Stars(树状数组)
  6. 前端学习(1716):前端系列javascript之页面配置下
  7. shell关闭指定进程
  8. 6.4. Test::More
  9. 像拍电影一样做软件(译者序)原创
  10. spring mvc 下载文件链接
  11. MySQL怎么查同一列多行展示_一个MySQL查询将多个行中的字符串合并为一行,并在另一列中显示相应的用户ID总和?...
  12. 链表相关的面试题型总结
  13. 分析一个JDK卡死问题,还真有点麻烦
  14. java后端getmonth_Java中的MonthDay getMonth()方法
  15. 钢琴节奏时值测试软件,钢琴技巧:弹奏时值较长双音的技巧——自网络
  16. Pandas requires version ‘2.0.1‘ or newer of ‘xlrd‘ (version ‘1.2.0‘ currently installed).
  17. 智能车辆纵向速度跟踪与控制方法研究
  18. (谷歌)Chrome浏览器添加扩展程序白名单
  19. ARM结构体系和接口技术
  20. Socks代理是什么意思

热门文章

  1. ubuntu 上 ESP8266 HomeKit 实战(五)2路继电器
  2. arcgis fishnet 单位_Arcgis CreateFishnet工具,生成到FileGDB中要素类的格网大小不一致...
  3. 2022-5-5 Leetcode 513.找树左下角的值
  4. ORA-00607 Internal error occurred while making a change to a data block处理
  5. php早起打卡,微信公众号早起打卡挑战应用制作教程
  6. 利用Spiking神经网络进行基于脑电图的情绪分类
  7. 交通方案 | 基于FET3399-C核心板打造公交二维码支付刷卡机
  8. 谈一谈游戏AI - 综述
  9. android自动发送dtmf,Android通话中发送DTMF信号
  10. 山工kw什么意思_为什么有时开了空调,反而感觉车子动力会变强