问题
First of all, a short introduction to the application. We are developing a wireless sensor that sends data over BLE using a single characteristic (hardware limitation) to a client UWP app. The messages vary in size from under 20 bytes, to 512 bytes. The messages consist of a start character (start_char), preamble, data, CRC for detecting errors and an end character (end_char). If these special characters occur inside the message, they are escaped.
Message processing on the client side consists of the following:
- Listening for the Characteristic.ValueChanged event on the GattCharacteristic.
- Passing the resulting byte array to a parser which builds the message.
- Passing the resulting message to the device object for interpretation.
If the message is larger than 20 bytes, the BLE layer automatically splits it into multiple smaller byte arrays, each of which triggers a Characteristic.ValueChanged event. The parser consists of an AddBytes(byte[] data) method, which starts a new message when it receives a start_char and stores subsequent data until it receives an end_char, then calculates the CRC of the message and passes it on.
The problem occurs when receiving messages larger than 20 bytes and it looks like some of the 20 byte long arrays are getting swapped. The following pictures shows a 512 byte message which, for debugging purposes, was set to represent a triangle wave (2 rises). I've marked out the places where the data gets corrupted.
img1 img2
At first I thought that this was a threading issue, because every Characteristic.ValueChanged event fires on a separate thread (I might be wrong about this one), so I tried using this:
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
}
The goal was to queue the 20 byte long arrays for processing so that I wouldn't start processing a new array before the previous one was done. ProcessByte(byte b) is a method of MessageBuffer and takes care of escaping and adding to the new message buffer. When it gets an end_char, it passes the message to potential subscribers through a MessageReceived event.
Is there anything wrong with this implementation, or is it possible that the BLE layer is swapping the byte arrays before it gives me the ValueChanged notification? What other possible sources for this behavior could there be?
As a side note, the app is being developed for Android and iOS also, and there is no such issue on either those platforms.
Another thing worth mentioning is that the frequency of these errors decreases when running the app on a more powerful machine, while on my Lumia 640 I very rarely get a correct message.
回答1:
A Task is a coroutine run on a threadpool, so you may or may not actually be running in a multithreaded context depending on processor power and device, but this issue definitely seems like a race condition of some kind.
is it possible that the BLE layer is swapping the byte arrays before it gives me the ValueChanged notification?
It kind of has to, unless the ValueChanged notification also includes a reference to a new byte array. Without knowing more, I'm guessing that there's a single reused buffer on the BLE side and it's reading into the same set of bytes over and over, and you're just racing to read them before it overwrites it with the next set.
Try cloning the byte buffer to a new byte array (.Clone()
use is fine for a primitive type array, it'll do a "deep" copy since there are no references inside byte arrays) inside AddBytes or your event handler (whichever is on the same thread as the read from the BLE layer) before passing the cloned array to a new Task and see if the problem persists.
来源:https://stackoverflow.com/questions/37140959/packets-swapped-on-ble-receive