首先,简要介绍一下该应用程序。 我们正在开发一种无线传感器,它使用单一特性(硬件限制)通过BLE向客户端UWP应用程序发送数据。消息的大小从20字节到512字节不等。消息由起始字符(start_char),前导码,数据,用于检测错误的CRC和结束字符(end_char)组成。如果这些特殊字符出现在邮件中,则会对其进行转义。
客户端的消息处理包括以下内容:
如果消息大于20个字节,则BLE层会自动将其拆分为多个较小的字节数组,每个数组都会触发一个Characteristics.ValueChanged事件。 解析器由一个AddBytes(byte [] data)方法组成,该方法在收到start_char时会启动一条新消息并存储后续数据,直到收到end_char,然后计算消息的CRC并将其传递。
接收大于20个字节的消息时会出现问题,看起来有些20字节长的数组正在交换。下图显示了512字节的消息,出于调试目的,它被设置为表示三角波(2上升)。我已经标出了数据被破坏的地方。
起初我认为这是一个线程问题,因为每个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(byte b)是MessageBuffer的一种方法,负责转义并添加到新的消息缓冲区。当它获得end_char时,它会通过MessageReceived事件将消息传递给潜在订阅者。
这个实现有什么问题,或者BLE层是否可能在它给我ValueChanged通知之前交换字节数组?这种行为可能有哪些其他可能的来源?
作为旁注,该应用程序也正在为Android和iOS开发,并且在这些平台上都没有这样的问题。
值得一提的另一件事是,在更强大的机器上运行应用程序时,这些错误的频率会降低,而在我的Lumia 640上,我很少收到正确的消息。
答案 0 :(得分:0)
任务是在线程池上运行的协程,因此您可能会或可能不会在多线程上下文中运行,具体取决于处理器能力和设备,但这个问题看起来确实像某种竞争条件。
BLE层是否有可能在它给出ValueChanged通知之前交换字节数组?
除非ValueChanged通知还包含对 new 字节数组的引用,否则必须这样做。在不知道更多的情况下,我猜测在BLE端有一个重用的缓冲区并且它一遍又一遍地读取相同的字节集,并且你只是在用下一组覆盖之前竞争它们。 / p>
尝试将字节缓冲区克隆到一个新的字节数组(.Clone()
使用适用于基本类型数组,它会在AddBytes或你的内部执行“深度”复制,因为字节数组中没有引用在将克隆数组传递给新任务并查看问题是否仍然存在之前,事件处理程序(与BLE层中的读取位于同一线程中)。