diff --git a/src/exercises/bare-metal/rtc/src/main.rs b/src/exercises/bare-metal/rtc/src/main.rs index 9ae96055..a24a3f83 100644 --- a/src/exercises/bare-metal/rtc/src/main.rs +++ b/src/exercises/bare-metal/rtc/src/main.rs @@ -28,7 +28,7 @@ use core::hint::spin_loop; // ANCHOR: imports use crate::pl011::Uart; use core::panic::PanicInfo; -use log::{error, info, LevelFilter}; +use log::{error, info, trace, LevelFilter}; use psci::system_off; /// Base address of the primary PL011 UART. @@ -63,9 +63,43 @@ extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) { "Waiting for {}", Utc.timestamp_opt(target.into(), 0).unwrap() ); + trace!( + "matched={}, interrupt_pending={}", + rtc.matched(), + rtc.interrupt_pending() + ); while !rtc.matched() { spin_loop(); } + trace!( + "matched={}, interrupt_pending={}", + rtc.matched(), + rtc.interrupt_pending() + ); + info!("Finished waiting"); + + // Wait another 3 seconds for an interrupt. + let target = timestamp + 6; + info!( + "Waiting for {}", + Utc.timestamp_opt(target.into(), 0).unwrap() + ); + rtc.set_match(target); + rtc.clear_interrupt(); + rtc.enable_interrupt(true); + trace!( + "matched={}, interrupt_pending={}", + rtc.matched(), + rtc.interrupt_pending() + ); + while !rtc.interrupt_pending() { + spin_loop(); + } + trace!( + "matched={}, interrupt_pending={}", + rtc.matched(), + rtc.interrupt_pending() + ); info!("Finished waiting"); // ANCHOR: main_end diff --git a/src/exercises/bare-metal/rtc/src/pl031.rs b/src/exercises/bare-metal/rtc/src/pl031.rs index da714213..46545118 100644 --- a/src/exercises/bare-metal/rtc/src/pl031.rs +++ b/src/exercises/bare-metal/rtc/src/pl031.rs @@ -83,6 +83,35 @@ impl Rtc { let ris = unsafe { addr_of!((*self.registers).ris).read_volatile() }; (ris & 0x01) != 0 } + + /// Returns whether there is currently an interrupt pending. + /// + /// This should be true iff `matched` returns true and the interrupt is + /// masked. + pub fn interrupt_pending(&self) -> bool { + // Safe because we know that self.registers points to the control + // registers of a PL031 device which is appropriately mapped. + let ris = unsafe { addr_of!((*self.registers).mis).read_volatile() }; + (ris & 0x01) != 0 + } + + /// Sets or clears the interrupt mask. + /// + /// When the mask is true the interrupt is enabled; when it is false the + /// interrupt is disabled. + pub fn enable_interrupt(&mut self, mask: bool) { + let imsc = if mask { 0x01 } else { 0x00 }; + // Safe because we know that self.registers points to the control + // registers of a PL031 device which is appropriately mapped. + unsafe { addr_of_mut!((*self.registers).imsc).write_volatile(imsc) } + } + + /// Clears a pending interrupt, if any. + pub fn clear_interrupt(&mut self) { + // Safe because we know that self.registers points to the control + // registers of a PL031 device which is appropriately mapped. + unsafe { addr_of_mut!((*self.registers).icr).write_volatile(0x01) } + } } // Safe because it just contains a pointer to device memory, which can be