修改nordic系列芯片广播名
一、local name 和device name的区别
关于local name 和device name,很多人可能有疑惑,为什么蓝牙有两个名字。可以这样简单地区分:
1.Local Name是广播出来的。Device Name是GATT service中的一个特性,需要连接后才能读或写。。
2.Local Name不能过长,因为广播包数据长度有限。Local Name有两类short和long。具体长度可以自己设置。Device Name的最长为248byte。Local Name最长能到达29bytes。
3.Local Name和Device Name要求保持一致性。Local Name必须是Device Name的开始连续的一部分或全部。例如Device Name是"BT_DEVICE",则Local Name可以是"BT_D"或 “BT_DEVICE”。
二、举例
1.如何用代码实现的
我们看看nordic sdk15.0的代码是如何去设置这两个名字的。
整个工程我们只看到“DEVICE_NAME”的宏定义。只找到设置Device Name,找不到设置local name的代码,其实是隐藏起来了。我们找到下面这个函数ble_advdata_encode,最后一段
这里是编码,把所有的adv data组合起来,用于广播的。我们再看深一层,看看name_encode这个函数。在这个函数里找到获取宏定义DEVICE_NAME里函数。
// Get GAP device name and length
err_code = sd_ble_gap_device_name_get(&p_encoded_data[(*p_offset) +AD_DATA_OFFSET], &actual_length);
2.验证
既然我们找到了,我们一起来修改这两个变量试试:
把DEVICE_NAME改成这样
#define DEVICE_NAME "Nordic_HRM__Nordic_HRM__Nordic_HRM__Nordic_HRM__Nordic_HRM__Nordic_HRM__Nordic_HRM__" /**< Name of device. Will be included in the advertising data. */
然后运行一下,发现出错了。(晕)
我们再看看是哪里出现的问题,device name的长度最长是248,local name的长度看广播了多少东西,但是这个name_encode这个函数帮我们截断,不用我们担心。
看看出错的地方:
[外链图片转存失败(img-0ETZ0al8-1564398878266)(en-resource://database/1644:0)]
就是下面这个函数出现的问题。这个函数是API,我们看不到里面的代码。
err_code = sd_ble_gap_device_name_set(&sec_mode,
(const uint8_t *)DEVICE_NAME,
strlen(DEVICE_NAME));
看看注释
/**@brief Set GAP device name.
*
* @note If the device name is located in application flash memory (see @ref ble_gap_cfg_device_name_t),
* it cannot be changed. Then @ref NRF_ERROR_FORBIDDEN will be returned.
*
* @param[in] p_write_perm Write permissions for the Device Name characteristic, see @ref ble_gap_conn_sec_mode_t.
* @param[in] p_dev_name Pointer to a UTF-8 encoded, <b>non NULL-terminated</b> string.
* @param[in] len Length of the UTF-8, <b>non NULL-terminated</b> string pointed to by p_dev_name in octets (must be smaller or equal than @ref BLE_GAP_DEVNAME_MAX_LEN).
*
* @retval ::NRF_SUCCESS GAP device name and permissions set successfully.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
* @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied.
* @retval ::NRF_ERROR_FORBIDDEN Device name is not writable.
*/
SVCALL(SD_BLE_GAP_DEVICE_NAME_SET, uint32_t, sd_ble_gap_device_name_set(ble_gap_conn_sec_mode_t const *p_write_perm, uint8_t const *p_dev_name, uint16_t len));
还是看不到什么东西,再看看这个类型 ble_gap_cfg_device_name_t
/**
* @brief Device name and its properties, set with @ref sd_ble_cfg_set.
*
* @note If the device name is not configured, the default device name will be
* @ref BLE_GAP_DEVNAME_DEFAULT, the maximum device name length will be
* @ref BLE_GAP_DEVNAME_DEFAULT_LEN, vloc will be set to @ref BLE_GATTS_VLOC_STACK and the device name
* will have no write access.
*
* @note If @ref max_len is more than @ref BLE_GAP_DEVNAME_DEFAULT_LEN and vloc is set to @ref BLE_GATTS_VLOC_STACK,
* the attribute table size must be increased to have room for the longer device name (see
* @ref sd_ble_cfg_set and @ref ble_gatts_cfg_attr_tab_size_t).
*
* @note If vloc is @ref BLE_GATTS_VLOC_STACK :
* - p_value must point to non-volatile memory (flash) or be NULL.
* - If p_value is NULL, the device name will initially be empty.
*
* @note If vloc is @ref BLE_GATTS_VLOC_USER :
* - p_value cannot be NULL.
* - If the device name is writable, p_value must point to volatile memory (RAM).
*
* @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true:
* - Invalid device name location (vloc).
* - Invalid device name security mode.
* @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true:
* - The device name length is invalid (must be between 0 and @ref BLE_GAP_DEVNAME_MAX_LEN).
* - The device name length is too long for the given Attribute Table.
* @retval ::NRF_ERROR_NOT_SUPPORTED Device name security mode is not supported.
*/
typedef struct
{
ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */
uint8_t vloc:2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/
uint8_t *p_value; /**< Pointer to where the value (device name) is stored or will be stored. */
uint16_t current_len; /**< Current length in bytes of the memory pointed to by p_value.*/
uint16_t max_len; /**< Maximum length in bytes of the memory pointed to by p_value.*/
} ble_gap_cfg_device_name_t;
好了,找到了BLE_GAP_DEVNAME_DEFAULT_LEN只有31,原来是我的设备名写得太长了。
怎么改呢,直接修改了BLE_GAP_DEVNAME_DEFAULT_LEN好像没用,因为这个函数没被调用,大家不要觉得协议栈能用到这个变量,协议栈的调用方式我之前介绍过,都是通过svc和swi的,就是中断服务函数,协议栈的变量不可能被应用层调用,反过来也是不可能的。
那怎么解决这个问题呢:
一、改短设备名的长度,小于31就没问题了。
二、上面的问题是因为分配的栈不足,那么怎么增大栈呢。
仔细看看nrf_sdh_ble_default_cfg_set这个函数,里面有很多分配stack的代码,我们依样画葫芦就好。在nrf_sdh_ble_default_cfg_set函数的最后增加下面的代码就可以了。
// BLE_GAP_CFG_DEVICE_NAME.
memset(&ble_cfg, 0x00, sizeof(ble_cfg));
ble_cfg.gap_cfg.device_name_cfg.max_len = 248;
ble_cfg.gap_cfg.device_name_cfg.vloc = BLE_GATTS_VLOC_STACK;
ret_code = sd_ble_cfg_set(BLE_GAP_CFG_DEVICE_NAME, &ble_cfg, *p_ram_start);
if (ret_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("sd_ble_cfg_set() returned %s when attempting to set BLE_GAP_CFG_DEVICE_NAME.",
nrf_strerror_get(ret_code));
}
欢迎关注个人公众号“低功耗蓝牙技术研究及推广”