diff --git a/ctru-rs/examples/wifi-info.rs b/ctru-rs/examples/wifi-info.rs new file mode 100644 index 0000000..c518039 --- /dev/null +++ b/ctru-rs/examples/wifi-info.rs @@ -0,0 +1,43 @@ +//! Wi-Fi info example +//! +//! This example prints out all the info about the console's network, like SSID, security, proxy info... + +use ctru::{prelude::*, services::ac::Ac}; + +fn main() { + ctru::use_panic_handler(); + + let gfx = Gfx::new().expect("Couldn't obtain GFX controller"); + let mut hid = Hid::new().expect("Couldn't obtain HID controller"); + let apt = Apt::new().expect("Couldn't obtain APT controller"); + + let _console = Console::new(gfx.top_screen.borrow_mut()); + + let mut ac = Ac::new().expect("Couldn't get an AC handle"); + + print_network_info(&ac).expect("Error while gathering network info"); + println!("Press START to exit."); + + while apt.main_loop() { + hid.scan_input(); + + if hid.keys_down().contains(KeyPad::START) { + break; + } + + gfx.wait_for_vblank(); + } +} + +fn print_network_info(ac: &Ac) -> ctru::Result<()> { + let connected = ac.get_wifi_status()?; + println!("Wi-Fi connected: {}", connected); + + // Some methods error out if the console isn't connected + if connected { + println!("Wi-Fi SSID: {}", ac.get_wifi_ssid()?); + println!("Wi-Fi security: {:?}", ac.get_wifi_security()?); + } + + Ok(()) +} diff --git a/ctru-rs/src/services/ac.rs b/ctru-rs/src/services/ac.rs new file mode 100644 index 0000000..4b91340 --- /dev/null +++ b/ctru-rs/src/services/ac.rs @@ -0,0 +1,170 @@ +use crate::error::ResultCode; +use std::ffi::CString; +use std::io::Write; +use std::marker::PhantomData; +pub struct Ac(()); + +impl Ac { + /// Initialize a new service handle. + /// + /// # Example + /// + /// ``` + /// # let _runner = test_runner::GdbRunner::default(); + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ac::Ac; + /// + /// let ac = Ac::new()?; + /// # + /// # Ok(()) + /// # } + /// ``` + #[doc(alias = "acInit")] + pub fn new() -> crate::Result { + unsafe { + ResultCode(ctru_sys::acInit())?; + Ok(Ac(())) + } + } + + /// Waits for an internet connection + /// + /// # Example + /// + /// ``` + /// # let _runner = test_runner::GdbRunner::default(); + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ac::Ac; + /// + /// let ac = Ac::new()?; + /// + /// println!("Waiting for an internet connection..."); + /// ac.wait_for_internet_connection()?; + /// println!("Connected."); + /// # + /// # Ok(()) + /// # } + /// ``` + #[doc(alias = "acWaitInternetConnection")] + pub fn wait_internet_connection(&self) -> crate::Result<()> { + unsafe { + ResultCode(ctru_sys::acWaitInternetConnection())?; + + Ok(()) + } + } + + /// Returns whether the console is connected to Wi-Fi + /// + /// # Example + /// + /// ``` + /// # let _runner = test_runner::GdbRunner::default(); + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ac::Ac; + /// + /// let ac = Ac::new()?; + /// + /// println!("Wi-Fi connected: {}", ac.get_wifi_status()?); + /// # + /// # Ok(()) + /// # } + /// ``` + #[doc(alias = "ACU_GetWifiStatus")] + pub fn get_wifi_status(&self) -> crate::Result { + unsafe { + let mut ret = 0u32; + ResultCode(ctru_sys::ACU_GetStatus(&mut ret))?; + + Ok(ret == 3) + } + } + + /// Returns whether the console is connected to Wi-Fi + /// + /// # Example + /// + /// ``` + /// # let _runner = test_runner::GdbRunner::default(); + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ac::Ac; + /// + /// let ac = Ac::new()?; + /// + /// # + /// # Ok(()) + /// # } + /// ``` + #[doc(alias = "ACU_GetWifiSecurityMode")] + pub fn get_wifi_security(&self) -> crate::Result { + unsafe { + let mut ret = 0u32; + ResultCode(ctru_sys::ACU_GetSecurityMode(&mut ret))?; + // fix this, for some reason the bindings have the type as a struct and not enum + // and so i can't impl TryFrom automatically + Ok(std::mem::transmute(ret)) + } + } + + /// Returns the SSID of the Wi-Fi network the console is connected to, or error if the console isn't connected to any network. + /// + /// You can check if the console is connected to a network using [`Self::get_wifi_status()`] + /// + /// # Example + /// + /// ``` + /// # let _runner = test_runner::GdbRunner::default(); + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ac::Ac; + /// + /// let ac = Ac::new()?; + /// + /// println!("The console is connected to the network \"{}\"", ac.get_wifi_ssid().unwrap()) + /// # + /// # Ok(()) + /// # } + /// ``` + #[doc(alias = "ACU_GetSSID")] + pub fn get_wifi_ssid(&self) -> crate::Result { + unsafe { + let mut len = 0u32; + ResultCode(ctru_sys::ACU_GetSSIDLength(&mut len))?; + // we don't really need space for the terminator + let mut vec: Vec = vec![0u8; len as usize]; + ResultCode(ctru_sys::ACU_GetSSID(vec.as_mut_ptr()))?; + // how do i handle this error? + Ok(String::from_utf8(vec).unwrap()) + } + } +} + +impl Drop for Ac { + #[doc(alias = "acExit")] + fn drop(&mut self) { + unsafe { ctru_sys::acExit() }; + } +} + +#[doc(alias = "acSecurityMode")] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum SecurityMode { + Open = 0, + WEP40Bit = 1, + WEP104Bit = 2, + WEP128Bit = 3, + WPA_TKIP = 4, + WPA2_TKIP = 5, + WPA_AES = 6, + WPA2_AES = 7 +} \ No newline at end of file diff --git a/ctru-rs/src/services/mod.rs b/ctru-rs/src/services/mod.rs index 4fadeb3..86ada52 100644 --- a/ctru-rs/src/services/mod.rs +++ b/ctru-rs/src/services/mod.rs @@ -26,6 +26,7 @@ mod reference; pub mod soc; pub mod sslc; pub mod svc; +pub mod ac; cfg_if::cfg_if! { if #[cfg(all(feature = "romfs", romfs_exists))] {