1//! This module allows hooking `esp-wifi` into an external scheduler, instead
2//! of using the integrated one as provided by the `preempt` module.
3//!
4//! In order to hook up an external scheduler, enable the `preempt-extern`
5//! feature, implement the `Scheduler` trait for a struct, and create the
6//! necessary `extern` functions using the `scheduler_impl!()` macro.
7//!
8//! Example:
9//!
10//! ```ignore
11//! use esp_wifi::preempt::Scheduler;
12//!
13//! struct MyScheduler {}
14//!
15//! impl Scheduler for MyScheduler {
16//! // impl goes here
17//! }
18//!
19//! esp_wifi::scheduler_impl!(static SCHEDULER: MyScheduler = MyScheduler {});
20//! ```
21use core::ffi::c_void;
2223pub trait Scheduler: Send + Sync + 'static {
24/// This function is called by `esp-wifi` when starting up the WiFi stack.
25fn enable(&self);
2627/// This function is called by `esp-wifi` when shutting down the WiFi stack.
28fn disable(&self);
2930/// This function is called by threads and should switch to the next thread.
31fn yield_task(&self);
3233/// This function is called by threads and should return an opaque handle
34 /// for the calling thread. The same handle will be passed to
35 /// `esp_wifi_preempt_schedule_task_deletion`.
36fn current_task(&self) -> *mut c_void;
3738/// This function is used to create threads.
39 /// It should allocate the stack.
40fn task_create(
41&self,
42 task: extern "C" fn(*mut c_void),
43 param: *mut c_void,
44 task_stack_size: usize,
45 ) -> *mut c_void;
4647/// This function is called to let the scheduler know this thread is not
48 /// needed anymore and should be deleted. After this function is called,
49 /// the thread should not be scheduled anymore. The thread stack can be
50 /// free'ed.
51fn schedule_task_deletion(&self, task_handle: *mut c_void);
5253/// This function should return an opaque per-thread pointer to an
54 /// usize-sized memory location, which will be used to store a pointer
55 /// to a semaphore for this thread.
56fn current_task_thread_semaphore(&self) -> *mut c_void;
57}
5859extern "Rust" {
60fn esp_wifi_preempt_enable();
61fn esp_wifi_preempt_disable();
62fn esp_wifi_preempt_yield_task();
63fn esp_wifi_preempt_current_task() -> *mut c_void;
64fn esp_wifi_preempt_task_create(
65 task: extern "C" fn(*mut c_void),
66 param: *mut c_void,
67 task_stack_size: usize,
68 ) -> *mut c_void;
69fn esp_wifi_preempt_schedule_task_deletion(task_handle: *mut c_void);
70fn esp_wifi_preempt_current_task_thread_semaphore() -> *mut c_void;
71}
7273pub(crate) fn enable() {
74unsafe { esp_wifi_preempt_enable() }
75}
7677pub(crate) fn disable() {
78unsafe { esp_wifi_preempt_disable() }
79}
8081pub(crate) fn yield_task() {
82unsafe { esp_wifi_preempt_yield_task() }
83}
8485pub(crate) fn current_task() -> *mut c_void {
86unsafe { esp_wifi_preempt_current_task() }
87}
8889pub(crate) fn task_create(
90 task: extern "C" fn(*mut c_void),
91 param: *mut c_void,
92 task_stack_size: usize,
93) -> *mut c_void {
94unsafe { esp_wifi_preempt_task_create(task, param, task_stack_size) }
95}
9697pub(crate) fn schedule_task_deletion(task_handle: *mut c_void) {
98unsafe { esp_wifi_preempt_schedule_task_deletion(task_handle) }
99}
100101pub(crate) fn current_task_thread_semaphore() -> *mut c_void {
102unsafe { esp_wifi_preempt_current_task_thread_semaphore() }
103}
104105/// Set the Scheduler implementation.
106///
107/// See the module documentation for an example.
108#[macro_export]
109macro_rules! scheduler_impl {
110 (static $name:ident: $t: ty = $val:expr) => {
111static $name: $t = $val;
112113#[no_mangle]
114fn esp_wifi_preempt_enable() {
115 <$t as $crate::preempt::Scheduler>::enable(&$name)
116 }
117#[no_mangle]
118fn esp_wifi_preempt_disable() {
119 <$t as $crate::preempt::Scheduler>::disable(&$name)
120 }
121#[no_mangle]
122fn esp_wifi_preempt_yield_task() {
123 <$t as $crate::preempt::Scheduler>::yield_task(&$name)
124 }
125#[no_mangle]
126fn esp_wifi_preempt_current_task() -> *mut c_void {
127 <$t as $crate::preempt::Scheduler>::current_task(&$name)
128 }
129#[no_mangle]
130fn esp_wifi_preempt_task_create(
131 task: extern "C" fn(*mut c_void),
132 param: *mut c_void,
133 task_stack_size: usize,
134 ) -> *mut c_void {
135 <$t as $crate::preempt::Scheduler>::task_create(&$name, task, param, task_stack_size)
136 }
137#[no_mangle]
138fn esp_wifi_preempt_schedule_task_deletion(task_handle: *mut c_void) {
139 <$t as $crate::preempt::Scheduler>::schedule_task_deletion(&$name, task_handle)
140 }
141#[no_mangle]
142fn esp_wifi_preempt_current_task_thread_semaphore() -> *mut c_void {
143 <$t as $crate::preempt::Scheduler>::current_task_thread_semaphore(&$name)
144 }
145 };
146}