[藍牙] 六、基於nRF51822的藍牙心率計工程消息流Log分析(詳細)

 

 

開機初始化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關係:

一、profile  
  profile能夠理解爲一種規範,一個標準的通訊協議,它存在於從機中。藍牙組織規定了一些標準的profile,例如 HID OVER GATT ,防丟器 ,心率計等。每一個profile中會包含多個service,每一個service表明從機的一種能力。
二、service
  service能夠理解爲一個服務,在ble從機中,經過有多個服務,例如電量信息服務、系統信息服務等,每一個service中又包含多個characteristic特徵值。每一個具體的characteristic特徵值纔是ble通訊的主題。好比當前的電量是80%,因此會經過電量的characteristic特徵值存在從機的profile裏,這樣主機就能夠經過這個characteristic來讀取80%這個數據
三、characteristic
  characteristic特徵值,ble主從機的通訊均是經過characteristic來實現,能夠理解爲一個標籤,經過這個標籤能夠獲取或者寫入想要的內容。
四、UUID
  UUID,統一識別碼,咱們剛纔提到的service和characteristic,都須要一個惟一的uuid來標識
 
每一個從機都會有一個叫作profile的東西存在,不論是上面的自定義的simpleprofile,仍是標準的防丟器profile,他們都是由一些列service組成,而後每一個service又包含了多個characteristic,主機和從機之間的通訊,均是經過characteristic來實現。
實際產品中,每一個藍牙4.0的設備都是經過服務和特徵來展現本身的,服務和特徵都是用UUID來惟一標識的。一個設備必然包含一個或多個服務,每一個服務下面又包含若干個特徵。特徵是與外界交互的最小單位。藍牙設備硬件廠商一般都會提供他們的設備裏面各個服務(service)和特徵(characteristics)的功能,好比哪些是用來交互(讀寫),哪些可獲取模塊信息(只讀)等。好比說,一臺藍牙4.0設備,用特徵A來描述本身的出廠信息,用特徵B來與收發數據等。
 
[3]、sd_ble_gatts_characteristic_add 功能的包格式:
 
一、Frame format encoding of the sd_ble_gatts_characteristic_add packet.

二、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協議及架構淺析&&基於廣播超時待機說廣播事件

[藍牙] 三、 剖析BLE心率檢測工程

[藍牙] 四、Heart Rate Service module

[藍牙] 五、Battery Service module

@beautifulzzzz 2015-12-17 continue~ 

相關文章
相關標籤/搜索