corstone300-hal 0.1.0

Hardware abstraction layer Crate for the Arm(R) Corstone(TM)-300 Reference System
Documentation
// Copyright 2022 Arm Limited and/or its affiliates <open-source-office@arm.com>
//
// SPDX-License-Identifier: MIT

use core::marker::PhantomData;

use crate::pac::{gpio0, GPIO0_SECURE, GPIO1_SECURE, GPIO2_SECURE};

pub trait PinMode {}

pub enum Gpio {}
impl PinMode for Gpio {}
pub enum Uart {}
impl PinMode for Uart {}
pub enum Spi {}
impl PinMode for Spi {}
pub enum I2c {}
impl PinMode for I2c {}

pub struct Pin<const SHIELD_ID: usize, const PIN_ID: usize, Mode: PinMode> {
    mode: PhantomData<Mode>,
}
impl<const SHIELD_ID: usize, const PIN_ID: usize, Mode: PinMode> Pin<SHIELD_ID, PIN_ID, Mode> {
    fn block_and_mask(&self) -> (*const gpio0::RegisterBlock, u32) {
        match (SHIELD_ID, PIN_ID) {
            (0, 16) => (GPIO2_SECURE::PTR, 0b0001),
            (0, 17) => (GPIO2_SECURE::PTR, 0b0010),
            (1, 16) => (GPIO2_SECURE::PTR, 0b0100),
            (1, 17) => (GPIO2_SECURE::PTR, 0b1000),
            (0, pid) => (GPIO0_SECURE::PTR, 1 << pid),
            (1, pid) => (GPIO1_SECURE::PTR, 1 << pid),
            (_, _) => unreachable!(),
        }
    }
}

pub enum Pins {}
impl Pins {
    #[allow(clippy::type_complexity)]
    pub fn get_pins_secure(
        gpio0: GPIO0_SECURE,
        gpio1: GPIO1_SECURE,
        gpio2: GPIO2_SECURE,
    ) -> (
        Pin<0, 0, Gpio>,
        Pin<0, 1, Gpio>,
        Pin<0, 2, Gpio>,
        Pin<0, 3, Gpio>,
        Pin<0, 4, Gpio>,
        Pin<0, 5, Gpio>,
        Pin<0, 6, Gpio>,
        Pin<0, 7, Gpio>,
        Pin<0, 8, Gpio>,
        Pin<0, 9, Gpio>,
        Pin<0, 10, Gpio>,
        Pin<0, 11, Gpio>,
        Pin<0, 12, Gpio>,
        Pin<0, 13, Gpio>,
        Pin<0, 14, Gpio>,
        Pin<0, 15, Gpio>,
        Pin<0, 16, Gpio>,
        Pin<0, 17, Gpio>,
        Pin<1, 0, Gpio>,
        Pin<1, 1, Gpio>,
        Pin<1, 2, Gpio>,
        Pin<1, 3, Gpio>,
        Pin<1, 4, Gpio>,
        Pin<1, 5, Gpio>,
        Pin<1, 6, Gpio>,
        Pin<1, 7, Gpio>,
        Pin<1, 8, Gpio>,
        Pin<1, 9, Gpio>,
        Pin<1, 10, Gpio>,
        Pin<1, 11, Gpio>,
        Pin<1, 12, Gpio>,
        Pin<1, 13, Gpio>,
        Pin<1, 14, Gpio>,
        Pin<1, 15, Gpio>,
        Pin<1, 16, Gpio>,
        Pin<1, 17, Gpio>,
    ) {
        // The pin types directly access the GPIO register from the GPIO block type.
        // The pin types are responsible of ensuring their operations are atomic and won't colide
        // with others.
        let _ = (gpio0, gpio1, gpio2);
        (
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
            Pin { mode: PhantomData },
        )
    }
}

macro_rules! impl_into_mode {
    ($(($shield:expr, $pin:expr) => $mode:ident)*) => {
        $(
            impl Pin<$shield, $pin, Gpio> {
                #[doc = concat!("Turns the current GPIO pin into a ", stringify!($mode), " pin")]
                pub fn into_mode(self) -> Pin<$shield, $pin, $mode> {
                    let (block, mask) = self.block_and_mask();
                    unsafe { &*block }.altfuncset.write(|w|unsafe { w.bits(mask) });
                    Pin {
                        mode: PhantomData
                    }
                }
            }
            impl Pin<$shield, $pin, $mode> {
                #[doc = concat!("Turns the current ", stringify!($mode), " pin into a GPIO pin")]
                pub fn into_mode(self) -> Pin<$shield, $pin, Gpio> {
                    let (block, mask) = self.block_and_mask();
                    unsafe { &*block }.altfuncclr.write(|w|unsafe { w.bits(mask) });
                    Pin {
                        mode: PhantomData
                    }
                }
            }
         )*
    };
}

impl_into_mode! {
    (0, 0) => Uart
    (0, 1) => Uart
    (0, 10) => Spi
    (0, 11) => Spi
    (0, 12) => Spi
    (0, 13) => Spi
    (0, 14) => I2c
    (0, 15) => I2c
    (1, 0) => Uart
    (1, 1) => Uart
    (1, 10) => Spi
    (1, 11) => Spi
    (1, 12) => Spi
    (1, 13) => Spi
    (1, 14) => I2c
    (1, 15) => I2c
}

impl<const SHIELD_ID: usize, const PIN_ID: usize> embedded_hal::digital::v2::InputPin
    for Pin<SHIELD_ID, PIN_ID, Gpio>
{
    type Error = core::convert::Infallible;

    fn is_high(&self) -> Result<bool, core::convert::Infallible> {
        let (block, mask) = self.block_and_mask();
        Ok((unsafe { &*block }.data.read().bits() & mask) != 0)
    }

    fn is_low(&self) -> Result<bool, core::convert::Infallible> {
        self.is_high().map(|b| !b)
    }
}