use crate::atmega2560p::hal::pin::{AnalogPin, DigitalPin};
use core::{
ptr::{read_volatile, write_volatile},
usize,
};
#[derive(Clone, Copy)]
pub enum PortName {
A,
B,
C,
D,
E,
F,
G,
H,
J,
K,
L,
}
#[derive(Clone, Copy)]
pub enum IOMode {
Input,
Output,
}
#[repr(C, packed)]
pub struct Port {
pub pin: u8,
pub ddr: u8,
pub port: u8,
}
#[repr(C, packed)]
#[derive(Clone, Copy)]
pub struct Pin {
pub port: *mut Port,
pub pin: usize,
}
impl Port {
pub fn new(name: PortName) -> &'static mut Port {
match name {
PortName::A => unsafe { &mut *(0x20 as *mut Port) },
PortName::B => unsafe { &mut *(0x23 as *mut Port) },
PortName::C => unsafe { &mut *(0x26 as *mut Port) },
PortName::D => unsafe { &mut *(0x29 as *mut Port) },
PortName::E => unsafe { &mut *(0x2C as *mut Port) },
PortName::F => unsafe { &mut *(0x2F as *mut Port) },
PortName::G => unsafe { &mut *(0x32 as *mut Port) },
PortName::H => unsafe { &mut *(0x100 as *mut Port) },
PortName::J => unsafe { &mut *(0x103 as *mut Port) },
PortName::K => unsafe { &mut *(0x106 as *mut Port) },
PortName::L => unsafe { &mut *(0x109 as *mut Port) },
}
}
pub fn name(&self) -> PortName {
let address = (self as *const Port) as usize; match address {
0x20 => PortName::A,
0x23 => PortName::B,
0x26 => PortName::C,
0x29 => PortName::D,
0x2C => PortName::E,
0x2F => PortName::F,
0x32 => PortName::G,
0x100 => PortName::H,
0x103 => PortName::J,
0x106 => PortName::K,
0x109 => PortName::L,
_ => unreachable!(),
}
}
pub fn pin(&mut self, pin: usize) -> Option<Pin> {
if pin < 0x8 {
Some(Pin { port: self, pin })
} else {
None
}
}
}
impl Pin {
pub fn new(port: PortName, pin: usize) -> Option<Pin> {
Port::new(port).pin(pin)
}
pub fn set_pin_mode(&mut self, mode: IOMode) {
let mut ddr_val = unsafe { read_volatile(&mut (*self.port).ddr) };
ddr_val &= !(0x1 << self.pin);
ddr_val |= match mode {
IOMode::Input => 0x0,
IOMode::Output => 0x1 << self.pin,
};
unsafe { write_volatile(&mut (*self.port).ddr, ddr_val) }
}
pub fn set_output(&mut self) {
self.set_pin_mode(IOMode::Output);
}
pub fn set_input(&mut self) {
self.set_pin_mode(IOMode::Input);
}
}
impl AnalogPin {
pub fn set_output(&mut self) {
self.pin.set_pin_mode(IOMode::Output);
}
pub fn set_input(&mut self) {
self.pin.set_pin_mode(IOMode::Input);
}
}
impl DigitalPin {
pub fn set_output(&mut self) {
self.pin.set_pin_mode(IOMode::Output);
}
pub fn set_input(&mut self) {
self.pin.set_pin_mode(IOMode::Input);
}
pub fn read(&mut self) -> u8 {
let port_val = unsafe { read_volatile(&mut (*self.pin.port).port) };
if port_val & (1 << self.pin.pin) == 0 {
return 0;
} else {
return 1;
}
}
}