mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-26 20:00:32 +00:00
Separate esp-radio support code (#4175)
This commit is contained in:
parent
6baba85f9e
commit
caadbbba41
@ -15,6 +15,7 @@ doc-config = { features = ["esp-hal/unstable"] }
|
||||
check-configs = [
|
||||
{ features = ["esp-hal/unstable"] },
|
||||
{ features = ["esp-hal/unstable", "esp-alloc"] },
|
||||
{ features = ["esp-hal/unstable", "esp-radio"] },
|
||||
]
|
||||
clippy-configs = [
|
||||
{ features = ["esp-hal/unstable", "esp-alloc", "defmt"] },
|
||||
@ -40,7 +41,7 @@ document-features = "0.2.11"
|
||||
esp-alloc = { version = "0.8.0", path = "../esp-alloc", optional = true }
|
||||
esp-config = { version = "0.5.0", path = "../esp-config" }
|
||||
esp-sync = { version = "0.0.0", path = "../esp-sync" }
|
||||
esp-radio-preempt-driver = { version = "0.0.1", path = "../esp-radio-preempt-driver" }
|
||||
esp-radio-preempt-driver = { version = "0.0.1", path = "../esp-radio-preempt-driver", optional = true }
|
||||
portable-atomic = { version = "1.11.0", default-features = false }
|
||||
|
||||
# Logging interfaces, they are mutually exclusive so they need to be behind separate features.
|
||||
@ -55,7 +56,7 @@ esp-metadata-generated = { version = "0.1.0", path = "../esp-metadata-generated"
|
||||
esp-hal = { version = "1.0.0-rc.0", path = "../esp-hal", features = ["unstable"] }
|
||||
|
||||
[features]
|
||||
default = ["esp-alloc"]
|
||||
default = ["esp-alloc", "esp-radio"]
|
||||
|
||||
## Enable the use of the `esp-alloc` crate for dynamic memory allocation.
|
||||
##
|
||||
@ -64,6 +65,9 @@ default = ["esp-alloc"]
|
||||
## - `pub extern "C" fn free_internal(ptr: *mut u8)`
|
||||
esp-alloc = ["dep:esp-alloc"]
|
||||
|
||||
## Enables esp-radio support.
|
||||
esp-radio = ["dep:esp-radio-preempt-driver"]
|
||||
|
||||
#! ### Chip selection
|
||||
#! One of the following features must be enabled to select the target chip:
|
||||
|
||||
|
171
esp-preempt/src/esp_radio/mod.rs
Normal file
171
esp-preempt/src/esp_radio/mod.rs
Normal file
@ -0,0 +1,171 @@
|
||||
//! esp-radio support
|
||||
|
||||
use core::{ffi::c_void, ptr::NonNull};
|
||||
|
||||
use allocator_api2::boxed::Box;
|
||||
use esp_hal::{
|
||||
system::Cpu,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use esp_radio_preempt_driver::{
|
||||
register_semaphore_implementation,
|
||||
semaphore::{SemaphoreImplementation, SemaphoreKind, SemaphorePtr},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
SCHEDULER,
|
||||
run_queue::MaxPriority,
|
||||
scheduler::Scheduler,
|
||||
semaphore::Semaphore,
|
||||
task::{self, Task},
|
||||
};
|
||||
|
||||
mod queue;
|
||||
mod timer_queue;
|
||||
|
||||
impl esp_radio_preempt_driver::Scheduler for Scheduler {
|
||||
fn initialized(&self) -> bool {
|
||||
self.with(|scheduler| {
|
||||
if scheduler.time_driver.is_none() {
|
||||
warn!("Trying to initialize esp-radio before starting esp-preempt");
|
||||
return false;
|
||||
}
|
||||
|
||||
let current_cpu = Cpu::current() as usize;
|
||||
if !scheduler.per_cpu[current_cpu].initialized {
|
||||
warn!(
|
||||
"Trying to initialize esp-radio on {:?} but esp-preempt is not running on this core",
|
||||
current_cpu
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
})
|
||||
}
|
||||
|
||||
fn yield_task(&self) {
|
||||
task::yield_task();
|
||||
}
|
||||
|
||||
fn yield_task_from_isr(&self) {
|
||||
task::yield_task();
|
||||
}
|
||||
|
||||
fn max_task_priority(&self) -> u32 {
|
||||
MaxPriority::MAX_PRIORITY as u32
|
||||
}
|
||||
|
||||
fn task_create(
|
||||
&self,
|
||||
name: &str,
|
||||
task: extern "C" fn(*mut c_void),
|
||||
param: *mut c_void,
|
||||
priority: u32,
|
||||
pin_to_core: Option<u32>,
|
||||
task_stack_size: usize,
|
||||
) -> *mut c_void {
|
||||
self.create_task(
|
||||
name,
|
||||
task,
|
||||
param,
|
||||
task_stack_size,
|
||||
priority.min(self.max_task_priority()),
|
||||
pin_to_core.and_then(|core| match core {
|
||||
0 => Some(Cpu::ProCpu),
|
||||
#[cfg(multi_core)]
|
||||
1 => Some(Cpu::AppCpu),
|
||||
_ => {
|
||||
warn!("Invalid core number: {}", core);
|
||||
None
|
||||
}
|
||||
}),
|
||||
)
|
||||
.as_ptr()
|
||||
.cast()
|
||||
}
|
||||
|
||||
fn current_task(&self) -> *mut c_void {
|
||||
self.current_task().as_ptr().cast()
|
||||
}
|
||||
|
||||
fn schedule_task_deletion(&self, task_handle: *mut c_void) {
|
||||
task::schedule_task_deletion(task_handle as *mut Task)
|
||||
}
|
||||
|
||||
fn current_task_thread_semaphore(&self) -> SemaphorePtr {
|
||||
task::with_current_task(|task| {
|
||||
NonNull::from(
|
||||
task.thread_semaphore
|
||||
.get_or_insert_with(|| Semaphore::new_counting(0, 1)),
|
||||
)
|
||||
.cast()
|
||||
})
|
||||
}
|
||||
|
||||
fn usleep(&self, us: u32) {
|
||||
SCHEDULER.sleep_until(Instant::now() + Duration::from_micros(us as u64));
|
||||
}
|
||||
|
||||
fn now(&self) -> u64 {
|
||||
// We're using a SingleShotTimer as the time driver, which lets us use the system timer's
|
||||
// timestamps.
|
||||
Instant::now().duration_since_epoch().as_micros()
|
||||
}
|
||||
}
|
||||
|
||||
impl Semaphore {
|
||||
unsafe fn from_ptr<'a>(ptr: SemaphorePtr) -> &'a Self {
|
||||
unsafe { ptr.cast::<Self>().as_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
impl SemaphoreImplementation for Semaphore {
|
||||
fn create(kind: SemaphoreKind) -> SemaphorePtr {
|
||||
let sem = Box::new(match kind {
|
||||
SemaphoreKind::Counting { max, initial } => Semaphore::new_counting(initial, max),
|
||||
SemaphoreKind::Mutex => Semaphore::new_mutex(false),
|
||||
SemaphoreKind::RecursiveMutex => Semaphore::new_mutex(true),
|
||||
});
|
||||
NonNull::from(Box::leak(sem)).cast()
|
||||
}
|
||||
|
||||
unsafe fn delete(semaphore: SemaphorePtr) {
|
||||
let sem = unsafe { Box::from_raw(semaphore.cast::<Semaphore>().as_ptr()) };
|
||||
core::mem::drop(sem);
|
||||
}
|
||||
|
||||
unsafe fn take(semaphore: SemaphorePtr, timeout_us: Option<u32>) -> bool {
|
||||
let semaphore = unsafe { Semaphore::from_ptr(semaphore) };
|
||||
|
||||
semaphore.take(timeout_us)
|
||||
}
|
||||
|
||||
unsafe fn give(semaphore: SemaphorePtr) -> bool {
|
||||
let semaphore = unsafe { Semaphore::from_ptr(semaphore) };
|
||||
|
||||
semaphore.give()
|
||||
}
|
||||
|
||||
unsafe fn current_count(semaphore: SemaphorePtr) -> u32 {
|
||||
let semaphore = unsafe { Semaphore::from_ptr(semaphore) };
|
||||
|
||||
semaphore.current_count()
|
||||
}
|
||||
|
||||
unsafe fn try_take(semaphore: SemaphorePtr) -> bool {
|
||||
let semaphore = unsafe { Semaphore::from_ptr(semaphore) };
|
||||
|
||||
semaphore.try_take()
|
||||
}
|
||||
|
||||
unsafe fn try_give_from_isr(semaphore: SemaphorePtr, _hptw: Option<&mut bool>) -> bool {
|
||||
unsafe { <Self as SemaphoreImplementation>::give(semaphore) }
|
||||
}
|
||||
|
||||
unsafe fn try_take_from_isr(semaphore: SemaphorePtr, _hptw: Option<&mut bool>) -> bool {
|
||||
unsafe { <Self as SemaphoreImplementation>::try_take(semaphore) }
|
||||
}
|
||||
}
|
||||
|
||||
register_semaphore_implementation!(Semaphore);
|
@ -61,13 +61,13 @@ extern crate alloc;
|
||||
// MUST be the first module
|
||||
mod fmt;
|
||||
|
||||
mod queue;
|
||||
#[cfg(feature = "esp-radio")]
|
||||
mod esp_radio;
|
||||
mod run_queue;
|
||||
mod scheduler;
|
||||
mod semaphore;
|
||||
pub mod semaphore;
|
||||
mod task;
|
||||
mod timer;
|
||||
mod timer_queue;
|
||||
mod wait_queue;
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
@ -87,6 +87,7 @@ use esp_hal::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
pub(crate) use scheduler::SCHEDULER;
|
||||
pub use task::CurrentThreadHandle;
|
||||
|
||||
use crate::timer::TimeDriver;
|
||||
|
||||
|
@ -1,17 +1,13 @@
|
||||
#[cfg(feature = "esp-radio")]
|
||||
use core::{ffi::c_void, ptr::NonNull};
|
||||
|
||||
use allocator_api2::boxed::Box;
|
||||
use esp_hal::{
|
||||
system::Cpu,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use esp_radio_preempt_driver::semaphore::{SemaphoreImplementation, SemaphoreKind, SemaphorePtr};
|
||||
use esp_hal::{system::Cpu, time::Instant};
|
||||
use esp_sync::NonReentrantMutex;
|
||||
|
||||
use crate::{
|
||||
InternalMemory,
|
||||
run_queue::{MaxPriority, RunQueue},
|
||||
semaphore::Semaphore,
|
||||
run_queue::RunQueue,
|
||||
task::{
|
||||
self,
|
||||
CpuContext,
|
||||
@ -93,6 +89,7 @@ impl CpuSchedulerState {
|
||||
|
||||
main_task: Task {
|
||||
cpu_context: CpuContext::new(),
|
||||
#[cfg(feature = "esp-radio")]
|
||||
thread_semaphore: None,
|
||||
state: TaskState::Ready,
|
||||
stack: core::ptr::slice_from_raw_parts_mut(core::ptr::null_mut(), 0),
|
||||
@ -201,6 +198,7 @@ impl SchedulerState {
|
||||
task::yield_task();
|
||||
}
|
||||
|
||||
#[cfg(feature = "esp-radio")]
|
||||
pub(crate) fn create_task(
|
||||
&mut self,
|
||||
name: &str,
|
||||
@ -365,6 +363,7 @@ impl SchedulerState {
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "esp-radio")]
|
||||
pub(crate) fn schedule_task_deletion(&mut self, task_to_delete: *mut Task) -> bool {
|
||||
let current_cpu = Cpu::current() as usize;
|
||||
let current_task = unwrap!(self.per_cpu[current_cpu].current_task);
|
||||
@ -408,7 +407,7 @@ impl SchedulerState {
|
||||
let task = Box::from_raw_in(to_delete.as_ptr(), InternalMemory);
|
||||
core::mem::drop(task);
|
||||
} else {
|
||||
to_delete.as_mut().thread_semaphore = None;
|
||||
core::ptr::drop_in_place(to_delete.as_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -436,10 +435,12 @@ impl Scheduler {
|
||||
self.inner.with(cb)
|
||||
}
|
||||
|
||||
#[cfg(feature = "esp-radio")]
|
||||
pub(crate) fn current_task(&self) -> TaskPtr {
|
||||
task::current_task()
|
||||
}
|
||||
|
||||
#[cfg(feature = "esp-radio")]
|
||||
pub(crate) fn create_task(
|
||||
&self,
|
||||
name: &str,
|
||||
@ -466,102 +467,12 @@ impl Scheduler {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "esp-radio")]
|
||||
esp_radio_preempt_driver::scheduler_impl!(pub(crate) static SCHEDULER: Scheduler = Scheduler {
|
||||
inner: NonReentrantMutex::new(SchedulerState::new())
|
||||
});
|
||||
|
||||
impl esp_radio_preempt_driver::Scheduler for Scheduler {
|
||||
fn initialized(&self) -> bool {
|
||||
self.with(|scheduler| {
|
||||
if scheduler.time_driver.is_none() {
|
||||
warn!("Trying to initialize esp-radio before starting esp-preempt");
|
||||
return false;
|
||||
}
|
||||
|
||||
let current_cpu = Cpu::current() as usize;
|
||||
if !scheduler.per_cpu[current_cpu].initialized {
|
||||
warn!(
|
||||
"Trying to initialize esp-radio on {:?} but esp-preempt is not running on this core",
|
||||
current_cpu
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
})
|
||||
}
|
||||
|
||||
fn yield_task(&self) {
|
||||
task::yield_task();
|
||||
}
|
||||
|
||||
fn yield_task_from_isr(&self) {
|
||||
task::yield_task();
|
||||
}
|
||||
|
||||
fn max_task_priority(&self) -> u32 {
|
||||
MaxPriority::MAX_PRIORITY as u32
|
||||
}
|
||||
|
||||
fn task_create(
|
||||
&self,
|
||||
name: &str,
|
||||
task: extern "C" fn(*mut c_void),
|
||||
param: *mut c_void,
|
||||
priority: u32,
|
||||
pin_to_core: Option<u32>,
|
||||
task_stack_size: usize,
|
||||
) -> *mut c_void {
|
||||
self.create_task(
|
||||
name,
|
||||
task,
|
||||
param,
|
||||
task_stack_size,
|
||||
priority.min(self.max_task_priority()),
|
||||
pin_to_core.and_then(|core| match core {
|
||||
0 => Some(Cpu::ProCpu),
|
||||
#[cfg(multi_core)]
|
||||
1 => Some(Cpu::AppCpu),
|
||||
_ => {
|
||||
warn!("Invalid core number: {}", core);
|
||||
None
|
||||
}
|
||||
}),
|
||||
)
|
||||
.as_ptr()
|
||||
.cast()
|
||||
}
|
||||
|
||||
fn current_task(&self) -> *mut c_void {
|
||||
self.current_task().as_ptr().cast()
|
||||
}
|
||||
|
||||
fn schedule_task_deletion(&self, task_handle: *mut c_void) {
|
||||
task::schedule_task_deletion(task_handle as *mut Task)
|
||||
}
|
||||
|
||||
fn current_task_thread_semaphore(&self) -> SemaphorePtr {
|
||||
task::with_current_task(|task| {
|
||||
if task.thread_semaphore.is_none() {
|
||||
task.thread_semaphore = Some(Semaphore::create(SemaphoreKind::Counting {
|
||||
max: 1,
|
||||
initial: 0,
|
||||
}));
|
||||
}
|
||||
|
||||
unwrap!(task.thread_semaphore)
|
||||
})
|
||||
}
|
||||
|
||||
fn usleep(&self, us: u32) {
|
||||
SCHEDULER.sleep_until(Instant::now() + Duration::from_micros(us as u64));
|
||||
}
|
||||
|
||||
fn now(&self) -> u64 {
|
||||
// We're using a SingleShotTimer as the time driver, which lets us use the system timer's
|
||||
// timestamps.
|
||||
esp_hal::time::Instant::now()
|
||||
.duration_since_epoch()
|
||||
.as_micros()
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "esp-radio"))]
|
||||
pub(crate) static SCHEDULER: Scheduler = Scheduler {
|
||||
inner: NonReentrantMutex::new(SchedulerState::new()),
|
||||
};
|
||||
|
@ -1,14 +1,7 @@
|
||||
use alloc::boxed::Box;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
use esp_hal::{
|
||||
system::Cpu,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use esp_radio_preempt_driver::{
|
||||
register_semaphore_implementation,
|
||||
semaphore::{SemaphoreImplementation, SemaphoreKind, SemaphorePtr},
|
||||
};
|
||||
use esp_sync::NonReentrantMutex;
|
||||
|
||||
use crate::{
|
||||
@ -143,30 +136,27 @@ pub struct Semaphore {
|
||||
}
|
||||
|
||||
impl Semaphore {
|
||||
pub fn new(kind: SemaphoreKind) -> Self {
|
||||
let inner = match kind {
|
||||
SemaphoreKind::Counting { initial, max } => SemaphoreInner::Counting {
|
||||
pub fn new_counting(initial: u32, max: u32) -> Self {
|
||||
Semaphore {
|
||||
inner: NonReentrantMutex::new(SemaphoreInner::Counting {
|
||||
current: initial,
|
||||
max,
|
||||
waiting: WaitQueue::new(),
|
||||
},
|
||||
SemaphoreKind::Mutex | SemaphoreKind::RecursiveMutex => SemaphoreInner::Mutex {
|
||||
recursive: matches!(kind, SemaphoreKind::RecursiveMutex),
|
||||
}),
|
||||
}
|
||||
}
|
||||
pub fn new_mutex(recursive: bool) -> Self {
|
||||
Semaphore {
|
||||
inner: NonReentrantMutex::new(SemaphoreInner::Mutex {
|
||||
recursive,
|
||||
owner: None,
|
||||
lock_counter: 0,
|
||||
original_priority: 0,
|
||||
waiting: WaitQueue::new(),
|
||||
},
|
||||
};
|
||||
Semaphore {
|
||||
inner: NonReentrantMutex::new(inner),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn from_ptr<'a>(ptr: SemaphorePtr) -> &'a Self {
|
||||
unsafe { ptr.cast::<Self>().as_ref() }
|
||||
}
|
||||
|
||||
pub fn try_take(&self) -> bool {
|
||||
self.inner.with(|sem| sem.try_take())
|
||||
}
|
||||
@ -220,49 +210,3 @@ impl Semaphore {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl SemaphoreImplementation for Semaphore {
|
||||
fn create(kind: SemaphoreKind) -> SemaphorePtr {
|
||||
let sem = Box::new(Semaphore::new(kind));
|
||||
NonNull::from(Box::leak(sem)).cast()
|
||||
}
|
||||
|
||||
unsafe fn delete(semaphore: SemaphorePtr) {
|
||||
let sem = unsafe { Box::from_raw(semaphore.cast::<Semaphore>().as_ptr()) };
|
||||
core::mem::drop(sem);
|
||||
}
|
||||
|
||||
unsafe fn take(semaphore: SemaphorePtr, timeout_us: Option<u32>) -> bool {
|
||||
let semaphore = unsafe { Semaphore::from_ptr(semaphore) };
|
||||
|
||||
semaphore.take(timeout_us)
|
||||
}
|
||||
|
||||
unsafe fn give(semaphore: SemaphorePtr) -> bool {
|
||||
let semaphore = unsafe { Semaphore::from_ptr(semaphore) };
|
||||
|
||||
semaphore.give()
|
||||
}
|
||||
|
||||
unsafe fn current_count(semaphore: SemaphorePtr) -> u32 {
|
||||
let semaphore = unsafe { Semaphore::from_ptr(semaphore) };
|
||||
|
||||
semaphore.current_count()
|
||||
}
|
||||
|
||||
unsafe fn try_take(semaphore: SemaphorePtr) -> bool {
|
||||
let semaphore = unsafe { Semaphore::from_ptr(semaphore) };
|
||||
|
||||
semaphore.try_take()
|
||||
}
|
||||
|
||||
unsafe fn try_give_from_isr(semaphore: SemaphorePtr, _hptw: Option<&mut bool>) -> bool {
|
||||
unsafe { <Self as SemaphoreImplementation>::give(semaphore) }
|
||||
}
|
||||
|
||||
unsafe fn try_take_from_isr(semaphore: SemaphorePtr, _hptw: Option<&mut bool>) -> bool {
|
||||
unsafe { <Self as SemaphoreImplementation>::try_take(semaphore) }
|
||||
}
|
||||
}
|
||||
|
||||
register_semaphore_implementation!(Semaphore);
|
||||
|
@ -2,21 +2,22 @@
|
||||
#[cfg_attr(xtensa, path = "xtensa.rs")]
|
||||
pub(crate) mod arch_specific;
|
||||
|
||||
use core::{ffi::c_void, marker::PhantomData, mem::MaybeUninit, ptr::NonNull};
|
||||
#[cfg(feature = "esp-radio")]
|
||||
use core::ffi::c_void;
|
||||
use core::{marker::PhantomData, mem::MaybeUninit, ptr::NonNull};
|
||||
|
||||
#[cfg(feature = "esp-radio")]
|
||||
use allocator_api2::alloc::Allocator;
|
||||
pub(crate) use arch_specific::*;
|
||||
use esp_hal::system::Cpu;
|
||||
use esp_radio_preempt_driver::semaphore::{SemaphoreHandle, SemaphorePtr};
|
||||
|
||||
use crate::{
|
||||
InternalMemory,
|
||||
SCHEDULER,
|
||||
run_queue::RunQueue,
|
||||
scheduler::SchedulerState,
|
||||
wait_queue::WaitQueue,
|
||||
use esp_hal::{
|
||||
system::Cpu,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
#[cfg(feature = "esp-radio")]
|
||||
use crate::{InternalMemory, semaphore::Semaphore};
|
||||
use crate::{SCHEDULER, run_queue::RunQueue, scheduler::SchedulerState, wait_queue::WaitQueue};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub(crate) enum TaskState {
|
||||
@ -59,6 +60,7 @@ task_list_item!(TaskTimerQueueElement, timer_queue_item);
|
||||
/// Extension trait for common task operations. These should be inherent methods but we can't
|
||||
/// implement stuff for NonNull.
|
||||
pub(crate) trait TaskExt {
|
||||
#[cfg(feature = "esp-radio")]
|
||||
fn resume(self);
|
||||
fn priority(self, _: &mut RunQueue) -> usize;
|
||||
fn set_priority(self, _: &mut RunQueue, new_pro: usize);
|
||||
@ -67,6 +69,7 @@ pub(crate) trait TaskExt {
|
||||
}
|
||||
|
||||
impl TaskExt for TaskPtr {
|
||||
#[cfg(feature = "esp-radio")]
|
||||
fn resume(self) {
|
||||
SCHEDULER.with(|scheduler| scheduler.resume_task(self))
|
||||
}
|
||||
@ -226,7 +229,8 @@ impl<E: TaskListElement> TaskQueue<E> {
|
||||
#[repr(C)]
|
||||
pub(crate) struct Task {
|
||||
pub cpu_context: CpuContext,
|
||||
pub thread_semaphore: Option<SemaphorePtr>,
|
||||
#[cfg(feature = "esp-radio")]
|
||||
pub thread_semaphore: Option<Semaphore>,
|
||||
pub state: TaskState,
|
||||
pub stack: *mut [MaybeUninit<u32>],
|
||||
pub priority: usize,
|
||||
@ -259,6 +263,7 @@ const STACK_CANARY: u32 =
|
||||
const { esp_config::esp_config_int!(u32, "ESP_HAL_CONFIG_STACK_GUARD_VALUE") };
|
||||
|
||||
impl Task {
|
||||
#[cfg(feature = "esp-radio")]
|
||||
pub(crate) fn new(
|
||||
name: &str,
|
||||
task_fn: extern "C" fn(*mut c_void),
|
||||
@ -299,6 +304,7 @@ impl Task {
|
||||
|
||||
Task {
|
||||
cpu_context: new_task_context(task_fn, param, stack_top),
|
||||
#[cfg(feature = "esp-radio")]
|
||||
thread_semaphore: None,
|
||||
state: TaskState::Ready,
|
||||
stack: stack_words,
|
||||
@ -333,10 +339,9 @@ impl Task {
|
||||
impl Drop for Task {
|
||||
fn drop(&mut self) {
|
||||
debug!("Dropping task: {:?}", self as *mut Task);
|
||||
if let Some(sem) = self.thread_semaphore {
|
||||
let sem = unsafe { SemaphoreHandle::from_ptr(sem) };
|
||||
core::mem::drop(sem)
|
||||
}
|
||||
|
||||
#[cfg(feature = "esp-radio")]
|
||||
let _ = self.thread_semaphore.take();
|
||||
}
|
||||
}
|
||||
|
||||
@ -390,6 +395,33 @@ pub(super) fn current_task() -> TaskPtr {
|
||||
with_current_task(|task| NonNull::from(task))
|
||||
}
|
||||
|
||||
/// A handle to the current thread.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct CurrentThreadHandle {
|
||||
_task: TaskPtr,
|
||||
}
|
||||
|
||||
impl CurrentThreadHandle {
|
||||
/// Retrieves a handle to the current task.
|
||||
pub fn get() -> Self {
|
||||
Self {
|
||||
_task: current_task(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Delays the current task for the specified duration.
|
||||
pub fn delay(self, duration: Duration) {
|
||||
self.delay_until(Instant::now() + duration);
|
||||
}
|
||||
|
||||
/// Delays the current task until the specified deadline.
|
||||
pub fn delay_until(self, deadline: Instant) {
|
||||
SCHEDULER.sleep_until(deadline);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "esp-radio")]
|
||||
pub(super) fn schedule_task_deletion(task: *mut Task) {
|
||||
trace!("schedule_task_deletion {:?}", task);
|
||||
SCHEDULER.with(|scheduler| {
|
||||
|
@ -1,3 +1,4 @@
|
||||
#[cfg(feature = "esp-radio")]
|
||||
use core::ffi::c_void;
|
||||
|
||||
use esp_hal::{interrupt::software::SoftwareInterrupt, riscv::register, system::Cpu};
|
||||
@ -117,6 +118,7 @@ pub(crate) fn set_idle_hook_entry(idle_context: &mut CpuContext) {
|
||||
idle_context.pc = idle_hook as usize;
|
||||
}
|
||||
|
||||
#[cfg(feature = "esp-radio")]
|
||||
pub(crate) fn new_task_context(
|
||||
task: extern "C" fn(*mut c_void),
|
||||
param: *mut c_void,
|
||||
|
@ -1,3 +1,4 @@
|
||||
#[cfg(feature = "esp-radio")]
|
||||
use core::ffi::c_void;
|
||||
|
||||
#[cfg(multi_core)]
|
||||
@ -28,6 +29,7 @@ pub(crate) fn set_idle_hook_entry(idle_context: &mut CpuContext) {
|
||||
idle_context.PS = current_ps;
|
||||
}
|
||||
|
||||
#[cfg(feature = "esp-radio")]
|
||||
pub(crate) fn new_task_context(
|
||||
task_fn: extern "C" fn(*mut c_void),
|
||||
param: *mut c_void,
|
||||
|
@ -120,7 +120,7 @@ macro_rules! scheduler_impl {
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[inline]
|
||||
fn esp_preempt_current_task_thread_semaphore() -> SemaphorePtr {
|
||||
fn esp_preempt_current_task_thread_semaphore() -> $crate::semaphore::SemaphorePtr {
|
||||
<$t as $crate::Scheduler>::current_task_thread_semaphore(&$driver)
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ use core::ffi::c_void;
|
||||
use defmt::info;
|
||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal};
|
||||
#[cfg(multi_core)]
|
||||
use esp_hal::system::{CpuControl, Stack};
|
||||
use esp_hal::system::{Cpu, CpuControl, Stack};
|
||||
#[cfg(xtensa)]
|
||||
use esp_hal::xtensa_lx::interrupt::free as interrupt_free;
|
||||
use esp_hal::{
|
||||
@ -25,13 +25,14 @@ use esp_hal::{
|
||||
#[cfg(riscv)]
|
||||
use esp_hal::{interrupt::software::SoftwareInterrupt, riscv::interrupt::free as interrupt_free};
|
||||
use esp_hal_embassy::InterruptExecutor;
|
||||
use esp_preempt::{CurrentThreadHandle, semaphore::Semaphore};
|
||||
use esp_radio::InitializationError;
|
||||
use esp_radio_preempt_driver::{
|
||||
self as preempt,
|
||||
semaphore::{SemaphoreHandle, SemaphoreKind},
|
||||
};
|
||||
use hil_test::mk_static;
|
||||
use portable_atomic::{AtomicUsize, Ordering};
|
||||
use portable_atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use static_cell::StaticCell;
|
||||
|
||||
#[allow(unused)] // compile test
|
||||
@ -193,7 +194,7 @@ mod tests {
|
||||
|
||||
let now = Instant::now();
|
||||
|
||||
preempt::usleep(10_000);
|
||||
CurrentThreadHandle::get().delay(Duration::from_millis(10));
|
||||
|
||||
hil_test::assert!(now.elapsed() >= Duration::from_millis(10));
|
||||
}
|
||||
@ -278,12 +279,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_esp_preempt_priority_inheritance(p: Peripherals) {
|
||||
use core::ffi::c_void;
|
||||
|
||||
use esp_radio_preempt_driver as preempt;
|
||||
use portable_atomic::{AtomicBool, Ordering};
|
||||
use preempt::semaphore::{SemaphoreHandle, SemaphoreKind};
|
||||
|
||||
#[cfg(riscv)]
|
||||
let sw_ints = SoftwareInterruptControl::new(p.SW_INTERRUPT);
|
||||
let timg0 = TimerGroup::new(p.TIMG0);
|
||||
@ -312,15 +307,15 @@ mod tests {
|
||||
// The medium priority task will assert that the high priority task has finished.
|
||||
|
||||
struct TestContext {
|
||||
ready_semaphore: SemaphoreHandle,
|
||||
mutex: SemaphoreHandle,
|
||||
ready_semaphore: Semaphore,
|
||||
mutex: Semaphore,
|
||||
high_priority_task_finished: AtomicBool,
|
||||
}
|
||||
let mut test_context = TestContext {
|
||||
// This semaphore signals the end of the test
|
||||
ready_semaphore: SemaphoreHandle::new(SemaphoreKind::Counting { max: 1, initial: 0 }),
|
||||
ready_semaphore: Semaphore::new_counting(0, 1),
|
||||
// We'll use this mutex to test priority inheritance
|
||||
mutex: SemaphoreHandle::new(SemaphoreKind::Mutex),
|
||||
mutex: Semaphore::new_mutex(false),
|
||||
high_priority_task_finished: AtomicBool::new(false),
|
||||
};
|
||||
|
||||
@ -395,12 +390,6 @@ mod tests {
|
||||
#[test]
|
||||
#[cfg(multi_core)]
|
||||
fn test_esp_preempt_smp(p: Peripherals) {
|
||||
use core::ffi::c_void;
|
||||
|
||||
use esp_hal::system::Cpu;
|
||||
use esp_radio_preempt_driver as preempt;
|
||||
use preempt::semaphore::{SemaphoreHandle, SemaphoreKind};
|
||||
|
||||
let sw_ints = SoftwareInterruptControl::new(p.SW_INTERRUPT);
|
||||
|
||||
let timg0 = TimerGroup::new(p.TIMG0);
|
||||
@ -409,12 +398,12 @@ mod tests {
|
||||
// increment a counter, if they are scheduled to run on their specific core.
|
||||
|
||||
struct TestContext {
|
||||
ready_semaphore: SemaphoreHandle,
|
||||
ready_semaphore: Semaphore,
|
||||
}
|
||||
let test_context = TestContext {
|
||||
// This semaphore signals the end of the test. Each test case will give it once it is
|
||||
// done.
|
||||
ready_semaphore: SemaphoreHandle::new(SemaphoreKind::Counting { max: 2, initial: 0 }),
|
||||
ready_semaphore: Semaphore::new_counting(0, 2),
|
||||
};
|
||||
|
||||
fn count_impl(context: &TestContext, core: Cpu) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user