赞
踩
蓝牙从机要想被主机连接,首先需要发送广播信息,周围主机通过扫描广播信号,根据从机的广播信息,判断是否连接。
不管是主机还是从机,要想使用蓝牙功能,都需要对蓝牙协议栈进行初始化操作
/**@brief Function for initializing the BLE stack. * * @details Initializes the SoftDevice and the BLE event interrupt. */ static void ble_stack_init(void) { ret_code_t err_code; // 1.协议栈低速时钟初始化并注册状态观察者函数 err_code = nrf_sdh_enable_request(); APP_ERROR_CHECK(err_code); // 2.使用默认配置配置蓝牙协议栈 uint32_t ram_start = 0; err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start); APP_ERROR_CHECK(err_code); // 3.使能协议栈 err_code = nrf_sdh_ble_enable(&ram_start); APP_ERROR_CHECK(err_code); // 4.注册蓝牙事件观察者回调函数 NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL); }
蓝牙协议栈初始化做了四件事:
协议栈时钟低速初始化并注册状态观察者函数
协议栈运行除了主时钟外还需要一个低速时钟,低速时钟有三种来源,根据功耗和硬件选择合适的时钟源。
// <0=> NRF_CLOCK_LF_SRC_RC //内部RC时钟,比外部低速晶振耗电多10ua左右
// <1=> NRF_CLOCK_LF_SRC_XTAL //外部低速晶振,最省电但是需要外接低速晶振
// <2=> NRF_CLOCK_LF_SRC_SYNTH //内部主时钟产生的低速时钟,最耗电
#ifndef NRF_SDH_CLOCK_LF_SRC
#define NRF_SDH_CLOCK_LF_SRC 1
#endif
nrf_clock_lf_cfg_t const clock_lf_cfg =
{
.source = NRF_SDH_CLOCK_LF_SRC,
.rc_ctiv = NRF_SDH_CLOCK_LF_RC_CTIV,
.rc_temp_ctiv = NRF_SDH_CLOCK_LF_RC_TEMP_CTIV,
.accuracy = NRF_SDH_CLOCK_LF_ACCURACY //时钟准确度
};
注册的状态观察者函数其实就是一个中断服务函数的子函数,用户根据返回的状态信息做出相应处理。比如蓝牙协议栈使能失败,协议栈会触发一个软中断,软中断中调用注册的状态观察者函数,用户在状态观察者函数中根据状态信息点灯或者干别的事情,方便用户观察协议栈的运行状态。
使用默认配置配置蓝牙协议栈
默认配置信息可以在sdk_config.h中根据自己需要自行修改。
// 空中包长度 = NRF_SDH_BLE_GATT_MAX_MTU_SIZE + 4,提高蓝牙传输速率时,可以修改这里 #ifndef NRF_SDH_BLE_GAP_DATA_LENGTH #define NRF_SDH_BLE_GAP_DATA_LENGTH 27 #endif // 从机角色个数,可以连接 ? 个主机 #ifndef NRF_SDH_BLE_PERIPHERAL_LINK_COUNT #define NRF_SDH_BLE_PERIPHERAL_LINK_COUNT 1 #endif // 主机角色个数,可以连接 ? 个从机 #ifndef NRF_SDH_BLE_CENTRAL_LINK_COUNT #define NRF_SDH_BLE_CENTRAL_LINK_COUNT 0 #endif // 主机+从机 总的角色个数 #ifndef NRF_SDH_BLE_TOTAL_LINK_COUNT #define NRF_SDH_BLE_TOTAL_LINK_COUNT 1 #endif // 一个连接间隔内可以用于数据传输的事件长度,以1.25 ms为单位。 // 提高蓝牙传输速率时,可以修改这里和连接事件长度扩展相配合 #ifndef NRF_SDH_BLE_GAP_EVENT_LENGTH #define NRF_SDH_BLE_GAP_EVENT_LENGTH 6 #endif // MTU最大长度 蓝牙4.0 最大23 蓝牙4.2以上最大247 #ifndef NRF_SDH_BLE_GATT_MAX_MTU_SIZE #define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 23 #endif // <o> NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE - Attribute Table size in bytes. The size must be a multiple of 4. #ifndef NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE #define NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE 1408 #endif // <o> NRF_SDH_BLE_VS_UUID_COUNT - The number of vendor-specific UUIDs. // 主要每增加一个UUIDs 协议栈消耗RAM会增加0x10 #ifndef NRF_SDH_BLE_VS_UUID_COUNT #define NRF_SDH_BLE_VS_UUID_COUNT 10 #endif // <q> NRF_SDH_BLE_SERVICE_CHANGED - Include the Service Changed characteristic in the Attribute Table. #ifndef NRF_SDH_BLE_SERVICE_CHANGED #define NRF_SDH_BLE_SERVICE_CHANGED 0 #endif
使能协议栈
注册蓝牙事件观察者回调函数
Generic Access Profile(通用访问协议)也就是常说的GAP,所有蓝牙设备中必须存在的profile。NRF52832 SDK中对GAP的操作均在 ble_gap.h中。
蓝牙配对时输入密码功能是GAP的一部分,当然也可以选择开放模式(不用输入密码)则不用进行这里的静态密匙设置操作
/**@brief GAP connection security modes. * * Security Mode 0 Level 0: No access permissions at all (this level is not defined by the Bluetooth Core specification).\n * Security Mode 1 Level 1: No security is needed (aka open link).\n * Security Mode 1 Level 2: Encrypted link required, MITM protection not necessary.\n * Security Mode 1 Level 3: MITM protected encrypted link required.\n * Security Mode 1 Level 4: LESC MITM protected encrypted link using a 128-bit strength encryption key required.\n * Security Mode 2 Level 1: Signing or encryption required, MITM protection not necessary.\n * Security Mode 2 Level 2: MITM protected signing required, unless link is MITM protected encrypted.\n */ typedef struct { uint8_t sm : 4; /**< Security Mode (1 or 2), 0 for no permissions at all. */ uint8_t lv : 4; /**< Level (1, 2, 3 or 4), 0 for no permissions at all. */ } ble_gap_conn_sec_mode_t; //设置静态钥匙 #define STATIC_PASSKEY "123456" static ble_opt_t m_static_pin_option; uint8_t passkey[] = STATIC_PASSKEY; m_static_pin_option.gap_opt.passkey.p_passkey = passkey; err_code = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &m_static_pin_option);
蓝牙的MAC地址分为两类
需要申请购买, 24bit(MSB)公司ID + 24bit设备地址
随机地址分为两种
随机生成的,其中MSB最高两位必须为 11
不解析私有地址,MSB最高两位必须为 00,隔一段时间会自动变化一次
解析私有地址, MSB最高两位必须为 01, 由24bit(MSB)随机数 + 24bit hash组成
一般静态随机地址比较常用,可以通过 sd_ble_gap_addr_set 函数在广播开始前设置蓝牙MAC地址。
ble_gap_addr_t gap_addr =
{
.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC,
.addr = {0x00, 0x11, 0x00, 0xE9, 0x81, 0xC9}
};
sd_ble_gap_addr_set(&gap_addr);
GAP中包含了蓝牙的名称,但是蓝牙名称信息是通过广播包传递给周围设备的,因此想要其他设备可以获取自己的蓝牙名称,需要在广播初始化时向广播包中添加蓝牙名称信息。
#define DEVICE_NAME "Nordic_Blinky"
ble_gap_conn_sec_mode_t sec_mode;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
sd_ble_gap_device_name_set(&sec_mode,(const uint8_t *)DEVICE_NAME, strlen(DEVICE_NAME));
注意大多数手机使用的是UTF-8编码格式,因此想要手机上显示中文蓝牙设备名,需要修改MDK文件编码格式为UTF-8
GAP中包含了蓝牙的图标信息,但是蓝牙图标信息也是通过广播包传递给周围设备的,因此想要其他设备可以获取对应的蓝牙图标,需要在广播初始化时向广播包中添加蓝牙图标信息。
/** @defgroup BLE_APPEARANCES Bluetooth Appearance values * @note Retrieved from http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml * @{ */ #define BLE_APPEARANCE_UNKNOWN 0 /**< Unknown. */ #define BLE_APPEARANCE_GENERIC_PHONE 64 /**< Generic Phone. */ #define BLE_APPEARANCE_GENERIC_COMPUTER 128 /**< Generic Computer. */ #define BLE_APPEARANCE_GENERIC_WATCH 192 /**< Generic Watch. */ #define BLE_APPEARANCE_WATCH_SPORTS_WATCH 193 /**< Watch: Sports Watch. */ #define BLE_APPEARANCE_GENERIC_CLOCK 256 /**< Generic Clock. */ #define BLE_APPEARANCE_GENERIC_DISPLAY 320 /**< Generic Display. */ #define BLE_APPEARANCE_GENERIC_REMOTE_CONTROL 384 /**< Generic Remote Control. */ #define BLE_APPEARANCE_GENERIC_EYE_GLASSES 448 /**< Generic Eye-glasses. */ #define BLE_APPEARANCE_GENERIC_TAG 512 /**< Generic Tag. */ #define BLE_APPEARANCE_GENERIC_KEYRING 576 /**< Generic Keyring. */ #define BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 640 /**< Generic Media Player. */ #define BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 704 /**< Generic Barcode Scanner. */ #define BLE_APPEARANCE_GENERIC_THERMOMETER 768 /**< Generic Thermometer. */ #define BLE_APPEARANCE_THERMOMETER_EAR 769 /**< Thermometer: Ear. */ #define BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR 832 /**< Generic Heart rate Sensor. */ #define BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT 833 /**< Heart Rate Sensor: Heart Rate Belt. */ #define BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 896 /**< Generic Blood Pressure. */ #define BLE_APPEARANCE_BLOOD_PRESSURE_ARM 897 /**< Blood Pressure: Arm. */ #define BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 898 /**< Blood Pressure: Wrist. */ #define BLE_APPEARANCE_GENERIC_HID 960 /**< Human Interface Device (HID). */ #define BLE_APPEARANCE_HID_KEYBOARD 961 /**< Keyboard (HID Subtype). */ #define BLE_APPEARANCE_HID_MOUSE 962 /**< Mouse (HID Subtype). */ #define BLE_APPEARANCE_HID_JOYSTICK 963 /**< Joystick (HID Subtype). */ #define BLE_APPEARANCE_HID_GAMEPAD 964 /**< Gamepad (HID Subtype). */ #define BLE_APPEARANCE_HID_DIGITIZERSUBTYPE 965 /**< Digitizer Tablet (HID Subtype). */ #define BLE_APPEARANCE_HID_CARD_READER 966 /**< Card Reader (HID Subtype). */ #define BLE_APPEARANCE_HID_DIGITAL_PEN 967 /**< Digital Pen (HID Subtype). */ #define BLE_APPEARANCE_HID_BARCODE 968 /**< Barcode Scanner (HID Subtype). */ #define BLE_APPEARANCE_GENERIC_GLUCOSE_METER 1024 /**< Generic Glucose Meter. */ #define BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR 1088 /**< Generic Running Walking Sensor. */ #define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE 1089 /**< Running Walking Sensor: In-Shoe. */ #define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE 1090 /**< Running Walking Sensor: On-Shoe. */ #define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP 1091 /**< Running Walking Sensor: On-Hip. */ #define BLE_APPEARANCE_GENERIC_CYCLING 1152 /**< Generic Cycling. */ #define BLE_APPEARANCE_CYCLING_CYCLING_COMPUTER 1153 /**< Cycling: Cycling Computer. */ #define BLE_APPEARANCE_CYCLING_SPEED_SENSOR 1154 /**< Cycling: Speed Sensor. */ #define BLE_APPEARANCE_CYCLING_CADENCE_SENSOR 1155 /**< Cycling: Cadence Sensor. */ #define BLE_APPEARANCE_CYCLING_POWER_SENSOR 1156 /**< Cycling: Power Sensor. */ #define BLE_APPEARANCE_CYCLING_SPEED_CADENCE_SENSOR 1157 /**< Cycling: Speed and Cadence Sensor. */ #define BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 3136 /**< Generic Pulse Oximeter. */ #define BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 3137 /**< Fingertip (Pulse Oximeter subtype). */ #define BLE_APPEARANCE_PULSE_OXIMETER_WRIST_WORN 3138 /**< Wrist Worn(Pulse Oximeter subtype). */ #define BLE_APPEARANCE_GENERIC_WEIGHT_SCALE 3200 /**< Generic Weight Scale. */ #define BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS_ACT 5184 /**< Generic Outdoor Sports Activity. */ #define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_DISP 5185 /**< Location Display Device (Outdoor Sports Activity subtype). */ #define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_DISP 5186 /**< Location and Navigation Display Device (Outdoor Sports Activity subtype). */ #define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_POD 5187 /**< Location Pod (Outdoor Sports Activity subtype). */ #define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_POD 5188 /**< Location and Navigation Pod (Outdoor Sports Activity subtype). */ //设置图标信息 sd_ble_gap_appearance_set(uint16_t appearance);
BLE功耗低的原因之一就是仅在数据收发时开启射频电路,这里有一个重要的参数----连接间隔 connection interval,它约定了BLE双方碰头时间,当主从机配对连接后,每隔一段时间,主机会向从机发送一包数据,从机接到主机数据后发一包数据给主机,用与主从机之间数据交换和连接状态判断(没有数据包会发生连接超时,断开连接)。当然连接间隔是可以根据需要灵活修改的(7.5ms – 4000ms)
#define MIN_CONN_INTERVAL MSEC_TO_UNITS(100, UNIT_1_25_MS) /**< Minimum acceptable connection interval (0.5 seconds). */ #define MAX_CONN_INTERVAL MSEC_TO_UNITS(200, UNIT_1_25_MS) /**< Maximum acceptable connection interval (1 second). */ #define SLAVE_LATENCY 0 /**< Slave latency. */ #define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) /**< Connection supervisory time-out (4 seconds). */ /**@brief Function for the GAP initialization. * * @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the * device including the device name, appearance, and the preferred connection parameters. */ static void gap_params_init(void) { ret_code_t err_code; ble_gap_conn_params_t gap_conn_params; 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; err_code = sd_ble_gap_ppcp_set(&gap_conn_params); APP_ERROR_CHECK(err_code); }
连接参数 | 解释 |
---|---|
最小连接间隔 | 范围 7.5ms - 4000ms 蓝牙连接后每隔一段时间唤醒一次射频模块进行主从机通信,连接间隔越长则越省电但是数据传输延迟和传输速率会越小 |
最大连接间隔 | 当没有数据时,主从机为了省电使用最大连接间隔 发生空数据包保持连接状态 |
潜伏周期 | 从机可以跳过连接数据包的次数。当潜伏周期为3时,如果从机没有数据需要发送则从机可以跳过三次连接数据包(不应答主机),从而降低从机功耗。 |
超时时间 | 超过超时时间还没有接收到蓝牙数据包,会产生超时事件,可以在超时事件中断开蓝牙连接。范围 100ms - 32000ms。 超时时间 >= 连接间隔 * ( 潜伏周期 + 1) |
其中图中M为主机发送的数据包, S为从机发送的数据包,当潜伏周期为0时,每个主机数据包从机均需要应答,而当潜伏周期为3时,从机可以跳过三个数据包应答一次主机。
nrf52832 支持-40dBm, -20dBm, -16dBm, -12dBm, -8dBm, -4dBm, 0dBm, +3dBm , +4dBm.9种功率,通过sd_ble_gap_tx_power_set 函数进行设置.
/**@brief GAP TX Power roles. */ enum BLE_GAP_TX_POWER_ROLES { BLE_GAP_TX_POWER_ROLE_ADV = 1, /**< 广播角色. */ BLE_GAP_TX_POWER_ROLE_SCAN_INIT = 2, /**< 扫描和发起者角色. */ BLE_GAP_TX_POWER_ROLE_CONN = 3, /**< 连接角色. */ }; /**@brief Set the radio's transmit power. * * @param[in] role The role to set the transmit power for, see @ref BLE_GAP_TX_POWER_ROLES for * possible roles. * @param[in] handle The handle parameter is interpreted depending on role: * - If role is @ref BLE_GAP_TX_POWER_ROLE_CONN, this value is the specific connection handle. * - If role is @ref BLE_GAP_TX_POWER_ROLE_ADV, the advertising set identified with the advertising handle, * will use the specified transmit power, and include it in the advertising packet headers if * @ref ble_gap_adv_properties_t::include_tx_power set. * - For all other roles handle is ignored. * @param[in] tx_power Radio transmit power in dBm (see note for accepted values). * * @note Supported tx_power values: -40dBm, -20dBm, -16dBm, -12dBm, -8dBm, -4dBm, 0dBm, +3dBm and +4dBm. * @note The initiator will have the same transmit power as the scanner. * @note When a connection is created it will inherit the transmit power from the initiator or * advertiser leading to the connection. * * @retval ::NRF_SUCCESS Successfully changed the transmit power. * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. */ SVCALL(SD_BLE_GAP_TX_POWER_SET, uint32_t, sd_ble_gap_tx_power_set(uint8_t role, uint16_t handle, int8_t tx_power));
在NRF52832协议栈中,当主从机连接后,如果想要修改GAP连接参数,需要从机向主机发起连接参数更新请求(从机发起连接参数请求前,使用主机的连接参数),主机收到连接参数更新请求后,如果同意更新GAP参数则会更改自身GAP参数然后向从机发送同意连接参数更新。从机是何时发起连接参数更新请求?
ret_code_t ble_conn_params_init(const ble_conn_params_init_t * p_init) { ret_code_t err_code; VERIFY_PARAM_NOT_NULL(p_init); m_conn_params_config = *p_init; m_conn_params_config.p_conn_params = &m_preferred_conn_params; if (p_init->p_conn_params != NULL) { // Set the connection params in stack. err_code = sd_ble_gap_ppcp_set(p_init->p_conn_params); if (err_code != NRF_SUCCESS) { return err_code; } m_preferred_conn_params = *p_init->p_conn_params; } else { // Get the (default) connection params from stack. err_code = sd_ble_gap_ppcp_get(&m_preferred_conn_params); if (err_code != NRF_SUCCESS) { return err_code; } } //lint -save -e681 "Loop not entered" when NRF_BLE_CONN_PARAMS_INSTANCE_COUNT is 0 for (uint32_t i = 0; i < NRF_BLE_CONN_PARAMS_INSTANCE_COUNT; i++) { ble_conn_params_instance_t * p_instance = &m_conn_params_instances[i]; instance_free(p_instance); p_instance->timer_id = &m_timer_data[i]; err_code = app_timer_create(&p_instance->timer_id, APP_TIMER_MODE_SINGLE_SHOT, update_timeout_handler); if (err_code != NRF_SUCCESS) { return NRF_ERROR_INTERNAL; } } //lint -restore return NRF_SUCCESS; } /**@brief Function for initializing the Connection Parameters module. */ 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; 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; //GAP 通知服务句柄 cp_init.disconnect_on_fail = false; //更新不成功自动断开连接? 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); }
ble_conn_params_init 函数其实就是创建了几个软件定时器,在软件定时器超时回调函数 update_timeout_handler 中发送参数更新请求。ble_conn_params.c中注册了一个观察者回调函数,当主从机连接成功后,会在 on_connect(p_ble_evt); 函数中开启参数更新软件定时器。
/** * @brief Function for handling BLE events. * * @param[in] p_ble_evt Event received from the BLE stack. * @param[in] p_context Context. */ static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) { switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: on_connect(p_ble_evt); break; case BLE_GAP_EVT_DISCONNECTED: on_disconnect(p_ble_evt); break; case BLE_GATTS_EVT_WRITE: on_write(p_ble_evt); break; case BLE_GAP_EVT_CONN_PARAM_UPDATE: on_conn_params_update(p_ble_evt); break; default: // No implementation needed. break; } }
nrf52832中对GATT初始化主要是为了初始化MTU长度。
MTU: 最大传输单元(MAXIMUM TRANSMISSION UNIT), 指在一个PDU (Protocol Data Unit: 协议数据单元,在一个传输单元中的有效传输数据)能够传输的最大数据量(多少字节可以一次性传输到对方)。
MTU 交换是为了在主从双方设置一个PDU中最大能够交换的数据量,通过MTU的交换和双方确认(注意这个MTU是不可以协商的,只是通知对方,双方在知道对方的极限后会选择一个较小的值作为以后的MTU,比如说,主设备发出一个150个字节的MTU请求,但是从设备回应MTU是23字节,那么今后双方要以较小的值23字节作为以后的MTU),主从双方约定每次在做数据传输时不超过这个最大数据单元
蓝牙建立连接后,必须要进行MTU交换,在NRF52832中 MTU最小23,最大247。
普通广播包最长为31 byte,如果不够还可以将广播信息放到广播回包中,广播回包也是31 byte。
蓝牙5.1以后引入拓展广播包以支持蓝牙测向(AOA,DOA)功能,但是没用过nrf52832也不支持。
#define BLE_GAP_ADV_SET_DATA_SIZE_MAX (31) static uint8_t m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; /**< Buffer for storing an encoded advertising set. */ static uint8_t m_enc_scan_response_data[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; /**< Buffer for storing an encoded scan data. */ /**@brief Struct that contains pointers to the encoded advertising data. */ static ble_gap_adv_data_t m_adv_data = { .adv_data = { .p_data = m_enc_advdata, .len = BLE_GAP_ADV_SET_DATA_SIZE_MAX }, .scan_rsp_data = { .p_data = m_enc_scan_response_data, .len = BLE_GAP_ADV_SET_DATA_SIZE_MAX } };
广播包31个byte中存放的是一个又一个的结构体,结构体由长度、数据类型、数据组成。
//结构体伪代码
typedef struct
{
uint8_t len;
uint8_t type;
uint8_t data[len];
}adv_t;
比如要将广播名称 广播出去,需要将数据类型设置为 BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME, 数据中填名字即可。其中全部的数据类型如下:
/**@defgroup BLE_GAP_AD_TYPE_DEFINITIONS GAP Advertising and Scan Response Data format * @note Found at https://www.bluetooth.org/Technical/AssignedNumbers/generic_access_profile.htm * @{ */ #define BLE_GAP_AD_TYPE_FLAGS 0x01 /**< Flags for discoverability. */ #define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE 0x02 /**< Partial list of 16 bit service UUIDs. */ #define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE 0x03 /**< Complete list of 16 bit service UUIDs. */ #define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE 0x04 /**< Partial list of 32 bit service UUIDs. */ #define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE 0x05 /**< Complete list of 32 bit service UUIDs. */ #define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE 0x06 /**< Partial list of 128 bit service UUIDs. */ #define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE 0x07 /**< Complete list of 128 bit service UUIDs. */ #define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 0x08 /**< Short local device name. */ #define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME 0x09 /**< Complete local device name. */ #define BLE_GAP_AD_TYPE_TX_POWER_LEVEL 0x0A /**< Transmit power level. */ #define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE 0x0D /**< Class of device. */ #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C 0x0E /**< Simple Pairing Hash C. */ #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F /**< Simple Pairing Randomizer R. */ #define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 /**< Security Manager TK Value. */ #define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS 0x11 /**< Security Manager Out Of Band Flags. */ #define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 /**< Slave Connection Interval Range. */ #define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT 0x14 /**< List of 16-bit Service Solicitation UUIDs. */ #define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT 0x15 /**< List of 128-bit Service Solicitation UUIDs. */ #define BLE_GAP_AD_TYPE_SERVICE_DATA 0x16 /**< Service Data - 16-bit UUID. */ #define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS 0x17 /**< Public Target Address. */ #define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS 0x18 /**< Random Target Address. */ #define BLE_GAP_AD_TYPE_APPEARANCE 0x19 /**< Appearance. */ #define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL 0x1A /**< Advertising Interval. */ #define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B /**< LE Bluetooth Device Address. */ #define BLE_GAP_AD_TYPE_LE_ROLE 0x1C /**< LE Role. */ #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256 0x1D /**< Simple Pairing Hash C-256. */ #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 0x1E /**< Simple Pairing Randomizer R-256. */ #define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID 0x20 /**< Service Data - 32-bit UUID. */ #define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID 0x21 /**< Service Data - 128-bit UUID. */ #define BLE_GAP_AD_TYPE_LESC_CONFIRMATION_VALUE 0x22 /**< LE Secure Connections Confirmation Value */ #define BLE_GAP_AD_TYPE_LESC_RANDOM_VALUE 0x23 /**< LE Secure Connections Random Value */ #define BLE_GAP_AD_TYPE_URI 0x24 /**< URI */ #define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA 0x3D /**< 3D Information Data. */ #define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF /**< Manufacturer Specific Data. */ /**@} */
在前面的GAP初始化中,已经初始化了蓝牙名称、蓝牙图标等信息,在广播初始化时可以将这些信息填到广播数据包中广播出去。
static void advertising_init(void) { ret_code_t err_code; ble_advdata_t advdata; ble_advdata_t srdata; ble_uuid_t adv_uuids[] = {{LBS_UUID_SERVICE, m_lbs.uuid_type}}; // Build and set advertising data. memset(&advdata, 0, sizeof(advdata)); advdata.name_type = BLE_ADVDATA_FULL_NAME; //广播名字信息 advdata.include_appearance = true; //广播图标信息 advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; //通用广播模式 //也可以将UUID信息 广播出去 memset(&srdata, 0, sizeof(srdata)); srdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]); srdata.uuids_complete.p_uuids = adv_uuids; //Nordic 的SDK中自带的函数,可以将名字信息、图标信息、UUID等信息封装成广播结构体并填入广播包中 err_code = ble_advdata_encode(&advdata, m_adv_data.adv_data.p_data, &m_adv_data.adv_data.len); APP_ERROR_CHECK(err_code); err_code = ble_advdata_encode(&srdata, m_adv_data.scan_rsp_data.p_data, &m_adv_data.scan_rsp_data.len); APP_ERROR_CHECK(err_code); ble_gap_adv_params_t adv_params; // Set advertising parameters. memset(&adv_params, 0, sizeof(adv_params)); adv_params.primary_phy = BLE_GAP_PHY_1MBPS; //1M adv_params.duration = APP_ADV_DURATION; //广播持续时间 adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED; //广播类型,所有主机都可以扫描到该广播信息 adv_params.p_peer_addr = NULL; adv_params.filter_policy = BLE_GAP_ADV_FP_ANY; //权限 adv_params.interval = APP_ADV_INTERVAL; //广播间隔 err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &adv_params); APP_ERROR_CHECK(err_code); }
初始化广播后,开启广播
static void advertising_start(void)
{
ret_code_t err_code;
err_code = sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);
APP_ERROR_CHECK(err_code);
bsp_board_led_on(ADVERTISING_LED);
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。