use super::{GpioDirection, LogicLevel};
#[derive(Debug, Clone, Copy)]
pub struct GpioValues {
pub gp0: Option<(GpioDirection, LogicLevel)>,
pub gp1: Option<(GpioDirection, LogicLevel)>,
pub gp2: Option<(GpioDirection, LogicLevel)>,
pub gp3: Option<(GpioDirection, LogicLevel)>,
}
impl GpioValues {
pub(crate) fn from_buffer(buf: &[u8; 64]) -> Self {
Self {
gp0: parse_bytes(buf[2], buf[3]),
gp1: parse_bytes(buf[4], buf[5]),
gp2: parse_bytes(buf[6], buf[7]),
gp3: parse_bytes(buf[8], buf[9]),
}
}
}
fn parse_bytes(level_byte: u8, direction_byte: u8) -> Option<(GpioDirection, LogicLevel)> {
let level = logic_level_from_byte(level_byte);
let direction = direction_from_byte(direction_byte);
if let (Some(direction), Some(level)) = (direction, level) {
Some((direction, level))
} else {
None
}
}
fn logic_level_from_byte(byte: u8) -> Option<LogicLevel> {
const NOT_GPIO: u8 = 0xEE;
match byte {
NOT_GPIO => None,
0x00 => Some(LogicLevel::Low),
0x01 => Some(LogicLevel::High),
_ => unreachable!("Invalid byte '{byte:X}' for GPIO logic level"),
}
}
fn direction_from_byte(byte: u8) -> Option<GpioDirection> {
const NOT_GPIO: u8 = 0xEF;
match byte {
NOT_GPIO => None,
0x00 => Some(GpioDirection::Output),
0x01 => Some(GpioDirection::Input),
_ => unreachable!("Invalid byte '{byte:X}' for GPIO pin direction"),
}
}
#[derive(Default, Debug, Clone, Copy)]
pub struct GpioChanges {
gp0_direction: Option<GpioDirection>,
gp0_level: Option<LogicLevel>,
gp1_direction: Option<GpioDirection>,
gp1_level: Option<LogicLevel>,
gp2_direction: Option<GpioDirection>,
gp2_level: Option<LogicLevel>,
gp3_direction: Option<GpioDirection>,
gp3_level: Option<LogicLevel>,
}
impl GpioChanges {
pub fn new() -> Self {
Self::default()
}
pub fn with_gp0_direction(&mut self, direction: GpioDirection) -> &mut Self {
self.gp0_direction = Some(direction);
self
}
pub fn with_gp0_level(&mut self, level: LogicLevel) -> &mut Self {
self.gp0_level = Some(level);
self
}
pub fn with_gp1_direction(&mut self, direction: GpioDirection) -> &mut Self {
self.gp1_direction = Some(direction);
self
}
pub fn with_gp1_level(&mut self, level: LogicLevel) -> &mut Self {
self.gp1_level = Some(level);
self
}
pub fn with_gp2_direction(&mut self, direction: GpioDirection) -> &mut Self {
self.gp2_direction = Some(direction);
self
}
pub fn with_gp2_level(&mut self, level: LogicLevel) -> &mut Self {
self.gp2_level = Some(level);
self
}
pub fn with_gp3_direction(&mut self, direction: GpioDirection) -> &mut Self {
self.gp3_direction = Some(direction);
self
}
pub fn with_gp3_level(&mut self, level: LogicLevel) -> &mut Self {
self.gp3_level = Some(level);
self
}
pub(crate) fn apply_to_buffer(&self, buf: &mut [u8; 64]) {
const ENABLE_SETTING: u8 = 0x01;
if let Some(level) = self.gp0_level {
buf[2] = ENABLE_SETTING;
buf[3] = level.into();
}
if let Some(direction) = self.gp0_direction {
buf[4] = ENABLE_SETTING;
buf[5] = direction.into();
}
if let Some(level) = self.gp1_level {
buf[6] = ENABLE_SETTING;
buf[7] = level.into();
}
if let Some(direction) = self.gp1_direction {
buf[8] = ENABLE_SETTING;
buf[9] = direction.into();
}
if let Some(level) = self.gp2_level {
buf[10] = ENABLE_SETTING;
buf[11] = level.into();
}
if let Some(direction) = self.gp2_direction {
buf[12] = ENABLE_SETTING;
buf[13] = direction.into();
}
if let Some(level) = self.gp3_level {
buf[14] = ENABLE_SETTING;
buf[15] = level.into();
}
if let Some(direction) = self.gp3_direction {
buf[16] = ENABLE_SETTING;
buf[17] = direction.into();
}
}
}