WriteWithoutResponse WriteRequested event raised out of sequence on Windows.Devices.Bluetooth UWP GattLocalCharacteristic

Viewed 274

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://docs.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.

0 Answers
Related