shinyorg / shiny

.NET Framework for Backgrounding & Device Hardware Services (iOS, Android, & Catalyst)
https://shinylib.net
MIT License
1.45k stars 227 forks source link

[Bug]: NotifyCharacteristic throws BleException "Characteristic notification descriptor not found" #1373

Closed gianisimone closed 9 months ago

gianisimone commented 9 months ago

Component/Nuget

BluetoothLE Client (Shiny.BluetoothLE)

What operating system(s) are effected?

Version(s) of Operation Systems

Android 13

Hosting Model

Steps To Reproduce

  1. Connect to a BLE Device
  2. Get a known characteristic which has no descriptors
  3. Subscribe to Observable returned by Peripheral.NotifyCharacteristic method

Expected Behavior

I expected to see the Next method called properly when notification on that characteristic happens

Actual Behavior

The OnError method of the Observer is called with the error message "Characteristic notification descriptor not found". Looking at the source code that exception is thrown when the notify descriptor is not found on that characteristic. This is fine, however in previous versions the same characteristic is able to receive notification, even if it has no descriptors for notification. Is it possible to have the same behaviour in the new version?

Exception or Log output

Characteristic notification descriptor not found

Code Sample

No response

Code of Conduct

aritchie commented 9 months ago

Android has always looked for a notification characteristic because it is required. This has never been any different.

gianisimone commented 9 months ago

@aritchie thank you for your reply. I can guarantee that with 2.7.2 subscribing to the characteristic which had no descriptor with WhenNotificationReceived actually worked. The OnNext was called perfectly even if the EnableNotifications failed to complete.

aritchie commented 9 months ago

Then send a reproducible case with the issue!

gianisimone commented 9 months ago

@aritchie Yes, sure. This is the code using the v3 of Shiny:

private async Task WhenConnected(IPeripheral P)
{
    var characteristics = await P.GetAllCharacteristicsAsync();
    Command = characteristics.FirstOrDefault(c => c.Uuid == BLECharacteristicCommandUuid);    

    if(Command != null) 
    {
        P.NotifyCharacteristic(Command).ObserveOn(RxApp.MainThreadScheduler).Subscribe(notification =>
        {
            Log($"COMMAND CHANGED {Encoding.UTF8.GetString(notification.Data)}");
        },
        (notifyEx) => Log($"Error while enabling notifications for COMMAND. {notifyEx.Message}"));
    }
}
// peripheral is IPeripheral
whenConnected = peripheral.WhenConnected().Subscribe(conn => _ = WhenConnected(conn));

In this example, when calling NotifyCharacteristic the error handler is called and I am not able to process any notifications in the OnNext handler.

This is the code I have for version 2.7.2

var d = await peripheral.GetAllCharacteristics();
d.FirstOrDefault(_ => _.Uuid.ToGuid() == BT_CHARACTERISTIC_COMMAND_UUID);

if(d != null)
{
    TaskCompletionSource<bool> enableCommandNotificationTask = new TaskCompletionSource<bool>();

    CommandNotifyDisposable = Command.WhenNotificationReceived().Subscribe(g =>
    {
        Log(string.Format("COMMAND CHANGED {0}", Encoding.UTF8.GetString(g.Data)));
    }, 
    err => Log("Error"));

    Command.EnableNotifications(true).Subscribe(encd =>
    {
        Log("Command notifications enabled");
    }, 
    err =>
    {
        Log(string.Format("Error while enabling notifications for command {0}", err.Message));
    });
}

The EnableNotifications calls the error method, however, when a notification is received on the characteristic which has no descriptor, the OnNext is called properly.

If you need more details let me know

aritchie commented 9 months ago

Ok so really this is more of a feature request. You would like the methods NotifyCharacteristic to be EnableNotification with a separate hook method. This is something I can consider for a future release, but honestly, I don't want to support the non-standard cases. I also merged these methods because people don't understand subscribing/unsubscribing/resubscribing post reconnect. It's a support case I don't want again

gianisimone commented 9 months ago

Yes, I would like to be able to process any notification received on the a Characteristic even if it has no descriptor. Is there something I could do to workaround that Exception at the moment?

aritchie commented 9 months ago

Not with the current implementation that I can think of. You can always create your own implementation.