From c2827aa2691ce4c9dfe5ae7cb98d38ba97bb934b Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sat, 30 Sep 2023 23:54:08 -0400 Subject: [PATCH 1/3] Add `os` module for querying OS and hardware state Most of these are dead simple and don't require any service initialization etc., so all we need is a simple wrapper. I didn't implement everything in <3ds/os.h> yet, but got most of the basic ones which seemed like likely use cases to me. --- ctru-rs/src/error.rs | 4 +- ctru-rs/src/lib.rs | 1 + ctru-rs/src/os.rs | 135 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 ctru-rs/src/os.rs diff --git a/ctru-rs/src/error.rs b/ctru-rs/src/error.rs index 41b09f8..62a4646 100644 --- a/ctru-rs/src/error.rs +++ b/ctru-rs/src/error.rs @@ -27,7 +27,7 @@ pub type Result = ::std::result::Result; /// pub fn hid_init() -> Result<()> { /// // We run an unsafe function which returns a `ctru_sys::Result`. /// let result: ctru_sys::Result = unsafe { ctru_sys::hidInit() }; -/// +/// /// // The result code is parsed and any possible error gets returned by the function. /// ResultCode(result)?; /// Ok(()) @@ -152,6 +152,8 @@ impl fmt::Debug for Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + // TODO: should we consider using ctru_sys::osStrError here as well? + // It might do some of the work for us or provide additional details &Self::Os(err) => write!( f, "libctru result code 0x{err:08X}: [{} {}] {}: {}", diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index ecc7dd9..baa9936 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -107,6 +107,7 @@ pub mod console; pub mod error; pub mod linear; pub mod mii; +pub mod os; pub mod prelude; pub mod services; diff --git a/ctru-rs/src/os.rs b/ctru-rs/src/os.rs new file mode 100644 index 0000000..58a4e87 --- /dev/null +++ b/ctru-rs/src/os.rs @@ -0,0 +1,135 @@ +//! Utilities to get information about the operating system and hardware state. + +/// System version information. +#[derive(Clone, Copy)] +pub struct Version(u32); + +impl Version { + /// Pack a system version from its components + pub fn new(major: u8, minor: u8, revision: u8) -> Self { + let major = u32::from(major); + let minor = u32::from(minor); + let revision = u32::from(revision); + + Self(major << 24 | minor << 16 | revision << 8) + } + + /// Get the major version from a packed system version. + pub fn major(&self) -> u8 { + (self.0 >> 24).try_into().unwrap() + } + + /// Get the minor version from a packed system version. + pub fn minor(&self) -> u8 { + (self.0 >> 16 & 0xFF).try_into().unwrap() + } + + /// Get the revision from a packed system version. + pub fn revision(&self) -> u8 { + (self.0 >> 8 & 0xFF).try_into().unwrap() + } +} + +/// Get the system's FIRM version. +pub fn firm_version() -> Version { + Version(unsafe { ctru_sys::osGetFirmVersion() }) +} + +/// Get the system's kernel version. +pub fn kernel_version() -> Version { + Version(unsafe { ctru_sys::osGetKernelVersion() }) +} + +// TODO: I can't seem to find good documentation on it, but we could probably +// define enums for firmware type (NATIVE_FIRM, SAFE_FIRM etc.) as well as +// application memory layout. Leaving those as future enhancements for now + +/// A region of memory. Most applications will only use [`Application`](MemRegion::Application) +/// memory, but the other types can be used to query memory usage information. +/// See +/// for more details on the different types of memory. +/// +/// # Example +/// ``` +/// # let _runner = test_runner::GdbRunner::default(); +/// let all_memory = ctru::os::MemRegion::All; +/// +/// assert!(all_memory.size() > 0); +/// assert!(all_memory.used() > 0); +/// assert!(all_memory.free() > 0); +/// ``` +#[derive(Clone, Copy, Debug)] +#[non_exhaustive] +#[repr(u32)] +pub enum MemRegion { + /// All memory regions. + All = ctru_sys::MEMREGION_ALL, + /// APPLICATION memory. + Application = ctru_sys::MEMREGION_APPLICATION, + /// SYSTEM memory. + System = ctru_sys::MEMREGION_SYSTEM, + /// BASE memory. + Base = ctru_sys::MEMREGION_BASE, +} + +impl MemRegion { + /// Get the total size of this memory region, in bytes. + pub fn size(&self) -> usize { + unsafe { ctru_sys::osGetMemRegionSize(*self as u32) } + .try_into() + .unwrap() + } + + /// Get the number of bytes used within this memory region. + pub fn used(&self) -> usize { + unsafe { ctru_sys::osGetMemRegionUsed(*self as u32) } + .try_into() + .unwrap() + } + + /// Get the number of bytes free within this memory region. + pub fn free(&self) -> usize { + unsafe { ctru_sys::osGetMemRegionFree(*self as u32) } + .try_into() + .unwrap() + } +} + +/// WiFi signal strength. This enum's [`u8`] representation corresponds with +/// the number of bars displayed in the Home menu. +#[non_exhaustive] +#[repr(u8)] +pub enum WifiStrength { + /// This may indicate a very poor signal quality even worse than `Bad`, + /// or it may indicate that no network is connected at all. + Disconnected = 0, + /// Poor signal strength. + Bad = 1, + /// Medium signal strength. + Decent = 2, + /// Good signal strength. + Good = 3, +} + +impl WifiStrength { + /// Get the current WiFi signal strength. + pub fn current() -> Self { + match unsafe { ctru_sys::osGetWifiStrength() } { + 0 => Self::Disconnected, + 1 => Self::Bad, + 2 => Self::Decent, + 3 => Self::Good, + other => panic!("Got unexpected WiFi strength value {other}"), + } + } +} + +/// Get the current value of the stereoscopic 3D slider on a scale from 0.0­–­1.0. +pub fn current_3d_slider_state() -> f32 { + unsafe { ctru_sys::osGet3DSliderState() } +} + +/// Whether or not a headset is currently plugged into the device. +pub fn is_headset_connected() -> bool { + unsafe { ctru_sys::osIsHeadsetConnected() } +} From 6aa50357c8b6bfbd435a7c745fc1d1d9dcb67443 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sun, 1 Oct 2023 00:07:49 -0400 Subject: [PATCH 2/3] Add some simple doctests for some new functions --- ctru-rs/src/os.rs | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/ctru-rs/src/os.rs b/ctru-rs/src/os.rs index 58a4e87..8be1de1 100644 --- a/ctru-rs/src/os.rs +++ b/ctru-rs/src/os.rs @@ -1,6 +1,16 @@ //! Utilities to get information about the operating system and hardware state. -/// System version information. +/// System version information. This struct is used for both kernel and firmware versions. +/// +/// # Example +/// ``` +/// # let _runner = test_runner::GdbRunner::default(); +/// let firm_version = ctru::os::firm_version(); +/// assert_ne!(firm_version.major(), 0); +/// +/// let kernel_version = ctru::os::kernel_version(); +/// assert_ne!(kernel_version.major(), 0); +/// ``` #[derive(Clone, Copy)] pub struct Version(u32); @@ -95,13 +105,22 @@ impl MemRegion { } } -/// WiFi signal strength. This enum's [`u8`] representation corresponds with +/// WiFi signal strength. This enum's `u8` representation corresponds with /// the number of bars displayed in the Home menu. +/// +/// # Example +/// +/// ``` +/// # let _runner = test_runner::GdbRunner::default(); +/// let strength = ctru::os::WifiStrength::current(); +/// assert!((strength as u8) < 4); +/// ``` +#[derive(Clone, Copy, Debug)] #[non_exhaustive] #[repr(u8)] pub enum WifiStrength { /// This may indicate a very poor signal quality even worse than `Bad`, - /// or it may indicate that no network is connected at all. + /// or that no network is connected at all. Disconnected = 0, /// Poor signal strength. Bad = 1, From 421a09bc37ab8a2311498be1b6a898b15a4697f7 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sun, 8 Oct 2023 17:33:18 -0400 Subject: [PATCH 3/3] Remove references to test_runner temporarily --- ctru-rs/src/os.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ctru-rs/src/os.rs b/ctru-rs/src/os.rs index 8be1de1..8eea697 100644 --- a/ctru-rs/src/os.rs +++ b/ctru-rs/src/os.rs @@ -4,7 +4,7 @@ /// /// # Example /// ``` -/// # let _runner = test_runner::GdbRunner::default(); +/// # // let _runner = test_runner::GdbRunner::default(); /// let firm_version = ctru::os::firm_version(); /// assert_ne!(firm_version.major(), 0); /// @@ -61,7 +61,7 @@ pub fn kernel_version() -> Version { /// /// # Example /// ``` -/// # let _runner = test_runner::GdbRunner::default(); +/// # // let _runner = test_runner::GdbRunner::default(); /// let all_memory = ctru::os::MemRegion::All; /// /// assert!(all_memory.size() > 0); @@ -111,7 +111,7 @@ impl MemRegion { /// # Example /// /// ``` -/// # let _runner = test_runner::GdbRunner::default(); +/// # // let _runner = test_runner::GdbRunner::default(); /// let strength = ctru::os::WifiStrength::current(); /// assert!((strength as u8) < 4); /// ```