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}