一、简介
iBeacon 是苹果公司2013年9月发布的移动设备用 OS(iOS7)上配备的新功能。其工作方式是,配备有 **低功耗蓝牙(BLE)**通信功能的设备使用 BLE 技术向周围发送自己特有的 ID,接收到该 ID 的应用软件会根据该 ID 采取一些行动。比如,在店铺里设置 iBeacon 通信模块的话,便可让 iPhone 和 iPad 上运行一资讯告知服务器,或者由服务器向顾客发送折扣券及进店积分。此外,还可以在家电发生故障或停止工作时使用 iBeacon 向应用软件发送资讯。
二、iBeacon格式
iBeacon 使用的是 BLE 技术,具体而言,利用的是 BLE 中名为“通告帧”(Advertising)的广播帧。通告帧是定期发送的帧,只要是支持 BLE 的设备就可以接收到。iBeacon 通过在这种通告帧的有效负载部分嵌入苹果自主格式的数据来实现。
AD Field Length | Type | Company ID | iBeacon Type | iBeacon Length | UUID | Major | Minor | TX Power |
---|
AD Field Length: Advertisement Data 的长度,表示有用的广播信息长度
Type: 广播类型
Company ID: 数据字段以两字节的公司 ID 码开始。SIG 将这些 ID 码发放给公司,其中 0x004C 代表的是Apple id(只有这个 ID,设备才会叫 iBeacon)
iBeacon Type: 字节 0x02 代表这个设备是 Beacon
iBeacon Length: 剩下字段的长度
UUID: 规定为 ISO/IEC11578:1996 标准的 128 位标识符
Major、Minor: 由 iBeacon 发布者自行设定,都是 16 位的标识符。比如,连锁店可以在 Major 写入区域资讯,可在 Minor 中写入个别店铺的 ID 等。另外,在家电中嵌入 iBeacon 功能时,可以用 Major 表示产品型号,用 Minor 表示错误代码,用来向外部通知故障
TX Power: APP 通过 iBeacon 发送信号强度估算出的在 1 米的时候 RSSI 强度
三、修改代码
打开工程 SDK\examples\ble_peripheral\ble_app_beacon
首先我们先定义 beacon 相关的数据,其中我们用户需要关注的主要有3个参数,UUID、Major 以及 Minor,其他的参数大家可以理解为固定的格式(格式固定,但数据内容不固定,可能有不同的厂商信息)。另外还有一个值得我们关注的数据,那就是 APP_COMPANY_IDENTIFIER
,如果我们定义此参数为 0x004C
(也就是 Apple id),那么我们的基站设备就被成为 iBeacon。
// BEACON数据
#define APP_BEACON_INFO_LENGTH 0x17 // BEACON数据总长度
#define APP_ADV_DATA_LENGTH 0x15 // BEACON特殊字节的长度
#define APP_DEVICE_TYPE 0x02 // 字节0x02代表这个设备是BEACON
#define APP_MEASURED_RSSI 0xC3 // BEACON在1米距离处的信号强度
#define APP_COMPANY_IDENTIFIER 0x004C // 004C代表的是Apple id(只有这个ID,设备才会叫iBeacon)
#define APP_MAJOR_VALUE 0x01, 0x02 // major
#define APP_MINOR_VALUE 0x03, 0x04 // minor
#define APP_BEACON_UUID 0x01, 0x12, 0x23, 0x34, \
0x45, 0x56, 0x67, 0x78, \
0x89, 0x9a, 0xab, 0xbc, \
0xcd, 0xde, 0xef, 0xf0 /**< Proprietary UUID for Beacon. */
// BEACON数据数组,用于初始化广播数据内容
static uint8_t m_beacon_info[APP_BEACON_INFO_LENGTH] =
{
APP_DEVICE_TYPE,
APP_ADV_DATA_LENGTH,
APP_BEACON_UUID,
APP_MAJOR_VALUE,
APP_MINOR_VALUE,
APP_MEASURED_RSSI
};
对于 iBeacon 的数据,通过广播形式广播出去,那么其主要设置就是主函数里广播初始化部分(查看NRF52832学习笔记(9)——GAP从机端广播),所有定义的参数必须在广播初始化的时候进行配置。
static void advertising_init(void)
{
uint32_t err_code;
ble_advdata_t advdata;
uint8_t flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED; // 广播类型
ble_advdata_manuf_data_t manuf_specific_data;
manuf_specific_data.company_identifier = APP_COMPANY_IDENTIFIER; // 公司ID号
#if defined(USE_UICR_FOR_MAJ_MIN_VALUES)
// If USE_UICR_FOR_MAJ_MIN_VALUES is defined, the major and minor values will be read from the
// UICR instead of using the default values. The major and minor values obtained from the UICR
// are encoded into advertising data in big endian order (MSB First).
// To set the UICR used by this example to a desired value, write to the address 0x10001080
// using the nrfjprog tool. The command to be used is as follows.
// nrfjprog --snr <Segger-chip-Serial-Number> --memwr 0x10001080 --val <your major/minor value>
// For example, for a major value and minor value of 0xabcd and 0x0102 respectively, the
// the following command should be used.
// nrfjprog --snr <Segger-chip-Serial-Number> --memwr 0x10001080 --val 0xabcd0102
uint16_t major_value = ((*(uint32_t *)UICR_ADDRESS) & 0xFFFF0000) >> 16;
uint16_t minor_value = ((*(uint32_t *)UICR_ADDRESS) & 0x0000FFFF);
uint8_t index = MAJ_VAL_OFFSET_IN_BEACON_INFO;
m_beacon_info[index++] = MSB_16(major_value);
m_beacon_info[index++] = LSB_16(major_value);
m_beacon_info[index++] = MSB_16(minor_value);
m_beacon_info[index++] = LSB_16(minor_value);
#endif
manuf_specific_data.data.p_data = (uint8_t *) m_beacon_info; // 数据结构体
manuf_specific_data.data.size = APP_BEACON_INFO_LENGTH; // 数据长度
// Build and set advertising data.
memset(&advdata, 0, sizeof(advdata));
advdata.name_type = BLE_ADVDATA_NO_NAME;
advdata.flags = flags;
advdata.p_manuf_specific_data = &manuf_specific_data;
// Initialize advertising parameters (used when starting advertising).
memset(&m_adv_params, 0, sizeof(m_adv_params));
m_adv_params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
m_adv_params.p_peer_addr = NULL; // Undirected advertisement.
m_adv_params.filter_policy = BLE_GAP_ADV_FP_ANY;
m_adv_params.interval = NON_CONNECTABLE_ADV_INTERVAL;
m_adv_params.duration = 0; // Never time out.
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 = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_adv_params);
APP_ERROR_CHECK(err_code);
}
在主函数中,调用初始化广播函数 advertising_init(),当函数 advertising_start() 启动广播后,就可以实现广播信息的发出,也就是信标的广播包的广播
int main(void)
{
// Initialize.
log_init();
timers_init();
leds_init();
power_management_init();
ble_stack_init(); // 协议栈初始化
advertising_init(); // 广播初始化
// Start execution.
NRF_LOG_INFO("Beacon example started.");
advertising_start(); // 开始广播
// Enter main loop.
for (;; )
{
idle_state_handle();
}
}
• 由 Leung 写于 2021 年 1 月 6 日
• 参考:青风电子社区