hermes_five/devices/input/
analog.rs1use std::fmt::{Display, Formatter};
2use std::sync::Arc;
3
4use parking_lot::RwLock;
5
6use crate::devices::input::{Input, InputEvent};
7use crate::devices::Device;
8use crate::errors::Error;
9use crate::hardware::Hardware;
10use crate::io::{IoProtocol, PinIdOrName, PinModeId};
11use crate::pause;
12use crate::utils::task;
13use crate::utils::{EventHandler, EventManager, State, TaskHandler};
14
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19#[derive(Clone, Debug)]
20pub struct AnalogInput {
21 pin: u8,
25 #[cfg_attr(feature = "serde", serde(with = "crate::devices::arc_rwlock_serde"))]
27 state: Arc<RwLock<u16>>,
28
29 #[cfg_attr(feature = "serde", serde(skip))]
32 protocol: Box<dyn IoProtocol>,
33 #[cfg_attr(feature = "serde", serde(skip))]
35 handler: Arc<RwLock<Option<TaskHandler>>>,
36 #[cfg_attr(feature = "serde", serde(skip))]
38 events: EventManager,
39}
40
41impl AnalogInput {
42 pub fn new<T: Into<PinIdOrName>>(board: &dyn Hardware, analog_pin: T) -> Result<Self, Error> {
49 let pin = board.get_io().read().get_pin(analog_pin)?.clone();
50
51 let mut sensor = Self {
52 pin: pin.id,
53 state: Arc::new(RwLock::new(pin.value)),
54 protocol: board.get_protocol(),
55 handler: Arc::new(RwLock::new(None)),
56 events: Default::default(),
57 };
58
59 sensor
61 .protocol
62 .set_pin_mode(sensor.pin, PinModeId::ANALOG)?;
63
64 sensor.protocol.report_analog(pin.channel.unwrap(), true)?;
66
67 sensor.attach();
69
70 Ok(sensor)
71 }
72
73 pub fn get_pin(&self) -> u8 {
75 self.pin
76 }
77
78 pub fn attach(&self) {
85 if self.handler.read().is_none() {
86 let self_clone = self.clone();
87 *self.handler.write() = Some(
88 task::run(async move {
89 loop {
90 let pin_value = self_clone
91 .protocol
92 .get_io()
93 .read()
94 .get_pin(self_clone.pin)?
95 .value;
96 let state_value = *self_clone.state.read();
97 if pin_value != state_value {
98 *self_clone.state.write() = pin_value;
99 self_clone.events.emit(InputEvent::OnChange, pin_value);
100 }
101
102 pause!(100);
104 }
105 #[allow(unreachable_code)]
106 Ok(())
107 })
108 .unwrap(),
109 );
110 }
111 }
112
113 pub fn detach(&self) {
116 if let Some(handler) = self.handler.read().as_ref() {
117 handler.abort();
118 }
119 *self.handler.write() = None
120 }
121
122 pub fn on<S, F, T, Fut>(&self, event: S, callback: F) -> EventHandler
161 where
162 S: Into<String>,
163 T: 'static + Send + Sync + Clone,
164 F: FnMut(T) -> Fut + Send + 'static,
165 Fut: std::future::Future<Output = Result<(), Error>> + Send + 'static,
166 {
167 self.events.on(event, callback)
168 }
169}
170
171impl Display for AnalogInput {
172 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
173 write!(
174 f,
175 "AnalogInput (pin={}) [state={}]",
176 self.pin,
177 self.state.read(),
178 )
179 }
180}
181
182#[cfg_attr(feature = "serde", typetag::serde)]
183impl Device for AnalogInput {}
184
185#[cfg_attr(feature = "serde", typetag::serde)]
186impl Input for AnalogInput {
187 fn get_state(&self) -> State {
188 State::from(*self.state.read())
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use crate::devices::input::analog::AnalogInput;
195 use crate::devices::input::Input;
196 use crate::devices::input::InputEvent;
197 use crate::hardware::Board;
198 use crate::mocks::plugin_io::MockIoProtocol;
199 use crate::pause;
200 use std::sync::atomic::{AtomicU16, Ordering};
201 use std::sync::Arc;
202
203 #[hermes_five_macros::test]
204 fn test_new_analog_input() {
205 let board = Board::new(MockIoProtocol::default());
206 let sensor = AnalogInput::new(&board, 14);
207 assert!(sensor.is_ok());
208 let sensor = sensor.unwrap();
209 assert_eq!(sensor.get_pin(), 14);
210 assert_eq!(sensor.get_state().as_integer(), 100);
211 sensor.detach();
212
213 let sensor = AnalogInput::new(&board, "A22").unwrap();
214 assert_eq!(sensor.get_pin(), 22);
215 assert_eq!(sensor.get_state().as_integer(), 222);
216
217 sensor.detach();
218 board.close();
219 }
220
221 #[hermes_five_macros::test]
222 fn test_analog_display() {
223 let board = Board::new(MockIoProtocol::default());
224 let sensor = AnalogInput::new(&board, "A15").unwrap();
225 assert_eq!(sensor.get_state().as_integer(), 200);
226 assert_eq!(
227 format!("{}", sensor),
228 String::from("AnalogInput (pin=15) [state=200]")
229 );
230
231 sensor.detach();
232 board.close();
233 }
234
235 #[hermes_five_macros::test]
236 fn test_analog_events() {
237 let pin = "A14";
238 let board = Board::new(MockIoProtocol::default());
239 let sensor = AnalogInput::new(&board, pin).unwrap();
240 assert_eq!(sensor.get_state().as_integer(), 100);
241
242 let change_flag = Arc::new(AtomicU16::new(100));
244 let moved_change_flag = change_flag.clone();
245 sensor.on(InputEvent::OnChange, move |new_state: u16| {
246 let captured_flag = moved_change_flag.clone();
247 async move {
248 captured_flag.store(new_state, Ordering::SeqCst);
249 Ok(())
250 }
251 });
252
253 assert_eq!(change_flag.load(Ordering::SeqCst), 100);
254
255 sensor
257 .protocol
258 .get_io()
259 .write()
260 .get_pin_mut(pin)
261 .unwrap()
262 .value = 0xFF;
263
264 pause!(500);
265 assert_eq!(change_flag.load(Ordering::SeqCst), 0xFF);
266
267 sensor.detach();
268 }
269}