1#[cfg(mock)]
2mod mock;
3
4use bincode::{Decode, Encode};
5use cu29::prelude::*;
6use cu29::CuResult;
7use std::sync::{Arc, Mutex};
8
9#[allow(unused_imports)]
10use cu29_traits::CuError;
11
12#[cfg(mock)]
13use mock::{get_pin, InputPin};
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 Output<'m> = output_msg!(EncoderPayload);
59
60 fn new(config: Option<&ComponentConfig>) -> CuResult<Self>
61 where
62 Self: Sized,
63 {
64 let ComponentConfig(config) =
65 config.ok_or("Encoder needs a config with clk_pin and dat_pin.")?;
66
67 let clk_pin_nb_value = config.get("clk_pin").ok_or("Encoder needs a clk_pin")?;
68 let clk_pin: u8 = clk_pin_nb_value.clone().into();
69
70 let dat_pin_nb_value = config.get("dat_pin").ok_or("Encoder needs a dat_pin")?;
71 let dat_pin: u8 = dat_pin_nb_value.clone().into();
72
73 let clk_pin: InputPin = get_pin(clk_pin)?;
74 let dat_pin: InputPin = get_pin(dat_pin)?;
75
76 Ok(Self {
77 clk_pin,
78 data_from_interrupts: Arc::new(Mutex::new(InterruptData {
79 dat_pin,
80 ticks: 0,
81 tov: CuDuration::default(),
82 })),
83 })
84 }
85
86 #[allow(unused_variables)]
87 fn start(&mut self, clock: &RobotClock) -> CuResult<()> {
88 let clock = clock.clone();
89 let idata = Arc::clone(&self.data_from_interrupts);
90 #[cfg(hardware)]
91 self.clk_pin
92 .set_async_interrupt(Trigger::FallingEdge, None, move |_| {
93 let mut idata = idata.lock().unwrap();
94 if idata.dat_pin.read() == Level::Low {
95 idata.ticks -= 1;
96 } else {
97 idata.ticks += 1;
98 }
99 idata.tov = clock.now();
100 })
101 .map_err(|e| CuError::new_with_cause("Failed to set async interrupt", e))?;
102 Ok(())
103 }
104
105 fn process(&mut self, clock: &RobotClock, new_msg: &mut Self::Output<'_>) -> CuResult<()> {
106 let idata = self.data_from_interrupts.lock().unwrap();
107 new_msg.tov = Some(clock.now()).into();
108 new_msg.metadata.set_status(idata.ticks);
109 new_msg.set_payload(EncoderPayload { ticks: idata.ticks });
110 Ok(())
111 }
112 fn stop(&mut self, _clock: &RobotClock) -> CuResult<()> {
113 #[cfg(hardware)]
114 self.clk_pin
115 .clear_async_interrupt()
116 .map_err(|e| CuError::new_with_cause("Failed to reset async interrupt", e))?;
117 Ok(())
118 }
119}