開機初始化Loghtml
Log編號 函數名 所在文件名web
1 000001: main ..\main.c 2 000002: timers_init ..\main.c 3 000003: gpiote_init ..\main.c 4 000004: buttons_init ..\main.c 5 000005: ble_stack_init ..\main.c 6 000006: bond_manager_init ..\main.c 7 000007: gap_params_init ..\main.c 8 000008: advertising_init ..\main.c 9 000009: services_init ..\main.c 10 000010: ble_hrs_init ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 11 000011: heart_rate_measurement_char_add ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 12 000012: hrm_encode ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 13 000013: body_sensor_location_char_add ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 14 000014: ble_bas_init ..\..\..\..\..\Source\ble\ble_services\ble_bas.c 15 000015: battery_level_char_add ..\..\..\..\..\Source\ble\ble_services\ble_bas.c 16 000016: ble_dis_init ..\..\..\..\..\Source\ble\ble_services\ble_dis.c 17 000017: char_add ..\..\..\..\..\Source\ble\ble_services\ble_dis.c 18 000018: conn_params_init ..\main.c 19 000019: sec_params_init ..\main.c 20 000020: advertising_start ..\main.c 21 000021: led_start ..\led.c 22 000022: ppi_init ..\led.c 23 000023: timer1_init ..\led.c 24 000024: gpiote_init ..\led.c
下面是main函數對應的初始化函數:架構
※ 上面Log中第九行server_init中會跳轉到hrs,bas,dis中進行相關操做,咱們重點分析——併發
【第一段黃色地帶講解】app
1 uint32_t ble_hrs_init(ble_hrs_t * p_hrs, const ble_hrs_init_t * p_hrs_init) 2 { 3 LOG(__FUNCTION__); 4 uint32_t err_code; 5 ble_uuid_t ble_uuid; 6 7 // Initialize service structure 8 p_hrs->evt_handler = p_hrs_init->evt_handler; 9 p_hrs->is_sensor_contact_supported = p_hrs_init->is_sensor_contact_supported; 10 p_hrs->conn_handle = BLE_CONN_HANDLE_INVALID; 11 p_hrs->is_sensor_contact_detected = false; 12 p_hrs->rr_interval_count = 0;
這一部分主要是初始化p_hrs結構體,p_hrs_init的內容在server_init賦值的,以下:
其中第433行設置hrs的事件句柄,這樣能夠在其中監聽hrs的相關事件,以下:
這個和ble_evt_dispatch傳送BLE協議棧事件給hrs模塊的ble_hrs_on_ble_evt函數稍有不一樣
在on_xxxx中主要處理on_connect、disconnect和write事件
注:其中case的兩個事件類型是自定義的枚舉型
上面437~443是設置hrs的attribute的可讀可寫等屬性的
其中hrs_hrm_attr_md是Initial security level for heart rate service measurement attribute
其中hrs_bsl_attr_md是Initial security level for body sensor location attribute
上面8九、90行的紅色部分的結構體爲:
可見,cccd比無cccd的多了個cccd_write_perm
這裏的cccd爲:客戶端特性配置描述符(Client Characteristic Configuration Descriptor,CCCD)
這個帶cccd的結構體在SDK描述以下:
Security settings structure.
This structure contains the security options needed during initialization of the service. It can be used when the charecteristics contains cccd.
個人理解是attribute中的屬性有兩種:屬性值或描述符。若是想支持通知或指示notify,那麼就得選用cccd的這種~
注:關於BLE的一些名詞[1] profile\service\characteristic\uuid關係[2]
綜上:HRS服務配置了兩個characteristic,他們分別是heart rate measurement characteristic(簡稱HRMC)和body sensor location characteristic。其中HRMC具備notify功能,不具備讀寫功能,即:他的值不能被其餘藍牙設備請求讀寫,只能主動發送給設備(稱爲notify,相似於web中的推送~)
14 // Add service 15 BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HEART_RATE_SERVICE);
16
17 err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_hrs->service_handle);
18 if (err_code != NRF_SUCCESS)
19 {
20 return err_code;
21 }
其中BLE_UUID_BLE_ASSIGN是一個給uuid初始賦值的宏定義:
而sd_ble_gatts_service_add負責:Add a service declaration to the local server ATT table.
談到sd_ble_gatts_service_add,就必須談一下Function packet format:
綜上:上面14~21行代碼就實現了將BLE_UUID_HEART_RATE_SERVICE加入到藍牙協議棧中~
23 // Add heart rate measurement characteristic 24 err_code = heart_rate_measurement_char_add(p_hrs, p_hrs_init); 25 if (err_code != NRF_SUCCESS) 26 { 27 return err_code; 28 }
這裏heart_rate_measurement_char_add是向上面添加的服務中添加characteristic的,非API函數,具體拆分講解以下:
該函數前面都是一些賦值操做,最後調用了一個API函數:
以下,該API實現將一個屬性聲明,一個屬性值聲明和一個可選屬性描述符聲明添加進ATT表。
這個添加的屬性會添加進最近添加的服務中,固然perminssions須要統一等狀況要注意~
該函數的參數狀況以下:
· 第一個service_handle指向該屬性所在的服務
· 第二個p_char_md是屬性的原數據
· 第三個p_attr_char_value是指向attribute結構體所對應的屬性值
· 第四個p_handles是指向指定句柄所存儲的結構體
在調用上面API以前,首先對p_char_md屬性原數據進行配置attribute
接着配置p_attr_char_value進行配置:
其實通過前面的這些配置以後,再調用API函數sd_ble_gatts_characteristic_add就會造成一個下面格式的包:
注:sd_ble_gatts_characteristic_add 功能的包格式[3]
30 if (p_hrs_init->p_body_sensor_location != NULL) 31 { 32 // Add body sensor location characteristic 33 err_code = body_sensor_location_char_add(p_hrs, p_hrs_init); 34 if (err_code != NRF_SUCCESS) 35 { 36 return err_code; 37 } 38 }
最後判斷是否要把body sensor location characteristic加入到hrs服務中~
40 return NRF_SUCCESS; 41 }
鏈接藍牙後的效果ide
1 000025: ble_evt_dispatch ..\main.c 2 000026: ble_hrs_on_ble_evt ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 3 000027: on_connect ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 4 000028: ble_bas_on_ble_evt ..\..\..\..\..\Source\ble\ble_services\ble_bas.c 5 000029: on_connect ..\..\..\..\..\Source\ble\ble_services\ble_bas.c 6 000030: on_ble_evt ..\main.c 7 000031: led_stop ..\led.c 8 000032: application_timers_start ..\main.c 9 000033: heart_rate_meas_timeout_handler ..\main.c 10 000034: ble_hrs_heart_rate_measurement_send ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 11 000035: hrm_encode ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 12 000036: heart_rate_meas_timeout_handler ..\main.c 13 000037: ble_hrs_heart_rate_measurement_send ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 14 000038: hrm_encode ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 15 000039: battery_level_meas_timeout_handler ..\main.c 16 000040: battery_start ..\battery.c 17 000041: ADC_IRQHandler ..\battery.c 18 000042: ble_bas_battery_level_update ..\..\..\..\..\Source\ble\ble_services\ble_bas.c 19 000043: heart_rate_meas_timeout_handler ..\main.c 20 000044: ble_hrs_heart_rate_measurement_send ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 21 000045: hrm_encode ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 22 000046: heart_rate_meas_timeout_handler ..\main.c 23 000047: ble_hrs_heart_rate_measurement_send ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c the same...
如Log第25行手機鏈接上nRF51822以後,BLE協議棧把事件經過ble_evt_dispatch分配到每一個模
函數
1 /**@brief Function for dispatching a BLE stack event to all modules with a BLE stack event handler. 2 * 3 * @details This function is called from the BLE Stack event interrupt handler after a BLE stack 4 * event has been received. 5 * 6 * @param[in] p_ble_evt Bluetooth stack event. 7 */ 8 static void ble_evt_dispatch(ble_evt_t * p_ble_evt) 9 { 10 LOG(__FUNCTION__); 11 ble_bondmngr_on_ble_evt(p_ble_evt); 12 ble_hrs_on_ble_evt(&m_hrs, p_ble_evt);
先進入ble_hrs_on_ble_evt,進而解析事件執行on_connect,以下:eto
13 ble_bas_on_ble_evt(&bas, p_ble_evt); 14 ble_conn_params_on_ble_evt(p_ble_evt); 15 on_ble_evt(p_ble_evt);
在on_ble_evt中當檢測到connected事件,
則關閉標誌廣播進行中的燈的定時器,
start在timer初始化中設置的hrs和bas定時器,也所以在Log中接着會輪流週期性觸發hrs和bas的timeout句柄
16 }
Heart Rate Measurement啓動或終止notify監聽時的Log post
1 002044: ble_evt_dispatch ..\main.c 2 002045: ble_hrs_on_ble_evt ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 3 002046: on_write ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 4 002047: on_hrm_cccd_write ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 5 002048: hrs_event_handler ..\main.c 6 002049: ble_bas_on_ble_evt ..\..\..\..\..\Source\ble\ble_services\ble_bas.c 7 002050: on_write ..\..\..\..\..\Source\ble\ble_services\ble_bas.c
當上位機(手機端)點擊start notify時,其實有一個交互過程的!字體
如上面的Log:ui
一、首先BLE協議棧把該事件經過dispatch分派給模塊ble_hrs_on_ble_evt
二、ble_hrs_on_ble_evt 對事件解析發現是BLE_GATTS_EVT_WRITE,並調用on_write
三、從on_write又進入on_hrm_cccd_write,在其中判斷併發送相應的evt_handler事件消息
四、該消息會發送到其接受函數hrs_event_handler中,並根據狀況設置notify
Heart Rate Measurement啓動監聽中的Log
1 000895: heart_rate_meas_timeout_handler ..\main.c 2 000896: ble_hrs_heart_rate_measurement_send ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 3 000897: hrm_encode ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 4 000898: ble_evt_dispatch ..\main.c 5 000899: ble_hrs_on_ble_evt ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 6 000900: ble_bas_on_ble_evt ..\..\..\..\..\Source\ble\ble_services\ble_bas.c 7 000901: on_ble_evt ..\main.c 8 000902: heart_rate_meas_timeout_handler ..\main.c 9 000903: ble_hrs_heart_rate_measurement_send ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 10 000904: hrm_encode ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 11 000905: battery_level_meas_timeout_handler ..\main.c 12 000906: battery_start ..\battery.c 13 000907: ADC_IRQHandler ..\battery.c 14 000908: ble_bas_battery_level_update ..\..\..\..\..\Source\ble\ble_services\ble_bas.c 15 000909: ble_evt_dispatch ..\main.c 16 000910: ble_hrs_on_ble_evt ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 17 000911: ble_bas_on_ble_evt ..\..\..\..\..\Source\ble\ble_services\ble_bas.c 18 000912: on_ble_evt ..\main.c
和鏈接藍牙後的Log的12-18行對比,因爲這裏開啓了notify,因此出現了些許不同的地方:
即:紅色字體的部分!
根據Log猜想(暫時沒有器材,沒法調試,到早上試,再給出最終結果~):
一、多是由於上位機使能了notification,執行了紅線那句話
二、以前因爲沒有執行這句話使ble_hrs_heart_rate_measurement_send和ble_bas_battery_level_update中的sd_ble_gatts_hvx函數沒有被執行,而一旦紅線那句話執行後sd_ble_gatts_hvx將被週期性地執行:
三、而每次sd_ble_gatts_hvx函數都會觸發ble協議棧產生相應的消息,經過ble_evt_dispatch派送到各個模塊,最終被on_ble_evt解析到BLE_GAP_EVT_SEC_PARAMS_REQUEST消息並執行相關操做,把消息發送出去:
藍牙斷開時的Log
1 008913: ble_evt_dispatch ..\main.c 2 008914: ble_hrs_on_ble_evt ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 3 008915: on_disconnect ..\..\..\..\..\Source\ble\ble_services\ble_hrs.c 4 008916: ble_bas_on_ble_evt ..\..\..\..\..\Source\ble\ble_services\ble_bas.c 5 008917: on_disconnect ..\..\..\..\..\Source\ble\ble_services\ble_bas.c 6 008918: on_ble_evt ..\main.c 7 008919: system_off_mode_enter ..\main.c
斷開藍牙比較簡單,消息從協議棧經dispatch分發到hrs、bas和on_ble_evt分別作相應處理!
注:
[1]、關於BLE的一些名詞:
每一個attribute屬性被UUID(通用惟一標識符)惟一標識 ,UUID是標準128-bit格式的ID用來惟一標識信息。attributes 被 ATT 格式化characteristics和services形式進行傳送。
· 特徵(Characteristics)— 一個characteristics包含一個單獨的value值和0 –n個用來描述characteristic 值(value)的descriptors。一個characteristics能夠被認爲是一種類型的,相似於一個類。
· 描述符(descriptor) —descriptor是被定義的attributes,用來描述一個characteristic的值。例如,一個descriptor能夠指定一我的類可讀的描述中,在可接受的範圍裏characteristic值,或者是測量單位,用來明確characteristic的值。
· 服務(service) —service是characteristic的集合。例如,你能夠有一個所謂的「Heart RateMonitor」service,其中包括characteristic,如「heart rate measurement 」。你能夠在 bluetooth.org找到關於一系列基於GATT的profile和service。
他們關係爲:藍牙設備能夠包括多個Profile,一個Profile中有多個Service,一個Service中有多個Characteristic,一個Characteristic中包括一個value和多個Descriptor。
[2]、profile\service\characteristic\uuid關係:
二、Operation Code = 0xA2 (162) for sd_ble_gatts_characteristic_add, see BLE_GATTS_SVCS.
三、The parameters provided as input to sd_ble_gatts_characteristic_add are encoded in the following order
- 1 byte: | Operation Code, Value = 0xA2 (162) |
|
- 2 bytes: | Service Handle |
|
- 1 byte: | Metadata Present | |
0x00 Field not present | ||
0x01 Field present and follows immediately in the packet | ||
- 11..539 bytes: | ble_gatts_char_md_t | Conditional: Characteristic Metadata |
- 1 byte: | Characteristic Attribute Present | |
0x00 Field not present | ||
0x01 Field present and follows immediately in the packet | ||
- 9..527 bytes: | ble_gatts_attr_t | Conditional: Characteristic Attribute |
- 1 byte: | Handles Present | |
0x00 Field not present | ||
0x01 Field present on Application Chip |
其包格式圖像表示爲:(其中characteristic metadata和char attributes展開太多,請參看SDK)
注:
本篇講了nrf51822藍牙ble工程的消息流
至此整個藍牙心率計工程分析得差很少了
本工程連接:http://pan.baidu.com/s/1dEalb6h
More:
[藍牙] 一、藍牙核心技術瞭解(藍牙協議、架構、硬件和軟件筆記)
[藍牙] 二、藍牙BLE協議及架構淺析&&基於廣播超時待機說廣播事件
[藍牙] 四、Heart Rate Service module
@beautifulzzzz 2015-12-17 continue~