Skip to content
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

Add support for extended advertising via Rust-only API #316

Merged
merged 3 commits into from
Nov 9, 2023

Conversation

whitevegagabriel
Copy link
Collaborator

  • Extended functionality is gated on an "unstable" feature
  • Designed for very simple use and minimal interferance with existing legacy implementation
  • Intended to be temporary, until bumble can integrate extended advertising into its core functionality
  • Added error case for controller's on_hci_le_set_scan_parameters_command (matching the BLE spec) to test error flow from Rust
  • Dropped HciCommandWrapper in favor of using bumble's HCI_Command.from_bytes for converting from PDL into bumble implementation
  • Refactored Address and Device constructors to better match what the python constructors expect

* Extended functionality is gated on an "unstable" feature
* Designed for very simple use and minimal interferance with existing legacy implementation
* Intended to be temporary, until bumble can integrate extended advertising into its core functionality
* Dropped `HciCommandWrapper` in favor of using bumble's `HCI_Command.from_bytes` for converting from PDL into bumble implementation
* Refactored Address and Device constructors to better match what the python constructors expect
println!("Starting extended advertisement...");
device.start_advertising_extended(adv_data).await?;
} else {
device.set_advertising_data(adv_data)?;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does the non-extended advertising need set advertisement data separately?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-extended advertising sets advertisement data separately to mirror the python behavior.

In adding extended advertising, I don't want to interfere with how advertisement_data is used for legacy use cases, so it takes advertisement data as a parameter.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah gotcha, perhaps set_advertising_data should be renamed to set_legacy_advertising_data then?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This raises an interesting question.

set_advertising_data literally sets a new value for the property called advertising_data.

So, is it better to (1) rename it to set_legacy_advertising_data and document that it sets the property called advertising_data, or (2) to call it set_advertising_data and document that it gets used for legacy advertisements?

Since extended advertising is gated as an "unstable" feature, I'm inclined toward (2), but I want to know what you think.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really, both have their merits. 1 is a better API overall, but 2 will cause less cognitive overhead for people switching from using the Python API.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless @barbibulle has some opinion on it, I'm probably going to stick with how it is currently. It may be confusing to some Rust users, but only if you opt-in for the unstable extended API, in which case you are expected to know what you're signing up for.

Plus, when extended is eventually added to bumble core, this API may disappear anyway.

rust/src/wrapper/device/mod.rs Show resolved Hide resolved
rust/src/wrapper/device/mod.rs Show resolved Hide resolved
rust/src/wrapper/device/mod.rs Outdated Show resolved Hide resolved
rust/src/wrapper/device/mod.rs Show resolved Hide resolved
rust/src/wrapper/device/mod.rs Show resolved Hide resolved
rust/src/wrapper/device/mod.rs Show resolved Hide resolved
rust/src/wrapper/device/mod.rs Show resolved Hide resolved
}

// if you change this, don't forget to change the same handle in `stop_advertising_extended`
let advertising_handle = 0x00;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will work temporarily for testing, but for real use cases, we'll need to support multiple advertising sets. For a typical device, you want to have one advertising set for legacy payloads (so that older peer devices can still find you) and one or more extended advertisers. Which does complicate the API somewhat (have to manage advertising instances, deal with running out of advertisers, etc.), which is why there's no official Bumble API for this yet (but working on it). The Android API is a good example for what an API could look like (even though it has its own gaps)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed that we will want to support multiple advertising sets in the future.

Once you've figured out how to support extended advertising in the core API, my plan is to completely drop this and adopt what you've implemented (which is why I've marked these additions as "unstable").

But in the meantime, we can at least use this for testing purposes.

bumble/controller.py Outdated Show resolved Hide resolved
println!("Starting extended advertisement...");
device.start_advertising_extended(adv_data).await?;
} else {
device.set_advertising_data(adv_data)?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really, both have their merits. 1 is a better API overall, but 2 will cause less cognitive overhead for people switching from using the Python API.

rust/Cargo.toml Show resolved Hide resolved
.map(|any| Self(any.into()))
.map(|any| Self {
obj: any.into(),
advertising_status: AdvertisingStatus::NotAdvertising,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if the device is a real dongle and it's actually already advertising?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The device could pretty much be in any state (beyond just advertising/not advertising) until we send HCI_Reset during power_on.

We could (a) prevent some operations if power_on has not been called (b) reset the controller during __init__ to ensure a clean slate (c) leave as-is

I wrote this to match how its written in device.py, though I do think (b) would be better (with some parameter to disable reset if desired).

(a) could be fine, but could result in more invalid states by accident if not careful

(b) would ideally be implemented in device.py since I don't think it makes sense to fix the bug in Rust only, but am curious to hear thoughts from @barbibulle

rust/src/wrapper/device/mod.rs Show resolved Hide resolved
rust/src/wrapper/device/mod.rs Show resolved Hide resolved
rust/src/wrapper/device/mod.rs Show resolved Hide resolved
After adding test for feature combinations, I found a corner case where, when Transport is dropped and the process is terminated in a test, the `close` Python future is not awaited.
I don't know what other situations this issue may arise, so I have safe-guarded it via `block_on` instead of spawning a thread.
@whitevegagabriel
Copy link
Collaborator Author

@barbibulle are there any other changes I should make to this PR to make it ready for merge?

@barbibulle
Copy link
Collaborator

@barbibulle are there any other changes I should make to this PR to make it ready for merge?

Sorry for the delay. Looks good to go. I'll merge it now.

@barbibulle barbibulle merged commit 46d6242 into google:main Nov 9, 2023
51 checks passed
@whitevegagabriel
Copy link
Collaborator Author

Sorry for the delay. Looks good to go. I'll merge it now.

Not a problem, thank you!

@whitevegagabriel whitevegagabriel deleted the extended branch April 5, 2024 15:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants