use crate::ll_api::{GpioInitParam, PortNum, ll_cmd::*};
use core::marker::PhantomData;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum PortModeInput {
InFloating,
InPullUp,
InPullDown,
}
impl PortModeInput {
fn to_flag(&self) -> u32 {
match self {
PortModeInput::InFloating => GpioInitParam::InFloating.param(),
PortModeInput::InPullUp => GpioInitParam::InPU.param(),
PortModeInput::InPullDown => GpioInitParam::InPD.param(),
}
}
}
pub enum PortModeOutput {
OutOD,
OutPP,
}
impl PortModeOutput {
fn to_flag(&self) -> u32 {
match self {
PortModeOutput::OutOD => GpioInitParam::OutOD.param(),
PortModeOutput::OutPP => GpioInitParam::OutPP.param(),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(C)]
pub struct PortReg {
pub idr: *mut u16,
pub odr: *mut u16,
pub bsr: *mut u16,
pub bcr: *mut u16,
}
unsafe impl Send for PortReg {}
unsafe impl Sync for PortReg {}
pub struct InputPort;
pub struct OutputPort;
#[derive(Clone, Copy, Debug)]
pub struct Port<MODE> {
gpio: PortNum,
mask: u16,
regs: &'static PortReg,
_mode: PhantomData<MODE>,
}
impl Port<()> {
pub fn new(gpio: PortNum, mask: u16, regs: &'static PortReg) -> Self {
let port = Port {
gpio,
mask,
regs,
_mode: PhantomData,
};
port
}
pub fn into_input(&self, mode: PortModeInput) -> Port<InputPort> {
let pin_mode = mode.to_flag();
self.port_init(pin_mode);
Port {
gpio: self.gpio,
mask: self.mask,
regs: self.regs,
_mode: PhantomData,
}
}
pub fn into_output(&self, mode: PortModeOutput) -> Port<OutputPort> {
let pin_mode = mode.to_flag();
self.port_init(pin_mode);
Port {
gpio: self.gpio,
mask: self.mask,
regs: self.regs,
_mode: PhantomData,
}
}
fn port_init(&self, mode: u32) {
for pin in 0..16 {
if (self.mask & (1 << pin)) > 0 {
ll_invoke_inner!(INVOKE_ID_GPIO_INIT, self.gpio, pin, mode);
}
}
}
}
impl Port<OutputPort> {
#[inline]
pub unsafe fn set_bits_uncheck(&mut self, bits: u16) {
unsafe { core::ptr::write_volatile(self.regs.bsr, bits) }
}
#[inline]
pub unsafe fn clr_bits_uncheck(&mut self, bits: u16) {
unsafe { core::ptr::write_volatile(self.regs.bcr, bits) };
}
#[inline]
pub unsafe fn read_output_bits_uncheck(&mut self) -> u16 {
unsafe { core::ptr::read_volatile(self.regs.odr) }
}
#[inline]
pub unsafe fn write_bits_uncheck(&mut self, bits: u16) {
unsafe { core::ptr::write_volatile(self.regs.odr, bits) };
}
pub fn set_bits(&mut self, bits: u16) {
if !self.regs.bsr.is_null() {
unsafe { self.set_bits_uncheck(bits & self.mask) }
} else {
let read = self.read_output_bits();
self.write_bits(bits | read);
}
}
pub fn clr_bits(&mut self, bits: u16) {
if !self.regs.bcr.is_null() {
unsafe { self.clr_bits_uncheck(bits & self.mask) }
} else {
let read = self.read_output_bits();
self.write_bits(!bits & read);
}
}
pub fn read_output_bits(&mut self) -> u16 {
if !self.regs.odr.is_null() {
return unsafe { self.read_output_bits_uncheck() } & self.mask;
}
return 0;
}
pub fn write_bits(&mut self, bits: u16) {
if !self.regs.odr.is_null() {
unsafe {
let read = self.read_output_bits_uncheck() & !self.mask;
self.write_bits_uncheck((bits & self.mask) | read);
}
}
}
pub fn read_input_bits(&mut self) -> u16 {
if !self.regs.idr.is_null() {
return unsafe { core::ptr::read_volatile(self.regs.idr) } & self.mask;
}
return 0;
}
}
impl Port<InputPort> {
#[inline]
pub unsafe fn read_input_bits_uncheck(&mut self) -> u16 {
unsafe { core::ptr::read_volatile(self.regs.idr) }
}
pub fn read_input_bits(&mut self) -> u16 {
if !self.regs.idr.is_null() {
return unsafe { self.read_input_bits_uncheck() } & self.mask;
}
return 0;
}
}
impl<MODE> embedded_hal::digital::ErrorType for Port<MODE> {
type Error = core::convert::Infallible;
}
impl embedded_hal::digital::OutputPin for Port<OutputPort> {
#[inline(always)]
fn set_high(&mut self) -> Result<(), Self::Error> {
self.set_bits(self.mask);
Ok(())
}
#[inline(always)]
fn set_low(&mut self) -> Result<(), Self::Error> {
self.clr_bits(self.mask);
Ok(())
}
}
impl embedded_hal::digital::StatefulOutputPin for Port<OutputPort> {
#[inline(always)]
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.read_output_bits() > 0)
}
#[inline(always)]
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Ok(self.read_output_bits() == 0)
}
}
impl embedded_hal::digital::InputPin for Port<InputPort> {
#[inline(always)]
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.read_input_bits() > 0)
}
#[inline(always)]
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(self.read_input_bits() == 0)
}
}
impl embedded_hal::digital::InputPin for Port<OutputPort> {
#[inline(always)]
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.read_input_bits() > 0)
}
#[inline(always)]
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(self.read_input_bits() == 0)
}
}