With a BLE GattLocalService on Windows.Devices.Bluetooth while acting as the Peripheral with a characteristic with only a WriteWithoutResponse property and Plain protection level we are seeing GattLocalCharacteristic event WriteRequested is raised out of order as compared to the bytes being sent. We must only use the WriteWithoutResponse property on the characteristic and cannot use Notify, which seems to work fine. The trouble comes that we are sending around 10K over BLE with an MTU of 20 through this characteristic and need to reassemble them in order once all bytes are received. While many of the functions are asynchronous we can't seem to determine the order in which the bytes were originally sent. When this is setup on either Android or iOS this it works perfectly fine but on the UWP implementation we are notified out of order. Understandably, UWP is using several Async functions - but not being able to reassemble the bytes in the order received is quite problematic.
While researching Microsoft's github examples they only show receiving about 4 bytes on a single characteristic - order here wouldn't really matter. We have looked at using the Offset property on the GattWriteRequest, which appears to always be 0. We have monitored the calls to the GattLocalCharacteristic and determined they are notified out of order.
We've attempted to adapt from Microsoft's example here: https://learn.microsoft.com/en-us/windows/uwp/devices-sensors/gatt-server#write
Our vb.NET adaptation of this prior example:
Private Async Sub InitializePerihperal()
Dim serviceResult As GattServiceProviderResult = Await GattServiceProvider.CreateAsync(New Guid(peripheralServiceUUID))
If serviceResult.Error <> BluetoothError.Success Then
peripheralResponseReceived = True
peripheralResponseError = "GattServiceError"
Exit Sub
End If
serviceProvider = serviceResult.ServiceProvider
Dim characResult As GattLocalCharacteristicResult
Dim propCentralToPeripheral As New GattLocalCharacteristicParameters
propCentralToPeripheral.CharacteristicProperties = GattCharacteristicProperties.WriteWithoutResponse
propCentralToPeripheral.WriteProtectionLevel = GattProtectionLevel.Plain
characResult = Await serviceProvider.Service.CreateCharacteristicAsync(New Guid(CentralToPeripheralUUID), propCentralToPeripheral)
characCentralToPeripheral = characResult.Characteristic
End Sub
Private Async Sub CentralResponseReceived(sender As GattLocalCharacteristic, args As GattWriteRequestedEventArgs) Handles characCentralToPeripheral.WriteRequested
Dim sequence As Int32 = Threading.Interlocked.Increment(PerihperalWriteSequence)
Using requestDeferral As Windows.Foundation.Deferral = args.GetDeferral
Dim request As GattWriteRequest = Await args.GetRequestAsync
Dim requestReader As DataReader = DataReader.FromBuffer(request.Value)
Dim response(CType(requestReader.UnconsumedBufferLength - 1, Int32)) As Byte
requestReader.ReadBytes(response)
'peripheralBlocks is a global ConcurrentDictionary
peripheralBlocks(sequence) = response
requestDeferral.Complete()
End Using
End Sub
We might be missing something, but it seems like either Offset on the response or the function should be called in sequence. Above we have attempted to eliminate issues with GetRequestAsync delays by immediately capturing a call sequence. Maybe we are just missing something on the API - but we can't seem to find anything.