1#![no_implicit_prelude]
21
22extern crate core;
23extern crate rpsp;
24
25use core::cmp::{self, PartialEq};
26use core::convert::From;
27use core::marker::Send;
28use core::mem::MaybeUninit;
29use core::ops::Deref;
30use core::option::Option::{self, None};
31use core::ptr::NonNull;
32use core::result::Result::{self, Ok};
33
34use rpsp::atomic::{Mutex, with};
35use rpsp::clock::{AlarmConfig, RtcError};
36use rpsp::i2c::I2cController;
37use rpsp::pin::gpio::Output;
38use rpsp::pin::{Pin, PinID};
39use rpsp::spi::{Spi, SpiConfig, SpiDev, SpiFormat, SpiPhase, SpiPolarity};
40use rpsp::time::Time;
41use rpsp::{Pico, ignore_error, static_instance};
42
43use crate::frame::ShiftRegister;
44use crate::fs::Storage;
45use crate::hw::{Buttons, ButtonsPtr, Leds, LedsPtr, WakeReason};
46use crate::pcf::PcfRtc;
47use crate::sd::Card;
48
49#[cfg_attr(rustfmt, rustfmt_skip)]
50pub use rpsp::{pin, pwm, sleep, sleep_us, ticks, ticks_ms};
51
52const PFC_RTC_HZ: u32 = 400_000u32;
53
54static_instance!(INSTANCE, MaybeUninit<Board>, Board::new());
55
56pub struct InkyBoard<'a> {
57 i: NonNull<Board<'a>>,
58 p: Pico,
59}
60
61struct Board<'a> {
62 rtc: PcfRtc<'a>,
63 spi: Option<Spi>,
64 pwr: Pin<Output>,
65 leds: Leds,
66 wake: WakeReason,
67 buttons: Buttons,
68}
69
70impl<'a> Board<'a> {
71 #[inline(always)]
72 const fn new() -> MaybeUninit<Board<'a>> {
73 MaybeUninit::zeroed()
74 }
75
76 #[inline(always)]
77 fn is_ready(&self) -> bool {
78 PinID::Pin0.ne(self.pwr.id())
79 }
80 #[inline]
81 fn setup(&mut self, p: &Pico) {
82 self.pwr = Pin::get(&p, PinID::Pin2).output_high();
84 self.spi = None;
85 let s = ShiftRegister::new(&p, PinID::Pin8, PinID::Pin9, PinID::Pin10);
86 let w = s.read();
87 self.wake = WakeReason::from(w);
88 self.buttons = Buttons::new(w, s);
89 self.rtc = PcfRtc::new(unsafe { I2cController::new(&p, PinID::Pin4, PinID::Pin5, PFC_RTC_HZ).unwrap_unchecked() });
93 ignore_error!(self.rtc.alarm_clear_state());
95 ignore_error!(self.rtc.alarm_disable());
96 ignore_error!(self.rtc.set_timer_interrupt(false, false));
97 self.leds = Leds::new(p)
98 }
99}
100impl<'a> InkyBoard<'a> {
101 #[inline]
102 pub fn get() -> InkyBoard<'a> {
103 let p = Pico::get();
104 InkyBoard {
105 i: with(|x| {
106 let f = unsafe { &mut *INSTANCE.borrow_mut(x).assume_init_mut() };
109 if !f.is_ready() {
110 f.setup(&p);
111 }
112 unsafe { NonNull::new_unchecked(f) }
113 }),
114 p,
115 }
116 }
117
118 #[inline(always)]
119 pub fn leds(&self) -> &Leds {
120 &self.ptr().leds
121 }
122 #[inline]
123 pub fn spi_bus(&self) -> &Spi {
124 self.ptr().spi.get_or_insert_with(|| unsafe {
126 Spi::new(
133 &self.p,
134 SpiConfig::DEFAULT_BAUD_RATE,
135 SpiConfig::new()
136 .bits(8)
137 .format(SpiFormat::Motorola)
138 .phase(SpiPhase::First)
139 .polarity(SpiPolarity::Low)
140 .primary(true),
141 SpiDev::new_rx(PinID::Pin19, PinID::Pin18, PinID::Pin16).unwrap_unchecked(),
142 )
143 .unwrap_unchecked()
144 })
145 }
146 #[inline]
147 pub fn sync_pcf_to_rtc(&self) {
148 ignore_error!(self.p.rtc().set_time_from(self.pcf()));
149 }
150 #[inline]
151 pub fn sync_rtc_to_pcf(&self) {
152 ignore_error!(self.pcf().set_time_from(self.p.rtc()));
153 }
154 #[inline(always)]
155 pub fn buttons(&self) -> &mut Buttons {
156 &mut self.ptr().buttons
157 }
158 #[inline]
159 pub fn set_rtc_and_pcf(&self, v: Time) {
160 ignore_error!(self.p.rtc().set_time(v));
161 ignore_error!(self.pcf().set_time(v));
162 }
163 #[inline(always)]
164 pub fn wake_reason(&self) -> WakeReason {
165 self.ptr().wake
166 }
167 #[inline(always)]
168 pub fn i2c_bus(&self) -> &I2cController {
169 self.ptr().rtc.i2c_bus()
170 }
171 #[inline(always)]
172 pub fn pcf(&'a self) -> &'a mut PcfRtc<'a> {
173 &mut self.ptr().rtc
174 }
175 #[inline(always)]
176 pub fn sd_card(&self) -> Storage<Card<'_>> {
177 Storage::new(Card::new(&self.p, PinID::Pin22, self.spi_bus()))
178 }
179 #[inline(always)]
180 pub fn shift_register(&self) -> &ShiftRegister {
181 &self.ptr().buttons.shift_register()
182 }
183 pub fn set_rtc_wake(&self, secs: u32) -> Result<u32, RtcError> {
185 let d = self.pcf();
186 let mut v = d.now()?.add_seconds(cmp::min(secs as i64, 0x24EA00));
187 if v.secs >= 55 && v.mins <= 58 {
188 (v.secs, v.mins) = (5, v.mins + 1);
190 }
191 d.alarm_clear_state()?;
192 d.set_alarm(
193 AlarmConfig::new()
194 .month(v.month)
195 .day(v.day)
196 .hours(v.hours)
197 .mins(v.mins)
198 .secs(v.secs),
199 )?;
200 d.set_alarm_interrupt(true)?;
201 Ok((secs * 1_000) & 0xFFFFFFFF)
202 }
203
204 #[inline]
211 pub unsafe fn power_off(&self) {
212 self.ptr().pwr.low();
213 self.sleep(1_500);
215 }
216 pub unsafe fn deep_sleep(&self, secs: u32) -> Result<(), RtcError> {
224 let v = self.set_rtc_wake(secs)?;
225 unsafe { self.power_off() };
226 self.p.sleep(v);
228 let d: &mut PcfRtc<'_> = self.pcf();
229 ignore_error!(d.alarm_clear_state());
232 ignore_error!(d.alarm_disable());
233 ignore_error!(d.set_timer_interrupt(false, false));
234 Ok(())
235 }
236
237 #[inline(always)]
238 fn ptr(&self) -> &mut Board {
239 unsafe { &mut *self.i.as_ptr() }
240 }
241}
242
243impl Deref for InkyBoard<'_> {
244 type Target = Pico;
245
246 #[inline(always)]
247 fn deref(&self) -> &Pico {
248 &self.p
249 }
250}
251
252unsafe impl Send for Board<'_> {}
253
254#[inline]
255pub fn leds() -> LedsPtr {
256 LedsPtr::new(&mut InkyBoard::get().ptr().leds)
257}
258#[inline]
259pub fn buttons() -> ButtonsPtr {
260 ButtonsPtr::new(InkyBoard::get().buttons())
261}