3

Once I am sure I have checked that System.Devices.Aep.Bluetooth.Le.IsConnectable == true I call

DiscoveredBluetoothLEDevice = await BluetoothLEDevice.FromIdAsync(DiscoveredDeviceInformation.Id);

Often this works fine and my app can subscribe to receive updates from the GATT characteristic I am after. But equally often the call to FromIdAsync fails with

Exception thrown: 'System.ArgumentException' in System.Private.CoreLib.dll
Value does not fall within the expected range.

The Id passed in is correct, and I have tried await BluetoothLEDevice.FromBluetoothAddressAsync instead with the known Bluetooth address of the device but I often get the same exception.

What underlying problem is this cryptic error is really referring to?

N.B. Following Xavier Xie's comment below

Have you tried the official code sample to see if you still face this issue?

I have. To recreate the error I place a breakpoint on line 119 in Scenario2_Client.ConnectButton_Click, i.e. the second line in

bluetoothLeDevice = await BluetoothLEDevice.FromIdAsync(rootPage.SelectedBleDeviceId);

if (bluetoothLeDevice == null) 

The first time I run the sample all is good, but if I restart when I hit the breakpoint then (in the second run through) I do not reach the breakpoint because I get the error thrown on the previous line.

dumbledad
  • 16,305
  • 23
  • 120
  • 273
  • Have you tried the [official code sample](https://github.com/Microsoft/Windows-universal-samples/tree/773db9338b5de0b1058097f77ad3ac68dbc0a73d/Samples/BluetoothLE) to see if you still face this issue? – Xie Steven Feb 26 '18 at 08:53
  • It's taken a while to get the sample to show the same error @XavierXie-MSFT but I have it throwing the error now and I have edited the question to show that. – dumbledad Feb 28 '18 at 23:23
  • @XavierXie-MSFT One other (possibly salient) point. It looks like swapping app fixes things. If I force the official code sample into the System.ArgumentException error then running my app fixes things, and if I force my app into the System.ArgumentException error then running the official sample app fixes things. Could the OS be holding a stale connection to an app (even with the app restarting) which swapping app clears? – dumbledad Feb 28 '18 at 23:48
  • 1
    Have you read this [FAQ](https://learn.microsoft.com/en-us/windows/uwp/devices-sensors/bluetooth-dev-faq#why-does-my-bluetooth-le-device-stop-responding-after-a-disconnect)? – Juan Mellado Mar 01 '18 at 14:30
  • Thanks @JuanMellado, I had not seen that entry about the custom pairing. It does not seem to help though. – dumbledad Mar 02 '18 at 13:20
  • 1
    Have you tried wrapping the `bluetoothLeDevice` retrieval in a `using` block? The class implements `IDisposable`, so it might help. – Martin Zikmund Mar 04 '18 at 05:54
  • I poked around a bit in other parts of the web, and found some scattered mentions that suggest this can happen if you try to do what you're doing twice on the same ID, presumably from the same process. I don't know if this applies to your situation in any way, but I thought it was worth mentioning, just in case. – Aiken Drum Mar 07 '18 at 16:04
  • That could be it! Do you have a reference? – dumbledad Mar 07 '18 at 16:26
  • It was sort of a general idea I got across a bunch of pages, but here's someone on SO discussing how it's the error you get in another API if you try to use something twice, and how behavior in the debugger can differ from running straight through: https://stackoverflow.com/questions/35628983/exception-when-supsending-resuming-on-w10m-value-does-not-fall-within-the-expe -- not sure this is a good parallel though. – Aiken Drum Mar 07 '18 at 19:03
  • Given that you're dealing with async stuff, it would certainly explain why it happens sometimes and not others. Race conditions will do that. – Aiken Drum Mar 07 '18 at 19:06
  • I wonder if this fellow had the same problem you have. The accepted answer isn't so clear to me, but maybe it is to you? https://stackoverflow.com/questions/44448895/why-value-does-not-fall-within-the-expected-range-when-setting-value-changed-for – Aiken Drum Mar 07 '18 at 19:15

1 Answers1

1

Are you correctly closing/disposing of the BluetoothLEDevice anywhere?

I'm certain @Martin Zikmund's comment is actually pretty much the the correct answer here.

That is you need to properly dispose of the BluetoothLEDevice object. Sometimes when you restart GC has collected sometimes it hasn't - hence the intermittent error.

To fix either use a using block, as Martin suggests, or manually ensure you have disposed of the BluetoothLEDevice and cleared any reference to it before you exit your application. e.g

using (BluetoothLEDevice btd = BluetoothLEDevice.FromIdAsync(...)) 
{
    // btd will be disposed when out of scope...
}

Or

bluetoothLeDevice.Dispose();
bluetoothLeDevice = null;
// You can also force garbage collection
GC.Collect(); 

What underlying problem is this cryptic error is really referring to?

The error is cryptic but I believe it is saying that the id is invalid (out of range) because it is already in use, that is a reference to the device exists and so you can't connect again.

As an aside you get the same thing with serial ports, etc, if you don't dispose of them properly. If you restart debugging with the same device, settings, etc - maybe GC will have cleaned up and it will work - or maybe it hasn't you'll get an error because the port is in use.

The lesson is to always properly close/dispose streams, ports, devices, files, etc. The best way to do this with objects that implement IDisposable is probably via the "using" statement syntax as you don't have to remember to do anything extra.

Fraser
  • 15,275
  • 8
  • 53
  • 104