Skip to main content

vuquest_3320/command/
serial_trigger.rs

1use alloc::string::String;
2
3use crate::result::{Error, Result};
4
5const SERIAL_TRIGGER: &str = "TRGSTO";
6/// Maximum timeout (in milliseconds) for [SerialTriggerMode].
7pub const MAX_SERIAL_TRIGGER: u32 = 300_000;
8
9/// Represents the `Mobile Phone Read Mode` serial command.
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub struct SerialTriggerMode {
12    ms: u32,
13}
14
15impl SerialTriggerMode {
16    /// Creates a new [SerialTriggerMode].
17    pub const fn new() -> Self {
18        Self { ms: 0 }
19    }
20
21    /// Gets the ASCII serial command code for [SerialTriggerMode].
22    pub fn command(&self) -> String {
23        format!("{SERIAL_TRIGGER}{}", self.ms)
24    }
25
26    /// Attempts to convert a [`u32`] number of timeout milliseconds into a [SerialTriggerMode].
27    ///
28    /// **NOTE**: `ms` must be below [MAX_SERIAL_TRIGGER] number of milliseconds.
29    pub const fn try_from_ms(ms: u32) -> Result<Self> {
30        if ms <= MAX_SERIAL_TRIGGER {
31            Ok(Self { ms })
32        } else {
33            Err(Error::InvalidValue(ms as usize))
34        }
35    }
36
37    /// Converts a [SerialTriggerMode] into a [`u32`] number of milliseconds.
38    pub const fn into_ms(self) -> u32 {
39        self.ms
40    }
41}
42
43impl Default for SerialTriggerMode {
44    fn default() -> Self {
45        Self::new()
46    }
47}
48
49impl TryFrom<&str> for SerialTriggerMode {
50    type Error = Error;
51
52    fn try_from(val: &str) -> Result<Self> {
53        let i = val.find(SERIAL_TRIGGER).ok_or(Error::InvalidVariant)?;
54
55        val.get(i + SERIAL_TRIGGER.len()..)
56            .ok_or(Error::InvalidVariant)?
57            .parse::<u32>()
58            .map(|ms| Self { ms })
59            .map_err(|_| Error::InvalidVariant)
60    }
61}
62
63impl TryFrom<String> for SerialTriggerMode {
64    type Error = Error;
65
66    fn try_from(val: String) -> Result<Self> {
67        val.as_str().try_into()
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn test_valid() {
77        (0..=MAX_SERIAL_TRIGGER).for_each(|ms| {
78            let exp_cmd = SerialTriggerMode { ms };
79            let exp_ascii_cmd = format!("{SERIAL_TRIGGER}{ms}");
80
81            assert_eq!(SerialTriggerMode::try_from_ms(ms), Ok(exp_cmd));
82            assert_eq!(exp_cmd.command(), exp_ascii_cmd);
83            assert_eq!(SerialTriggerMode::try_from(exp_ascii_cmd), Ok(exp_cmd));
84        });
85    }
86}