Skip to main content

lego_powered_up/
iodevice.rs

1use tokio::sync::broadcast;
2
3use crate::hubs::{Channels, Tokens};
4use crate::notifications::{
5    DatasetType, NetworkCommand, PortOutputCommandFeedbackFormat,
6    PortValueCombinedFormat, PortValueSingleFormat,
7};
8use crate::IoTypeId;
9use crate::{Error, Result};
10use basic::Basic;
11use definition::Definition;
12use hubled::HubLed;
13use motor::EncoderMotor;
14use remote::RcDevice;
15use sensor::GenericSensor;
16use visionsensor::VisionSensor;
17
18pub mod basic;
19pub mod definition;
20pub mod headlight;
21pub mod hubled;
22pub mod modes;
23pub mod motor;
24pub mod remote;
25pub mod sensor;
26pub mod visionsensor;
27
28#[derive(Debug, Clone)]
29pub struct IoDevice {
30    pub def: Definition,
31    tokens: Tokens,
32    channels: Channels,
33}
34
35impl IoDevice {
36    pub fn kind(&self) -> &IoTypeId {
37        self.def.kind()
38    }
39    pub fn def(&self) -> &Definition {
40        &self.def
41    }
42    pub fn port(&self) -> u8 {
43        self.def.port()
44    }
45    pub fn channels(&self) -> &Channels {
46        &self.channels
47    }
48    pub fn new(kind: IoTypeId, port: u8, tokens: Tokens) -> Self {
49        Self {
50            def: Definition::new(kind, port),
51            tokens,
52            channels: Default::default(),
53        }
54    }
55    pub fn cache_channels(&mut self, channels: Channels) {
56        self.channels = channels;
57    }
58}
59
60// Implement device-traits
61impl Basic for IoDevice {
62    fn port(&self) -> u8 {
63        self.def.port()
64    }
65    fn tokens(&self) -> Tokens {
66        self.tokens.clone()
67    }
68    fn get_rx(&self) -> Result<broadcast::Receiver<PortValueSingleFormat>> {
69        if let Some(sender) = &self.channels.singlevalue_sender {
70            Ok(sender.subscribe())
71        } else {
72            Err(Error::NoneError(String::from("Sender not found")))
73        }
74    }
75}
76impl GenericSensor for IoDevice {
77    fn check(&self) -> Result<()> {
78        Ok(())
79    }
80    fn check_dataset(&self, mode: u8, datasettype: DatasetType) -> Result<()> {
81        if let Some(pm) = self.def.modes().get(&mode) {
82            let vf = pm.value_format;
83            if datasettype == vf.dataset_type {
84                Ok(())
85            } else {
86                Err(Error::NoneError(String::from("Incorrect dataset type")))
87            }
88        } else {
89            Err(Error::NoneError(String::from("Mode not found")))
90        }
91    }
92}
93
94impl RcDevice for IoDevice {
95    fn get_rx_pvs(&self) -> Result<broadcast::Receiver<PortValueSingleFormat>> {
96        if let Some(sender) = &self.channels.singlevalue_sender {
97            Ok(sender.subscribe())
98        } else {
99            Err(Error::NoneError(String::from("Sender not found")))
100        }
101    }
102    fn get_rx_nwc(&self) -> Result<broadcast::Receiver<NetworkCommand>> {
103        if let Some(sender) = &self.channels.networkcmd_sender {
104            Ok(sender.subscribe())
105        } else {
106            Err(Error::NoneError(String::from("Sender not found")))
107        }
108    }
109    fn check(&self) -> Result<()> {
110        match self.def.kind() {
111            IoTypeId::RemoteButtons => Ok(()),
112            _ => Err(Error::HubError(String::from(
113                "Not a remote control device",
114            ))),
115        }
116    }
117}
118
119impl EncoderMotor for IoDevice {
120    fn get_rx_combined(
121        &self,
122    ) -> Result<broadcast::Receiver<PortValueCombinedFormat>> {
123        if let Some(sender) = &self.channels.combinedvalue_sender {
124            Ok(sender.subscribe())
125        } else {
126            Err(Error::NoneError(String::from("Sender not found")))
127        }
128    }
129    fn get_rx_feedback(
130        &self,
131    ) -> Result<broadcast::Receiver<PortOutputCommandFeedbackFormat>> {
132        if let Some(sender) = &self.channels.commandfeedback_sender {
133            Ok(sender.subscribe())
134        } else {
135            Err(Error::NoneError(String::from("Sender not found")))
136        }
137    }
138    fn check(&self) -> Result<()> {
139        match self.def.kind() {
140            IoTypeId::TechnicLargeLinearMotor
141            | IoTypeId::TechnicXLargeLinearMotor
142            | IoTypeId::TechnicMediumAngularMotorGrey
143            | IoTypeId::TechnicLargeAngularMotorGrey
144            | IoTypeId::InternalMotorTacho => Ok(()),
145            _ => Err(Error::HubError(String::from("Not an Encoder Motor"))),
146        }
147    }
148}
149
150impl HubLed for IoDevice {
151    fn check(&self) -> Result<()> {
152        match self.def.kind() {
153            IoTypeId::HubLed => Ok(()),
154            _ => Err(Error::HubError(String::from("Not a Hub LED device"))),
155        }
156    }
157}
158
159impl VisionSensor for IoDevice {
160    fn check(&self) -> Result<()> {
161        match self.def.kind() {
162            IoTypeId::VisionSensor => Ok(()),
163            _ => {
164                Err(Error::HubError(String::from("Not a Vision sensor Motor")))
165            }
166        }
167    }
168}
169
170#[macro_export]
171macro_rules! device_trait {
172    ($name:tt, [$( $b:item ),*])  => {
173        #[async_trait]
174        pub trait $name: Debug + Send + Sync + Basic {
175            fn check(&self) -> Result<()>;
176            $(
177                $b
178            )*
179        }
180    }
181}