use embedded_hal::digital::{ErrorType, InputPin, OutputPin};
use caravel_pac::{
UserProjectRegisters,
bitfields::{UserIOBits, UserIoXferBits},
};
pub struct UserIoPin {
regs: &'static UserProjectRegisters,
pub n: usize,
}
unsafe impl Send for UserIoPin {}
impl UserIoPin {
pub const fn new(regs: &'static UserProjectRegisters, n: usize) -> Self {
Self { regs, n }
}
#[inline]
pub fn configure(&mut self, f: impl FnOnce(UserIOBits) -> UserIOBits) {
unsafe {
self.regs.io[self.n].modify(f);
}
}
#[inline]
pub fn toggle(&mut self) -> Result<(), core::convert::Infallible> {
if self.is_high()? {
self.set_low()
} else {
self.set_high()
}
}
}
impl ErrorType for UserIoPin {
type Error = core::convert::Infallible;
}
impl OutputPin for UserIoPin {
#[inline]
fn set_low(&mut self) -> Result<(), Self::Error> {
if self.n < 32 {
unsafe {
self.regs.datal.modify(|x| x & !(1 << self.n));
}
} else {
unsafe {
self.regs.datah.modify(|x| x & !(1 << (self.n - 32)));
}
}
Ok(())
}
#[inline]
fn set_high(&mut self) -> Result<(), Self::Error> {
if self.n < 32 {
unsafe {
self.regs.datal.modify(|x| x | (1 << self.n));
}
} else {
unsafe {
self.regs.datah.modify(|x| x | (1 << (self.n - 32)));
}
}
Ok(())
}
}
impl InputPin for UserIoPin {
#[inline]
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(if self.n < 32 {
(self.regs.datal.read() >> self.n) & 1 != 0
} else {
(self.regs.datah.read() >> (self.n - 32)) & 1 != 0
})
}
#[inline]
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(!self.is_high()?)
}
}
pub struct UserIoBuilder {
regs: &'static UserProjectRegisters,
config: [UserIOBits; 38],
}
impl UserIoBuilder {
const fn new() -> Self {
Self {
regs: UserProjectRegisters::new(),
config: const {
let mut arr = [UserIOBits::MGMT_STD_INPUT_NOPULL; 38];
arr[0] = UserIOBits::MGMT_STD_ANALOG; arr[1] = UserIOBits::MGMT_STD_OUTPUT; arr
},
}
}
pub const fn pin(mut self, n: usize, bits: UserIOBits) -> Self {
self.config[n] = bits;
self
}
pub fn xfer(self) -> UserIo {
unsafe {
for (i, bits) in self.config.iter().enumerate() {
self.regs.io[i].write(*bits);
}
}
let mut user_io = UserIo { regs: self.regs };
user_io.transfer();
user_io
}
}
pub struct UserIo {
regs: &'static UserProjectRegisters,
}
unsafe impl Send for UserIo {}
impl UserIo {
pub const fn configure() -> UserIoBuilder {
UserIoBuilder::new()
}
pub fn pin<const N: usize>(&self) -> UserIoPin {
assert!(N < 38, "User I/O pin number must be 0-37");
UserIoPin {
regs: self.regs,
n: N,
}
}
#[inline]
pub fn pin_checked(&mut self, n: usize) -> Option<UserIoPin> {
(n < 38).then(|| UserIoPin { regs: self.regs, n })
}
pub fn transfer(&mut self) {
unsafe {
self.regs
.xfer
.write(UserIoXferBits::new().with_xfer_busy(true));
}
while self.regs.xfer.read().xfer_busy() {}
}
}