主機使用例程:nRF5_SDK_17.1.0_ddde560\examples\ble_central\ble_app_blinky_c\pca10040\s132\arm5_no_packs
從機使用例程:nRF5_SDK_17.1.0_ddde560\examples\ble_peripheral\ble_app_blinky\pca10040\s132\arm5_no_packs
nrf52832
- 1. 空中資料包格式
-
- 1.1 Preamble
- 1.2 Access Address
- 1.3 PDU
-
- 1.3.1 當PDU在主要或者次要廣播信道上傳輸時,PDU格式
- 1.3.2 當PDU在資料信道上傳輸時,PDU格式
- 1.4 CRC
- 2. 主從機互動過程中SN和NESN變化
-
- 2.1 正常互動
- 2.2 重傳
- 2.3 CRC錯誤
- 3. 主從機連接配接抓包
-
- 3.1 從機廣播
- 3.2 主機連接配接
- 3.3 主機從機服務句柄值資訊交換
-
- 3.3.1 主機請求
- 3.3.2 從機響應
- 3.4 主機從機服務特征值資訊交換
-
- 3.4.1 主機請求
- 3.4.2 從機響應
- 3.5 其他互動過程
- 3.6 連接配接參數更新
-
- 3.6.1 從機請求
- 3.6.2 主機響應
- 3.7 資料互動
-
- 3.7.1 主機向從機寫入資料
- 3.7.2 從機向主機通知
1. 空中資料包格式
1.1 Preamble
如果在LE 1M實體層上發送或者接收時前導碼為1位元組;在LE 2M實體層上發送或者接收時為2位元組。前導碼是由bit位1和bit位0交替組成的,由接入位址的LSB位決定。
LE 1M實體層:
若接入位址的LSB位為0:01010101
若接入位址的LSB位為1:10101010
LE 2M實體層:
若接入位址的LSB位為0:0101010101010101
若接入位址的LSB位為1:1010101010101010
1.2 Access Address
接入位址為4位元組,廣播接入位址:
所有廣播接入位址的值都是固定的,其值為10001110100010011011111011010110b (0x8E89BED6)
資料接入位址:
這個位址是随機的,目的是使兩個裝置之間的每個鍊路層連接配接或者每個周期性的廣播時擁有不同的通路位址。處于初始化狀态的鍊路層将為它發送的每個初始化PDU生成一個新的通路位址;處于廣播狀态的鍊路層在每次設定啟用周期性廣播時,也會生成一個新的通路位址。這種随機的通路位址應該是一個32位的值。鍊路層生成的新的通路位址滿足以下條件:
1.它不得是本裝置上任何現有的鍊路層連接配接的通路位址。
2.它不得是任何啟用的周期性廣播的通路位址。
3.它不得有超過六個連續的0或1。
4.它不得是廣播信道包的通路位址。
5.它不應是一個與廣播信道包通路位址僅相差一位的序列。
6.不得所有4個位元組相等。
7.不得超過24個比特位翻轉。
8.在最後的6位中至少有2個比特位翻轉。
1.3 PDU
PDU為協定資料單元(Protocol Data Unit)。
1.3.1 當PDU在主要或者次要廣播信道上傳輸時,PDU格式
其中Header格式:
PDU Type:
RFU:1bit,保留給未來使用。
ChSel:1bit,表示通道選擇;為1支援通道選擇,為0不支援通道選擇。
TxAdd:1bit,廣播裝置位址類型;為0表示公共位址,為1表示随機位址。
RxAdd:1bit,目标裝置位址類型;為0表示公共位址,為1表示随機位址。
Length:8bit,表示Payload負載的長度;PDU的Payload負載長度與PDU類型有關。
1.3.2 當PDU在資料信道上傳輸時,PDU格式
其中Header格式:
相關字段的描述:
1.4 CRC
在每個鍊路層資料包的末尾都有一個24位的CRC。CRC多項式:x24 + x10 + x9 + x6 + x4 + x3 + x + 1
2. 主從機互動過程中SN和NESN變化
按照藍牙核心規範,通信從主裝置(裝置A )發送一個鍊路層資料包開始,SN和NESN都設定為零。從這一點開始,在每次發生的資料包交換中,如果一切正常,裝置A設定的SN字段的值将在0和1之間交替。是以,次裝置(裝置B )總是知道下一個要接收的資料包的SN值應該是多少,并對此進行檢查。
2.1 正常互動
正常互動時SN和NESN變化圖:
Nordic的協定棧正常互動時同藍牙核心規範一緻。
2.2 重傳
如果裝置B接收到一個SN值錯誤的資料包,則假定該資料包是接收到的前一個資料包的重傳,承認該資料包,但不将其上傳到協定棧進行進一步處理。如果裝置A從裝置B的應答中收到了一個未預期的NESN值,或者根本沒有收到應答,它會重新發送原來使用相同SN值的資料包。不同的控制器實作可以自由地執行不同的算法,以确定通信失敗的次數。
重傳時SN和NESN變化圖:
2.3 CRC錯誤
每個資料包包含一個CRC字段,加密後的資料包也包含一個MIC字段。在接收到資料包時,鍊路層檢查CRC,如果MIC存在,則檢查MIC。如果其中一個檢查失敗,則不承認該資料包,這通常會導緻資料包的發起者重新發送該資料包。
Nordic的協定棧在出現CRC錯誤後,下一個連接配接事件直接把SN和NESN設定為1,跟藍牙核心規範不相同。
3. 主從機連接配接抓包
3.1 從機廣播
PDU Type為ADV_IND時,Payload格式:
PDU Type為SCAN_RSP時,Payload格式:
二者前6個位元組表示廣播裝置的位址,後面由0-31個位元組組成廣播資料。
廣播資料分為有效部分和無效部分,有效部分由一個個廣播資料結構體組成,length為結構體長度,AD Type表示AD Data的類型定義。在工程中ble_gap.h檔案中對AD Type有定義:
如果使用外觀的話隻能用SIG定義的外觀,工程中相關定義在ble_types.h檔案中:
上面3個AD structure中内容由從機在GAP參數初始化函數中設定:
在廣播初始化函數中選擇如何廣播:
3.2 主機連接配接
發起連接配接的一方稱為主機。PDU Type為CONNECT_IND或者AUX_CONNECT_REQ時,Payload格式:
InitA為主機位址,AdvA為廣播位址,其中LLData格式為:
AA:鍊路層生成通路位址。
CRCInit:校驗的初值,由鍊路層生成的随機值。
WinSize:建立連接配接時的連接配接視窗,值為WinSize1.25ms。
WinOffset:建立連接配接時的連接配接視窗偏移量,值為WinOffset1.25ms。
Interval:連接配接間隔,值為Interval1.25ms。
Latency:從機握手潛伏期。
Timeout:從機斷開逾時時間,值為Timeout10ms。
Chm:信道占用圖。
Hop:調頻算法的增量,值範圍5-16。
SCA:睡眠時鐘精度
主機工程在掃描初始化函數scan_init中調用了nrf_ble_scan_init函數,如果沒有設定連接配接參數,則會使用預設的連接配接參數:
3.3 主機從機服務句柄值資訊交換
L2CAP基本資訊幀如下:
Channel ID也就是CID,其中0x0004表示屬性協定:
ATT主機請求服務句柄值資訊Payload如下:
ATT從機響應服務句柄值資訊Payload如下:
句柄資訊Handles Information包含如下:
UUID類型在ble_types.h中定義:
3.3.1 主機請求
128位私有服務的UUID就是從機工程中定義的基本UUID加上服務UUID:
#define LBS_UUID_BASE {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, \
0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00}
#define LBS_UUID_SERVICE 0x1523
#define LBS_UUID_BUTTON_CHAR 0x1524
#define LBS_UUID_LED_CHAR 0x1525
3.3.2 從機響應
3.4 主機從機服務特征值資訊交換
ATT主機請求服務特征值資訊Payload如下:
ATT從機響應服務特征值資訊Payload如下:
3.4.1 主機請求
句柄的值是唯一的,是以本次請求時起始句柄值從服務句柄值開始。
3.4.2 從機響應
從機工程主服務有兩個特征值,一個是按鍵通知,一個是LED控制,因為MTU的值為預設值23,是以需要分兩次交換特征性。
3.5 其他互動過程
此外還有其他的互動過程主要是針對按鍵服務打開通知功能。
查找資訊請求(Find Information Request0x04)及響應(Find Information Response0x05)用于擷取屬性句柄與其關聯類型的映射。這使得用戶端可以在伺服器上發現屬性及其類型的清單。
寫請求(Write Request0x12)及寫響應(Write Response0x13)用于請求伺服器寫入一個屬性的值,并在Write Response中确認已經寫入成功。
3.6 連接配接參數更新
連接配接參數主要包括最小連接配接間隔、最大連接配接間隔、從機潛伏周期和連接配接逾時時間。在最大連接配接間隔内要有一次成功的資料互動,可以是空的PDU;在連接配接逾時時間到達時如果沒有一次成功的資料互動,則認為連接配接斷開;從機潛伏周期為從機能忽略多少個主機的連接配接事件,用于從機達到更好的功耗。設定時最小連接配接間隔和最大連接配接間隔步進為1.25ms,範圍7.5ms至4s(值6至3200),連接配接逾時時間步進為10ms,範圍100ms至32s(值10至3200)。
在未進行連接配接參數更新時,主機和從機之間使用主機設定的連接配接間隔來進行互動,預設最大連接配接間隔為30ms,最小連接配接間隔為7.5ms。
3.6.1 從機請求
L2CAP的CID為0x0005,連接配接參數更新請求代碼為0x12。
連接配接參數更新由從機發起,格式為:
其中Identifier字段長度為1位元組,響應與請求比對,請求裝置設定此字段,響應裝置在其響應中使用相同的值。
從機請求的這些連接配接參數就是在GAP參數初始化gap_params_init函數中設定的值。
static void gap_params_init(void)
{
ret_code_t err_code;
ble_gap_conn_params_t gap_conn_params;
ble_gap_conn_sec_mode_t sec_mode;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);//連接配接模式,主要是是否需要加密
err_code = sd_ble_gap_device_name_set(&sec_mode,
(const uint8_t *)DEVICE_NAME,
strlen(DEVICE_NAME));//裝置名稱設定
APP_ERROR_CHECK(err_code);
err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_HID_MOUSE);
memset(&gap_conn_params, 0, sizeof(gap_conn_params));//連接配接參數設定
gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;//最小連接配接間隔
gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;//最大連接配接間隔
gap_conn_params.slave_latency = SLAVE_LATENCY;//從裝置延遲,從裝置可以跳過連接配接事件
gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;//兩個成功的連接配接事件之間的最大間隔,超過後會認為連接配接丢失(100ms至32s之間)
err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
APP_ERROR_CHECK(err_code);
}
3.6.2 主機響應
主機響應格式:
其中Result定義:
連接配接參數更新完成後,主機和從機之間的連接配接間隔會以從機請求成功的值來運作,從機設定的最大連接配接間隔為200ms,最小連接配接間隔為100ms。
從機什麼時候去更新連接配接參數是由自己決定的,在從機工程中conn_params_init函數中有設定first_conn_params_update_delay參數表示從連接配接後多久更新連接配接參數。ble_conn_params_init函數中會建立一個軟體定時器來處理連接配接參數更新的過程。工程中FIRST_CONN_PARAMS_UPDATE_DELAY宏定義為20s。
static void conn_params_init(void)
{
ret_code_t err_code;
ble_conn_params_init_t cp_init;
memset(&cp_init, 0, sizeof(cp_init));
cp_init.p_conn_params = NULL;//指向應用程式中設定的GAP連接配接參數,如果設定為NULL,則連接配接參數從主機獲得
cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;//初始化事件(連接配接或啟動通知)到第一次連接配接參數更新的時間
cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;//第一次更新後,下次發起更新申請的間隔時間
cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;//放棄協商連接配接參數前最大重試次數
cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
cp_init.disconnect_on_fail = false;//設定為TRUE時如果連接配接參數更新失敗,則會自動斷開連接配接
cp_init.evt_handler = on_conn_params_evt;//連接配接參數更新結果對應的處理事件
cp_init.error_handler = conn_params_error_handler;//發生錯誤時的處理
err_code = ble_conn_params_init(&cp_init);
APP_ERROR_CHECK(err_code);
}
連接配接開始時間:
連接配接參數更新時間如下,時間間隔為20s:
3.7 資料互動
3.7.1 主機向從機寫入資料
主機向從機寫入資料需要用到寫指令:
3.7.2 從機向主機通知
伺服器可以随時發送屬性值的通知。伺服器也就是從機,用戶端是主機。