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

Adding a way to deinitialize the WiFi stack. #2187

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

playfulFence
Copy link
Contributor

@playfulFence playfulFence commented Sep 18, 2024

Thank you for your contribution!

We appreciate the time and effort you've put into this pull request.
To help us review it efficiently, please ensure you've gone through the following checklist:

Submission Checklist 📝

  • I have updated existing examples or added new ones (if applicable).
  • I have used cargo xtask fmt-packages command to ensure that all changed code is formatted correctly.
  • My changes were added to the CHANGELOG.md in the proper section.
  • I have added necessary changes to user code to the Migration Guide.
  • My changes are in accordance to the esp-rs API guidelines

Extra:

Pull Request Details 📖

closes #1604

Description

⚠️ DRAFT
Problems to be fixed:

  • something is not being freed correctly for NPL BLE chips
  • C2 can be deinitialized while using BLE in coex mode, but not when using BLE alone.
  • User can't create more than 1 socket at this point

However, I decided to do at least a Draft PR to get some feedback or implementation suggestions

Testing

Some short examples (will
BLE:

let deinit = deinitialize_ble(ble).unwrap();
let init = reinitialize(EspWifiFor::Ble, deinit).unwrap();

Wi-Fi:

let deinit = deinitialize_wifi(controller, wifi_stack).unwrap();
let init = reinitialize(EspWifiFor::Wifi, deinit).unwrap();

Coex:

let deinit = deinitialize_all(controller, wifi_stack).unwrap();
let init = reinitialize(EspWifiFor::WifiBle, deinit).unwrap();

@@ -13,6 +13,7 @@ categories = ["embedded", "hardware-support", "no-std"]

[dependencies]
defmt = { version = "0.3.8", optional = true }
bleps = { git = "https://github.com/bjoernQ/bleps", package = "bleps", rev = "a5148d8ae679e021b78f53fd33afb8bb35d0b62e", features = [ "macros", "async"] }
Copy link
Contributor

Choose a reason for hiding this comment

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

that's not good - we won't be able to release esp-wifi with a git dependency - and also users are free to use any BLE stack they want

Copy link
Member

@MabezDev MabezDev left a comment

Choose a reason for hiding this comment

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

Thanks for working on this! I'm excited to see this land!

I see the core functionality is in place (minus the c2 issues) but I think the API surface could do with some polish.

info!("WiFi and BLE coexistence deinitialized");

// Drop the WiFi controller and stack
drop(controller);
Copy link
Member

Choose a reason for hiding this comment

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

No need to call drop manually here.

drop(controller);
drop(stack);
drop(ble);

Copy link
Member

Choose a reason for hiding this comment

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

We also need to stop the timer responsible for task switching (this was @bugadani's main complaint iirc) so for both arch's we need an equivalent setup_timer to tear down the timer.

Copy link
Contributor

Choose a reason for hiding this comment

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

Correct, my stuff was really sensitive to the periodic interruptions caused by the scheduler.

Copy link
Contributor

Choose a reason for hiding this comment

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

Would be probably safer to also unlisten interrupts related to the radio peripherals

))
}

pub fn reinitialize(
Copy link
Member

Choose a reason for hiding this comment

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

Can we drop this function and just use initialize instead?

Copy link
Contributor

Choose a reason for hiding this comment

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

I would pretty much prefer that 👍

@@ -282,7 +282,7 @@ impl<'a, MODE: WifiDeviceMode> WifiStack<'a, MODE> {
/// Create a new [Socket]
#[cfg(feature = "tcp")]
pub fn get_socket<'s>(
&'s self,
&'s mut self,
Copy link
Member

Choose a reason for hiding this comment

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

@bjoernQ I'm not that familiar with the stack, but I think this should stay as &self? That's why we wrap things in refcell internally, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, agree, I've covered it in masked User can't create more than 1 socket at this point item of a TODO list above 😆

Will do something about that

Copy link
Contributor

Choose a reason for hiding this comment

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

Definitely - having only one socket is quite limiting 🤣

common_adapter::RADIO_CLOCKS,
hal::system::{RadioClockController, RadioPeripherals},
};

// use crate::{
Copy link
Member

Choose a reason for hiding this comment

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

Remove these if they're not used

@@ -215,12 +215,21 @@ extern "C" {

pub(crate) fn ble_controller_init(cfg: *const esp_bt_controller_config_t) -> i32;

// #[cfg(not(esp32c2))]
Copy link
Member

Choose a reason for hiding this comment

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

Remove these if they are useless

esp_wifi_result!(unsafe { esp_wifi_stop() })?;
esp_wifi_result!(unsafe { esp_wifi_deinit_internal() })?;

// Deinitialize BLE
Copy link
Member

Choose a reason for hiding this comment

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

We should resuse the deinitialize_ble etc methods here in the deinit all

Copy link
Contributor

Choose a reason for hiding this comment

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

Ideally, we shouldn't care about what network or Bluetooth stack the user is using - e.g. they can use embassy-net instead and they can use Trouble instead of bleps. Users can even directly deal with HCI and use raw smoltcp


bt_periph_module_disable();

// npl::esp_ble_unregister_bb_funcs();
Copy link
Member

Choose a reason for hiding this comment

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

Needed?

let event = event.cast_mut();

if (*event).dummy == 0 {
panic!("Trying to deinitialize an uninitialized event");
Copy link
Member

Choose a reason for hiding this comment

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

This a bit sus, was this just test code or do the blobs really emit empty events?

unsafe {
// HCI deinit
npl::r_ble_hci_trans_cfg_hs(
Some(core::mem::transmute::<
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks sus, these should be None when null, shouldn't they?

Some(core::mem::transmute::<
*const (),
unsafe extern "C" fn(*const u8, *const c_void),
>(core::ptr::null())),
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

unsafe {
// HCI deinit
npl::r_ble_hci_trans_cfg_hs(
Some(core::mem::transmute::<
Copy link
Contributor

Choose a reason for hiding this comment

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

And here

#[non_exhaustive]
/// An internal struct designed to make [`EspWifiDeinitialization`] uncreatable
/// outside of this crate.
pub struct EspWifiDeinitializationInternal;
Copy link
Contributor

Choose a reason for hiding this comment

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

We shouldn't need multiple internal-but-externally-not-constructible types

@@ -290,7 +314,7 @@ impl EspWifiTimerSource for TimeBase {
/// # }
/// ```
pub fn initialize(
init_for: EspWifiInitFor,
init_for: EspWifiFor,
timer: impl EspWifiTimerSource,
rng: hal::rng::Rng,
radio_clocks: hal::peripherals::RADIO_CLK,
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm guessing we'll need to pass peripherals as impl Peripheral and bind their lifetimes in EspWifiInitialization so that they aren't reused before deinited. Then we'd pass EspWifiInitialization to the deinit functions, which may return a different EspWifiInitialization if they only partially deinit, or () if everything was dropped.

#[derive(Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Represents the state of being deinitialized for WiFi, Bluetooth or both.
pub enum EspWifiDeinitialization {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't get why this is needed. Just transform EspWifiInitialization if something changes.

@bjoernQ
Copy link
Contributor

bjoernQ commented Sep 19, 2024

Awesome achievement and a great start!

I'm not a huge fan of renaming EspWifiInitFor since that introduces a lot of noise when reviewing but I see why the original naming doesn't suit things well anymore

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.

Add a way to de-initialize the wifi stack
4 participants