mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-27 12:20:56 +00:00
Add more implementation docs (#4078)
This commit is contained in:
parent
e15e837246
commit
29ded39fe2
@ -12,26 +12,11 @@
|
||||
//! This crate abstracts the capabilities of FreeRTOS. The scheduler must implement the following
|
||||
//! capabilities:
|
||||
//!
|
||||
//! - A preemptive task scheduler
|
||||
//! - Mutexes
|
||||
//! - Semaphores
|
||||
//! - Queues
|
||||
//! - Timers (functions that are executed at a specific time)
|
||||
//!
|
||||
//! In order to hook up a scheduler, implement the `Scheduler` trait for a struct, and register it
|
||||
//! using the `scheduler_impl!()` macro. Only one scheduler can be registered in a firmware.
|
||||
//!
|
||||
//! Example:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! struct MyScheduler {}
|
||||
//!
|
||||
//! impl esp_preempt::Scheduler for MyScheduler {
|
||||
//! // impl goes here
|
||||
//! }
|
||||
//!
|
||||
//! esp_preempt::scheduler_impl!(static SCHEDULER: MyScheduler = MyScheduler {});
|
||||
//! ```
|
||||
//! - A preemptive task scheduler: [`Scheduler`]
|
||||
//! - Mutexes: [`mutex::MutexImplementation`]
|
||||
//! - Semaphores: [`semaphore::SemaphoreImplementation`]
|
||||
//! - Queues: [`queue::QueueImplementation`]
|
||||
//! - Timers (functions that are executed at a specific time): [`timer::TimerImplementation`]
|
||||
//!
|
||||
//! [`esp-preempt`]: https://crates.io/crates/esp-preempt
|
||||
|
||||
@ -170,6 +155,73 @@ macro_rules! scheduler_impl {
|
||||
///
|
||||
/// This trait needs to be implemented by a driver crate to integrate esp-radio with a software
|
||||
/// platform.
|
||||
///
|
||||
/// The following snippet demonstrates the boilerplate necessary to implement a scheduler using the
|
||||
/// `Scheduler` trait:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// struct MyScheduler {}
|
||||
///
|
||||
/// impl esp_radio_preempt_driver::Scheduler for MyScheduler {
|
||||
///
|
||||
/// fn initialized(&self) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn enable(&self) {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn disable(&self) {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn yield_task(&self) {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn yield_task_from_isr(&self) {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn max_task_priority(&self) -> u32 {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn task_create(
|
||||
/// &self,
|
||||
/// 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 {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn current_task(&self) -> *mut c_void {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn schedule_task_deletion(&self, task_handle: *mut c_void) {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn current_task_thread_semaphore(&self) -> SemaphorePtr {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn usleep(&self, us: u32) {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn now(&self) -> u64 {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// esp_radio_preempt_driver::scheduler_impl!(static SCHEDULER: MyScheduler = MyScheduler {});
|
||||
/// ```
|
||||
pub trait Scheduler: Send + Sync + 'static {
|
||||
/// This function is called by `esp_radio::init` to verify that the scheduler is properly set
|
||||
/// up.
|
||||
|
@ -1,4 +1,20 @@
|
||||
//! Mutexes
|
||||
//! # Mutexes (mutual exclusion)
|
||||
//!
|
||||
//! Mutexes are a synchronization primitive used to protect shared data from concurrent access.
|
||||
//! They allow only one thread at a time to access a critical section of code or data.
|
||||
//!
|
||||
//! ## Implementation
|
||||
//!
|
||||
//! Implement the `MutexImplementation` trait for an object, and use the
|
||||
//! `register_mutex_implementation` to register that implementation for esp-radio.
|
||||
//!
|
||||
//! See the [`MutexImplementation`] documentation for more information.
|
||||
//!
|
||||
//! ## Usage
|
||||
//!
|
||||
//! Users should use [`MutexHandle`] to interact with mutexes created by the driver implementation.
|
||||
//!
|
||||
//! > Note that the only expected user of this crate is esp-radio.
|
||||
|
||||
use core::ptr::NonNull;
|
||||
|
||||
@ -13,8 +29,48 @@ unsafe extern "Rust" {
|
||||
fn esp_preempt_mutex_unlock(mutex: MutexPtr) -> bool;
|
||||
}
|
||||
|
||||
/// A mutex (mutual exclusion) primitive.
|
||||
///
|
||||
/// The following snippet demonstrates the boilerplate necessary to implement a mutex using the
|
||||
/// `MutexImplementation` trait:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use esp_radio_preempt_driver::{
|
||||
/// mutex::{MutexImplementation, MutexPtr},
|
||||
/// register_mutex_implementation,
|
||||
/// };
|
||||
///
|
||||
/// struct MyMutex {
|
||||
/// // Mutex implementation details
|
||||
/// }
|
||||
///
|
||||
/// impl MutexImplementation for MyMutex {
|
||||
/// fn create(recursive: bool) -> MutexPtr {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn delete(mutex: MutexPtr) {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn lock(mutex: MutexPtr, timeout_us: Option<u32>) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn unlock(mutex: MutexPtr) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// register_mutex_implementation!(MyMutex);
|
||||
/// ```
|
||||
pub trait MutexImplementation {
|
||||
/// Creates a new mutex instance.
|
||||
///
|
||||
/// The mutex should start in the unlocked state.
|
||||
///
|
||||
/// If `recursive` is `true`, the mutex should support recursive locking (i.e. the mutex owner
|
||||
/// can lock the mutex multiple times).
|
||||
fn create(recursive: bool) -> MutexPtr;
|
||||
|
||||
/// Deletes a mutex instance.
|
||||
@ -34,7 +90,7 @@ pub trait MutexImplementation {
|
||||
///
|
||||
/// This function returns `true` if the mutex was locked, `false` if the timeout was reached.
|
||||
///
|
||||
/// Recursive mutexes can be re-locked by the mutex owner.
|
||||
/// Recursive mutexes can be re-locked by the mutex owner without blocking.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
@ -44,7 +100,8 @@ pub trait MutexImplementation {
|
||||
/// Unlocks a mutex.
|
||||
///
|
||||
/// This function returns `true` if the mutex was unlocked, `false` if the mutex wasn't locked,
|
||||
/// or the unlocking task was not the mutex owner.
|
||||
/// or the unlocking task was not the mutex owner. Unlocking a recursive mutex also returns
|
||||
/// `true` if the mutex's lock counter is successfully decremented.
|
||||
///
|
||||
/// Recursive mutexes are released only when `unlock` has been called for each preceding `lock`.
|
||||
///
|
||||
@ -83,6 +140,9 @@ macro_rules! register_mutex_implementation {
|
||||
};
|
||||
}
|
||||
|
||||
/// Mutex handle.
|
||||
///
|
||||
/// This handle is used to interact with mutexes created by the driver implementation.
|
||||
#[repr(transparent)]
|
||||
pub struct MutexHandle(MutexPtr);
|
||||
impl MutexHandle {
|
||||
|
@ -1,4 +1,20 @@
|
||||
//! Queues
|
||||
//! # Queues
|
||||
//!
|
||||
//! Queues are a synchronization primitive used to communicate between tasks.
|
||||
//! They allow tasks to send and receive data in a first-in-first-out (FIFO) manner.
|
||||
//!
|
||||
//! ## Implementation
|
||||
//!
|
||||
//! Implement the `QueueImplementation` trait for an object, and use the
|
||||
//! `register_queue_implementation` to register that implementation for esp-radio.
|
||||
//!
|
||||
//! See the [`QueueImplementation`] documentation for more information.
|
||||
//!
|
||||
//! ## Usage
|
||||
//!
|
||||
//! Users should use [`QueueHandle`] to interact with queues created by the driver implementation.
|
||||
//!
|
||||
//! > Note that the only expected user of this crate is esp-radio.
|
||||
|
||||
use core::ptr::NonNull;
|
||||
|
||||
@ -34,8 +50,73 @@ unsafe extern "Rust" {
|
||||
fn esp_preempt_queue_messages_waiting(queue: QueuePtr) -> usize;
|
||||
}
|
||||
|
||||
/// A queue primitive.
|
||||
///
|
||||
/// The following snippet demonstrates the boilerplate necessary to implement a queue using the
|
||||
/// `QueueImplementation` trait:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use esp_radio_preempt_driver::{
|
||||
/// queue::{QueueImplementation, QueuePtr},
|
||||
/// register_queue_implementation,
|
||||
/// };
|
||||
///
|
||||
/// struct MyQueue {
|
||||
/// // Queue implementation details
|
||||
/// }
|
||||
///
|
||||
/// impl QueueImplementation for MyQueue {
|
||||
/// fn create(capacity: usize, item_size: usize) -> QueuePtr {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn delete(queue: QueuePtr) {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn send_to_front(queue: QueuePtr, item: *const u8, timeout_us: Option<u32>) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn send_to_back(queue: QueuePtr, item: *const u8, timeout_us: Option<u32>) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn try_send_to_back_from_isr(
|
||||
/// queue: QueuePtr,
|
||||
/// item: *const u8,
|
||||
/// higher_prio_task_waken: Option<&mut bool>,
|
||||
/// ) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn receive(queue: QueuePtr, item: *mut u8, timeout_us: Option<u32>) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn try_receive_from_isr(
|
||||
/// queue: QueuePtr,
|
||||
/// item: *mut u8,
|
||||
/// higher_prio_task_waken: Option<&mut bool>,
|
||||
/// ) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn remove(queue: QueuePtr, item: *const u8) {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn messages_waiting(queue: QueuePtr) -> usize {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// register_queue_implementation!(MyQueue);
|
||||
/// ```
|
||||
pub trait QueueImplementation {
|
||||
/// Creates a new queue instance.
|
||||
/// Creates a new, empty queue instance.
|
||||
///
|
||||
/// The queue must have a capacity for `capacity` number of `item_size` byte items.
|
||||
fn create(capacity: usize, item_size: usize) -> QueuePtr;
|
||||
|
||||
/// Deletes a queue instance.
|
||||
@ -227,6 +308,9 @@ macro_rules! register_queue_implementation {
|
||||
};
|
||||
}
|
||||
|
||||
/// Queue handle.
|
||||
///
|
||||
/// This handle is used to interact with queues created by the driver implementation.
|
||||
#[repr(transparent)]
|
||||
pub struct QueueHandle(QueuePtr);
|
||||
impl QueueHandle {
|
||||
|
@ -1,4 +1,22 @@
|
||||
//! Semaphores
|
||||
//! Counting Semaphores
|
||||
//!
|
||||
//! Semaphores are synchronization primitives that allow threads to coordinate their execution.
|
||||
//! They are used to control access to a shared resource by limiting the number of threads that can
|
||||
//! access it simultaneously.
|
||||
//!
|
||||
//! ## Implementation
|
||||
//!
|
||||
//! Implement the `SemaphoreImplementation` trait for an object, and use the
|
||||
//! `register_semaphore_implementation` to register that implementation for esp-radio.
|
||||
//!
|
||||
//! See the [`SemaphoreImplementation`] documentation for more information.
|
||||
//!
|
||||
//! ## Usage
|
||||
//!
|
||||
//! Users should use [`SemaphoreHandle`] to interact with semaphores created by the driver
|
||||
//! implementation.
|
||||
//!
|
||||
//! > Note that the only expected user of this crate is esp-radio.
|
||||
|
||||
use core::ptr::NonNull;
|
||||
|
||||
@ -24,6 +42,63 @@ unsafe extern "Rust" {
|
||||
) -> bool;
|
||||
}
|
||||
|
||||
/// A counting semaphore primitive.
|
||||
///
|
||||
/// The following snippet demonstrates the boilerplate necessary to implement a semaphore using the
|
||||
/// `SemaphoreImplementation` trait:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use esp_radio_preempt_driver::{
|
||||
/// register_semaphore_implementation,
|
||||
/// semaphore::{SemaphoreImplementation, SemaphorePtr},
|
||||
/// };
|
||||
///
|
||||
/// struct MySemaphore {
|
||||
/// // Semaphore implementation details
|
||||
/// }
|
||||
///
|
||||
/// impl SemaphoreImplementation for MySemaphore {
|
||||
/// fn create(max: u32, initial: u32) -> SemaphorePtr {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn delete(semaphore: SemaphorePtr) {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn take(semaphore: SemaphorePtr, timeout_us: Option<u32>) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn give(semaphore: SemaphorePtr) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn try_give_from_isr(
|
||||
/// semaphore: SemaphorePtr,
|
||||
/// higher_prio_task_waken: Option<&mut bool>,
|
||||
/// ) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn current_count(semaphore: SemaphorePtr) -> u32 {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn try_take(semaphore: SemaphorePtr) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn try_take_from_isr(
|
||||
/// semaphore: SemaphorePtr,
|
||||
/// higher_prio_task_waken: Option<&mut bool>,
|
||||
/// ) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// register_semaphore_implementation!(MySemaphore);
|
||||
/// ```
|
||||
pub trait SemaphoreImplementation {
|
||||
/// Creates a new semaphore instance.
|
||||
fn create(max: u32, initial: u32) -> SemaphorePtr;
|
||||
@ -182,10 +257,15 @@ macro_rules! register_semaphore_implementation {
|
||||
};
|
||||
}
|
||||
|
||||
/// Semaphore handle.
|
||||
///
|
||||
/// This handle is used to interact with semaphores created by the driver implementation.
|
||||
#[repr(transparent)]
|
||||
pub struct SemaphoreHandle(SemaphorePtr);
|
||||
impl SemaphoreHandle {
|
||||
/// Creates a new semaphore instance.
|
||||
///
|
||||
/// The semaphore will have the specified initial and maximum values.
|
||||
pub fn new(initial: u32, max: u32) -> Self {
|
||||
let ptr = unsafe { esp_preempt_semaphore_create(initial, max) };
|
||||
Self(ptr)
|
||||
|
@ -1,4 +1,17 @@
|
||||
//! Timers
|
||||
//! Timers (callbacks scheduled to run in the future)
|
||||
//!
|
||||
//! ## Implementation
|
||||
//!
|
||||
//! Implement the `TimerImplementation` trait for an object, and use the
|
||||
//! `register_timer_implementation` to register that implementation for esp-radio.
|
||||
//!
|
||||
//! See the [`TimerImplementation`] documentation for more information.
|
||||
//!
|
||||
//! ## Usage
|
||||
//!
|
||||
//! Users should use [`TimerHandle`] to interact with timers created by the driver implementation.
|
||||
//!
|
||||
//! > Note that the only expected user of this crate is esp-radio.
|
||||
|
||||
use core::{ffi::c_void, ptr::NonNull};
|
||||
|
||||
@ -16,6 +29,41 @@ unsafe extern "Rust" {
|
||||
fn esp_preempt_timer_disarm(timer: TimerPtr);
|
||||
}
|
||||
|
||||
/// A timer implementation.
|
||||
///
|
||||
/// The following snippet demonstrates the boilerplate necessary to implement a timer using the
|
||||
/// `TimerImplementation` trait:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use esp_radio_preempt_driver::{
|
||||
/// register_timer_implementation,
|
||||
/// timer::{TimerImplementation, TimerPtr},
|
||||
/// };
|
||||
///
|
||||
/// struct MyTimer {
|
||||
/// // Timer implementation details
|
||||
/// }
|
||||
///
|
||||
/// impl TimerImplementation for MyTimer {
|
||||
/// fn create(function: unsafe extern "C" fn(*mut c_void), data: *mut c_void) -> TimerPtr {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn delete(mutex: MutexPtr) {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn arm(timer: TimerPtr, timeout: u64, periodic: bool) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn disarm(timer: TimerPtr) -> bool {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// register_timer_implementation!(MyTimer);
|
||||
/// ```
|
||||
pub trait TimerImplementation {
|
||||
/// Creates a new timer instance from the given callback.
|
||||
fn create(function: unsafe extern "C" fn(*mut c_void), data: *mut c_void) -> TimerPtr;
|
||||
@ -77,6 +125,9 @@ macro_rules! register_timer_implementation {
|
||||
};
|
||||
}
|
||||
|
||||
/// A timer handle.
|
||||
///
|
||||
/// This handle is used to interact with timers created by the driver implementation.
|
||||
#[repr(transparent)]
|
||||
pub struct TimerHandle(TimerPtr);
|
||||
impl TimerHandle {
|
||||
|
Loading…
x
Reference in New Issue
Block a user