Skip to content

Commit

Permalink
refactor esp-wifi to ease using external task scheduler (#3106)
Browse files Browse the repository at this point in the history
* esp-wifi: untangle `setup_timer_isr`

* esp-wifi: bundle scheduler functions into `preempt`

* esp-wifi: split `timer` into `preempt::timer`, `radio` and `time`

* move more deinit stuff into `preempt::disable()`

* move getter of `thread_semaphore` into `preempt`
  • Loading branch information
kaspar030 authored Feb 7, 2025
1 parent d6bc83c commit 235ee62
Show file tree
Hide file tree
Showing 22 changed files with 138 additions and 136 deletions.
2 changes: 1 addition & 1 deletion esp-wifi/src/ble/btdm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ unsafe extern "C" fn task_create(
extern "C" fn(*mut esp_wifi_sys::c_types::c_void),
>(func);

let task = crate::preempt::arch_specific::task_create(task_func, param, stack_depth as usize);
let task = crate::preempt::task_create(task_func, param, stack_depth as usize);
*(handle as *mut usize) = task as usize;

1
Expand Down
4 changes: 2 additions & 2 deletions esp-wifi/src/ble/npl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
self,
common::{str_from_c, ConcurrentQueue},
},
timer::yield_task,
preempt::yield_task,
};

#[cfg_attr(esp32c2, path = "os_adapter_esp32c2.rs")]
Expand Down Expand Up @@ -403,7 +403,7 @@ unsafe extern "C" fn task_create(
extern "C" fn(*mut esp_wifi_sys::c_types::c_void),
>(task_func);

let task = crate::preempt::arch_specific::task_create(task_func, param, stack_depth as usize);
let task = crate::preempt::task_create(task_func, param, stack_depth as usize);
*(task_handle as *mut usize) = task as usize;

1
Expand Down
13 changes: 6 additions & 7 deletions esp-wifi/src/compat/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ use crate::{
binary::c_types::{c_int, c_void},
hal::sync::Locked,
memory_fence::memory_fence,
preempt::current_task,
timer::yield_task,
preempt::{current_task, yield_task},
};

pub(crate) const OSI_FUNCS_TIME_BLOCKING: u32 = u32::MAX;
Expand Down Expand Up @@ -206,7 +205,7 @@ pub(crate) fn sem_take(semphr: *mut c_void, tick: u32) -> i32 {

let forever = tick == OSI_FUNCS_TIME_BLOCKING;
let timeout = tick as u64;
let start = crate::timer::systimer_count();
let start = crate::time::systimer_count();

let sem = semphr as *mut u32;

Expand All @@ -227,7 +226,7 @@ pub(crate) fn sem_take(semphr: *mut c_void, tick: u32) -> i32 {
return 1;
}

if !forever && crate::timer::elapsed_time_since(start) > timeout {
if !forever && crate::time::elapsed_time_since(start) > timeout {
break 'outer;
}

Expand All @@ -251,7 +250,7 @@ pub(crate) fn sem_give(semphr: *mut c_void) -> i32 {

pub(crate) fn thread_sem_get() -> *mut c_void {
trace!("wifi_thread_semphr_get");
unsafe { &mut ((*current_task()).thread_semaphore) as *mut _ as *mut c_void }
crate::preempt::current_task_thread_semaphore()
}

pub(crate) fn create_recursive_mutex() -> *mut c_void {
Expand Down Expand Up @@ -376,15 +375,15 @@ pub(crate) fn receive_queued(

let forever = block_time_tick == OSI_FUNCS_TIME_BLOCKING;
let timeout = block_time_tick as u64;
let start = crate::timer::systimer_count();
let start = crate::time::systimer_count();

loop {
if unsafe { (*queue).try_dequeue(item) } {
trace!("received");
return 1;
}

if !forever && crate::timer::elapsed_time_since(start) > timeout {
if !forever && crate::time::elapsed_time_since(start) > timeout {
trace!("queue_recv returns with timeout");
return -1;
}
Expand Down
6 changes: 3 additions & 3 deletions esp-wifi/src/compat/timer_compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl TimerQueue {
let mut current = self.head.as_mut();
while let Some(timer) = current {
if timer.active
&& crate::timer::time_diff(timer.started, current_timestamp) >= timer.timeout
&& crate::time::time_diff(timer.started, current_timestamp) >= timer.timeout
{
return Some(timer);
}
Expand Down Expand Up @@ -149,8 +149,8 @@ pub(crate) fn compat_timer_arm(ets_timer: *mut ets_timer, tmout: u32, repeat: bo
}

pub(crate) fn compat_timer_arm_us(ets_timer: *mut ets_timer, us: u32, repeat: bool) {
let systick = crate::timer::systimer_count();
let ticks = crate::timer::micros_to_ticks(us as u64);
let systick = crate::time::systimer_count();
let ticks = crate::time::micros_to_ticks(us as u64);

trace!(
"timer_arm_us {:x} current: {} ticks: {} repeat: {}",
Expand Down
23 changes: 16 additions & 7 deletions esp-wifi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,17 +124,20 @@ use portable_atomic::Ordering;
#[cfg(feature = "wifi")]
use crate::wifi::WifiError;
use crate::{
preempt::yield_task,
radio::{setup_radio_isr, shutdown_radio_isr},
tasks::init_tasks,
timer::{setup_timer_isr, shutdown_timer_isr},
};

mod binary {
pub use esp_wifi_sys::*;
}
mod compat;

mod preempt;

mod timer;
mod radio;
mod time;

#[cfg(feature = "wifi")]
pub mod wifi;
Expand Down Expand Up @@ -236,7 +239,7 @@ const _: () = {
core::assert!(CONFIG.rx_ba_win < (CONFIG.static_rx_buf_num * 2), "WiFi configuration check: rx_ba_win should not be larger than double of the static_rx_buf_num!");
};

type TimeBase = PeriodicTimer<'static, Blocking>;
pub(crate) type TimeBase = PeriodicTimer<'static, Blocking>;

pub(crate) mod flags {
use portable_atomic::{AtomicBool, AtomicUsize};
Expand Down Expand Up @@ -382,8 +385,14 @@ pub fn init<'d, T: EspWifiTimerSource, R: EspWifiRngSource>(
info!("esp-wifi configuration {:?}", crate::CONFIG);
crate::common_adapter::chip_specific::enable_wifi_power_domain();
phy_mem_init();

setup_radio_isr();

// This initializes the task switcher and timer tick interrupt.
preempt::setup(unsafe { timer.clone_unchecked() }.timer());

init_tasks();
setup_timer_isr(unsafe { timer.clone_unchecked() }.timer());
yield_task();

wifi_set_log_verbose();
init_clocks();
Expand Down Expand Up @@ -435,10 +444,10 @@ pub unsafe fn deinit_unchecked() -> Result<(), InitializationError> {
crate::flags::BLE.store(false, Ordering::Release);
}

shutdown_timer_isr();
crate::preempt::delete_all_tasks();
shutdown_radio_isr();

crate::timer::TIMER.with(|timer| timer.take());
// This shuts down the task switcher and timer tick interrupt.
preempt::disable();

crate::flags::ESP_WIFI_INITIALIZED.store(false, Ordering::Release);

Expand Down
31 changes: 27 additions & 4 deletions esp-wifi/src/preempt/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
#[cfg_attr(target_arch = "riscv32", path = "preempt_riscv.rs")]
#[cfg_attr(target_arch = "xtensa", path = "preempt_xtensa.rs")]
pub mod arch_specific;
mod arch_specific;
pub mod timer;

use core::mem::size_of;

use arch_specific::*;
use esp_hal::sync::Locked;
use esp_wifi_sys::include::malloc;
use timer::{disable_multitasking, disable_timer, setup_multitasking, setup_timer};
//
pub(crate) use {arch_specific::task_create, timer::yield_task};

use crate::{compat::malloc::free, hal::trapframe::TrapFrame, memory_fence::memory_fence};

Expand All @@ -19,7 +23,22 @@ static CTX_NOW: Locked<ContextWrapper> = Locked::new(ContextWrapper(core::ptr::n

static mut SCHEDULED_TASK_TO_DELETE: *mut Context = core::ptr::null_mut();

pub(crate) fn allocate_main_task() -> *mut Context {
pub(crate) fn setup(timer: crate::TimeBase) {
// allocate the main task
allocate_main_task();
setup_timer(timer);
setup_multitasking();
}

pub(crate) fn disable() {
disable_timer();
disable_multitasking();
delete_all_tasks();

timer::TIMER.with(|timer| timer.take());
}

fn allocate_main_task() -> *mut Context {
CTX_NOW.with(|ctx_now| unsafe {
if !ctx_now.0.is_null() {
panic!("Tried to allocate main task multiple times");
Expand Down Expand Up @@ -114,8 +133,6 @@ pub(crate) fn current_task() -> *mut Context {
}

pub(crate) fn schedule_task_deletion(task: *mut Context) {
use crate::timer::yield_task;

unsafe {
SCHEDULED_TASK_TO_DELETE = task;
}
Expand All @@ -140,3 +157,9 @@ pub(crate) fn task_switch(trap_frame: &mut TrapFrame) {
next_task();
restore_task_context(current_task(), trap_frame);
}

pub(crate) fn current_task_thread_semaphore() -> *mut crate::binary::c_types::c_void {
unsafe {
&mut ((*current_task()).thread_semaphore) as *mut _ as *mut crate::binary::c_types::c_void
}
}
11 changes: 11 additions & 0 deletions esp-wifi/src/preempt/timer/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use esp_hal::sync::Locked;

#[cfg_attr(xtensa, path = "xtensa.rs")]
#[cfg_attr(riscv, path = "riscv.rs")]
mod arch_specific;

pub(crate) use arch_specific::*;

use crate::TimeBase;

pub(crate) static TIMER: Locked<Option<TimeBase>> = Locked::new(None);
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ use crate::{
/// The timer responsible for time slicing.
const TIMESLICE_FREQUENCY: Rate = Rate::from_hz(crate::CONFIG.tick_rate_hz);

// Time keeping
pub const TICKS_PER_SECOND: u64 = 1_000_000;

use super::TIMER;

pub(crate) fn setup_timer(mut alarm0: TimeBase) {
Expand Down Expand Up @@ -88,17 +85,3 @@ pub(crate) fn yield_task() {
.cpu_intr_from_cpu_3()
.modify(|_, w| w.cpu_intr_from_cpu_3().set_bit());
}

/// Current systimer count value
/// A tick is 1 / 1_000_000 seconds
pub(crate) fn systimer_count() -> u64 {
esp_hal::time::Instant::now()
.duration_since_epoch()
.as_micros()
}

// TODO: use an Instance type instead...
pub(crate) fn time_diff(start: u64, end: u64) -> u64 {
// 52-bit wrapping sub
end.wrapping_sub(start) & 0x000f_ffff_ffff_ffff
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,6 @@ const TIMESLICE_FREQUENCY: Rate = Rate::from_hz(crate::CONFIG.tick_rate_hz);

use super::TIMER;

// Time keeping
pub const TICKS_PER_SECOND: u64 = 1_000_000;

/// This function must not be called in a critical section. Doing so may return
/// an incorrect value.
pub(crate) fn systimer_count() -> u64 {
esp_hal::time::Instant::now()
.duration_since_epoch()
.as_micros()
}

pub(crate) fn setup_timer(mut timer1: TimeBase) {
timer1.set_interrupt_handler(InterruptHandler::new(
unsafe { core::mem::transmute::<*const (), extern "C" fn()>(handler as *const ()) },
Expand Down Expand Up @@ -89,8 +78,3 @@ pub(crate) fn yield_task() {
core::arch::asm!("wsr.intset {0}", in(reg) intr, options(nostack));
}
}

// TODO: use an Instance type instead...
pub(crate) fn time_diff(start: u64, end: u64) -> u64 {
end.wrapping_sub(start)
}
10 changes: 10 additions & 0 deletions esp-wifi/src/radio/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#[cfg_attr(esp32, path = "radio_esp32.rs")]
#[cfg_attr(esp32c2, path = "radio_esp32c2.rs")]
#[cfg_attr(esp32c3, path = "radio_esp32c3.rs")]
#[cfg_attr(esp32c6, path = "radio_esp32c6.rs")]
#[cfg_attr(esp32h2, path = "radio_esp32h2.rs")]
#[cfg_attr(esp32s3, path = "radio_esp32s3.rs")]
#[cfg_attr(esp32s2, path = "radio_esp32s2.rs")]
mod chip_specific;

pub(crate) use chip_specific::*;
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
9 changes: 3 additions & 6 deletions esp-wifi/src/tasks.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
use crate::{
compat::timer_compat::TIMERS,
preempt::arch_specific::task_create,
timer::{systimer_count, yield_task},
preempt::{task_create, yield_task},
time::systimer_count,
};

/// Initializes the `main` and `timer` tasks for the Wi-Fi driver.
/// Initializes the `timer` task for the Wi-Fi driver.
pub(crate) fn init_tasks() {
// allocate the main task
crate::preempt::allocate_main_task();

// schedule the timer task
task_create(timer_task, core::ptr::null_mut(), 8192);
}
Expand Down
51 changes: 51 additions & 0 deletions esp-wifi/src/time.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Time keeping
pub const TICKS_PER_SECOND: u64 = 1_000_000;

/// Current systimer count value
/// A tick is 1 / 1_000_000 seconds
/// This function must not be called in a critical section. Doing so may return
/// an incorrect value.
pub(crate) fn systimer_count() -> u64 {
esp_hal::time::Instant::now()
.duration_since_epoch()
.as_micros()
}

// TODO: use an Instance type instead...
#[cfg(target_arch = "riscv32")]
pub(crate) fn time_diff(start: u64, end: u64) -> u64 {
// 52-bit wrapping sub
end.wrapping_sub(start) & 0x000f_ffff_ffff_ffff
}

// TODO: use an Instance type instead...
#[cfg(target_arch = "xtensa")]
pub(crate) fn time_diff(start: u64, end: u64) -> u64 {
end.wrapping_sub(start)
}

#[allow(unused)]
pub(crate) fn micros_to_ticks(us: u64) -> u64 {
us * (TICKS_PER_SECOND / 1_000_000)
}

#[allow(unused)]
pub(crate) fn millis_to_ticks(ms: u64) -> u64 {
ms * (TICKS_PER_SECOND / 1_000)
}

#[allow(unused)]
pub(crate) fn ticks_to_micros(ticks: u64) -> u64 {
ticks / (TICKS_PER_SECOND / 1_000_000)
}

#[allow(unused)]
pub(crate) fn ticks_to_millis(ticks: u64) -> u64 {
ticks / (TICKS_PER_SECOND / 1_000)
}

/// Do not call this in a critical section!
pub(crate) fn elapsed_time_since(start: u64) -> u64 {
let now = systimer_count();
time_diff(start, now)
}
Loading

0 comments on commit 235ee62

Please sign in to comment.