hermes_five/io/mod.rs
1//! Defines various protocols to control devices associated to boards.
2
3use crate::errors::Error;
4use crate::utils::Range;
5use dyn_clone::DynClone;
6use parking_lot::RwLock;
7use std::any::type_name;
8use std::fmt::{Debug, Display};
9use std::sync::Arc;
10
11mod constants;
12mod data;
13mod protocols;
14mod transports;
15
16pub use data::*;
17pub use protocols::*;
18pub use transports::*;
19
20pub trait IO {
21 // ########################################
22 // Inner data related functions
23
24 /// Returns a protected arc to the inner [`IoData`].
25 fn get_io(&self) -> &Arc<RwLock<IoData>>;
26
27 /// Checks if the communication is opened using the underlying protocol.
28 fn is_connected(&self) -> bool;
29
30 // ########################################
31 // Read/Write on pins
32
33 /// Sets the `mode` of the specified `pin`.
34 ///
35 /// <https://github.com/firmata/protocol/blob/master/protocol.md#data-message-expansion>
36 fn set_pin_mode(&mut self, pin: u8, mode: PinModeId) -> Result<(), Error>;
37
38 /// Writes `level` to the digital `pin`.
39 ///
40 /// Send an DIGITAL_MESSAGE (0x90 - set digital value).
41 /// <https://github.com/firmata/protocol/blob/master/protocol.md#message-types>
42 fn digital_write(&mut self, pin: u8, level: bool) -> Result<(), Error>;
43
44 /// Writes `level` to the analog `pin`.
45 ///
46 /// Send an ANALOG_MESSAGE (0xE0 - set analog value).
47 /// <https://github.com/firmata/protocol/blob/master/protocol.md#message-types>
48 fn analog_write(&mut self, pin: u8, level: u16) -> Result<(), Error>;
49
50 /// Reads the digital `pin` value.
51 fn digital_read(&mut self, pin: u8) -> Result<bool, Error>;
52
53 /// Reads the analog `pin` value.
54 fn analog_read(&mut self, pin: u8) -> Result<u16, Error>;
55
56 // ########################################
57 // SERVO
58
59 /// Sends a SERVO_CONFIG command (0x70 - configure servo)
60 /// <https://github.com/firmata/protocol/blob/master/servos.md>
61 fn servo_config(&mut self, pin: u8, pwm_range: Range<u16>) -> Result<(), Error>;
62
63 // ########################################
64 // I2C
65
66 /// Configures the `delay` in microseconds for I2C devices that require a delay between when the
67 /// register is written to and the data in that register can be read.
68 fn i2c_config(&mut self, delay: u16) -> Result<(), Error>;
69 /// Reads `size` bytes from I2C device at the specified `address`.
70 fn i2c_read(&mut self, address: u8, size: u16) -> Result<(), Error>;
71 /// Writes `data` to the I2C device at the specified `address`.
72 fn i2c_write(&mut self, address: u8, data: &[u16]) -> Result<(), Error>;
73}
74
75// Makes a Box<dyn IoPlugin> clone (used for Board cloning).
76dyn_clone::clone_trait_object!(IoProtocol);
77
78/// Defines the trait all protocols must implement.
79#[cfg_attr(feature = "serde", typetag::serde(tag = "type"))]
80pub trait IoProtocol: IO + DynClone + Send + Sync + Debug + Display {
81 /// Returns the protocol name.
82 fn get_name(&self) -> &'static str {
83 type_name::<Self>().split("::").last().unwrap()
84 }
85
86 /// Opens the communication using the underlying protocol.
87 fn open(&mut self) -> Result<(), Error>;
88
89 /// Gracefully shuts down the communication.
90 fn close(&mut self) -> Result<(), Error>;
91
92 /// Sets the analog reporting `state` of the specified analog `pin`.
93 ///
94 /// When activated, the pin will send its value periodically. The value will be stored in the IoProtocol synced data.
95 /// ```no_run
96 /// use hermes_five::hardware::{Board, Hardware};
97 /// use hermes_five::io::IO;
98 /// let mut board = Board::default();
99 /// board.get_protocol().report_analog(0, true).expect("");
100 /// board.get_io().read().get_pin("A0").expect("").value;
101 /// ```
102 fn report_analog(&mut self, channel: u8, state: bool) -> Result<(), Error>;
103
104 /// Sets the digital reporting `state` of the specified digital `pin`.
105 ///
106 /// This will activate the reporting of all pins in port (hence the pin will send us its value periodically)
107 /// <https://github.com/firmata/protocol/blob/master/protocol.md>
108 fn report_digital(&mut self, pin: u8, state: bool) -> Result<(), Error>;
109
110 /// Set the sampling `interval` (in ms).
111 ///
112 /// The sampling interval sets how often analog data and i2c data is reported to the
113 /// client. The default for the arduino implementation is 19ms. This means that every
114 /// 19ms analog data will be reported and any i2c devices with read continuous mode
115 /// will be read.
116 /// <https://github.com/firmata/protocol/blob/master/protocol.md#sampling-interval>
117 fn sampling_interval(&mut self, interval: u16) -> Result<(), Error>;
118}
119
120#[cfg(not(tarpaulin_include))]
121impl Default for Box<dyn IoProtocol> {
122 fn default() -> Self {
123 Box::new(RemoteIo::default())
124 }
125}