Replace some esp-wifi critical sections with locks (#2554)

* Replace some esp-wifi critical sections with locks

* Remove critical section from event handlers

* Fix doc warnings and accidentally hard-coded esp32s3

* Use Lock in wifi_int_disable/restore

* Replace critical_section in ConcurrentQueue

* Deduplicate wifi_int_disable
This commit is contained in:
Dániel Buga 2024-11-25 18:06:05 +01:00 committed by GitHub
parent aed0fac0eb
commit eec75c8f82
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 195 additions and 475 deletions

View File

@ -12,6 +12,7 @@ use esp_wifi_sys::include::malloc;
use super::malloc::free; use super::malloc::free;
use crate::{ use crate::{
binary::c_types::{c_int, c_void}, binary::c_types::{c_int, c_void},
hal::sync::Locked,
memory_fence::memory_fence, memory_fence::memory_fence,
preempt::current_task, preempt::current_task,
timer::yield_task, timer::yield_task,
@ -27,36 +28,34 @@ struct Mutex {
} }
pub(crate) struct ConcurrentQueue { pub(crate) struct ConcurrentQueue {
raw_queue: critical_section::Mutex<RefCell<RawQueue>>, raw_queue: Locked<RawQueue>,
} }
impl ConcurrentQueue { impl ConcurrentQueue {
pub(crate) fn new(count: usize, item_size: usize) -> Self { pub(crate) fn new(count: usize, item_size: usize) -> Self {
Self { Self {
raw_queue: critical_section::Mutex::new(RefCell::new(RawQueue::new(count, item_size))), raw_queue: Locked::new(RawQueue::new(count, item_size)),
} }
} }
fn release_storage(&mut self) { fn release_storage(&mut self) {
critical_section::with(|cs| unsafe { self.raw_queue.with(|q| unsafe { q.release_storage() })
self.raw_queue.borrow_ref_mut(cs).release_storage();
})
} }
pub(crate) fn enqueue(&mut self, item: *mut c_void) -> i32 { pub(crate) fn enqueue(&mut self, item: *mut c_void) -> i32 {
critical_section::with(|cs| unsafe { self.raw_queue.borrow_ref_mut(cs).enqueue(item) }) self.raw_queue.with(|q| unsafe { q.enqueue(item) })
} }
pub(crate) fn try_dequeue(&mut self, item: *mut c_void) -> bool { pub(crate) fn try_dequeue(&mut self, item: *mut c_void) -> bool {
critical_section::with(|cs| unsafe { self.raw_queue.borrow_ref_mut(cs).try_dequeue(item) }) self.raw_queue.with(|q| unsafe { q.try_dequeue(item) })
} }
pub(crate) fn remove(&mut self, item: *mut c_void) { pub(crate) fn remove(&mut self, item: *mut c_void) {
critical_section::with(|cs| unsafe { self.raw_queue.borrow_ref_mut(cs).remove(item) }); self.raw_queue.with(|q| unsafe { q.remove(item) })
} }
pub(crate) fn count(&self) -> usize { pub(crate) fn count(&self) -> usize {
critical_section::with(|cs| unsafe { self.raw_queue.borrow_ref(cs).count() }) self.raw_queue.with(|q| unsafe { q.count() })
} }
} }

View File

@ -1,7 +1,6 @@
use alloc::boxed::Box; use alloc::boxed::Box;
use core::cell::RefCell;
use critical_section::Mutex; use esp_hal::sync::Locked;
use crate::binary::{ use crate::binary::{
c_types, c_types,
@ -138,7 +137,7 @@ impl TimerQueue {
unsafe impl Send for TimerQueue {} unsafe impl Send for TimerQueue {}
pub(crate) static TIMERS: Mutex<RefCell<TimerQueue>> = Mutex::new(RefCell::new(TimerQueue::new())); pub(crate) static TIMERS: Locked<TimerQueue> = Locked::new(TimerQueue::new());
pub(crate) fn compat_timer_arm(ets_timer: *mut ets_timer, tmout: u32, repeat: bool) { pub(crate) fn compat_timer_arm(ets_timer: *mut ets_timer, tmout: u32, repeat: bool) {
compat_timer_arm_us(ets_timer, tmout * 1000, repeat); compat_timer_arm_us(ets_timer, tmout * 1000, repeat);
@ -156,8 +155,8 @@ pub(crate) fn compat_timer_arm_us(ets_timer: *mut ets_timer, us: u32, repeat: bo
repeat repeat
); );
critical_section::with(|cs| { TIMERS.with(|timers| {
if let Some(timer) = TIMERS.borrow_ref_mut(cs).find(ets_timer) { if let Some(timer) = timers.find(ets_timer) {
timer.started = systick; timer.started = systick;
timer.timeout = ticks; timer.timeout = ticks;
timer.active = true; timer.active = true;
@ -170,8 +169,8 @@ pub(crate) fn compat_timer_arm_us(ets_timer: *mut ets_timer, us: u32, repeat: bo
pub fn compat_timer_disarm(ets_timer: *mut ets_timer) { pub fn compat_timer_disarm(ets_timer: *mut ets_timer) {
trace!("timer disarm"); trace!("timer disarm");
critical_section::with(|cs| { TIMERS.with(|timers| {
if let Some(timer) = TIMERS.borrow_ref_mut(cs).find(ets_timer) { if let Some(timer) = timers.find(ets_timer) {
trace!("timer_disarm {:x}", timer.id()); trace!("timer_disarm {:x}", timer.id());
timer.active = false; timer.active = false;
} else { } else {
@ -182,8 +181,7 @@ pub fn compat_timer_disarm(ets_timer: *mut ets_timer) {
pub fn compat_timer_done(ets_timer: *mut ets_timer) { pub fn compat_timer_done(ets_timer: *mut ets_timer) {
trace!("timer done"); trace!("timer done");
critical_section::with(|cs| { TIMERS.with(|timers| {
let mut timers = TIMERS.borrow_ref_mut(cs);
if let Some(timer) = timers.find(ets_timer) { if let Some(timer) = timers.find(ets_timer) {
trace!("timer_done {:x}", timer.id()); trace!("timer_done {:x}", timer.id());
timer.active = false; timer.active = false;
@ -211,8 +209,7 @@ pub(crate) fn compat_timer_setfn(
pfunction, pfunction,
parg parg
); );
let set = critical_section::with(|cs| unsafe { let set = TIMERS.with(|timers| unsafe {
let mut timers = TIMERS.borrow_ref_mut(cs);
if let Some(timer) = timers.find(ets_timer) { if let Some(timer) = timers.find(ets_timer) {
timer.callback = TimerCallback::new(pfunction, parg); timer.callback = TimerCallback::new(pfunction, parg);
timer.active = false; timer.active = false;

View File

@ -22,16 +22,15 @@
//! ```toml //! ```toml
//! [dependencies.esp-wifi] //! [dependencies.esp-wifi]
//! # A supported chip needs to be specified, as well as specific use-case features //! # A supported chip needs to be specified, as well as specific use-case features
//! features = ["esp32s3", "wifi", "esp-now"] #![doc = concat!(r#"features = [""#, esp_hal::chip!(), r#"", "wifi", "esp-now"]"#)]
//! ``` //! ```
//! //!
//! ### Optimization Level //! ### Optimization Level
//! //!
//! It is necessary to build with optimization level 2 or 3 since otherwise, it //! It is necessary to build with optimization level 2 or 3 since otherwise, it
//! might not even be able to connect or advertise. //! might not even be able to connect or advertise.
//! //!
//! To make it work also for your debug builds add this to your `Cargo.toml` //! To make it work also for your debug builds add this to your `Cargo.toml`
//!
//! ```toml //! ```toml
//! [profile.dev.package.esp-wifi] //! [profile.dev.package.esp-wifi]
//! opt-level = 3 //! opt-level = 3
@ -419,7 +418,7 @@ pub unsafe fn deinit_unchecked() -> Result<(), InitializationError> {
shutdown_timer_isr(); shutdown_timer_isr();
crate::preempt::delete_all_tasks(); crate::preempt::delete_all_tasks();
critical_section::with(|cs| crate::timer::TIMER.borrow_ref_mut(cs).take()); crate::timer::TIMER.with(|timer| timer.take());
crate::flags::ESP_WIFI_INITIALIZED.store(false, Ordering::Release); crate::flags::ESP_WIFI_INITIALIZED.store(false, Ordering::Release);

View File

@ -2,10 +2,10 @@
#[cfg_attr(target_arch = "xtensa", path = "preempt_xtensa.rs")] #[cfg_attr(target_arch = "xtensa", path = "preempt_xtensa.rs")]
pub mod arch_specific; pub mod arch_specific;
use core::{cell::RefCell, mem::size_of}; use core::mem::size_of;
use arch_specific::*; use arch_specific::*;
use critical_section::Mutex; use esp_hal::sync::Locked;
use esp_wifi_sys::include::malloc; use esp_wifi_sys::include::malloc;
use crate::{compat::malloc::free, hal::trapframe::TrapFrame, memory_fence::memory_fence}; use crate::{compat::malloc::free, hal::trapframe::TrapFrame, memory_fence::memory_fence};
@ -15,14 +15,12 @@ struct ContextWrapper(*mut Context);
unsafe impl Send for ContextWrapper {} unsafe impl Send for ContextWrapper {}
static CTX_NOW: Mutex<RefCell<ContextWrapper>> = static CTX_NOW: Locked<ContextWrapper> = Locked::new(ContextWrapper(core::ptr::null_mut()));
Mutex::new(RefCell::new(ContextWrapper(core::ptr::null_mut())));
static mut SCHEDULED_TASK_TO_DELETE: *mut Context = core::ptr::null_mut(); static mut SCHEDULED_TASK_TO_DELETE: *mut Context = core::ptr::null_mut();
pub(crate) fn allocate_main_task() -> *mut Context { pub(crate) fn allocate_main_task() -> *mut Context {
critical_section::with(|cs| unsafe { CTX_NOW.with(|ctx_now| unsafe {
let mut ctx_now = CTX_NOW.borrow_ref_mut(cs);
if !ctx_now.0.is_null() { if !ctx_now.0.is_null() {
panic!("Tried to allocate main task multiple times"); panic!("Tried to allocate main task multiple times");
} }
@ -36,8 +34,7 @@ pub(crate) fn allocate_main_task() -> *mut Context {
} }
fn allocate_task() -> *mut Context { fn allocate_task() -> *mut Context {
critical_section::with(|cs| unsafe { CTX_NOW.with(|ctx_now| unsafe {
let mut ctx_now = CTX_NOW.borrow_ref_mut(cs);
if ctx_now.0.is_null() { if ctx_now.0.is_null() {
panic!("Called `allocate_task` before allocating main task"); panic!("Called `allocate_task` before allocating main task");
} }
@ -51,8 +48,7 @@ fn allocate_task() -> *mut Context {
} }
fn next_task() { fn next_task() {
critical_section::with(|cs| unsafe { CTX_NOW.with(|ctx_now| unsafe {
let mut ctx_now = CTX_NOW.borrow_ref_mut(cs);
ctx_now.0 = (*ctx_now.0).next; ctx_now.0 = (*ctx_now.0).next;
}); });
} }
@ -61,8 +57,8 @@ fn next_task() {
/// ///
/// This will also free the memory (stack and context) allocated for it. /// This will also free the memory (stack and context) allocated for it.
pub(crate) fn delete_task(task: *mut Context) { pub(crate) fn delete_task(task: *mut Context) {
critical_section::with(|cs| unsafe { CTX_NOW.with(|ctx_now| unsafe {
let mut ptr = CTX_NOW.borrow_ref_mut(cs).0; let mut ptr = ctx_now.0;
let initial = ptr; let initial = ptr;
loop { loop {
if (*ptr).next == task { if (*ptr).next == task {
@ -85,9 +81,8 @@ pub(crate) fn delete_task(task: *mut Context) {
} }
pub(crate) fn delete_all_tasks() { pub(crate) fn delete_all_tasks() {
critical_section::with(|cs| unsafe { CTX_NOW.with(|ctx_now| unsafe {
let mut ctx_now_ref = CTX_NOW.borrow_ref_mut(cs); let current_task = ctx_now.0;
let current_task = ctx_now_ref.0;
if current_task.is_null() { if current_task.is_null() {
return; return;
@ -108,14 +103,14 @@ pub(crate) fn delete_all_tasks() {
task_to_delete = next_task; task_to_delete = next_task;
} }
ctx_now_ref.0 = core::ptr::null_mut(); ctx_now.0 = core::ptr::null_mut();
memory_fence(); memory_fence();
}); });
} }
pub(crate) fn current_task() -> *mut Context { pub(crate) fn current_task() -> *mut Context {
critical_section::with(|cs| CTX_NOW.borrow_ref(cs).0) CTX_NOW.with(|ctx_now| ctx_now.0)
} }
pub(crate) fn schedule_task_deletion(task: *mut Context) { pub(crate) fn schedule_task_deletion(task: *mut Context) {

View File

@ -18,21 +18,16 @@ pub(crate) fn init_tasks() {
pub(crate) extern "C" fn timer_task(_param: *mut esp_wifi_sys::c_types::c_void) { pub(crate) extern "C" fn timer_task(_param: *mut esp_wifi_sys::c_types::c_void) {
loop { loop {
let current_timestamp = systimer_count(); let current_timestamp = systimer_count();
let to_run = critical_section::with(|cs| unsafe { let to_run = TIMERS.with(|timers| {
let mut timers = TIMERS.borrow_ref_mut(cs); let to_run = unsafe { timers.find_next_due(current_timestamp) }?;
let to_run = timers.find_next_due(current_timestamp);
if let Some(to_run) = to_run { to_run.active = to_run.periodic;
to_run.active = to_run.periodic;
if to_run.periodic { if to_run.periodic {
to_run.started = current_timestamp; to_run.started = current_timestamp;
}
Some(to_run.callback)
} else {
None
} }
Some(to_run.callback)
}); });
// run the due timer callback NOT in an interrupt free context // run the due timer callback NOT in an interrupt free context

View File

@ -1,6 +1,4 @@
use core::cell::RefCell; use esp_hal::sync::Locked;
use critical_section::Mutex;
#[cfg_attr(esp32, path = "timer_esp32.rs")] #[cfg_attr(esp32, path = "timer_esp32.rs")]
#[cfg_attr(esp32c2, path = "timer_esp32c2.rs")] #[cfg_attr(esp32c2, path = "timer_esp32c2.rs")]
@ -20,7 +18,7 @@ pub(crate) use chip_specific::*;
use crate::TimeBase; use crate::TimeBase;
pub(crate) static TIMER: Mutex<RefCell<Option<TimeBase>>> = Mutex::new(RefCell::new(None)); pub(crate) static TIMER: Locked<Option<TimeBase>> = Locked::new(None);
pub(crate) fn setup_timer_isr(timebase: TimeBase) { pub(crate) fn setup_timer_isr(timebase: TimeBase) {
setup_radio_isr(); setup_radio_isr();

View File

@ -30,16 +30,17 @@ pub(crate) fn setup_timer(mut alarm0: TimeBase) {
let cb: extern "C" fn() = unsafe { core::mem::transmute(handler as *const ()) }; let cb: extern "C" fn() = unsafe { core::mem::transmute(handler as *const ()) };
alarm0.set_interrupt_handler(InterruptHandler::new(cb, interrupt::Priority::Priority1)); alarm0.set_interrupt_handler(InterruptHandler::new(cb, interrupt::Priority::Priority1));
unwrap!(alarm0.start(TIMESLICE_FREQUENCY.into_duration())); unwrap!(alarm0.start(TIMESLICE_FREQUENCY.into_duration()));
critical_section::with(|cs| { TIMER.with(|timer| {
alarm0.enable_interrupt(true); alarm0.enable_interrupt(true);
TIMER.borrow_ref_mut(cs).replace(alarm0); timer.replace(alarm0);
}); });
} }
pub(crate) fn disable_timer() { pub(crate) fn disable_timer() {
critical_section::with(|cs| { TIMER.with(|timer| {
unwrap!(TIMER.borrow_ref_mut(cs).as_mut()).enable_interrupt(false); let timer = unwrap!(timer.as_mut());
unwrap!(unwrap!(TIMER.borrow_ref_mut(cs).as_mut()).cancel()); timer.enable_interrupt(false);
unwrap!(timer.cancel());
}); });
} }
@ -60,8 +61,8 @@ pub(crate) fn disable_multitasking() {
extern "C" fn handler(trap_frame: &mut TrapFrame) { extern "C" fn handler(trap_frame: &mut TrapFrame) {
// clear the systimer intr // clear the systimer intr
critical_section::with(|cs| { TIMER.with(|timer| {
unwrap!(TIMER.borrow_ref_mut(cs).as_mut()).clear_interrupt(); unwrap!(timer.as_mut()).clear_interrupt();
}); });
task_switch(trap_frame); task_switch(trap_frame);
@ -76,8 +77,7 @@ extern "C" fn FROM_CPU_INTR3(trap_frame: &mut TrapFrame) {
.modify(|_, w| w.cpu_intr_from_cpu_3().clear_bit()); .modify(|_, w| w.cpu_intr_from_cpu_3().clear_bit());
} }
critical_section::with(|cs| { TIMER.with(|alarm0| {
let mut alarm0 = TIMER.borrow_ref_mut(cs);
let alarm0 = unwrap!(alarm0.as_mut()); let alarm0 = unwrap!(alarm0.as_mut());
alarm0.clear_interrupt(); alarm0.clear_interrupt();
}); });

View File

@ -27,16 +27,17 @@ pub(crate) fn setup_timer(mut timer1: TimeBase) {
interrupt::Priority::Priority2, interrupt::Priority::Priority2,
)); ));
unwrap!(timer1.start(TIMESLICE_FREQUENCY.into_duration())); unwrap!(timer1.start(TIMESLICE_FREQUENCY.into_duration()));
critical_section::with(|cs| { TIMER.with(|timer| {
timer1.enable_interrupt(true); timer1.enable_interrupt(true);
TIMER.borrow_ref_mut(cs).replace(timer1); timer.replace(timer1);
}); });
} }
pub(crate) fn disable_timer() { pub(crate) fn disable_timer() {
critical_section::with(|cs| { TIMER.with(|timer| {
unwrap!(TIMER.borrow_ref_mut(cs).as_mut()).enable_interrupt(false); let timer = unwrap!(timer.as_mut());
unwrap!(unwrap!(TIMER.borrow_ref_mut(cs).as_mut()).cancel()); timer.enable_interrupt(false);
unwrap!(timer.cancel());
}); });
} }
@ -58,8 +59,7 @@ pub(crate) fn disable_multitasking() {
} }
fn do_task_switch(context: &mut TrapFrame) { fn do_task_switch(context: &mut TrapFrame) {
critical_section::with(|cs| { TIMER.with(|timer| {
let mut timer = TIMER.borrow_ref_mut(cs);
let timer = unwrap!(timer.as_mut()); let timer = unwrap!(timer.as_mut());
timer.clear_interrupt(); timer.clear_interrupt();
}); });

View File

@ -1,7 +1,6 @@
use alloc::boxed::Box; use alloc::boxed::Box;
use core::cell::RefCell;
use critical_section::Mutex; use esp_hal::sync::Locked;
use super::WifiEvent; use super::WifiEvent;
@ -10,17 +9,17 @@ pub(crate) mod sealed {
pub trait Event { pub trait Event {
/// Get the static reference to the handler for this event. /// Get the static reference to the handler for this event.
fn handler() -> &'static Mutex<RefCell<Option<Box<Handler<Self>>>>>; fn handler() -> &'static Locked<Option<Box<Handler<Self>>>>;
/// # Safety /// # Safety
/// `ptr` must be a valid for casting to this event's inner event data. /// `ptr` must be a valid for casting to this event's inner event data.
unsafe fn from_raw_event_data(ptr: *mut crate::binary::c_types::c_void) -> Self; unsafe fn from_raw_event_data(ptr: *mut crate::binary::c_types::c_void) -> Self;
} }
} }
/// The type of handlers of events. /// The type of handlers of events.
pub type Handler<T> = dyn FnMut(critical_section::CriticalSection<'_>, &T) + Sync + Send; pub type Handler<T> = dyn FnMut(&T) + Sync + Send;
fn default_handler<Event: 'static>() -> Box<Handler<Event>> { fn default_handler<Event: 'static>() -> Box<Handler<Event>> {
fn drop_ref<T>(_: critical_section::CriticalSection<'_>, _: &T) {} fn drop_ref<T>(_: &T) {}
// perf: `drop_ref` is a ZST [function item](https://doc.rust-lang.org/reference/types/function-item.html) // perf: `drop_ref` is a ZST [function item](https://doc.rust-lang.org/reference/types/function-item.html)
// so this doesn't actually allocate. // so this doesn't actually allocate.
Box::new(drop_ref) Box::new(drop_ref)
@ -29,9 +28,10 @@ fn default_handler<Event: 'static>() -> Box<Handler<Event>> {
/// Extension trait for setting handlers for an event. /// Extension trait for setting handlers for an event.
/// ///
/// Register a new event handler like: /// Register a new event handler like:
/// ``` ///
/// ```rust, no_run
/// # use esp_wifi::wifi::event::{self, *}; /// # use esp_wifi::wifi::event::{self, *};
/// # fn new_handler(_: critical_section::CriticalSection<'_>, _: &ApStaconnected) {} /// # fn new_handler(_: &ApStaconnected) {}
/// event::ApStaconnected::update_handler(|_cs, event| { /// event::ApStaconnected::update_handler(|_cs, event| {
/// new_handler(event); /// new_handler(event);
/// }) /// })
@ -43,46 +43,28 @@ fn default_handler<Event: 'static>() -> Box<Handler<Event>> {
pub trait EventExt: sealed::Event + Sized + 'static { pub trait EventExt: sealed::Event + Sized + 'static {
/// Get the handler for this event, replacing it with the default handler. /// Get the handler for this event, replacing it with the default handler.
fn take_handler() -> Box<Handler<Self>> { fn take_handler() -> Box<Handler<Self>> {
critical_section::with(|cs| { Self::handler().with(|handler| handler.take().unwrap_or_else(default_handler::<Self>))
Self::handler()
.borrow_ref_mut(cs)
.take()
.unwrap_or_else(default_handler::<Self>)
})
} }
/// Set the handler for this event, returning the old handler. /// Set the handler for this event, returning the old handler.
fn replace_handler< fn replace_handler<F: FnMut(&Self) + Sync + Send + 'static>(f: F) -> Box<Handler<Self>> {
F: FnMut(critical_section::CriticalSection<'_>, &Self) + Sync + Send + 'static, Self::handler().with(|handler| {
>( handler
f: F,
) -> Box<Handler<Self>> {
critical_section::with(|cs| {
Self::handler()
.borrow_ref_mut(cs)
.replace(Box::new(f)) .replace(Box::new(f))
.unwrap_or_else(default_handler::<Self>) .unwrap_or_else(default_handler::<Self>)
}) })
} }
/// Atomic combination of [`take_handler`] and [`replace_handler`]. Use this /// Atomic combination of [`Self::take_handler`] and
/// to add a new handler which runs after the previously registered /// [`Self::replace_handler`]. Use this to add a new handler which runs
/// handlers. /// after the previously registered handlers.
fn update_handler< fn update_handler<F: FnMut(&Self) + Sync + Send + 'static>(mut f: F) {
F: FnMut(critical_section::CriticalSection<'_>, &Self) + Sync + Send + 'static, Self::handler().with(|handler| {
>( let mut prev: Box<Handler<Self>> =
mut f: F, handler.take().unwrap_or_else(default_handler::<Self>);
) { handler.replace(Box::new(move |event| {
critical_section::with(move |cs| { prev(event);
let mut handler: Box<Handler<Self>> = Self::handler() f(event)
.borrow_ref_mut(cs) }));
.take() })
.unwrap_or_else(default_handler::<Self>);
Self::handler().borrow_ref_mut(cs).replace(Box::new(
move |cs: critical_section::CriticalSection<'_>, event| {
handler(cs, event);
f(cs, event)
},
));
});
} }
} }
impl<T: sealed::Event + 'static> EventExt for T {} impl<T: sealed::Event + 'static> EventExt for T {}
@ -97,9 +79,8 @@ macro_rules! impl_wifi_event {
unsafe fn from_raw_event_data(_: *mut crate::binary::c_types::c_void) -> Self { unsafe fn from_raw_event_data(_: *mut crate::binary::c_types::c_void) -> Self {
Self Self
} }
fn handler() -> &'static Mutex<RefCell<Option<Box<Handler<Self>>>>> { fn handler() -> &'static Locked<Option<Box<Handler<Self>>>> {
static HANDLE: Mutex<RefCell<Option<Box<Handler<$newtype>>>>> = static HANDLE: Locked<Option<Box<Handler<$newtype>>>> = Locked::new(None);
Mutex::new(RefCell::new(None));
&HANDLE &HANDLE
} }
} }
@ -114,9 +95,8 @@ macro_rules! impl_wifi_event {
unsafe fn from_raw_event_data(ptr: *mut crate::binary::c_types::c_void) -> Self { unsafe fn from_raw_event_data(ptr: *mut crate::binary::c_types::c_void) -> Self {
Self(unsafe { *ptr.cast() }) Self(unsafe { *ptr.cast() })
} }
fn handler() -> &'static Mutex<RefCell<Option<Box<Handler<Self>>>>> { fn handler() -> &'static Locked<Option<Box<Handler<Self>>>> {
static HANDLE: Mutex<RefCell<Option<Box<Handler<$newtype>>>>> = static HANDLE: Locked<Option<Box<Handler<$newtype>>>> = Locked::new(None);
Mutex::new(RefCell::new(None));
&HANDLE &HANDLE
} }
} }
@ -170,23 +150,21 @@ impl_wifi_event!(HomeChannelChange, wifi_event_home_channel_change_t);
impl_wifi_event!(StaNeighborRep, wifi_event_neighbor_report_t); impl_wifi_event!(StaNeighborRep, wifi_event_neighbor_report_t);
/// Handle the given event using the registered event handlers. /// Handle the given event using the registered event handlers.
pub fn handle<Event: EventExt>( pub fn handle<Event: EventExt>(event_data: &Event) -> bool {
cs: critical_section::CriticalSection<'_>, Event::handler().with(|handler| {
event_data: &Event, if let Some(handler) = handler {
) -> bool { handler(event_data);
if let Some(handler) = &mut *Event::handler().borrow_ref_mut(cs) { true
handler(cs, event_data); } else {
true false
} else { }
false })
}
} }
/// Handle an event given the raw pointers. /// Handle an event given the raw pointers.
/// # Safety /// # Safety
/// The pointer should be valid to cast to `Event`'s inner type (if it has one) /// The pointer should be valid to cast to `Event`'s inner type (if it has one)
pub(crate) unsafe fn handle_raw<Event: EventExt>( pub(crate) unsafe fn handle_raw<Event: EventExt>(
cs: critical_section::CriticalSection<'_>,
event_data: *mut crate::binary::c_types::c_void, event_data: *mut crate::binary::c_types::c_void,
event_data_size: usize, event_data_size: usize,
) -> bool { ) -> bool {
@ -195,7 +173,7 @@ pub(crate) unsafe fn handle_raw<Event: EventExt>(
core::mem::size_of::<Event>(), core::mem::size_of::<Event>(),
"wrong size event data" "wrong size event data"
); );
handle::<Event>(cs, unsafe { &Event::from_raw_event_data(event_data) }) handle::<Event>(unsafe { &Event::from_raw_event_data(event_data) })
} }
/// Handle event regardless of its type. /// Handle event regardless of its type.
@ -203,146 +181,145 @@ pub(crate) unsafe fn handle_raw<Event: EventExt>(
/// Arguments should be self-consistent. /// Arguments should be self-consistent.
#[rustfmt::skip] #[rustfmt::skip]
pub(crate) unsafe fn dispatch_event_handler( pub(crate) unsafe fn dispatch_event_handler(
cs: critical_section::CriticalSection<'_>,
event: WifiEvent, event: WifiEvent,
event_data: *mut crate::binary::c_types::c_void, event_data: *mut crate::binary::c_types::c_void,
event_data_size: usize, event_data_size: usize,
) -> bool { ) -> bool {
match event { match event {
WifiEvent::WifiReady => { WifiEvent::WifiReady => {
handle_raw::<WifiReady>(cs, event_data, event_data_size) handle_raw::<WifiReady>(event_data, event_data_size)
} }
WifiEvent::ScanDone => { WifiEvent::ScanDone => {
handle_raw::<ScanDone>(cs, event_data, event_data_size) handle_raw::<ScanDone>(event_data, event_data_size)
} }
WifiEvent::StaStart => { WifiEvent::StaStart => {
handle_raw::<StaStart>(cs, event_data, event_data_size) handle_raw::<StaStart>(event_data, event_data_size)
} }
WifiEvent::StaStop => { WifiEvent::StaStop => {
handle_raw::<StaStop>(cs, event_data, event_data_size) handle_raw::<StaStop>(event_data, event_data_size)
} }
WifiEvent::StaConnected => { WifiEvent::StaConnected => {
handle_raw::<StaConnected>(cs, event_data, event_data_size) handle_raw::<StaConnected>(event_data, event_data_size)
} }
WifiEvent::StaDisconnected => { WifiEvent::StaDisconnected => {
handle_raw::<StaDisconnected>(cs, event_data, event_data_size) handle_raw::<StaDisconnected>(event_data, event_data_size)
} }
WifiEvent::StaAuthmodeChange => { WifiEvent::StaAuthmodeChange => {
handle_raw::<StaAuthmodeChange>(cs, event_data, event_data_size) handle_raw::<StaAuthmodeChange>(event_data, event_data_size)
} }
WifiEvent::StaWpsErSuccess => { WifiEvent::StaWpsErSuccess => {
handle_raw::<StaWpsErSuccess>(cs, event_data, event_data_size) handle_raw::<StaWpsErSuccess>(event_data, event_data_size)
} }
WifiEvent::StaWpsErFailed => { WifiEvent::StaWpsErFailed => {
handle_raw::<StaWpsErFailed>(cs, event_data, event_data_size) handle_raw::<StaWpsErFailed>(event_data, event_data_size)
} }
WifiEvent::StaWpsErTimeout => { WifiEvent::StaWpsErTimeout => {
handle_raw::<StaWpsErTimeout>(cs, event_data, event_data_size) handle_raw::<StaWpsErTimeout>(event_data, event_data_size)
} }
WifiEvent::StaWpsErPin => { WifiEvent::StaWpsErPin => {
handle_raw::<StaWpsErPin>(cs, event_data, event_data_size) handle_raw::<StaWpsErPin>(event_data, event_data_size)
} }
WifiEvent::StaWpsErPbcOverlap => { WifiEvent::StaWpsErPbcOverlap => {
handle_raw::<StaWpsErPbcOverlap>(cs, event_data, event_data_size) handle_raw::<StaWpsErPbcOverlap>(event_data, event_data_size)
} }
WifiEvent::ApStart => { WifiEvent::ApStart => {
handle_raw::<ApStart>(cs, event_data, event_data_size) handle_raw::<ApStart>(event_data, event_data_size)
} }
WifiEvent::ApStop => { WifiEvent::ApStop => {
handle_raw::<ApStop>(cs, event_data, event_data_size) handle_raw::<ApStop>(event_data, event_data_size)
} }
WifiEvent::ApStaconnected => { WifiEvent::ApStaconnected => {
handle_raw::<ApStaconnected>(cs, event_data, event_data_size) handle_raw::<ApStaconnected>(event_data, event_data_size)
} }
WifiEvent::ApStadisconnected => { WifiEvent::ApStadisconnected => {
handle_raw::<ApStadisconnected>(cs, event_data, event_data_size) handle_raw::<ApStadisconnected>(event_data, event_data_size)
} }
WifiEvent::ApProbereqrecved => { WifiEvent::ApProbereqrecved => {
handle_raw::<ApProbereqrecved>(cs, event_data, event_data_size) handle_raw::<ApProbereqrecved>(event_data, event_data_size)
} }
WifiEvent::FtmReport => { WifiEvent::FtmReport => {
handle_raw::<FtmReport>(cs, event_data, event_data_size) handle_raw::<FtmReport>(event_data, event_data_size)
} }
WifiEvent::StaBssRssiLow => { WifiEvent::StaBssRssiLow => {
handle_raw::<StaBssRssiLow>(cs, event_data, event_data_size) handle_raw::<StaBssRssiLow>(event_data, event_data_size)
} }
WifiEvent::ActionTxStatus => { WifiEvent::ActionTxStatus => {
handle_raw::<ActionTxStatus>(cs, event_data, event_data_size) handle_raw::<ActionTxStatus>(event_data, event_data_size)
} }
WifiEvent::RocDone => { WifiEvent::RocDone => {
handle_raw::<RocDone>(cs, event_data, event_data_size) handle_raw::<RocDone>(event_data, event_data_size)
} }
WifiEvent::StaBeaconTimeout => { WifiEvent::StaBeaconTimeout => {
handle_raw::<StaBeaconTimeout>(cs, event_data, event_data_size) handle_raw::<StaBeaconTimeout>(event_data, event_data_size)
} }
WifiEvent::ConnectionlessModuleWakeIntervalStart => { WifiEvent::ConnectionlessModuleWakeIntervalStart => {
handle_raw::<ConnectionlessModuleWakeIntervalStart>(cs, event_data, event_data_size) handle_raw::<ConnectionlessModuleWakeIntervalStart>(event_data, event_data_size)
} }
WifiEvent::ApWpsRgSuccess => { WifiEvent::ApWpsRgSuccess => {
handle_raw::<ApWpsRgSuccess>(cs, event_data, event_data_size) handle_raw::<ApWpsRgSuccess>(event_data, event_data_size)
} }
WifiEvent::ApWpsRgFailed => { WifiEvent::ApWpsRgFailed => {
handle_raw::<ApWpsRgFailed>(cs, event_data, event_data_size) handle_raw::<ApWpsRgFailed>(event_data, event_data_size)
} }
WifiEvent::ApWpsRgTimeout => { WifiEvent::ApWpsRgTimeout => {
handle_raw::<ApWpsRgTimeout>(cs, event_data, event_data_size) handle_raw::<ApWpsRgTimeout>(event_data, event_data_size)
} }
WifiEvent::ApWpsRgPin => { WifiEvent::ApWpsRgPin => {
handle_raw::<ApWpsRgPin>(cs, event_data, event_data_size) handle_raw::<ApWpsRgPin>(event_data, event_data_size)
} }
WifiEvent::ApWpsRgPbcOverlap => { WifiEvent::ApWpsRgPbcOverlap => {
handle_raw::<ApWpsRgPbcOverlap>(cs, event_data, event_data_size) handle_raw::<ApWpsRgPbcOverlap>(event_data, event_data_size)
} }
WifiEvent::ItwtSetup => { WifiEvent::ItwtSetup => {
handle_raw::<ItwtSetup>(cs, event_data, event_data_size) handle_raw::<ItwtSetup>(event_data, event_data_size)
} }
WifiEvent::ItwtTeardown => { WifiEvent::ItwtTeardown => {
handle_raw::<ItwtTeardown>(cs, event_data, event_data_size) handle_raw::<ItwtTeardown>(event_data, event_data_size)
} }
WifiEvent::ItwtProbe => { WifiEvent::ItwtProbe => {
handle_raw::<ItwtProbe>(cs, event_data, event_data_size) handle_raw::<ItwtProbe>(event_data, event_data_size)
} }
WifiEvent::ItwtSuspend => { WifiEvent::ItwtSuspend => {
handle_raw::<ItwtSuspend>(cs, event_data, event_data_size) handle_raw::<ItwtSuspend>(event_data, event_data_size)
} }
WifiEvent::TwtWakeup => { WifiEvent::TwtWakeup => {
handle_raw::<TwtWakeup>(cs, event_data, event_data_size) handle_raw::<TwtWakeup>(event_data, event_data_size)
} }
WifiEvent::BtwtSetup => { WifiEvent::BtwtSetup => {
handle_raw::<BtwtSetup>(cs, event_data, event_data_size) handle_raw::<BtwtSetup>(event_data, event_data_size)
} }
WifiEvent::BtwtTeardown => { WifiEvent::BtwtTeardown => {
handle_raw::<BtwtTeardown>(cs, event_data, event_data_size) handle_raw::<BtwtTeardown>(event_data, event_data_size)
} }
WifiEvent::NanStarted => { WifiEvent::NanStarted => {
handle_raw::<NanStarted>(cs, event_data, event_data_size) handle_raw::<NanStarted>(event_data, event_data_size)
} }
WifiEvent::NanStopped => { WifiEvent::NanStopped => {
handle_raw::<NanStopped>(cs, event_data, event_data_size) handle_raw::<NanStopped>(event_data, event_data_size)
} }
WifiEvent::NanSvcMatch => { WifiEvent::NanSvcMatch => {
handle_raw::<NanSvcMatch>(cs, event_data, event_data_size) handle_raw::<NanSvcMatch>(event_data, event_data_size)
} }
WifiEvent::NanReplied => { WifiEvent::NanReplied => {
handle_raw::<NanReplied>(cs, event_data, event_data_size) handle_raw::<NanReplied>(event_data, event_data_size)
} }
WifiEvent::NanReceive => { WifiEvent::NanReceive => {
handle_raw::<NanReceive>(cs, event_data, event_data_size) handle_raw::<NanReceive>(event_data, event_data_size)
} }
WifiEvent::NdpIndication => { WifiEvent::NdpIndication => {
handle_raw::<NdpIndication>(cs, event_data, event_data_size) handle_raw::<NdpIndication>(event_data, event_data_size)
} }
WifiEvent::NdpConfirm => { WifiEvent::NdpConfirm => {
handle_raw::<NdpConfirm>(cs, event_data, event_data_size) handle_raw::<NdpConfirm>(event_data, event_data_size)
} }
WifiEvent::NdpTerminated => { WifiEvent::NdpTerminated => {
handle_raw::<NdpTerminated>(cs, event_data, event_data_size) handle_raw::<NdpTerminated>(event_data, event_data_size)
} }
WifiEvent::HomeChannelChange => { WifiEvent::HomeChannelChange => {
handle_raw::<HomeChannelChange>(cs, event_data, event_data_size) handle_raw::<HomeChannelChange>(event_data, event_data_size)
} }
WifiEvent::StaNeighborRep => { WifiEvent::StaNeighborRep => {
handle_raw::<StaNeighborRep>(cs, event_data, event_data_size) handle_raw::<StaNeighborRep>(event_data, event_data_size)
} }
} }
} }

View File

@ -6,15 +6,14 @@ pub(crate) mod state;
use alloc::collections::vec_deque::VecDeque; use alloc::collections::vec_deque::VecDeque;
use core::{ use core::{
cell::{RefCell, RefMut},
fmt::Debug, fmt::Debug,
mem::{self, MaybeUninit}, mem::{self, MaybeUninit},
ptr::addr_of, ptr::addr_of,
time::Duration, time::Duration,
}; };
use critical_section::{CriticalSection, Mutex};
use enumset::{EnumSet, EnumSetType}; use enumset::{EnumSet, EnumSetType};
use esp_hal::sync::Locked;
use esp_wifi_sys::include::{ use esp_wifi_sys::include::{
esp_eap_client_clear_ca_cert, esp_eap_client_clear_ca_cert,
esp_eap_client_clear_certificate_and_key, esp_eap_client_clear_certificate_and_key,
@ -952,11 +951,11 @@ const DATA_FRAME_SIZE: usize = MTU + ETHERNET_FRAME_HEADER_SIZE;
const RX_QUEUE_SIZE: usize = crate::CONFIG.rx_queue_size; const RX_QUEUE_SIZE: usize = crate::CONFIG.rx_queue_size;
const TX_QUEUE_SIZE: usize = crate::CONFIG.tx_queue_size; const TX_QUEUE_SIZE: usize = crate::CONFIG.tx_queue_size;
pub(crate) static DATA_QUEUE_RX_AP: Mutex<RefCell<VecDeque<EspWifiPacketBuffer>>> = pub(crate) static DATA_QUEUE_RX_AP: Locked<VecDeque<EspWifiPacketBuffer>> =
Mutex::new(RefCell::new(VecDeque::new())); Locked::new(VecDeque::new());
pub(crate) static DATA_QUEUE_RX_STA: Mutex<RefCell<VecDeque<EspWifiPacketBuffer>>> = pub(crate) static DATA_QUEUE_RX_STA: Locked<VecDeque<EspWifiPacketBuffer>> =
Mutex::new(RefCell::new(VecDeque::new())); Locked::new(VecDeque::new());
/// Common errors. /// Common errors.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@ -1529,14 +1528,13 @@ unsafe extern "C" fn recv_cb_sta(
eb: *mut c_types::c_void, eb: *mut c_types::c_void,
) -> esp_err_t { ) -> esp_err_t {
let packet = EspWifiPacketBuffer { buffer, len, eb }; let packet = EspWifiPacketBuffer { buffer, len, eb };
// We must handle the result outside of the critical section because // We must handle the result outside of the lock because
// EspWifiPacketBuffer::drop must not be called in a critical section. // EspWifiPacketBuffer::drop must not be called in a critical section.
// Dropping an EspWifiPacketBuffer will call `esp_wifi_internal_free_rx_buffer` // Dropping an EspWifiPacketBuffer will call `esp_wifi_internal_free_rx_buffer`
// which will try to lock an internal mutex. If the mutex is already taken, // which will try to lock an internal mutex. If the mutex is already taken,
// the function will try to trigger a context switch, which will fail if we // the function will try to trigger a context switch, which will fail if we
// are in a critical section. // are in an interrupt-free context.
if critical_section::with(|cs| { if DATA_QUEUE_RX_STA.with(|queue| {
let mut queue = DATA_QUEUE_RX_STA.borrow_ref_mut(cs);
if queue.len() < RX_QUEUE_SIZE { if queue.len() < RX_QUEUE_SIZE {
queue.push_back(packet); queue.push_back(packet);
true true
@ -1563,9 +1561,8 @@ unsafe extern "C" fn recv_cb_ap(
// Dropping an EspWifiPacketBuffer will call `esp_wifi_internal_free_rx_buffer` // Dropping an EspWifiPacketBuffer will call `esp_wifi_internal_free_rx_buffer`
// which will try to lock an internal mutex. If the mutex is already taken, // which will try to lock an internal mutex. If the mutex is already taken,
// the function will try to trigger a context switch, which will fail if we // the function will try to trigger a context switch, which will fail if we
// are in a critical section. // are in an interrupt-free context.
if critical_section::with(|cs| { if DATA_QUEUE_RX_AP.with(|queue| {
let mut queue = DATA_QUEUE_RX_AP.borrow_ref_mut(cs);
if queue.len() < RX_QUEUE_SIZE { if queue.len() < RX_QUEUE_SIZE {
queue.push_back(packet); queue.push_back(packet);
true true
@ -1905,7 +1902,7 @@ mod sealed {
fn wrap_config(config: Self::Config) -> Configuration; fn wrap_config(config: Self::Config) -> Configuration;
fn data_queue_rx(self, cs: CriticalSection) -> RefMut<'_, VecDeque<EspWifiPacketBuffer>>; fn data_queue_rx(self) -> &'static Locked<VecDeque<EspWifiPacketBuffer>>;
fn can_send(self) -> bool { fn can_send(self) -> bool {
WIFI_TX_INFLIGHT.load(Ordering::SeqCst) < TX_QUEUE_SIZE WIFI_TX_INFLIGHT.load(Ordering::SeqCst) < TX_QUEUE_SIZE
@ -1928,13 +1925,12 @@ mod sealed {
} }
fn rx_token(self) -> Option<(WifiRxToken<Self>, WifiTxToken<Self>)> { fn rx_token(self) -> Option<(WifiRxToken<Self>, WifiTxToken<Self>)> {
let is_empty = critical_section::with(|cs| self.data_queue_rx(cs).is_empty()); let is_empty = self.data_queue_rx().with(|q| q.is_empty());
if is_empty || !self.can_send() { if is_empty || !self.can_send() {
crate::timer::yield_task(); crate::timer::yield_task();
} }
let is_empty = let is_empty = is_empty && self.data_queue_rx().with(|q| q.is_empty());
is_empty && critical_section::with(|cs| self.data_queue_rx(cs).is_empty());
if !is_empty { if !is_empty {
self.tx_token().map(|tx| (WifiRxToken { mode: self }, tx)) self.tx_token().map(|tx| (WifiRxToken { mode: self }, tx))
@ -1967,8 +1963,8 @@ mod sealed {
Configuration::Client(config) Configuration::Client(config)
} }
fn data_queue_rx(self, cs: CriticalSection) -> RefMut<'_, VecDeque<EspWifiPacketBuffer>> { fn data_queue_rx(self) -> &'static Locked<VecDeque<EspWifiPacketBuffer>> {
DATA_QUEUE_RX_STA.borrow_ref_mut(cs) &DATA_QUEUE_RX_STA
} }
fn interface(self) -> wifi_interface_t { fn interface(self) -> wifi_interface_t {
@ -2003,8 +1999,8 @@ mod sealed {
Configuration::AccessPoint(config) Configuration::AccessPoint(config)
} }
fn data_queue_rx(self, cs: CriticalSection) -> RefMut<'_, VecDeque<EspWifiPacketBuffer>> { fn data_queue_rx(self) -> &'static Locked<VecDeque<EspWifiPacketBuffer>> {
DATA_QUEUE_RX_AP.borrow_ref_mut(cs) &DATA_QUEUE_RX_AP
} }
fn interface(self) -> wifi_interface_t { fn interface(self) -> wifi_interface_t {
@ -2321,7 +2317,7 @@ impl PromiscuousPkt<'_> {
frame_type, frame_type,
len, len,
data: core::slice::from_raw_parts( data: core::slice::from_raw_parts(
(buf as *const u8).add(size_of::<wifi_pkt_rx_ctrl_t>()), (buf as *const u8).add(core::mem::size_of::<wifi_pkt_rx_ctrl_t>()),
len, len,
), ),
} }
@ -2329,18 +2325,14 @@ impl PromiscuousPkt<'_> {
} }
#[cfg(feature = "sniffer")] #[cfg(feature = "sniffer")]
#[allow(clippy::type_complexity)] static SNIFFER_CB: Locked<Option<fn(PromiscuousPkt)>> = Locked::new(None);
static SNIFFER_CB: Mutex<RefCell<Option<fn(PromiscuousPkt)>>> = Mutex::new(RefCell::new(None));
#[cfg(feature = "sniffer")] #[cfg(feature = "sniffer")]
unsafe extern "C" fn promiscuous_rx_cb(buf: *mut core::ffi::c_void, frame_type: u32) { unsafe extern "C" fn promiscuous_rx_cb(buf: *mut core::ffi::c_void, frame_type: u32) {
critical_section::with(|cs| { if let Some(sniffer_callback) = SNIFFER_CB.with(|callback| *callback) {
let Some(sniffer_callback) = *SNIFFER_CB.borrow_ref(cs) else {
return;
};
let promiscuous_pkt = PromiscuousPkt::from_raw(buf as *const _, frame_type); let promiscuous_pkt = PromiscuousPkt::from_raw(buf as *const _, frame_type);
sniffer_callback(promiscuous_pkt); sniffer_callback(promiscuous_pkt);
}); }
} }
#[cfg(feature = "sniffer")] #[cfg(feature = "sniffer")]
@ -2385,9 +2377,7 @@ impl Sniffer {
} }
/// Set the callback for receiving a packet. /// Set the callback for receiving a packet.
pub fn set_receive_cb(&mut self, cb: fn(PromiscuousPkt)) { pub fn set_receive_cb(&mut self, cb: fn(PromiscuousPkt)) {
critical_section::with(|cs| { SNIFFER_CB.with(|callback| *callback = Some(cb));
*SNIFFER_CB.borrow_ref_mut(cs) = Some(cb);
});
} }
} }
@ -2675,21 +2665,19 @@ impl<MODE: Sealed> WifiRxToken<MODE> {
where where
F: FnOnce(&mut [u8]) -> R, F: FnOnce(&mut [u8]) -> R,
{ {
let mut data = critical_section::with(|cs| { let mut data = self.mode.data_queue_rx().with(|queue| {
let mut queue = self.mode.data_queue_rx(cs);
unwrap!( unwrap!(
queue.pop_front(), queue.pop_front(),
"unreachable: transmit()/receive() ensures there is a packet to process" "unreachable: transmit()/receive() ensures there is a packet to process"
) )
}); });
// We handle the received data outside of the critical section because // We handle the received data outside of the lock because
// EspWifiPacketBuffer::drop must not be called in a critical section. // EspWifiPacketBuffer::drop must not be called in a critical section.
// Dropping an EspWifiPacketBuffer will call `esp_wifi_internal_free_rx_buffer` // Dropping an EspWifiPacketBuffer will call `esp_wifi_internal_free_rx_buffer`
// which will try to lock an internal mutex. If the mutex is already // which will try to lock an internal mutex. If the mutex is already
// taken, the function will try to trigger a context switch, which will // taken, the function will try to trigger a context switch, which will
// fail if we are in a critical section. // fail if we are in an interrupt-free context.
let buffer = data.as_slice_mut(); let buffer = data.as_slice_mut();
dump_packet_info(buffer); dump_packet_info(buffer);
@ -3321,7 +3309,7 @@ mod asynch {
} }
fn clear_events(events: impl Into<EnumSet<WifiEvent>>) { fn clear_events(events: impl Into<EnumSet<WifiEvent>>) {
critical_section::with(|cs| WIFI_EVENTS.borrow_ref_mut(cs).remove_all(events.into())); WIFI_EVENTS.with(|evts| evts.get_mut().remove_all(events.into()));
} }
/// Wait for one [`WifiEvent`]. /// Wait for one [`WifiEvent`].
@ -3390,7 +3378,7 @@ mod asynch {
cx: &mut core::task::Context<'_>, cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> { ) -> Poll<Self::Output> {
self.event.waker().register(cx.waker()); self.event.waker().register(cx.waker());
if critical_section::with(|cs| WIFI_EVENTS.borrow_ref_mut(cs).remove(self.event)) { if WIFI_EVENTS.with(|events| events.get_mut().remove(self.event)) {
Poll::Ready(()) Poll::Ready(())
} else { } else {
Poll::Pending Poll::Pending
@ -3417,8 +3405,8 @@ mod asynch {
self: core::pin::Pin<&mut Self>, self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>, cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> { ) -> Poll<Self::Output> {
let output = critical_section::with(|cs| { let output = WIFI_EVENTS.with(|events| {
let mut events = WIFI_EVENTS.borrow_ref_mut(cs); let events = events.get_mut();
let active = events.intersection(self.event); let active = events.intersection(self.event);
events.remove_all(active); events.remove_all(active);
active active

View File

@ -9,8 +9,8 @@ pub(crate) mod os_adapter_chip_specific;
use core::{cell::RefCell, ptr::addr_of_mut}; use core::{cell::RefCell, ptr::addr_of_mut};
use critical_section::Mutex;
use enumset::EnumSet; use enumset::EnumSet;
use esp_hal::sync::{Lock, Locked};
use super::WifiEvent; use super::WifiEvent;
use crate::{ use crate::{
@ -35,12 +35,14 @@ use crate::{
timer::yield_task, timer::yield_task,
}; };
static WIFI_LOCK: Lock = Lock::new();
static mut QUEUE_HANDLE: *mut ConcurrentQueue = core::ptr::null_mut(); static mut QUEUE_HANDLE: *mut ConcurrentQueue = core::ptr::null_mut();
// useful for waiting for events - clear and wait for the event bit to be set // useful for waiting for events - clear and wait for the event bit to be set
// again // again
pub(crate) static WIFI_EVENTS: Mutex<RefCell<EnumSet<WifiEvent>>> = pub(crate) static WIFI_EVENTS: Locked<RefCell<EnumSet<WifiEvent>>> =
Mutex::new(RefCell::new(enumset::enum_set!())); Locked::new(RefCell::new(enumset::enum_set!()));
/// ************************************************************************** /// **************************************************************************
/// Name: wifi_env_is_chip /// Name: wifi_env_is_chip
@ -214,10 +216,11 @@ pub unsafe extern "C" fn spin_lock_delete(lock: *mut crate::binary::c_types::c_v
/// ///
/// ************************************************************************* /// *************************************************************************
pub unsafe extern "C" fn wifi_int_disable( pub unsafe extern "C" fn wifi_int_disable(
wifi_int_mux: *mut crate::binary::c_types::c_void, _wifi_int_mux: *mut crate::binary::c_types::c_void,
) -> u32 { ) -> u32 {
trace!("wifi_int_disable"); trace!("wifi_int_disable");
crate::wifi::os_adapter::os_adapter_chip_specific::wifi_int_disable(wifi_int_mux) // TODO: can we use wifi_int_mux?
unsafe { WIFI_LOCK.acquire() as _ }
} }
/// ************************************************************************** /// **************************************************************************
@ -236,11 +239,12 @@ pub unsafe extern "C" fn wifi_int_disable(
/// ///
/// ************************************************************************* /// *************************************************************************
pub unsafe extern "C" fn wifi_int_restore( pub unsafe extern "C" fn wifi_int_restore(
wifi_int_mux: *mut crate::binary::c_types::c_void, _wifi_int_mux: *mut crate::binary::c_types::c_void,
tmp: u32, tmp: u32,
) { ) {
trace!("wifi_int_restore"); trace!("wifi_int_restore");
crate::wifi::os_adapter::os_adapter_chip_specific::wifi_int_restore(wifi_int_mux, tmp) let token = tmp as critical_section::RawRestoreState;
unsafe { WIFI_LOCK.release(token) }
} }
/// ************************************************************************** /// **************************************************************************
@ -867,11 +871,8 @@ pub unsafe extern "C" fn event_post(
let event = unwrap!(WifiEvent::from_i32(event_id)); let event = unwrap!(WifiEvent::from_i32(event_id));
trace!("EVENT: {:?}", event); trace!("EVENT: {:?}", event);
let mut handled = false; WIFI_EVENTS.with(|events| events.borrow_mut().insert(event));
critical_section::with(|cs| { let handled = super::event::dispatch_event_handler(event, event_data, event_data_size);
WIFI_EVENTS.borrow_ref_mut(cs).insert(event);
handled = super::event::dispatch_event_handler(cs, event, event_data, event_data_size);
});
super::state::update_state(event, handled); super::state::update_state(event, handled);

View File

@ -1,11 +1,5 @@
#![allow(unused_variables)]
#![allow(dead_code)]
#![allow(non_snake_case)]
use crate::hal::{interrupt, peripherals}; use crate::hal::{interrupt, peripherals};
const DPORT_WIFI_CLK_WIFI_EN_M: u32 = 0x406;
pub(crate) fn chip_ints_on(mask: u32) { pub(crate) fn chip_ints_on(mask: u32) {
unsafe { crate::hal::xtensa_lx::interrupt::enable_mask(mask) }; unsafe { crate::hal::xtensa_lx::interrupt::enable_mask(mask) };
} }
@ -14,21 +8,6 @@ pub(crate) fn chip_ints_off(mask: u32) {
crate::hal::xtensa_lx::interrupt::disable_mask(mask); crate::hal::xtensa_lx::interrupt::disable_mask(mask);
} }
pub(crate) unsafe extern "C" fn wifi_int_disable(
wifi_int_mux: *mut crate::binary::c_types::c_void,
) -> u32 {
core::mem::transmute(critical_section::acquire())
}
pub(crate) unsafe extern "C" fn wifi_int_restore(
wifi_int_mux: *mut crate::binary::c_types::c_void,
tmp: u32,
) {
critical_section::release(core::mem::transmute::<u32, critical_section::RestoreState>(
tmp,
))
}
pub(crate) unsafe extern "C" fn phy_common_clock_disable() { pub(crate) unsafe extern "C" fn phy_common_clock_disable() {
crate::common_adapter::chip_specific::phy_disable_clock(); crate::common_adapter::chip_specific::phy_disable_clock();
} }
@ -50,24 +29,6 @@ pub(crate) unsafe extern "C" fn set_intr(
intr_matrix_set(0, intr_source, intr_num); intr_matrix_set(0, intr_source, intr_num);
} }
pub(crate) unsafe extern "C" fn wifi_clock_enable() {
let dport = &*crate::hal::peripherals::SYSTEM::ptr();
dport.wifi_clk_en().modify(|r, w| {
let old = r.bits();
let new_bits = old | DPORT_WIFI_CLK_WIFI_EN_M;
w.bits(new_bits)
});
}
pub(crate) unsafe extern "C" fn wifi_clock_disable() {
let dport = &*crate::hal::peripherals::SYSTEM::ptr();
dport.wifi_clk_en().modify(|r, w| {
let old = r.bits();
let new_bits = old & !DPORT_WIFI_CLK_WIFI_EN_M;
w.bits(new_bits)
});
}
/// ************************************************************************** /// **************************************************************************
/// Name: esp_set_isr /// Name: esp_set_isr
/// ///

View File

@ -1,8 +1,4 @@
use crate::hal::{ use crate::hal::{interrupt, peripherals};
interrupt,
peripherals::{self, Interrupt},
riscv,
};
pub(crate) fn chip_ints_on(mask: u32) { pub(crate) fn chip_ints_on(mask: u32) {
unsafe { unsafe {
@ -20,40 +16,6 @@ pub(crate) fn chip_ints_off(mask: u32) {
} }
} }
pub(crate) unsafe extern "C" fn wifi_int_disable(
wifi_int_mux: *mut crate::binary::c_types::c_void,
) -> u32 {
let res = if riscv::register::mstatus::read().mie() {
1
} else {
0
};
riscv::interrupt::disable();
trace!(
"wifi_int_disable wifi_int_mux {:?} - return {}",
wifi_int_mux,
res,
);
res
}
pub(crate) unsafe extern "C" fn wifi_int_restore(
wifi_int_mux: *mut crate::binary::c_types::c_void,
tmp: u32,
) {
trace!(
"wifi_int_restore wifi_int_mux {:?} tmp {}",
wifi_int_mux,
tmp
);
if tmp == 1 {
riscv::interrupt::enable();
}
}
pub(crate) unsafe extern "C" fn set_intr( pub(crate) unsafe extern "C" fn set_intr(
_cpu_no: i32, _cpu_no: i32,
_intr_source: u32, _intr_source: u32,
@ -103,11 +65,11 @@ pub unsafe extern "C" fn set_isr(
#[cfg(feature = "wifi")] #[cfg(feature = "wifi")]
{ {
unwrap!(interrupt::enable( unwrap!(interrupt::enable(
Interrupt::WIFI_MAC, peripherals::Interrupt::WIFI_MAC,
interrupt::Priority::Priority1 interrupt::Priority::Priority1
)); ));
unwrap!(interrupt::enable( unwrap!(interrupt::enable(
Interrupt::WIFI_PWR, peripherals::Interrupt::WIFI_PWR,
interrupt::Priority::Priority1 interrupt::Priority::Priority1
)); ));
} }

View File

@ -1,8 +1,4 @@
use crate::hal::{ use crate::hal::{interrupt, peripherals};
interrupt,
peripherals::{self, Interrupt},
riscv,
};
pub(crate) fn chip_ints_on(mask: u32) { pub(crate) fn chip_ints_on(mask: u32) {
unsafe { unsafe {
@ -20,40 +16,6 @@ pub(crate) fn chip_ints_off(mask: u32) {
} }
} }
pub(crate) unsafe extern "C" fn wifi_int_disable(
wifi_int_mux: *mut crate::binary::c_types::c_void,
) -> u32 {
let res = if riscv::register::mstatus::read().mie() {
1
} else {
0
};
riscv::interrupt::disable();
trace!(
"wifi_int_disable wifi_int_mux {:?} - return {}",
wifi_int_mux,
res,
);
res
}
pub(crate) unsafe extern "C" fn wifi_int_restore(
wifi_int_mux: *mut crate::binary::c_types::c_void,
tmp: u32,
) {
trace!(
"wifi_int_restore wifi_int_mux {:?} tmp {}",
wifi_int_mux,
tmp
);
if tmp == 1 {
riscv::interrupt::enable();
}
}
pub(crate) unsafe extern "C" fn set_intr( pub(crate) unsafe extern "C" fn set_intr(
_cpu_no: i32, _cpu_no: i32,
_intr_source: u32, _intr_source: u32,
@ -104,11 +66,11 @@ pub unsafe extern "C" fn set_isr(
#[cfg(feature = "wifi")] #[cfg(feature = "wifi")]
{ {
unwrap!(interrupt::enable( unwrap!(interrupt::enable(
Interrupt::WIFI_MAC, peripherals::Interrupt::WIFI_MAC,
interrupt::Priority::Priority1 interrupt::Priority::Priority1
)); ));
unwrap!(interrupt::enable( unwrap!(interrupt::enable(
Interrupt::WIFI_PWR, peripherals::Interrupt::WIFI_PWR,
interrupt::Priority::Priority1 interrupt::Priority::Priority1
)); ));
} }

View File

@ -1,8 +1,4 @@
use crate::hal::{ use crate::hal::{interrupt, peripherals};
interrupt,
peripherals::{self, Interrupt},
riscv,
};
pub(crate) fn chip_ints_on(mask: u32) { pub(crate) fn chip_ints_on(mask: u32) {
unsafe { unsafe {
@ -20,40 +16,6 @@ pub(crate) fn chip_ints_off(mask: u32) {
} }
} }
pub(crate) unsafe extern "C" fn wifi_int_disable(
wifi_int_mux: *mut crate::binary::c_types::c_void,
) -> u32 {
let res = if riscv::register::mstatus::read().mie() {
1
} else {
0
};
riscv::interrupt::disable();
trace!(
"wifi_int_disable wifi_int_mux {:?} - return {}",
wifi_int_mux,
res,
);
res
}
pub(crate) unsafe extern "C" fn wifi_int_restore(
wifi_int_mux: *mut crate::binary::c_types::c_void,
tmp: u32,
) {
trace!(
"wifi_int_restore wifi_int_mux {:?} tmp {}",
wifi_int_mux,
tmp
);
if tmp == 1 {
riscv::interrupt::enable();
}
}
pub(crate) unsafe extern "C" fn set_intr( pub(crate) unsafe extern "C" fn set_intr(
_cpu_no: i32, _cpu_no: i32,
_intr_source: u32, _intr_source: u32,
@ -117,11 +79,11 @@ pub unsafe extern "C" fn set_isr(
#[cfg(feature = "wifi")] #[cfg(feature = "wifi")]
{ {
unwrap!(interrupt::enable( unwrap!(interrupt::enable(
Interrupt::WIFI_MAC, peripherals::Interrupt::WIFI_MAC,
interrupt::Priority::Priority1 interrupt::Priority::Priority1
)); ));
unwrap!(interrupt::enable( unwrap!(interrupt::enable(
Interrupt::WIFI_PWR, peripherals::Interrupt::WIFI_PWR,
interrupt::Priority::Priority1 interrupt::Priority::Priority1
)); ));
} }

View File

@ -1,8 +1,4 @@
use crate::hal::{ use crate::hal::{interrupt, peripherals};
interrupt,
peripherals::{self, Interrupt},
riscv,
};
pub(crate) fn chip_ints_on(mask: u32) { pub(crate) fn chip_ints_on(mask: u32) {
unsafe { unsafe {
@ -20,40 +16,6 @@ pub(crate) fn chip_ints_off(mask: u32) {
} }
} }
pub(crate) unsafe extern "C" fn wifi_int_disable(
wifi_int_mux: *mut crate::binary::c_types::c_void,
) -> u32 {
let res = if riscv::register::mstatus::read().mie() {
1
} else {
0
};
riscv::interrupt::disable();
trace!(
"wifi_int_disable wifi_int_mux {:?} - return {}",
wifi_int_mux,
res,
);
res
}
pub(crate) unsafe extern "C" fn wifi_int_restore(
wifi_int_mux: *mut crate::binary::c_types::c_void,
tmp: u32,
) {
trace!(
"wifi_int_restore wifi_int_mux {:?} tmp {}",
wifi_int_mux,
tmp
);
if tmp == 1 {
riscv::interrupt::enable();
}
}
pub(crate) unsafe extern "C" fn set_intr( pub(crate) unsafe extern "C" fn set_intr(
_cpu_no: i32, _cpu_no: i32,
_intr_source: u32, _intr_source: u32,

View File

@ -1,7 +1,3 @@
#![allow(unused_variables)]
#![allow(dead_code)]
#![allow(non_snake_case)]
use crate::hal::{interrupt, peripherals}; use crate::hal::{interrupt, peripherals};
pub(crate) fn chip_ints_on(mask: u32) { pub(crate) fn chip_ints_on(mask: u32) {
@ -12,21 +8,6 @@ pub(crate) fn chip_ints_off(mask: u32) {
crate::hal::xtensa_lx::interrupt::disable_mask(mask); crate::hal::xtensa_lx::interrupt::disable_mask(mask);
} }
pub(crate) unsafe extern "C" fn wifi_int_disable(
wifi_int_mux: *mut crate::binary::c_types::c_void,
) -> u32 {
core::mem::transmute(critical_section::acquire())
}
pub(crate) unsafe extern "C" fn wifi_int_restore(
wifi_int_mux: *mut crate::binary::c_types::c_void,
tmp: u32,
) {
critical_section::release(core::mem::transmute::<u32, critical_section::RestoreState>(
tmp,
))
}
pub(crate) unsafe extern "C" fn set_intr( pub(crate) unsafe extern "C" fn set_intr(
_cpu_no: i32, _cpu_no: i32,
intr_source: u32, intr_source: u32,

View File

@ -1,7 +1,3 @@
#![allow(unused_variables)]
#![allow(dead_code)]
#![allow(non_snake_case)]
use crate::hal::{interrupt, peripherals}; use crate::hal::{interrupt, peripherals};
pub(crate) fn chip_ints_on(mask: u32) { pub(crate) fn chip_ints_on(mask: u32) {
@ -12,21 +8,6 @@ pub(crate) fn chip_ints_off(mask: u32) {
crate::hal::xtensa_lx::interrupt::disable_mask(mask); crate::hal::xtensa_lx::interrupt::disable_mask(mask);
} }
pub(crate) unsafe extern "C" fn wifi_int_disable(
wifi_int_mux: *mut crate::binary::c_types::c_void,
) -> u32 {
core::mem::transmute(critical_section::acquire())
}
pub(crate) unsafe extern "C" fn wifi_int_restore(
wifi_int_mux: *mut crate::binary::c_types::c_void,
tmp: u32,
) {
critical_section::release(core::mem::transmute::<u32, critical_section::RestoreState>(
tmp,
))
}
pub(crate) unsafe extern "C" fn set_intr( pub(crate) unsafe extern "C" fn set_intr(
_cpu_no: i32, _cpu_no: i32,
intr_source: u32, intr_source: u32,

View File

@ -52,15 +52,15 @@ fn main() -> ! {
// Set event handlers for wifi before init to avoid missing any. // Set event handlers for wifi before init to avoid missing any.
let mut connections = 0u32; let mut connections = 0u32;
_ = event::ApStart::replace_handler(|_, _| esp_println::println!("ap start event")); _ = event::ApStart::replace_handler(|_| esp_println::println!("ap start event"));
event::ApStaconnected::update_handler(move |_, event| { event::ApStaconnected::update_handler(move |event| {
connections += 1; connections += 1;
esp_println::println!("connected {}, mac: {:?}", connections, event.0.mac); esp_println::println!("connected {}, mac: {:?}", connections, event.0.mac);
}); });
event::ApStaconnected::update_handler(|_, event| { event::ApStaconnected::update_handler(|event| {
esp_println::println!("connected aid: {}", event.0.aid); esp_println::println!("connected aid: {}", event.0.aid);
}); });
event::ApStadisconnected::update_handler(|_, event| { event::ApStadisconnected::update_handler(|event| {
esp_println::println!( esp_println::println!(
"disconnected mac: {:?}, reason: {:?}", "disconnected mac: {:?}, reason: {:?}",
event.0.mac, event.0.mac,

View File

@ -9,7 +9,7 @@
//! Because of the huge task-arena size configured this won't work on ESP32-S2 //! Because of the huge task-arena size configured this won't work on ESP32-S2
//! //!
//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi esp-wifi/utils //% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi esp-wifi/utils esp-wifi/sniffer
//% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6
#![no_std] #![no_std]