Embedded & Generics

A while ago someone posted a link to a youtube video of someone showing how they used generics in rust to achieve some interesting safety guarantees with regards to pin configurations on their embedded platform.

I've been trying to find it again, but have failed to do so. Anyone know which video I'm talking about? Anyone have a link to it?

Hey, well I don't have the link to this video but I could imagine that you are referring to a possibility to store the state of a pin as generic with the structure to encode it at compile time.

Something like this (encoding pin function and pull-up/down config):

pub struct Pin<FUNCTION, PUD> {
    function: FUNCTION,
    pud: PUD,
}

/// Type states for the FUNCTION generic argument of the pin.
pub(crate) mod function {
    pub struct Input;
    pub struct Output;
    pub struct Unknown;
}

/// Type states for the PUD template argument of the pin
pub(crate) mod pud {
    pub struct PullDown;
    pub struct PullUp;
    pub struct Disabled;
    pub struct Unknown;
}

/// Functions available for any kind of pin
impl<FUNC, PUD> Pin<FUNC, PUD> {
    /// Create a new ``Pin`` with an unknown function and PUD settings.
    #[allow(clippy::new_ret_no_self)]
    pub fn new(num: u32) -> Pin<function::Unknown, pud::Unknown> {
        Pin {
            function: function::Unknown,
            pud: pud::Unknown,
        }
    }

    /// switch any pin into an input pin
    pub fn into_input(self) -> Pin<function::Input, PUD> {
        /* do the hardware config */
        Pin {
            function: function::Input,
            pud: self.pud,
        }
    }
   /* implement the other methods accordingly to provide the different pin config's */
}

/// Functions available only for an Output pin with any PUD setting
impl<PUD> Pin<function::Output, PUD> {
    pub fn high(&self) {
        /* do the register / hardware stuff */
    }

    pub fn low(&self) {
        /* do the register / hardware stuff */
    }
}

A function can then be defined to require a specific pin config

fn foo<PUD>(pin: &Pin<function::Output, PUD>) {
  pin.high();
}

use this then like this

let pin = Pin::<function::Unknown, pud::Unknown>::new(10).into_input();
foo(&pin);

The above call gives compile error:

63 |     foo(&pin);
   |         ^^^^ expected struct `function::Output`, found struct `function::Input`
   |
   = note: expected reference `&Pin<function::Output, _>`
              found reference `&Pin<function::Input, pud::Unknown>`

as we have passed an input pin where an output pin is expected.
Hope this helps :wink:

1 Like

Yes, this looks familiar -- I'm pretty sure this was the gist of the video. Thanks!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.