NRF52832學習筆記(10)——GAP從機端廣播自定義數據

一、背景

鏈路層(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列表在廣播中,實際工程還有更多UUID
  • uuids_complete:全部服務UUID列表,廣播中顯示UUID列表就是實際工程中所有UUID
  • uuids_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廣播,設置爲NULL
  • p_tk_value:安全管理TK值的區域。這個區域僅僅用於NFC。對應BLE廣播,設置爲NULL
  • p_sec_mgr_oob_flags:安全管理器帶外標誌字段。這個區域僅僅用於NFC。對應BLE廣播,設置爲NULL
  • p_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列表在廣播中,實際工程還有更多UUID
  • uuids_complete:全部服務UUID列表,廣播中顯示UUID列表就是實際工程中所有UUID
  • uuids_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列表的指針指向這個結構體。

  1. 首先,在主函數 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 長度是不同的,分別爲 128bit16bit,如下面定義:
/** @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). */
/** @} */
  1. 接着,在廣播初始化函數中添加如下代碼:
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 個字節的空間,因此需要注意可使用的空間。

  1. 同上,首先在主函數 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}
};
  1. 接着,在廣播初始化函數中添加如下代碼:
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 工程中,廣播初始化的代碼如下:

  1. 首先,聲明 m_adv_uuids 結構體:
static ble_uuid_t m_adv_uuids[] =
{
  {BLE_UUID_CURRENT_TIME_SERVICE, BLE_UUID_TYPE_BLE}
};
  1. 接着,在廣播初始化函數中添加如下代碼:
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 掃描後顯示:

五、廣播自定義數據

  1. 首先,在 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 號爲:0x0059
  • data:製造商自定義的數據,這個參數可以自由的設置,只要廣播包的空間足夠。假設自定義數據爲 0x11,0x22,0x33,0x44,0x55。
  1. 接着,在廣播初始化函數中添加如下代碼:
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.cuser_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 初始化廣播內容

通過調用 InitAdvertisingDataInitScanResponseData 兩個函數初始化廣播數據包和掃描響應包

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 日

• 參考:青風電子社區

發佈了89 篇原創文章 · 獲贊 134 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章