Skip to content

Commit

Permalink
Release 0.2.0: Add implementations for GPIO types (#1)
Browse files Browse the repository at this point in the history
* Release 0.2.0: Add implementations for GPIO types
  • Loading branch information
jbeaurivage authored Dec 15, 2023
1 parent 613bc28 commit 17fe50e
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 62 deletions.
9 changes: 6 additions & 3 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ env:
CARGO_TERM_COLOR: always

jobs:
build:
check:
runs-on: rust-latest
steps:
- uses: actions/checkout@v3
- name: build
run: cargo build --verbose
- name: clippy
run: cargo clippy --verbose -- -Dwarnings
- name: rustfmt
run: cargo +nightly fmt --check
- name: test
run: cargo test --verbose
- name: Check semver
uses: obi1kenobi/cargo-semver-checks-action@v2

6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Unreleased

# 0.2.0

* Add `Instrument` implementations for GPIOs: `embedded-hal` version 1.0 and `embedded-hal` version 0.2 `OutputPins`
* Hide documentation for `TraceTaskFuture`, `TracePollFuture` and `TraceTaskAndPollFuture`
* Improve documentation

# 0.1.0

* Initial version
11 changes: 9 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "embedded-trace"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
authors = ["Justin Beaurivage <[email protected]>"]
description = "A Future tracing utility for embedded systems"
Expand All @@ -9,4 +9,11 @@ license = "MIT OR Apache-2.0"
keywords = ["trace", "tracing", "async", "futures", "no_std"]

[dependencies]
pin-project-lite = "0.2.13"
pin-project-lite = "0.2.13"
embedded-hal_1 = { package = "embedded-hal", version = "1.0.0-rc.3" }
embedded-hal_0_2 = { package = "embedded-hal", version = "0.2.7", optional = true}

[features]

[package.metadata.docs.rs]
all-features = true
62 changes: 34 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ A `Future` tracing utility for embedded systems.
This crate aims to provide tools to measure the execution time and debug
`async` tasks and `Future`s for `#![no_std]` projects.

![gpio_trace](assets/gpio_trace.png)

# How to use this library

Two main traits are defined: `TraceFuture` and `Instrument`.
Expand All @@ -20,41 +22,45 @@ three provided methods call `on_enter` and `on_exit` when entering the
specified spans, respectively. Consult the `TraceFuture` trait
documentation for more information.

## `Instrument`
`Instrument` represents the mechanism by which `TraceFuture`'s methods
will signal when a span is entered or exited. Implement this trait on your
own types. For instance, a simple mechanism may be to set a GPIO pin HIGH
when entering the span, and setting it LOW when exiting.
## Instrument
Instrument represents the mechanism by which TraceFuture's methods
will signal when a span is entered or exited. You can implement this trait
on your own types. Some implementation for commonly used types are also
provided in the instruments module.

For instance, a simple mechanism may be to set a GPIO pin HIGH
when entering the span, and setting it LOW when exiting. This
instrumentation is provided in the instruments::gpio module.

### Supported GPIO implementations:

* Types implementing `embedded-hal` version 1.0 `OutputPin`
* Types implementing `embedded-hal` version 0.2 `OutputPin` (by enabling the `embedded-hal_0_2` Cargo feature)

## Example use
## Example use with GPIO instrumentation

```rust
use core::future::Future;
// `TraceFuture` must be in scope in order to use its methods.
use embedded_trace::{TraceFuture, Instrument};
use embedded_trace::{TraceFuture, Gpio, GpioRef};
use embedded_hal::digital::OutputPin;

/// A simulated GPIO pin that prints to `stdout` instead of setting a a physical pin's electrical state
struct FakeGpio;
async fn trace_my_future<F, P1, P2>(future: F, task_pin: P1, poll_pin: &mut P2)
where
F: Future,
P1: OutputPin,
P2: OutputPin
{
// `Gpio` can be used where we can take the pin...
let mut task_instrument = Gpio::new(task_pin);
// ...or `GpioRef` when all we have is a mutable reference to a pin.
let mut poll_instrument = GpioRef::new(poll_pin);

// Implement `Instrument` on our type
impl Instrument for FakeGpio {
fn on_enter(&mut self) {
println!("HIGH");
}
// Poll our future while tracing its execution.
future.trace_task_and_poll(&mut task_instrument, &mut poll_instrument).await;

fn on_exit(&mut self) {
println!("LOW");
}
// We can reclaim the pin taken by `Gpio`
let task_pin = task_instrument.free();
}
```

async fn trace_a_future<F: Future>(future: F){
let mut gpio = FakeGpio;

// Trace the task execution
future.trace_task(&mut gpio).await;

// Expedted output:
// > HIGH
// > LOW
}
```
Binary file added assets/gpio_trace.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
172 changes: 172 additions & 0 deletions src/instruments/gpio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
//! [`Instrument`] implementations for GPIO pins.
//!
//! Types implementing `embedded-hal v1.0`
//! [`OutputPin`](embedded_hal_1::digital::OutputPin) and `embedded-hal v0.2`
//! [`OutputPin`](embedded_hal_0_2::digital::v2::OutputPin) are supported.
use crate::Instrument;
use embedded_hal_1 as embedded_hal;

#[cfg(feature = "embedded-hal_0_2")]
use embedded_hal_0_2 as embedded_hal_legacy;

/// [`Instrument`] implementation for an [`OutputPin`] (`embedded-hal` version
/// 1.0).
///
/// This type is also available as [`GpioRef`], which does not consume the
/// underlying [`OutputPin`]. For an [`Instrument`] implementation which
/// supports `embedded-hal` version 0.2, see [`LegacyGpio`].
///
/// [`OutputPin`]: embedded_hal::digital::OutputPin
pub struct Gpio<P: embedded_hal::digital::OutputPin> {
pin: P,
}

impl<P: embedded_hal::digital::OutputPin> From<P> for Gpio<P> {
#[inline]
fn from(pin: P) -> Self {
Self::new(pin)
}
}

impl<P: embedded_hal::digital::OutputPin> Gpio<P> {
/// Create a new [`Gpio`].
#[inline]
pub fn new(pin: P) -> Self {
Self { pin }
}

/// Return the underlying [`OutputPin`](embedded_hal::digital::OutputPin).
#[inline]
pub fn free(self) -> P {
self.pin
}
}

impl<P: embedded_hal::digital::OutputPin> Instrument for Gpio<P> {
#[inline]
fn on_enter(&mut self) {
let _ = self.pin.set_high();
}

#[inline]
fn on_exit(&mut self) {
let _ = self.pin.set_low();
}
}

/// Reference-taking version of an [`Instrument`] implementation for an
/// [`OutputPin`] (`embedded-hal` version 1.0).
///
/// This type is also available as [`Gpio`], which does consumes the
/// underlying [`OutputPin`]. For an [`Instrument`] implementation which
/// supports `embedded-hal` version 0.2, see [`LegacyGpioRef`].
///
/// [`OutputPin`]: embedded_hal::digital::OutputPin
pub struct GpioRef<'a, P: embedded_hal::digital::OutputPin> {
pin: &'a mut P,
}

impl<'a, P: embedded_hal::digital::OutputPin> GpioRef<'a, P> {
/// Create a new [`GpioRef`].
#[inline]
pub fn new(pin: &'a mut P) -> Self {
Self { pin }
}
}

impl<'a, P: embedded_hal::digital::OutputPin> Instrument for GpioRef<'a, P> {
#[inline]
fn on_enter(&mut self) {
let _ = self.pin.set_high();
}

#[inline]
fn on_exit(&mut self) {
let _ = self.pin.set_low();
}
}

/// [`Instrument`] implementation for an [`OutputPin`] (`embedded-hal` version
/// 0.2).
///
/// This type is also available as [`LegacyGpioRef`], which does not consume the
/// underlying [`OutputPin`]. For an [`Instrument`] implementation which
/// supports `embedded-hal` version 1.0, see [`Gpio`].
///
/// [`OutputPin`]: embedded_hal::digital::OutputPin
#[cfg(feature = "embedded-hal_0_2")]
pub struct LegacyGpio<P: embedded_hal_legacy::digital::v2::OutputPin> {
pin: P,
}

#[cfg(feature = "embedded-hal_0_2")]
impl<P: embedded_hal_legacy::digital::v2::OutputPin> From<P> for LegacyGpio<P> {
fn from(pin: P) -> Self {
Self { pin }
}
}

#[cfg(feature = "embedded-hal_0_2")]
impl<P: embedded_hal_legacy::digital::v2::OutputPin> LegacyGpio<P> {
/// Create a new [`LegacyGpio`].
#[inline]
pub fn new(pin: P) -> Self {
Self { pin }
}

/// Return the underlying
/// [`OutputPin`](embedded_hal_legacy::digital::v2::OutputPin).
#[inline]
pub fn free(self) -> P {
self.pin
}
}

#[cfg(feature = "embedded-hal_0_2")]
impl<P: embedded_hal_legacy::digital::v2::OutputPin> Instrument for LegacyGpio<P> {
#[inline]
fn on_enter(&mut self) {
let _ = self.pin.set_high();
}

#[inline]
fn on_exit(&mut self) {
let _ = self.pin.set_low();
}
}

/// Reference-taking version of an [`Instrument`] implementation for an
/// [`OutputPin`] (`embedded-hal` version 0.2).
///
/// This type is also available as [`LegacyGpio`], which consumes the
/// underlying [`OutputPin`]. For an [`Instrument`] implementation which
/// supports `embedded-hal` version 1.0, see [`GpioRef`].
///
/// [`OutputPin`]: embedded_hal::digital::OutputPin
#[cfg(feature = "embedded-hal_0_2")]
pub struct LegacyGpioRef<'a, P: embedded_hal_legacy::digital::v2::OutputPin> {
pin: &'a mut P,
}

#[cfg(feature = "embedded-hal_0_2")]
impl<'a, P: embedded_hal_legacy::digital::v2::OutputPin> LegacyGpioRef<'a, P> {
/// Create a new [`LegacyGpioRef`].
#[inline]
pub fn new(pin: &'a mut P) -> Self {
Self { pin }
}
}

#[cfg(feature = "embedded-hal_0_2")]
impl<'a, P: embedded_hal_legacy::digital::v2::OutputPin> Instrument for LegacyGpioRef<'a, P> {
#[inline]
fn on_enter(&mut self) {
let _ = self.pin.set_high();
}

#[inline]
fn on_exit(&mut self) {
let _ = self.pin.set_low();
}
}
4 changes: 4 additions & 0 deletions src/instruments/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//! [`Instrument`](crate::Instrument) implementations for various types.
pub mod gpio;
pub use gpio::*;
Loading

0 comments on commit 17fe50e

Please sign in to comment.