Skip to main content

strand_led_box_comms/
lib.rs

1// Copyright (C) The Strand-Braid Authors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Communication protocol types for the [Strand Camera](https://strawlab.org/strand-cam) LED Box device.
5//!
6//! This crate provides the data structures and constants for communicating
7//! with the Strand LED Box hardware device over serial communication.
8//!
9//! ## Features
10//!
11//! - `std`: Enables standard library support (default)
12//! - `print-defmt`: Enables defmt formatting for embedded debugging
13
14#![cfg_attr(not(feature = "std"), no_std)]
15#![warn(missing_docs)]
16
17extern crate serde;
18
19#[cfg(not(feature = "std"))]
20extern crate core as std;
21
22use serde::{Deserialize, Serialize};
23
24/// Maximum intensity value for LED channels.
25pub const MAX_INTENSITY: u16 = 16000;
26/// Communication protocol version.
27pub const COMM_VERSION: u16 = 3;
28/// Serial communication baud rate.
29pub const BAUD_RATE: u32 = 230_400;
30
31/// Messages sent to the LED box device.
32#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy)]
33#[cfg_attr(feature = "print-defmt", derive(defmt::Format))]
34pub enum ToDevice {
35    /// Set the device state.
36    DeviceState(DeviceState),
37    /// Send an echo request with 8 bytes.
38    EchoRequest8((u8, u8, u8, u8, u8, u8, u8, u8)),
39    /// Request the firmware version.
40    VersionRequest,
41}
42
43/// Messages received from the LED box device.
44#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy)]
45#[cfg_attr(feature = "print-defmt", derive(defmt::Format))]
46pub enum FromDevice {
47    /// Current device state.
48    DeviceState(DeviceState),
49    /// Echo response with 8 bytes.
50    EchoResponse8((u8, u8, u8, u8, u8, u8, u8, u8)),
51    /// Firmware version response.
52    VersionResponse(u16),
53    /// Confirmation that state was set.
54    StateWasSet,
55}
56
57/// Complete state of the LED box device with all four channels.
58#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy)]
59#[cfg_attr(feature = "print-defmt", derive(defmt::Format))]
60pub struct DeviceState {
61    /// Channel 1 state.
62    pub ch1: ChannelState,
63    /// Channel 2 state.
64    pub ch2: ChannelState,
65    /// Channel 3 state.
66    pub ch3: ChannelState,
67    /// Channel 4 state.
68    pub ch4: ChannelState,
69}
70
71impl DeviceState {
72    /// Create a default device state with all channels off.
73    pub const fn default() -> DeviceState {
74        DeviceState {
75            ch1: ChannelState::default(1),
76            ch2: ChannelState::default(2),
77            ch3: ChannelState::default(3),
78            ch4: ChannelState::default(4),
79        }
80    }
81}
82
83impl Default for DeviceState {
84    fn default() -> DeviceState {
85        DeviceState::default()
86    }
87}
88
89/// State of a single LED channel.
90#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy)]
91#[cfg_attr(feature = "print-defmt", derive(defmt::Format))]
92pub struct ChannelState {
93    /// Channel number (1-4).
94    pub num: u8,
95    /// Whether the channel is on or off.
96    pub on_state: OnState,
97    /// LED intensity level.
98    pub intensity: u16,
99}
100
101impl ChannelState {
102    /// Create a default channel state with the given channel number.
103    pub const fn default(num: u8) -> ChannelState {
104        ChannelState {
105            num,
106            on_state: OnState::Off,
107            intensity: MAX_INTENSITY,
108        }
109    }
110}
111
112impl Default for ChannelState {
113    fn default() -> ChannelState {
114        ChannelState::default(1)
115    }
116}
117
118/// LED channel on/off state.
119#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy)]
120#[cfg_attr(feature = "print-defmt", derive(defmt::Format))]
121#[derive(Default)]
122pub enum OnState {
123    #[default]
124    /// LED is turned off.
125    Off,
126    /// LED is constantly on.
127    ConstantOn,
128}
129
130impl std::fmt::Display for OnState {
131    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
132        std::fmt::Debug::fmt(self, fmt)
133    }
134}
135
136#[cfg(feature = "std")]
137impl strand_cam_enum_iter::EnumIter for OnState {
138    fn variants() -> Vec<Self> {
139        vec![OnState::Off, OnState::ConstantOn]
140    }
141}