[蓝牙] 6、基于nRF51822的蓝牙心率计工程消息流Log分析(详细)
?
?
開機初始化Log
?
Log編號 函數名 ? 所在文件名
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中進行相關操作,我們重點分析——
【第一段黃色地帶講解】
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
上面89、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 }
?
連接藍牙后的效果
?
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分配到每個模
先進入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?
?
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:
1、首先BLE協議棧把該事件通過dispatch分派給模塊ble_hrs_on_ble_evt?
2、ble_hrs_on_ble_evt 對事件解析發現是BLE_GATTS_EVT_WRITE,并調用on_write
3、從on_write又進入on_hrm_cccd_write,在其中判斷并發送相應的evt_handler事件消息
4、該消息會發送到其接受函數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.c6 000900: ble_bas_on_ble_evt ..\..\..\..\..\Source\ble\ble_services\ble_bas.c7 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猜測(暫時沒有器材,無法調試,到早上試,再給出最終結果~):
1、可能是因為上位機使能了notification,執行了紅線那句話
2、之前由于沒有執行這句話使ble_hrs_heart_rate_measurement_send和ble_bas_battery_level_update中的sd_ble_gatts_hvx函數沒有被執行,而一旦紅線那句話執行后sd_ble_gatts_hvx將被周期性地執行:
3、而每次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關系:
1、profile ? profile可以理解為一種規范,一個標準的通信協議,它存在于從機中。藍牙組織規定了一些標準的profile,例如 HID OVER GATT ,防丟器 ,心率計等。每個profile中會包含多個service,每個service代表從機的一種能力。 2、service service可以理解為一個服務,在ble從機中,通過有多個服務,例如電量信息服務、系統信息服務等,每個service中又包含多個characteristic特征值。每個具體的characteristic特征值才是ble通信的主題。比如當前的電量是80%,所以會通過電量的characteristic特征值存在從機的profile里,這樣主機就可以通過這個characteristic來讀取80%這個數據 3、characteristic characteristic特征值,ble主從機的通信均是通過characteristic來實現,可以理解為一個標簽,通過這個標簽可以獲取或者寫入想要的內容。 4、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 功能的包格式: 1、Frame format encoding of the sd_ble_gatts_characteristic_add packet.2、Operation Code = 0xA2 (162) for sd_ble_gatts_characteristic_add, see BLE_GATTS_SVCS.
3、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:
[藍牙] 1、藍牙核心技術了解(藍牙協議、架構、硬件和軟件筆記)
[藍牙] 2、藍牙BLE協議及架構淺析&&基于廣播超時待機說廣播事件
[藍牙] 3、 剖析BLE心率檢測工程
[藍牙] 4、Heart Rate Service module
[藍牙] 5、Battery Service module
@beautifulzzzz?2015-12-17 continue~?
?
本文轉自beautifulzzzz博客園博客,原文鏈接:http://www.cnblogs.com/zjutlitao/p/5051166.html,如需轉載請自行聯系原作者
總結
以上是生活随笔為你收集整理的[蓝牙] 6、基于nRF51822的蓝牙心率计工程消息流Log分析(详细)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 按钮框
- 下一篇: wampserver 403forbid