#![no_implicit_prelude]
extern crate core;
extern crate rpsp;
use core::cmp::{self, PartialEq};
use core::convert::From;
use core::marker::Send;
use core::mem::MaybeUninit;
use core::ops::Deref;
use core::option::Option::{self, None};
use core::ptr::NonNull;
use core::result::Result::{self, Ok};
use rpsp::atomic::{Mutex, with};
use rpsp::clock::{AlarmConfig, RtcError};
use rpsp::i2c::I2cController;
use rpsp::pin::gpio::Output;
use rpsp::pin::{Pin, PinID};
use rpsp::spi::{Spi, SpiConfig, SpiDev, SpiFormat, SpiPhase, SpiPolarity};
use rpsp::time::Time;
use rpsp::{Pico, ignore_error, static_instance};
use crate::frame::ShiftRegister;
use crate::fs::Storage;
use crate::hw::{Buttons, ButtonsPtr, Leds, LedsPtr, WakeReason};
use crate::pcf::PcfRtc;
use crate::sd::Card;
#[cfg_attr(rustfmt, rustfmt_skip)]
pub use rpsp::{pin, pwm, sleep, sleep_us, ticks, ticks_ms};
const PFC_RTC_HZ: u32 = 400_000u32;
static_instance!(INSTANCE, MaybeUninit<Board>, Board::new());
pub struct InkyBoard<'a> {
i: NonNull<Board<'a>>,
p: Pico,
}
struct Board<'a> {
rtc: PcfRtc<'a>,
spi: Option<Spi>,
pwr: Pin<Output>,
leds: Leds,
wake: WakeReason,
buttons: Buttons,
}
impl<'a> Board<'a> {
#[inline(always)]
const fn new() -> MaybeUninit<Board<'a>> {
MaybeUninit::zeroed()
}
#[inline(always)]
fn is_ready(&self) -> bool {
PinID::Pin0.ne(self.pwr.id())
}
#[inline]
fn setup(&mut self, p: &Pico) {
self.pwr = Pin::get(&p, PinID::Pin2).output_high();
self.spi = None;
let s = ShiftRegister::new(&p, PinID::Pin8, PinID::Pin9, PinID::Pin10);
let w = s.read();
self.wake = WakeReason::from(w);
self.buttons = Buttons::new(w, s);
self.rtc = PcfRtc::new(unsafe { I2cController::new(&p, PinID::Pin4, PinID::Pin5, PFC_RTC_HZ).unwrap_unchecked() });
ignore_error!(self.rtc.alarm_clear_state());
ignore_error!(self.rtc.alarm_disable());
ignore_error!(self.rtc.set_timer_interrupt(false, false));
self.leds = Leds::new(p)
}
}
impl<'a> InkyBoard<'a> {
#[inline]
pub fn get() -> InkyBoard<'a> {
let p = Pico::get();
InkyBoard {
i: with(|x| {
let f = unsafe { &mut *INSTANCE.borrow_mut(x).assume_init_mut() };
if !f.is_ready() {
f.setup(&p);
}
unsafe { NonNull::new_unchecked(f) }
}),
p,
}
}
#[inline(always)]
pub fn leds(&self) -> &Leds {
&self.ptr().leds
}
#[inline]
pub fn spi_bus(&self) -> &Spi {
self.ptr().spi.get_or_insert_with(|| unsafe {
Spi::new(
&self.p,
SpiConfig::DEFAULT_BAUD_RATE,
SpiConfig::new()
.bits(8)
.format(SpiFormat::Motorola)
.phase(SpiPhase::First)
.polarity(SpiPolarity::Low)
.primary(true),
SpiDev::new_rx(PinID::Pin19, PinID::Pin18, PinID::Pin16).unwrap_unchecked(),
)
.unwrap_unchecked()
})
}
#[inline]
pub fn sync_pcf_to_rtc(&self) {
ignore_error!(self.p.rtc().set_time_from(self.pcf()));
}
#[inline]
pub fn sync_rtc_to_pcf(&self) {
ignore_error!(self.pcf().set_time_from(self.p.rtc()));
}
#[inline(always)]
pub fn buttons(&self) -> &mut Buttons {
&mut self.ptr().buttons
}
#[inline]
pub fn set_rtc_and_pcf(&self, v: Time) {
ignore_error!(self.p.rtc().set_time(v));
ignore_error!(self.pcf().set_time(v));
}
#[inline(always)]
pub fn wake_reason(&self) -> WakeReason {
self.ptr().wake
}
#[inline(always)]
pub fn i2c_bus(&self) -> &I2cController {
self.ptr().rtc.i2c_bus()
}
#[inline(always)]
pub fn pcf(&'a self) -> &'a mut PcfRtc<'a> {
&mut self.ptr().rtc
}
#[inline(always)]
pub fn sd_card(&self) -> Storage<Card<'_>> {
Storage::new(Card::new(&self.p, PinID::Pin22, self.spi_bus()))
}
#[inline(always)]
pub fn shift_register(&self) -> &ShiftRegister {
&self.ptr().buttons.shift_register()
}
pub fn set_rtc_wake(&self, secs: u32) -> Result<u32, RtcError> {
let d = self.pcf();
let mut v = d.now()?.add_seconds(cmp::min(secs as i64, 0x24EA00));
if v.secs >= 55 && v.mins <= 58 {
(v.secs, v.mins) = (5, v.mins + 1);
}
d.alarm_clear_state()?;
d.set_alarm(
AlarmConfig::new()
.month(v.month)
.day(v.day)
.hours(v.hours)
.mins(v.mins)
.secs(v.secs),
)?;
d.set_alarm_interrupt(true)?;
Ok((secs * 1_000) & 0xFFFFFFFF)
}
#[inline]
pub unsafe fn power_off(&self) {
self.ptr().pwr.low();
self.sleep(1_500);
}
pub unsafe fn deep_sleep(&self, secs: u32) -> Result<(), RtcError> {
let v = self.set_rtc_wake(secs)?;
unsafe { self.power_off() };
self.p.sleep(v);
let d: &mut PcfRtc<'_> = self.pcf();
ignore_error!(d.alarm_clear_state());
ignore_error!(d.alarm_disable());
ignore_error!(d.set_timer_interrupt(false, false));
Ok(())
}
#[inline(always)]
fn ptr(&self) -> &mut Board {
unsafe { &mut *self.i.as_ptr() }
}
}
impl Deref for InkyBoard<'_> {
type Target = Pico;
#[inline(always)]
fn deref(&self) -> &Pico {
&self.p
}
}
unsafe impl Send for Board<'_> {}
#[inline]
pub fn leds() -> LedsPtr {
LedsPtr::new(&mut InkyBoard::get().ptr().leds)
}
#[inline]
pub fn buttons() -> ButtonsPtr {
ButtonsPtr::new(InkyBoard::get().buttons())
}