use crate::atmega328p::hal::pin::{AnalogPin, DigitalPin};
use core::ptr::{read_volatile, write_volatile};
#[derive(Clone, Copy)]
pub enum PortName {
B,
C,
D,
}
#[repr(C, packed)]
pub struct Port {
pub pin: u8,
pub ddr: u8,
pub port: u8,
}
impl Port {
pub fn new(port_name: PortName) -> &'static mut Port {
unsafe {
&mut *match port_name {
PortName::B => 0x23 as *mut Port,
PortName::C => 0x26 as *mut Port,
PortName::D => 0x29 as *mut Port,
}
}
}
pub fn name(&self) -> PortName {
let addr = (self as *const Port) as usize;
match addr {
0x23 => PortName::B,
0x26 => PortName::C,
0x29 => PortName::D,
_ => unreachable!(),
}
}
}
#[repr(C, packed)]
#[derive(Clone, Copy)]
pub struct Pin {
pub port: *mut Port,
pub pin: u8,
}
#[derive(Clone, Copy)]
pub enum IOMode {
Input,
Output,
}
impl Port {
pub fn pin(&mut self, pin: u8) -> Option<Pin> {
if pin < 0x8 {
Some(Pin { port: self, pin })
} else {
None
}
}
}
impl Pin {
pub fn new(port_name: PortName, pin: u8) -> Option<Pin> {
Port::new(port_name).pin(pin)
}
pub fn set_mode(&mut self, io_mode: IOMode) {
if self.pin >= 8 {
return;
}
let mut ddr_val = unsafe { read_volatile(&mut (*self.port).ddr) };
ddr_val &= !(0x1 << self.pin);
ddr_val |= match io_mode {
IOMode::Input => 0x0,
IOMode::Output => 0x1 << self.pin,
};
unsafe { write_volatile(&mut (*self.port).ddr, ddr_val) }
}
pub fn toggle(&mut self) {
if self.pin >= 8 {
return;
}
unsafe { write_volatile(&mut (*self.port).pin, 0x1 << self.pin) }
}
pub fn high(&mut self) {
if self.pin >= 8 {
return;
}
let port_val = unsafe { read_volatile(&mut (*self.port).port) };
if port_val & (1 << self.pin) == 0 {
self.toggle();
}
}
pub fn low(&mut self) {
if self.pin >= 8 {
return;
}
let port_val = unsafe { read_volatile(&mut (*self.port).port) };
if port_val & (1 << self.pin) != 0 {
self.toggle();
}
}
pub fn set_output(&mut self) {
self.set_mode(IOMode::Output);
}
}
impl AnalogPin {
pub fn set_output(&mut self) {
self.pin.set_mode(IOMode::Output);
}
}
impl DigitalPin {
pub fn set_output(&mut self) {
self.pin.set_mode(IOMode::Output);
}
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;
}
}
}