1use std::collections::HashMap;
2use std::fmt::{Debug, Display, Formatter};
3
4use crate::errors::HardwareError::{IncompatiblePin, UnknownPin};
5use crate::errors::*;
6
7#[derive(Clone, Debug, Default)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct IoData {
15 #[cfg_attr(feature = "serde", serde(skip))]
17 pub pins: HashMap<u8, Pin>,
18 #[cfg_attr(feature = "serde", serde(skip))]
20 pub i2c_data: Vec<I2CReply>,
21 pub digital_reported_pins: Vec<u8>,
23 pub analog_reported_channels: Vec<u8>,
25 pub protocol_version: String,
27 pub firmware_name: String,
29 pub firmware_version: String,
31 pub connected: bool,
33}
34
35impl IoData {
36 pub fn get_pin<T: Into<PinIdOrName>>(&self, pin: T) -> Result<&Pin, Error> {
41 let pin = pin.into();
42 match &pin {
43 PinIdOrName::Id(id) => self.pins.get(id).ok_or(Error::from(UnknownPin { pin })),
44 PinIdOrName::Name(name) => Ok(self
45 .pins
46 .iter()
47 .find(|(_, pin)| pin.name == *name)
48 .ok_or(Error::from(UnknownPin { pin }))?
49 .1),
50 }
51 }
52
53 pub fn get_pin_mut<T: Into<PinIdOrName>>(&mut self, pin: T) -> Result<&mut Pin, Error> {
58 let pin = pin.into();
59 match &pin {
60 PinIdOrName::Id(id) => self.pins.get_mut(id).ok_or(Error::from(UnknownPin { pin })),
61 PinIdOrName::Name(name) => Ok(self
62 .pins
63 .iter_mut()
64 .find(|(_, &mut ref pin)| pin.name == *name)
65 .ok_or(Error::from(UnknownPin { pin }))?
66 .1),
67 }
68 }
69}
70
71#[derive(Default, Debug, Clone)]
73#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
74pub struct I2CReply {
75 pub address: u8,
76 pub register: u8,
77 pub data: Vec<u8>,
78}
79
80#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82#[derive(Clone, Default)]
83pub struct Pin {
84 pub id: u8,
86 pub name: String,
88 pub mode: PinMode,
90 pub supported_modes: Vec<PinMode>,
92 pub channel: Option<u8>,
94 pub value: u16,
96}
97
98impl Pin {
99 pub fn supports_mode(&self, mode: PinModeId) -> Option<PinMode> {
101 self.supported_modes.iter().find(|m| m.id == mode).copied()
102 }
103
104 pub fn validate_current_mode(&self, mode: PinModeId) -> Result<(), Error> {
106 match self.mode.id == mode {
107 true => Ok(()),
108 false => Err(IncompatiblePin {
109 mode: self.mode.id,
110 pin: self.id,
111 context: "check_current_mode",
112 }),
113 }?;
114 Ok(())
115 }
116
117 pub fn get_max_possible_value(&self) -> u16 {
121 self.mode.get_max_possible_value()
122 }
123}
124
125impl Debug for Pin {
126 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
127 let mode_str = format!("{}", self.mode);
129
130 let mut debug_struct = f.debug_struct("Pin");
131 debug_struct
132 .field("id", &self.id)
133 .field("name", &self.name)
134 .field("mode", &mode_str)
135 .field("supported modes", &self.supported_modes);
136 if let Some(channel) = self.channel {
137 debug_struct.field("channel", &channel);
138 } else {
139 debug_struct.field("channel", &None::<u8>);
140 }
141 debug_struct.field("value", &self.value).finish()
142 }
143}
144
145#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
149#[derive(Clone, PartialEq, Debug)]
150pub enum PinIdOrName {
151 Id(u8),
152 Name(String),
153}
154
155impl From<u8> for PinIdOrName {
156 fn from(n: u8) -> Self {
157 PinIdOrName::Id(n)
158 }
159}
160
161impl From<&str> for PinIdOrName {
162 fn from(s: &str) -> Self {
163 PinIdOrName::Name(s.to_string())
164 }
165}
166
167impl From<String> for PinIdOrName {
168 fn from(s: String) -> Self {
169 PinIdOrName::Name(s)
170 }
171}
172
173impl Display for PinIdOrName {
174 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
175 match self {
176 PinIdOrName::Id(n) => write!(f, "{}", n),
177 PinIdOrName::Name(s) => write!(f, "{:?}", s),
178 }
179 }
180}
181
182#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
186#[derive(Clone, Default, Copy)]
187pub struct PinMode {
188 pub id: PinModeId,
190 pub resolution: u8,
192}
193
194impl PinMode {
195 pub fn get_max_possible_value(&self) -> u16 {
197 (1 << self.resolution) - 1
198 }
199}
200
201impl Display for PinMode {
202 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
203 write!(f, "{}", self.id)
204 }
205}
206
207impl Debug for PinMode {
208 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
209 match self.id {
210 PinModeId::UNSUPPORTED => write!(f, "[{}]", self.id),
211 _ => write!(f, "[id: {}, resolution: {}]", self.id, self.resolution),
212 }
213 }
214}
215
216#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
220#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
221#[repr(u8)]
222pub enum PinModeId {
223 INPUT = 0,
225 OUTPUT = 1,
227 ANALOG = 2,
229 PWM = 3,
231 SERVO = 4,
233 SHIFT = 5,
235 I2C = 6,
237 ONEWIRE = 7,
239 STEPPER = 8,
241 ENCODER = 9,
243 SERIAL = 0x0A,
245 PULLUP = 0x0B,
247 SPI = 0x0C,
249 SONAR = 0x0D,
251 TONE = 0x0E,
253 DHT = 0x0F,
255 #[default]
257 UNSUPPORTED = 0x7F,
258}
259
260impl PinModeId {
261 pub fn from_u8(value: u8) -> Result<PinModeId, Error> {
272 match value {
273 0 => Ok(PinModeId::INPUT),
274 1 => Ok(PinModeId::OUTPUT),
275 2 => Ok(PinModeId::ANALOG),
276 3 => Ok(PinModeId::PWM),
277 4 => Ok(PinModeId::SERVO),
278 5 => Ok(PinModeId::SHIFT),
279 6 => Ok(PinModeId::I2C),
280 7 => Ok(PinModeId::ONEWIRE),
281 8 => Ok(PinModeId::STEPPER),
282 9 => Ok(PinModeId::ENCODER),
283 0x0A => Ok(PinModeId::SERIAL),
284 0x0B => Ok(PinModeId::PULLUP),
285 0x0C => Ok(PinModeId::SPI),
286 0x0D => Ok(PinModeId::SONAR),
287 0x0E => Ok(PinModeId::TONE),
288 0x0F => Ok(PinModeId::DHT),
289 0x7F => Ok(PinModeId::UNSUPPORTED),
290 x => Err(UnknownError {
291 info: format!("PinMode not found with value: {}", x),
292 }),
293 }
294 }
295}
296
297impl From<PinModeId> for u8 {
298 fn from(mode: PinModeId) -> u8 {
299 mode as u8
300 }
301}
302
303impl Display for PinModeId {
304 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
305 write!(f, "{:?}", self)
306 }
307}
308
309#[cfg(test)]
310mod tests {
311 use crate::io::{Pin, PinIdOrName, PinMode, PinModeId};
312 use crate::mocks::create_test_plugin_io_data;
313
314 #[test]
315 fn test_get_pin_success() {
316 assert_eq!(create_test_plugin_io_data().get_pin(3).unwrap().value, 3);
317 assert_eq!(create_test_plugin_io_data().get_pin(11).unwrap().value, 11);
318 assert_eq!(
319 create_test_plugin_io_data().get_pin_mut(3).unwrap().value,
320 3
321 );
322 assert_eq!(
323 create_test_plugin_io_data().get_pin_mut(11).unwrap().value,
324 11
325 );
326 }
327
328 #[test]
329 fn test_get_pin_error() {
330 assert!(create_test_plugin_io_data().get_pin(66).is_err());
331 assert!(create_test_plugin_io_data().get_pin_mut(66).is_err());
332 }
333
334 #[test]
335 fn test_mutate_pin() {
336 let mut hardware = create_test_plugin_io_data();
337 assert_eq!(hardware.get_pin_mut(11).unwrap().value, 11);
338 hardware.get_pin_mut(11).unwrap().value = 255;
339 assert_eq!(hardware.get_pin_mut(11).unwrap().value, 255);
340 }
341
342 #[test]
343 fn test_pin_supports_mode() {
344 let pin = Pin {
345 supported_modes: vec![
346 PinMode {
347 id: PinModeId::INPUT,
348 resolution: 0,
349 },
350 PinMode {
351 id: PinModeId::OUTPUT,
352 resolution: 0,
353 },
354 ],
355 ..Default::default()
356 };
357
358 let supported_mode = pin.supports_mode(PinModeId::INPUT);
360 assert!(supported_mode.is_some());
361
362 assert!(pin.supports_mode(PinModeId::PWM).is_none());
364 }
365
366 #[test]
367 fn test_pin_mode_max_value() {
368 let pin_mode = PinMode {
369 id: PinModeId::INPUT,
370 resolution: 8,
371 };
372
373 assert_eq!(pin_mode.get_max_possible_value(), 255);
374 }
375
376 #[test]
377 fn test_check_current_mode_success() {
378 let pin = Pin {
379 mode: PinMode {
380 id: PinModeId::PWM,
381 resolution: 10,
382 },
383 ..Default::default()
384 };
385
386 assert!(pin.validate_current_mode(PinModeId::PWM).is_ok());
387 assert!(pin.validate_current_mode(PinModeId::SHIFT).is_err());
388 assert_eq!(pin.get_max_possible_value(), 1023);
389 }
390
391 #[test]
392 fn test_pin_display() {
393 let mut pin = Pin {
394 supported_modes: vec![
395 PinMode {
396 id: PinModeId::INPUT,
397 resolution: 0,
398 },
399 PinMode {
400 id: PinModeId::OUTPUT,
401 resolution: 1,
402 },
403 PinMode {
404 id: PinModeId::ANALOG,
405 resolution: 8,
406 },
407 ],
408 channel: Some(1),
409 ..Default::default()
410 };
411 assert_eq!(format!("{:?}", pin), String::from("Pin { id: 0, name: \"\", mode: \"UNSUPPORTED\", supported modes: [[id: INPUT, resolution: 0], [id: OUTPUT, resolution: 1], [id: ANALOG, resolution: 8]], channel: 1, value: 0 }"));
412 pin.mode = PinMode {
413 id: PinModeId::INPUT,
414 resolution: 0,
415 };
416 pin.channel = None;
417 assert_eq!(format!("{:?}", pin), String::from("Pin { id: 0, name: \"\", mode: \"INPUT\", supported modes: [[id: INPUT, resolution: 0], [id: OUTPUT, resolution: 1], [id: ANALOG, resolution: 8]], channel: None, value: 0 }"));
418 }
419
420 #[test]
421 fn test_pin_mode_display() {
422 let mode = PinMode {
423 id: PinModeId::PWM,
424 resolution: 8,
425 };
426 assert_eq!(format!("{}", mode), "PWM");
427 }
428
429 #[test]
430 fn test_pin_mode_debug() {
431 let mode = PinMode {
432 id: PinModeId::PWM,
433 resolution: 8,
434 };
435 assert_eq!(format!("{:?}", mode), "[id: PWM, resolution: 8]");
436 let unsupported = PinMode {
437 id: PinModeId::UNSUPPORTED,
438 resolution: 0,
439 };
440 assert_eq!(format!("{:?}", unsupported), "[UNSUPPORTED]");
441 }
442
443 #[test]
444 fn test_pin_mode_id_conversions() {
445 let mode = PinModeId::from_u8(0x0F);
447 assert!(mode.is_ok());
448 assert_eq!(PinModeId::from_u8(0).unwrap(), PinModeId::INPUT);
449 assert_eq!(PinModeId::from_u8(1).unwrap(), PinModeId::OUTPUT);
450 assert_eq!(PinModeId::from_u8(2).unwrap(), PinModeId::ANALOG);
451 assert_eq!(PinModeId::from_u8(3).unwrap(), PinModeId::PWM);
452 assert_eq!(PinModeId::from_u8(4).unwrap(), PinModeId::SERVO);
453 assert_eq!(PinModeId::from_u8(5).unwrap(), PinModeId::SHIFT);
454 assert_eq!(PinModeId::from_u8(6).unwrap(), PinModeId::I2C);
455 assert_eq!(PinModeId::from_u8(7).unwrap(), PinModeId::ONEWIRE);
456 assert_eq!(PinModeId::from_u8(8).unwrap(), PinModeId::STEPPER);
457 assert_eq!(PinModeId::from_u8(9).unwrap(), PinModeId::ENCODER);
458 assert_eq!(PinModeId::from_u8(0x0A).unwrap(), PinModeId::SERIAL);
459 assert_eq!(PinModeId::from_u8(0x0B).unwrap(), PinModeId::PULLUP);
460 assert_eq!(PinModeId::from_u8(0x0C).unwrap(), PinModeId::SPI);
461 assert_eq!(PinModeId::from_u8(0x0D).unwrap(), PinModeId::SONAR);
462 assert_eq!(PinModeId::from_u8(0x0E).unwrap(), PinModeId::TONE);
463 assert_eq!(PinModeId::from_u8(0x0F).unwrap(), PinModeId::DHT);
464 assert_eq!(PinModeId::from_u8(0x7F).unwrap(), PinModeId::UNSUPPORTED);
465
466 let error_mode = PinModeId::from_u8(100);
468 assert!(error_mode.is_err());
469 assert_eq!(
470 error_mode.err().unwrap().to_string(),
471 "Unknown error: PinMode not found with value: 100."
472 );
473
474 assert_eq!(u8::from(PinModeId::SHIFT), 5);
476 }
477
478 #[test]
479 fn test_pin_mode_id_display() {
480 assert_eq!(format!("{}", PinModeId::PWM), "PWM");
481 }
482
483 #[test]
484 fn test_pin_id_from() {
485 let pin = PinIdOrName::from(42);
486 assert_eq!(pin, PinIdOrName::Id(42));
487 let pin: PinIdOrName = 4.into();
488 assert_eq!(pin, PinIdOrName::Id(4));
489 let pin = PinIdOrName::from("D1");
490 assert_eq!(pin, PinIdOrName::Name("D1".to_string()));
491 let pin = PinIdOrName::from("A1".to_string());
492 assert_eq!(pin, PinIdOrName::Name("A1".to_string()));
493 }
494
495 #[test]
496 fn test_pin_id_display() {
497 let pin = PinIdOrName::Id(42);
498 assert_eq!(pin.to_string(), "42");
499 let pin = PinIdOrName::Name(String::from("A0"));
500 assert_eq!(pin.to_string(), "\"A0\"");
501 }
502}