Skip to content

Commit

Permalink
Merge branch 'master' into portable-atomic
Browse files Browse the repository at this point in the history
  • Loading branch information
korken89 authored Jun 23, 2024
2 parents 224a311 + 9aeae03 commit 6d0ede5
Show file tree
Hide file tree
Showing 16 changed files with 228 additions and 11 deletions.
1 change: 1 addition & 0 deletions rtic-macros/src/syntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub struct AppArgs {
pub dispatchers: Dispatchers,

/// Backend-specific arguments
#[allow(dead_code)]
pub backend: Option<BackendArgs>,
}

Expand Down
10 changes: 9 additions & 1 deletion rtic-monotonics/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,15 @@ This project adheres to [Semantic Versioning](http://semver.org/).

For each category, *Added*, *Changed*, *Fixed* add new entries at the top!

## Unreleased - v2.0.0
## Unreleased

## v2.0.1 - 2024-06-02

### Changed

- Make monotonics created with their respective macros public

## v2.0.0 - 2024-05-29

### Changed

Expand Down
2 changes: 1 addition & 1 deletion rtic-monotonics/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rtic-monotonics"
version = "2.0.0"
version = "2.0.1"

edition = "2021"
authors = [
Expand Down
2 changes: 1 addition & 1 deletion rtic-monotonics/src/imxrt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ macro_rules! __internal_create_imxrt_timer_interrupt {
macro_rules! __internal_create_imxrt_timer_struct {
($name:ident, $mono_backend:ident, $timer:ident, $tick_rate_hz:expr) => {
/// A `Monotonic` based on the GPT peripheral.
struct $name;
pub struct $name;

impl $name {
/// Starts the `Monotonic`.
Expand Down
2 changes: 1 addition & 1 deletion rtic-monotonics/src/nrf/rtc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ macro_rules! __internal_create_nrf_rtc_interrupt {
macro_rules! __internal_create_nrf_rtc_struct {
($name:ident, $mono_backend:ident, $timer:ident) => {
/// A `Monotonic` based on the nRF RTC peripheral.
struct $name;
pub struct $name;

impl $name {
/// Starts the `Monotonic`.
Expand Down
2 changes: 1 addition & 1 deletion rtic-monotonics/src/nrf/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ macro_rules! __internal_create_nrf_timer_interrupt {
macro_rules! __internal_create_nrf_timer_struct {
($name:ident, $mono_backend:ident, $timer:ident, $tick_rate_hz:expr) => {
/// A `Monotonic` based on the nRF Timer peripheral.
struct $name;
pub struct $name;

impl $name {
/// Starts the `Monotonic`.
Expand Down
2 changes: 1 addition & 1 deletion rtic-monotonics/src/rp2040.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl TimerQueueBackend for TimerBackend {
macro_rules! rp2040_timer_monotonic {
($name:ident) => {
/// A `Monotonic` based on the RP2040 Timer peripheral.
struct $name;
pub struct $name;

impl $name {
/// Starts the `Monotonic`.
Expand Down
3 changes: 2 additions & 1 deletion rtic-monotonics/src/stm32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ macro_rules! __internal_create_stm32_timer_interrupt {
#[macro_export]
macro_rules! __internal_create_stm32_timer_struct {
($name:ident, $mono_backend:ident, $timer:ident, $tick_rate_hz:expr) => {
struct $name;
/// A `Monotonic` based on an STM32 timer peripheral.
pub struct $name;

impl $name {
/// Starts the `Monotonic`.
Expand Down
2 changes: 1 addition & 1 deletion rtic-monotonics/src/systick.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ macro_rules! systick_monotonic {
};
($name:ident, $tick_rate_hz:expr) => {
/// A `Monotonic` based on SysTick.
struct $name;
pub struct $name;

impl $name {
/// Starts the `Monotonic`.
Expand Down
1 change: 1 addition & 0 deletions rtic-sync/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ For each category, _Added_, _Changed_, _Fixed_ add new entries at the top!
### Added

- `defmt v0.3` derives added and forwarded to `embedded-hal(-x)` crates.
- signal structure

## v1.2.0 - 2024-01-10

Expand Down
3 changes: 2 additions & 1 deletion rtic-sync/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ embedded-hal-bus = { version = "0.1.0", features = ["async"] }
defmt-03 = { package = "defmt", version = "0.3", optional = true }

[dev-dependencies]
static_cell = "2.1.0"
tokio = { version = "1", features = ["rt", "macros", "time"] }

[features]
default = []
testing = ["critical-section/std", "rtic-common/testing"]
defmt-03 = ["dep:defmt-03", "embedded-hal/defmt-03", "embedded-hal-async/defmt-03", "embedded-hal-bus/defmt-03"]
defmt-03 = ["dep:defmt-03", "embedded-hal/defmt-03", "embedded-hal-async/defmt-03", "embedded-hal-bus/defmt-03"]
1 change: 1 addition & 0 deletions rtic-sync/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use defmt_03 as defmt;
pub mod arbiter;
pub mod channel;
pub use portable_atomic;
pub mod signal;

#[cfg(test)]
#[macro_use]
Expand Down
201 changes: 201 additions & 0 deletions rtic-sync/src/signal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
//! A "latest only" value store with unlimited writers and async waiting.

use core::{cell::UnsafeCell, future::poll_fn, task::Poll};
use rtic_common::waker_registration::CriticalSectionWakerRegistration;

/// Basically an Option but for indicating
/// whether the store has been set or not
#[derive(Clone, Copy)]
enum Store<T> {
Set(T),
Unset,
}

/// A "latest only" value store with unlimited writers and async waiting.
pub struct Signal<T: Copy> {
waker: CriticalSectionWakerRegistration,
store: UnsafeCell<Store<T>>,
}

impl<T: Copy> Default for Signal<T> {
fn default() -> Self {
Self::new()
}
}

unsafe impl<T: Copy> Send for Signal<T> {}
unsafe impl<T: Copy> Sync for Signal<T> {}

impl<T: Copy> Signal<T> {
/// Create a new signal.
pub const fn new() -> Self {
Self {
waker: CriticalSectionWakerRegistration::new(),
store: UnsafeCell::new(Store::Unset),
}
}

/// Split the signal into a writer and reader.
pub fn split(&self) -> (SignalWriter<T>, SignalReader<T>) {
(SignalWriter { parent: self }, SignalReader { parent: self })
}
}

/// Fascilitates the writing of values to a Signal.
#[derive(Clone)]
pub struct SignalWriter<'a, T: Copy> {
parent: &'a Signal<T>,
}

impl<'a, T: Copy> SignalWriter<'a, T> {
/// Write a raw Store value to the Signal.
fn write_inner(&mut self, value: Store<T>) {
critical_section::with(|_| {
// SAFETY: in a cs: exclusive access
unsafe { self.parent.store.get().replace(value) };
});

self.parent.waker.wake();
}

/// Write a value to the Signal.
pub fn write(&mut self, value: T) {
self.write_inner(Store::Set(value));
}

/// Clear the stored value in the Signal (if any).
pub fn clear(&mut self) {
self.write_inner(Store::Unset);
}
}

/// Fascilitates the async reading of values from the Signal.
pub struct SignalReader<'a, T: Copy> {
parent: &'a Signal<T>,
}

impl<'a, T: Copy> SignalReader<'a, T> {
/// Immediately read and evict the latest value stored in the Signal.
fn take(&mut self) -> Store<T> {
critical_section::with(|_| {
// SAFETY: in a cs: exclusive access
unsafe { self.parent.store.get().replace(Store::Unset) }
})
}

/// Returns a pending value if present, or None if no value is available.
///
/// Upon read, the stored value is evicted.
pub fn try_read(&mut self) -> Option<T> {
match self.take() {
Store::Unset => None,
Store::Set(value) => Some(value),
}
}

/// Wait for a new value to be written and read it.
///
/// If a value is already pending it will be returned immediately.
///
/// Upon read, the stored value is evicted.
pub async fn wait(&mut self) -> T {
poll_fn(|ctx| {
self.parent.waker.register(ctx.waker());
match self.take() {
Store::Unset => Poll::Pending,
Store::Set(value) => Poll::Ready(value),
}
})
.await
}

/// Wait for a new value to be written and read it.
///
/// If a value is already pending, it will be evicted and a new
/// value must be written for the wait to resolve.
///
/// Upon read, the stored value is evicted.
pub async fn wait_fresh(&mut self) -> T {
self.take();
self.wait().await
}
}

/// Convenience macro for creating a Signal.
#[macro_export]
macro_rules! make_signal {
( $T:ty ) => {{
static SIGNAL: Signal<$T> = Signal::new();

SIGNAL.split()
}};
}

#[cfg(test)]
mod tests {
use static_cell::StaticCell;

use super::*;

#[test]
fn empty() {
let (_writer, mut reader) = make_signal!(u32);

assert!(reader.try_read().is_none());
}

#[test]
fn ping_pong() {
let (mut writer, mut reader) = make_signal!(u32);

writer.write(0xde);
assert!(reader.try_read().is_some_and(|value| value == 0xde));
}

#[test]
fn latest() {
let (mut writer, mut reader) = make_signal!(u32);

writer.write(0xde);
writer.write(0xad);
writer.write(0xbe);
writer.write(0xef);
assert!(reader.try_read().is_some_and(|value| value == 0xef));
}

#[test]
fn consumption() {
let (mut writer, mut reader) = make_signal!(u32);

writer.write(0xaa);
assert!(reader.try_read().is_some_and(|value| value == 0xaa));
assert!(reader.try_read().is_none());
}

#[tokio::test]
async fn pending() {
let (mut writer, mut reader) = make_signal!(u32);

writer.write(0xaa);

assert_eq!(reader.wait().await, 0xaa);
}

#[tokio::test]
async fn waiting() {
static READER: StaticCell<SignalReader<u32>> = StaticCell::new();
let (mut writer, reader) = make_signal!(u32);

writer.write(0xaa);

let reader = READER.init(reader);
let handle = tokio::spawn(reader.wait_fresh());

tokio::task::yield_now().await; // encourage tokio executor to poll reader future
assert!(!handle.is_finished()); // verify reader future did not resolve after poll

writer.write(0xab);

assert!(handle.await.is_ok_and(|value| value == 0xab));
}
}
4 changes: 3 additions & 1 deletion rtic-time/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ This project adheres to [Semantic Versioning](http://semver.org/).

For each category, *Added*, *Changed*, *Fixed* add new entries at the top!

## Unreleased - v2.0.0
## Unreleased

## v2.0.0 - 2024-05-29

### Added

### Changed

- Full rewrite of the `Monotonic` API.
- Now split into multiple traits:
- `Monotonic` - A user-facing trait that defines what the functionality of a monotonic is.
Expand Down
2 changes: 1 addition & 1 deletion xtask/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ clap = { version = "4", features = ["derive"] }
pretty_env_logger = "0.5.0"
log = "0.4.17"
rayon = { version = "1.6.1", optional = true }
diffy = "0.3.0"
diffy = "0.4.0"
1 change: 1 addition & 0 deletions xtask/src/cargo_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub enum CargoCommand<'a> {
},
ExampleCheck {
cargoarg: &'a Option<&'a str>,
#[allow(dead_code)]
platform: Platforms, // to tell which platform. If None, it assumes lm3s6965
example: &'a str,
target: Option<Target<'a>>,
Expand Down

0 comments on commit 6d0ede5

Please sign in to comment.