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::{SocketAddrV4, 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: Option<AudioWriter>,
58 wifi_status: u8,
59 network: NetworkImpl<'a>,
60 serial: SerialImpl,
61 tcp_conn: Option<TcpStream>,
62}
63
64impl<'a> DeviceImpl<'a> {
65 pub fn new(config: DeviceConfig) -> Self {
66 #[cfg(not(target_os = "android"))]
67 let audio = start_audio(&config);
68 #[cfg(target_os = "android")]
69 let audio = None;
70 Self {
71 start: std::time::Instant::now(),
72 gamepad: GamepadManager::new(),
73 audio,
74 config,
75 wifi_status: 2,
76 network: NetworkImpl::new(),
77 serial: SerialImpl::new(),
78 tcp_conn: None,
79 }
80 }
81
82 pub fn update_input(&mut self, input: InputState) {
84 self.gamepad.update_input(input)
85 }
86
87 pub fn alloc_psram(&self, size: usize) -> Vec<u8> {
88 Vec::with_capacity(size)
89 }
90}
91
92impl<'a> Device for DeviceImpl<'a> {
93 type Dir = DirImpl;
94
95 fn now(&self) -> Instant {
96 let now = std::time::Instant::now();
97 let dur = now.duration_since(self.start);
98 Instant {
99 us: dur.as_micros() as u32,
100 }
101 }
102
103 fn delay(&self, d: Duration) {
104 let dur = core::time::Duration::from_micros(d.us as u64);
105 std::thread::sleep(dur);
106 }
107
108 fn read_input(&mut self) -> Option<InputState> {
109 self.gamepad.read_input()
110 }
111
112 fn log_debug<D: Display>(&mut self, src: &str, msg: D) {
113 println!("DEBUG({src}): {msg}");
114 }
115
116 fn log_error<D: Display>(&mut self, src: &str, msg: D) {
117 eprintln!("ERROR({src}): {msg}");
118 }
119
120 fn random(&mut self) -> u32 {
121 rand::random()
122 }
123
124 fn open_dir(&mut self, path: &[&str]) -> Result<Self::Dir, FSError> {
125 let path: PathBuf = path.iter().collect();
126 let path = self.config.root.join(path);
127 if !path.exists() {
128 return Err(FSError::NotFound);
129 }
130 if !path.is_dir() {
131 return Err(FSError::OpenedFileAsDir);
132 }
133 Ok(DirImpl { path })
134 }
135
136 fn has_headphones(&mut self) -> bool {
137 false
138 }
139
140 fn get_audio_buffer(&mut self) -> &mut [i16] {
141 match &mut self.audio {
142 Some(audio) => audio.get_write_buf(),
143 None => &mut [][..],
144 }
145 }
146
147 #[cfg(target_os = "android")]
148 fn get_battery_status(&mut self) -> Option<BatteryStatus> {
149 None
150 }
151
152 #[cfg(not(target_os = "android"))]
153 fn get_battery_status(&mut self) -> Option<BatteryStatus> {
154 use battery::units::electric_potential::microvolt;
155 let manager = battery::Manager::new().ok()?;
156 let mut batteries = manager.batteries().ok()?;
157 let battery = batteries.next()?;
158 let battery = battery.ok()?;
159 let state = battery.state();
160 let voltage = battery.voltage().get::<microvolt>();
161 Some(BatteryStatus {
162 voltage: voltage as u16,
163 connected: state == battery::State::Charging,
164 full: state == battery::State::Full,
165 })
166 }
167}
168
169pub struct DirImpl {
170 path: PathBuf,
171}
172
173impl Dir for DirImpl {
174 type Read = File;
175 type Write = File;
176
177 fn open_file(&mut self, name: &str) -> Result<Self::Read, FSError> {
178 let path = self.path.join(name);
179 let file = std::fs::File::open(path)?;
180 Ok(File { file })
181 }
182
183 fn create_file(&mut self, name: &str) -> Result<Self::Write, FSError> {
184 let path = self.path.join(name);
185 if let Some(parent) = path.parent() {
186 _ = std::fs::create_dir_all(parent);
187 }
188 let file = std::fs::File::create(path)?;
189 Ok(File { file })
190 }
191
192 fn append_file(&mut self, name: &str) -> Result<Self::Write, FSError> {
193 let path = self.path.join(name);
194 let mut opts = std::fs::OpenOptions::new();
195 let file = opts.append(true).open(path)?;
196 Ok(File { file })
197 }
198
199 fn get_file_size(&mut self, name: &str) -> Result<u32, FSError> {
200 let path = self.path.join(name);
201 let meta = std::fs::metadata(path)?;
202 Ok(meta.len() as u32)
203 }
204
205 fn remove_file(&mut self, name: &str) -> Result<(), FSError> {
206 let path = self.path.join(name);
207 let res = std::fs::remove_file(path);
208 match res {
209 Ok(_) => Ok(()),
210 Err(err) => match err.kind() {
211 std::io::ErrorKind::NotFound => Ok(()),
212 _ => Err(err.into()),
213 },
214 }
215 }
216
217 fn create_dir(&mut self, name: &str) -> Result<(), FSError> {
218 let path = self.path.join(name);
219 std::fs::create_dir(path)?;
220 Ok(())
221 }
222
223 fn remove_dir(self) -> Result<(), FSError> {
224 let res = std::fs::remove_dir_all(&self.path);
225 match res {
226 Ok(_) => Ok(()),
227 Err(err) => match err.kind() {
228 std::io::ErrorKind::NotFound => Ok(()),
229 _ => Err(err.into()),
230 },
231 }
232 }
233
234 fn iter_dir<F>(&mut self, mut f: F) -> Result<(), FSError>
235 where
236 F: FnMut(EntryKind, &[u8]),
237 {
238 let entries = std::fs::read_dir(&self.path)?;
239 for entry in entries {
240 let entry = entry?;
241 let path = entry.path();
242 let kind = if path.is_dir() {
243 EntryKind::Dir
244 } else if path.is_file() {
245 EntryKind::File
246 } else {
247 continue;
248 };
249 let fname = entry.file_name();
250 let fname = fname.as_encoded_bytes();
251 f(kind, fname);
252 }
253 Ok(())
254 }
255}
256
257pub struct File {
258 file: std::fs::File,
259}
260
261impl embedded_io::ErrorType for File {
262 type Error = std::io::Error;
263}
264
265impl embedded_io::Read for File {
266 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
267 std::io::Read::read(&mut self.file, buf)
268 }
269}
270
271impl embedded_io::Write for File {
272 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
273 std::io::Write::write(&mut self.file, buf)
274 }
275
276 fn flush(&mut self) -> Result<(), Self::Error> {
277 std::io::Write::flush(&mut self.file)
278 }
279}
280
281pub struct NetworkImpl<'a> {
282 worker: Cell<Option<UdpWorker>>,
283 r_in: mpsc::Receiver<NetMessage>,
284 s_out: mpsc::Sender<NetMessage>,
285 s_stop: mpsc::Sender<()>,
286 local_addr: Option<SocketAddr>,
287 _life: &'a PhantomData<()>,
288}
289
290impl<'a> NetworkImpl<'a> {
291 fn new() -> Self {
292 let (s_in, r_in) = mpsc::channel();
293 let (s_out, r_out) = mpsc::channel();
294 let (s_stop, r_stop) = mpsc::channel();
295 let worker = Cell::new(Some(UdpWorker {
296 s_in,
297 r_out,
298 r_stop,
299 }));
300 Self {
301 worker,
302 r_in,
303 s_out,
304 s_stop,
305 local_addr: None,
306 _life: &PhantomData,
307 }
308 }
309}
310
311pub type Addr = SocketAddr;
312
313impl<'a> Network for DeviceImpl<'a> {
314 type Addr = SocketAddr;
315
316 fn net_local_addr(&self) -> SocketAddr {
317 self.network.local_addr.unwrap()
318 }
319
320 fn net_start(&mut self) -> NetworkResult<()> {
321 let worker = self.network.worker.replace(None);
322 let Some(worker) = worker else {
323 return Ok(());
324 };
325 let local_addr = worker.start(self.config.udp_ip)?;
326 self.network.local_addr = Some(local_addr);
327 Ok(())
328 }
329
330 fn net_stop(&mut self) -> NetworkResult<()> {
331 _ = self.network.s_stop.send(());
332 Ok(())
333 }
334
335 fn net_advertise(&mut self) -> NetworkResult<()> {
336 let hello = b"HELLO".to_owned();
337 let hello: Box<[u8]> = Box::new(hello);
338 for ip in &self.config.peers {
339 for port in UDP_PORT_MIN..=UDP_PORT_MAX {
340 let addr = SocketAddr::new(*ip, port);
341 let res = self.network.s_out.send((addr, hello.clone()));
342 if res.is_err() {
343 return Err(NetworkError::NetThreadDeallocated);
344 }
345 }
346 }
347 Ok(())
348 }
349
350 fn net_recv(&mut self) -> NetworkResult<Option<(Self::Addr, Box<[u8]>)>> {
351 Ok(self.network.r_in.try_recv().ok())
352 }
353
354 fn net_send(&mut self, addr: Self::Addr, data: &[u8]) -> NetworkResult<()> {
355 if data.len() >= 200 {
356 return Err(NetworkError::OutMessageTooBig);
357 };
358 let msg = data.to_vec().into_boxed_slice();
359 let res = self.network.s_out.send((addr, msg));
360 if res.is_err() {
361 return Err(NetworkError::NetThreadDeallocated);
362 }
363 Ok(())
364 }
365
366 fn net_send_status(&mut self, _: Self::Addr) -> NetworkResult<firefly_types::spi::SendStatus> {
367 Ok(firefly_types::spi::SendStatus::Empty)
368 }
369}
370
371pub struct SerialImpl {
372 worker: Cell<Option<TcpWorker>>,
373 r_in: mpsc::Receiver<SerialMessage>,
374 s_out: mpsc::Sender<SerialMessage>,
375 s_stop: mpsc::Sender<()>,
376}
377
378impl SerialImpl {
379 fn new() -> Self {
380 let (s_in, r_in) = mpsc::channel();
381 let (s_out, r_out) = mpsc::channel();
382 let (s_stop, r_stop) = mpsc::channel();
383 let worker = TcpWorker {
384 s_in,
385 r_out,
386 r_stop,
387 };
388 let worker = Cell::new(Some(worker));
389 Self {
390 worker,
391 r_in,
392 s_out,
393 s_stop,
394 }
395 }
396}
397
398impl Serial for DeviceImpl<'_> {
399 fn serial_start(&mut self) -> NetworkResult<()> {
400 let worker = self.serial.worker.replace(None);
401 let Some(worker) = worker else {
402 return Ok(());
403 };
404 worker.start(self.config.tcp_ip)?;
405 Ok(())
406 }
407
408 fn serial_stop(&mut self) -> NetworkResult<()> {
409 _ = self.serial.s_stop.send(());
410 Ok(())
411 }
412
413 fn serial_recv(&mut self) -> NetworkResult<Option<Box<[u8]>>> {
414 Ok(self.serial.r_in.try_recv().ok())
415 }
416
417 fn serial_send(&mut self, data: &[u8]) -> NetworkResult<()> {
418 if data.len() >= 200 {
419 return Err(NetworkError::OutMessageTooBig);
420 };
421 let msg = data.to_vec().into_boxed_slice();
422 let res = self.serial.s_out.send(msg);
423 if res.is_err() {
424 return Err(NetworkError::NetThreadDeallocated);
425 }
426 Ok(())
427 }
428}
429
430impl Wifi for DeviceImpl<'_> {
431 fn wifi_scan(&mut self) -> NetworkResult<[String; 6]> {
432 let points = ["Default Network", "", "", "", "", ""];
433 let points = points.map(|s| s.to_string());
434 Ok(points)
435 }
436
437 fn wifi_connect(&mut self, ssid: &str, pass: &str) -> NetworkResult<()> {
438 if ssid != "Default Network" {
439 self.wifi_status = 2; } else if pass == "invalid" {
441 self.wifi_status = 1; } else {
443 self.wifi_status = 3; }
445 Ok(())
446 }
447
448 fn wifi_status(&mut self) -> NetworkResult<u8> {
449 if self.wifi_status == 3 {
450 self.wifi_status = 4; Ok(3)
452 } else {
453 Ok(self.wifi_status)
454 }
455 }
456
457 fn wifi_disconnect(&mut self) -> NetworkResult<()> {
458 self.wifi_status = 2;
459 Ok(())
460 }
461
462 fn tcp_connect(&mut self, ip: u32, port: u16) -> NetworkResult<()> {
463 if self.wifi_status != 4 {
464 return Err(NetworkError::Error("not connected to wifi"));
465 }
466 let ip = Ipv4Addr::new(
467 (ip >> 24) as u8,
468 (ip >> 16) as u8,
469 (ip >> 8) as u8,
470 ip as u8,
471 );
472 let addr = SocketAddrV4::new(ip, port);
473 let Ok(stream) = TcpStream::connect(addr) else {
474 return Err(NetworkError::CannotBind);
475 };
476 _ = stream.set_nonblocking(true);
477 self.tcp_conn = Some(stream);
478 Ok(())
479 }
480
481 fn tcp_status(&mut self) -> NetworkResult<u8> {
482 let Some(stream) = &mut self.tcp_conn else {
483 return Ok(1);
484 };
485 if stream.peer_addr().is_err() {
486 return Ok(1);
487 }
488 Ok(5)
489 }
490
491 fn tcp_send(&mut self, data: &[u8]) -> NetworkResult<()> {
492 let Some(stream) = &mut self.tcp_conn else {
493 return Err(NetworkError::NotInitialized);
494 };
495 let res = stream.write_all(data);
496 if let Err(err) = res {
497 let err = alloc::format!("{err}");
498 return Err(NetworkError::OwnedError(err));
499 }
500 Ok(())
501 }
502
503 fn tcp_recv(&mut self) -> NetworkResult<Box<[u8]>> {
504 let Some(stream) = &mut self.tcp_conn else {
505 return Err(NetworkError::NotInitialized);
506 };
507 let mut buf = vec![0; 80];
508 let n = match stream.read(&mut buf) {
509 Ok(n) => n,
510 Err(err) => {
511 if err.kind() == std::io::ErrorKind::WouldBlock {
512 0
513 } else {
514 return Err(NetworkError::Error("failed to read incoming TCP data"));
515 }
516 }
517 };
518 buf.truncate(n);
519 Ok(buf.into_boxed_slice())
520 }
521
522 fn tcp_close(&mut self) -> NetworkResult<()> {
523 let Some(stream) = self.tcp_conn.take() else {
524 return Ok(());
525 };
526 _ = stream.shutdown(std::net::Shutdown::Both);
527 Ok(())
528 }
529}
530
531type NetMessage = (SocketAddr, Box<[u8]>);
532type SerialMessage = Box<[u8]>;
533
534struct UdpWorker {
535 s_in: mpsc::Sender<NetMessage>,
536 r_out: mpsc::Receiver<NetMessage>,
537 r_stop: mpsc::Receiver<()>,
538}
539
540impl UdpWorker {
541 fn start(self, ip: IpAddr) -> Result<SocketAddr, NetworkError> {
542 let addrs: Vec<_> = (UDP_PORT_MIN..=UDP_PORT_MAX)
543 .map(|port| SocketAddr::new(ip, port))
544 .collect();
545 let socket = match UdpSocket::bind(&addrs[..]) {
546 Ok(socket) => socket,
547 Err(_) => return Err(NetworkError::CannotBind),
548 };
549 let timeout = std::time::Duration::from_millis(10);
550 socket.set_read_timeout(Some(timeout)).unwrap();
551 if let Ok(addr) = socket.local_addr() {
552 println!("listening on {addr}/udp");
553 } else {
554 println!("listening a UDP port");
555 }
556 let local_addr = socket.local_addr().unwrap();
557 std::thread::spawn(move || {
558 loop {
559 match self.r_stop.try_recv() {
560 Ok(_) | Err(mpsc::TryRecvError::Disconnected) => {
561 break;
562 }
563 Err(mpsc::TryRecvError::Empty) => {}
564 }
565 let mut buf = vec![0; 64];
566 if let Ok((size, addr)) = socket.recv_from(&mut buf) {
567 if size == 0 {
568 continue;
569 }
570 buf.truncate(size);
571 let buf = buf.into_boxed_slice();
572 _ = self.s_in.send((addr, buf));
573 }
574 if let Ok((addr, buf)) = self.r_out.try_recv() {
575 if addr == local_addr {
576 continue;
577 }
578 _ = socket.send_to(&buf, addr);
579 }
580 }
581 });
582 Ok(local_addr)
583 }
584}
585
586struct TcpWorker {
587 s_in: mpsc::Sender<SerialMessage>,
588 r_out: mpsc::Receiver<SerialMessage>,
589 r_stop: mpsc::Receiver<()>,
590}
591
592impl TcpWorker {
593 fn start(self, ip: IpAddr) -> Result<(), NetworkError> {
594 let addrs: Vec<_> = (TCP_PORT_MIN..=TCP_PORT_MAX)
595 .map(|port| SocketAddr::new(ip, port))
596 .collect();
597 let Ok(socket) = TcpListener::bind(&addrs[..]) else {
598 return Err(NetworkError::CannotBind);
599 };
600 socket.set_nonblocking(true).unwrap();
601 std::thread::spawn(move || {
602 let mut streams = RingBuf::new();
603 loop {
604 match self.r_stop.try_recv() {
605 Ok(_) | Err(mpsc::TryRecvError::Disconnected) => {
606 break;
607 }
608 Err(mpsc::TryRecvError::Empty) => {}
609 }
610
611 if let Ok((stream, _addr)) = socket.accept() {
612 stream.set_nonblocking(true).unwrap();
613 streams.push(stream);
614 };
615
616 for stream in streams.iter_mut() {
617 let mut buf = vec![0; 200];
618 let Ok(size) = stream.read(&mut buf) else {
619 continue;
620 };
621 if size == 0 {
622 continue;
623 }
624 buf.truncate(size);
625 let buf = buf.into_boxed_slice();
626 _ = self.s_in.send(buf);
627 }
628 if let Ok(buf) = self.r_out.try_recv() {
629 for stream in streams.iter_mut() {
630 _ = stream.write_all(&buf)
631 }
632 }
633 }
634 });
635 Ok(())
636 }
637}
638
639struct RingBuf {
644 data: [Option<TcpStream>; 4],
645 next: usize,
646}
647
648impl RingBuf {
649 fn new() -> Self {
650 Self {
651 data: [None, None, None, None],
652 next: 0,
653 }
654 }
655
656 fn push(&mut self, val: TcpStream) {
657 self.data[self.next] = Some(val);
658 self.next = (self.next + 1) % 4
659 }
660
661 fn iter_mut(&mut self) -> impl Iterator<Item = &mut TcpStream> {
662 self.data.iter_mut().filter_map(Option::as_mut)
663 }
664}
665
666#[cfg(not(target_os = "android"))]
667fn start_audio(config: &DeviceConfig) -> Option<AudioWriter> {
668 let wav = if let Some(filename) = &config.wav {
669 let spec = hound::WavSpec {
670 channels: 2,
671 sample_rate: SAMPLE_RATE,
672 bits_per_sample: 16,
673 sample_format: hound::SampleFormat::Int,
674 };
675 let writer = hound::WavWriter::create(filename, spec).unwrap();
676 Some(writer)
677 } else {
678 None
679 };
680
681 let (send, recv) = mpsc::sync_channel(AUDIO_BUF_SIZE);
682 let Ok(mut stream) = rodio::OutputStreamBuilder::open_default_stream() else {
683 eprintln!("WARNING: audio device is not available, sound will be disabled");
684 return None;
685 };
686 stream.log_on_drop(false);
687 let mixer = stream.mixer();
688 let source = AudioReader { wav, recv };
689 mixer.add(source);
690 let audio = AudioWriter {
691 buf: [0; AUDIO_BUF_SIZE],
692 idx: 0,
693 send,
694 _stream: stream,
695 };
696 Some(audio)
697}
698
699struct AudioWriter {
700 buf: [i16; AUDIO_BUF_SIZE],
701 send: mpsc::SyncSender<i16>,
702 idx: usize,
704 #[cfg(not(target_os = "android"))]
705 _stream: rodio::OutputStream,
706}
707
708impl AudioWriter {
709 fn get_write_buf(&mut self) -> &mut [i16] {
710 if self.idx == AUDIO_BUF_SIZE {
711 self.idx = 0;
712 }
713 let start = self.idx;
714 let mut idx = self.idx;
715 while idx < AUDIO_BUF_SIZE {
717 let res = self.send.try_send(self.buf[idx]);
718 if res.is_err() {
719 break;
720 }
721 idx += 1;
722 }
723 self.idx = idx;
724 &mut self.buf[start..idx]
726 }
727}
728
729#[cfg(not(target_os = "android"))]
730struct AudioReader {
731 wav: Option<hound::WavWriter<std::io::BufWriter<std::fs::File>>>,
732 recv: mpsc::Receiver<i16>,
733}
734
735#[cfg(not(target_os = "android"))]
736impl rodio::Source for AudioReader {
737 fn current_span_len(&self) -> Option<usize> {
738 None
739 }
740
741 fn channels(&self) -> u16 {
742 2
743 }
744
745 fn sample_rate(&self) -> u32 {
746 SAMPLE_RATE
747 }
748
749 fn total_duration(&self) -> Option<core::time::Duration> {
750 None
751 }
752}
753
754#[cfg(not(target_os = "android"))]
755impl Iterator for AudioReader {
756 type Item = f32;
757
758 fn next(&mut self) -> Option<Self::Item> {
759 let s = self.recv.try_recv().unwrap_or_default();
760 if let Some(wav) = self.wav.as_mut() {
761 wav.write_sample(s).unwrap()
762 }
763 let s = f32::from(s) / f32::from(i16::MAX);
764 Some(s)
765 }
766}