一、背景
鏈路層(LL)控制設備的射頻狀態,有五個設備狀態:待機、廣播、掃描、初始化和連接。
廣播 爲廣播數據包,而 掃描 則是監聽廣播。
GAP通信中角色,中心設備(Central - 主機)用來掃描和連接 外圍設備(Peripheral - 從機)。
大部分情況下外圍設備通過廣播自己來讓中心設備發現自己,並建立 GATT 連接,從而進行更多的數據交換。
也有些情況是不需要連接的,只要外設廣播自己的數據即可,用這種方式主要目的是讓外圍設備,把自己的信息發送給多箇中心設備。
在藍牙 4.x 的協議中,廣播包的大小爲 31 個字節,如果主機有主動掃描,還有一個 31 字節大小的掃描響應包,也就是說如果是藍牙 4.x 模式,最大可實現 62 個字節大小的廣播內容。
在藍牙 5.0 中,把廣播信道抽象爲兩類,一種叫主廣播信道(primary advertisement channels),另一種叫次廣播信道,或者第二廣播信道(secondary advertising packets)。
所謂的主廣播類似於藍牙 4.x 的廣播,只工作在 37、38、39 三個信道,最大廣播字節爲 31 字節。而次廣播允許藍牙在除開 37、38、39 三個信道之外的其他 37 個信道上發送長度介於 0-255 字節的數據。次廣播信道(0-36 channel)廣播 255 字節數據。
二、廣播內容參數
在 ble_advertising.h 文件中,提供了廣播的初始化參數結構體,如果你需要自定義廣播內容,那麼就需要在廣播數據包 advdata
或者掃描響應包 srdata
中添加內容。
/**@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
:廣播數據包srdata
:掃描響應包config
:配置廣播參數(廣播模式、廣播間隔、廣播時間)evt_handler
:將在廣播事件上調用的事件處理程序error_handler
:錯誤處理程序,將把內部錯誤導入主應用程序
我們可以看到廣播數據包advdata
或者掃描響應包srdata
都是結構體ble_advdata_t
類型,該結構體內定義了廣播數據包或掃描響應包可以定義的內容:
/**@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
:設備名稱的類型short_name_len
:短設備名稱的長度(如果指定了短類型)include_appearance
:確定是否包括展示圖標flags
:廣播數據標識字段p_tx_power_level
:TX 電平發送功率等級uuids_more_available
:部分服務UUID列表,只顯示部分UUID列表在廣播中,實際工程還有更多UUIDuuids_complete
:全部服務UUID列表,廣播中顯示UUID列表就是實際工程中所有UUIDuuids_solicited
:請求服務的UUID列表,一個從機設備可以發送服務請求數據類型廣播去邀請主機進行連接,該主機設備包含一個或多個這個服務器請求數據廣播所指定的服務p_slave_conn_int
:從機連接間隔範圍p_manuf_specific_data
:製造商特定的數據,自定義廣播數據p_service_data_array
:服務數據結構數組service_data_count
:服務數據結構的數量include_ble_device_addr
:確定是否包含LE藍牙設備地址le_role
:LE角色區域。這個區域僅僅用於NFC。對應BLE廣播,設置爲NULLp_tk_value
:安全管理TK值的區域。這個區域僅僅用於NFC。對應BLE廣播,設置爲NULLp_sec_mgr_oob_flags
:安全管理器帶外標誌字段。這個區域僅僅用於NFC。對應BLE廣播,設置爲NULLp_lesc_data
:LE OOB數據的安全連接。這個區域僅僅用於NFC。對應BLE廣播,設置爲NULL
三、廣播UUID的值
UUID的種類分爲兩種:
- 一種是 SIG 定義的公共服務 UUID,所有的公共服務共用一個 128bit 的基礎 UUID,不同的服務採用一個 16bit UUID 進行定義。
- 另一種就是私有服務的 UUID,這是一個自定義的 128bit UUID。
注意:廣播包裏的 UUID 不影響服務特徵值中 UUID 的值,僅僅是讓廣播把 UUID 的值廣播給掃描設備,方便觀察。
3.1 顯示全部服務UUID列表
在廣播參數裏列出了三類 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
:部分服務UUID列表,只顯示部分UUID列表在廣播中,實際工程還有更多UUIDuuids_complete
:全部服務UUID列表,廣播中顯示UUID列表就是實際工程中所有UUIDuuids_solicited
:請求服務的UUID列表,一個從機設備可以發送服務請求數據類型廣播去邀請主機進行連接,該主機設備包含一個或多個這個服務器請求數據廣播所指定的服務
UUID專門有個一個結構體 ble_advdata_uuid_list_t
進行標識:
typedef struct
{
uint16_t uuid_cnt; // UUID的數目
ble_uuid_t * p_uuids; // 指向UUID列表的指針
} ble_advdata_uuid_list_t
如果需要在廣播中廣播 UUID,需要專門建立一個 UUID 的結構體,讓指向UUID列表的指針指向這個結構體。
- 首先,在主函數 main.c 中,聲明如下
m_adv_uuids
結構體:
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}
};
- 這個結構體內包含了 3 個 UUID 的列表:一個藍牙串口服務,一個電池服務,一個發射功率服務。同時標註服務 UUID 的類型,其中藍牙串口服務爲私有服務,電池服務和發射功率服務爲 SIG 定義的公共服務。兩種服務類型 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). */
/** @} */
- 接着,在廣播初始化函數中添加如下代碼:
static void advertising_init(void)
{
ret_code_t err_code;
ble_advertising_init_t init;
memset(&init, 0, sizeof(init));
···
···
// 定義全部UUID列表(包含一個128bit的UUID和兩個服務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);// 初始化廣播,導入參數
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);// 設置廣播識別號
}
由於要顯示 128bit 的 UUID 長度比較長,因此把 UUID 的參數放入掃描響應包中。通過手機APP nrf connect 掃描後顯示,Complete list of 表示是完整 UUID 列表。
3.2 顯示部分服務UUID列表
通過設置 uuid_cnt
的數目控制廣播中顯示的 UUID 數目,不管廣播數據包還是掃描響應包,都只提供 31 個字節的空間,因此需要注意可使用的空間。
- 同上,首先在主函數 main.c 中,聲明如下
m_adv_uuids
結構體:
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}
};
- 接着,在廣播初始化函數中添加如下代碼:
static void advertising_init(void)
{
ret_code_t err_code;
ble_advertising_init_t init;
memset(&init, 0, sizeof(init));
···
···
// 定義全部UUID列表(包含一個128bit的UUID和兩個服務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);// 初始化廣播,導入參數
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);// 設置廣播識別號
}
通過手機APP nrf connect 掃描後顯示,Incomplete list of 表示是部分 UUID 列表。這裏只顯示了一個 16bit UUID 和 一個 128bit UUID,而實際有三個 UUID。
3.3 顯示請求服務UUID列表
一個典型的請求服務的 UUID 列表例子就是 ANCS 廣播。這個例子需要一個 GATT 從機端和一個有這個 ANCS 的 GATT 主機端。通過在廣播中廣播 ANCS 請求服務的 UUID 去告訴掃描端(iOS設備)它正在“尋找”一個具有 ANCS 服務的主機設備。對於當前時間服務 CTS 的客戶機也是如此。ble_app_cts_c 使用所請求的服務是因爲它需要一個具有當前時間服務的 GATT 服務器的主機端,在 ble_app_cts_c 工程中,廣播初始化的代碼如下:
- 首先,聲明
m_adv_uuids
結構體:
static ble_uuid_t m_adv_uuids[] =
{
{BLE_UUID_CURRENT_TIME_SERVICE, BLE_UUID_TYPE_BLE}
};
- 接着,在廣播初始化函數中添加如下代碼:
static void advertising_init(void)
{
ret_code_t err_code;
ble_advertising_init_t init;
memset(&init, 0, sizeof(init));
···
···
// 定義全部UUID列表(包含一個128bit的UUID和兩個服務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);// 初始化廣播,導入參數
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);// 設置廣播識別號
}
通過手機APP nrf connect 掃描後顯示:
四、廣播從機的連接間隔參數
從機與主機之間的連接間隔,是由從機提出與主機進行協商,然後再由主機決定的參數。
在廣播參數結構體 ble_advdata_t
中包含了一個結構體參數 ble_advdata_conn_int_t
typedef struct
{
···
ble_advdata_conn_int_t *p_slave_conn_int; /**< Slave Connection Interval Range. */
···
} ble_advdata_t;
指定了廣播中可以廣播的兩個連接參數的值:
/**@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;
使用這個結構體,可以在廣播初始化中定義需要廣播的連接間隔的參數:
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;
// 從機連接間隔範圍最小值:10*1.25ms = 12.5ms
conn_range.min_conn_interval = 10;
// 從機連接間隔範圍最大值:20*1.25ms = 25ms
conn_range.max_conn_interval = 20;
// 廣播數據中包含從機連接間隔範圍
init.advdata.p_slave_conn_int = &conn_range;
···
···
err_code = ble_advertising_init(&m_advertising, &init);// 初始化廣播,導入參數
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);// 設置廣播識別號
}
通過手機APP nrf connect 掃描後顯示:
五、廣播自定義數據
- 首先,在 ble_advdata.h 文件中,定義了結構體
ble_advdata_manuf_data_t
表示公司廠家的數據與ID代碼:
typedef struct
{
uint16_t company_identifier; // 公司ID代碼
uint8_arry_t data; // 製造者自定義的數據
} ble_advdata_manuf_data_t;
company_identifier
:公司ID號,每個公司都有獨立申請的值,一般 company_identifier 都是廠家在 SIG 申請定義的唯一 ID 號。不同公司的 ID 號可以具體在 SIG 網站查詢。例如 Nordic 的製造商 ID 號爲:0x0059data
:製造商自定義的數據,這個參數可以自由的設置,只要廣播包的空間足夠。假設自定義數據爲 0x11,0x22,0x33,0x44,0x55。
- 接着,在廣播初始化函數中添加如下代碼:
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};
// 定義一個製造商自定義數據的結構體變量,配置廣播數據時將該變量的地址賦值給廣播數據包中
ble_advdata_manuf_data_t manuf_specific_data;
// 0x0059是Nordic的製造商ID
manuf_specific_data.company_identifier = 0x0059;
// 指向自定義數據
manuf_specific_data.data.p_data = my_adv_manuf_data;
// 自定義數據的大小
manuf_specific_data.data.size = sizeof(my_adv_manuf_data);
// 定義自定義數據到廣播包中
init.advdata.p_manuf_specific_data = &manuf_specific_data;
···
···
err_code = ble_advertising_init(&m_advertising, &init);// 初始化廣播,導入參數
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);// 設置廣播識別號
}
通過手機APP nrf connect 掃描後顯示:
六、動態更新廣播內容
動態更新廣播內容實際就是更新第四節中 manuf_specific_data.data.p_data
的值,然後停止廣播,再更新廣播內容,再開啓廣播,這裏涉及到三個函數:
advertising_stop()
:停止廣播advertising_advdata_update()
:更新廣播內容advertising_start()
:開啓廣播
例子如下。
七、自定義廣播內容及動態更新廣播例子
下載 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
*/
// 廣播數據
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,
};
// 掃描響應數據
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 初始化廣播數據包
@param pInit - 廣播數據初始化結構體
@return 無
*/
void InitAdvertisingData(ble_advertising_init_t *pInit)
{
pInit->advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; // 藍牙設備模式,LE普通發現模式和不支持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 初始化掃描應答包
@param pInit - 廣播數據初始化結構體
@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; // 廣播時的名稱顯示
}
/**
@brief 開啓廣播
@param 無
@return 無
*/
void EnableAdvertising(void)
{
bool eraseBonds;
advertising_start(eraseBonds);
}
/**
@brief 關閉廣播
@param 無
@return 無
*/
void DisableAdvertising(void)
{
advertising_stop();
}
/**
@brief 更新廣播內容
@param 無
@return 無
*/
void UpdataAdvData(void)
{
bool eraseBonds = false;
advertising_stop();
advertising_advdata_update();;
advertising_start(eraseBonds);
}
- 這裏對廣播數據包中的製造商ID
company_identifier
也當作自定義數據使用
g_advertisingData.company_identifier = 0x11;
g_advertisingData.company_identifier = g_advertisingData.company_identifier | (0x22 << 8);
- 其他自定義數據則對
g_advertisingDataEventsAndParamsData
數組進行賦值
g_advertisingData.data.p_data = g_advertisingDataEventsAndParamsData;
g_advertisingData.data.size = 19;
- 掃描響應包也是如此,同時再掃描響應包的內容中加入了設備名稱
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 設置BLE連接狀態
@param status -[in] true - 已連接;false - 已斷開
@return 無
*/
void SetBleConnectStatus(bool status)
{
s_isConnectedFlag = status;
}
/**
@brief 獲取BLE連接狀態
@param 無
@return true - 已連接;false - 已斷開
*/
bool GetBleConnectStatus(void)
{
return s_isConnectedFlag;
}
static bool s_waitForUpdateAdvDataFlag = false;
/**
@brief 設置等待更新廣播狀態
@param status -[in] true - 等待;false - 空閒
@return 無
*/
void SetWaitForUpdateAdvDataStatus(bool status)
{
s_waitForUpdateAdvDataFlag = status;
}
/**
@brief 獲取等待更新廣播狀態
@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); // 初始化廣播,導入參數
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG); // 設置廣播識別號
}
/**@brief Function for initializing the Advertising functionality.
*/
static void advertising_init(void)
{
ret_code_t err_code;
memset(&g_advertisingInit, 0, sizeof(g_advertisingInit));
// 初始化廣播數據包和掃描響應包內容
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; // 廣播超時時間,值0則保持一種廣播模式不變
g_advertisingInit.evt_handler = on_adv_evt;
err_code = ble_advertising_init(&m_advertising, &g_advertisingInit); // 初始化廣播,導入參數
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG); // 設置廣播識別號
}
7.4 初始化廣播內容
通過調用 InitAdvertisingData
和 InitScanResponseData
兩個函數初始化廣播數據包和掃描響應包
7.5 動態更新廣播內容
例如在一些中斷函數中,通過對 g_advertisingDataEventsAndParamsData
進行賦值,同時在連接時不更新廣播,等待斷開連接後更新。
// 中斷函數中
g_advertisingDataEventsAndParamsData = 0x55
if(GetBleConnectStatus() == false)
{
UpdataAdvData(); // 非連接狀態,立即更新廣播
}
else
{
SetWaitForUpdateAdvDataStatus(true); // 等待斷開後更新廣播
}
然後再藍牙事件處理函數 ble_evt_handler
中,判斷是否正在連接中,如果不是,立即更新廣播內容
/**@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 日
• 參考:青風電子社區