supmcu_rs/supmcu/
parsing.rs

1use crate::ParsingError;
2use byteorder::{ReadBytesExt, LE};
3use itertools::Itertools;
4use serde::{Deserialize, Serialize};
5use std::convert::TryFrom;
6use std::fmt;
7use std::io::{BufRead, Cursor};
8use std::mem::size_of;
9
10use async_graphql::{Enum, SimpleObject};
11
12#[cfg(feature = "pumqry")]
13use clap::ValueEnum;
14
15#[cfg(test)]
16use rand::rngs::SmallRng;
17
18use super::DEFAULT_RESPONSE_DELAY;
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Enum)]
21#[repr(u8)]
22/// Different possible data types that can be returned from SupMCU Telemetry
23pub enum DataType {
24    Str = b'S',
25    Char = b'c',
26    UINT8 = b'u',
27    INT8 = b't',
28    UINT16 = b's',
29    INT16 = b'n',
30    UINT32 = b'i',
31    INT32 = b'd',
32    UINT64 = b'l',
33    INT64 = b'k',
34    Float = b'f',
35    Double = b'F',
36    Hex8 = b'x',
37    Hex16 = b'z',
38}
39
40// e.g. SupMCUValue::I8.into() == 't'
41impl Into<char> for DataType {
42    fn into(self) -> char {
43        self as u8 as char
44    }
45}
46
47impl TryFrom<char> for DataType {
48    type Error = ParsingError;
49
50    fn try_from(c: char) -> Result<Self, ParsingError> {
51        match c {
52            'S' => Ok(DataType::Str),
53            'c' => Ok(DataType::Char),
54            'u' => Ok(DataType::UINT8),
55            't' => Ok(DataType::INT8),
56            's' => Ok(DataType::UINT16),
57            'n' => Ok(DataType::INT16),
58            'i' => Ok(DataType::UINT32),
59            'd' => Ok(DataType::INT32),
60            'l' => Ok(DataType::UINT64),
61            'k' => Ok(DataType::INT64),
62            'f' => Ok(DataType::Float),
63            'F' => Ok(DataType::Double),
64            'x' => Ok(DataType::Hex8),
65            'X' => Ok(DataType::Hex8),
66            'z' => Ok(DataType::Hex16),
67            'Z' => Ok(DataType::Hex16),
68            _ => Err(ParsingError::InvalidFormatCharacter(c)),
69        }
70    }
71}
72
73impl DataType {
74    /// Returns the size in bytes of the data type, unless the type is Str
75    pub fn get_byte_length(&self) -> Option<usize> {
76        match self {
77            DataType::Str => None,
78            DataType::Char => Some(1),
79            DataType::UINT8 => Some(size_of::<u8>()),
80            DataType::INT8 => Some(size_of::<i8>()),
81            DataType::UINT16 => Some(size_of::<u16>()),
82            DataType::INT16 => Some(size_of::<i16>()),
83            DataType::UINT32 => Some(size_of::<u32>()),
84            DataType::INT32 => Some(size_of::<i32>()),
85            DataType::UINT64 => Some(size_of::<u64>()),
86            DataType::INT64 => Some(size_of::<i64>()),
87            DataType::Float => Some(size_of::<f32>()),
88            DataType::Double => Some(size_of::<f64>()),
89            DataType::Hex8 => Some(1),
90            DataType::Hex16 => Some(2),
91        }
92    }
93}
94
95#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, SimpleObject)]
96/// A format to describe the module telemetry data
97pub struct SupMCUFormat {
98    format: Vec<DataType>,
99}
100
101impl IntoIterator for SupMCUFormat {
102    type Item = DataType;
103    type IntoIter = std::vec::IntoIter<Self::Item>;
104
105    fn into_iter(self) -> Self::IntoIter {
106        self.format.into_iter()
107    }
108}
109
110impl SupMCUFormat {
111    /// Creates a new SupMCUFormat from the valid format characters in a string
112    pub fn new(fmt_str: &str) -> Self {
113        let mut format = vec![];
114        for c in fmt_str.chars() {
115            if let Ok(t) = DataType::try_from(c) {
116                format.push(t);
117            }
118        }
119        SupMCUFormat { format }
120    }
121
122    /// Returns the byte length of the data that the format
123    /// specifies or `None` if there is a string type
124    pub fn get_byte_length(&self) -> Option<usize> {
125        let mut sum: usize = 0;
126        for b in self.format.as_slice() {
127            if let Some(l) = b.get_byte_length() {
128                sum += l;
129            } else {
130                return None;
131            }
132        }
133        Some(sum)
134    }
135
136    /// Returns the stored format string
137    pub fn get_format_str(&self) -> String {
138        let mut s = String::new();
139        for c in self.format.as_slice() {
140            s.push((*c).into());
141        }
142        s
143    }
144
145    /// Parses telemetry data into a vector of `SupMCUValue`s
146    pub fn parse_data(
147        &self,
148        rdr: &mut Cursor<&Vec<u8>>,
149    ) -> Result<Vec<SupMCUValue>, ParsingError> {
150        let mut out = vec![];
151
152        for dt in self.format.as_slice() {
153            out.push(match dt {
154                DataType::Str => {
155                    let mut buf = vec![];
156                    rdr.read_until(0, &mut buf)?;
157                    buf.pop();
158                    SupMCUValue::Str(String::from_utf8(buf)?)
159                }
160                DataType::Char => SupMCUValue::Char(rdr.read_u8()? as char),
161                DataType::UINT8 => SupMCUValue::U8(rdr.read_u8()?),
162                DataType::INT8 => SupMCUValue::I8(rdr.read_i8()?),
163                DataType::UINT16 => SupMCUValue::U16(rdr.read_u16::<LE>()?),
164                DataType::INT16 => SupMCUValue::I16(rdr.read_i16::<LE>()?),
165                DataType::UINT32 => SupMCUValue::U32(rdr.read_u32::<LE>()?),
166                DataType::INT32 => SupMCUValue::I32(rdr.read_i32::<LE>()?),
167                DataType::UINT64 => SupMCUValue::U64(rdr.read_u64::<LE>()?),
168                DataType::INT64 => SupMCUValue::I64(rdr.read_i64::<LE>()?),
169                DataType::Float => SupMCUValue::Float(rdr.read_f32::<LE>()?),
170                DataType::Double => SupMCUValue::Double(rdr.read_f64::<LE>()?),
171                DataType::Hex8 => SupMCUValue::Hex8(rdr.read_u8()?),
172                DataType::Hex16 => SupMCUValue::Hex16(rdr.read_u16::<LE>()?),
173            });
174        }
175        Ok(out)
176    }
177
178    /// Generates random data as a vector of `SupMCUValue`s
179    #[cfg(test)]
180    pub fn random_data(&self, rng: &mut SmallRng) -> Vec<SupMCUValue> {
181        use rand::Rng;
182
183        let mut out = vec![];
184
185        for dt in self.format.as_slice() {
186            out.push(match dt {
187                DataType::Str => SupMCUValue::Str("A random string".into()),
188                DataType::Char => SupMCUValue::Char(rng.gen::<u8>() as char),
189                DataType::UINT8 => SupMCUValue::U8(rng.gen()),
190                DataType::INT8 => SupMCUValue::I8(rng.gen()),
191                DataType::UINT16 => SupMCUValue::U16(rng.gen()),
192                DataType::INT16 => SupMCUValue::I16(rng.gen()),
193                DataType::UINT32 => SupMCUValue::U32(rng.gen()),
194                DataType::INT32 => SupMCUValue::I32(rng.gen()),
195                DataType::UINT64 => SupMCUValue::U64(rng.gen()),
196                DataType::INT64 => SupMCUValue::I64(rng.gen()),
197                DataType::Float => SupMCUValue::Float(rng.gen()),
198                DataType::Double => SupMCUValue::Double(rng.gen()),
199                DataType::Hex8 => SupMCUValue::Hex8(rng.gen()),
200                DataType::Hex16 => SupMCUValue::Hex16(rng.gen()),
201            });
202        }
203        out
204    }
205}
206
207#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
208#[serde(tag = "type", content = "value")]
209pub enum SupMCUValue {
210    Str(String),
211    Char(char),
212    U8(u8),
213    I8(i8),
214    U16(u16),
215    I16(i16),
216    U32(u32),
217    I32(i32),
218    U64(u64),
219    I64(i64),
220    Float(f32),
221    Double(f64),
222    Hex8(u8),
223    Hex16(u16),
224}
225
226impl fmt::Display for SupMCUValue {
227    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
228        match self {
229            SupMCUValue::Str(i) => write!(f, "{i}"),
230            SupMCUValue::Char(i) => write!(f, "{i}"),
231            SupMCUValue::U8(i) => write!(f, "{i}"),
232            SupMCUValue::I8(i) => write!(f, "{i}"),
233            SupMCUValue::U16(i) => write!(f, "{i}"),
234            SupMCUValue::I16(i) => write!(f, "{i}"),
235            SupMCUValue::U32(i) => write!(f, "{i}"),
236            SupMCUValue::I32(i) => write!(f, "{i}"),
237            SupMCUValue::U64(i) => write!(f, "{i}"),
238            SupMCUValue::I64(i) => write!(f, "{i}"),
239            SupMCUValue::Float(i) => write!(f, "{i}"),
240            SupMCUValue::Double(i) => write!(f, "{i}"),
241            SupMCUValue::Hex8(i) => write!(f, "0x{i:x}"),
242            SupMCUValue::Hex16(i) => write!(f, "0x{i:x}"),
243        }
244    }
245}
246
247impl Into<Vec<u8>> for SupMCUValue {
248    fn into(self) -> Vec<u8> {
249        match self {
250            SupMCUValue::Str(i) => i.into_bytes(),
251            SupMCUValue::Char(i) => (i as u8).to_le_bytes().to_vec(),
252            SupMCUValue::U8(i) => i.to_le_bytes().to_vec(),
253            SupMCUValue::I8(i) => i.to_le_bytes().to_vec(),
254            SupMCUValue::U16(i) => i.to_le_bytes().to_vec(),
255            SupMCUValue::I16(i) => i.to_le_bytes().to_vec(),
256            SupMCUValue::U32(i) => i.to_le_bytes().to_vec(),
257            SupMCUValue::I32(i) => i.to_le_bytes().to_vec(),
258            SupMCUValue::U64(i) => i.to_le_bytes().to_vec(),
259            SupMCUValue::I64(i) => i.to_le_bytes().to_vec(),
260            SupMCUValue::Float(i) => i.to_le_bytes().to_vec(),
261            SupMCUValue::Double(i) => i.to_le_bytes().to_vec(),
262            SupMCUValue::Hex8(i) => i.to_le_bytes().to_vec(),
263            SupMCUValue::Hex16(i) => i.to_le_bytes().to_vec(),
264        }
265    }
266}
267
268#[derive(Debug, Serialize, Deserialize)]
269pub struct SupMCUHDR {
270    pub ready: bool,
271    pub timestamp: u32,
272}
273
274impl TryFrom<&mut Cursor<&Vec<u8>>> for SupMCUHDR {
275    type Error = ParsingError;
276
277    fn try_from(rdr: &mut Cursor<&Vec<u8>>) -> Result<Self, Self::Error> {
278        Ok(SupMCUHDR {
279            ready: rdr.read_u8()? & 0b01 == 1,
280            timestamp: rdr.read_u32::<LE>()?,
281        })
282    }
283}
284
285#[cfg(test)]
286impl Into<Vec<u8>> for SupMCUHDR {
287    fn into(self) -> Vec<u8> {
288        let mut buf = vec![self.ready as u8];
289        buf.extend(self.timestamp.to_le_bytes());
290        buf
291    }
292}
293
294pub type SupMCUTelemetryData = Vec<SupMCUValue>;
295
296#[derive(Debug, Serialize, Deserialize)]
297pub struct SupMCUTelemetry {
298    pub definition: SupMCUTelemetryDefinition,
299    pub header: SupMCUHDR,
300    pub data: SupMCUTelemetryData,
301}
302
303impl SupMCUTelemetry {
304    pub fn from_bytes(
305        buff: Vec<u8>,
306        def: &SupMCUTelemetryDefinition,
307    ) -> Result<Self, ParsingError> {
308        let mut rdr = Cursor::new(&buff);
309
310        Ok(SupMCUTelemetry {
311            definition: def.clone(),
312            header: SupMCUHDR::try_from(&mut rdr)?,
313            data: def.format.parse_data(&mut rdr)?,
314        })
315    }
316}
317
318#[cfg(test)]
319impl<'a> Into<&'a [u8]> for SupMCUTelemetry {
320    fn into(self) -> &'a [u8] {
321        todo!()
322    }
323}
324
325#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize, Default, Copy, Enum)]
326#[cfg_attr(feature = "pumqry", derive(ValueEnum))]
327#[cfg_attr(feature = "pumqry", clap(rename_all = "lower"))]
328pub enum TelemetryType {
329    #[default]
330    SupMCU,
331    Module,
332}
333
334impl fmt::Display for TelemetryType {
335    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
336        match self {
337            TelemetryType::SupMCU => write!(f, "SupMCU"),
338            TelemetryType::Module => write!(f, "Module"),
339        }
340    }
341}
342
343#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize, Copy, Enum, Default)]
344pub enum McuType {
345    #[default]
346    UNKNOWN,
347    PIC24EP256MC206,
348    PIC24EP512MC206,
349}
350
351impl fmt::Display for McuType {
352    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
353        match self {
354            McuType::UNKNOWN => write!(f, "UKNOWN"),
355            McuType::PIC24EP256MC206 => write!(f, "PIC24EP256MC206"),
356            McuType::PIC24EP512MC206 => write!(f, "PIC24EP512MC206"),
357        }
358    }
359}
360
361impl TryFrom<&u8> for McuType {
362    type Error = ParsingError;
363    fn try_from(value: &u8) -> Result<Self, Self::Error> {
364        match value {
365            1 => Ok(Self::PIC24EP256MC206),
366            2 => Ok(Self::PIC24EP512MC206),
367            _ => Err(ParsingError::McuIdParsingError(*value)),
368        }
369    }
370}
371
372#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, SimpleObject)]
373pub struct SupMCUTelemetryDefinition {
374    pub name: String,
375    #[serde(flatten)]
376    pub format: SupMCUFormat,
377    pub length: Option<usize>,
378    #[graphql(skip)]
379    pub default_sim_value: Option<Vec<SupMCUValue>>,
380    pub idx: usize,
381    pub telemetry_type: TelemetryType,
382}
383
384impl Default for SupMCUTelemetryDefinition {
385    fn default() -> Self {
386        SupMCUTelemetryDefinition {
387            name: "".into(),
388            format: SupMCUFormat::new(""),
389            length: None,
390            default_sim_value: None,
391            idx: 0,
392            telemetry_type: TelemetryType::SupMCU,
393        }
394    }
395}
396
397impl SupMCUTelemetryDefinition {
398    pub fn simulatable(&self) -> bool {
399        self.default_sim_value.is_some()
400    }
401}
402
403#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, SimpleObject)]
404pub struct SupMCUCommand {
405    pub name: String,
406    pub idx: u16,
407}
408
409#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, SimpleObject)]
410pub struct SupMCUModuleDefinition {
411    /// This is the prefix to every SCPI MODULE command (e.g. `{cmd_name}:TEL? 15`)
412    pub name: String,
413    pub address: u16,
414    pub simulatable: bool,
415    pub telemetry: Vec<SupMCUTelemetryDefinition>,
416    pub commands: Vec<SupMCUCommand>,
417    pub mcu: McuType,
418    pub response_delay: f32,
419}
420
421impl Default for SupMCUModuleDefinition {
422    fn default() -> Self {
423        SupMCUModuleDefinition {
424            name: "".into(),
425            address: 0,
426            simulatable: false,
427            telemetry: vec![],
428            commands: vec![],
429            mcu: McuType::UNKNOWN,
430            response_delay: DEFAULT_RESPONSE_DELAY,
431        }
432    }
433}
434
435impl fmt::Display for SupMCUModuleDefinition {
436    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
437        write!(f, "{} @ {}", self.name, self.address)
438    }
439}
440
441impl SupMCUModuleDefinition {
442    pub fn get_supmcu_telemetry(&self) -> Vec<SupMCUTelemetryDefinition> {
443        self.telemetry
444            .clone()
445            .into_iter()
446            .filter(|def| def.telemetry_type == TelemetryType::SupMCU)
447            .sorted_by_key(|def| def.idx)
448            .collect()
449    }
450
451    pub fn get_module_telemetry(&self) -> Vec<SupMCUTelemetryDefinition> {
452        self.telemetry
453            .clone()
454            .into_iter()
455            .filter(|def| def.telemetry_type == TelemetryType::Module)
456            .sorted_by_key(|def| def.idx)
457            .collect()
458    }
459}