-
Notifications
You must be signed in to change notification settings - Fork 25
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
Understanding adapter.c binc_device_set_is_central logic? #87
Comments
Hi, whether a device is bonded or not has nothing to do with it being a central or peripheral. Bonding just refers to the fact whether a shared key has been set. Perhaps in your case it coincidentally matched your needs, but it is not a generic way to deal with roles. Bluez doesn't allow me to detect whether a device is having a central or peripheral role. So I used a heuristic, i.e. I look whether Bluez has service uuids for the device. If it doesn't, it typically will be a central. But this logic is flawed. For example, if a device is having both roles, it doesn't work. That is probably what is causing trouble in your app. Right now, I don't know how to improve this in a generic way. I asked a question about this to the Bluez guys but I never got an answer.... |
Ah, yes. thanks! Bonding is independent of the central/peripheral roles. And now I see the problem with determining which is central. But, in the original binc_internal_device_changed the bonded state is being used--I am confused? May I ask the role of the RSSI in the heuristic? My separate dbus efforts seem to show that RSSI is not available once connected, so binc_device_get_rssi is using a cached value. Are you using it in a different way? You helped me identify a potentially thorny issue as I continue. My adapter is both a client and peripheral, but in the current case only the peripheral side is bonded because the client side is connected to a broadcasting device/beacon--so never bonded. I have been researching the Experimental Simultaneous Central and Peripheral feature in bluez. They must have a way of keeping track. Definitely owe you more than a few coffees. |
I did some research into bluez and there is an interesting bearer_state of "initiator". Not sure this is the Link Layer state needed. I joined the discussion at bluez/bluez#975 which seems to be where others have focused the investigation. |
The Bluez team is usually not very responsive. I think using heuristics is a better shortterm solution. One thing I could do to improve it is adding another bool flag to indicate that the application has initiated the connection. I can set it when you call connect on a device. So when a device connects and this flag isn't set, then it is only a central. Would that help you? |
Yes, the bluez team seems overwhelmed with keeping specific devices working. I took a hard look at the bluez code and was able to define/access a new device property "initiator", the bearer_state initiator flag did not seem to act as I expected. In the short term, I have hard-coded two test centrals--one with a public address and another with random resolvable with fixed name 'iPad'--fortunately I only have one of these within range. Plus neither changes roles with respect to my application.--always centrals. My need is to decide which callback to trigger, and for example stop advertising or stop discovering. What you are proposing sounds quite like the initiator flag at the application level. It certainly sounds better than hard coding. |
Hi. I mention this to potentially save you from going down a rabbit hole for a specialized case, especially if I'm the only one asking for this functionality. In testing using the Garmin watch central and my bluez_inc peripheral, there is enough state logic contained in the adapter.c and device.c to properly detect a remote central device in both the binc_internal_device_changed and binc_internal_device_appeared functions. One must use the isDiscoveryResult logic (which I don't quite understand how it works), and track whether the connection state is a rising or falling edge. I'll need to test more to ensure it functions my multi-role application. If you'd like I can send you the files, but they are still in quite a verbose ugly state. |
Thanks for letting me know. I don't have much time to work on this nowadays. Might try something when I find the time... |
I've been experiencing an odd behavior where two different central/clients (Garmin watch and multiple iOS 17 and 18 apps) happily connect with the bluez part of my RPi BLE binc server. Services and data (r/w/n/i) are working as designed. However, binc is missing the changes in connection state and consequently not triggering the adapter->centralStateCallback(adapter, device). This is messing up the server internal logic as the states of the underlying bluez/central do not match binc states.
I should also note that I am simultaneously running a central/client at the same time, scanning for a nonconnectable beacon, so am continuously scanning with the RPi binc central client as well as having binc server being connected to the remote client.
I've narrowed it down to the logic behind deciding if a device is a central. I think the decision about being a central is determined by bonding state, correct? And aren't connection state and rssi irrelevant in this determination? (My central RSSIs range from -30 (close) to -70 (far), but never -255.)
I provide two snippets here that fix the issues I was experiencing. However, I want to understand the original logic as I may be screwing up some other aspects. Before I submit a PR--because as you know I suck at GitHub.
Please let me know is a PR is warranted. Thank you.
IN ADAPTER.C
In binc_internal_device_appeared()
`
// Device appeared. If bonded previously and has uuids, set it as central regardless of connection state and rssi
// ORIGINAL if (binc_device_get_connection_state(device) == BINC_CONNECTED &&
// ORIGINAL binc_device_get_rssi(device) != -255 &&
if( binc_device_get_bonding_state(device) == BINC_BONDED && // ADDED
binc_device_get_uuids(device) == NULL) {
binc_device_set_is_central(device, TRUE);
if (adapter->centralStateCallback != NULL) {
adapter->centralStateCallback(adapter, device);
}
}
1
In binc_internal_device_changed()
// Catch possible bonding change. If bonded, device is central, rssi irrelevant // ORIGINAL if (binc_device_get_bonding_state(device) == BINC_BONDED && binc_device_get_rssi(device) == -255) { if (binc_device_get_bonding_state(device) == BINC_BONDED ) { // ADDED binc_device_set_is_central(device, TRUE); }
The text was updated successfully, but these errors were encountered: