From e1ac328ce63c30031ef0a38139dd02fae98704ff Mon Sep 17 00:00:00 2001 From: Alex Janka Date: Wed, 15 Mar 2023 12:02:34 +1100 Subject: [PATCH] embedded-hal --- agb/Cargo.toml | 2 ++ agb/src/serial_link/mod.rs | 73 ++++++++++++++++++++++++++++++-------- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/agb/Cargo.toml b/agb/Cargo.toml index 36659cdf..ba932d84 100644 --- a/agb/Cargo.toml +++ b/agb/Cargo.toml @@ -29,6 +29,8 @@ agb_fixnum = { version = "0.13.0", path = "../agb-fixnum" } bare-metal = "1" modular-bitfield = "0.11" rustc-hash = { version = "1", default-features = false } +embedded-hal = "0.2.7" +nb = "1.1" [package.metadata.docs.rs] default-target = "thumbv6m-none-eabi" diff --git a/agb/src/serial_link/mod.rs b/agb/src/serial_link/mod.rs index ce1540a3..9775b2cf 100644 --- a/agb/src/serial_link/mod.rs +++ b/agb/src/serial_link/mod.rs @@ -1,41 +1,67 @@ -use core::ops::Deref; +use core::ops::{Deref, DerefMut}; -use crate::memory_mapped::MemoryMapped; +use embedded_hal::serial::{Read, Write}; + +use crate::{memory_mapped::MemoryMapped, println}; const SIODATA8: MemoryMapped = unsafe { MemoryMapped::new(0x0400_012A) }; const SIOCNT: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0128) }; const RCNT: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0134) }; +#[derive(Debug)] pub enum LinkPortError { GbaErrorBit, - Blocked, } pub struct LinkPortUart; impl LinkPortUart { - pub fn init(rate: BaudRate) -> Self { + pub fn init(rate: BaudRate, with_interrupts: bool, clear_to_send: bool) -> Self { + println!("begin init"); RCNT.set(0x0); - SIOCNT.set(SioControlReg::default_uart().with_baud(rate).into()); + println!("have set rcnt"); + SIOCNT.set(0x0); + let reg: u16 = SioControlReg::default_uart() + .with_baud(rate) + .with_interrupts(with_interrupts) + .with_cts(clear_to_send) + .into(); + SIOCNT.set(reg); + println!("have set siocnt to {reg:#X}/{reg:#b}"); Self } +} - pub fn read(&mut self) -> Result { +impl Read for LinkPortUart { + type Error = LinkPortError; + + fn read(&mut self) -> Result> { match SioControlReg::from(SIOCNT.get()) { - v if *v.error => Err(LinkPortError::GbaErrorBit), - v if *v.recv_empty => Err(LinkPortError::Blocked), + v if *v.error => Err(nb::Error::Other(LinkPortError::GbaErrorBit)), + v if *v.recv_empty => Err(nb::Error::WouldBlock), _ => Ok((SIODATA8.get() & 0xFF) as u8), } } +} - pub fn write(&mut self, data: u8) -> Result<(), LinkPortError> { - match SioControlReg::from(SIOCNT.get()) { - v if *v.error => Err(LinkPortError::GbaErrorBit), - v if *v.send_full => Err(LinkPortError::Blocked), - _ => { - SIODATA8.set(data as u16); +impl Write for LinkPortUart { + type Error = LinkPortError; + + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + match self.flush() { + Ok(_) => { + SIODATA8.set(word as u16); Ok(()) } + Err(e) => Err(e), + } + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + match SioControlReg::from(SIOCNT.get()) { + v if *v.error => Err(nb::Error::Other(LinkPortError::GbaErrorBit)), + v if *v.send_full => Err(nb::Error::WouldBlock), + _ => Ok(()), } } } @@ -104,6 +130,7 @@ impl SioControlReg { recv_empty: BoolField(false), error: BoolField(false), data_8bit: BoolField(true), + // fifo_enabled: BoolField(true), fifo_enabled: BoolField(true), parity_enabled: BoolField(false), tx_enabled: BoolField(true), @@ -117,6 +144,16 @@ impl SioControlReg { self.baud_rate = rate; self } + + fn with_interrupts(mut self, interrupts: bool) -> Self { + *self.irq_enable = interrupts; + self + } + + fn with_cts(mut self, clear_to_send: bool) -> Self { + *self.flow_control = clear_to_send; + self + } } impl From for u16 { @@ -127,7 +164,7 @@ impl From for u16 { | u16::from(value.send_full) << 4 | u16::from(value.recv_empty) << 5 | u16::from(value.error) << 6 - | u16::from(value.data_8bit) << 7 + | u16::from(value.data_8bit) << 7 // bit start | u16::from(value.fifo_enabled) << 8 | u16::from(value.parity_enabled) << 9 | u16::from(value.tx_enabled) << 10 @@ -167,6 +204,12 @@ impl Deref for BoolField { } } +impl DerefMut for BoolField { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + impl From for u16 { fn from(value: BoolField) -> Self { if *value {