#![no_implicit_prelude]
extern crate core;
use core::mem::zeroed;
use core::ptr::{NonNull, write_volatile};
use core::result::Result;
use crate::atomic::{Mutex, with};
use crate::clock::{Clock, RtcClock, Timer};
use crate::pin::gpio::Output;
use crate::pin::pwm::PwmPin;
use crate::pin::{Pin, PinID, setup_pins};
use crate::static_instance;
use crate::watchdog::Watchdog;
static_instance!(INSTANCE, Inner, Inner::new());
pub struct Board(NonNull<Inner>);
pub type Pico = Board;
pub type MayFail<T> = Result<!, T>;
struct Inner {
clk: Clock,
dog: Watchdog,
timer: Timer,
}
impl Board {
#[inline]
pub fn get() -> Board {
Board(with(|x| {
let p = INSTANCE.borrow_mut(x);
if !p.is_ready() {
p.setup();
}
unsafe { NonNull::new_unchecked(p) }
}))
}
#[inline]
pub fn sleep(&self, ms: u32) {
self.ptr().timer.sleep_ms(ms)
}
#[inline]
pub fn timer(&self) -> &Timer {
&self.ptr().timer
}
#[inline]
pub fn rtc(&self) -> &RtcClock {
self.ptr().clk.rtc()
}
#[inline]
pub fn sleep_us(&self, us: u32) {
self.ptr().timer.sleep_us(us)
}
#[inline]
pub fn system_freq(&self) -> u32 {
self.ptr().clk.freq()
}
#[inline]
pub fn current_tick(&self) -> u64 {
self.ptr().timer.current_tick()
}
#[inline]
pub fn watchdog(&self) -> &Watchdog {
&self.ptr().dog
}
#[inline]
pub fn system_clock(&self) -> &Clock {
&self.ptr().clk
}
#[inline]
pub fn pin(&self, p: PinID) -> Pin<Output> {
Pin::get(self, p)
}
#[inline]
pub(crate) fn enable_ticks(&self) {
if !self.watchdog().is_ticking() {
self.watchdog().enable_ticks();
}
}
#[inline]
fn ptr(&self) -> &mut Inner {
unsafe { &mut *self.0.as_ptr() }
}
}
impl Inner {
#[inline]
const fn new() -> Inner {
unsafe { zeroed() }
}
#[inline]
fn setup(&mut self) {
setup_pins(); self.clk = Clock::new();
self.timer = Timer::new(&self.clk);
self.dog = Watchdog::new(self.clk.freq());
}
#[inline]
fn is_ready(&self) -> bool {
self.clk.freq() > 0
}
}
#[inline]
pub fn ticks() -> u64 {
Board::get().current_tick()
}
#[inline]
pub fn sleep(ms: u32) {
Board::get().sleep(ms);
}
#[inline]
pub fn watchdog_feed() {
Board::get().watchdog().feed();
}
#[inline]
pub fn ticks_ms() -> u64 {
Board::get().current_tick() / 1_000
}
#[inline]
pub fn sleep_us(us: u32) {
Board::get().sleep_us(us);
}
#[inline]
pub fn watchdog_enable_ticks() {
Board::get().watchdog().enable_ticks();
}
#[inline]
pub fn watchdog_start(ms: u32) {
Board::get().watchdog().start(ms);
}
#[inline]
pub fn pin(p: PinID) -> Pin<Output> {
Board::get().pin(p)
}
#[inline]
pub fn pwm(p: PinID) -> PwmPin<Output> {
Board::get().pin(p).into_pwm()
}
#[inline]
pub(super) fn write_reg(reg: *mut u32, v: u32, clear: bool) {
unsafe {
write_volatile(
(reg as usize + if clear { 0x3000 } else { 0x2000 }) as *mut u32,
v,
)
}
}