-
Notifications
You must be signed in to change notification settings - Fork 137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
linux & macos: adapter power state handling #188
base: dev
Are you sure you want to change the base?
Conversation
Yay 🎉 Thank you so much for this. Hmm, I am thinking how do we determine the initial adapter state on all platforms? Probably the library should always trigger an initial statechange event (after an Enable) based on whatever information it can get out of the platform. The behaviour will need to belong to the library, as we can't trust the underlying implementations to behave the same. |
On each platform, the Enable function will return an error if the adapter can't be turned on correctly. On macos this occurs after a timeout if the "Powered" signal doesn't arrive. This is the same powered signal used in this PR for the state-change callback. So at least on macos you could set up the callback before calling enable and expect to get the callback firing. On linux the I have no insight into the windows side, so if you are able to get something similar working on that end that would be awesome. Also, I am not sure why tests are failing for some of the bare-metal targets. I need to dig into that as well. |
So far my experience is that Are you getting different behaviour? Maybe it's a different discussion 🤔 |
I can't speak for Windows, but on my M1 Macbook, if I start my application with Bluetooth turned off, calling I have just tested on linux and I do not get an error when calling |
On bare metal, the What actual problem are you trying to solve with this PR? I can think of a few:
For the first, if we know that Bluetooth is starting but not yet finished, I'd argue the proper way to fix it is not by introducing a new API but instead to make sure For the second, an event based system does make sense but I'm not sure this is actually the problem that you're trying to solve? Also, I'm not sure when that would be useful in practice. |
In our case, we are building persistent Bluetooth gateway software that runs on MacOS and Linux to interface with our devices remotely. Think Bluetooth shell, SMP configuration, and OTA. This software needs to be robust and persistent. On MacOS, and MacBooks in particular, having our software maintain functionality after the laptop has been closed and woken up again is critical, without the changes in this PR I wasn't able to find a way to capture the state changes that MacOS puts the Bluetooth adapter through. Less of a typical experience but still important is having the ability to respond to manual enabling and disabling of the adapter and having our software persist through such events. |
I feel like there should be something stronger in this library's interface which allows a user to handle this in a normalized cross-platform way. This issue currently happens with the connect / disconnect handler. We need a few more simple and explicit checks we can make so that we can ignore the underlying platform quirks. Also you don’t always receive these events depending on what happened. So I think we should either:
Or:
We basically need to some way to find out the state (pull), and some way to be told the state (push). One without the other doesn't quite cover the cases. |
Right. I assume these are pre-M1 laptops that fully shut down Bluetooth when suspended? I'm not sure about the newer ones but I think they keep Bluetooth alive when the lid is closed (at least that's what I experienced). This seems like a good argument for adding some way to listen for changes. I hadn't considered suspend before. Also, adding methods to check the current state seems reasonable. Those will probably be very simple. |
// AdapterStateUnknown is the state of the adaptor when it is unknown. | ||
AdapterStateUnknown |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it actually possible for the state to be unknown, and under what circumstances can this happen?
If possible, I'd rather avoid this condition as it's just another special case.
If there are only two states, we can just use a boolean (enabled bool
as a parameter for example).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They vary between OS's.
The MacOS implementation does define an unknown state along with a few others . On the linux side the Powered
state that this PR watches only has on
or off
.
The Unknown
was just an attempt to do 'something' with the extra ones that Core Bluetooth throws at us. I wasn't sure if the other states are merely transient and the adapter will always eventually fall into an on | off
state or if there is a chance the states like CBManagerStateUnsupported
may be a permanent latch.
Actually, I am experiencing this on an M1, 14-inch Macbook Pro. I typically have it on power saving mode so that could be the explanation. |
I have added some simple queries to get the adapter state on macOS and Linux. |
Regarding Windows, it appears we can use https://learn.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothadapter.isperipheralrolesupported?view=winrt-22621 to check if the adaptor is enabled. |
Regarding nrf, we cannot default to the unknown state until We could default to |
Looking at this PR again, I think this would be a helpful feature. |
A simple PR to address some of the issues brought up in #184. In particular, this adds a state change handler to the adapter which calls a provided callback when the powered state changes.
On macos this uses the existing
CentralManagerDidUpdateState
process that is already used to know when the adapter has been correctly enabled. On linux this watches for thePowered
adapter D-Bus property to change.This has been tested on an M1 Macbook Pro and a Raspberry Pi 4.
This PR modifies the existing API by adding
(a *Adapter) SetStateChangeHandler(c func(newState AdapterState))
. I also add some const states to provide generality between platforms, although these are probably unnecessary.Unknowns:
@xeanhort One additional note about #184, while this PR does not directly provide a mechanism to confirm if the adapter is scanning correctly or not. There is an adapter property called
Discovering
that can be watched to hopefully provide this insight. This can be easily integrated into the watching procedure added toadapter_linux.go
in this PR.If we can find a similar signal on the other platforms perhaps we can add it to the state change callback in a future PR.