1use bincode::{Decode, Encode};
2use cu29::prelude::*;
3use serde::{Deserialize, Serialize};
4
5#[cfg(hardware)]
6use {
7 cu29::CuError,
8 rppal::gpio::{Gpio, Level, OutputPin},
9 std::sync::OnceLock,
10};
11
12#[cfg(hardware)]
13static GPIO: OnceLock<Gpio> = OnceLock::new();
14
15#[cfg(hardware)]
16fn gpio() -> &'static Gpio {
17 GPIO.get_or_init(|| Gpio::new().expect("Could not create GPIO bindings"))
18}
19
20pub struct RPGpio {
24 #[cfg(hardware)]
25 pin: OutputPin,
26 #[cfg(mock)]
27 pin: u8,
28}
29
30#[derive(Debug, Clone, Copy, Encode, Decode, Default, PartialEq, Serialize, Deserialize)]
31pub struct RPGpioPayload {
32 pub on: bool,
33}
34
35impl From<RPGpioPayload> for bool {
36 fn from(msg: RPGpioPayload) -> Self {
37 msg.on
38 }
39}
40
41impl From<RPGpioPayload> for u8 {
42 fn from(msg: RPGpioPayload) -> Self {
43 if msg.on {
44 1
45 } else {
46 0
47 }
48 }
49}
50
51#[cfg(hardware)]
52impl From<RPGpioPayload> for Level {
53 fn from(msg: RPGpioPayload) -> Self {
54 if msg.on {
55 Level::Low
56 } else {
57 Level::High
58 }
59 }
60}
61
62impl Freezable for RPGpio {}
63
64impl CuSinkTask for RPGpio {
65 type Input<'m> = input_msg!(RPGpioPayload);
66
67 fn new(config: Option<&ComponentConfig>) -> CuResult<Self>
68 where
69 Self: Sized,
70 {
71 let ComponentConfig(kv) =
72 config.ok_or("RPGpio needs a config, None was passed as ComponentConfig")?;
73
74 let pin_nb: u8 = kv
75 .get("pin")
76 .expect("RPGpio expects a pin config value pointing to output pin you want to address")
77 .clone()
78 .into();
79
80 #[cfg(hardware)]
81 let pin = gpio()
82 .get(pin_nb)
83 .map_err(|e| CuError::new_with_cause("Could not get pin", e))?
84 .into_output();
85 #[cfg(mock)]
86 let pin = pin_nb;
87 Ok(Self { pin })
88 }
89
90 fn process(&mut self, _clock: &RobotClock, msg: &Self::Input<'_>) -> CuResult<()> {
91 #[cfg(hardware)]
92 self.pin.write((*msg.payload().unwrap()).into());
93
94 #[cfg(mock)]
95 debug!(
96 "Would write to pin {} the value {}.",
97 self.pin,
98 msg.payload()
99 );
100
101 Ok(())
102 }
103}