Skip to content

Commit

Permalink
Add async utils for blinking LEDs
Browse files Browse the repository at this point in the history
  • Loading branch information
uklotzde committed Aug 30, 2023
1 parent 5cd8c98 commit 6fdcfe1
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 22 deletions.
12 changes: 10 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[package]
name = "djio"
description = "DJ Hardware Control(ler) Support"
version = "0.0.12"
version = "0.0.13"
license = "MPL-2.0"
readme = "README.md"
repository = "https://github.com/uklotzde/djio"
Expand All @@ -25,6 +25,7 @@ strum = { version = "0.25.0", features = ["derive"] }
thiserror = "1.0.47"

# Optional dependencies
discro = { version = "0.11.0", optional = true }
midir = { version = "0.9.1", optional = true }
tokio = { version = "1.32.0", default-features = false, optional = true }

Expand All @@ -42,11 +43,18 @@ hidapi = "2.4.1"
pretty_env_logger = "0.5.0"

[features]
default = ["all-controllers", "midir", "controller-thread"]
default = [
"all-controllers",
"midir",
"spawn-blinking-led-task",
"controller-thread",
]
hid = ["dep:hidapi"]
jack = ["midir?/jack"]
midi = []
midir = ["dep:midir"]
blinking-led-task = ["dep:discro", "discro/tokio", "dep:tokio", "tokio/time"]
spawn-blinking-led-task = ["blinking-led-task", "tokio/rt"]
controller-thread = ["dep:tokio", "tokio/rt", "tokio/time"]

# Controller support features
Expand Down
9 changes: 7 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,14 @@ pub use self::input::{
};

mod output;
#[cfg(feature = "blinking-led-task")]
pub use self::output::blinking_led_task;
#[cfg(feature = "spawn-blinking-led-task")]
pub use self::output::spawn_blinking_led_task;
pub use self::output::{
BlinkingLedsOutput, BlinkingLedsTicker, ControlOutputGateway, DimLedOutput, LedOutput,
LedState, OutputError, OutputResult, RgbLedOutput, SendOutputsError, VirtualLed,
BlinkingLedOutput, BlinkingLedTicker, ControlOutputGateway, DimLedOutput, LedOutput, LedState,
OutputError, OutputResult, RgbLedOutput, SendOutputsError, VirtualLed,
DEFAULT_BLINKING_LED_PERIOD,
};

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down
33 changes: 33 additions & 0 deletions src/output/blinking_led_task.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: The djio authors
// SPDX-License-Identifier: MPL-2.0

use std::{future::Future, time::Duration};

use discro::{new_pubsub, Publisher, Subscriber};

use crate::{BlinkingLedOutput, BlinkingLedTicker};

#[allow(clippy::manual_async_fn)] // Explicit return type to to enforce the trait bounds
pub fn blinking_led_task(
period: Duration,
publisher: Publisher<BlinkingLedOutput>,
) -> impl Future<Output = ()> + Send + 'static {
async move {
let mut ticker = BlinkingLedTicker::default();
let mut interval = tokio::time::interval(period);
loop {
interval.tick().await;
let output = ticker.tick();
publisher.write(output);
}
}
}

#[cfg(feature = "spawn-blinking-led-task")]
#[must_use]
pub fn spawn_blinking_led_task(period: Duration) -> Subscriber<BlinkingLedOutput> {
let (publisher, subscriber) = new_pubsub(BlinkingLedOutput::ON);
let task = blinking_led_task(period, publisher);
tokio::spawn(task);
subscriber
}
46 changes: 28 additions & 18 deletions src/output/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use std::{
borrow::Cow,
ops::{Deref, DerefMut},
time::Duration,
};

use futures::StreamExt as _;
Expand All @@ -15,6 +16,13 @@ use thiserror::Error;

use crate::{Control, ControlValue};

#[cfg(feature = "blinking-led-task")]
mod blinking_led_task;
#[cfg(feature = "blinking-led-task")]
pub use blinking_led_task::blinking_led_task;
#[cfg(feature = "spawn-blinking-led-task")]
pub use blinking_led_task::spawn_blinking_led_task;

#[derive(Debug, Error)]
pub enum OutputError {
#[error("disconnected")]
Expand Down Expand Up @@ -171,53 +179,55 @@ impl LedState {
/// the periodic switching takes over.
#[must_use]
pub const fn initial_output(self) -> LedOutput {
self.output(BlinkingLedsOutput::ON)
self.output(BlinkingLedOutput::ON)
}

/// LED output depending on the current blinking state
#[must_use]
pub const fn output(self, blinking_leds_output: BlinkingLedsOutput) -> LedOutput {
pub const fn output(self, blinking_led_output: BlinkingLedOutput) -> LedOutput {
match self {
Self::Off => LedOutput::Off,
Self::BlinkFast => blinking_leds_output.fast,
Self::BlinkSlow => blinking_leds_output.slow,
Self::BlinkFast => blinking_led_output.fast,
Self::BlinkSlow => blinking_led_output.slow,
Self::On => LedOutput::On,
}
}
}

pub const DEFAULT_BLINKING_LED_PERIOD: Duration = Duration::from_millis(250);

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BlinkingLedsOutput {
pub struct BlinkingLedOutput {
pub fast: LedOutput,
pub slow: LedOutput,
}

impl BlinkingLedsOutput {
impl BlinkingLedOutput {
pub const ON: Self = Self {
fast: LedOutput::On,
slow: LedOutput::On,
};
}

#[derive(Debug, Default)]
pub struct BlinkingLedsTicker(usize);
pub struct BlinkingLedTicker(usize);

impl BlinkingLedsTicker {
fn output_from_value(value: usize) -> BlinkingLedsOutput {
impl BlinkingLedTicker {
fn output_from_value(value: usize) -> BlinkingLedOutput {
match value & 0b11 {
0b00 => BlinkingLedsOutput {
0b00 => BlinkingLedOutput {
fast: LedOutput::On,
slow: LedOutput::On,
},
0b01 => BlinkingLedsOutput {
0b01 => BlinkingLedOutput {
fast: LedOutput::Off,
slow: LedOutput::On,
},
0b10 => BlinkingLedsOutput {
0b10 => BlinkingLedOutput {
fast: LedOutput::On,
slow: LedOutput::Off,
},
0b11 => BlinkingLedsOutput {
0b11 => BlinkingLedOutput {
fast: LedOutput::Off,
slow: LedOutput::Off,
},
Expand All @@ -226,22 +236,22 @@ impl BlinkingLedsTicker {
}

#[must_use]
pub fn tick(&mut self) -> BlinkingLedsOutput {
pub fn tick(&mut self) -> BlinkingLedOutput {
let value = self.0;
self.0 = self.0.wrapping_add(1);
Self::output_from_value(value)
}

#[must_use]
pub fn output(&self) -> BlinkingLedsOutput {
pub fn output(&self) -> BlinkingLedOutput {
let value = self.0;
Self::output_from_value(value)
}

pub fn map_into_output_stream(
self,
periodic: impl futures::Stream<Item = ()> + 'static,
) -> impl futures::Stream<Item = BlinkingLedsOutput> {
) -> impl futures::Stream<Item = BlinkingLedOutput> {
futures::stream::unfold(
(self, Box::pin(periodic)),
|(mut ticker, mut periodic)| async move {
Expand Down Expand Up @@ -290,9 +300,9 @@ impl VirtualLed {
/// Update the blinking output
///
/// The output is updated accordingly while the state remains unchanged.
pub fn update_blinking_output(&mut self, blinking_leds_output: BlinkingLedsOutput) {
pub fn update_blinking_output(&mut self, blinking_led_output: BlinkingLedOutput) {
let Self { state, output } = self;
*output = state.output(blinking_leds_output);
*output = state.output(blinking_led_output);
}
}

Expand Down

0 comments on commit 6fdcfe1

Please sign in to comment.