人工智能如何赋能物联网?EDGE AI →
  1. Home
  2. 新闻

    带响应的周期性广播 (PAwR)

带响应的周期性广播 (PAwR) 2024-09-07 Hung Bui

有了 PAwR,现在就有可能建立一个超大型的一对多双向网络,并以极低的功耗运行。

**带响应的周期性广播(PAWR)**是蓝牙 5.4的一项新功能。它扩展了蓝牙 5.0 中的周期性广播协议。周期性广播是指设备以确定的时间发送广播数据,现在可以进行双向通信。接收器可将响应有效载荷传送回广播者。有了 PAwR,现在就可以建立一个超大型的一对多双向网络,并以极低的功耗运行。在许多应用中,人们必须通过双向通信管理成百上千个能源受限的设备,例如电子货架标签(ESL)、传感器网络、仓库管理等。让我们深入了解这项非常有趣的新技术。

1. PAwR 如何工作

1.1 广播类型

Bluetooth PAwR

蓝牙 5.4 在逻辑传输层上定义了三种主要的广告类型: 广播(Advertising Broadcast, ADVB), 周期广播(Periodic Advertising Broadcast, PADVB), 和带响应的周期性广播 (Periodic Advertising with Responses, PAwR)。这些广播协议允许广播商向周围任意数量的扫描仪广播数据,仅受广播商射频范围的限制。

蓝牙 LE 传统广播和蓝牙 LE 扩展广播都属于 ADVB。在这些模式中,广播是不规则的,数据只向一个方向发送。在大多数情况下,扫描仪需要有充足的电源,因为扫描仪和广播器之间没有时间同步。此外,为避免广播商之间的定时碰撞,广播间隔会有 0-10 毫秒的随机延迟。这就要求扫描仪具有较大的 RX 窗口,因此需要消耗更多的电流。

与 ADVB 不同,周期性广播(PADVB)进行定期且精确的定时广播。扫描仪和广播商之间有时间同步。PADVB 不使用 ADVB 的 0-10 毫秒随机延迟。因此,扫描仪只需监听一段非常短且可预测的时间。利用周期性广播建立一个大型的一对多低功耗网络是可能的,例如音频广播、测向、物联网网络等。然而,缺少的是低功耗扫描仪只能接收数据,而不能将数据发送回广播商。

PAwR 的推出就是为了解决这个问题。它允许广播商发送精确的常规广播数据,同时允许扫描仪向广播商发送响应有效载荷。此外,在需要更高的吞吐量时,它还为广播商提供了与扫描仪建立蓝牙(Bluetooth LE)连接的机制。

1.2 时间

Bluetooth PAwR

与其他类型的广播类似,PAwR 的运行间隔称为周期性广播间隔(Periodic Advertising Interval)。它在准确的时间间隔内发生,没有随机延迟。每个 PAwR 事件都会有多个子事件。这与 PADVB 不同,在 PADVB 中,每个事件只有一个周期性广播数据包。重要的是,同步到 PAwR 的扫描仪不会监听所有子事件,只会选择它订阅/同步到的子事件。多个扫描仪可以订阅同一个子事件。这意味着一台扫描仪可以订阅多个子事件。每个广播事件最多可以有 128 个子事件。

Bluetooth PAwR

放大其中一个子事件,在事件开始时,有一个来自广播商的传输包。它可以是:

  • AUX_SYNC_SUBEVENT_IND - 周期性广播包.
  • AUX_CONNECT_REQ - 广播商的连接请求.

与该子事件同步的所有扫描器都会扫描该数据包并处理有效载荷。数据包发出后,会有一列响应槽供扫描仪将其响应发送回广播商。响应槽最多可达 256 个。在哪个响应槽上发送哪个扫描器由应用程序/配置文件决定。为避免碰撞,一个响应槽中只能有一个扫描仪响应。

这是 PAwR 的 R 部分,是与普通周期性广播的主要区别。这样就能以极低的功耗形成超大型双向一对多网络。可以发现,扫描器/观测器只需在每个周期性广播间隔唤醒一次,以扫描子事件传输包。如果它有数据提供给广播商,就可以在其中一个响应时隙进行传输,然后再次休眠。由于并非所有扫描器都需要同时发送数据,因此一个广播商可以为大量扫描器提供服务。延迟时间很短;可低至周期性广播间隔,根据广播商的配置,间隔时间在 7.5ms 至 81.91875s 之间。

这里的限制是吞吐量。如果扫描仪需要传输或接收大量数据,可能会受到广播时间间隔的限制。如上所述,广播时间间隔最长可达 81.91875 秒,将广播时间间隔改为更短的时间间隔需要更新所有扫描仪以同步到新的时间间隔。在大多数情况下,这是不现实的。

解决这个问题的办法是在扫描仪和广播商之间建立蓝牙 LE 连接。PAwR 支持在不使用传统 ADVB 的情况下建立连接。为了启动连接,广播商在子事件传输包中发送 AUX_CONNECT_REQ 包,而不是 AUX_SYNC_SUBEVENT_IND 包。AUX_CONNECT_REQ 包含扫描仪的地址和扫描仪进入蓝牙 LE 连接时应使用的连接参数。待连接的扫描仪将以 AUX_CONNECT_RSP 作为回应。该响应应在 AUX_CONNECT_REQ 数据包之后立即发送,无需等待响应时隙。随后将立即建立蓝牙 LE 连接。广播商将成为中心,扫描仪将成为外围。通过这种分离的蓝牙 LE 连接,它们可以以更高的吞吐量进行通信。

1.3 同步

要跟踪周期性广播并订阅子事件,扫描仪需要从广播商处获得同步和 PAwR 信息。获取同步信息的程序与普通定期广播PADVB 类似。扫描器可以通过扫描扩展广播数据包 ADV_EXT_IND 来获取信息:

Bluetooth PAwR

或者通过建立连接并执行周期性广播同步传输 (PAST) 程序。

Bluetooth PAwR

这两种方法各有利弊。扫描扩展广播数据包 ADV_EXT_IND 不需要连接,但它要求扫描仪能够进行连续扫描以捕捉广播数据包。相比之下,使用 PAST 进行连接并接收定时信息可适用于电源有限的扫描仪,因为它只要求扫描仪进行正常的蓝牙 LE 广播。不过,这对广播商的无线电调度要求更高,因为广播商需要同时进行周期性广播和扫描以建立蓝牙 LE 连接。广播商可以决定不做 ADV_EXT_IND,只做周期性广播 AUX_SYNC_SUBEVENT_IND。这是为了减少广播商的工作量。在这种情况下,PAST 是同步扫描仪的唯一选择。

与 PADVB 相比,除了 SyncInfo(周期性广播间隔、同步Packet Window Offset)外,还有一些专门用于 PAwR 的额外信息需要交换:

  • ACAD- Additional Controller Advertising Data:
    • 响应访问地址
    • 子事件数量
    • 子事件间隔
    • 响应时隙延迟
    • 响应槽间隔

您可能会发现,这些程序中没有定义扫描仪应订阅哪些子事件或响应槽的信息。这就需要应用程序/上层来决定扫描仪应如何获取有关子事件和响应槽的信息。例如,在执行 PAST 时配置响应槽,或对扫描器进行硬编码,使其根据自身地址自动选择响应槽。

2. PAwR 优势和局限

2.1 优势

  • 一对多拓扑结构中的双向通信. PAwR 为蓝牙产品增加了一个重要的缺失部分:大规模双向一对多网络。在蓝牙 5.4 之前,常见的蓝牙网络拓扑结构如下:
    • 一对一。一个外设连接一个中心。
    • 一对多,星形网络。一个中心可以连接多个外围设备,但链接数量有限,通常每个中心的连接数少于 20 个。
    • 一对多广播。一个广播商可以向许多观察者广播数据。观察者的数量可以非常多,但数据只能单向传播,即从广播商到观察者。
    • 多对多,mesh。mesh网络可提供大规模双向网络。不过,它需要由backbone节点组成的基础设施来中继信息。这些backbone节点通常需要主电源。连接的mesh网络可以作为一种解决方案,但它可能比较复杂和僵化。

      使用 PAwR,只需一个简单的同步程序,即可建立一个拥有数百或数千个节点的一对多网络。一个广告商就可以管理与数千台设备之间的数据收发任务。这里的亮点在于,这种双向通信是以同步方式进行的,没有泛洪或潜在的碰撞。
  • **广播数据可以频繁更改。**PAwR 允许频繁更改广播数据。特别是,主机可以精确控制哪个数据包将进入哪个广播子事件。这是 ADVB 和 PADVB 所不具备的。使用 ADVB 和 PADVB 时,您可以随时间更新广播数据,但数据是重复发送的,而且您对广播进行时如何更新数据的控制也很有限。使用 PAwR 时,控制器会请求主机(应用程序)在每次广播事件中更新数据。应用程序可以更新每个广播事件中的每个子事件广播数据包。
  • **广播商可与扫描仪建立蓝牙 LE 连接。**当对等设备需要传输大量数据,而 PAwR 有限的吞吐量无法满足要求时,例如向 ESL 标签传输显示图像时,就会使用这种连接。它与普通的蓝牙 LE 连接略有不同,不是由扫描仪,而是由周期性广播商决定与扫描仪建立连接。它选择应该连接哪个扫描仪。这样做是有道理的,因为这样可以避免大量节点同时发布连接广播,造成广播信道拥塞。此外,它还允许广播商安排新的连接,以免与正在进行的 PAwR 活动相冲突。
  • **低功耗运行,但仍有相对较低的延迟。**扫描仪的功耗与正常蓝牙 LE 连接时的功耗相似。这意味着超低功耗。设备可以使用纽扣电池运行数年,延迟时间等于网络的周期性广播间隔。

2.2 局限

  • 该网络依靠一个广播商作为网关/接入点。这意味着网络中的所有节点都必须在广播商的覆盖范围内。可以通过多个广播商来扩展网络,但规范并没有定义如何建立这样的网络。
  • 吞吐量有限。广播商需要为大量节点提供服务,与普通蓝牙 LE 连接相比,数据吞吐量相对较低,具体取决于广播间隔和响应槽的大小。
  • 每个扫描仪可能没有足够的响应槽。多个扫描仪可以同步到同一个子事件,而子事件中的每个节点往往没有足够的响应槽。应用程序需要定义扫描仪应如何轮流向接入点发送数据。
  • PAwR 的设计将大部分复杂性放在了广播商/接入点一方。广播商必须足够强大,才能同时处理 PAwR 广告、连接处理和节点管理任务。
  • PAwR 只处理堆栈的低端。它没有规定网络的高级功能,如流量控制、数据包确认、加密、身份验证等。上层有责任为应用定制这些功能。

3. 在 nRF Connect SDK 中实现

本节主要介绍如何在 nRF Connect SDK 中实现 PAwR 应用程序。nRF Connect SDK 在 v2.4.0 中添加了两对示例来演示 PAwR。我们将深入代码,了解 PAwR 在这些示例中是如何实现的。

  • 带响应的周期性广播(PAwR) 广播商和同步 (periodic_adv_rsp& periodic_sync_rsp):
    • 广播商会定期发布广播并扫描 PAST 广播商。建立蓝牙 LE 连接后,它将发送 PAST 信息,然后发送子事件信息。
    • 开始时,观察者/扫描器会做广播以获取 PAST 信息。同步后,它将收到子事件信息,从而知道应该监听哪个子事件。
  • 周期性广播连接程序 - 发起方和响应方 (periodic_adv_conn& periodic_sync_conn):
    • 广播商只做周期性广播,不做 PAST。
    • 观察者/扫描器扫描扩展广播数据包并同步。同步后,它会在 PAwR 响应中向广播商发送地址,以便广播商通过 AUX_CONNECT_REQ 建立连接。有关子事件的信息是硬编码。

3.1 广播

让我们仔细看看 periodic_adv_rsp 示例中是如何设置周期性广播的:

pei:

#define NUM_RSP_SLOTS 5
#define NUM_SUBEVENTS 5

static const struct bt_le_per_adv_param per_adv_params = {
    .interval_min = 0xFF,
	.interval_max = 0xFF,
	.options = 0,
	.num_subevents = NUM_SUBEVENTS,
	.subevent_interval = 0x30,
	.response_slot_delay = 0x5,
	.response_slot_spacing = 0x50,
	.num_response_slots = NUM_RSP_SLOTS,
};
struct bt_le_ext_adv *pawr_adv;
static const struct bt_le_ext_adv_cb adv_cb = {
	.pawr_data_request = request_cb,
	.pawr_response = response_cb,
};

配置子事件和响应槽时间参数时需要格外注意。

  • The advertising interval should be ≥ subevent_interval * NUM_SUBEVENTS.
  • The subevent_interval should be ≥ response_slot_delay + response_slot_spacing*NUM_RSP_SLOT

Otherwise you will receive error 12 BT_HCI_ERR_INVALID_PARAM.

Setup and start advertising:

/* Create a non-connectable non-scannable advertising set */
bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN, &adv_cb, &pawr_adv);
/* Set periodic advertising parameters */
bt_le_per_adv_set_param(pawr_adv, &per_adv_params);
/* Enable Periodic Advertising */
bt_le_per_adv_start(pawr_adv);
/* Start Periodic Advertising */
bt_le_ext_adv_start(pawr_adv, BT_LE_EXT_ADV_START_DEFAULT);

After bt_le_ext_adv_start(), the advertiser will do both extended advertising and PAwR. This includes the packets showed at figure 4: ADV_EXT_IND, AUX_ADV_IND, and AUX_SYNC_SUBEVENT_IND.

As mentioned in the last section. An advertiser can choose not to do extended advertising (ADV_EXT_IND & AUX_ADV_IND) and only do periodic advertising. This will help reduce the extra advertising activities on the advertiser so it can serve more connections/responses. To stop extended advertising you call bt_le_ext_adv_stop() after the periodic advertising started. This will not stop the periodic advertising. To stop periodic advertising you need to call bt_le_per_adv_stop().
Note: Most sniffers rely on the extended advertising's Syncinfo to follow the periodic advertising train. If you turn off extended advertising, the sniffer won't be able to find the periodic advertising packets.

There are 2 callbacks for the periodic advertiser:

  • pawr_data_request: called when there is a buffer available for the advertiser to update the content for the subevent data packet. Normally you will receive a callback for each subevent slot to update. In this example, the code simply increase the counter by one on each subevent.
  • pawr_response: called when there is a response from one of the scanner on one of the subevent. In the example the scanner simply echo back what it receives in the subevent packet.

These are the main differences to normal advertising or periodic advertising. You can now control the payload for the exact advertising packet (subevent packet). And you can get response data from a scanner which you can't have with the scan request when you do other types of advertising.

3.2 Synchronization

For synchronizing, either extended advertising or PAST is needed. If you want to do PAST, you would need to scans for normal advertising to establish Bluetooth LE connection then do PAST. You would need to call bt_le_per_adv_set_info_transfer() after the connection is established. This will send the syncinfo and the PAwR info to the scanner.

In the periodic_adv_rsp sample, you can find a write command to send some proprietary data (sync_config) about subevent number and response slot number for the scanner. This is up to the application to decide how this should be done.

The following code is from periorid_adv_rsp. The advertiser stop scanning after the maximum number of synced device reached.

while (num_synced < MAX_SYNCS) {
	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
	if (err) {
		printk("Scanning failed to start (err %d)\n", err);
		return 0;
	}

	printk("Scanning successfully started\n");

	k_sem_take(&sem_connected, K_FOREVER);

	err = bt_le_per_adv_set_info_transfer(pawr_adv, default_conn, 0);
	if (err) {
		printk("Failed to send PAST (err %d)\n", err);

		goto disconnect;
	}

	printk("PAST sent\n");

	discover_params.uuid = &pawr_char_uuid.uuid;
	discover_params.func = discover_func;
	discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
	discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
	discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
	err = bt_gatt_discover(default_conn, &discover_params);
	if (err) {
		printk("Discovery failed (err %d)\n", err);

		goto disconnect;
	}

	printk("Discovery started\n");

	err = k_sem_take(&sem_discovered, K_SECONDS(10));
	if (err) {
		printk("Timed out during GATT discovery\n");

		goto disconnect;
	}

	sync_config.subevent = num_synced % NUM_SUBEVENTS;
	sync_config.response_slot = num_synced / NUM_RSP_SLOTS;
	num_synced++;

	write_params.func = write_func;
	write_params.handle = pawr_attr_handle;
	write_params.offset = 0;
	write_params.data = &sync_config;
	write_params.length = sizeof(sync_config);

	err = bt_gatt_write(default_conn, &write_params);
	if (err) {
		printk("Write failed (err %d)\n", err);
		num_synced--;

		goto disconnect;
	}

	printk("Write started\n");

	err = k_sem_take(&sem_written, K_SECONDS(10));
	if (err) {
		printk("Timed out during GATT write\n");
		num_synced--;

		goto disconnect;
	}

	printk("PAwR config written to sync %d, disconnecting\n", num_synced - 1);

disconnect:
	err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
	if (err) {
		return 0;
	}

	k_sem_take(&sem_disconnected, K_FOREVER);
	}

The advertiser goes straight to disconnect after sending the transfer information. It doesn't know if the scanner has synced to the PAwR train or not. It can be improved by putting a delay before disconnecting or better have a response from the scanner before disconnect. You can find the delay added in the provided code at the end of this guide.

On the scanner's side, if you have a look at perioridc_sync_conn sample you can find how it register PAwR and scans for extended advertising packet that contain sync and PAwr information.

bt_le_scan_cb_register(&scan_callbacks);
bt_le_per_adv_sync_cb_register(&sync_callbacks);

err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
if (err) {
	printk("failed (err %d)\n", err);

return 0;
}

Note that after you have captured the extended advertising packet you would need to create sync object so that the scanner can start following the periodic advertising packet. To create sync object you call bt_le_per_adv_sync_create(). This will allow you to receive the bt_le_per_adv_sync_cb.synced callback when the scanner synced to periodic advertising (not PAwR) :

{
struct bt_le_per_adv_sync_subevent_params params;
uint8_t subevents[1];
char le_addr[BT_ADDR_LE_STR_LEN];
int err;

bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
printk("Synced to %s with %d subevents\n", le_addr, info->num_subevents);

params.properties = 0;
params.num_subevents = 1;
params.subevents = subevents;
subevents[0] = 0;
err = bt_le_per_adv_sync_subevent(sync, &params);
if (err) {
	printk("Failed to set subevents to sync to (err %d)\n", err);
}

k_sem_give(&sem_per_sync);
}

As you may find in the code, after syncing, if you want to receive the PAwR subevent packet, you need to call bt_le_per_adv_sync_subevent() to subscribe to a subevent(s). In this sample the subevent to subscribe to is hardcoded to subevent 0 and the response slot in this subevent is also hardcoded to 0 (see recv_cb function).
The sample sends the device's address to the advertiser and wait for a connection (connection v2 via AUX_CONNECT_REQ) from the advertiser. This is specific to this application. Call bt_le_per_adv_set_response_data() with the subevent and the response slot you want to send data with.

static void recv_cb(struct bt_le_per_adv_sync *sync,
		const struct bt_le_per_adv_sync_recv_info *info, struct net_buf_simple *buf)
{
	int err;
	struct bt_le_oob oob;
	char addr_str[BT_ADDR_LE_STR_LEN];

	if (default_conn) {
		/* Only respond with address if not already connected */
		return;
	}

	if (buf && buf->len) {
		/* Respond with own address for the advertiser to connect to */
		net_buf_simple_reset(&rsp_buf);

		rsp_params.request_event = info->periodic_event_counter;
		rsp_params.request_subevent = info->subevent;
		rsp_params.response_subevent = info->subevent;
		rsp_params.response_slot = 0;

		err = bt_le_oob_get_local(BT_ID_DEFAULT, &oob);
		if (err) {
			printk("Failed to get OOB data (err %d)\n", err);

			return;
		}

		bt_addr_le_to_str(&oob.addr, addr_str, sizeof(addr_str));
		printk("Responding with own addr: %s\n", addr_str);

		net_buf_simple_add_u8(&rsp_buf, sizeof(bt_addr_le_t));
		net_buf_simple_add_u8(&rsp_buf, BT_DATA_LE_BT_DEVICE_ADDRESS);
		net_buf_simple_add_mem(&rsp_buf, &oob.addr.a, sizeof(oob.addr.a));
		net_buf_simple_add_u8(&rsp_buf, oob.addr.type);

		err = bt_le_per_adv_set_response_data(sync, &rsp_params, &rsp_buf);
		if (err) {
			printk("Failed to send response (err %d)\n", err);
		}
	} else if (buf) {
		printk("Received empty indication: subevent %d\n", info->subevent);
	} else {
		printk("Failed to receive indication: subevent %d\n", info->subevent);
	}
}

3.3 Connection v2

A PAwR advertiser can decide to connect to a synced scanner when it needs to communicate with the scanner at higher throughput or lower latency. To do that the advertiser needs to have the scanner device's address and the subevent that the scanner listens to. To establish the connection you need to call bt_conn_le_create_synced():

bt_addr_le_to_str(&peer, addr_str, sizeof(addr_str));
printk("Connecting to %s in subevent %d\n", addr_str, info->subevent);

synced_param.peer = &peer;
synced_param.subevent = info->subevent;

/* Choose same interval as PAwR advertiser to avoid scheduling conflicts */
conn_param.interval_min = SUBEVENT_INTERVAL;
conn_param.interval_max = SUBEVENT_INTERVAL;

/* Default values */
conn_param.latency = 0;
conn_param.timeout = 400;

err = bt_conn_le_create_synced(adv, &synced_param, &conn_param, &default_conn);
if (err) {
	printk("Failed to initiate connection (err %d)", err);
}

There is no concept of scan timeout when you do connection v2, the result of the bt_conn_le_create_synced() command is returned in the next periodic advertising interval in the callback.

Note: It is suggested to choose the connection interval to be equal or multiple of the subevent interval. This would cause less scheduling config resulting in better throughput.

4. Low power consumption demo

Attached is slightly modified version of the periodic_adv_rsp & periodic_sync_rsp samples. The advertiser will scan and establish Bluetooth LE connection to send PAST information and subevent information. The scanner after synced to the advertiser will send data back on each advertising interval.

The main modification is to turn off UART logging on the scanner and adding more meaningful data in the response. The scanner would send back its internal temperature on each response slot. The advertiser is slightly changed to make it more robust with longer advertising interval. The main point of the code is to demonstrate the low power consumption of the scanner (the sensor) with varied periodic advertising intervals.

You can download the demo source code here (tested on nRF Connect SDK v2.5.0): 8562.PAwR_Demo.zip

When running the demo, on the advertiser side you will see the temperature report from each scanner:

Bluetooth PAwR

Unchanged from the periodic_adv_rsp, the advertiser only supports one scanner per subevent. However it should be possible to modify the code to support more scanner per subevent or to increase the number of subevent. You will need to decide the logic on how the scanners in the same subevent should send response back; very often the number of response slot per subevent is smaller than the number of scanner.

Following are some power measurements on the scanner with different periodic advertising interval, varied from 100ms to 1s to 10s. This varies the latency of the scanner. The longer the latency the lower the power consumption.

Bluetooth PAwR

80uA at 100ms intervals, 4 bytes response for each subevent.

Bluetooth PAwR

15uA at 1s interval 4 bytes response each subevent.

Bluetooth PAwR

7.3uA at 10s interval, 4 bytes response each subevent.

One can achieve very low power consumption at 15uA at a relatively low latency of 1s. We can do a rough calculation considering a CR2032 battery with 250mAh capacity. If we can utilize 70% of the capacity for Bluetooth LE, it would last 250mAh * 70% / 15uA = 12500 hours = 520 days

5. Summary

PAwR is an exciting new feature of Bluetooth LE. It enhanced the periodic advertising protocol and may open the door for Bluetooth LE technology in new business verticals. Many applications once not possible or too complex to build are now feasible with Bluetooth LE and PAwR. We are excited to see how it will be implemented and ready to help you get this technology out to the market.

If you are interested in ESL, one of the main applications of PAwR, please continue with the following guide:

订阅Nordic新闻简报

了解最新信息!订阅后即可获取最新Nordic及物联网资讯

立即订阅