【消息序列】详解(8):探秘物联网中设备广播服务
目录
一、概述
1.1. 定义与特点
1.2. 工作原理
1.3. 应用场景
1.4. 技术优势
二、截断寻呼(Truncated Page)流程
2.1. 截断寻呼的流程
2.2. 示例代码
2.3. 注意事项
三、无连接外围广播过程
3.1. 设备 A 启动无连接外围设备广播
3.2. 示例代码
3.3. 注意事项
四、同步序列(Synchronization Train)特性
4.1. 同步序列启动的流程
4.2. 示例代码
五、广播(Connectionless Peripheral Broadcast)数据包的接收
5.1. 广播接收流程
5.2. 示例代码
六、总结
CONNECTIONLESS PERIPHERAL BROADCAST SERVICES(CPB服务)是蓝牙技术中的一种特殊通信模式,旨在实现一对多的无连接数据广播。该服务允许一台中心设备作为发射器,定期向多台周边设备作为接收器广播数据包,而无需在它们之间建立传统的蓝牙连接。CPB服务通过同步队列和同步扫描机制确保数据的可靠传输,周边设备可以根据接收到的广播数据包进行相应的处理。
一、概述
1.1. 定义与特点
无连接周边广播(Connectionless Peripheral Broadcast,简称CPB)是蓝牙技术中的一种1:n(一台中心设备对多台周边设备)通信模式。在此模式下,一台中心设备作为发射器,向多台作为接收器的周边设备广播数据包,而无需建立传统的蓝牙连接。这种通信方式具有以下特点:
- 单向广播:数据从中心设备向周边设备单向传输,没有数据接收确认机制。
- 无需连接:周边设备无需与中心设备建立连接即可接收广播数据。
- 广播信道:CPB采用的射频信道与低功耗蓝牙中的主广播射频信道一致,即2402MHz、2426MHz和2480MHz。
1.2. 工作原理
- 同步队列:中心设备定期发送包含CPB时序、跳频序列和接入码信息的同步队列。需要同步于CPB的周边设备通过同步扫描即可获取这些信息,从而与中心设备保持同步。
- 广播数据:在同步建立后,中心设备在指定的无连接周边广播时刻,通过CPB逻辑传输通道向周边设备广播数据包。
- 接收数据:周边设备在同步于中心设备的时序和信道上接收广播数据,并进行处理。
1.3. 应用场景
无连接周边广播服务广泛应用于需要一对多通信的场景,如:
- 室内定位:中心设备广播位置信息,周边设备(如智能手机、智能手表等)接收并处理这些信息,实现室内定位功能。
- 信息推送:中心设备向周边设备广播通知、广告等信息,如商场内的促销信息、展览馆的展品信息等。
- 健康监测:在健身房或医院等场所,中心设备广播健康监测数据,周边设备接收并显示这些数据,方便用户随时了解自己的健康状况。
1.4. 技术优势
CPB服务具有高效性、灵活性和可靠性等特点,适用于需要将数据从一台设备广播到多台设备的场景。与低功耗蓝牙(BLE)相比,CPB服务在数据传输速率和传输距离方面可能具有优势,但功耗可能相对较高。因此,在选择使用CPB服务时,需要根据具体应用场景和需求进行权衡。
- 高效性:无连接周边广播服务采用单向广播方式,无需建立连接和进行数据确认,提高了数据传输的效率。
- 灵活性:中心设备可以同时向多台周边设备广播数据,适用于需要一对多通信的场景。
- 低功耗:周边设备在接收广播数据时处于低功耗状态,延长了设备的续航时间。
无连接周边广播服务是蓝牙技术中的一种重要通信模式,具有高效性、灵活性和低功耗等优点。随着物联网和智能设备的不断发展,无连接周边广播服务将在更多领域得到广泛应用。
二、截断寻呼(Truncated Page)流程
截断寻呼流程在蓝牙通信等相关场景中有着重要作用,主要用于设备之间建立连接或者重新连接等操作时,通过一种特定的、相对简化的寻呼方式来提高效率、节省资源等。
2.1. 截断寻呼的流程
在蓝牙通信环境中,截断寻呼是一种用于快速确认设备间存在性和可用性的机制。当设备B想要与设备A建立连接或重新取得联系时,可以选择使用截断寻呼来减少数据交互量并加快响应速度。这种方法在设备电量有限或周围通信环境较复杂的情况下特别有用,因为它能够更高效地建立通信链路。
- 设备B发起截断寻呼:设备B(通过其控制器Controller B)使用截断寻呼方法向设备A发送寻呼请求。设备A通过发送HCI_Write_Scan_Enable命令来启用扫描,以便能够接收来自设备B的寻呼请求。
- 寻呼请求与响应:设备A(通过其控制器Controller A)在接收到page请求后,会通过其控制器Controller A发送一个Page Response作为响应。这个响应表明设备A已经接收到了page请求,并准备进行进一步的通信。
- 截断寻呼完成:当设备B成功接收到设备A的Page Response后,它会给Host上报一个HCI_Truncated_Page_Complete事件来标记截断page过程的完成。这个事件表明设备B已经成功与设备A建立了连接(尽管是临时的,仅用于page),并且不再需要继续发送page请求。
- page超时:如果设备A达到了预定的Scan时间限制(由pagerespTO参数指定),则会发生Page Response超时。此时,设备A(通过其控制器Controller A)会向Host A上报一个HCI_Peripheral_Page_Response_Timeout事件来标记page response超时。
2.2. 示例代码
以下是一个简化的、概念性的代码框架,用于说明如何模拟截断寻呼流程。请注意,这个示例并不包含完整的蓝牙写有栈实现,而是展示了流程中的关键步骤和概念。
#include <stdio.h>
#include <stdlib.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>// 假设的HCI命令发送函数
// 在实际实现中,这个函数会调用蓝牙协议栈提供的API来发送HCI命令
int send_hci_command(uint16_t opcode, uint8_t *param, uint16_t param_len) {// 这里省略了实际的发送逻辑// 返回一个假设的成功值return 0; // 假设命令发送成功
}// 假设的HCI事件处理函数
// 在实际实现中,这个函数会根据接收到的HCI事件类型进行相应处理
void handle_hci_event(uint8_t *event, uint16_t event_len) {// 这里省略了实际的处理逻辑// 仅打印一条消息表示接收到了HCI事件printf("Received HCI event\n");
}// 设备A启用扫描的函数
int enable_scan_on_device_a() {uint8_t param[] = { 0x01, 0x00, 0x00 }; // 假设的参数,启用主动和被动扫描return send_hci_command(HCI_WRITE_SCAN_ENABLE, param, sizeof(param));
}// 设备B发起截断寻呼的函数
int initiate_truncated_page_on_device_b(bdaddr_t *target_address) {// 构造截断寻呼请求的参数(这里省略了详细的参数构造)uint8_t param[18] = { /* ... */ }; // 需要包含目标设备的地址等信息return send_hci_command(/* HCI_TRUNCATED_PAGE 命令操作码 */, param, sizeof(param));
}// 设备A处理寻呼响应的函数(在接收到寻呼请求后由蓝牙协议栈调用)
void device_a_handle_page_response() {// 这里省略了实际的响应处理逻辑// 例如,发送一个确认响应给设备Bprintf("Device A received page request and sent response\n");
}// 设备B处理截断寻呼完成事件的函数
void device_b_handle_truncated_page_complete() {// 这里省略了实际的处理逻辑// 例如,通知上层应用已经成功与设备A建立了临时连接printf("Device B truncated page complete\n");
}// 设备A处理寻呼响应超时的函数
void device_a_handle_page_response_timeout() {// 这里省略了实际的处理逻辑// 例如,通知上层应用寻呼请求超时printf("Device A page response timeout\n");
}int main() {bdaddr_t target_address = { /* ... */ }; // 目标设备A的蓝牙地址// 设备A启用扫描if (enable_scan_on_device_a() != 0) {fprintf(stderr, "Failed to enable scan on device A\n");return EXIT_FAILURE;}// 设备B发起截断寻呼if (initiate_truncated_page_on_device_b(&target_address) != 0) {fprintf(stderr, "Failed to initiate truncated page on device B\n");return EXIT_FAILURE;}// 假设的等待和处理HCI事件循环(在实际实现中,这个循环会不断接收和处理HCI事件)// 注意:这个循环是简化的,并不包含实际的事件接收和处理逻辑while (1) {// 接收HCI事件(在实际实现中,这个调用会阻塞直到接收到一个HCI事件)// uint8_t event[256];// uint16_t event_len;// if (receive_hci_event(event, &event_len) == 0) {// handle_hci_event(event, event_len);// }// 由于这是一个示例,我们仅模拟处理一些事件// 在实际情况下,这些事件处理函数应该由蓝牙协议栈在接收到相应事件时调用device_a_handle_page_response(); // 假设设备A已经处理了寻呼响应device_b_handle_truncated_page_complete(); // 假设设备B已经接收到了截断寻呼完成事件// 注意:在实际情况下,不应该在这里直接调用这些函数,而应该由事件驱动// 退出循环(在实际实现中,这个循环应该一直运行直到程序被显式地终止)break; // 仅用于示例,实际中应该有一个更合适的退出条件}// 注意:在实际实现中,应该有一个机制来处理寻呼响应超时的情况// 例如,如果设备A在预定时间内没有收到设备B的响应,则应该调用device_a_handle_page_response_timeout()return EXIT_SUCCESS;
}
HCI命令和操作码:示例中的HCI命令操作码(如
HCI_WRITE_SCAN_ENABLE
和HCI_TRUNCATED_PAGE
)是假设的,实际的操作码取决于蓝牙规范。参数构造:在
initiate_truncated_page_on_device_b
函数中,需要根据蓝牙协议栈和硬件规范来构造截断寻呼请求的参数。通常包括目标设备的蓝牙地址、寻呼参数等。事件处理:示例中的事件处理函数(如
device_a_handle_page_response
和device_b_handle_truncated_page_complete
)是假设的,实际的处理逻辑取决于应用需求。需要根据接收到的HCI事件类型来调用相应的处理函数。事件循环:示例中的事件循环是简化的,并不包含实际的事件接收和处理逻辑。在实际实现中,需要有一个不断运行的事件循环来接收和处理来自蓝牙协议栈的HCI事件。
超时处理:示例中没有包含寻呼响应超时的处理逻辑。在实际实现中,需要有一个机制来检测和处理寻呼响应超时的情况。
依赖项:示例代码依赖于蓝牙协议栈提供的API。在编译和运行示例代码之前,需要确保已经安装了适当的蓝牙协议栈,并正确配置了编译环境。
错误处理:示例代码中的错误处理是简化的。在实际实现中,需要添加更详细的错误处理逻辑来确保程序的健壮性。
2.3. 注意事项
-
截断寻呼是一种用于在蓝牙设备之间建立临时连接的方法,通常用于设备发现、配对或连接建立过程中的某些阶段。
-
在截断寻呼过程中,设备A和设备B之间不会建立完整的蓝牙连接,而是仅通过page请求和响应来确认彼此的存在和可用性。
-
page超时是截断page过程中的一个重要环节,它用于处理设备B在指定时间内未收到设备A响应的情况。在这种情况下,设备B会停止发送page请求,并可能采取其他措施来尝试与设备A建立连接。
三、无连接外围广播过程
在某些蓝牙应用场景下,设备 A 需要向周围的设备发送广播信息,且采用无连接的方式进行。这种无连接外围设备广播常用于不需要建立专门连接就能向特定范围内的设备传递一些通用信息的情况,比如设备 A 要向周边设备广播自身的状态信息、提供某种公共服务的相关通知等。通过这种广播方式,能方便快捷地将信息扩散出去,而无需事先与每个接收设备都建立一对一的连接,提高信息传播的效率和便捷性,所以设备 A 启动了这一广播流程。
3.1. 设备 A 启动无连接外围设备广播
无连接外围设备广播数据包的流程在蓝牙通信中为设备间无需建立连接即可传递信息提供了有效的途径,对于诸如设备状态通告、公共服务信息分享等应用场景有着重要的实现意义,有助于提升信息传播的便捷性和效率,同时也展现了蓝牙通信在不同通信模式下严谨且规范的操作机制。
-
设置保留的本地地址:在开始无连接外围广播之前,设备A(通过其控制器Controller A)首先使用HCI_Set_Reserved_LT_ADDR命令来设置一个保留的本地临时地址命令(Reserved Local Address,LT_ADDR)。这个地址用于在无连接广播过程中唯一标识设备A。
-
设置无连接外围广播数据:接下来,设备A使用HCI_Set_Connectionless_Peripheral_Broadcast_Data命令来配置要广播的数据。这些数据可能包括设备A的标识符、服务信息或其他相关信息,供设备B在接收到广播时进行处理。
-
启用无连接外围广播:完成数据设置后,设备A通过发送HCI_Set_Connectionless_Peripheral_Broadcast命令来启用无连接外围广播功能。这个命令会指示设备A的控制器Controller A开始发送广播数据包。
-
发送无连接外围广播数据包:一旦无连接外围广播被启用,设备A的控制器Controller A就会开始周期性地发送无连接外围广播数据包。这些数据包包含之前设置的广播数据,并被发送到设备B可以接收的广播频道上。
-
接收广播数据包:设备B(通过其控制器Controller B)在扫描过程中接收到来自设备A的无连接外围广播数据包。设备B可以根据数据包中的信息来识别设备A,并决定是否进一步与设备A建立连接或进行其他操作。
3.2. 示例代码
以下是一个简化的C语言代码示例,用于说明如何实现无连接外围广播的流程。请注意,这只是一个概念性的示例,并不包含完整的蓝牙协议栈实现或错误处理。在实际应用中,需要使用蓝牙协议栈提供的API(如BlueZ、Bluedroid或厂商特定的SDK)来执行这些操作。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 假设这些是蓝牙协议栈提供的API函数(实际使用时需要替换为真实的API)
extern int HCI_Set_Reserved_LT_ADDR(const char* address);
extern int HCI_Set_Connectionless_Peripheral_Broadcast_Data(const unsigned char* data, int length);
extern int HCI_Set_Connectionless_Peripheral_Broadcast(int enable);// 设备A的保留本地地址
#define RESERVED_LT_ADDR "AA:BB:CC:DD:EE:FF"// 要广播的数据
#define BROADCAST_DATA "Hello, Device B!"int main() {// 设置保留的本地地址if (HCI_Set_Reserved_LT_ADDR(RESERVED_LT_ADDR) != 0) {fprintf(stderr, "Failed to set reserved local address.\n");return EXIT_FAILURE;}printf("Reserved local address set successfully.\n");// 设置无连接外围广播数据unsigned char broadcast_data[] = BROADCAST_DATA;int data_length = strlen(BROADCAST_DATA);if (HCI_Set_Connectionless_Peripheral_Broadcast_Data(broadcast_data, data_length) != 0) {fprintf(stderr, "Failed to set connectionless peripheral broadcast data.\n");return EXIT_FAILURE;}printf("Connectionless peripheral broadcast data set successfully.\n");// 启用无连接外围广播if (HCI_Set_Connectionless_Peripheral_Broadcast(1) != 0) {fprintf(stderr, "Failed to enable connectionless peripheral broadcast.\n");return EXIT_FAILURE;}printf("Connectionless peripheral broadcast enabled successfully.\n");// 在这里,设备A会开始周期性地发送广播数据包// ...(实际代码中,这里可能是一个循环,等待用户中断或其他条件来停止广播)// 假设在某个时刻,我们决定停止广播if (HCI_Set_Connectionless_Peripheral_Broadcast(0) != 0) {fprintf(stderr, "Failed to disable connectionless peripheral broadcast.\n");return EXIT_FAILURE;}printf("Connectionless peripheral broadcast disabled successfully.\n");return EXIT_SUCCESS;
}
API函数:
HCI_Set_Reserved_LT_ADDR
、HCI_Set_Connectionless_Peripheral_Broadcast_Data
和HCI_Set_Connectionless_Peripheral_Broadcast
是假设的API函数,用于说明流程。在实际应用中,需要使用蓝牙协议栈提供的真实API。错误处理:示例代码中的错误处理非常基础,仅用于说明。在实际应用中,需要更详细的错误处理逻辑。
广播数据:在示例中,广播数据被硬编码为字符串。在实际应用中,可能需要从其他来源获取这些数据,如配置文件或用户输入。
广播周期:示例代码没有显示设置广播周期。在实际应用中,可能需要配置广播间隔和其他相关参数。
设备B的接收:示例代码仅涉及设备A的广播流程。设备B需要实现相应的扫描逻辑来接收这些广播数据包。
蓝牙栈初始化:在实际应用中,需要在开始之前初始化蓝牙协议栈,并在结束时进行清理。这些步骤在示例代码中未显示。
多线程/异步处理:蓝牙通信通常是异步的。在实际应用中,可能需要使用多线程或异步回调来处理蓝牙事件。
3.3. 注意事项
-
无连接外围广播允许设备在不建立完整连接的情况下发送和接收数据。这对于需要快速广播信息而不需要持续连接的设备来说非常有用。
- 在无连接外围广播过程中,设备A和设备B之间不会建立完整的蓝牙连接。广播数据包是单向发送的,设备B只能接收这些数据包而不能直接回复。
- 设备A可能需要配置一些额外的参数来优化无连接外围广播的性能,如广播间隔、广播频道等。这些参数可以通过相应的HCI命令进行设置。
四、同步序列(Synchronization Train)特性
在一些对时间同步要求较高或者需要按照特定节奏、顺序来传递和接收信息的蓝牙通信应用场景中,同步序列功能就发挥了重要作用。例如,在多设备协同工作且各设备的操作需要精准同步的情况下,或者是进行周期性数据广播且接收方要依据固定时间间隔来准确接收处理数据时,设备 A 作为发送方就需要启动同步序列,以此来建立一种有规律、可同步的信息传输模式,方便设备 B 等接收设备能更好地与它进行协调工作,准确接收广播数据包并进行后续处理。
4.1. 同步序列启动的流程
在无连接的外围设备广播场景中,设备A会周期性地发送广播数据包,而设备B则负责接收这些数据包。同步序列功能增强了这种广播机制,通过发送一系列预定义的、格式化的数据包,使得设备B能够更可靠地接收并处理来自设备A的信息。
-
HCI_Write_Synchronization_Train_Parameters:设备A开始同步序列的广播过程。通常涉及设置一系列参数,如广播间隔、广播数据包的内容等。可以将其理解为是为整个同步序列的运行制定一套详细的 “规则手册”,只有明确了这些参数,后续的同步序列才能按照既定的节奏和要求进行运转,是启动同步序列操作前至关重要的准备工作,确保整个过程有章可循。设备A通过发送
HCI_Write_Synchronization_Train_Parameters
命令来配置这些参数。蓝牙硬件(或控制器A)在接收到参数设置命令后,会返回一个HCI_Command_Complete
事件,表示参数已成功设置。 -
HCI_Start_Synchronization_Train:设备A的主机(Host A)通过控制器A发送
HCI_Start_Synchronization_Train
命令来启动同步序列的广播。控制器A在接收到该命令后,会返回一个HCI_Command_Status
事件,表示命令已接收并正在处理。 -
Synchronization Train packet:一旦同步序列启动,设备A的控制器A会开始周期性地发送同步序列数据包。这些数据包包含设备A的标识符、服务信息或其他相关信息,供设备B在接收到广播时进行处理。它们就像是按照固定车次、固定时间出发的 “列车”,沿着蓝牙通信链路驶向设备 B 等接收设备所在的方向,是实现信息有规律、同步传输的核心载体,也是整个同步序列功能在实际操作中的关键体现,确保接收设备能够依据这种规律来准确接收和处理信息。
-
HCI_Receive_Synchronization_Train:在设备 B 端,Host B会发送 HCI_Receive_Synchronization_Train 命令告知Controller B(设备B的控制器)来接收同步序列数据包。发出该命令后,Controller B会返回 HCI_Command_Status事件信息给Host B,确认设备 B 的接收准备命令已被系统接收并进入正常处理流程,保障设备 B 后续能够顺利开展接收操作,确保整个同步序列的发送与接收环节能够有效衔接起来。
-
HCI_Synchronization_Train_Received:当设备 B 成功接收到设备 A 发送过来的同步序列数据包后,Controller B会向设备 Host B 发送 HCI_Synchronization_Train_Received 事件,告知Host B 它已经接收到了相应的数据包,可以进行后续的处理工作(比如对数据包中的数据进行解析、应用等操作),同时也向整个蓝牙通信系统反馈了接收情况,保障信息传递的准确性和完整性。
-
synchronization_trainTO(超时):在同步序列的运行过程中,如果出现设备A达到了预定的时间限制,就会触发 synchronization_trainTO 机制来表示这种超时现象。Controller A会向设备 Host A 发送 HCI_Synchronization_Train_Complete事件,告知Host A 此次同步序列操作已经全部完成,整个流程顺利结束,意味着设备 A 可以根据此次同步序列的执行情况(如是否成功、有无异常等)来决定后续是否需要再次启动或者调整相关操作,保障整个通信过程的完整性以及对同步序列操作的有效管理。
-
HCI_Synchronization_Train_Complete:当同步序列广播完成(例如,达到了预定的数据包数量或时间限制)时,设备A的控制器A会发送一个
HCI_Synchronization_Train_Complete
事件来通知Host A。标志着同步序列广播过程的结束。
4.2. 示例代码
以下是一个简化的代码示例,用于模拟同步序列启动的流程。请注意,这个示例并不包含实际的蓝牙通信或HCI命令的实现,而是用函数调用来模拟这些过程。在实际应用中,需要使用特定的蓝牙协议栈或API来实现这些功能。
#include <stdio.h>
#include <stdbool.h>// 模拟HCI命令和事件的回调函数类型
typedef void (*HCI_Callback)(const char* event_name, const char* data);// 模拟设备A和设备B的结构体
typedef struct {HCI_Callback callback;
} Device;// 模拟发送HCI命令的函数
void send_hci_command(Device* device, const char* command_name, const char* data, HCI_Callback callback) {printf("Sending HCI command: %s with data: %s\n", command_name, data ? data : "NULL");// 在这里,我们简单地调用回调函数来模拟HCI事件的返回if (callback) {callback(command_name, data);}
}// 模拟HCI命令完成的回调函数
void hci_command_complete_callback(const char* event_name, const char* data) {printf("HCI Command Complete: %s\n", event_name);
}// 模拟同步序列参数设置的函数
void set_synchronization_train_parameters(Device* deviceA) {send_hci_command(deviceA, "HCI_Write_Synchronization_Train_Parameters", "params", hci_command_complete_callback);
}// 模拟启动同步序列的函数
void start_synchronization_train(Device* deviceA) {send_hci_command(deviceA, "HCI_Start_Synchronization_Train", "NULL", NULL); // 这里可能不需要回调,因为启动是异步的// 在实际情况下,可能需要在某个时刻模拟接收到HCI_Command_Status事件printf("HCI Command Status: HCI_Start_Synchronization_Train\n");
}// 模拟接收同步序列数据包的回调函数
void receive_synchronization_train_callback(const char* event_name, const char* data) {printf("HCI Receive Synchronization Train: %s\n", event_name);// 在这里,可能需要处理接收到的数据包
}// 模拟同步序列数据包接收完成的回调函数
void synchronization_train_received_callback(const char* event_name, const char* data) {printf("HCI Synchronization Train Received: %s\n", event_name);// 在这里,可能需要处理接收完成后的逻辑
}// 模拟同步序列超时的回调函数(注意:在实际应用中,超时可能由底层蓝牙协议栈处理)
void synchronization_train_timeout_callback(const char* event_name, const char* data) {printf("Synchronization Train Timeout: %s\n", event_name);// 在这里,可能需要处理超时逻辑
}// 模拟同步序列完成的回调函数
void synchronization_train_complete_callback(const char* event_name, const char* data) {printf("HCI Synchronization Train Complete: %s\n", event_name);// 在这里,可能需要处理同步序列完成后的逻辑
}int main() {// 创建设备A和设备B的实例Device deviceA;Device deviceB;// 设置设备A的回调函数(用于模拟HCI事件的返回)deviceA.callback = synchronization_train_complete_callback;// 设置同步序列参数set_synchronization_train_parameters(&deviceA);// 启动同步序列start_synchronization_train(&deviceA);// 在这里,可能需要模拟设备B接收同步序列数据包的逻辑// 由于这是异步的,我们简单地使用回调函数来模拟接收过程// 注意:在实际应用中,设备B的接收逻辑应该由蓝牙栈或底层驱动处理send_hci_command(&deviceB, "HCI_Receive_Synchronization_Train", "NULL", receive_synchronization_train_callback);// 假设接收成功,触发接收完成事件synchronization_train_received_callback("HCI_Synchronization_Train_Received", "data");// 模拟同步序列完成(这里可能是由设备A的控制器在内部触发的)synchronization_train_complete_callback("HCI_Synchronization_Train_Complete", "NULL");// 注意:超时回调在这个示例中没有显式触发,因为它通常是由底层蓝牙栈在达到时间限制时自动处理的return 0;
}
在这个示例中,我们使用了函数调用来模拟发送HCI命令和接收HCI事件的过程。每个命令或事件都有一个对应的回调函数,用于模拟实际蓝牙通信中可能发生的各种情况。然而,请注意,这个示例并不包含实际的蓝牙通信逻辑,而是用于展示同步序列启动流程的一个概念性框架。在实际应用中,需要使用特定的蓝牙协议栈或API来实现这些功能,并根据蓝牙规范来处理各种命令和事件。
五、广播(Connectionless Peripheral Broadcast)数据包的接收
广播接收机制在蓝牙通信中为设备间实现信息共享、状态感知等应用场景提供了有效的途径,使得设备 B 能够及时获取设备 A 广播的信息,进而依据这些信息开展后续的相关操作,有助于提升蓝牙通信在多设备环境下信息传播和利用的效率。
5.1. 广播接收流程
在蓝牙通信应用场景里,设备 B 出于获取设备 A 广播信息的需求,例如设备 A 会不定期广播自身状态信息、提供的某些服务相关数据等,而设备 B 需要利用这些信息来做进一步决策(如判断是否要与设备 A 建立连接、根据其状态调整自身配置等),所以要启动接收广播数据包的流程,使其自身处于能够监听并接收来自设备 A 广播内容的状态,进而实现信息从设备 A 到设备 B 的传递。
-
Connectionless Peripheral Broadcast packet(设备广播数据包):在设备 B 开始操作前,设备 A 可能已经在按照其广播机制持续发送无连接外围设备广播数据包了。这些数据包承载着设备 A 想要对外广播的各种信息,在链路层面上朝着设备 B 所在方向等广播范围内进行传播,它们是整个广播通信的核心内容载体,虽然此时设备 B 还未完成接收准备,但数据包已经在发送途中,后续设备 B 的操作就是为了能准确捕获并处理这些数据包。
-
HCI_Set_Connectionless_Peripheral_Broadcast_Receive(设置广播接收命令):Host B发送 HCI_Set_Connectionless_Peripheral_Broadcast_Receive 命令配置Controller B 自身的接收功能,使其能够识别并接收来自设备 A 的广播数据包。它相当于为设备 B 的 “接收天线” 进行调谐和设置参数,告诉设备 B 应该去关注哪些类型的广播、按照什么样的规则来接收等,是设备 B 启动接收流程的关键准备步骤,确保其具备接收相应广播数据包的基础能力
-
HCI_Connectionless_Peripheral_Broadcast_Receive(外围设备广播接收状态):随着设备 B 完成接收功能配置,对于每个接收到的广播数据包,设备B都会触发HCI_Connectionless_Peripheral_Broadcast_Receive 事件,它就像是一个实时的 “接收指示灯”,展示着设备 B 的接收情况,确保设备 B 能够不断地捕获广播数据包并进行相应处理,同时也向整个蓝牙通信系统反馈其接收工作的持续进展。
5.2. 示例代码
以下是一个简化的示例代码框架,用于说明如何设置接收无连接外围设备广播数据包。请注意,实际的实现将依赖于特定的蓝牙协议栈和硬件平台,因此以下代码仅作为概念性示例。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>// 假设有一个函数用于发送HCI命令
// 这个函数在实际应用中需要由蓝牙协议栈或硬件接口库提供
int send_hci_command(uint16_t opcode, uint8_t *param, uint8_t param_len) {// 这里省略了实际的发送逻辑// 返回一个假设的成功值return 0; // 成功
}// 假设有一个函数用于处理HCI事件
// 这个函数在实际应用中需要根据具体的事件类型进行处理
void handle_hci_event(uint8_t *event, uint16_t event_len) {// 这里省略了实际的处理逻辑// 例如,检查事件类型并调用相应的处理函数printf("Received HCI event\n");
}// 设置接收无连接外围设备广播数据包的函数
int set_connectionless_peripheral_broadcast_receive() {// 定义HCI_Set_Connectionless_Peripheral_Broadcast_Receive命令的参数// 注意:这里的参数是假设的,实际参数取决于蓝牙协议栈和硬件规范uint8_t param[] = {// 假设的参数,例如启用接收的标志、过滤条件等0x01, // 启用接收// 其他可能的参数...};// 发送HCI_Set_Connectionless_Peripheral_Broadcast_Receive命令int result = send_hci_command(0xXXXX, // 这里需要填入实际的HCI命令操作码param,sizeof(param));if (result != 0) {// 命令发送失败fprintf(stderr, "Failed to send HCI Set Connectionless Peripheral Broadcast Receive command\n");return -1;}// 命令发送成功,等待接收广播数据包的事件// 注意:这里应该有一个事件循环来不断接收和处理HCI事件// 由于这是一个简化的示例,我们仅打印一条消息来表示等待接收printf("Waiting for Connectionless Peripheral Broadcast packets...\n");// 在实际的应用中,这里应该有一个循环来不断调用handle_hci_event来处理接收到的HCI事件// 例如:/*while (1) {uint8_t event[256]; // 假设的事件缓冲区大小uint16_t event_len; // 事件长度// 接收HCI事件(这个函数在实际应用中需要由蓝牙堆栈或硬件接口库提供)// result = receive_hci_event(event, &event_len);// 如果接收成功,则处理事件// if (result == 0) {// handle_hci_event(event, event_len);// }}*/// 由于这是一个示例,我们直接返回成功return 0;
}int main() {// 初始化蓝牙协议栈和硬件(这个步骤在实际应用中需要完成)// 例如:初始化HCI层、打开蓝牙适配器等// 设置接收无连接外围设备广播数据包int result = set_connectionless_peripheral_broadcast_receive();if (result != 0) {// 设置接收失败fprintf(stderr, "Failed to set up connectionless peripheral broadcast receive\n");return EXIT_FAILURE;}// 在实际应用中,这里应该有一个无限循环来保持程序运行并处理接收到的广播数据包// 由于这是一个示例,我们仅打印一条消息并退出printf("Broadcast receive setup complete. Exiting now (this is just an example).\n");return EXIT_SUCCESS;
}
HCI命令和操作码:示例中的
0xXXXX
需要替换为实际的HCI命令操作码。这个操作码取决于蓝牙协议规范。参数:
param
数组中的参数是假设的,实际参数取决于蓝牙规范。事件处理:示例中的
handle_hci_event
函数需要根据实际的事件类型进行处理。这通常涉及解析事件数据包并根据其内容执行相应的操作。事件循环:示例中注释掉的事件循环是实际接收和处理广播数据包所必需的。在实际应用中,应该有一个循环来不断调用
handle_hci_event
来处理接收到的HCI事件。初始化:示例中的初始化步骤(如初始化蓝牙协议栈和硬件)需要在实际应用中完成。这通常涉及调用蓝牙协议栈提供的API来打开蓝牙适配器、初始化HCI层等。
依赖项:示例代码依赖于蓝牙协议栈和硬件接口库提供的函数。这些函数在实际应用中需要由相应的库提供。因此,在编译和运行示例代码之前,需要确保已经安装了适当的蓝牙协议栈和硬件接口库,并正确配置了编译环境。
六、总结
CPB服务是经典蓝牙技术中的一种重要通信模式,通过无连接的数据广播方式实现一对多的数据传输。该服务具有高效、灵活和可靠的特点,适用于需要将数据从中心设备广播到多台周边设备的场景。CPB服务通过同步队列和同步扫描机制确保数据的可靠传输,并在多个领域得到了广泛应用。然而,与BLE相比,CPB服务在功耗方面可能较高,因此在选择使用时需要综合考虑具体应用场景和需求。
相关文章:
【消息序列】详解(8):探秘物联网中设备广播服务
目录 一、概述 1.1. 定义与特点 1.2. 工作原理 1.3. 应用场景 1.4. 技术优势 二、截断寻呼(Truncated Page)流程 2.1. 截断寻呼的流程 2.2. 示例代码 2.3. 注意事项 三、无连接外围广播过程 3.1. 设备 A 启动无连接外围设备广播 3.2. 示例代…...
【RL Base】强化学习核心算法:深度Q网络(DQN)算法
📢本篇文章是博主强化学习(RL)领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅…...
深入浅出 Python 网络爬虫:从零开始构建你的数据采集工具
在大数据时代,网络爬虫作为一种数据采集技术,已经成为开发者和数据分析师不可或缺的工具。Python 凭借其强大的生态和简单易用的语言特点,在爬虫领域大放异彩。本文将带你从零开始,逐步构建一个 Python 网络爬虫,解决实…...
美国发布《联邦风险和授权管理计划 (FedRAMP) 路线图 (2024-2025)》
文章目录 前言一、战略目标实施背景2010年12月,《改革联邦信息技术管理的25点实施计划》2011年2月,《联邦云计算战略》2011年12月,《关于“云计算环境中的信息系统安全授权”的首席信息官备忘录》2022年12月,《FedRAMP 授权法案》…...
Python语法基础(三)
🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 我们这篇文章来说一下函数的返回值和匿名函数 函数的返回值 我们先来看下面的这一段函数的定义代码 # 1、返回值的意义 def func1():print(111111111------start)num166print…...
云计算之elastaicsearch logstach kibana面试题
1.ELK是什么? ELK 其实并不是一款软件,而是一整套解决方案,是三个软件产品的首字母缩写 Elasticsearch:负责日志检索和储存 Logstash:负责日志的收集和分析、处理 Kibana:负责日志的可视化 这三款软件都是开源软件,通常是配合使用,而且又先后归于 Elastic.co 公司名下,…...
【已解决】git push需要输入用户名和密码问题
解决方法: 1)查看使用的clone方式: git remote -v 2)若为HTTPS,删除原clone方式: git remote rm origin 3)添加新的clone方式: git remote add origin gitgithub.com:zludon/git_test.git …...
python的字符串处理
需求: 编写一个程序,输入一段英文句子,统计每个单词的长度,并将单词按照长度从短到长排序。 程序逻辑框图 1、用户输入一句英文句子。 2、对输入的句子进行预处理(去空格并分割为单词列表)。 3、统计每个单…...
【线程】Java多线程代码案例(2)
【线程】Java多线程代码案例(2) 一、定时器的实现1.1Java标准库定时器1.2 定时器的实现 二、线程池的实现2.1 线程池2.2 Java标准库中的线程池2.3 线程池的实现 一、定时器的实现 1.1Java标准库定时器 import java.util.Timer; import java.util.Timer…...
虚拟机之间复制文件
在防火墙关闭的前提下,您可以通过几种不同的方法将文件从一个虚拟机复制到另一个虚拟机。这里,我们假设您想要从 IP 地址为 192.168.4.5 的虚拟机上的 /tmp 文件夹复制文件到当前虚拟机(192.168.4.6)的 /tmp 文件夹下。以下是几种…...
如何为 XFS 文件系统的 /dev/centos/root 增加 800G 空间
如何为 XFS 文件系统的 /dev/centos/root 增加 800G 空间 一、前言二、准备工作三、扩展逻辑卷1. 检查现有 LVM 配置2. 扩展物理卷3. 扩展卷组4. 扩展逻辑卷四、调整文件系统大小1. 检查文件系统状态2. 扩展文件系统五、处理可能出现的问题1. 文件系统无法扩展2. 磁盘空间不足3…...
Java算法OJ(11)双指针练习
目录 1.前言 2.正文 2.1存在重复数字 2.1.1题目 2.1.2解法一代码 解析: 2.1.3解法二代码 解析: 2.2存在重复数字plus 2.2.1题目 2.2.2代码 2.2.3解析 3.小结 1.前言 哈喽大家好吖,今天来给大家分享双指针算法的相关练习&…...
44.扫雷第二部分、放置随机的雷,扫雷,炸死或成功 C语言
按照教程打完了。好几个bug都是自己打出来的。比如统计周围8个格子时,有一个各自加号填成了减号。我还以为平移了,一会显示是0一会显示是2。结果单纯的打错了。debug的时候断点放在scanf后面会顺畅一些。中间多放一些变量名方便监视。以及mine要多显示&a…...
大语言模型LLM的微调代码详解
代码的摘要说明 一、整体功能概述 这段 Python 代码主要实现了基于 Hugging Face Transformers 库对预训练语言模型(具体为 TAIDE-LX-7B-Chat 模型)进行微调(Fine-tuning)的功能,使其能更好地应用于生成唐诗相关内容的…...
钉钉与企业微信机器人:助力网站定时任务高效实现
钉钉、企业微信机器人在网站定时任务中的应用,主要体现在自动化通知、提醒以及数据处理等方面。 以下是一些具体的应用场景: 1. 自动化通知 项目进度提醒:在蒙特网站所负责的软件开发或网站建设项目中,可以利用机器人设置定时任…...
自然语言处理工具-广告配音工具用于语音合成助手/自媒体配音/广告配音/文本朗读-已经解锁了 全功能的 apk包
Android -「安卓端」 广告配音工具用于语音合成助手/自媒体配音/广告配音/文本朗读。 广告配音工具:让您的文字“说话”,在这个快速发展的数字时代,广告配音工具为各种语音合成需求提供了一站式解决方案。无论是自媒体配音、商业广告配音、…...
深入解析注意力机制
引言随着深度学习的快速发展,注意力机制(Attention Mechanism)逐渐成为许多领域的关键技术,尤其是在自然语言处理(NLP)和计算机视觉(CV)中。其核心思想是赋予模型“关注重点”的能力…...
Unity图形学之雾Fog
1.设置雾化: 2.雾化变化曲线:FogMode (1)线性: (2)一次指数: (3)二次指数: Shader "Custom/FogTest" {Properties{_Color ("Color…...
【大数据学习 | Spark-Core】详解Spark的Shuffle阶段
1. shuffle前言 对spark任务划分阶段,遇到宽依赖会断开,所以在stage 与 stage 之间会产生shuffle,大多数Spark作业的性能主要就是消耗在了shuffle环节,因为该环节包含了大量的磁盘IO、序列化、网络数据传输等操作。 负责shuffle…...
如何启动 Docker 服务:全面指南
如何启动 Docker 服务:全面指南 一、Linux 系统(以 Ubuntu 为例)二、Windows 系统(以 Docker Desktop 为例)三、macOS 系统(以 Docker Desktop for Mac 为例)四、故障排查五、总结Docker,作为一种轻量级的虚拟化技术,已经成为开发者和运维人员不可或缺的工具。它允许用…...
使用client-go在命令空间test里面对pod进行操作
目录 一、获取使用restApi调用的token信息 二、client-go操作pod示例 1、获取到客户端 2、创建pod 3、获取test命令空间的所有pod 4、获取某个具体pod的详细信息 5、更新pod 6、删除pod 三、总结 官方参考地址:https://kubernetes.io/docs/reference/kuber…...
Linux中网络文件系统nfs使用
一、nfs服务 NFS(Network File System) 是一种用于在网络中共享文件的协议,允许不同操作系统(如 Linux、Unix、MacOS 等)之间进行文件共享。 NFS 的工作原理基于客户端-服务器模型,服务器提供共享文件系统…...
气膜建筑:打造全天候安全作业空间,提升工程建设效率—轻空间
在现代建筑工程中,施工环境的管理和作业效率是决定项目进度和质量的关键因素。然而,施工过程中常常会受到天气变化的影响,诸如大风、雨雪、沙尘等恶劣天气常常延误工期,增加施工难度。为了解决这一问题,气膜建筑以其独…...
【HarmonyOS学习日志(10)】一次开发,多端部署之功能级一多开发,工程级一多开发
功能级一多开发 SysCap机制介绍 HarmonyOS使用SysCap机制(即SystemCapability),可以帮助开发者仅关注设备的系统能力,而不用考虑成百上千种具体的设备类型。 在过去,开发不同设备上的应用就用不同设备的SDK进行开发&…...
dmdba用户资源限制ulimit -a 部分配置未生效
dmdba用户资源限制ulimit -a 部分配置未生效 1 环境介绍2 数据库实例日志报错2.1 mpp01 实例日志报错2.2 mpp02 实例日志报错 3 mpp02 服务器资源限制情况4 关闭SELinux 问题解决4.1 临时关闭 SELinux4.2 永久关闭 SELinux 5 达梦数据库学习使用列表 1 环境介绍 Cpu x86 Os Ce…...
【Code First】.NET开源 ORM 框架 SqlSugar 系列
.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列 …...
如何在谷歌浏览器中切换DNS服务器
在浏览网页时,DNS(域名系统)服务器的作用是将您输入的网址转换为计算机可以理解的IP地址。有时,您可能需要更改默认的DNS服务器以提升网络速度或解决访问问题。本文将详细介绍如何在谷歌浏览器中切换DNS服务器,并在此过…...
Spring Cloud Stream实现数据流处理
1.什么是Spring Cloud Stream? Spring Cloud Stream的核心是Stream,准确来讲Spring Cloud Stream提供了一整套数据流走向(流向)的API, 它的最终目的是使我们不关心数据的流入和写出,而只关心对数据的业务处…...
列表上移下移功能实现
后台管理某列表需实现上移下移功能,并与前端展示列表排序相关。 现将开发完成过程笔记记录下来。 目录 列表增加属性 JQuery脚本 服务端 控制器 服务层 总结 列表增加属性 在循环渲染时,在table表格的tr上增加id和排序的属性值,以便传…...
升级智享 AI 直播三代:领航原生直播驶向自动化运营新航道
在瞬息万变的数字商业世界,直播行业恰似一艘破浪前行的巨轮,原生直播作为初始 “航船”,在历经风雨后,终于迎来智享 AI 直播三代这股强劲 “东风”,校准航向,开启自动化运营的全新航道,驶向一片…...
简易广州网站建设/外贸建站seo
第四章 进程 1、windows支持两种应用程序:GUI程序和CUI程序,即图形用户界面程序和控制台应用程序。 在Visual Studio中,可以使用项目属性的连接器开关设置选择哪种程序,/SUBSYSTEM:CONSOLE和/SUBSYSTEM:WINDOWS 当运行应用程序时操…...
适合vue做的网站类型/网站排名快速提升
2019独角兽企业重金招聘Python工程师标准>>> 如果你的服务器每天需要处理大量数据,比如每天千万级,那么强烈建议你修改你的代码,可以把单条的insert改成批量的提交 ,update也是同理,这对于数据录入和修改的…...
网站自助建设推广/网店推广方案策划书
基于H5的App在IOS App Store的打包发布流程0、说明1、ios证书配置(1)创建CSR文件(2)申请开发者证书(3)申请推送证书(4)申请provisioning profile2、打包(1)We…...
石家庄计算机培训机构/合肥关键词优化平台
在PHP中,数组函数 array_fill_keys () 用于使用指定的键和值填充数组。 函数语法: array_fill_keys ( array $keys , mixed $value ) : array 函数参数说明: 参数描述keys必需。数组,其值将被用于填充数组的键名。value必需。规…...
网站域名dns/seo服务收费
通达信精选指标——主力潜伏中优化版N:14;M:156;TYP:(HIGHLOWCLOSE)/3;CCI:(TYP-MA(TYP,N))/(0.15*AVEDEV(TYP,N));DIFF:EMA(CLOSE,12)-EMA(CLOSE,26);DEA:EMA(DIFF,9);MACD:2*(DIFF-DEA);主力潜伏中:COUNT(MACD<0,10)10,colorred,LINETHICK0;STICKLINE(主力潜伏中,0,MACD*3…...
电商网站开发主要技术问题/关于友情链接说法正确的是
当我们想要对应用程序的请求或响应进行一些预处理/后处理时,使用截取过滤器设计模式。 在将请求传递到实际目标应用程序之前,在请求上定义和应用过滤器。 过滤器可以进行请求的认证/授权/日志记录或跟踪,然后将请求传递给相应的处理程序。 以…...