svisual/
lib.rs

1//! Embedded client of [SVisual](https://github.com/Tyill/SVisual/) monitor
2//!
3//! Requires Rust 1.51
4
5#![no_std]
6#![deny(missing_docs)]
7
8/// Prelude module for easy import
9pub mod prelude;
10
11use embedded_hal::serial::Write;
12use heapless::LinearMap;
13use nb;
14
15/// Boolean signal that shows only positive front impulses
16pub struct OnlyFront(pub bool);
17
18/// Types supported by SVisual
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20#[repr(u8)]
21pub enum ValueType {
22    /// Boolean value
23    Bool = 0,
24    /// `i32` value
25    Int = 1,
26    /// `f32` value
27    Float = 2,
28}
29
30/// Value Record. Contents values of 1 signal. `P` is package size
31#[derive(Clone)]
32pub struct ValueRec<const P: usize> {
33    /// Only positive front
34    is_only_front: bool,
35    vtype: ValueType,
36    vals: [i32; P],
37}
38
39impl<const P: usize> ValueRec<P> {
40    /// Create empty Value Record
41    pub const fn new(vtype: ValueType) -> Self {
42        Self {
43            is_only_front: false,
44            vtype,
45            vals: [0; P],
46        }
47    }
48}
49
50/// Errors of adding values to container
51pub enum AddError {
52    /// Overflow of container
53    MapOverflow,
54}
55
56/// Go to next sendable value position
57pub trait NextValue {
58    /// Use previous values if no update will come.
59    /// `F` is send package function
60    fn next<F>(&mut self, f: F)
61    where
62        F: FnOnce(&Self);
63}
64
65/// Generic signal container
66#[derive(Clone, Copy)]
67pub struct SVStruct<M> {
68    current: usize,
69    map: M,
70}
71
72impl<M> core::ops::Deref for SVStruct<M> {
73    type Target = M;
74    fn deref(&self) -> &Self::Target {
75        &self.map
76    }
77}
78
79impl<M> core::ops::DerefMut for SVStruct<M> {
80    fn deref_mut(&mut self) -> &mut Self::Target {
81        &mut self.map
82    }
83}
84
85/// Map of signals
86pub type SVMap<const N: usize, const P: usize> = SVStruct<LinearMap<&'static str, ValueRec<P>, N>>;
87
88impl<const N: usize, const P: usize> SVMap<N, P> {
89    /// Create new instance
90    pub const fn new() -> Self {
91        Self {
92            current: 0,
93            map: LinearMap::new(),
94        }
95    }
96
97    /// Checks if package is empty
98    pub fn is_first(&self) -> bool {
99        self.current == 0
100    }
101
102    /// Checks if package is full
103    pub fn is_last(&self) -> bool {
104        self.current == P - 1
105    }
106
107    fn set_value(
108        &mut self,
109        name: &'static str,
110        vtype: ValueType,
111        val: i32,
112        only_pos_front: bool,
113    ) -> Result<(), AddError> {
114        if !self.map.contains_key(&name) {
115            if self.map.insert(name, ValueRec::new(vtype)).is_err() {
116                return Err(AddError::MapOverflow);
117            }
118        }
119
120        let vr = self.map.get_mut(name).unwrap();
121        vr.vals[self.current] = val;
122        vr.is_only_front = only_pos_front;
123
124        Ok(())
125    }
126
127    /// Update value of specified type at current time position
128    pub fn set<T: Value>(&mut self, name: &'static Name, value: T) -> Result<(), AddError> {
129        self.set_value(name, T::TYPE, value.to_i32(), T::ONLY_FRONT)
130    }
131}
132
133/// Supported value transfer type
134pub trait Value {
135    /// Associated `[ValueType]`
136    const TYPE: ValueType;
137    /// Only positive front
138    const ONLY_FRONT: bool;
139    /// `i32` representation
140    fn to_i32(self) -> i32;
141}
142
143impl Value for i32 {
144    const TYPE: ValueType = ValueType::Int;
145    const ONLY_FRONT: bool = false;
146    fn to_i32(self) -> i32 {
147        self
148    }
149}
150
151impl Value for f32 {
152    const TYPE: ValueType = ValueType::Float;
153    const ONLY_FRONT: bool = false;
154    fn to_i32(self) -> i32 {
155        self.to_bits() as i32
156    }
157}
158
159impl Value for bool {
160    const TYPE: ValueType = ValueType::Bool;
161    const ONLY_FRONT: bool = false;
162    fn to_i32(self) -> i32 {
163        self as i32
164    }
165}
166
167impl Value for OnlyFront {
168    const TYPE: ValueType = ValueType::Bool;
169    const ONLY_FRONT: bool = true;
170    fn to_i32(self) -> i32 {
171        self.0 as i32
172    }
173}
174
175impl<const N: usize, const P: usize> NextValue for SVMap<N, P> {
176    fn next<F>(&mut self, f: F)
177    where
178        F: FnOnce(&Self),
179    {
180        let previous = self.current;
181        self.current += 1;
182        if self.current >= P {
183            self.current -= P;
184            f(self);
185        }
186        for (_, v) in self.map.iter_mut() {
187            v.vals[self.current] = if v.is_only_front { 0 } else { v.vals[previous] };
188        }
189    }
190}
191
192/// Form and send package
193pub trait SendPackage<V> {
194    /// Error type
195    type Error;
196    /// Send package with module name
197    fn send_package(&mut self, module: &'static Name, values: &V) -> Result<(), Self::Error>;
198}
199
200/// Implementation of SendPackage for all that support `embedded-hal::serial::Write`
201impl<Tx, const N: usize, const P: usize> SendPackage<SVMap<N, P>> for Tx
202where
203    Tx: WriteIter,
204{
205    type Error = <Tx as WriteIter>::Error;
206    fn send_package(
207        &mut self,
208        module: &'static Name,
209        values: &SVMap<N, P>,
210    ) -> Result<(), Self::Error> {
211        use core::iter::repeat;
212        let vl_size = Name::MAX_SIZE + 4 + P * 4;
213        // Full package size
214        let full_size = (Name::MAX_SIZE + vl_size * values.map.len()) as u32;
215
216        // Open package
217        self.bwrite_iter(
218            "=begin="
219                .bytes()
220                .chain(full_size.to_le_bytes().iter().cloned())
221                // Identifier (name) of the module
222                .chain(module.bytes())
223                .chain(repeat(0).take(Name::MAX_SIZE - module.len())),
224        )?;
225        self.bflush()?;
226
227        for (&name, v) in values.map.iter() {
228            // Identifier (name) of signal
229            self.bwrite_iter(
230                name.bytes()
231                    .chain(repeat(0).take(Name::MAX_SIZE - name.len()))
232                    // Signal type
233                    .chain((v.vtype as i32).to_le_bytes().iter().cloned())
234                    // Values of one signal in package
235                    .chain(v.vals.iter().flat_map(|val| val.to_le_bytes())),
236            )?;
237            self.bflush()?;
238        }
239
240        // Close package
241        self.bwrite_iter("=end=".bytes())?;
242        self.bflush()?;
243
244        Ok(())
245    }
246}
247
248/// Compile-time chacked name string
249pub struct Name(&'static str);
250
251impl core::ops::Deref for Name {
252    type Target = str;
253    fn deref(&self) -> &Self::Target {
254        self.0
255    }
256}
257
258impl Name {
259    /// Maximum length of module/signal name
260    const MAX_SIZE: usize = 24;
261
262    /// New name instance
263    pub const fn new(name: &'static str) -> Self {
264        assert!(!name.is_empty());
265        assert!(name.len() < Self::MAX_SIZE);
266        assert!(!equal(name, "=end="));
267        assert!(!equal(name, "=begin="));
268        Self(name)
269    }
270}
271
272const fn equal(first: &'static str, second: &'static str) -> bool {
273    if first.len() != second.len() {
274        return false;
275    }
276    let fb = first.as_bytes();
277    let sb = second.as_bytes();
278    let mut i = 0;
279    while i < first.len() {
280        if fb[i] != sb[i] {
281            return false;
282        }
283        i += 1;
284    }
285    true
286}
287
288/// Write iterator
289pub trait WriteIter {
290    /// Error type
291    type Error;
292    /// Blocking write of iterator
293    fn bwrite_iter<WI>(&mut self, bytes: WI) -> Result<(), Self::Error>
294    where
295        WI: Iterator<Item = u8>;
296    /// Blocking flush
297    fn bflush(&mut self) -> Result<(), Self::Error>;
298}
299
300impl<Tx> WriteIter for Tx
301where
302    Tx: Write<u8>,
303{
304    type Error = <Tx as Write<u8>>::Error;
305
306    fn bwrite_iter<WI>(&mut self, mut bytes: WI) -> Result<(), Self::Error>
307    where
308        WI: Iterator<Item = u8>,
309    {
310        bytes.try_for_each(|c| nb::block!(self.write(c)))
311    }
312
313    fn bflush(&mut self) -> Result<(), Self::Error> {
314        nb::block!(self.flush())
315    }
316}