1use crate::gamepad::GamepadManager;
2use crate::*;
3use alloc::boxed::Box;
4use core::cell::Cell;
5use core::fmt::Display;
6use core::marker::PhantomData;
7use core::net::{IpAddr, Ipv4Addr, SocketAddr};
8use std::io::{Read, Write};
9use std::net::{TcpListener, TcpStream, UdpSocket};
10use std::path::PathBuf;
11use std::sync::mpsc;
12
13const UDP_PORT_MIN: u16 = 3110;
14const UDP_PORT_MAX: u16 = 3117;
15const TCP_PORT_MIN: u16 = 3210;
16const TCP_PORT_MAX: u16 = 3217;
17const AUDIO_BUF_SIZE: usize = SAMPLE_RATE as usize / 6;
18
19#[derive(Clone)]
20pub struct DeviceConfig {
21 pub root: PathBuf,
23
24 pub tcp_ip: IpAddr,
26
27 pub udp_ip: IpAddr,
29
30 pub peers: Vec<IpAddr>,
32
33 pub wav: Option<PathBuf>,
35}
36
37impl Default for DeviceConfig {
38 fn default() -> Self {
39 let localhost = IpAddr::V4(Ipv4Addr::LOCALHOST);
40 Self {
41 root: PathBuf::new(),
42 tcp_ip: localhost,
43 udp_ip: localhost,
44 peers: vec![localhost],
45 wav: None,
46 }
47 }
48}
49
50pub struct DeviceImpl<'a> {
51 config: DeviceConfig,
52 start: std::time::Instant,
54 gamepad: GamepadManager,
56 audio: AudioWriter,
58 _life: &'a PhantomData<()>,
59}
60
61impl<'a> DeviceImpl<'a> {
62 pub fn new(config: DeviceConfig) -> Self {
63 let audio = start_audio(&config);
64 Self {
65 start: std::time::Instant::now(),
66 gamepad: GamepadManager::new(),
67 audio,
68 config,
69 _life: &PhantomData,
70 }
71 }
72
73 pub fn update_input(&mut self, input: InputState) {
75 self.gamepad.update_input(input)
76 }
77
78 pub fn alloc_psram(&self, size: usize) -> Vec<u8> {
79 Vec::with_capacity(size)
80 }
81}
82
83impl<'a> Device for DeviceImpl<'a> {
84 type Network = NetworkImpl<'a>;
85 type Serial = SerialImpl;
86 type Dir = DirImpl;
87
88 fn now(&self) -> Instant {
89 let now = std::time::Instant::now();
90 let dur = now.duration_since(self.start);
91 Instant {
92 us: dur.as_micros() as u32,
93 }
94 }
95
96 fn delay(&self, d: Duration) {
97 let dur = core::time::Duration::from_micros(d.us as u64);
98 std::thread::sleep(dur);
99 }
100
101 fn read_input(&mut self) -> Option<InputState> {
102 self.gamepad.read_input()
103 }
104
105 fn log_debug<D: Display>(&self, src: &str, msg: D) {
106 println!("DEBUG({src}): {msg}");
107 }
108
109 fn log_error<D: Display>(&self, src: &str, msg: D) {
110 eprintln!("ERROR({src}): {msg}");
111 }
112
113 fn random(&mut self) -> u32 {
114 rand::random()
115 }
116
117 fn open_dir(&mut self, path: &[&str]) -> Result<Self::Dir, FSError> {
118 let path: PathBuf = path.iter().collect();
119 let path = self.config.root.join(path);
120 if !path.exists() {
121 return Err(FSError::NotFound);
122 }
123 if !path.is_dir() {
124 return Err(FSError::OpenedFileAsDir);
125 }
126 Ok(DirImpl { path })
127 }
128
129 fn has_headphones(&mut self) -> bool {
130 false
131 }
132
133 fn get_audio_buffer(&mut self) -> &mut [i16] {
134 self.audio.get_write_buf()
135 }
136
137 fn get_battery_status(&mut self) -> Option<BatteryStatus> {
138 use battery::units::electric_potential::microvolt;
139 let manager = battery::Manager::new().ok()?;
140 let mut batteries = manager.batteries().ok()?;
141 let battery = batteries.next()?;
142 let battery = battery.ok()?;
143 let state = battery.state();
144 let voltage = battery.voltage().get::<microvolt>();
145 Some(BatteryStatus {
146 voltage: voltage as u16,
147 connected: state == battery::State::Charging,
148 full: state == battery::State::Full,
149 })
150 }
151
152 fn network(&mut self) -> Self::Network {
153 NetworkImpl::new(self.config.clone())
154 }
155
156 fn serial(&self) -> Self::Serial {
157 SerialImpl::new(self.config.tcp_ip)
158 }
159}
160
161pub struct DirImpl {
162 path: PathBuf,
163}
164
165impl Dir for DirImpl {
166 type Read = File;
167 type Write = File;
168
169 fn open_file(&mut self, name: &str) -> Result<Self::Read, FSError> {
170 let path = self.path.join(name);
171 let file = std::fs::File::open(path)?;
172 Ok(File { file })
173 }
174
175 fn create_file(&mut self, name: &str) -> Result<Self::Write, FSError> {
176 let path = self.path.join(name);
177 if let Some(parent) = path.parent() {
178 _ = std::fs::create_dir_all(parent);
179 }
180 let file = std::fs::File::create(path)?;
181 Ok(File { file })
182 }
183
184 fn append_file(&mut self, name: &str) -> Result<Self::Write, FSError> {
185 let path = self.path.join(name);
186 let mut opts = std::fs::OpenOptions::new();
187 let file = opts.append(true).open(path)?;
188 Ok(File { file })
189 }
190
191 fn get_file_size(&mut self, name: &str) -> Result<u32, FSError> {
192 let path = self.path.join(name);
193 let meta = std::fs::metadata(path)?;
194 Ok(meta.len() as u32)
195 }
196
197 fn remove_file(&mut self, name: &str) -> Result<(), FSError> {
198 let path = self.path.join(name);
199 let res = std::fs::remove_file(path);
200 match res {
201 Ok(_) => Ok(()),
202 Err(err) => match err.kind() {
203 std::io::ErrorKind::NotFound => Ok(()),
204 _ => Err(err.into()),
205 },
206 }
207 }
208
209 fn iter_dir<F>(&mut self, mut f: F) -> Result<(), FSError>
210 where
211 F: FnMut(EntryKind, &[u8]),
212 {
213 let entries = std::fs::read_dir(&self.path)?;
214 for entry in entries {
215 let entry = entry?;
216 let path = entry.path();
217 let kind = if path.is_dir() {
218 EntryKind::Dir
219 } else if path.is_file() {
220 EntryKind::File
221 } else {
222 continue;
223 };
224 let fname = entry.file_name();
225 let fname = fname.as_encoded_bytes();
226 f(kind, fname);
227 }
228 Ok(())
229 }
230}
231
232pub struct File {
233 file: std::fs::File,
234}
235
236impl embedded_io::ErrorType for File {
237 type Error = std::io::Error;
238}
239
240impl embedded_io::Read for File {
241 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
242 std::io::Read::read(&mut self.file, buf)
243 }
244}
245
246impl embedded_io::Write for File {
247 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
248 std::io::Write::write(&mut self.file, buf)
249 }
250
251 fn flush(&mut self) -> Result<(), Self::Error> {
252 std::io::Write::flush(&mut self.file)
253 }
254}
255
256pub struct NetworkImpl<'a> {
257 config: DeviceConfig,
258 worker: Cell<Option<UdpWorker>>,
259 r_in: mpsc::Receiver<NetMessage>,
260 s_out: mpsc::Sender<NetMessage>,
261 s_stop: mpsc::Sender<()>,
262 local_addr: Option<SocketAddr>,
263 _life: &'a PhantomData<()>,
264}
265
266impl<'a> NetworkImpl<'a> {
267 fn new(config: DeviceConfig) -> Self {
268 let (s_in, r_in) = mpsc::channel();
269 let (s_out, r_out) = mpsc::channel();
270 let (s_stop, r_stop) = mpsc::channel();
271 let worker = Cell::new(Some(UdpWorker {
272 s_in,
273 r_out,
274 r_stop,
275 }));
276 Self {
277 config,
278 worker,
279 r_in,
280 s_out,
281 s_stop,
282 local_addr: None,
283 _life: &PhantomData,
284 }
285 }
286}
287
288pub type Addr = SocketAddr;
289
290impl<'a> Network for NetworkImpl<'a> {
291 type Addr = SocketAddr;
292
293 fn local_addr(&self) -> SocketAddr {
294 self.local_addr.unwrap()
295 }
296
297 fn start(&mut self) -> NetworkResult<()> {
298 let worker = self.worker.replace(None);
299 let Some(worker) = worker else {
300 return Err(NetworkError::AlreadyInitialized);
301 };
302 let local_addr = worker.start(self.config.udp_ip)?;
303 self.local_addr = Some(local_addr);
304 Ok(())
305 }
306
307 fn stop(&mut self) -> NetworkResult<()> {
308 _ = self.s_stop.send(());
309 Ok(())
310 }
311
312 fn advertise(&mut self) -> NetworkResult<()> {
313 let hello = b"HELLO".to_owned();
314 let hello: Box<[u8]> = Box::new(hello);
315 for ip in &self.config.peers {
316 for port in UDP_PORT_MIN..=UDP_PORT_MAX {
317 let addr = SocketAddr::new(*ip, port);
318 let res = self.s_out.send((addr, hello.clone()));
319 if res.is_err() {
320 return Err(NetworkError::NetThreadDeallocated);
321 }
322 }
323 }
324 Ok(())
325 }
326
327 fn recv(&mut self) -> NetworkResult<Option<(Self::Addr, Box<[u8]>)>> {
328 Ok(self.r_in.try_recv().ok())
329 }
330
331 fn send(&mut self, addr: Self::Addr, data: &[u8]) -> NetworkResult<()> {
332 if data.len() >= 200 {
333 return Err(NetworkError::OutMessageTooBig);
334 };
335 let msg = data.to_vec().into_boxed_slice();
336 let res = self.s_out.send((addr, msg));
337 if res.is_err() {
338 return Err(NetworkError::NetThreadDeallocated);
339 }
340 Ok(())
341 }
342
343 fn send_status(&mut self, _: Self::Addr) -> NetworkResult<firefly_types::spi::SendStatus> {
344 Ok(firefly_types::spi::SendStatus::Empty)
345 }
346}
347
348pub struct SerialImpl {
349 ip: IpAddr,
350 worker: Cell<Option<TcpWorker>>,
351 r_in: mpsc::Receiver<SerialMessage>,
352 s_out: mpsc::Sender<SerialMessage>,
353 s_stop: mpsc::Sender<()>,
354}
355
356impl SerialImpl {
357 fn new(ip: IpAddr) -> Self {
358 let (s_in, r_in) = mpsc::channel();
359 let (s_out, r_out) = mpsc::channel();
360 let (s_stop, r_stop) = mpsc::channel();
361 let worker = TcpWorker {
362 s_in,
363 r_out,
364 r_stop,
365 };
366 let worker = Cell::new(Some(worker));
367 Self {
368 ip,
369 worker,
370 r_in,
371 s_out,
372 s_stop,
373 }
374 }
375}
376
377impl Serial for SerialImpl {
378 fn start(&mut self) -> NetworkResult<()> {
379 let worker = self.worker.replace(None);
380 let Some(worker) = worker else {
381 return Err(NetworkError::AlreadyInitialized);
382 };
383 worker.start(self.ip)?;
384 Ok(())
385 }
386
387 fn stop(&mut self) -> NetworkResult<()> {
388 _ = self.s_stop.send(());
389 Ok(())
390 }
391
392 fn recv(&mut self) -> NetworkResult<Option<Box<[u8]>>> {
393 Ok(self.r_in.try_recv().ok())
394 }
395
396 fn send(&mut self, data: &[u8]) -> NetworkResult<()> {
397 if data.len() >= 200 {
398 return Err(NetworkError::OutMessageTooBig);
399 };
400 let msg = data.to_vec().into_boxed_slice();
401 let res = self.s_out.send(msg);
402 if res.is_err() {
403 return Err(NetworkError::NetThreadDeallocated);
404 }
405 Ok(())
406 }
407}
408type NetMessage = (SocketAddr, Box<[u8]>);
409type SerialMessage = Box<[u8]>;
410
411struct UdpWorker {
412 s_in: mpsc::Sender<NetMessage>,
413 r_out: mpsc::Receiver<NetMessage>,
414 r_stop: mpsc::Receiver<()>,
415}
416
417impl UdpWorker {
418 fn start(self, ip: IpAddr) -> Result<SocketAddr, NetworkError> {
419 let addrs: Vec<_> = (UDP_PORT_MIN..=UDP_PORT_MAX)
420 .map(|port| SocketAddr::new(ip, port))
421 .collect();
422 let socket = match UdpSocket::bind(&addrs[..]) {
423 Ok(socket) => socket,
424 Err(_) => return Err(NetworkError::CannotBind),
425 };
426 let timeout = std::time::Duration::from_millis(10);
427 socket.set_read_timeout(Some(timeout)).unwrap();
428 if let Ok(addr) = socket.local_addr() {
429 println!("listening on {addr}/udp");
430 } else {
431 println!("listening a UDP port");
432 }
433 let local_addr = socket.local_addr().unwrap();
434 std::thread::spawn(move || {
435 loop {
436 match self.r_stop.try_recv() {
437 Ok(_) | Err(mpsc::TryRecvError::Disconnected) => {
438 break;
439 }
440 Err(mpsc::TryRecvError::Empty) => {}
441 }
442 let mut buf = vec![0; 64];
443 if let Ok((size, addr)) = socket.recv_from(&mut buf) {
444 if size == 0 {
445 continue;
446 }
447 buf.truncate(size);
448 let buf = buf.into_boxed_slice();
449 _ = self.s_in.send((addr, buf));
450 }
451 if let Ok((addr, buf)) = self.r_out.try_recv() {
452 if addr == local_addr {
453 continue;
454 }
455 _ = socket.send_to(&buf, addr);
456 }
457 }
458 });
459 Ok(local_addr)
460 }
461}
462
463struct TcpWorker {
464 s_in: mpsc::Sender<SerialMessage>,
465 r_out: mpsc::Receiver<SerialMessage>,
466 r_stop: mpsc::Receiver<()>,
467}
468
469impl TcpWorker {
470 fn start(self, ip: IpAddr) -> Result<(), NetworkError> {
471 let addrs: Vec<_> = (TCP_PORT_MIN..=TCP_PORT_MAX)
472 .map(|port| SocketAddr::new(ip, port))
473 .collect();
474 let socket = match TcpListener::bind(&addrs[..]) {
475 Ok(socket) => socket,
476 Err(_) => return Err(NetworkError::CannotBind),
477 };
478 socket.set_nonblocking(true).unwrap();
479 std::thread::spawn(move || {
480 let mut streams = RingBuf::new();
481 loop {
482 match self.r_stop.try_recv() {
483 Ok(_) | Err(mpsc::TryRecvError::Disconnected) => {
484 break;
485 }
486 Err(mpsc::TryRecvError::Empty) => {}
487 }
488
489 if let Ok((stream, _addr)) = socket.accept() {
490 stream.set_nonblocking(true).unwrap();
491 streams.push(stream);
492 };
493
494 for stream in streams.iter_mut() {
495 let mut buf = vec![0; 200];
496 let Ok(size) = stream.read(&mut buf) else {
497 continue;
498 };
499 if size == 0 {
500 continue;
501 }
502 buf.truncate(size);
503 let buf = buf.into_boxed_slice();
504 _ = self.s_in.send(buf);
505 }
506 if let Ok(buf) = self.r_out.try_recv() {
507 for stream in streams.iter_mut() {
508 _ = stream.write_all(&buf)
509 }
510 }
511 }
512 });
513 Ok(())
514 }
515}
516
517struct RingBuf {
522 data: [Option<TcpStream>; 4],
523 next: usize,
524}
525
526impl RingBuf {
527 fn new() -> Self {
528 Self {
529 data: [None, None, None, None],
530 next: 0,
531 }
532 }
533
534 fn push(&mut self, val: TcpStream) {
535 self.data[self.next] = Some(val);
536 self.next = (self.next + 1) % 4
537 }
538
539 fn iter_mut(&mut self) -> impl Iterator<Item = &mut TcpStream> {
540 self.data.iter_mut().filter_map(Option::as_mut)
541 }
542}
543
544fn start_audio(config: &DeviceConfig) -> AudioWriter {
545 let wav = if let Some(filename) = &config.wav {
546 let spec = hound::WavSpec {
547 channels: 2,
548 sample_rate: SAMPLE_RATE,
549 bits_per_sample: 16,
550 sample_format: hound::SampleFormat::Int,
551 };
552 let writer = hound::WavWriter::create(filename, spec).unwrap();
553 Some(writer)
554 } else {
555 None
556 };
557
558 let (send, recv) = mpsc::sync_channel(AUDIO_BUF_SIZE);
559 let mut stream = rodio::OutputStreamBuilder::open_default_stream().unwrap();
560 stream.log_on_drop(false);
561 let mixer = stream.mixer();
562 let source = AudioReader { wav, recv };
563 mixer.add(source);
564 AudioWriter {
565 buf: [0; AUDIO_BUF_SIZE],
566 idx: 0,
567 send,
568 _stream: stream,
569 }
570}
571
572struct AudioWriter {
573 buf: [i16; AUDIO_BUF_SIZE],
574 send: mpsc::SyncSender<i16>,
575 idx: usize,
577 _stream: rodio::OutputStream,
578}
579
580impl AudioWriter {
581 fn get_write_buf(&mut self) -> &mut [i16] {
582 if self.idx == AUDIO_BUF_SIZE {
583 self.idx = 0;
584 }
585 let start = self.idx;
586 let mut idx = self.idx;
587 while idx < AUDIO_BUF_SIZE {
589 let res = self.send.try_send(self.buf[idx]);
590 if res.is_err() {
591 break;
592 }
593 idx += 1;
594 }
595 self.idx = idx;
596 &mut self.buf[start..idx]
598 }
599}
600
601struct AudioReader {
602 wav: Option<hound::WavWriter<std::io::BufWriter<std::fs::File>>>,
603 recv: mpsc::Receiver<i16>,
604}
605
606impl rodio::Source for AudioReader {
607 fn current_span_len(&self) -> Option<usize> {
608 None
609 }
610
611 fn channels(&self) -> u16 {
612 2
613 }
614
615 fn sample_rate(&self) -> u32 {
616 SAMPLE_RATE
617 }
618
619 fn total_duration(&self) -> Option<core::time::Duration> {
620 None
621 }
622}
623
624impl Iterator for AudioReader {
625 type Item = f32;
626
627 fn next(&mut self) -> Option<Self::Item> {
628 let s = self.recv.try_recv().unwrap_or_default();
629 if let Some(wav) = self.wav.as_mut() {
630 wav.write_sample(s).unwrap()
631 }
632 let s = f32::from(s) / f32::from(i16::MAX);
633 Some(s)
634 }
635}