1#[cfg(mock)]
2mod mock;
3
4use bincode::{Decode, Encode};
5use cu29::CuResult;
6use cu29::prelude::*;
7use std::sync::{Arc, Mutex};
8
9#[allow(unused_imports)]
10use cu29_traits::CuError;
11
12#[cfg(mock)]
13use mock::{InputPin, get_pin};
14#[cfg(hardware)]
15use rppal::gpio::{Gpio, InputPin, Level, Trigger};
16use serde::Deserialize;
17
18#[allow(dead_code)]
19struct InterruptData {
20 dat_pin: InputPin,
21 ticks: i32,
22 tov: CuDuration,
23}
24
25#[cfg(hardware)]
26fn get_pin(pin_nb: u8) -> CuResult<InputPin> {
27 Ok(Gpio::new()
29 .expect("Could not create GPIO bindings")
30 .get(pin_nb)
31 .map_err(|e| CuError::new_with_cause("Could not get pin", e))?
32 .into_input())
33}
34
35#[derive(Default, Clone, Debug, Encode, Decode, Serialize, Deserialize)]
36pub struct EncoderPayload {
37 pub ticks: i32,
38}
39
40impl From<&EncoderPayload> for f32 {
42 fn from(payload: &EncoderPayload) -> f32 {
43 payload.ticks as f32
44 }
45}
46
47#[allow(dead_code)]
48pub struct Encoder {
49 clk_pin: InputPin,
50 data_from_interrupts: Arc<Mutex<InterruptData>>,
51}
52
53impl Freezable for Encoder {
54 }
56
57impl CuSrcTask for Encoder {
58 type Resources<'r> = ();
59 type Output<'m> = output_msg!(EncoderPayload);
60
61 fn new(config: Option<&ComponentConfig>, _resources: Self::Resources<'_>) -> CuResult<Self>
62 where
63 Self: Sized,
64 {
65 let ComponentConfig(config) =
66 config.ok_or("Encoder needs a config with clk_pin and dat_pin.")?;
67
68 let clk_pin_nb_value = config.get("clk_pin").ok_or("Encoder needs a clk_pin")?;
69 let clk_pin: u8 = clk_pin_nb_value.clone().into();
70
71 let dat_pin_nb_value = config.get("dat_pin").ok_or("Encoder needs a dat_pin")?;
72 let dat_pin: u8 = dat_pin_nb_value.clone().into();
73
74 let clk_pin: InputPin = get_pin(clk_pin)?;
75 let dat_pin: InputPin = get_pin(dat_pin)?;
76
77 Ok(Self {
78 clk_pin,
79 data_from_interrupts: Arc::new(Mutex::new(InterruptData {
80 dat_pin,
81 ticks: 0,
82 tov: CuDuration::default(),
83 })),
84 })
85 }
86
87 #[allow(unused_variables)]
88 fn start(&mut self, clock: &RobotClock) -> CuResult<()> {
89 let clock = clock.clone();
90 let idata = Arc::clone(&self.data_from_interrupts);
91 #[cfg(hardware)]
92 self.clk_pin
93 .set_async_interrupt(Trigger::FallingEdge, None, move |_| {
94 let mut idata = idata.lock().unwrap();
95 if idata.dat_pin.read() == Level::Low {
96 idata.ticks -= 1;
97 } else {
98 idata.ticks += 1;
99 }
100 idata.tov = clock.now();
101 })
102 .map_err(|e| CuError::new_with_cause("Failed to set async interrupt", e))?;
103 Ok(())
104 }
105
106 fn process(&mut self, clock: &RobotClock, new_msg: &mut Self::Output<'_>) -> CuResult<()> {
107 let idata = self.data_from_interrupts.lock().unwrap();
108 new_msg.tov = Some(clock.now()).into();
109 new_msg.metadata.set_status(idata.ticks);
110 new_msg.set_payload(EncoderPayload { ticks: idata.ticks });
111 Ok(())
112 }
113 fn stop(&mut self, _clock: &RobotClock) -> CuResult<()> {
114 #[cfg(hardware)]
115 self.clk_pin
116 .clear_async_interrupt()
117 .map_err(|e| CuError::new_with_cause("Failed to reset async interrupt", e))?;
118 Ok(())
119 }
120}