Home >> Views >>桃芯视角 >> 蓝牙开发零门槛之二:iBeacon
详细内容

蓝牙开发零门槛之二:iBeacon

时间:2019-04-04     作者:桃芯科技【原创】

INGCHIPS 为客户提供易用的 SDK,帮助客户便捷、高效地开发蓝牙产品。


01.jpg


 SDK Overview

本教材演示如何通过INGChips SDK开发 iBeacon 设备和 iBeacon 扫描器。iBeacon 由苹果公司开发,2013 年发布。利用 iBeacon 可以进行室内精准导航、定位,精准消息推送等,用途广泛。


1、iBeacon 设备

着手开发之前,先从 App Store 下载一个 iBeacon app,比如Locate。Locate预置了一系列 UUID,其中有一个全 0 的(按协议规定,最终产品中 UUID 不得全部为 0)。下面我们就开发一个 UUID 全为 0 的 iBeacon 设备。


01 iBeacon 规范

iBeacon 广播数据包里包含两个项目:


1. Flags

值固定为0x06,也即置起了两个比特,LE General Discoverable Mode & BR/EDR Not Supported。


2. Manufacturer Specific Data

该项里的数据如下表所示:


02.jpg


02 创建 iBeacon 项目

开发 iBeacon 设备的方法与上一教程完成相同,整个开发过程不需要写一行代码,唯一的区别就在于按规范进行设置广播数据。INGChips SDK全面支持Keil、IAR、SEGGER集成开发环境及GNU Arm Toolchain。让我们来试试GNU Arm Toolchain。


03.jpg


03 编辑广播数据

用广播数据编辑器填加0x01 - «Flags»和0xFF - «Manufacturer Specific Data»两项。点击0x01 - «Flags»,勾选LE General Discoverable Mode和BR/EDR Not Supported。


04.jpg


04 编辑 iBeacon 厂家数据

点击0xFF - «Manufacturer Specific Data», 然后点击Edit as按钮从弹出的快捷菜单里选择iBeacon ...打开 iBeacon 数据编辑器。


05.jpg


UUID 全填为0,1m 处的信号功率可随意填写一个合理值,如 -50dBm,稍候我们将利用Locate app 校准信号功率。


05 试一试

完成项目向导里的其它各步骤一个可用GNU Arm Toolchain编译的项目就创建好了。


06.jpg


点击 iBeacon 项目打开控制台,输出make命令编译项目。回到ingWizard,使用跟上一教程中相同的步骤下载程序。打开Locate app 就能看到我们开发的 iBeacon 设备了。


07.jpg


06 在 Locate app 里查看 iBeacon

点选 iBeacon 设备,可以校准信号功率,也可以实时查看距离。


08.jpg


信号功率校准后,回到ingWizard,在项目上右键点击,选择Edit Data -> Advertising菜单调出广播数据编辑器,修改信号功率。在控制台输入make rebuild命令重新编译项目。重新下载程序,可以发现Locate app 里显示的距离精确了一些。


说明:按照规范,iBeacon 设备要使用不可连接非定向(non connectable undirected)广播包以 100ms 为周期发送信标信号。本教程不碰代码,广播采用默认参数发送。



2、iBeacon 扫描器


接下来再开发一个 iBeacon 扫描器。温馨提醒:要写代码了。


01 创建“iscanner” 项目

像往常一样,在ingWizard里创建项目,这次试试IAR Embedded Workbench。Role of Your Device页里将设备角色设定成Central,然后一路Next下去,iscanner项目就创建好了。


09.jpg


打开项目,在profile.c里找到函数user_packet_handler,可以看到一个名为GAP_EVENT_ADVERTISING_REPORT的广播报告事件。每次扫描到广播时就会收到这个事件:



case GAP_EVENT_ADVERTISING_REPORT:

     gap_get_advertisingReport(&report, packet);

     // add your code

     ......

     break;


收到广播报告后需要检查是否是合法的 iBeacon 广播。基于上一教程的讨论,iBeacon 的数据结构可以很直接地写出来:



typedef __packed struct ibeacon_adv

{

    uint16_t apple_id;

    uint16_t id;

    uint8_t  uuid[16];

    uint16_t major;

    uint16_t minor;

    int8_t   ref_power;

} ibeacon_adv_t;


#define APPLE_COMPANY_ID        0x004C

#define IBEACON_ID              0x1502



扩展关键字__packed表示结构体内的各个域以 1 字节,ARM和IAR的编译器皆支持。如果是用SEGGER或者GNU Arm Toolchain,可以使用#pragma pack指令,或者__attribute__ ((packed))属性:



#pragma pack (push, 1) 

typedef struct ibeacon_adv

{

    ...

} ibeacon_adv_t;

#pragma pack (pop)



              

先编写打印 UUID 的辅助函数热热身:



const char *format_uuid(char *buffer, uint8_t *uuid)

{

    sprintf(buffer, "{%02X%02X%02X%02X-%02X%02X-%02X%02X-"

                    "%02X%02X-%02X%02X%02X%02X%02X%02X}", 

           uuid[0], uuid[1], uuid[2], uuid[3],

           uuid[4], uuid[5], uuid[6], uuid[7], uuid[8], uuid[9],

           uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);

    return buffer;

}


距离估计

电磁波在自由空间中传输的损耗公式为:



Loss=32.45+20log(d)+20log(f)



这里到辐射源的距离  以 km 为单位,频率  以 MHz 为单位,计算出的损耗  用 dB 表示。


广播报告里包含接收信号强度指示 (RSSI)。假设开发板得到的 RSSI 跟 iPhone 5s 一致,利用 RSSI 和 iBeacon 广播里携带的ref_power, 根据损耗公式可直接估计距离如下:



double estimate_distance(int8_t ref_power, int8_t rssi)

{

    return pow(10, (ref_power - rssi) / 20.0);   

}


02 iBeacon 扫描器的完整代码



uint8_t length;

    ibeacon_adv_t *p_ibeacon;

    char str_buffer[80];

    ......

    case GAP_EVENT_ADVERTISING_REPORT:

        gap_get_advertisingReport(&report, packet);

        

        // 提取 Manufacturer Specific Data

        p_ibeacon = (ibeacon_adv_t *)ad_data_from_type(report.length, 

                       (uint8_t *)report.data, 0xff, &length);


        // 判断是否为 iBeacon

        if ((length != sizeof(ibeacon_adv_t))

            || (p_ibeacon->apple_id != APPLE_COMPANY_ID)

            || (p_ibeacon->id != IBEACON_ID))

            break;

        

        // 计算并打输出

        printf("%s %04X,%04X, %.1fm\n", 

                format_uuid(str_buffer, p_ibeacon->uuid), 

                p_ibeacon->major, p_ibeacon->minor,

                estimate_distance(p_ibeacon->ref_power, report.rssi));

        break;


按下F7编译,然后下载。利用Locate app 或者用另一块开发板发送 iBeacon 信号,iBeacon 扫描器立即就能扫描到:


10.jpg


iBeacon Scan Result

注意:本教程中的距离估计仅供演示,实际中需要考虑 RSSI 波动的问题。另外,苹果公司提供的SDK并不直接提供距离,而是以 immediate、near、far 三个类别表示。


最新评论
请先登录才能进行回复登录