一默蚌、背景
鏈路層(LL)控制設(shè)備的射頻狀態(tài)冻晤,有五個(gè)設(shè)備狀態(tài):待機(jī)、廣播绸吸、掃描鼻弧、初始化和連接。
廣播 為廣播數(shù)據(jù)包锦茁,而 掃描 則是監(jiān)聽廣播攘轩。
GAP通信中角色,中心設(shè)備(Central - 主機(jī))用來掃描和連接 外圍設(shè)備(Peripheral - 從機(jī))码俩。
大部分情況下外圍設(shè)備通過廣播自己來讓中心設(shè)備發(fā)現(xiàn)自己度帮,并建立 GATT 連接,從而進(jìn)行更多的數(shù)據(jù)交換稿存。
也有些情況是不需要連接的笨篷,只要外設(shè)廣播自己的數(shù)據(jù)即可,用這種方式主要目的是讓外圍設(shè)備瓣履,把自己的信息發(fā)送給多個(gè)中心設(shè)備率翅。
在藍(lán)牙 4.x 的協(xié)議中,廣播包的大小為 31 個(gè)字節(jié)拂苹,如果主機(jī)有主動(dòng)掃描安聘,還有一個(gè) 31 字節(jié)大小的掃描響應(yīng)包,也就是說如果是藍(lán)牙 4.x 模式瓢棒,最大可實(shí)現(xiàn) 62 個(gè)字節(jié)大小的廣播內(nèi)容浴韭。
在藍(lán)牙 5.0 中,把廣播信道抽象為兩類脯宿,一種叫主廣播信道(primary advertisement channels)念颈,另一種叫次廣播信道,或者第二廣播信道(secondary advertising packets)连霉。
所謂的主廣播類似于藍(lán)牙 4.x 的廣播榴芳,只工作在 37嗡靡、38、39 三個(gè)信道窟感,最大廣播字節(jié)為 31 字節(jié)讨彼。而次廣播允許藍(lán)牙在除開 37、38柿祈、39 三個(gè)信道之外的其他 37 個(gè)信道上發(fā)送長度介于 0-255 字節(jié)的數(shù)據(jù)哈误。次廣播信道(0-36 channel)廣播 255 字節(jié)數(shù)據(jù)。
本篇是關(guān)于廣播自定義數(shù)據(jù)包躏嚎,配置以及啟動(dòng)或關(guān)閉廣播的流程查看 NRF52832學(xué)習(xí)筆記(9)——GAP從機(jī)端廣播
二蜜自、廣播內(nèi)容參數(shù)
在 ble_advertising.h 文件中,提供了廣播的初始化參數(shù)結(jié)構(gòu)體卢佣,如果你需要自定義廣播內(nèi)容重荠,那么就需要在廣播數(shù)據(jù)包 advdata
或者掃描響應(yīng)包 srdata
中添加內(nèi)容。
/**@brief Initialization parameters for the Advertising Module.
* @details This structure is used to pass advertising options, advertising data,
* and an event handler to the Advertising Module during initialization.
*/
typedef struct
{
ble_advdata_t advdata; /**< Advertising data: name, appearance, discovery flags, and more. */
ble_advdata_t srdata; /**< Scan response data: Supplement to advertising data. */
ble_adv_modes_config_t config; /**< Select which advertising modes and intervals will be utilized.*/
ble_adv_evt_handler_t evt_handler; /**< Event handler that will be called upon advertising events. */
ble_adv_error_handler_t error_handler; /**< Error handler that will propogate internal errors to the main applications. */
} ble_advertising_init_t;
-
advdata
:廣播數(shù)據(jù)包 -
srdata
:掃描響應(yīng)包 -
config
:配置廣播參數(shù)(廣播模式虚茶、廣播間隔戈鲁、廣播時(shí)間) -
evt_handler
:將在廣播事件上調(diào)用的事件處理程序 -
error_handler
:錯(cuò)誤處理程序,將把內(nèi)部錯(cuò)誤導(dǎo)入主應(yīng)用程序
我們可以看到廣播數(shù)據(jù)包advdata
或者掃描響應(yīng)包srdata
都是結(jié)構(gòu)體ble_advdata_t
類型媳危,該結(jié)構(gòu)體內(nèi)定義了廣播數(shù)據(jù)包或掃描響應(yīng)包可以定義的內(nèi)容:
/**@brief Advertising data structure. This structure contains all options and data needed for encoding and
* setting the advertising data. */
typedef struct
{
ble_advdata_name_type_t name_type; /**< Type of device name. */
uint8_t short_name_len; /**< Length of short device name (if short type is specified). */
bool include_appearance; /**< Determines if Appearance shall be included. */
uint8_t flags; /**< Advertising data Flags field. */
int8_t * p_tx_power_level; /**< TX Power Level field. */
ble_advdata_uuid_list_t uuids_more_available; /**< List of UUIDs in the 'More Available' list. */
ble_advdata_uuid_list_t uuids_complete; /**< List of UUIDs in the 'Complete' list. */
ble_advdata_uuid_list_t uuids_solicited; /**< List of solicited UUIDs. */
ble_advdata_conn_int_t * p_slave_conn_int; /**< Slave Connection Interval Range. */
ble_advdata_manuf_data_t * p_manuf_specific_data; /**< Manufacturer specific data. */
ble_advdata_service_data_t * p_service_data_array; /**< Array of Service data structures. */
uint8_t service_data_count; /**< Number of Service data structures. */
bool include_ble_device_addr; /**< Determines if LE Bluetooth Device Address shall be included. */
ble_advdata_le_role_t le_role; /**< LE Role field. Included when different from @ref BLE_ADVDATA_ROLE_NOT_PRESENT. @warning This field can be used only for NFC. For BLE advertising, set it to NULL. */
ble_advdata_tk_value_t * p_tk_value; /**< Security Manager TK value field. Included when different from NULL. @warning This field can be used only for NFC. For BLE advertising, set it to NULL.*/
uint8_t * p_sec_mgr_oob_flags; /**< Security Manager Out Of Band Flags field. Included when different from NULL. @warning This field can be used only for NFC. For BLE advertising, set it to NULL.*/
ble_gap_lesc_oob_data_t * p_lesc_data; /**< LE Secure Connections OOB data. Included when different from NULL. @warning This field can be used only for NFC. For BLE advertising, set it to NULL.*/
} ble_advdata_t;
-
name_type
:設(shè)備名稱的類型 -
short_name_len
:短設(shè)備名稱的長度(如果指定了短類型) -
include_appearance
:確定是否包括展示圖標(biāo) -
flags
:廣播數(shù)據(jù)標(biāo)識(shí)字段 -
p_tx_power_level
:TX 電平發(fā)送功率等級(jí) -
uuids_more_available
:部分服務(wù)UUID列表荞彼,只顯示部分UUID列表在廣播中,實(shí)際工程還有更多UUID -
uuids_complete
:全部服務(wù)UUID列表待笑,廣播中顯示UUID列表就是實(shí)際工程中所有UUID -
uuids_solicited
:請(qǐng)求服務(wù)的UUID列表鸣皂,一個(gè)從機(jī)設(shè)備可以發(fā)送服務(wù)請(qǐng)求數(shù)據(jù)類型廣播去邀請(qǐng)主機(jī)進(jìn)行連接,該主機(jī)設(shè)備包含一個(gè)或多個(gè)這個(gè)服務(wù)器請(qǐng)求數(shù)據(jù)廣播所指定的服務(wù) -
p_slave_conn_int
:從機(jī)連接間隔范圍 -
p_manuf_specific_data
:制造商特定的數(shù)據(jù)暮蹂,自定義廣播數(shù)據(jù) -
p_service_data_array
:服務(wù)數(shù)據(jù)結(jié)構(gòu)數(shù)組 -
service_data_count
:服務(wù)數(shù)據(jù)結(jié)構(gòu)的數(shù)量 -
include_ble_device_addr
:確定是否包含LE藍(lán)牙設(shè)備地址 -
le_role
:LE角色區(qū)域寞缝。這個(gè)區(qū)域僅僅用于NFC。對(duì)應(yīng)BLE廣播仰泻,設(shè)置為NULL -
p_tk_value
:安全管理TK值的區(qū)域荆陆。這個(gè)區(qū)域僅僅用于NFC。對(duì)應(yīng)BLE廣播集侯,設(shè)置為NULL -
p_sec_mgr_oob_flags
:安全管理器帶外標(biāo)志字段被啼。這個(gè)區(qū)域僅僅用于NFC。對(duì)應(yīng)BLE廣播棠枉,設(shè)置為NULL -
p_lesc_data
:LE OOB數(shù)據(jù)的安全連接浓体。這個(gè)區(qū)域僅僅用于NFC。對(duì)應(yīng)BLE廣播辈讶,設(shè)置為NULL
三命浴、廣播UUID的值
UUID的種類分為兩種:
- 一種是 SIG 定義的公共服務(wù) UUID,所有的公共服務(wù)共用一個(gè) 128bit 的基礎(chǔ) UUID,不同的服務(wù)采用一個(gè) 16bit UUID 進(jìn)行定義生闲。
- 另一種就是私有服務(wù)的 UUID媳溺,這是一個(gè)自定義的 128bit UUID。
注意:廣播包里的 UUID 不影響服務(wù)特征值中 UUID 的值碍讯,僅僅是讓廣播把 UUID 的值廣播給掃描設(shè)備悬蔽,方便觀察。
3.1 顯示全部服務(wù)UUID列表
在廣播參數(shù)里列出了三類 UUID 列表的情況:
typedef struct
{
···
ble_advdata_uuid_list_t uuids_more_available;
ble_advdata_uuid_list_t uuids_complete;
ble_advdata_uuid_list_t uuids_solicited;
···
} ble_advdata_t;
-
uuids_more_available
:部分服務(wù)UUID列表捉兴,只顯示部分UUID列表在廣播中屯阀,實(shí)際工程還有更多UUID -
uuids_complete
:全部服務(wù)UUID列表,廣播中顯示UUID列表就是實(shí)際工程中所有UUID -
uuids_solicited
:請(qǐng)求服務(wù)的UUID列表轴术,一個(gè)從機(jī)設(shè)備可以發(fā)送服務(wù)請(qǐng)求數(shù)據(jù)類型廣播去邀請(qǐng)主機(jī)進(jìn)行連接,該主機(jī)設(shè)備包含一個(gè)或多個(gè)這個(gè)服務(wù)器請(qǐng)求數(shù)據(jù)廣播所指定的服務(wù)
UUID專門有個(gè)一個(gè)結(jié)構(gòu)體 ble_advdata_uuid_list_t
進(jìn)行標(biāo)識(shí):
typedef struct
{
uint16_t uuid_cnt; // UUID的數(shù)目
ble_uuid_t * p_uuids; // 指向UUID列表的指針
} ble_advdata_uuid_list_t
如果需要在廣播中廣播 UUID钦无,需要專門建立一個(gè) UUID 的結(jié)構(gòu)體逗栽,讓指向UUID列表的指針指向這個(gè)結(jié)構(gòu)體。
- 首先失暂,在主函數(shù) main.c 中彼宠,聲明如下
m_adv_uuids
結(jié)構(gòu)體:
static ble_uuid_t m_adv_uuids[] =
{
{BLE_UUID_NUS_SERVICE, BLE_UUID_TYPE_VENDOR_BEGIN},
{BLE_UUID_BATTERY_SERVICE, BLE_UUID_TYPE_BLE}弟塞,
{BLE_UUID_TX_POWER_SERVICE, BLE_UUID_TYPE_BLE}
};
- 這個(gè)結(jié)構(gòu)體內(nèi)包含了 3 個(gè) UUID 的列表:一個(gè)藍(lán)牙串口服務(wù)凭峡,一個(gè)電池服務(wù),一個(gè)發(fā)射功率服務(wù)决记。同時(shí)標(biāo)注服務(wù) UUID 的類型摧冀,其中藍(lán)牙串口服務(wù)為私有服務(wù),電池服務(wù)和發(fā)射功率服務(wù)為 SIG 定義的公共服務(wù)系宫。兩種服務(wù)類型 UUID 長度是不同的索昂,分別為
128bit
和16bit
,如下面定義:
/** @defgroup BLE_UUID_TYPES Types of UUID
* @{ */
#define BLE_UUID_TYPE_UNKNOWN 0x00 /**< Invalid UUID type. */
#define BLE_UUID_TYPE_BLE 0x01 /**< Bluetooth SIG UUID (16-bit). */
#define BLE_UUID_TYPE_VENDOR_BEGIN 0x02 /**< Vendor UUID types start at this index (128-bit). */
/** @} */
- 接著扩借,在廣播初始化函數(shù)中添加如下代碼:
static void advertising_init(void)
{
ret_code_t err_code;
ble_advertising_init_t init;
memset(&init, 0, sizeof(init));
···
···
// 定義全部UUID列表(包含一個(gè)128bit的UUID和兩個(gè)服務(wù)16bit的UUID)
init.srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
init.srdata.uuids_complete.p_uuids = m_adv_uuids;
···
···
err_code = ble_advertising_init(&m_advertising, &init);// 初始化廣播椒惨,導(dǎo)入?yún)?shù)
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);// 設(shè)置廣播識(shí)別號(hào)
}
由于要顯示 128bit 的 UUID 長度比較長,因此把 UUID 的參數(shù)放入掃描響應(yīng)包中潮罪。通過手機(jī)APP nrf connect 掃描后顯示康谆,Complete list of 表示是完整 UUID 列表。
3.2 顯示部分服務(wù)UUID列表
通過設(shè)置 uuid_cnt
的數(shù)目控制廣播中顯示的 UUID 數(shù)目嫉到,不管廣播數(shù)據(jù)包還是掃描響應(yīng)包沃暗,都只提供 31 個(gè)字節(jié)的空間,因此需要注意可使用的空間屯碴。
- 同上描睦,首先在主函數(shù) main.c 中,聲明如下
m_adv_uuids
結(jié)構(gòu)體:
static ble_uuid_t m_adv_uuids[] =
{
{BLE_UUID_NUS_SERVICE, BLE_UUID_TYPE_VENDOR_BEGIN}导而,
{BLE_UUID_BATTERY_SERVICE, BLE_UUID_TYPE_BLE}忱叭,
{BLE_UUID_TX_POWER_SERVICE, BLE_UUID_TYPE_BLE}
};
- 接著隔崎,在廣播初始化函數(shù)中添加如下代碼:
static void advertising_init(void)
{
ret_code_t err_code;
ble_advertising_init_t init;
memset(&init, 0, sizeof(init));
···
···
// 定義全部UUID列表(包含一個(gè)128bit的UUID和兩個(gè)服務(wù)16bit的UUID)
init.srdata.uuids_more_available.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]) - 1;
init.srdata.uuids_more_available.p_uuids = m_adv_uuids;
···
···
err_code = ble_advertising_init(&m_advertising, &init);// 初始化廣播,導(dǎo)入?yún)?shù)
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);// 設(shè)置廣播識(shí)別號(hào)
}
通過手機(jī)APP nrf connect 掃描后顯示韵丑,Incomplete list of 表示是部分 UUID 列表爵卒。這里只顯示了一個(gè) 16bit UUID 和 一個(gè) 128bit UUID,而實(shí)際有三個(gè) UUID撵彻。
3.3 顯示請(qǐng)求服務(wù)UUID列表
一個(gè)典型的請(qǐng)求服務(wù)的 UUID 列表例子就是 ANCS 廣播钓株。這個(gè)例子需要一個(gè) GATT 從機(jī)端和一個(gè)有這個(gè) ANCS 的 GATT 主機(jī)端。通過在廣播中廣播 ANCS 請(qǐng)求服務(wù)的 UUID 去告訴掃描端(iOS設(shè)備)它正在“尋找”一個(gè)具有 ANCS 服務(wù)的主機(jī)設(shè)備陌僵。對(duì)于當(dāng)前時(shí)間服務(wù) CTS 的客戶機(jī)也是如此轴合。ble_app_cts_c 使用所請(qǐng)求的服務(wù)是因?yàn)樗枰粋€(gè)具有當(dāng)前時(shí)間服務(wù)的 GATT 服務(wù)器的主機(jī)端,在 ble_app_cts_c 工程中碗短,廣播初始化的代碼如下:
- 首先受葛,聲明
m_adv_uuids
結(jié)構(gòu)體:
static ble_uuid_t m_adv_uuids[] =
{
{BLE_UUID_CURRENT_TIME_SERVICE, BLE_UUID_TYPE_BLE}
};
- 接著,在廣播初始化函數(shù)中添加如下代碼:
static void advertising_init(void)
{
ret_code_t err_code;
ble_advertising_init_t init;
memset(&init, 0, sizeof(init));
···
···
// 定義全部UUID列表(包含一個(gè)128bit的UUID和兩個(gè)服務(wù)16bit的UUID)
init.srdata.uuids_solicited.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]) ;
init.srdata.uuids_solicited.p_uuids = m_adv_uuids;
···
···
err_code = ble_advertising_init(&m_advertising, &init);// 初始化廣播偎谁,導(dǎo)入?yún)?shù)
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);// 設(shè)置廣播識(shí)別號(hào)
}
通過手機(jī)APP nrf connect 掃描后顯示:
四总滩、廣播從機(jī)的連接間隔參數(shù)
從機(jī)與主機(jī)之間的連接間隔,是由從機(jī)提出與主機(jī)進(jìn)行協(xié)商巡雨,然后再由主機(jī)決定的參數(shù)闰渔。
在廣播參數(shù)結(jié)構(gòu)體 ble_advdata_t
中包含了一個(gè)結(jié)構(gòu)體參數(shù) ble_advdata_conn_int_t
typedef struct
{
···
ble_advdata_conn_int_t *p_slave_conn_int; /**< Slave Connection Interval Range. */
···
} ble_advdata_t;
指定了廣播中可以廣播的兩個(gè)連接參數(shù)的值:
/**@brief Connection interval range structure. */
typedef struct
{
uint16_t min_conn_interval; /**< Minimum connection interval, in units of 1.25 ms, range 6 to 3200 (7.5 ms to 4 s). */
uint16_t max_conn_interval; /**< Maximum connection interval, in units of 1.25 ms, range 6 to 3200 (7.5 ms to 4 s). The value 0xFFFF indicates no specific maximum. */
} ble_advdata_conn_int_t;
使用這個(gè)結(jié)構(gòu)體,可以在廣播初始化中定義需要廣播的連接間隔的參數(shù):
static void advertising_init(void)
{
ret_code_t err_code;
ble_advertising_init_t init;
memset(&init, 0, sizeof(init));
···
···
ble_advdata_conn_int_t conn_range;
// 從機(jī)連接間隔范圍最小值:10*1.25ms = 12.5ms
conn_range.min_conn_interval = 10;
// 從機(jī)連接間隔范圍最大值:20*1.25ms = 25ms
conn_range.max_conn_interval = 20;
// 廣播數(shù)據(jù)中包含從機(jī)連接間隔范圍
init.advdata.p_slave_conn_int = &conn_range;
···
···
err_code = ble_advertising_init(&m_advertising, &init);// 初始化廣播铐望,導(dǎo)入?yún)?shù)
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);// 設(shè)置廣播識(shí)別號(hào)
}
通過手機(jī)APP nrf connect 掃描后顯示:
五冈涧、廣播自定義數(shù)據(jù)
- 首先,在 ble_advdata.h 文件中蝌以,定義了結(jié)構(gòu)體
ble_advdata_manuf_data_t
表示公司廠家的數(shù)據(jù)與ID代碼:
typedef struct
{
uint16_t company_identifier; // 公司ID代碼
uint8_arry_t data; // 制造者自定義的數(shù)據(jù)
} ble_advdata_manuf_data_t;
-
company_identifier
:公司ID號(hào)炕舵,每個(gè)公司都有獨(dú)立申請(qǐng)的值,一般 company_identifier 都是廠家在 SIG 申請(qǐng)定義的唯一 ID 號(hào)跟畅。不同公司的 ID 號(hào)可以具體在 SIG 網(wǎng)站查詢咽筋。例如 Nordic 的制造商 ID 號(hào)為:0x0059 -
data
:制造商自定義的數(shù)據(jù),這個(gè)參數(shù)可以自由的設(shè)置徊件,只要廣播包的空間足夠奸攻。假設(shè)自定義數(shù)據(jù)為 0x11,0x22虱痕,0x33睹耐,0x44,0x55部翘。
- 接著硝训,在廣播初始化函數(shù)中添加如下代碼:
static void advertising_init(void)
{
ret_code_t err_code;
ble_advertising_init_t init;
memset(&init, 0, sizeof(init));
···
···
uint8_t my_adv_manuf_data[5] = {0x11,0x22,0x33,0x44,0x55};
// 定義一個(gè)制造商自定義數(shù)據(jù)的結(jié)構(gòu)體變量,配置廣播數(shù)據(jù)時(shí)將該變量的地址賦值給廣播數(shù)據(jù)包中
ble_advdata_manuf_data_t manuf_specific_data;
// 0x0059是Nordic的制造商ID
manuf_specific_data.company_identifier = 0x0059;
// 指向自定義數(shù)據(jù)
manuf_specific_data.data.p_data = my_adv_manuf_data;
// 自定義數(shù)據(jù)的大小
manuf_specific_data.data.size = sizeof(my_adv_manuf_data);
// 定義自定義數(shù)據(jù)到廣播包中
init.advdata.p_manuf_specific_data = &manuf_specific_data;
···
···
err_code = ble_advertising_init(&m_advertising, &init);// 初始化廣播,導(dǎo)入?yún)?shù)
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);// 設(shè)置廣播識(shí)別號(hào)
}
通過手機(jī)APP nrf connect 掃描后顯示:
六窖梁、動(dòng)態(tài)更新廣播內(nèi)容
動(dòng)態(tài)更新廣播內(nèi)容實(shí)際就是更新第四節(jié)中 manuf_specific_data.data.p_data
的值赘风,然后停止廣播,再更新廣播內(nèi)容纵刘,再開啟廣播邀窃,這里涉及到三個(gè)函數(shù):
-
advertising_stop()
:停止廣播 -
advertising_advdata_update()
:更新廣播內(nèi)容 -
advertising_start()
:開啟廣播
例子如下。
七假哎、自定義廣播內(nèi)容及動(dòng)態(tài)更新廣播例子
下載 user_advertising.c
和 user_advertising.h
鏈接:https://pan.baidu.com/s/1zH3uwEwdla-s331a1XzvkQ 提取碼:8gp5
7.1 user_advertising.c
/*********************************************************************
* INCLUDES
*/
#include "ble_advertising.h"
#include "app_error.h"
/*********************************************************************
* GLOBAL VARIABLES
*/
// 廣播數(shù)據(jù)
ble_advertising_init_t g_advertisingInit;
ble_advdata_manuf_data_t g_advertisingData;
uint8 g_advertisingDataEventsAndParamsData[] =
{
// events and params
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
// 掃描響應(yīng)數(shù)據(jù)
ble_advdata_manuf_data_t g_scanResponseData;
uint8 g_scanResponseStatusAndParamsData[] =
{
// status and params
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
/*********************************************************************
* EXTERN FUNCTIONS
*/
extern void advertising_init(void);
extern void advertising_start(bool eraseBonds);
extern void advertising_stop(void);
extern void advertising_advdata_update(void);
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/**
@brief 初始化廣播數(shù)據(jù)包
@param pInit - 廣播數(shù)據(jù)初始化結(jié)構(gòu)體
@return 無
*/
void InitAdvertisingData(ble_advertising_init_t *pInit)
{
pInit->advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; // 藍(lán)牙設(shè)備模式瞬捕,LE普通發(fā)現(xiàn)模式和不支持BR/EDR模式
g_advertisingData.company_identifier = 0x11;
g_advertisingData.company_identifier = g_advertisingData.company_identifier | (0x22 << 8);
g_advertisingData.data.p_data = g_advertisingDataEventsAndParamsData;
g_advertisingData.data.size = 19;
pInit->advdata.p_manuf_specific_data = &g_advertisingData;
}
/**
@brief 初始化掃描應(yīng)答包
@param pInit - 廣播數(shù)據(jù)初始化結(jié)構(gòu)體
@return 無
*/
void InitScanResponseData(ble_advertising_init_t *pInit)
{
g_scanResponseData.company_identifier = g_scanResponseData.company_identifier | 0x11;
g_scanResponseData.company_identifier = g_scanResponseData.company_identifier | (0x22<<8);
*g_scanResponseStatusAndParamsData = 0x33;
g_scanResponseData.data.p_data = g_scanResponseStatusAndParamsData;
g_scanResponseData.data.size = 15;
pInit->srdata.p_manuf_specific_data = &g_scanResponseData;
pInit->srdata.name_type = BLE_ADVDATA_FULL_NAME; // 廣播時(shí)的名稱顯示
}
/**
@brief 開啟廣播
@param 無
@return 無
*/
void EnableAdvertising(void)
{
bool eraseBonds;
advertising_start(eraseBonds);
}
/**
@brief 關(guān)閉廣播
@param 無
@return 無
*/
void DisableAdvertising(void)
{
advertising_stop();
}
/**
@brief 更新廣播內(nèi)容
@param 無
@return 無
*/
void UpdataAdvData(void)
{
bool eraseBonds = false;
advertising_stop();
advertising_advdata_update();;
advertising_start(eraseBonds);
}
- 這里對(duì)廣播數(shù)據(jù)包中的制造商ID
company_identifier
也當(dāng)作自定義數(shù)據(jù)使用
g_advertisingData.company_identifier = 0x11;
g_advertisingData.company_identifier = g_advertisingData.company_identifier | (0x22 << 8);
- 其他自定義數(shù)據(jù)則對(duì)
g_advertisingDataEventsAndParamsData
數(shù)組進(jìn)行賦值
g_advertisingData.data.p_data = g_advertisingDataEventsAndParamsData;
g_advertisingData.data.size = 19;
- 掃描響應(yīng)包也是如此,同時(shí)再掃描響應(yīng)包的內(nèi)容中加入了設(shè)備名稱
pInit->srdata.name_type = BLE_ADVDATA_FULL_NAME;
7.2 user_advertising.h
#ifndef _USER_ADVERTISING_H_
#define _USER_ADVERTISING_H_
/*********************************************************************
* INCLUDES
*/
#include "ble_advertising.h"
/*********************************************************************
* GLOBAL VARIABLES
*/
extern ble_advdata_manuf_data_t g_advertisingData;
extern uint8 g_advertisingDataEventsAndParamsData[];
extern ble_advdata_manuf_data_t g_scanResponseData;
extern uint8 g_scanResponseStatusAndParamsData[];
extern ble_advertising_init_t g_advertisingInit;
/*********************************************************************
* API FUNCTIONS
*/
void InitAdvertisingData(ble_advertising_init_t *pInit);
void InitScanResponseData(ble_advertising_init_t *pInit);
void EnableAdvertising(void);
void DisableAdvertising(void);
void UpdataAdvData(void);
void SetAdvDataTriggerEventTimeStamp(uint8 eventTypeLenghtLocation);
#endif /* _USER_ADVERTISING_H_ */
7.3 main.c
#include "user_advertising.h"
BLE_ADVERTISING_DEF(m_advertising); /**< Advertising module instance. */
int main(void)
{
bool erase_bonds;
···
···
advertising_init(); // 廣播初始化
···
advertising_start(erase_bonds); // 開啟廣播
}
static bool s_isConnectedFlag = false;
/**
@brief 設(shè)置BLE連接狀態(tài)
@param status -[in] true - 已連接舵抹;false - 已斷開
@return 無
*/
void SetBleConnectStatus(bool status)
{
s_isConnectedFlag = status;
}
/**
@brief 獲取BLE連接狀態(tài)
@param 無
@return true - 已連接肪虎;false - 已斷開
*/
bool GetBleConnectStatus(void)
{
return s_isConnectedFlag;
}
static bool s_waitForUpdateAdvDataFlag = false;
/**
@brief 設(shè)置等待更新廣播狀態(tài)
@param status -[in] true - 等待;false - 空閑
@return 無
*/
void SetWaitForUpdateAdvDataStatus(bool status)
{
s_waitForUpdateAdvDataFlag = status;
}
/**
@brief 獲取等待更新廣播狀態(tài)
@param 無
@return true - 等待惧蛹;false - 空閑
*/
bool GetWaitForUpdateAdvDataStatus(void)
{
return s_waitForUpdateAdvDataFlag;
}
/**@brief Function for starting advertising.
*/
void advertising_start(bool erase_bonds)
{
if(erase_bonds == true)
{
delete_bonds();
// Advertising is started by PM_EVT_PEERS_DELETED_SUCEEDED event
}
else
{
ret_code_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
APP_ERROR_CHECK(err_code);
}
}
/**@brief Function for stopping advertising.
*/
void advertising_stop(void)
{
sd_ble_gap_adv_stop(m_advertising.adv_handle);
}
/**@brief Function for update advertising data or scan response data.
*/
void advertising_advdata_update(void)
{
ret_code_t err_code;
err_code = ble_advertising_init(&m_advertising, &g_advertisingInit); // 初始化廣播笋轨,導(dǎo)入?yún)?shù)
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG); // 設(shè)置廣播識(shí)別號(hào)
}
/**@brief Function for initializing the Advertising functionality.
*/
static void advertising_init(void)
{
ret_code_t err_code;
memset(&g_advertisingInit, 0, sizeof(g_advertisingInit));
// 初始化廣播數(shù)據(jù)包和掃描響應(yīng)包內(nèi)容
InitAdvertisingData(&g_advertisingInit);
InitScanResponseData(&g_advertisingInit);
g_advertisingInit.config.ble_adv_fast_enabled = true; // 廣播類型,快速廣播
g_advertisingInit.config.ble_adv_fast_interval = APP_ADV_INTERVAL; // 廣播間隔
g_advertisingInit.config.ble_adv_fast_timeout = APP_ADV_DURATION; // 廣播超時(shí)時(shí)間赊淑,值0則保持一種廣播模式不變
g_advertisingInit.evt_handler = on_adv_evt;
err_code = ble_advertising_init(&m_advertising, &g_advertisingInit); // 初始化廣播,導(dǎo)入?yún)?shù)
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG); // 設(shè)置廣播識(shí)別號(hào)
}
7.4 初始化廣播內(nèi)容
通過調(diào)用 InitAdvertisingData
和 InitScanResponseData
兩個(gè)函數(shù)初始化廣播數(shù)據(jù)包和掃描響應(yīng)包
7.5 動(dòng)態(tài)更新廣播內(nèi)容
例如在一些中斷函數(shù)中仅讽,通過對(duì) g_advertisingDataEventsAndParamsData
進(jìn)行賦值陶缺,同時(shí)在連接時(shí)不更新廣播,等待斷開連接后更新洁灵。
// 中斷函數(shù)中
g_advertisingDataEventsAndParamsData = 0x55
if(GetBleConnectStatus() == false)
{
UpdataAdvData(); // 非連接狀態(tài)饱岸,立即更新廣播
}
else
{
SetWaitForUpdateAdvDataStatus(true); // 等待斷開后更新廣播
}
然后再藍(lán)牙事件處理函數(shù) ble_evt_handler
中,判斷是否正在連接中徽千,如果不是苫费,立即更新廣播內(nèi)容
/**@brief Function for handling BLE events.
*
* @param[in] p_ble_evt Bluetooth stack event.
* @param[in] p_context Unused.
*/
static void ble_evt_handler(ble_evt_t const *p_ble_evt, void *p_context)
{
ret_code_t err_code = NRF_SUCCESS;
switch(p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_DISCONNECTED:
NRF_LOG_INFO("Disconnected.");
SetBleConnectStatus(false); // 已斷開
if(GetWaitForUpdateAdvDataStatus() == true) // 等待更新廣播
{
UpdataAdvData();
SetWaitForUpdateAdvDataStatus(false);
}
break;
case BLE_GAP_EVT_CONNECTED:
NRF_LOG_INFO("Connected.");
err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
APP_ERROR_CHECK(err_code);
m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
APP_ERROR_CHECK(err_code);
SetBleConnectStatus(true); // 已連接
break;
···
···
? 由 Leung 寫于 2020 年 2 月 12 日
? 參考:青風(fēng)電子社區(qū)