Skip to content

Commit

Permalink
runtime: Fix UART transmission to use deferred calls (#22)
Browse files Browse the repository at this point in the history
This way the debug logs don't get jammed up forever.
  • Loading branch information
swenson authored Nov 16, 2024
1 parent 454679d commit b8019b9
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 8 deletions.
4 changes: 3 additions & 1 deletion runtime/src/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ impl<'a> VeeRDefaultPeripherals<'a> {
}
}

pub fn init(&self) {}
pub fn init(&'static self) {
kernel::deferred_call::DeferredCallClient::register(&self.uart);
}
}

impl<'a> InterruptService for VeeRDefaultPeripherals<'a> {
Expand Down
47 changes: 40 additions & 7 deletions runtime/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use core::ptr::{addr_of, addr_of_mut};
use core::ptr::{read_volatile, write_volatile};
use kernel::debug;
use kernel::debug::IoWrite;
use kernel::deferred_call::{DeferredCall, DeferredCallClient};
use kernel::hil;
use kernel::hil::time::{Alarm, AlarmClient, Ticks, Ticks64, Time};
use kernel::utilities::cells::{OptionalCell, TakeCell};
Expand Down Expand Up @@ -81,6 +82,10 @@ pub struct SemihostUart<'a> {
rx_index: Cell<usize>,
rx_len: Cell<usize>,
alarm: VirtualMuxAlarm<'a, InternalTimers<'a>>,
tx_client: OptionalCell<&'a dyn hil::uart::TransmitClient>,
tx_buffer: TakeCell<'static, [u8]>,
tx_len: Cell<usize>,
deferred_call: DeferredCall,
}

impl<'a> SemihostUart<'a> {
Expand All @@ -91,6 +96,10 @@ impl<'a> SemihostUart<'a> {
rx_len: Cell::new(0),
rx_index: Cell::new(0),
alarm: VirtualMuxAlarm::new(alarm),
tx_client: OptionalCell::empty(),
tx_buffer: TakeCell::empty(),
tx_len: Cell::new(0),
deferred_call: DeferredCall::new(),
}
}

Expand Down Expand Up @@ -133,21 +142,31 @@ impl<'a> hil::uart::Configure for SemihostUart<'a> {
}

impl<'a> hil::uart::Transmit<'a> for SemihostUart<'a> {
fn set_transmit_client(&self, _client: &'a dyn hil::uart::TransmitClient) {}
fn set_transmit_client(&self, client: &'a dyn hil::uart::TransmitClient) {
self.tx_client.set(client);
}

fn transmit_buffer(
&self,
tx_buffer: &'static mut [u8],
tx_len: usize,
) -> Result<(), (ErrorCode, &'static mut [u8])> {
unsafe {
WRITER.write(&tx_buffer[..tx_len]);
if tx_len == 0 || tx_len > tx_buffer.len() {
Err((ErrorCode::SIZE, tx_buffer))
} else if self.tx_buffer.is_some() {
Err((ErrorCode::BUSY, tx_buffer))
} else {
unsafe {
WRITER.write(&tx_buffer[..tx_len]);
}
self.tx_len.set(tx_len);
self.tx_buffer.replace(tx_buffer);
// The whole buffer was transmitted immediately
self.deferred_call.set();
Ok(())
}
// Returning Ok(()) requires an async confirmation of the transfer which is supposed to happen later on.
// We have no interrupts here and nothing happens asynchronously so just write all the bytes immediately
// and pretend it failed.
Err((ErrorCode::FAIL, tx_buffer))
}

fn transmit_word(&self, _word: u32) -> Result<(), ErrorCode> {
Err(ErrorCode::FAIL)
}
Expand Down Expand Up @@ -204,3 +223,17 @@ impl<'a> AlarmClient for SemihostUart<'a> {
}
}
}

impl<'a> DeferredCallClient for SemihostUart<'a> {
fn register(&'static self) {
self.deferred_call.register(self);
}

fn handle_deferred_call(&self) {
self.tx_client.map(|client| {
self.tx_buffer.take().map(|tx_buf| {
client.transmitted_buffer(tx_buf, self.tx_len.get(), Ok(()));
});
});
}
}

0 comments on commit b8019b9

Please sign in to comment.