From 172c3c260eb971e806ad4d3fef7c1eb38bd93f90 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sat, 7 May 2022 16:06:51 -0400 Subject: [PATCH] Add 3dslink redirection to Soc service - Add example of usage - Fix broken thread-info compilation --- ctru-rs/examples/output-3dslink.rs | 35 ++++++++++++++++++++++++++ ctru-rs/examples/thread-info.rs | 2 +- ctru-rs/src/services/soc.rs | 40 ++++++++++++++++++++++++++++-- 3 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 ctru-rs/examples/output-3dslink.rs diff --git a/ctru-rs/examples/output-3dslink.rs b/ctru-rs/examples/output-3dslink.rs new file mode 100644 index 0000000..fd5a526 --- /dev/null +++ b/ctru-rs/examples/output-3dslink.rs @@ -0,0 +1,35 @@ +use ctru::gfx::Gfx; +use ctru::services::apt::Apt; +use ctru::services::hid::{Hid, KeyPad}; +use ctru::services::soc::Soc; + +fn main() { + ctru::init(); + let gfx = Gfx::init().expect("Couldn't obtain GFX controller"); + let hid = Hid::init().expect("Couldn't obtain HID controller"); + let apt = Apt::init().expect("Couldn't obtain APT controller"); + + let mut soc = Soc::init().expect("Couldn't obtain SOC controller"); + + soc.redirect_to_3dslink(true, true) + .expect("unable to redirect stdout/err to 3dslink server"); + + println!("Hello 3dslink!"); + eprintln!("Press Start on the device to disconnect and exit."); + + // Main loop + while apt.main_loop() { + //Scan all the inputs. This should be done once for each frame + hid.scan_input(); + + if hid.keys_down().contains(KeyPad::KEY_START) { + break; + } + // Flush and swap framebuffers + gfx.flush_buffers(); + gfx.swap_buffers(); + + //Wait for VBlank + gfx.wait_for_vblank(); + } +} diff --git a/ctru-rs/examples/thread-info.rs b/ctru-rs/examples/thread-info.rs index 47ae486..337c49e 100644 --- a/ctru-rs/examples/thread-info.rs +++ b/ctru-rs/examples/thread-info.rs @@ -10,7 +10,7 @@ use std::os::horizon::thread::BuilderExt; fn main() { ctru::init(); - let gfx = Gfx::default(); + let gfx = Gfx::init().expect("Couldn't obtain GFX controller"); let hid = Hid::init().expect("Couldn't obtain HID controller"); let apt = Apt::init().expect("Couldn't obtain APT controller"); let _console = Console::init(gfx.top_screen.borrow_mut()); diff --git a/ctru-rs/src/services/soc.rs b/ctru-rs/src/services/soc.rs index 5705d06..e058516 100644 --- a/ctru-rs/src/services/soc.rs +++ b/ctru-rs/src/services/soc.rs @@ -10,6 +10,7 @@ use crate::services::ServiceReference; #[non_exhaustive] pub struct Soc { _service_handler: ServiceReference, + sock_3dslink: libc::c_int, } static SOC_ACTIVE: Lazy> = Lazy::new(|| Mutex::new(0)); @@ -52,7 +53,10 @@ impl Soc { }, )?; - Ok(Self { _service_handler }) + Ok(Self { + _service_handler, + sock_3dslink: -1, + }) } /// IP Address of the Nintendo 3DS system. @@ -60,6 +64,38 @@ impl Soc { let raw_id = unsafe { libc::gethostid() }; Ipv4Addr::from(raw_id.to_ne_bytes()) } + + /// Redirect output streams (i.e. [`println`] and [`eprintln`]) to the `3dslink` server. + /// Requires `3dslink` >= 0.6.1 and `new-hbmenu` >= 2.3.0. + /// + /// # Errors + /// + /// Returns an error if a connection cannot be established to the server, or + /// output was already previously redirected. + pub fn redirect_to_3dslink(&mut self, stdout: bool, stderr: bool) -> crate::Result<()> { + if self.sock_3dslink >= 0 { + // TODO AlreadyRedirected or something + return Err(crate::Error::ServiceAlreadyActive); + } + + let sock = unsafe { ctru_sys::link3dsConnectToHost(stdout, stderr) }; + if sock < 0 { + Err(sock.into()) + } else { + self.sock_3dslink = sock; + Ok(()) + } + } +} + +impl Drop for Soc { + fn drop(&mut self) { + if self.sock_3dslink >= 0 { + unsafe { + libc::closesocket(self.sock_3dslink); + } + } + } } #[cfg(test)] @@ -69,7 +105,7 @@ mod tests { #[test] fn soc_duplicate() { - let _soc = Soc::init().unwrap(); + // let _soc = Soc::init().unwrap(); assert!(matches!(Soc::init(), Err(Error::ServiceAlreadyActive))) }