nxtusb/
sensor.rs

1//! Types and functionality related to sensor & input functions
2
3use crate::{Error, Result};
4use num_derive::FromPrimitive;
5use num_traits::FromPrimitive;
6use std::fmt::{self, Display, Formatter};
7
8/// Available inpur ports
9#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, FromPrimitive)]
10#[cfg_attr(feature = "strum", derive(strum_macros::EnumIter))]
11#[repr(u8)]
12#[allow(missing_docs)]
13pub enum InPort {
14    S1 = 0,
15    S2 = 1,
16    S3 = 2,
17    S4 = 3,
18}
19
20impl TryFrom<u8> for InPort {
21    type Error = Error;
22    fn try_from(code: u8) -> Result<Self> {
23        Self::from_u8(code).ok_or(Error::Parse("Invalid InPort"))
24    }
25}
26
27/// Supported sensor types
28#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, FromPrimitive)]
29#[cfg_attr(feature = "strum", derive(strum_macros::EnumIter))]
30#[repr(u8)]
31#[allow(missing_docs)]
32pub enum SensorType {
33    #[default]
34    None = 0,
35    Switch = 1,
36    Temperature = 2,
37    /// RCX light sensor
38    Reflection = 3,
39    /// RCX rotation sensor
40    Angle = 4,
41    /// NXT light sensor; LED on
42    LightActive = 5,
43    /// NXT light sensor; LED off
44    LightInactive = 6,
45    SoundDb = 7,
46    SoundDba = 8,
47    Custom = 9,
48    LowSpeed = 10,
49    LowSpeed9v = 11,
50    HighSpeed = 12,
51    ColourFull = 13,
52    ColourRed = 14,
53    ColourGreen = 15,
54    ColourBlue = 16,
55    ColourNone = 17,
56    /// "Internal use only"
57    ColourExit = 18,
58}
59
60impl TryFrom<u8> for SensorType {
61    type Error = Error;
62    fn try_from(code: u8) -> Result<Self> {
63        Self::from_u8(code).ok_or(Error::Parse("Invalid SensorType"))
64    }
65}
66
67/// Supported sensor modes
68#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, FromPrimitive)]
69#[cfg_attr(feature = "strum", derive(strum_macros::EnumIter))]
70#[repr(u8)]
71#[allow(missing_docs)]
72pub enum SensorMode {
73    #[default]
74    Raw = 0x00,
75    Bool = 0x20,
76    /// Count both rising and falling edges; reset counter with the
77    /// sensor reset API
78    Edge = 0x40,
79    /// Count only falling edges; reset counter with the sensor reset
80    /// API
81    Pulse = 0x60,
82    Percent = 0x80,
83    Celsius = 0xA0,
84    Farenheight = 0xC0,
85    /// RCX rotation sensor
86    Rotation = 0xE0,
87}
88
89impl TryFrom<u8> for SensorMode {
90    type Error = Error;
91    fn try_from(code: u8) -> Result<Self> {
92        Self::from_u8(code).ok_or(Error::Parse("Invalid SensorMode"))
93    }
94}
95
96/// Data returned by the `GetInputState` API
97#[derive(Copy, Clone, Debug, PartialEq, Eq)]
98#[allow(missing_docs)]
99pub struct InputValues {
100    pub port: InPort,
101    /// False if the sensor has not been read since its mode was last
102    /// changed; true otherwise
103    pub valid: bool,
104    /// Not used; will always be false
105    pub calibrated: bool,
106    pub sensor_type: SensorType,
107    pub sensor_mode: SensorMode,
108    pub raw_value: u16,
109    pub normalised_value: u16,
110    /// Scaled value is where e.g. the switch boolean or pulse counter
111    /// value will be
112    pub scaled_value: i16,
113    pub calibrated_value: i16,
114}
115
116impl Display for InputValues {
117    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
118        if self.valid {
119            match self.sensor_mode {
120                SensorMode::Raw => {
121                    write!(fmt, "{}", self.raw_value)
122                }
123                SensorMode::Bool => {
124                    write!(fmt, "{}", self.scaled_value != 0)
125                }
126                SensorMode::Edge | SensorMode::Pulse => {
127                    write!(fmt, "{}", self.scaled_value)
128                }
129                SensorMode::Percent => {
130                    write!(fmt, "{}%", self.scaled_value)
131                }
132                SensorMode::Celsius => {
133                    write!(fmt, "{}°C", self.scaled_value)
134                }
135                SensorMode::Farenheight => {
136                    write!(fmt, "{}°F", self.scaled_value)
137                }
138                SensorMode::Rotation => {
139                    write!(fmt, "{} ticks", self.scaled_value)
140                }
141            }
142        } else {
143            write!(fmt, "...")
144        }
145    }
146}