蓝牙广播动态切换发送

424 阅读3分钟

概述

标准的蓝牙广播最多 31 字节,在一些情况下 31 字节放不下所需的所有字段,比如既要苹果的 iBeacon 厂商自定义字段还要 UUID、Local Name 等,一个解决思路就是交替发出两个不同的广播,分别满足不同需要。

下文以 TI 的 CC2640 蓝牙芯片为例说明此方法。基于官方例程 ti\simplelink_cc2640r2_sdk_1_40_00_45\examples\rtos\CC2640R2_LAUNCHXL\blestack\simple_peripheral,修改 simple_peripheral.c 文件。

设置广播数据

保留原本的 advertData 数组,在广播数据里设置 UUIDs 数据。

static uint8_t advertData[] =
{
// Flags: this field sets the device to use general discoverable
// mode (advertises indefinitely) instead of general
// discoverable mode (advertise for 30 seconds at a time)
0x02, // length of this data
GAP_ADTYPE_FLAGS,
DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,
// service UUID, to notify central devices what services are included
// in this peripheral
0x03, // length of this data
GAP_ADTYPE_16BIT_MORE, // some of the UUID's, but not all
LO_UINT16(SIMPLEPROFILE_SERV_UUID),
HI_UINT16(SIMPLEPROFILE_SERV_UUID)
};

添加新的广播数据数组,发送不一样的 UUIDs。

static uint8_t advertDataNew[] =
{
0x02, // length of this data
0x01,
0x06,
0x05, // length of this data
0x05,
0xAA,
0x9E,
0xC7,
0x71
};

定义新的事件、周期时钟

#define USER_PERIODIC_EVT                  0x0020
#define USER_PERIODIC_EVT_PERIOD           1000
static Clock_Struct USER_periodicClock;
static uint8_t advFlag = 0;

添加周期事件处理函数

在新增自定义处理函数内部进行广播数据切换。

static void USER_performPeriodicTask(void)
{
    if (advFlag == 0) {
        uint8_t initial_advertising_enable = FALSE;
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);

        GAP_UpdateAdvertisingData(selfEntity, TRUE,
                                  sizeof(advertData), advertData );

        initial_advertising_enable = TRUE;
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);
        advFlag = 1;
    }
    else {
        uint8_t initial_advertising_enable = FALSE;
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);

        GAP_UpdateAdvertisingData(selfEntity, TRUE,
                                  sizeof(advertDataNew), advertDataNew);

        initial_advertising_enable = TRUE;
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);
        advFlag = 0;
    }
}

初始化并启动周期时钟

在 SimpleBLEPeripheral_init 函数中初始化时钟,用于周期触发事件,然后改变广播数据。

Util_constructClock(&USER_periodicClock, SimpleBLEPeripheral_clockHandler,
                    USER_PERIODIC_EVT_PERIOD, 0, false, USER_PERIODIC_EVT);
Util_startClock(&USER_periodicClock);

增加监听新增的自定义事件

在 SimpleBLEPeripheral_taskFxn 函数中进行时钟事件处理

//修改事件监听调用,添加自定义事件 USER_PERIODIC_EVT
events = Event_pend(syncEvent, Event_Id_NONE, SBP_ALL_EVENTS | USER_PERIODIC_EVT, ICALL_TIMEOUT_FOREVER);

筛选自定义事件并处理

if (events)
{
    ...
    //添加对应的时间处理,调用函数进行广播数据切换
    if (events & USER_PERIODIC_EVT)
    {
        events &= ~USER_PERIODIC_EVT;
        Util_startClock(&USER_periodicClock);
        USER_performPeriodicTask();
    }
}

参考