BLE接收交换的数据包
本文关键字:数据包 交换 BLE | 更新日期: 2025-03-17 20:23:21
首先简单介绍一下应用程序。我们正在开发一种无线传感器,该传感器使用单一特性(硬件限制)通过BLE向客户端UWP应用程序发送数据。消息的大小从20字节以下到512字节不等。消息由开始字符(start_char)、前导码、数据、用于检测错误的CRC和结束字符(end_char)组成。如果这些特殊字符出现在消息中,则对其进行转义。
客户端的消息处理包括以下内容:
- 倾听特征。GattCharacteristic上的ValueChanged事件
- 将生成的字节数组传递给构建消息的解析器
- 将生成的消息传递给设备对象以进行解释
如果消息大于20个字节,BLE层会自动将其拆分为多个较小的字节数组,每个数组都会触发Characteristic。ValueChanged事件。解析器由AddBytes(byte[]data)方法组成,该方法在接收到start_char时启动新消息,并存储后续数据,直到接收到end_char,然后计算消息的CRC并将其传递
当接收到大于20字节的消息时,就会出现问题,并且看起来20字节长的数组中的一些正在被交换。以下图片显示了一个512字节的消息,出于调试目的,该消息被设置为表示三角波(2个上升)。我已经标出了数据被破坏的地方。
img1img2
起初我认为这是一个线程问题,因为每个Characteristics。ValueChanged事件在一个单独的线程上触发(我可能错了),所以我尝试使用这个:
public class ScheduledBuffer : MessageBuffer
{
#region Fields / Properties
TaskScheduler scheduler;
TaskFactory taskFactory;
#endregion
#region Methods
#region Constructors
public ScheduledBuffer() : base()
{
scheduler = TaskScheduler.FromCurrentSynchronizationContext();
taskFactory = new TaskFactory(scheduler);
}
#endregion
#region Private Methods
void ProcessByteArray(byte[] buffer)
{
foreach (byte b in buffer)
{
ProcessByte(b);
}
}
#endregion
#region Public Methods
public override void AddBytes(byte[] newData)
{
taskFactory
.StartNew(() => { ProcessByteArray(newData); })
.ContinueWith(t => { });
}
#endregion
#endregion
#region Events
#endregion
#region Commands
#endregion
}
目标是对20字节长的数组进行排队处理,这样我就不会在前一个数组完成之前开始处理新的数组。ProcessByte(字节b)是MessageBuffer的一个方法,负责转义和添加到新的消息缓冲区。当它获得end_char时,它会通过MessageReceived事件将消息传递给潜在的订阅者。
这个实现有什么问题吗?或者BLE层可能在给我ValueChanged通知之前交换了字节数组吗?这种行为还有哪些可能的来源?
顺便说一句,该应用程序也正在为Android和iOS开发,这两个平台都没有这样的问题。
另一件值得一提的事情是,当在功能更强大的机器上运行应用程序时,这些错误的频率会降低,而在我的Lumia 640上,我很少收到正确的消息。
Task是在线程池上运行的协同程序,因此根据处理器功率和设备的不同,您可能会也可能不会在多线程上下文中运行,但这个问题看起来肯定是某种竞争条件。
BLE层在给我ValueChanged通知之前是否可能正在交换字节数组?
它必须这样做,除非ValueChanged通知还包括对新字节数组的引用。在不了解更多信息的情况下,我猜BLE端有一个可重复使用的缓冲区,它正在一遍又一遍地读取同一组字节,而你只是在它用下一组覆盖它之前争着读取它们。
尝试将字节缓冲区克隆到AddBytes或事件处理程序(与从BLE层读取的字节在同一线程上)内的一个新字节数组(.Clone()
对于基元类型的数组来说是可以使用的,它会进行"深度"复制,因为字节数组内没有引用),然后将克隆的数组传递给新的Task,看看问题是否仍然存在。