1use crate::errors::*;
2use alloc::boxed::Box;
3use alloc::string::String;
4use core::fmt::Display;
5use core::ops::*;
6use firefly_types::spi::SendStatus;
7
8pub const SAMPLE_RATE: u32 = 44_100;
9
10#[derive(Copy, Clone)]
12pub struct Instant {
13 pub(crate) us: u32,
15}
16
17impl Instant {
18 pub fn us(self) -> u32 {
19 self.us
20 }
21}
22
23impl Sub for Instant {
24 type Output = Duration;
25
26 fn sub(self, rhs: Self) -> Duration {
27 Duration {
28 us: self.us.saturating_sub(rhs.us),
29 }
30 }
31}
32
33impl Add<Duration> for Instant {
34 type Output = Instant;
35
36 fn add(self, rhs: Duration) -> Self::Output {
37 Self {
38 us: self.us + rhs.us,
39 }
40 }
41}
42
43#[derive(PartialEq, PartialOrd, Copy, Clone)]
47pub struct Duration {
48 pub(crate) us: u32,
49}
50
51impl Duration {
52 pub const fn from_fps(fps: u32) -> Self {
54 Self {
55 us: 1_000_000 / fps,
56 }
57 }
58
59 pub const fn from_s(s: u32) -> Self {
60 Self { us: s * 1_000_000 }
61 }
62
63 pub const fn from_ms(ms: u32) -> Self {
64 Self { us: ms * 1000 }
65 }
66
67 pub const fn from_us(us: u32) -> Self {
68 Self { us }
69 }
70
71 pub const fn s(&self) -> u32 {
72 self.us / 1_000_000
73 }
74
75 pub const fn ms(&self) -> u32 {
76 self.us / 1000
77 }
78
79 pub const fn us(&self) -> u32 {
80 self.us
81 }
82
83 pub const fn ns(&self) -> u32 {
84 self.us.saturating_mul(1000)
85 }
86}
87
88impl Sub for Duration {
89 type Output = Self;
90
91 fn sub(self, rhs: Self) -> Self {
92 Self {
93 us: self.us - rhs.us,
94 }
95 }
96}
97
98impl AddAssign for Duration {
99 fn add_assign(&mut self, rhs: Self) {
100 self.us = self.us.saturating_add(rhs.us)
101 }
102}
103
104impl SubAssign for Duration {
105 fn sub_assign(&mut self, rhs: Self) {
106 self.us = self.us.saturating_sub(rhs.us)
107 }
108}
109
110pub trait Device: Network + Serial + Wifi {
111 type Dir: Dir;
112
113 fn now(&self) -> Instant;
123
124 fn delay(&self, d: Duration);
132
133 fn read_input(&mut self) -> Option<InputState>;
135
136 fn get_name(&mut self) -> Option<&'static str>;
141
142 fn log_debug<D: Display>(&mut self, src: &str, msg: D);
149
150 fn log_error<D: Display>(&mut self, src: &str, msg: D);
157
158 fn random(&mut self) -> u32;
160
161 fn open_dir(&mut self, path: &[&str]) -> Result<Self::Dir, FSError>;
162
163 fn has_headphones(&mut self) -> bool;
165
166 fn get_audio_buffer(&mut self) -> &mut [i16];
168
169 fn get_battery_status(&mut self) -> Option<BatteryStatus>;
170
171 fn write_main_flash(&mut self, offset: u32, data: &[u8]) -> Result<(), &'static str>;
172 fn write_io_flash(&mut self, offset: u32, data: &[u8]) -> NetworkResult<()>;
173 fn switch_main_partition(&mut self, part: u8) -> Result<(), &'static str>;
174 fn switch_io_partition(&mut self, part: u8) -> NetworkResult<()>;
175}
176
177pub(crate) type NetworkResult<T> = Result<T, NetworkError>;
178
179pub trait Network {
180 type Addr: Ord;
184
185 fn net_start(&mut self) -> NetworkResult<()>;
187
188 fn net_stop(&mut self) -> NetworkResult<()>;
190
191 fn net_local_addr(&self) -> Self::Addr;
196
197 fn net_advertise(&mut self) -> NetworkResult<()>;
199
200 #[expect(clippy::type_complexity)]
202 fn net_recv(&mut self) -> NetworkResult<Option<(Self::Addr, Box<[u8]>)>>;
203
204 fn net_send(&mut self, addr: Self::Addr, data: &[u8]) -> NetworkResult<()>;
206
207 fn net_send_status(&mut self, addr: Self::Addr) -> NetworkResult<SendStatus>;
209}
210
211pub trait Wifi {
212 fn wifi_scan(&mut self) -> NetworkResult<[String; 6]>;
213 fn wifi_connect(&mut self, ssid: &str, pass: &str) -> NetworkResult<()>;
214 fn wifi_status(&mut self) -> NetworkResult<u8>;
215 fn wifi_disconnect(&mut self) -> NetworkResult<()>;
216 fn tcp_connect(&mut self, ip: u32, port: u16) -> NetworkResult<()>;
217 fn tcp_status(&mut self) -> NetworkResult<u8>;
218 fn tcp_send(&mut self, data: &[u8]) -> NetworkResult<()>;
219 fn tcp_recv(&mut self) -> NetworkResult<Box<[u8]>>;
220 fn tcp_close(&mut self) -> NetworkResult<()>;
221}
222
223pub trait Dir {
224 type Read: embedded_io::Read + embedded_io::Seek;
225 type Write: embedded_io::Write;
226
227 fn open_file(&mut self, name: &str) -> Result<Self::Read, FSError>;
245
246 fn create_file(&mut self, name: &str) -> Result<Self::Write, FSError>;
250
251 fn append_file(&mut self, name: &str) -> Result<Self::Write, FSError>;
253
254 fn get_file_size(&mut self, name: &str) -> Result<u32, FSError>;
258
259 fn remove_file(&mut self, name: &str) -> Result<(), FSError>;
263
264 fn create_dir(&mut self, name: &str) -> Result<(), FSError>;
268
269 fn remove_dir(self) -> Result<(), FSError>;
271
272 fn iter_dir<F>(&mut self, f: F) -> Result<(), FSError>
279 where
280 F: FnMut(EntryKind, &[u8]);
281}
282
283pub trait Serial {
285 fn serial_start(&mut self) -> NetworkResult<()>;
286 fn serial_stop(&mut self) -> NetworkResult<()>;
287 fn serial_recv(&mut self) -> NetworkResult<Option<Box<[u8]>>>;
288 fn serial_send(&mut self, data: &[u8]) -> NetworkResult<()>;
289}
290
291#[derive(PartialEq, Copy, Clone)]
292pub enum EntryKind {
293 Dir,
294 File,
295}
296
297#[derive(Default, Clone, Debug)]
298pub struct Pad {
299 pub x: i16,
300 pub y: i16,
301}
302
303impl From<(i16, i16)> for Pad {
304 fn from(value: (i16, i16)) -> Self {
305 Self {
306 x: value.0,
307 y: value.1,
308 }
309 }
310}
311
312impl From<Pad> for (i16, i16) {
313 fn from(value: Pad) -> Self {
314 (value.x, value.y)
315 }
316}
317
318#[derive(Default, Clone, Debug)]
319pub struct InputState {
320 pub pad: Option<Pad>,
321 pub buttons: u8,
322}
323
324impl InputState {
325 pub fn s(&self) -> bool {
326 self.buttons & 0b1 > 0
327 }
328
329 pub fn e(&self) -> bool {
330 self.buttons & 0b10 > 0
331 }
332
333 pub fn w(&self) -> bool {
334 self.buttons & 0b100 > 0
335 }
336
337 pub fn n(&self) -> bool {
338 self.buttons & 0b1000 > 0
339 }
340
341 pub fn menu(&self) -> bool {
342 self.buttons & 0b10000 > 0
343 }
344
345 pub fn rotate(&mut self) {
346 if let Some(pad) = self.pad.as_mut() {
347 pad.x = -pad.x;
348 pad.y = -pad.y;
349 };
350 let mut btns = u8::from(self.menu());
351 btns = (btns << 1) | u8::from(self.s());
352 btns = (btns << 1) | u8::from(self.e());
353 btns = (btns << 1) | u8::from(self.w());
354 btns = (btns << 1) | u8::from(self.n());
355 self.buttons = btns;
356 }
357
358 #[must_use]
359 pub fn merge(&self, other: &Self) -> Self {
360 Self {
361 pad: match &self.pad {
362 Some(pad) => Some(pad.clone()),
363 None => other.pad.clone(),
364 },
365 buttons: self.buttons | other.buttons,
366 }
367 }
368}
369
370#[derive(PartialEq, Eq, Clone, Copy)]
376pub struct BatteryStatus {
377 pub voltage: u16,
387
388 pub connected: bool,
392
393 pub full: bool,
395}
396
397