use crate::Error;
use crate::gpio::{GpioDirection, LogicLevel};
use bit_field::BitField;
#[derive(Debug, Clone, Copy)]
pub struct GpSettings {
pub gp0_mode: Gp0Mode,
pub gp1_mode: Gp1Mode,
pub gp2_mode: Gp2Mode,
pub gp3_mode: Gp3Mode,
pub gp0_value: LogicLevel,
pub gp0_direction: GpioDirection,
pub gp1_value: LogicLevel,
pub gp1_direction: GpioDirection,
pub gp2_value: LogicLevel,
pub gp2_direction: GpioDirection,
pub gp3_value: LogicLevel,
pub gp3_direction: GpioDirection,
}
const FLASH_START_BYTE: usize = 4;
const SRAM_START_BYTE: usize = 22;
impl GpSettings {
pub(crate) fn try_from_flash_buffer(buf: &[u8; 64]) -> Result<Self, Error> {
GpSettings::try_from_buffer(FLASH_START_BYTE, buf)
}
pub(crate) fn try_from_sram_buffer(buf: &[u8; 64]) -> Result<Self, Error> {
GpSettings::try_from_buffer(SRAM_START_BYTE, buf)
}
fn try_from_buffer(start_byte: usize, buf: &[u8; 64]) -> Result<Self, Error> {
Ok(Self {
gp0_value: buf[start_byte].get_bit(4).into(),
gp0_direction: buf[start_byte].get_bit(3).into(),
gp0_mode: buf[start_byte].get_bits(0..=2).try_into()?,
gp1_value: buf[start_byte + 1].get_bit(4).into(),
gp1_direction: buf[start_byte + 1].get_bit(3).into(),
gp1_mode: buf[start_byte + 1].get_bits(0..=2).try_into()?,
gp2_value: buf[start_byte + 2].get_bit(4).into(),
gp2_direction: buf[start_byte + 2].get_bit(3).into(),
gp2_mode: buf[start_byte + 2].get_bits(0..=2).try_into()?,
gp3_value: buf[start_byte + 3].get_bit(4).into(),
gp3_direction: buf[start_byte + 3].get_bit(3).into(),
gp3_mode: buf[start_byte + 3].get_bits(0..=2).try_into()?,
})
}
pub(crate) fn apply_to_flash_buffer(&self, buf: &mut [u8; 64]) {
buf[2].set_bit(4, self.gp0_value.into());
buf[2].set_bit(3, self.gp0_direction.into());
buf[2].set_bits(0..=2, self.gp0_mode.into());
buf[3].set_bit(4, self.gp1_value.into());
buf[3].set_bit(3, self.gp1_direction.into());
buf[3].set_bits(0..=2, self.gp1_mode.into());
buf[4].set_bit(4, self.gp2_value.into());
buf[4].set_bit(3, self.gp2_direction.into());
buf[4].set_bits(0..=2, self.gp2_mode.into());
buf[5].set_bit(4, self.gp3_value.into());
buf[5].set_bit(3, self.gp3_direction.into());
buf[5].set_bits(0..=2, self.gp3_mode.into());
}
}
#[doc(hidden)]
macro_rules! pin_mode_err {
($pin:literal, $mode:ident) => {
return Err(Error::InvalidPinModeFromDevice {
pin: $pin,
mode: $mode,
})
};
}
#[derive(Debug, Clone, Copy)]
pub enum Gp0Mode {
UartReceiveIndicator,
UsbSuspendState,
Gpio,
}
#[doc(hidden)]
impl TryFrom<u8> for Gp0Mode {
type Error = Error;
fn try_from(mode: u8) -> Result<Self, Error> {
assert!(mode <= 0b111, "Incorrect use of the from constructor.");
Ok(match mode {
0b010 => Self::UartReceiveIndicator,
0b001 => Self::UsbSuspendState,
0b000 => Self::Gpio,
_ => pin_mode_err!("GP0", mode),
})
}
}
#[doc(hidden)]
impl From<Gp0Mode> for u8 {
fn from(value: Gp0Mode) -> Self {
match value {
Gp0Mode::UsbSuspendState => 0b010,
Gp0Mode::UartReceiveIndicator => 0b001,
Gp0Mode::Gpio => 0b000,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum Gp1Mode {
ClockOutput,
InterruptDetection,
UartTransmitIndicator,
AnalogInput,
Gpio,
}
impl Gp1Mode {
pub(crate) fn is_analog_input(&self) -> bool {
matches!(self, Self::AnalogInput)
}
}
#[doc(hidden)]
impl TryFrom<u8> for Gp1Mode {
type Error = Error;
fn try_from(mode: u8) -> Result<Self, Error> {
assert!(mode <= 0b111, "Incorrect use of the from constructor.");
Ok(match mode {
0b001 => Self::ClockOutput,
0b100 => Self::InterruptDetection,
0b011 => Self::UartTransmitIndicator,
0b010 => Self::AnalogInput,
0b000 => Self::Gpio,
_ => pin_mode_err!("GP1", mode),
})
}
}
#[doc(hidden)]
impl From<Gp1Mode> for u8 {
fn from(value: Gp1Mode) -> Self {
match value {
Gp1Mode::InterruptDetection => 0b100,
Gp1Mode::UartTransmitIndicator => 0b11,
Gp1Mode::AnalogInput => 0b010,
Gp1Mode::ClockOutput => 0b001,
Gp1Mode::Gpio => 0b000,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum Gp2Mode {
AnalogOutput,
AnalogInput,
UsbDeviceConfiguredStatus,
Gpio,
}
impl Gp2Mode {
pub(crate) fn is_analog_input(&self) -> bool {
matches!(self, Self::AnalogInput)
}
}
#[doc(hidden)]
impl TryFrom<u8> for Gp2Mode {
type Error = Error;
fn try_from(mode: u8) -> Result<Self, Error> {
assert!(mode <= 0b111, "Incorrect use of the from constructor.");
Ok(match mode {
0b011 => Self::AnalogOutput,
0b010 => Self::AnalogInput,
0b001 => Self::UsbDeviceConfiguredStatus,
0b000 => Self::Gpio,
_ => pin_mode_err!("GP2", mode),
})
}
}
#[doc(hidden)]
impl From<Gp2Mode> for u8 {
fn from(value: Gp2Mode) -> Self {
match value {
Gp2Mode::AnalogOutput => 0b011,
Gp2Mode::AnalogInput => 0b010,
Gp2Mode::UsbDeviceConfiguredStatus => 0b001,
Gp2Mode::Gpio => 0b000,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum Gp3Mode {
AnalogOutput,
AnalogInput,
I2cActivityIndicator,
Gpio,
}
impl Gp3Mode {
pub(crate) fn is_analog_input(&self) -> bool {
matches!(self, Self::AnalogInput)
}
}
#[doc(hidden)]
impl TryFrom<u8> for Gp3Mode {
type Error = Error;
fn try_from(mode: u8) -> Result<Self, Error> {
assert!(mode <= 0b111, "Incorrect use of the from constructor.");
Ok(match mode {
0b011 => Self::AnalogOutput,
0b010 => Self::AnalogInput,
0b001 => Self::I2cActivityIndicator,
0b000 => Self::Gpio,
_ => pin_mode_err!("GP3", mode),
})
}
}
#[doc(hidden)]
impl From<Gp3Mode> for u8 {
fn from(value: Gp3Mode) -> Self {
match value {
Gp3Mode::AnalogOutput => 0b011,
Gp3Mode::AnalogInput => 0b010,
Gp3Mode::I2cActivityIndicator => 0b001,
Gp3Mode::Gpio => 0b000,
}
}
}