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