diff --git a/rtic-common/src/lib.rs b/rtic-common/src/lib.rs index 03d0306373..2dd96731c2 100644 --- a/rtic-common/src/lib.rs +++ b/rtic-common/src/lib.rs @@ -1,4 +1,4 @@ -//! Crate +//! Utility structs that can be useful to other subcrates. #![no_std] #![deny(missing_docs)] diff --git a/rtic-common/src/wait_queue.rs b/rtic-common/src/wait_queue.rs index b1aa775714..4b1b0f3206 100644 --- a/rtic-common/src/wait_queue.rs +++ b/rtic-common/src/wait_queue.rs @@ -1,4 +1,4 @@ -//! ... +//! A wait queue implementation using a doubly linked list. use core::marker::PhantomPinned; use core::pin::Pin; @@ -8,15 +8,18 @@ use core::task::Waker; use critical_section as cs; /// A helper definition of a wait queue. -pub type WaitQueue = LinkedList; +pub type WaitQueue = DoublyLinkedList; -/// A FIFO linked list for a wait queue. -pub struct LinkedList { +/// An atomic, doubly linked, FIFO list for a wait queue. +/// +/// Atomicity is guaranteed by short [`critical_section`]s, so this list is _not_ lock free, +/// but it will not deadlock. +pub struct DoublyLinkedList { head: AtomicPtr>, // UnsafeCell<*mut Link> tail: AtomicPtr>, } -impl LinkedList { +impl DoublyLinkedList { /// Create a new linked list. pub const fn new() -> Self { Self { @@ -26,7 +29,7 @@ impl LinkedList { } } -impl LinkedList { +impl DoublyLinkedList { const R: Ordering = Ordering::Relaxed; /// Pop the first element in the queue. @@ -130,7 +133,7 @@ impl Link { } /// Remove this link from a linked list. - pub fn remove_from_list(&self, list: &LinkedList) { + pub fn remove_from_list(&self, list: &DoublyLinkedList) { cs::with(|_| { // Make sure all previous writes are visible core::sync::atomic::fence(Ordering::SeqCst); @@ -172,7 +175,7 @@ impl Link { } #[cfg(test)] -impl LinkedList { +impl DoublyLinkedList { fn print(&self) { cs::with(|_| { // Make sure all previous writes are visible @@ -232,7 +235,7 @@ mod tests { #[test] fn linked_list() { - let wq = LinkedList::::new(); + let wq = DoublyLinkedList::::new(); let i1 = Link::new(10); let i2 = Link::new(11); diff --git a/rtic-macros/src/codegen/bindings.rs b/rtic-macros/src/codegen/bindings.rs index 6c214cdb1f..c328ee0be8 100644 --- a/rtic-macros/src/codegen/bindings.rs +++ b/rtic-macros/src/codegen/bindings.rs @@ -1,10 +1,3 @@ -#[cfg(not(any( - feature = "cortex-m-source-masking", - feature = "cortex-m-basepri", - feature = "test-template" -)))] -compile_error!("No backend selected"); - #[cfg(any(feature = "cortex-m-source-masking", feature = "cortex-m-basepri"))] pub use cortex::*; diff --git a/rtic-macros/src/codegen/bindings/template.rs b/rtic-macros/src/codegen/bindings/template.rs index a33bae8ef9..690dfb0387 100644 --- a/rtic-macros/src/codegen/bindings/template.rs +++ b/rtic-macros/src/codegen/bindings/template.rs @@ -43,6 +43,6 @@ pub fn interrupt_exit(_app: &App, _analysis: &CodegenAnalysis) -> Vec Vec { +pub fn async_prio_limit(_app: &App, _analysis: &CodegenAnalysis) -> Vec { vec![] } diff --git a/rtic-macros/src/lib.rs b/rtic-macros/src/lib.rs index cd2a9245db..3a655977d6 100644 --- a/rtic-macros/src/lib.rs +++ b/rtic-macros/src/lib.rs @@ -4,87 +4,110 @@ )] //deny_warnings_placeholder_for_ci -use proc_macro::TokenStream; -use std::{env, fs, path::Path}; +macro_rules! with_backend { + (mod: [$($mod:tt),*]) => { + $( + with_backend!{ mod $mod; } + )* + }; + ($($tokens:tt)*) => { + #[cfg(any( + feature = "cortex-m-source-masking", + feature = "cortex-m-basepri", + feature = "test-template" + ))] + $($tokens)* + }; +} -mod analyze; -mod check; -mod codegen; -mod syntax; +with_backend! { mod: [analyze, check, codegen, syntax] } +with_backend! { use std::{fs, env, path::Path}; } +with_backend! { use proc_macro::TokenStream; } -// Used for mocking the API in testing -#[doc(hidden)] -#[proc_macro_attribute] -pub fn mock_app(args: TokenStream, input: TokenStream) -> TokenStream { - if let Err(e) = syntax::parse(args, input) { - e.to_compile_error().into() - } else { - "fn main() {}".parse().unwrap() +with_backend! { + // Used for mocking the API in testing + #[doc(hidden)] + #[proc_macro_attribute] + pub fn mock_app(args: TokenStream, input: TokenStream) -> TokenStream { + if let Err(e) = syntax::parse(args, input) { + e.to_compile_error().into() + } else { + "fn main() {}".parse().unwrap() + } } } -/// Attribute used to declare a RTIC application -/// -/// For user documentation see the [RTIC book](https://rtic.rs) -/// -/// # Panics -/// -/// Should never panic, cargo feeds a path which is later converted to a string -#[proc_macro_attribute] -pub fn app(args: TokenStream, input: TokenStream) -> TokenStream { - let (app, analysis) = match syntax::parse(args, input) { - Err(e) => return e.to_compile_error().into(), - Ok(x) => x, - }; +with_backend! { + /// Attribute used to declare a RTIC application + /// + /// For user documentation see the [RTIC book](https://rtic.rs) + /// + /// # Panics + /// + /// Should never panic, cargo feeds a path which is later converted to a string + #[proc_macro_attribute] + pub fn app(_args: TokenStream, _input: TokenStream) -> TokenStream { + let (app, analysis) = match syntax::parse(_args, _input) { + Err(e) => return e.to_compile_error().into(), + Ok(x) => x, + }; - if let Err(e) = check::app(&app, &analysis) { - return e.to_compile_error().into(); - } + if let Err(e) = check::app(&app, &analysis) { + return e.to_compile_error().into(); + } - let analysis = analyze::app(analysis, &app); + let analysis = analyze::app(analysis, &app); - let ts = codegen::app(&app, &analysis); + let ts = codegen::app(&app, &analysis); - // Default output path: /target/ - let mut out_dir = Path::new("target"); + // Default output path: /target/ + let mut out_dir = Path::new("target"); - // Get output directory from Cargo environment - // TODO don't want to break builds if OUT_DIR is not set, is this ever the case? - let out_str = env::var("OUT_DIR").unwrap_or_else(|_| "".to_string()); + // Get output directory from Cargo environment + // TODO don't want to break builds if OUT_DIR is not set, is this ever the case? + let out_str = env::var("OUT_DIR").unwrap_or_else(|_| "".to_string()); - if !out_dir.exists() { - // Set out_dir to OUT_DIR - out_dir = Path::new(&out_str); + if !out_dir.exists() { + // Set out_dir to OUT_DIR + out_dir = Path::new(&out_str); - // Default build path, annotated below: - // $(pwd)/target/thumbv7em-none-eabihf/debug/build/rtic-/out/ - // ///debug/build/rtic-/out/ - // - // traverse up to first occurrence of TARGET, approximated with starts_with("thumbv") - // and use the parent() of this path - // - // If no "target" directory is found, / is used - for path in out_dir.ancestors() { - if let Some(dir) = path.components().last() { - let dir = dir.as_os_str().to_str().unwrap(); + // Default build path, annotated below: + // $(pwd)/target/thumbv7em-none-eabihf/debug/build/rtic-/out/ + // ///debug/build/rtic-/out/ + // + // traverse up to first occurrence of TARGET, approximated with starts_with("thumbv") + // and use the parent() of this path + // + // If no "target" directory is found, / is used + for path in out_dir.ancestors() { + if let Some(dir) = path.components().last() { + let dir = dir.as_os_str().to_str().unwrap(); - if dir.starts_with("thumbv") || dir.starts_with("riscv") { - if let Some(out) = path.parent() { - out_dir = out; + if dir.starts_with("thumbv") || dir.starts_with("riscv") { + if let Some(out) = path.parent() { + out_dir = out; + break; + } + // If no parent, just use it + out_dir = path; break; } - // If no parent, just use it - out_dir = path; - break; } } } - } - // Try to write the expanded code to disk - if let Some(out_str) = out_dir.to_str() { - fs::write(format!("{out_str}/rtic-expansion.rs"), ts.to_string()).ok(); - } + // Try to write the expanded code to disk + if let Some(out_str) = out_dir.to_str() { + fs::write(format!("{out_str}/rtic-expansion.rs"), ts.to_string()).ok(); + } - ts.into() + ts.into() + } } + +#[cfg(not(any( + feature = "cortex-m-source-masking", + feature = "cortex-m-basepri", + feature = "test-template" +)))] +compile_error!("Cannot compile. No backend feature selected."); diff --git a/rtic-monotonics/Cargo.toml b/rtic-monotonics/Cargo.toml index b9145a245a..3c294ea728 100644 --- a/rtic-monotonics/Cargo.toml +++ b/rtic-monotonics/Cargo.toml @@ -11,10 +11,12 @@ authors = [ "Per Lindgren ", ] categories = ["concurrency", "embedded", "no-std", "asynchronous"] -description = "rtic-monotonics lib TODO" +description = "A library that provides implementations of the Monotonic trait from rtic-time" license = "MIT OR Apache-2.0" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[package.metadata.docs.rs] +features = ["cortex-m-systick", "rp2040", "nrf52840"] +rustdoc-flags = ["--cfg", "docsrs"] [dependencies] rtic-time = { version = "1.0.0-alpha.1", path = "../rtic-time" } diff --git a/rtic-monotonics/src/lib.rs b/rtic-monotonics/src/lib.rs index 04ce4e2451..507ee64c8b 100644 --- a/rtic-monotonics/src/lib.rs +++ b/rtic-monotonics/src/lib.rs @@ -1,10 +1,31 @@ -//! Crate +//! In-tree implementations of the [`rtic_time::Monotonic`] (reexported) trait for +//! timers & clocks found on commonly used microcontrollers. +//! +//! To enable the implementations, you must enable a feature for the specific MCU you're targeting. +//! +//! # Cortex-M Systick +//! The [`systick`] monotonic works on all cortex-M parts, and requires that the feature `cortex-m-systick` is enabled. +//! +//! # RP2040 +//! The RP2040 monotonics require that the `rp2040` feature is enabled. +//! +//! # nRF +//! nRF monotonics require that one of the available `nrf52*` features is enabled. +//! +//! All implementations of timers for the nRF52 family are documented here. Monotonics that +//! are not available on all parts in this family will have an `Available on crate features X only` +//! tag, describing what parts _do_ support that monotonic. Monotonics without an +//! `Available on crate features X only` tag are available on any `nrf52*` feature. +//! +// To build these docs correctly: +// RUSTFLAGS="--cfg docsrs" cargo doc --featuers cortex-m-systick,rp2040,nrf52840 #![no_std] #![deny(missing_docs)] //deny_warnings_placeholder_for_ci #![allow(incomplete_features)] #![feature(async_fn_in_trait)] +#![cfg_attr(docsrs, feature(doc_cfg))] pub use rtic_time::{Monotonic, TimeoutError, TimerQueue}; diff --git a/rtic-monotonics/src/nrf.rs b/rtic-monotonics/src/nrf.rs index 0f6b97370d..f2fd3f6fcd 100644 --- a/rtic-monotonics/src/nrf.rs +++ b/rtic-monotonics/src/nrf.rs @@ -1,4 +1,4 @@ -//! Monotonic implementations for the nRF series of MCUs. +//! [`Monotonic`](super::Monotonic) implementations for the nRF series of MCUs. pub mod rtc; pub mod timer; diff --git a/rtic-monotonics/src/nrf/rtc.rs b/rtic-monotonics/src/nrf/rtc.rs index 2e23389f19..50087ab644 100644 --- a/rtic-monotonics/src/nrf/rtc.rs +++ b/rtic-monotonics/src/nrf/rtc.rs @@ -1,4 +1,4 @@ -//! RTIC Monotonic impl for the nRF RTCs. +//! [`Monotonic`] implementation for the nRF Real Time Clocks (RTC). //! //! # Example //! @@ -82,6 +82,10 @@ macro_rules! create_nrf_rtc1_monotonic_token { /// Register the Rtc2 interrupt for the monotonic. #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] +#[cfg_attr( + docsrs, + doc(cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))) +)] #[macro_export] macro_rules! create_nrf_rtc2_monotonic_token { () => {{ @@ -90,8 +94,11 @@ macro_rules! create_nrf_rtc2_monotonic_token { } macro_rules! make_rtc { - ($mono_name:ident, $rtc:ident, $overflow:ident, $tq:ident) => { + ($mono_name:ident, $rtc:ident, $overflow:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => { /// Monotonic timer queue implementation. + $( + #[cfg_attr(docsrs, doc(cfg($($doc)*)))] + )? pub struct $mono_name; static $overflow: AtomicU32 = AtomicU32::new(0); @@ -243,4 +250,4 @@ macro_rules! make_rtc { make_rtc!(Rtc0, RTC0, RTC0_OVERFLOWS, RTC0_TQ); make_rtc!(Rtc1, RTC1, RTC1_OVERFLOWS, RTC1_TQ); #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] -make_rtc!(Rtc2, RTC2, RTC2_OVERFLOWS, RTC2_TQ); +make_rtc!(Rtc2, RTC2, RTC2_OVERFLOWS, RTC2_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))); diff --git a/rtic-monotonics/src/nrf/timer.rs b/rtic-monotonics/src/nrf/timer.rs index 5e8fe932b4..6b7ade6a0c 100644 --- a/rtic-monotonics/src/nrf/timer.rs +++ b/rtic-monotonics/src/nrf/timer.rs @@ -1,4 +1,7 @@ -//! Monotonic impl for the 32-bit timers of the nRF series. +//! [`Monotonic`] impl for the 32-bit timers of the nRF series. +//! +//! Not all timers are available on all parts. Ensure that only the available +//! timers are exposed by having the correct `nrf52*` feature enabled for `rtic-monotonic`. //! //! # Example //! @@ -95,6 +98,10 @@ macro_rules! create_nrf_timer2_monotonic_token { } /// Register the Timer3 interrupt for the monotonic. +#[cfg_attr( + docsrs, + doc(cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))) +)] #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] #[macro_export] macro_rules! create_nrf_timer3_monotonic_token { @@ -104,6 +111,10 @@ macro_rules! create_nrf_timer3_monotonic_token { } /// Register the Timer4 interrupt for the monotonic. +#[cfg_attr( + docsrs, + doc(cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))) +)] #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] #[macro_export] macro_rules! create_nrf_timer4_monotonic_token { @@ -113,8 +124,11 @@ macro_rules! create_nrf_timer4_monotonic_token { } macro_rules! make_timer { - ($mono_name:ident, $timer:ident, $overflow:ident, $tq:ident) => { + ($mono_name:ident, $timer:ident, $overflow:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => { /// Monotonic timer queue implementation. + $( + #[cfg_attr(docsrs, doc(cfg($($doc)*)))] + )? pub struct $mono_name; static $overflow: AtomicU32 = AtomicU32::new(0); @@ -274,6 +288,6 @@ make_timer!(Timer0, TIMER0, TIMER0_OVERFLOWS, TIMER0_TQ); make_timer!(Timer1, TIMER1, TIMER1_OVERFLOWS, TIMER1_TQ); make_timer!(Timer2, TIMER2, TIMER2_OVERFLOWS, TIMER2_TQ); #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] -make_timer!(Timer3, TIMER3, TIMER3_OVERFLOWS, TIMER3_TQ); +make_timer!(Timer3, TIMER3, TIMER3_OVERFLOWS, TIMER3_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))); #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] -make_timer!(Timer4, TIMER4, TIMER4_OVERFLOWS, TIMER4_TQ); +make_timer!(Timer4, TIMER4, TIMER4_OVERFLOWS, TIMER4_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))); diff --git a/rtic-monotonics/src/rp2040.rs b/rtic-monotonics/src/rp2040.rs index 8c248f9cab..ac1fc1a7a5 100644 --- a/rtic-monotonics/src/rp2040.rs +++ b/rtic-monotonics/src/rp2040.rs @@ -1,4 +1,4 @@ -//! A monotonic implementation for RP2040's Timer peripheral. +//! [`Monotonic`] implementation for RP2040's Timer peripheral. //! //! # Example //! diff --git a/rtic-monotonics/src/systick.rs b/rtic-monotonics/src/systick.rs index cba9aa290d..0f215a7c3c 100644 --- a/rtic-monotonics/src/systick.rs +++ b/rtic-monotonics/src/systick.rs @@ -1,6 +1,14 @@ -//! A monotonics based on Cortex-M SysTick. Note that this implementation is inefficient as it -//! ticks, and generates interrupts, at a constant rate. +//! [`Monotonic`] based on Cortex-M SysTick. Note: this implementation is inefficient as it +//! ticks and generates interrupts at a constant rate. //! +//! Currently, the following tick rates are supported: +//! +//! | Feature | Tick rate | Precision | +//! |:----------------:|----------:|----------:| +//! | (none / default) | 1 Hz | 1 ms | +//! | systick-100hz | 100 Hz | 10 ms | +//! | systick-10khz | 10 KHz | 0.1 ms | + //! # Example //! //! ``` diff --git a/rtic-sync/src/arbiter.rs b/rtic-sync/src/arbiter.rs index d50b1ea9b5..deb0a4f8c8 100644 --- a/rtic-sync/src/arbiter.rs +++ b/rtic-sync/src/arbiter.rs @@ -1,4 +1,27 @@ -//! Crate +//! A Mutex-like FIFO with unlimited-waiter for embedded systems. +//! +//! Example usage: +//! +//! ```rust +//! # async fn select(f1: F1, f2: F2) {} +//! use rtic_sync::arbiter::Arbiter; +//! +//! // Instantiate an Arbiter with a static lifetime. +//! static ARBITER: Arbiter = Arbiter::new(32); +//! +//! async fn run(){ +//! let write_42 = async move { +//! *ARBITER.access().await = 42; +//! }; +//! +//! let write_1337 = async move { +//! *ARBITER.access().await = 1337; +//! }; +//! +//! // Attempt to access the Arbiter concurrently. +//! select(write_42, write_1337).await; +//! } +//! ``` use core::cell::UnsafeCell; use core::future::poll_fn; @@ -45,7 +68,7 @@ impl Arbiter { } } - /// Get access to the inner value in the `Arbiter`. This will wait until access is granted, + /// Get access to the inner value in the [`Arbiter`]. This will wait until access is granted, /// for non-blocking access use `try_access`. pub async fn access(&self) -> ExclusiveAccess<'_, T> { let mut link_ptr: Option> = None; @@ -132,7 +155,7 @@ impl Arbiter { } } -/// This token represents exclusive access to the value protected by the `Arbiter`. +/// This token represents exclusive access to the value protected by the [`Arbiter`]. pub struct ExclusiveAccess<'a, T> { arbiter: &'a Arbiter, inner: &'a mut T, diff --git a/rtic-sync/src/channel.rs b/rtic-sync/src/channel.rs index b7b5a485fa..8c9f861d2e 100644 --- a/rtic-sync/src/channel.rs +++ b/rtic-sync/src/channel.rs @@ -1,4 +1,4 @@ -//! Crate +//! An async aware MPSC channel that can be used on no-alloc systems. use core::{ cell::UnsafeCell, diff --git a/rtic-time/src/lib.rs b/rtic-time/src/lib.rs index 1ed1e9d6ce..f0135b7517 100644 --- a/rtic-time/src/lib.rs +++ b/rtic-time/src/lib.rs @@ -1,4 +1,7 @@ -//! Crate +//! Time-related traits & structs. +//! +//! This crate contains basic definitions and utilities that can be used +//! to keep track of time. #![no_std] #![deny(missing_docs)] diff --git a/rtic-time/src/linked_list.rs b/rtic-time/src/linked_list.rs index c2a99676b2..b84b92db57 100644 --- a/rtic-time/src/linked_list.rs +++ b/rtic-time/src/linked_list.rs @@ -1,11 +1,12 @@ -//! ... - use core::marker::PhantomPinned; use core::pin::Pin; use core::sync::atomic::{AtomicPtr, Ordering}; use critical_section as cs; -/// A sorted linked list for the timer queue. +/// An atomic sorted linked list for the timer queue. +/// +/// Atomicity is guaranteed using very short [`critical_section`]s, so this list is _not_ +/// lock free, but it will not deadlock. pub(crate) struct LinkedList { head: AtomicPtr>, } diff --git a/rtic-time/src/monotonic.rs b/rtic-time/src/monotonic.rs index 513cc07bb8..ad79bf2053 100644 --- a/rtic-time/src/monotonic.rs +++ b/rtic-time/src/monotonic.rs @@ -1,4 +1,4 @@ -//! ... +//! A monotonic clock / counter definition. /// # A monotonic clock / counter definition. /// diff --git a/rtic/Cargo.toml b/rtic/Cargo.toml index 9a05b7532e..f28c9a721a 100644 --- a/rtic/Cargo.toml +++ b/rtic/Cargo.toml @@ -24,6 +24,9 @@ repository = "https://github.com/rtic-rs/rtic" version = "2.0.0-alpha.1" +[package.metadata.docs.rs] +features = ["rtic-macros/test-template"] + [lib] name = "rtic" diff --git a/rtic/src/lib.rs b/rtic/src/lib.rs index ac05d93d6c..d5f65bc32e 100644 --- a/rtic/src/lib.rs +++ b/rtic/src/lib.rs @@ -9,8 +9,8 @@ //! //! # Minimum Supported Rust Version (MSRV) //! -//! This crate is compiled and tested with the latest toolchain (rolling) as of the release date. -//! If you run into compilation errors, try the latest stable release of the rust toolchain. +//! This crate is compiled and tested with the latest nightly toolchain (rolling). +//! If you run into compilation errors, try the latest nightly release of the rust toolchain. //! //! # Semantic Versioning //!