cu_rp_gpio/
lib.rs

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
20/// Example of a GPIO output driver for the Raspberry Pi
21/// The config takes one config value: `pin` which is the pin you want to address
22/// Gpio uses BCM pin numbering. For example: BCM GPIO 23 is tied to physical pin 16.
23pub 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}