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

Merged
merged 24 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions esp-wifi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Added `have-strchr` feature to disable including `strchr` (#2096)
- Adding a way to deinitialize the WiFi stack (#2187)
playfulFence marked this conversation as resolved.
Show resolved Hide resolved

### Changed

Expand Down
22 changes: 20 additions & 2 deletions esp-wifi/src/ble/btdm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,15 @@ unsafe extern "C" fn task_create(
1
}

unsafe extern "C" fn task_delete(_task: *const ()) {
todo!();
unsafe extern "C" fn task_delete(task: *const ()) {
trace!("task delete called for {:?}", task);

let task = if task.is_null() {
crate::preempt::current_task()
} else {
task as *mut _
};
crate::preempt::schedule_task_deletion(task);
}

#[ram]
Expand Down Expand Up @@ -514,6 +521,17 @@ pub(crate) fn ble_init() {
}
}

pub(crate) fn ble_deinit() {
extern "C" {
fn btdm_controller_deinit();
}

unsafe {
btdm_controller_deinit();
crate::common_adapter::chip_specific::phy_disable();
}
}

static mut BLE_HCI_READ_DATA: [u8; 256] = [0u8; 256];
static mut BLE_HCI_READ_DATA_INDEX: usize = 0;
static mut BLE_HCI_READ_DATA_LEN: usize = 0;
Expand Down
87 changes: 81 additions & 6 deletions esp-wifi/src/ble/npl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,15 @@ extern "C" {
#[cfg(esp32c2)]
pub(crate) fn ble_controller_init(cfg: *const esp_bt_controller_config_t) -> i32;

#[cfg(not(esp32c2))]
pub(crate) fn r_ble_controller_disable() -> i32;

#[cfg(not(esp32c2))]
pub(crate) fn r_ble_controller_deinit() -> i32;

#[cfg(esp32c2)]
pub(crate) fn ble_controller_deinit() -> i32;

#[cfg(not(esp32c2))]
pub(crate) fn r_ble_controller_init(cfg: *const esp_bt_controller_config_t) -> i32;

Expand All @@ -213,10 +222,14 @@ extern "C" {
#[cfg(not(esp32c2))]
pub(crate) fn r_ble_controller_enable(mode: u8) -> i32;

pub(crate) fn esp_unregister_ext_funcs();

pub(crate) fn esp_register_ext_funcs(funcs: *const ExtFuncsT) -> i32;

pub(crate) fn esp_register_npl_funcs(funcs: *const npl_funcs_t) -> i32;

pub(crate) fn esp_unregister_npl_funcs();

#[cfg(esp32c2)]
pub(crate) fn ble_get_npl_element_info(
cfg: *const esp_bt_controller_config_t,
Expand Down Expand Up @@ -406,8 +419,15 @@ unsafe extern "C" fn task_create(
1
}

unsafe extern "C" fn task_delete(_: *const c_void) {
todo!();
unsafe extern "C" fn task_delete(task: *const c_void) {
trace!("task delete called for {:?}", task);

let task = if task.is_null() {
crate::preempt::current_task()
} else {
task as *mut _
};
crate::preempt::schedule_task_deletion(task);
}

unsafe extern "C" fn osi_assert(ln: u32, fn_name: *const c_void, param1: u32, param2: u32) {
Expand Down Expand Up @@ -795,8 +815,18 @@ unsafe extern "C" fn ble_npl_event_reset(event: *const ble_npl_event) {
}
}

unsafe extern "C" fn ble_npl_event_deinit(_event: *const ble_npl_event) {
todo!()
unsafe extern "C" fn ble_npl_event_deinit(event: *const ble_npl_event) {
trace!("ble_npl_event_deinit {:?}", event);

let event = event.cast_mut();

if (*event).dummy == 0 {
panic!("Trying to deinitialize an uninitialized event");
playfulFence marked this conversation as resolved.
Show resolved Hide resolved
} else {
let idx = ((*event).dummy - 1) as usize;
EVENTS[idx] = None;
(*event).dummy = 0;
}
}

unsafe extern "C" fn ble_npl_event_init(
Expand Down Expand Up @@ -908,8 +938,23 @@ unsafe extern "C" fn ble_npl_eventq_get(
}
}

unsafe extern "C" fn ble_npl_eventq_deinit(_queue: *const ble_npl_eventq) {
todo!()
unsafe extern "C" fn ble_npl_eventq_deinit(queue: *const ble_npl_eventq) {
trace!("ble_npl_eventq_deinit {:?}", queue);

let queue = queue.cast_mut();
if (*queue).dummy == 0 {
panic!("Trying to deinitialize an uninitialized queue");
} else {
critical_section::with(|_| {
while let Some(event_idx) = EVENT_QUEUE.dequeue() {
if let Some(event) = EVENTS[event_idx - 1].as_mut() {
event.queued = false;
}
}
});

(*queue).dummy = 0;
}
}

unsafe extern "C" fn ble_npl_callout_init(
Expand Down Expand Up @@ -1179,6 +1224,36 @@ pub(crate) fn ble_init() {
}
}

pub(crate) fn ble_deinit() {
unsafe {
// HCI deinit
npl::r_ble_hci_trans_cfg_hs(None, core::ptr::null(), None, core::ptr::null());

#[cfg(not(esp32c2))]
npl::r_ble_controller_disable();

#[cfg(not(esp32c2))]
let res = npl::r_ble_controller_deinit();

#[cfg(esp32c2)]
let res = npl::ble_controller_deinit();

if res != 0 {
panic!("ble_controller_deinit returned {}", res);
}

npl::esp_unregister_npl_funcs();

npl::esp_unregister_ext_funcs();

crate::common_adapter::chip_specific::phy_disable();

CALLOUTS.iter_mut().for_each(|item| {
item.take();
});
}
}

#[cfg(esp32c2)]
fn os_msys_buf_alloc() -> bool {
unsafe {
Expand Down
20 changes: 16 additions & 4 deletions esp-wifi/src/ble/os_adapter_esp32s3.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use super::*;
use crate::binary::include::esp_bt_controller_config_t;
use crate::{
binary::include::esp_bt_controller_config_t,
hal::{interrupt, peripherals::Interrupt},
};

pub static mut ISR_INTERRUPT_5: (
*mut crate::binary::c_types::c_void,
Expand Down Expand Up @@ -292,13 +295,22 @@ pub(crate) fn create_ble_config() -> esp_bt_controller_config_t {

pub(crate) unsafe extern "C" fn interrupt_on(intr_num: i32) -> i32 {
trace!("interrupt_on {}", intr_num);
unwrap!(interrupt::enable(
MabezDev marked this conversation as resolved.
Show resolved Hide resolved
Interrupt::try_from(intr_num as u16).unwrap(),
interrupt::Priority::Priority1,
));

// NO-OP
0
}

pub(crate) unsafe extern "C" fn interrupt_off(_intr_num: i32) -> i32 {
todo!();
pub(crate) unsafe extern "C" fn interrupt_off(intr_num: i32) -> i32 {
trace!("interrupt_off {}", intr_num);
interrupt::disable(
crate::hal::Cpu::ProCpu,
Interrupt::try_from(intr_num as u16).unwrap(),
);

0
}

pub(crate) fn btdm_controller_mem_init() {
Expand Down
4 changes: 4 additions & 0 deletions esp-wifi/src/common_adapter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ pub(crate) fn init_radio_clock_control(rcc: hal::peripherals::RADIO_CLK) {
unsafe { RADIO_CLOCKS = Some(rcc) };
}

pub(crate) fn deinit_radio_clock_control() -> Option<hal::peripherals::RADIO_CLK> {
unsafe { RADIO_CLOCKS.take() }
}

/// **************************************************************************
/// Name: esp_semphr_create
///
Expand Down
90 changes: 84 additions & 6 deletions esp-wifi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,12 @@ extern crate alloc;
// MUST be the first module
mod fmt;

use common_adapter::{chip_specific::phy_mem_init, init_radio_clock_control, RADIO_CLOCKS};
use common_adapter::{
chip_specific::phy_mem_init,
deinit_radio_clock_control,
init_radio_clock_control,
RADIO_CLOCKS,
};
use esp_config::*;
use esp_hal as hal;
#[cfg(not(feature = "esp32"))]
Expand All @@ -117,9 +122,18 @@ use hal::{
timer::{timg::Timer as TimgTimer, AnyTimer, PeriodicTimer},
};
#[cfg(feature = "wifi")]
use wifi::WifiError;
use num_traits::FromPrimitive;

use crate::{common_adapter::init_rng, tasks::init_tasks, timer::setup_timer_isr};
#[cfg(feature = "wifi")]
use crate::{
binary::include::{self, esp_supplicant_deinit, esp_wifi_deinit_internal, esp_wifi_stop},
wifi::WifiError,
};
use crate::{
common_adapter::init_rng,
tasks::init_tasks,
timer::{setup_timer_isr, shutdown_timer_isr},
};

mod binary {
pub use esp_wifi_sys::*;
Expand Down Expand Up @@ -396,14 +410,13 @@ pub fn initialize(
}

info!("esp-wifi configuration {:?}", crate::CONFIG);

crate::common_adapter::chip_specific::enable_wifi_power_domain();

phy_mem_init();
init_radio_clock_control(radio_clocks);
init_rng(rng);
init_tasks();
setup_timer_isr(timer.timer())?;

wifi_set_log_verbose();
init_clocks();

Expand Down Expand Up @@ -441,15 +454,80 @@ pub fn initialize(
}
}

/// Deinitializes WiFi and/or BLE
///
/// After user calls this function, WiFi and/or BLE (depending on what has been
/// initialized) are fully stopped and deinitialized. After that, they should
/// not be used until they have been reinitialized with the `init` function.
///
/// The function also disables the corresponding interrupts, deinitializes
/// the timer and radio clock, freeing these resources and returning them.
///
/// Calling this while still using WiFi/BLE will cause crashes or undefined
/// behavior.
///
/// # Safety
/// Actual implementation assumes that the user takes responsibility for how the
/// function is used. For example, after using this function, user should not
/// use BLE or WiFi stack or controller instances (it is possible to
/// reinitialize communication using the `init` function), not to call
/// `deinit_unsafe` before the first initialization, and so on. Also, there is
/// currently no way to track whether a peripheral has been initialized,
/// so deinitialization is done based on the activated feature (`wifi`, `ble`
/// and/or `coex`).
/// Before deinitializing, chips with NPL bluetooth (esp32c2, esp32c6, esp32h2)
Copy link
Contributor

Choose a reason for hiding this comment

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

"Before deinitializing, chips with NPL bluetooth (esp32c2, esp32c6, esp32h2) users must make sure to stop BLE advertising before."

/// users must make sure to stop BLE advertising before.
pub unsafe fn deinit_unchecked(
init: EspWifiInitialization,
) -> Result<(TimeBase, hal::peripherals::RADIO_CLK), InitializationError> {
// Disable coexistence
#[cfg(coex)]
{
unsafe { crate::wifi::os_adapter::coex_disable() };
unsafe { crate::wifi::os_adapter::coex_deinit() };
}

// Deinitialize WiFi
#[cfg(feature = "wifi")]
if init.is_wifi() {
esp_wifi_result!(unsafe { esp_wifi_stop() })?;
esp_wifi_result!(unsafe { esp_wifi_deinit_internal() })?;
esp_wifi_result!(esp_supplicant_deinit())?;
}

// Deinitialize BLE
playfulFence marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(feature = "ble")]
MabezDev marked this conversation as resolved.
Show resolved Hide resolved
if init.is_ble() {
#[cfg(any(esp32, esp32c3, esp32s3))]
crate::ble::btdm::ble_deinit();

#[cfg(any(esp32c2, esp32c6, esp32h2))]
crate::ble::npl::ble_deinit();
}

shutdown_timer_isr().unwrap();
crate::preempt::delete_all_tasks();

let timer = critical_section::with(|cs| crate::timer::TIMER.borrow_ref_mut(cs).take())
.ok_or(InitializationError::TimerUnavailable)?;

let radio_clocks =
deinit_radio_clock_control().ok_or(InitializationError::RadioClockUnavailable)?;

Ok((timer, radio_clocks))
}

#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Error which can be returned during [`initialize`].
/// Error which can be returned during [`init`].
pub enum InitializationError {
General(i32),
#[cfg(feature = "wifi")]
WifiError(WifiError),
WrongClockConfig,
Timer(hal::timer::Error),
TimerUnavailable,
RadioClockUnavailable,
}

impl From<hal::timer::Error> for InitializationError {
Expand Down
Loading