From 243863cfb97eac5191e8d1e1c83423d2fa21c2bf Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sat, 6 May 2023 18:12:20 +0200 Subject: [PATCH 01/39] Fixed wrong type quotations --- ctru-rs/src/console.rs | 2 +- ctru-rs/src/lib.rs | 7 ++-- ctru-rs/src/linear.rs | 2 +- ctru-rs/src/mii.rs | 2 +- ctru-rs/src/services/cam.rs | 60 +++++++++++++++---------------- ctru-rs/src/services/fs.rs | 38 ++++---------------- ctru-rs/src/services/gfx.rs | 15 ++++---- ctru-rs/src/services/ndsp/mod.rs | 26 +++++++------- ctru-rs/src/services/ndsp/wave.rs | 10 +++--- 9 files changed, 69 insertions(+), 93 deletions(-) diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index e3ba62e6..bad114e1 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -19,7 +19,7 @@ impl<'screen> Console<'screen> { /// /// # Notes /// - /// [Console] automatically takes care of flushing and swapping buffers for its screen when printing. + /// [`Console`] automatically takes care of flushing and swapping buffers for its screen when printing. pub fn new(screen: RefMut<'screen, dyn Screen>) -> Self { let mut context = Box::::default(); diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index 210d37ff..5b0ad400 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -1,3 +1,6 @@ +//! Safe Rust wrapper around `libctru`. +//! +//! This library behaves as the main tool to access system-specific features and feature fixes. #![crate_type = "rlib"] #![crate_name = "ctru"] #![feature(test)] @@ -27,8 +30,8 @@ macro_rules! from_impl { /// Activate the default panic handler. /// -/// With this implementation, the main thread will stop and try to print debug info to an available [console::Console]. -/// In case it fails to find an active [console::Console] the program will just exit. +/// With this implementation, the main thread will stop and try to print debug info to an available [`Console`](console::Console). +/// In case it fails to find an active [`Console`](console::Console) the program will just exit. /// /// # Notes /// diff --git a/ctru-rs/src/linear.rs b/ctru-rs/src/linear.rs index c07ce49f..718e975f 100644 --- a/ctru-rs/src/linear.rs +++ b/ctru-rs/src/linear.rs @@ -15,7 +15,7 @@ use std::ptr::NonNull; // Sadly the linear memory allocator included in `libctru` doesn't implement `linearRealloc` at the time of these additions, // but the default fallback of the `std` will take care of that for us. -/// [`std::alloc::Allocator`] struct for LINEAR memory +/// [`Allocator`](std::alloc::Allocator) struct for LINEAR memory /// To use this struct the main crate must activate the `allocator_api` unstable feature. #[derive(Copy, Clone, Default, Debug)] pub struct LinearAllocator; diff --git a/ctru-rs/src/mii.rs b/ctru-rs/src/mii.rs index 17cb9bf8..a992a2ac 100644 --- a/ctru-rs/src/mii.rs +++ b/ctru-rs/src/mii.rs @@ -176,7 +176,7 @@ pub struct MoleDetails { /// Some values are not ordered _like_ the Mii Editor UI. The mapped values can be seen here: /// /// -/// This struct is returned by the [``MiiSelector``](crate::applets::mii_selector::MiiSelector) +/// This struct is returned by the [`MiiSelector`](crate::applets::mii_selector::MiiSelector) #[derive(Clone, Debug)] pub struct MiiData { pub options: MiiDataOptions, diff --git a/ctru-rs/src/services/cam.rs b/ctru-rs/src/services/cam.rs index 4a06421c..6ddb37fa 100644 --- a/ctru-rs/src/services/cam.rs +++ b/ctru-rs/src/services/cam.rs @@ -20,7 +20,7 @@ pub struct Cam { pub both_outer_cams: BothOutwardCam, } -/// Flag to pass to [Camera::flip_image] +/// Flag to pass to [`Camera::flip_image`] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum FlipMode { @@ -30,7 +30,7 @@ pub enum FlipMode { Reverse = ctru_sys::FLIP_REVERSE, } -/// Flag to pass to [Camera::set_view_size] +/// Flag to pass to [`Camera::set_view_size`] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum ViewSize { @@ -47,7 +47,7 @@ pub enum ViewSize { DSX4 = ctru_sys::SIZE_DS_LCDx4, } -/// Flag to pass to [Camera::set_frame_rate] +/// Flag to pass to [`Camera::set_frame_rate`] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum FrameRate { @@ -66,8 +66,8 @@ pub enum FrameRate { Fps30To10 = ctru_sys::FRAME_RATE_30_TO_10, } -/// Flag to pass to [Camera::set_white_balance] or -/// [Camera::set_white_balance_without_base_up] +/// Flag to pass to [`Camera::set_white_balance`] or +/// [`Camera::set_white_balance_without_base_up`] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum WhiteBalance { @@ -85,7 +85,7 @@ pub enum WhiteBalance { Temp7000K = ctru_sys::WHITE_BALANCE_7000K, } -/// Flag to pass to [Camera::set_photo_mode] +/// Flag to pass to [`Camera::set_photo_mode`] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum PhotoMode { @@ -96,7 +96,7 @@ pub enum PhotoMode { Letter = ctru_sys::PHOTO_MODE_LETTER, } -/// Flag to pass to [Camera::set_effect] +/// Flag to pass to [`Camera::set_effect`] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Effect { @@ -108,7 +108,7 @@ pub enum Effect { Sepia01 = ctru_sys::EFFECT_SEPIA01, } -/// Flag to pass to [Camera::set_contrast] +/// Flag to pass to [`Camera::set_contrast`] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Contrast { @@ -120,7 +120,7 @@ pub enum Contrast { High = ctru_sys::CONTRAST_HIGH, } -/// Flag to pass to [Camera::set_lens_correction] +/// Flag to pass to [`Camera::set_lens_correction`] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum LensCorrection { @@ -129,7 +129,7 @@ pub enum LensCorrection { Bright = ctru_sys::LENS_CORRECTION_BRIGHT, } -/// Flag to pass to [Camera::set_output_format] +/// Flag to pass to [`Camera::set_output_format`] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum OutputFormat { @@ -137,7 +137,7 @@ pub enum OutputFormat { Rgb565 = ctru_sys::OUTPUT_RGB_565, } -/// Flag to pass to [Cam::play_shutter_sound] +/// Flag to pass to [`Cam::play_shutter_sound`] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum ShutterSound { @@ -168,7 +168,7 @@ impl TryFrom for FramebufferFormat { } } -/// Struct containing coordinates passed to [Camera::set_trimming_params]. +/// Struct containing coordinates passed to [`Camera::set_trimming_params`]. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct TrimmingParams { x_start: i16, @@ -178,7 +178,7 @@ pub struct TrimmingParams { } impl TrimmingParams { - /// Creates a new [CamTrimmingParams] and guarantees the start coordinates are less than or + /// Creates a new [`TrimmingParams`] and guarantees the start coordinates are less than or /// equal to the end coordinates. /// /// `x_start <= x_end && y_start <= y_end` @@ -296,7 +296,7 @@ pub trait Camera { } /// Sets whether or not the camera should trim the image based on parameters set by - /// [Camera::set_trimming_params] + /// [`Camera::set_trimming_params`] fn set_trimming(&mut self, enabled: bool) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetTrimming(self.port_as_raw(), enabled))?; @@ -313,7 +313,7 @@ pub trait Camera { } } - /// Sets trimming parameters based on coordinates specified inside a [TrimmingParams] + /// Sets trimming parameters based on coordinates specified inside a [`TrimmingParams`] fn set_trimming_params(&mut self, params: TrimmingParams) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetTrimmingParams( @@ -327,7 +327,7 @@ pub trait Camera { } } - /// Returns the [TrimmingParams] set + /// Returns the [`TrimmingParams`] set fn trimming_params(&self) -> crate::Result { unsafe { let mut x_start = 0; @@ -381,7 +381,7 @@ pub trait Camera { } } - /// Sets the white balance mod of the camera based on the passed [WhiteBalance] argument + /// Sets the white balance mod of the camera based on the passed [`WhiteBalance`] argument fn set_white_balance(&mut self, white_balance: WhiteBalance) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetWhiteBalance( @@ -392,7 +392,7 @@ pub trait Camera { } } - /// Sets the white balance mode of the camera based on the passed [WhiteBalance] argument + /// Sets the white balance mode of the camera based on the passed [`WhiteBalance`] argument // TODO: Explain base up fn set_white_balance_without_base_up( &mut self, @@ -461,7 +461,7 @@ pub trait Camera { } } - /// Sets the flip direction of the camera's image based on the passed [FlipMode] argument + /// Sets the flip direction of the camera's image based on the passed [`FlipMode`] argument fn flip_image(&mut self, flip: FlipMode) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_FlipImage( @@ -507,7 +507,7 @@ pub trait Camera { } } - /// Sets the view size of the camera based on the passed [ViewSize] argument. + /// Sets the view size of the camera based on the passed [`ViewSize`] argument. fn set_view_size(&mut self, size: ViewSize) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetSize( @@ -519,7 +519,7 @@ pub trait Camera { } } - /// Sets the frame rate of the camera based on the passed [FrameRate] argument. + /// Sets the frame rate of the camera based on the passed [`FrameRate`] argument. fn set_frame_rate(&mut self, frame_rate: FrameRate) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetFrameRate( @@ -530,7 +530,7 @@ pub trait Camera { } } - /// Sets the photo mode of the camera based on the passed [PhotoMode] argument. + /// Sets the photo mode of the camera based on the passed [`PhotoMode`] argument. fn set_photo_mode(&mut self, photo_mode: PhotoMode) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetPhotoMode( @@ -541,9 +541,9 @@ pub trait Camera { } } - /// Sets the effect of the camera based on the passed [Effect] argument. + /// Sets the effect of the camera based on the passed [`Effect`] argument. /// - /// Multiple effects can be set at once by combining the bitflags of [CamEffect] + /// Multiple effects can be set at once by combining the bitflags of [`Effect`] fn set_effect(&mut self, effect: Effect) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetEffect( @@ -555,7 +555,7 @@ pub trait Camera { } } - /// Sets the contrast of the camera based on the passed [Contrast] argument. + /// Sets the contrast of the camera based on the passed [`Contrast`] argument. fn set_contrast(&mut self, contrast: Contrast) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetContrast( @@ -566,7 +566,7 @@ pub trait Camera { } } - /// Sets the lens correction of the camera based on the passed [LensCorrection] argument. + /// Sets the lens correction of the camera based on the passed [`LensCorrection`] argument. fn set_lens_correction(&mut self, lens_correction: LensCorrection) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetLensCorrection( @@ -577,7 +577,7 @@ pub trait Camera { } } - /// Sets the output format of the camera based on the passed [OutputFormat] argument. + /// Sets the output format of the camera based on the passed [`OutputFormat`] argument. fn set_output_format(&mut self, format: OutputFormat) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetOutputFormat( @@ -652,7 +652,7 @@ pub trait Camera { } /// Sets the image quality calibration data for the camera based on the passed in - /// [ImageQualityCalibrationData] argument + /// [`ImageQualityCalibrationData`] argument fn set_image_quality_calibration_data( &mut self, data: ImageQualityCalibrationData, @@ -663,7 +663,7 @@ pub trait Camera { } } - /// Returns the current [ImageQualityCalibrationData] for the camera + /// Returns the current [`ImageQualityCalibrationData`] for the camera fn image_quality_calibration_data(&self) -> crate::Result { unsafe { let mut data = ImageQualityCalibrationData::default(); @@ -783,7 +783,7 @@ impl Cam { } } - /// Plays the specified sound based on the [ShutterSound] argument + /// Plays the specified sound based on the [`ShutterSound`] argument pub fn play_shutter_sound(&self, sound: ShutterSound) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_PlayShutterSound(sound.into()))?; diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index 04e0c1e4..faa03e33 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -183,36 +183,26 @@ pub struct File { /// Metadata information about a file. /// -/// This structure is returned from the [`metadata`] function and +/// This structure is returned from the [`File::metadata`] function and /// represents known metadata about a file. -/// -/// [`metadata`]: fn.metadata.html pub struct Metadata { attributes: u32, size: u64, } /// Options and flags which can be used to configure how a [`File`] is opened. -/// This builder exposes the ability to configure how a `File` is opened +/// This builder exposes the ability to configure how a [`File`] is opened /// and what operations are permitted on the open file. The [`File::open`] /// and [`File::create`] methods are aliases for commonly used options /// using this builder. /// -/// [`File`]: struct.File.html -/// [`File::open`]: struct.File.html#method.open -/// [`File::create`]: struct.File.html#method.create -/// -/// Generally speaking, when using `OpenOptions`, you'll first call [`new()`], -/// then chain calls to methods to set each option, then call [`open()`], +/// Generally speaking, when using [`OpenOptions`], you'll first call [`OpenOptions::new`], +/// then chain calls to methods to set each option, then call [`OpenOptions::open`], /// passing the path of the file you're trying to open. /// /// It is required to also pass a reference to the [`Archive`] that the /// file lives in. /// -/// [`new()`]: struct.OpenOptions.html#method.new -/// [`open()`]: struct.OpenOptions.html#method.open -/// [`Archive`]: struct.Archive.html -/// /// # Examples /// /// Opening a file to read: @@ -257,14 +247,11 @@ pub struct OpenOptions { /// Iterator over the entries in a directory. /// -/// This iterator is returned from the [`read_dir`] function of this module and +/// This iterator is returned from the [`File::read_dir`] function of this module and /// will yield instances of `Result`. Through a [`DirEntry`] /// information like the entry's path and possibly other metadata can be /// learned. /// -/// [`read_dir`]: fn.read_dir.html -/// [`DirEntry`]: struct.DirEntry.html -/// /// # Errors /// /// This Result will return Err if there's some sort of intermittent IO error @@ -277,8 +264,6 @@ pub struct ReadDir<'a> { /// Entries returned by the [`ReadDir`] iterator. /// -/// [`ReadDir`]: struct.ReadDir.html -/// /// An instance of `DirEntry` represents an entry inside of a directory on the /// filesystem. Each entry can be inspected via methods to learn about the full /// path or possibly other metadata. @@ -338,8 +323,6 @@ impl Fs { impl Archive { /// Retrieves an Archive's [`ArchiveID`] - /// - /// [`ArchiveID`]: enum.ArchiveID.html pub fn id(&self) -> ArchiveID { self.id } @@ -355,8 +338,6 @@ impl File { /// This function will return an error if `path` does not already exit. /// Other errors may also be returned accoridng to [`OpenOptions::open`] /// - /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open - /// /// # Examples /// /// ```no_run @@ -382,9 +363,7 @@ impl File { /// # Errors /// /// This function will return an error if `path` does not already exit. - /// Other errors may also be returned accoridng to [`OpenOptions::create`] - /// - /// [`OpenOptions::create`]: struct.OpenOptions.html#method.create + /// Other errors may also be returned accoridng to [`OpenOptions::create`]. /// /// # Examples /// @@ -597,8 +576,6 @@ impl OpenOptions { /// to the `archive` method. /// * Filesystem-level errors (full disk, etc). /// * Invalid combinations of open options. - /// - /// [`Archive`]: struct.Archive.html pub fn open>(&mut self, path: P) -> IoResult { self._open(path.as_ref(), self.open_flags()) } @@ -901,7 +878,6 @@ fn to_utf16(path: &Path) -> WideCString { WideCString::from_str(path).unwrap() } -// Adapted from sys/windows/fs.rs in libstd fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] { match v.iter().position(|c| *c == 0) { // don't include the 0 @@ -910,8 +886,6 @@ fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] { } } -// Copied from sys/common/io.rs in libstd - // Provides read_to_end functionality over an uninitialized buffer. // This function is unsafe because it calls the underlying // read function with a slice into uninitialized memory. The default diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index 3a5ba370..8c602804 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -90,14 +90,10 @@ pub trait Swap: private::Sealed { /// Swaps the video buffers. /// /// If double buffering is disabled, "swapping" the buffers has the side effect - /// of committing any configuration changes to the buffers (e.g. [`set_wide_mode`], - /// [`set_framebuffer_format`], [`set_double_buffering`]). + /// of committing any configuration changes to the buffers (e.g. [`TopScreen::set_wide_mode`], + /// [`Screen::set_framebuffer_format`], [`Screen::set_double_buffering`]). /// /// This should be called once per frame at most. - /// - /// [`set_wide_mode`]: TopScreen::set_wide_mode - /// [`set_framebuffer_format`]: Screen::set_framebuffer_format - /// [`set_double_buffering`]: Screen::set_double_buffering fn swap_buffers(&mut self); } @@ -213,9 +209,12 @@ pub struct Gfx { static GFX_ACTIVE: Mutex = Mutex::new(0); impl Gfx { - /// Creates a new [Gfx] instance with default init values + /// Creates a new [`Gfx`] instance with default init values /// It's the same as calling: - /// `Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false)` + /// + /// ``` + /// Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false) + /// ``` pub fn new() -> Result { Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false) } diff --git a/ctru-rs/src/services/ndsp/mod.rs b/ctru-rs/src/services/ndsp/mod.rs index 8f67b1b5..72e2413f 100644 --- a/ctru-rs/src/services/ndsp/mod.rs +++ b/ctru-rs/src/services/ndsp/mod.rs @@ -204,8 +204,8 @@ impl Channel<'_> { /// /// # Warning /// - /// `libctru` expects the user to manually keep the info data (in this case [Wave]) alive during playback. - /// To ensure safety, checks within [Wave] will clear the whole channel queue if any queued [Wave] is dropped prematurely. + /// `libctru` expects the user to manually keep the info data (in this case [`Wave`]) alive during playback. + /// To ensure safety, checks within [`Wave`] will clear the whole channel queue if any queued [`Wave`] is dropped prematurely. pub fn queue_wave(&mut self, wave: &mut Wave) -> std::result::Result<(), NdspError> { match wave.status() { WaveStatus::Playing | WaveStatus::Queued => return Err(NdspError::WaveBusy(self.id)), @@ -222,7 +222,7 @@ impl Channel<'_> { /// Functions to handle audio filtering. /// -/// Refer to [libctru](https://libctru.devkitpro.org/channel_8h.html#a1da3b363c2edfd318c92276b527daae6) for more info. +/// Refer to [`libctru`](https://libctru.devkitpro.org/channel_8h.html#a1da3b363c2edfd318c92276b527daae6) for more info. impl Channel<'_> { /// Enables/disables monopole filters. pub fn iir_mono_set_enabled(&mut self, enable: bool) { @@ -314,7 +314,7 @@ impl AudioFormat { } impl AudioMix { - /// Creates a new [AudioMix] with all volumes set to 0. + /// Creates a new [`AudioMix`] with all volumes set to 0. pub fn zeroed() -> Self { Self { raw: [0.; 12] } } @@ -365,8 +365,8 @@ impl AudioMix { /// /// # Notes /// - /// [Channel] will normalize the mix values to be within 0 and 1. - /// However, an [AudioMix] instance with larger/smaller values is valid. + /// [`Channel`] will normalize the mix values to be within 0 and 1. + /// However, an [`AudioMix`] instance with larger/smaller values is valid. pub fn set_front(&mut self, left: f32, right: f32) { self.raw[0] = left; self.raw[1] = right; @@ -376,8 +376,8 @@ impl AudioMix { /// /// # Notes /// - /// [Channel] will normalize the mix values to be within 0 and 1. - /// However, an [AudioMix] instance with larger/smaller values is valid. + /// [`Channel`] will normalize the mix values to be within 0 and 1. + /// However, an [`AudioMix`] instance with larger/smaller values is valid. pub fn set_back(&mut self, left: f32, right: f32) { self.raw[2] = left; self.raw[3] = right; @@ -387,8 +387,8 @@ impl AudioMix { /// /// # Notes /// - /// [Channel] will normalize the mix values to be within 0 and 1. - /// However, an [AudioMix] instance with larger/smaller values is valid. + /// [`Channel`] will normalize the mix values to be within 0 and 1. + /// However, an [`AudioMix`] instance with larger/smaller values is valid. pub fn set_aux_front(&mut self, left: f32, right: f32, id: usize) { if id > 1 { panic!("invalid auxiliary output device index") @@ -404,8 +404,8 @@ impl AudioMix { /// /// # Notes /// - /// [Channel] will normalize the mix values to be within 0 and 1. - /// However, an [AudioMix] instance with larger/smaller values is valid. + /// [`Channel`] will normalize the mix values to be within 0 and 1. + /// However, an [`AudioMix`] instance with larger/smaller values is valid. pub fn set_aux_back(&mut self, left: f32, right: f32, id: usize) { if id > 1 { panic!("invalid auxiliary output device index") @@ -418,7 +418,7 @@ impl AudioMix { } } -/// Returns an [AudioMix] object with "front left" and "front right" volumes set to 100%, and all other volumes set to 0%. +/// Returns an [`AudioMix`] object with "front left" and "front right" volumes set to 100%, and all other volumes set to 0%. impl Default for AudioMix { fn default() -> Self { let mut mix = AudioMix::zeroed(); diff --git a/ctru-rs/src/services/ndsp/wave.rs b/ctru-rs/src/services/ndsp/wave.rs index feff4cd2..6cc58478 100644 --- a/ctru-rs/src/services/ndsp/wave.rs +++ b/ctru-rs/src/services/ndsp/wave.rs @@ -1,7 +1,7 @@ use super::{AudioFormat, NdspError}; use crate::linear::LinearAllocator; -/// Informational struct holding the raw audio data and playback info. This corresponds to [ctru_sys::ndspWaveBuf]. +/// Informational struct holding the raw audio data and playback info. This corresponds to [`ctru_sys::ndspWaveBuf`]. pub struct Wave { /// Data block of the audio wave (and its format information). buffer: Box<[u8], LinearAllocator>, @@ -13,7 +13,7 @@ pub struct Wave { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u8)] -/// Enum representing the playback status of a [Wave]. +/// Enum representing the playback status of a [`Wave`]. pub enum WaveStatus { Free = ctru_sys::NDSP_WBUF_FREE as u8, Queued = ctru_sys::NDSP_WBUF_QUEUED as u8, @@ -69,7 +69,7 @@ impl Wave { /// /// # Errors /// - /// This function will return an error if the [Wave] is currently busy, + /// This function will return an error if the [`Wave`] is currently busy, /// with the id to the channel in which it's queued. pub fn get_buffer_mut(&mut self) -> Result<&mut [u8], NdspError> { match self.status() { @@ -89,7 +89,7 @@ impl Wave { /// /// # Notes /// - /// This value varies depending on [Self::set_sample_count]. + /// This value varies depending on [`Wave::set_sample_count`]. pub fn sample_count(&self) -> usize { self.raw_data.nsamples as usize } @@ -117,7 +117,7 @@ impl Wave { /// # Errors /// /// This function will return an error if the sample size exceeds the buffer's capacity - /// or if the [Wave] is currently queued. + /// or if the [`Wave`] is currently queued. pub fn set_sample_count(&mut self, sample_count: usize) -> Result<(), NdspError> { match self.status() { WaveStatus::Playing | WaveStatus::Queued => { From f497a1fba437bbbc667010ec224ac1c1cec315ae Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Thu, 6 Jul 2023 20:56:15 +0200 Subject: [PATCH 02/39] General setup for the new documentation --- README.md | 4 ++-- ctru-rs/Cargo.toml | 6 +++++- ctru-rs/src/lib.rs | 31 ++++++++++++++++++++++++++++--- ctru-rs/src/prelude.rs | 7 ++++++- ctru-rs/src/services/gfx.rs | 2 +- ctru-rs/src/services/mod.rs | 3 --- 6 files changed, 42 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index abd23dd5..ae3e6c7b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ctru-rs -A Rust wrapper library for smealum's [ctrulib](https://github.com/smealum/ctrulib). +A Rust wrapper around [libctru](https://github.com/devkitPro/libctru). ## Structure @@ -8,7 +8,7 @@ This repository is organized as follows: * `ctru-rs`: Safe, idiomatic wrapper around `ctru-sys` -* `ctru-sys`: Low-level, unsafe bindings to ctrulib. +* `ctru-sys`: Low-level, unsafe bindings to `libctru`. This crate's version changes according to the version of `libctru` used to generate the bindings, with the following convention: diff --git a/ctru-rs/Cargo.toml b/ctru-rs/Cargo.toml index 2811900a..bf2ec15a 100644 --- a/ctru-rs/Cargo.toml +++ b/ctru-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] authors = ["Rust3DS Org", "Ronald Kinard "] -description = "A safe wrapper around smealum's ctrulib." +description = "A safe wrapper around libctru" license = "Zlib" name = "ctru-rs" version = "0.7.1" @@ -45,6 +45,10 @@ std-threads = [] [package.metadata.cargo-3ds] romfs_dir = "examples/romfs" +[package.metadata.docs.rs] +default-target = "armv6k-nintendo-3ds" +cargo-args = ["-Z", "build-std"] + [[example]] name = "thread-basic" required-features = ["std-threads"] diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index 5b0ad400..92645dde 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -1,14 +1,39 @@ -//! Safe Rust wrapper around `libctru`. -//! -//! This library behaves as the main tool to access system-specific features and feature fixes. +//! Safe wrapper around `libctru`. +//! +//! # About +//! +//! This crate behaves as the main tool to access system-specific functionality on the Nintendo 3DS when developing homebrew software in Rust. +//! Thanks to it, developers can access the underlying system services and the console's hardware to develop userland applications +//! (such as HID devices, network capabilities, graphics, built-in cameras, etc.). +//! +//! Among these features, `ctru` also automatically includes functionality to properly integrate the Rust `std` with the console, which the developer would otherwise need to implement manually. +//! +//! # Usage +//! +//! Read thoroughly the official [`ctru` wiki](https://github.com/rust3ds/ctru-rs/wiki) which guides you through the setup needed to install the required toolchain and helpful tools. +//! After following the guide and understanding the many quirks of the Nintendo 3DS homebrew development environment, you can create a new project by including this crate as a dependency +//! of your project in your `Cargo.toml` manifest and build your binaries either manually (for the `armv6k-nintendo-3ds` target) or via [`cargo-3ds`](https://github.com/rust3ds/cargo-3ds). +//! +//! # Examples +//! +//! You can check out the examples provided with this crate which dive into most of the implemented functionality. +//! + #![crate_type = "rlib"] #![crate_name = "ctru"] +#![warn(missing_docs)] #![feature(test)] #![feature(custom_test_frameworks)] #![feature(try_trait_v2)] #![feature(allocator_api)] #![feature(nonnull_slice_from_raw_parts)] #![test_runner(test_runner::run)] +#![doc( + html_favicon_url = "https://user-images.githubusercontent.com/11131775/225929072-2fa1741c-93ae-4b47-9bdf-af70f3d59910.png" +)] +#![doc( + html_logo_url = "https://user-images.githubusercontent.com/11131775/225929072-2fa1741c-93ae-4b47-9bdf-af70f3d59910.png" +)] // Nothing is imported from these crates but their inclusion here assures correct linking of the missing implementations. extern crate pthread_3ds; diff --git a/ctru-rs/src/prelude.rs b/ctru-rs/src/prelude.rs index 74faa41e..49095fa5 100644 --- a/ctru-rs/src/prelude.rs +++ b/ctru-rs/src/prelude.rs @@ -1,2 +1,7 @@ pub use crate::console::Console; -pub use crate::services::{gfx::Gfx, hid::KeyPad, soc::Soc, Apt, Hid}; +pub use crate::services::{ + apt::Apt, + gfx::Gfx, + hid::{Hid, KeyPad}, + soc::Soc, +}; diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index 8c602804..a7ba7081 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -211,7 +211,7 @@ static GFX_ACTIVE: Mutex = Mutex::new(0); impl Gfx { /// Creates a new [`Gfx`] instance with default init values /// It's the same as calling: - /// + /// /// ``` /// Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false) /// ``` diff --git a/ctru-rs/src/services/mod.rs b/ctru-rs/src/services/mod.rs index 1d31deac..d825c461 100644 --- a/ctru-rs/src/services/mod.rs +++ b/ctru-rs/src/services/mod.rs @@ -42,7 +42,4 @@ cfg_if::cfg_if! { } } -pub use self::apt::Apt; -pub use self::hid::Hid; - pub(crate) use self::reference::ServiceReference; From cd7a041180018810606b7fd38c5f605dff844a64 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Fri, 7 Jul 2023 13:03:54 +0200 Subject: [PATCH 03/39] error module documentation --- ctru-rs/Cargo.toml | 1 + ctru-rs/src/error.rs | 36 +++++++++++++++++++++++++++++++++--- ctru-rs/src/lib.rs | 13 ++++++++++--- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/ctru-rs/Cargo.toml b/ctru-rs/Cargo.toml index bf2ec15a..8049fea2 100644 --- a/ctru-rs/Cargo.toml +++ b/ctru-rs/Cargo.toml @@ -5,6 +5,7 @@ license = "Zlib" name = "ctru-rs" version = "0.7.1" edition = "2021" +repository = "https://github.com/rust3ds/ctru-rs" rust-version = "1.64" [lib] diff --git a/ctru-rs/src/error.rs b/ctru-rs/src/error.rs index 004b4616..9e1f3c58 100644 --- a/ctru-rs/src/error.rs +++ b/ctru-rs/src/error.rs @@ -1,3 +1,6 @@ +//! Error handling interface. +//! +//! This module holds the generic error and result types to interface with [`ctru_sys`] and the safe wrapper. use std::borrow::Cow; use std::error; use std::ffi::CStr; @@ -6,8 +9,27 @@ use std::ops::{ControlFlow, FromResidual, Try}; use ctru_sys::result::{R_DESCRIPTION, R_LEVEL, R_MODULE, R_SUMMARY}; +/// Custom type alias for generic `ctru` operations. +/// +/// This type is compatible with `ctru-sys` result codes. pub type Result = ::std::result::Result; +/// Validity checker of raw [`ctru_sys::Result`] codes. +/// +/// This struct supports the "try" syntax (`?`) to convert to an [`Error::Os`]. +/// +/// # Example +/// +/// ```no_run +/// pub fn hid_init() -> crate::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(()) +/// } +/// ``` #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord)] #[repr(transparent)] pub struct ResultCode(pub ctru_sys::Result); @@ -48,13 +70,20 @@ impl FromResidual for Result { } } -/// The error type returned by all libctru functions. +/// The generic error enum returned by `ctru` functions. +/// +/// This error enum supports parsing and displaying [`ctru_sys::Result`] codes. #[non_exhaustive] pub enum Error { + /// Raw [`ctru_sys::Result`] codes. Os(ctru_sys::Result), + /// Generic `libc` error codes. Libc(String), + /// Requested service is already active and cannot be activated again. ServiceAlreadyActive, + /// `stdout` is already being redirected. OutputAlreadyRedirected, + /// The buffer provided by the user to store some data is shorter than required. BufferTooShort { /// Length of the buffer provided by the user. provided: usize, @@ -64,8 +93,9 @@ pub enum Error { } impl Error { - /// Create an [`Error`] out of the last set value in `errno`. This can be used - /// to get a human-readable error string from calls to `libc` functions. + /// Create an [`Error`] out of the last set value in `errno`. + /// + /// This can be used to get a human-readable error string from calls to `libc` functions. pub(crate) fn from_errno() -> Self { let error_str = unsafe { let errno = ctru_sys::errno(); diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index 92645dde..713705e8 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -17,7 +17,6 @@ //! # Examples //! //! You can check out the examples provided with this crate which dive into most of the implemented functionality. -//! #![crate_type = "rlib"] #![crate_name = "ctru"] @@ -39,6 +38,9 @@ extern crate pthread_3ds; extern crate shim_3ds; +/// Expanded stack size used to spawn the main thread by `libctru`. +/// +/// This value was chosen to support crate dependencies which expected more stack than provided, without compromising performance. #[no_mangle] #[cfg(feature = "big-stack")] static __stacksize__: usize = 2 * 1024 * 1024; // 2MB @@ -53,19 +55,24 @@ macro_rules! from_impl { }; } -/// Activate the default panic handler. +/// Activate the custom `ctru` panic handler. /// /// With this implementation, the main thread will stop and try to print debug info to an available [`Console`](console::Console). /// In case it fails to find an active [`Console`](console::Console) the program will just exit. /// /// # Notes /// -/// When ´test´ is enabled, this function won't do anything, as it should be overridden by the ´test´ environment. +/// When ´test´ is enabled, this function will not do anything, as it should be overridden by the ´test´ environment. pub fn use_panic_handler() { #[cfg(not(test))] panic_hook_setup(); } +/// Internal protocol to activate the custom panic handler hook. +/// +/// # Notes +/// +/// When `test` is enabled, this function will be ignored. #[cfg(not(test))] fn panic_hook_setup() { use crate::services::hid::{Hid, KeyPad}; From 9b97e904846237869da325396e38ff934349b10a Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Fri, 7 Jul 2023 13:20:19 +0200 Subject: [PATCH 04/39] Renew manifests and fix warnings --- Cargo.toml | 1 + ctru-rs/Cargo.toml | 4 +++- ctru-rs/src/error.rs | 16 ++++++++-------- ctru-rs/src/lib.rs | 7 +++---- ctru-rs/src/services/gfx.rs | 2 +- ctru-rs/src/services/romfs.rs | 2 +- ctru-sys/Cargo.toml | 4 ++++ 7 files changed, 21 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index af22c84a..33abd1c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = ["ctru-rs", "ctru-sys", "ctru-sys/bindgen-ctru-sys"] default-members = ["ctru-rs", "ctru-sys"] +resolver = "2" [patch.'https://github.com/rust3ds/ctru-rs'] # Make sure all dependencies use the local ctru-sys package diff --git a/ctru-rs/Cargo.toml b/ctru-rs/Cargo.toml index 8049fea2..69f88f41 100644 --- a/ctru-rs/Cargo.toml +++ b/ctru-rs/Cargo.toml @@ -1,12 +1,14 @@ [package] authors = ["Rust3DS Org", "Ronald Kinard "] description = "A safe wrapper around libctru" +keywords = ["3ds", "libctru"] +categories = ["os", "api-bindings"] license = "Zlib" name = "ctru-rs" version = "0.7.1" edition = "2021" repository = "https://github.com/rust3ds/ctru-rs" -rust-version = "1.64" +rust-version = "1.70" [lib] crate-type = ["rlib"] diff --git a/ctru-rs/src/error.rs b/ctru-rs/src/error.rs index 9e1f3c58..71c0f46b 100644 --- a/ctru-rs/src/error.rs +++ b/ctru-rs/src/error.rs @@ -1,5 +1,5 @@ //! Error handling interface. -//! +//! //! This module holds the generic error and result types to interface with [`ctru_sys`] and the safe wrapper. use std::borrow::Cow; use std::error; @@ -10,16 +10,16 @@ use std::ops::{ControlFlow, FromResidual, Try}; use ctru_sys::result::{R_DESCRIPTION, R_LEVEL, R_MODULE, R_SUMMARY}; /// Custom type alias for generic `ctru` operations. -/// +/// /// This type is compatible with `ctru-sys` result codes. pub type Result = ::std::result::Result; /// Validity checker of raw [`ctru_sys::Result`] codes. -/// +/// /// This struct supports the "try" syntax (`?`) to convert to an [`Error::Os`]. -/// +/// /// # Example -/// +/// /// ```no_run /// pub fn hid_init() -> crate::Result<()> { /// // We run an unsafe function which returns a `ctru_sys::Result`. @@ -71,13 +71,13 @@ impl FromResidual for Result { } /// The generic error enum returned by `ctru` functions. -/// +/// /// This error enum supports parsing and displaying [`ctru_sys::Result`] codes. #[non_exhaustive] pub enum Error { /// Raw [`ctru_sys::Result`] codes. Os(ctru_sys::Result), - /// Generic `libc` error codes. + /// Generic `libc` error codes. Libc(String), /// Requested service is already active and cannot be activated again. ServiceAlreadyActive, @@ -94,7 +94,7 @@ pub enum Error { impl Error { /// Create an [`Error`] out of the last set value in `errno`. - /// + /// /// This can be used to get a human-readable error string from calls to `libc` functions. pub(crate) fn from_errno() -> Self { let error_str = unsafe { diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index 713705e8..f2f3e7c9 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -25,7 +25,6 @@ #![feature(custom_test_frameworks)] #![feature(try_trait_v2)] #![feature(allocator_api)] -#![feature(nonnull_slice_from_raw_parts)] #![test_runner(test_runner::run)] #![doc( html_favicon_url = "https://user-images.githubusercontent.com/11131775/225929072-2fa1741c-93ae-4b47-9bdf-af70f3d59910.png" @@ -39,7 +38,7 @@ extern crate pthread_3ds; extern crate shim_3ds; /// Expanded stack size used to spawn the main thread by `libctru`. -/// +/// /// This value was chosen to support crate dependencies which expected more stack than provided, without compromising performance. #[no_mangle] #[cfg(feature = "big-stack")] @@ -69,9 +68,9 @@ pub fn use_panic_handler() { } /// Internal protocol to activate the custom panic handler hook. -/// +/// /// # Notes -/// +/// /// When `test` is enabled, this function will be ignored. #[cfg(not(test))] fn panic_hook_setup() { diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index a7ba7081..dd6fbffa 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -134,7 +134,7 @@ impl Flush for S { let framebuffer = self.raw_framebuffer(); // Flush the data array. `self.raw_framebuffer` should get the correct parameters for all kinds of screens - unsafe { + let _ = unsafe { ctru_sys::GSPGPU_FlushDataCache( framebuffer.ptr.cast(), (framebuffer.height * framebuffer.width) as u32, diff --git a/ctru-rs/src/services/romfs.rs b/ctru-rs/src/services/romfs.rs index 49369a6e..c87b8844 100644 --- a/ctru-rs/src/services/romfs.rs +++ b/ctru-rs/src/services/romfs.rs @@ -36,7 +36,7 @@ impl RomFS { }, || { let mount_name = CStr::from_bytes_with_nul(b"romfs\0").unwrap(); - unsafe { ctru_sys::romfsUnmount(mount_name.as_ptr()) }; + let _ = unsafe { ctru_sys::romfsUnmount(mount_name.as_ptr()) }; }, )?; diff --git a/ctru-sys/Cargo.toml b/ctru-sys/Cargo.toml index d4cb24b2..03435b67 100644 --- a/ctru-sys/Cargo.toml +++ b/ctru-sys/Cargo.toml @@ -2,9 +2,13 @@ name = "ctru-sys" version = "22.2.0+2.2.2-1" authors = [ "Rust3DS Org", "Ronald Kinard " ] +description = "Raw bindings to libctru" +keywords = ["3ds", "libctru"] +categories = ["os", "external-ffi-bindings", "no-std"] license = "Zlib" links = "ctru" edition = "2021" +repository = "https://github.com/rust3ds/ctru-rs" [dependencies] libc = { version = "0.2.121", default-features = false } From 39829e18206a76782b68fb778f17cd35a90665cd Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sat, 8 Jul 2023 12:52:44 +0200 Subject: [PATCH 05/39] Am, Apt and refactoring to streamline the API and docs --- ctru-rs/examples/title-info.rs | 13 +++---- ctru-rs/src/lib.rs | 5 ++- ctru-rs/src/services/am.rs | 64 +++++++++++++++++++++++++--------- ctru-rs/src/services/apt.rs | 24 +++++++++++++ ctru-rs/src/services/mod.rs | 12 +++++-- 5 files changed, 91 insertions(+), 27 deletions(-) diff --git a/ctru-rs/examples/title-info.rs b/ctru-rs/examples/title-info.rs index fee5cb6b..a03c0022 100644 --- a/ctru-rs/examples/title-info.rs +++ b/ctru-rs/examples/title-info.rs @@ -80,12 +80,13 @@ fn main() { // Move cursor to top left println!("\x1b[1;1"); - match selected_title.title_info() { - Ok(info) => { - println!("Size: {} KB", info.size_bytes() / 1024); - println!("Version: 0x{:x}", info.version()); - } - Err(e) => println!("Failed to get title info: {}", e), + match selected_title.size() { + Ok(size) => println!("Size: {} kB", size / 1024), + Err(e) => println!("Failed to get title size: {}", e), + } + match selected_title.version() { + Ok(version) => println!("Version: 0x{:x}", version), + Err(e) => println!("Failed to get title version: {}", e), } match selected_title.product_code() { Ok(code) => println!("Product code: \"{code}\""), diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index f2f3e7c9..37428f82 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -24,6 +24,7 @@ #![feature(test)] #![feature(custom_test_frameworks)] #![feature(try_trait_v2)] +#![feature(once_cell_try)] #![feature(allocator_api)] #![test_runner(test_runner::run)] #![doc( @@ -39,7 +40,9 @@ extern crate shim_3ds; /// Expanded stack size used to spawn the main thread by `libctru`. /// -/// This value was chosen to support crate dependencies which expected more stack than provided, without compromising performance. +/// It takes effect only if the `big-stack` feature is active. Otherwise, the default stack size should be ~32kB. +/// +/// This value was chosen to support crate dependencies which expected more stack than provided. It's suggested to use less stack if possible. #[no_mangle] #[cfg(feature = "big-stack")] static __stacksize__: usize = 2 * 1024 * 1024; // 2MB diff --git a/ctru-rs/src/services/am.rs b/ctru-rs/src/services/am.rs index 70bd1512..2af11520 100644 --- a/ctru-rs/src/services/am.rs +++ b/ctru-rs/src/services/am.rs @@ -1,35 +1,34 @@ +//! Application Manager service. +//! +//! As the name implies, the AM service manages installed applications. It can: +//! - Read the installed applications on the console and their information (depending on the install location). +//! - Install compatible applications to the console. +//! +//! `ctru` doesn't support installing titles (yet). + use crate::error::ResultCode; use crate::services::fs::FsMediaType; +use std::cell::OnceCell; use std::marker::PhantomData; use std::mem::MaybeUninit; -#[derive(Copy, Clone, Debug)] -#[repr(transparent)] -pub struct TitleInfo(ctru_sys::AM_TitleEntry); - -impl TitleInfo { - pub fn id(&self) -> u64 { - self.0.titleID - } - pub fn size_bytes(&self) -> u64 { - self.0.size - } - pub fn version(&self) -> u16 { - self.0.version - } -} - +/// Struct holding general information about a specific title. +#[doc(alias = "AM_TitleEntry")] pub struct Title<'a> { id: u64, mediatype: FsMediaType, + entry: OnceCell, _am: PhantomData<&'a Am>, } impl<'a> Title<'a> { + /// Returns this title's ID. pub fn id(&self) -> u64 { self.id } + /// Returns this title's unique product code. + #[doc(alias = "AM_GetTitleProductCode")] pub fn product_code(&self) -> crate::Result { let mut buf: [u8; 16] = [0; 16]; @@ -43,7 +42,9 @@ impl<'a> Title<'a> { Ok(String::from_utf8_lossy(&buf).to_string()) } - pub fn title_info(&self) -> crate::Result { + /// Retrieves additional information on the title. + #[doc(alias = "AM_GetTitleInfo")] + fn title_info(&self) -> crate::Result { let mut info = MaybeUninit::zeroed(); unsafe { @@ -57,11 +58,34 @@ impl<'a> Title<'a> { Ok(info.assume_init()) } } + + /// Returns the size of this title in bytes. + pub fn size(&self) -> crate::Result { + // Get the internal entry, or fill it if empty. + let entry = self.entry.get_or_try_init(|| -> crate::Result { + self.title_info() + })?; + + Ok(entry.size) + } + + /// Returns the installed version of this title. + pub fn version(&self) -> crate::Result { + // Get the internal entry, or fill it if empty. + let entry = self.entry.get_or_try_init(|| -> crate::Result { + self.title_info() + })?; + + Ok(entry.version) + } } +/// Handle to the Application Manager service. pub struct Am(()); impl Am { + /// Initialize a new handle. + #[doc(alias = "amInit")] pub fn new() -> crate::Result { unsafe { ResultCode(ctru_sys::amInit())?; @@ -69,6 +93,8 @@ impl Am { } } + /// Returns the amount of titles currently installed in a specific install location. + #[doc(alias = "AM_GetTitleCount")] pub fn title_count(&self, mediatype: FsMediaType) -> crate::Result { unsafe { let mut count = 0; @@ -77,6 +103,8 @@ impl Am { } } + /// Returns the list of titles installed in a specific install location. + #[doc(alias = "AM_GetTitleList")] pub fn title_list(&self, mediatype: FsMediaType) -> crate::Result> { let count = self.title_count(mediatype)?; let mut buf = vec![0; count as usize]; @@ -94,6 +122,7 @@ impl Am { .map(|id| Title { id, mediatype, + entry: OnceCell::new(), _am: PhantomData, }) .collect()) @@ -101,6 +130,7 @@ impl Am { } impl Drop for Am { + #[doc(alias = "amExit")] fn drop(&mut self) { unsafe { ctru_sys::amExit() }; } diff --git a/ctru-rs/src/services/apt.rs b/ctru-rs/src/services/apt.rs index f7731bef..0f5eb25e 100644 --- a/ctru-rs/src/services/apt.rs +++ b/ctru-rs/src/services/apt.rs @@ -1,8 +1,17 @@ +//! Applet service. +//! +//! The APT service handles integration with some higher level OS features such as Sleep mode, the Home Menu and application switching. +//! +//! It also handles running applets, small programs made available by the OS to streamline specific functionality. Those are implemented in the [`applets`](crate::applets) module. + use crate::error::ResultCode; +/// Handle to the Applet service. pub struct Apt(()); impl Apt { + /// Initialize a new handle. + #[doc(alias = "aptInit")] pub fn new() -> crate::Result { unsafe { ResultCode(ctru_sys::aptInit())?; @@ -10,10 +19,24 @@ impl Apt { } } + /// Returns `true` if the application is running in the foreground as normal. + /// + /// # Notes + /// + /// This function is called as such since it automatically handles all checks for Home Menu switching, Sleep mode and other events that could take away control from the application. + /// For this reason, its main use is as the condition of a while loop that controls the main logic for your program. + #[doc(alias = "aptMainLoop")] pub fn main_loop(&self) -> bool { unsafe { ctru_sys::aptMainLoop() } } + /// Sets (in percentage) the amount of time to lend to the application thread spawned on the syscore (core #1). + /// + /// # Notes + /// + /// It is necessary to set a time limit before spawning threads on the syscore. + /// The percentage value must be withing 5% and 89%, though it is suggested to use lower values (around 30-45%) to avoid slowing down the OS processes. + #[doc(alias = "APT_SetAppCpuTimeLimit")] pub fn set_app_cpu_time_limit(&mut self, percent: u32) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::APT_SetAppCpuTimeLimit(percent))?; @@ -23,6 +46,7 @@ impl Apt { } impl Drop for Apt { + #[doc(alias = "aptExit")] fn drop(&mut self) { unsafe { ctru_sys::aptExit() }; } diff --git a/ctru-rs/src/services/mod.rs b/ctru-rs/src/services/mod.rs index d825c461..a3879333 100644 --- a/ctru-rs/src/services/mod.rs +++ b/ctru-rs/src/services/mod.rs @@ -1,9 +1,15 @@ -//! System services used to handle system-specific functionalities. +//! OS services used to handle system-specific functionality. //! -//! Most of the 3DS console's functionalities (when writing homebrew) are locked behind services, +//! Most of the 3DS console's functionalities (when writing user-land homebrew) are accessible via services, //! which need to be initialized before accessing any particular feature. //! -//! Some include: button input, audio playback, graphics rendering, built-in cameras, etc. +//! To ensure safety measures when using the underlying services, `ctru` leverages Rust's lifetime model. +//! After initializing the handle for a specific service (e.g. [`Apt`](apt::Apt)) the service will be accessible as long as there is at least one handle "alive". +//! As such, handles should be dropped *after* the use of a specific service. This is particularly important for services which are necessary for functionality +//! "outside" their associated methods, such as [`RomFS`](romfs::RomFS), which creates an accessible virtual filesystem, or [`Soc`](soc::Soc), +//! which enables all network communications via sockets. +//! +//! In `ctru` some services only allow a single handle to be created at a time, to ensure a safe and controlled environment. pub mod am; pub mod apt; From d315ebd10cf90e28387f1b1c040c14ad7c924950 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sat, 8 Jul 2023 14:13:41 +0200 Subject: [PATCH 06/39] doc(alias) everywhere --- ctru-rs/src/applets/mii_selector.rs | 9 ++++++ ctru-rs/src/applets/swkbd.rs | 11 +++++++ ctru-rs/src/console.rs | 5 ++++ ctru-rs/src/linear.rs | 3 ++ ctru-rs/src/mii.rs | 1 + ctru-rs/src/services/cam.rs | 46 +++++++++++++++++++++++++++++ ctru-rs/src/services/cfgu.rs | 10 +++++++ ctru-rs/src/services/fs.rs | 18 +++++++++++ ctru-rs/src/services/gfx.rs | 17 +++++++++-- ctru-rs/src/services/gspgpu.rs | 3 ++ ctru-rs/src/services/hid.rs | 8 +++++ ctru-rs/src/services/ndsp/mod.rs | 27 +++++++++++++++++ ctru-rs/src/services/ps.rs | 7 +++++ ctru-rs/src/services/romfs.rs | 6 ++++ ctru-rs/src/services/soc.rs | 5 ++++ ctru-rs/src/services/sslc.rs | 2 ++ 16 files changed, 176 insertions(+), 2 deletions(-) diff --git a/ctru-rs/src/applets/mii_selector.rs b/ctru-rs/src/applets/mii_selector.rs index bd0eac28..eada7e33 100644 --- a/ctru-rs/src/applets/mii_selector.rs +++ b/ctru-rs/src/applets/mii_selector.rs @@ -46,6 +46,7 @@ bitflags! { /// /// let result = mii_selector.launch().unwrap(); /// ``` +#[doc(alias = "MiiSelectorConf")] #[derive(Clone, Debug)] pub struct MiiSelector { config: Box, @@ -70,6 +71,7 @@ pub enum LaunchError { impl MiiSelector { /// Initializes a Mii Selector + #[doc(alias = "miiSelectorInit")] pub fn new() -> Self { let mut config = Box::::default(); unsafe { @@ -81,6 +83,7 @@ impl MiiSelector { /// Set the title of the Mii Selector. /// /// This function would panic if the given ``&str`` contains NUL bytes. + #[doc(alias = "miiSelectorSetTitle")] pub fn set_title(&mut self, text: &str) { // This can only fail if the text contains NUL bytes in the string... which seems // unlikely and is documented @@ -91,11 +94,13 @@ impl MiiSelector { } /// Set the options of the Mii Selector + #[doc(alias = "miiSelectorSetOptions")] pub fn set_options(&mut self, options: Options) { unsafe { ctru_sys::miiSelectorSetOptions(self.config.as_mut(), options.bits) } } /// Whitelist a guest Mii + #[doc(alias = "miiSelectorWhitelistGuestMii")] pub fn whitelist_guest_mii(&mut self, mii_index: Index) { let index = match mii_index { Index::Index(i) => i, @@ -106,6 +111,7 @@ impl MiiSelector { } /// Blacklist a guest Mii + #[doc(alias = "miiSelectorBlacklistGuestMii")] pub fn blacklist_guest_mii(&mut self, mii_index: Index) { let index = match mii_index { Index::Index(i) => i, @@ -116,6 +122,7 @@ impl MiiSelector { } /// Whitelist a user Mii + #[doc(alias = "miiSelectorWhitelistUserMii")] pub fn whitelist_user_mii(&mut self, mii_index: Index) { let index = match mii_index { Index::Index(i) => i, @@ -126,6 +133,7 @@ impl MiiSelector { } /// Blacklist a user Mii + #[doc(alias = "miiSelectorBlacklistUserMii")] pub fn blacklist_user_mii(&mut self, mii_index: Index) { let index = match mii_index { Index::Index(i) => i, @@ -145,6 +153,7 @@ impl MiiSelector { /// Launch the Mii Selector. /// Returns an error when the checksum of the Mii is invalid. + #[doc(alias = "miiSelectorLaunch")] pub fn launch(&mut self) -> Result { let mut return_val = Box::::default(); unsafe { ctru_sys::miiSelectorLaunch(self.config.as_mut(), return_val.as_mut()) } diff --git a/ctru-rs/src/applets/swkbd.rs b/ctru-rs/src/applets/swkbd.rs index 8f4aab65..49a41039 100644 --- a/ctru-rs/src/applets/swkbd.rs +++ b/ctru-rs/src/applets/swkbd.rs @@ -7,6 +7,7 @@ use std::iter::once; use std::str; /// An instance of the software keyboard. +#[doc(alias = "SwkbdState")] #[derive(Clone)] pub struct Swkbd { state: Box, @@ -19,6 +20,7 @@ pub struct Swkbd { /// Numpad is a number pad. /// Western is a text keyboard without japanese symbols (only applies to JPN systems). For other /// systems it's the same as a Normal keyboard. +#[doc(alias = "SwkbdType")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Kind { @@ -29,6 +31,7 @@ pub enum Kind { } /// Represents which button the user pressed to close the software keyboard. +#[doc(alias = "SwkbdButton")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Button { @@ -38,6 +41,7 @@ pub enum Button { } /// Error type for the software keyboard. +#[doc(alias = "SwkbdResult")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(i32)] pub enum Error { @@ -52,6 +56,7 @@ pub enum Error { } /// Restrictions on keyboard input +#[doc(alias = "SwkbdValidInput")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum ValidInput { @@ -90,6 +95,7 @@ bitflags! { impl Swkbd { /// Initializes a software keyboard of the specified type and the chosen number of buttons /// (from 1-3). + #[doc(alias = "swkbdInit")] pub fn new(keyboard_type: Kind, num_buttons: i32) -> Self { unsafe { let mut state = Box::::default(); @@ -101,6 +107,7 @@ impl Swkbd { /// Gets input from this keyboard and appends it to the provided string. /// /// The text received from the keyboard will be truncated if it is longer than `max_bytes`. + #[doc(alias = "swkbdInputText")] pub fn get_string(&mut self, max_bytes: usize) -> Result<(String, Button), Error> { // Unfortunately the libctru API doesn't really provide a way to get the exact length // of the string that it receieves from the software keyboard. Instead it expects you @@ -125,6 +132,7 @@ impl Swkbd { /// /// If the buffer is too small to contain the entire sequence received from the keyboard, /// the output will be truncated but should still be well-formed UTF-8. + #[doc(alias = "swkbdInputText")] pub fn write_exact(&mut self, buf: &mut [u8]) -> Result { unsafe { match swkbdInputText(self.state.as_mut(), buf.as_mut_ptr(), buf.len()) { @@ -138,6 +146,7 @@ impl Swkbd { } /// Sets special features for this keyboard + #[doc(alias = "swkbdSetFeatures")] pub fn set_features(&mut self, features: Features) { unsafe { swkbdSetFeatures(self.state.as_mut(), features.bits) } } @@ -156,6 +165,7 @@ impl Swkbd { /// Sets the hint text for this software keyboard (that is, the help text that is displayed /// when the textbox is empty) + #[doc(alias = "swkbdSetHintText")] pub fn set_hint_text(&mut self, text: &str) { unsafe { let nul_terminated: String = text.chars().chain(once('\0')).collect(); @@ -169,6 +179,7 @@ impl Swkbd { /// `text` configures the display text for the button /// `submit` configures whether pressing the button will accept the keyboard's input or /// discard it. + #[doc(alias = "swkbdSetButton")] pub fn configure_button(&mut self, button: Button, text: &str, submit: bool) { unsafe { let nul_terminated: String = text.chars().chain(once('\0')).collect(); diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index bad114e1..cd6b51f7 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -7,6 +7,7 @@ use crate::services::gfx::Screen; static mut EMPTY_CONSOLE: PrintConsole = unsafe { const_zero::const_zero!(PrintConsole) }; +#[doc(alias = "PrintConsole")] pub struct Console<'screen> { context: Box, _screen: RefMut<'screen, dyn Screen>, @@ -20,6 +21,7 @@ impl<'screen> Console<'screen> { /// # Notes /// /// [`Console`] automatically takes care of flushing and swapping buffers for its screen when printing. + #[doc(alias = "consoleInit")] pub fn new(screen: RefMut<'screen, dyn Screen>) -> Self { let mut context = Box::::default(); @@ -45,6 +47,7 @@ impl<'screen> Console<'screen> { } /// Select this console as the current target for stdout + #[doc(alias = "consoleSelect")] pub fn select(&self) { unsafe { consoleSelect(self.context.as_ref() as *const _ as *mut _); @@ -52,6 +55,7 @@ impl<'screen> Console<'screen> { } /// Clears all text from the console + #[doc(alias = "consoleClear")] pub fn clear(&self) { unsafe { consoleClear() } } @@ -64,6 +68,7 @@ impl<'screen> Console<'screen> { /// # Safety /// This function is unsafe because it does not validate that the input will produce /// a console that actually fits on the screen + #[doc(alias = "consoleSetWindow")] pub unsafe fn set_window(&mut self, x: i32, y: i32, width: i32, height: i32) { consoleSetWindow(self.context.as_mut(), x, y, width, height); } diff --git a/ctru-rs/src/linear.rs b/ctru-rs/src/linear.rs index 718e975f..d0164c0a 100644 --- a/ctru-rs/src/linear.rs +++ b/ctru-rs/src/linear.rs @@ -22,12 +22,14 @@ pub struct LinearAllocator; impl LinearAllocator { /// Returns the amount of free space left in the LINEAR sector + #[doc(alias = "linearSpaceFree")] pub fn free_space() -> u32 { unsafe { ctru_sys::linearSpaceFree() } } } unsafe impl Allocator for LinearAllocator { + #[doc(alias = "linearAlloc", alias = "linearMemAlign")] fn allocate(&self, layout: Layout) -> Result, AllocError> { let pointer = unsafe { ctru_sys::linearMemAlign(layout.size(), layout.align()) }; @@ -36,6 +38,7 @@ unsafe impl Allocator for LinearAllocator { .ok_or(AllocError) } + #[doc(alias = "linearFree")] unsafe fn deallocate(&self, ptr: NonNull, _layout: Layout) { ctru_sys::linearFree(ptr.as_ptr().cast()); } diff --git a/ctru-rs/src/mii.rs b/ctru-rs/src/mii.rs index a992a2ac..120eee12 100644 --- a/ctru-rs/src/mii.rs +++ b/ctru-rs/src/mii.rs @@ -177,6 +177,7 @@ pub struct MoleDetails { /// /// /// This struct is returned by the [`MiiSelector`](crate::applets::mii_selector::MiiSelector) +#[doc(alias = "MiiData")] #[derive(Clone, Debug)] pub struct MiiData { pub options: MiiDataOptions, diff --git a/ctru-rs/src/services/cam.rs b/ctru-rs/src/services/cam.rs index 6ddb37fa..0d18d896 100644 --- a/ctru-rs/src/services/cam.rs +++ b/ctru-rs/src/services/cam.rs @@ -21,6 +21,7 @@ pub struct Cam { } /// Flag to pass to [`Camera::flip_image`] +#[doc(alias = "CAMU_Flip")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum FlipMode { @@ -31,6 +32,7 @@ pub enum FlipMode { } /// Flag to pass to [`Camera::set_view_size`] +#[doc(alias = "CAMU_Size")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum ViewSize { @@ -48,6 +50,7 @@ pub enum ViewSize { } /// Flag to pass to [`Camera::set_frame_rate`] +#[doc(alias = "CAMU_FramRate")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum FrameRate { @@ -68,6 +71,7 @@ pub enum FrameRate { /// Flag to pass to [`Camera::set_white_balance`] or /// [`Camera::set_white_balance_without_base_up`] +#[doc(alias = "CAMU_WhiteBalance")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum WhiteBalance { @@ -86,6 +90,7 @@ pub enum WhiteBalance { } /// Flag to pass to [`Camera::set_photo_mode`] +#[doc(alias = "CAMU_PhotoMode")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum PhotoMode { @@ -97,6 +102,7 @@ pub enum PhotoMode { } /// Flag to pass to [`Camera::set_effect`] +#[doc(alias = "CAMU_Effect")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Effect { @@ -109,6 +115,7 @@ pub enum Effect { } /// Flag to pass to [`Camera::set_contrast`] +#[doc(alias = "CAMU_Contrast")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Contrast { @@ -121,6 +128,7 @@ pub enum Contrast { } /// Flag to pass to [`Camera::set_lens_correction`] +#[doc(alias = "CAMU_LensCorrection")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum LensCorrection { @@ -130,6 +138,7 @@ pub enum LensCorrection { } /// Flag to pass to [`Camera::set_output_format`] +#[doc(alias = "CAMU_OutputFormat")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum OutputFormat { @@ -138,6 +147,7 @@ pub enum OutputFormat { } /// Flag to pass to [`Cam::play_shutter_sound`] +#[doc(alias = "CAMU_ShutterSoundType")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum ShutterSound { @@ -194,10 +204,12 @@ impl TrimmingParams { } /// Represents data used by the camera to calibrate image quality +#[doc(alias = "CAMU_ImageQualityCalibrationData")] #[derive(Default, Clone, Copy, Debug)] pub struct ImageQualityCalibrationData(pub ctru_sys::CAMU_ImageQualityCalibrationData); /// Represents data used by the camera to calibrate image quality when using both outward cameras +#[doc(alias = "CAMU_StereoCameraCalibrationData")] #[derive(Default, Clone, Copy, Debug)] pub struct StereoCameraCalibrationData(pub ctru_sys::CAMU_StereoCameraCalibrationData); @@ -240,6 +252,7 @@ pub struct BothOutwardCam; impl BothOutwardCam { /// Sets whether to enable or disable synchronization /// of brightness for both left and right cameras + #[doc(alias = "CAMU_SetBrightnessSynchronization")] pub fn set_brightness_synchronization( &mut self, brightness_synchronization: bool, @@ -274,6 +287,7 @@ pub trait Camera { } /// Returns true if the camera is busy (receiving data) + #[doc(alias = "CAMU_IsBusy")] fn is_busy(&self) -> crate::Result { unsafe { let mut is_busy = false; @@ -284,6 +298,7 @@ pub trait Camera { /// Returns the maximum amount of transfer bytes based on the view size, trimming, and other /// modifications set to the camera + #[doc(alias = "CAMU_GetTransferBytes")] fn transfer_byte_count(&self) -> crate::Result { unsafe { let mut transfer_bytes = 0; @@ -297,6 +312,7 @@ pub trait Camera { /// Sets whether or not the camera should trim the image based on parameters set by /// [`Camera::set_trimming_params`] + #[doc(alias = "CAMU_SetTrimming")] fn set_trimming(&mut self, enabled: bool) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetTrimming(self.port_as_raw(), enabled))?; @@ -305,6 +321,7 @@ pub trait Camera { } /// Returns whether or not trimming is currently enabled for the camera + #[doc(alias = "CAMU_IsTrimming")] fn is_trimming_enabled(&self) -> crate::Result { unsafe { let mut trimming = false; @@ -314,6 +331,7 @@ pub trait Camera { } /// Sets trimming parameters based on coordinates specified inside a [`TrimmingParams`] + #[doc(alias = "CAMU_SetTrimmingParams")] fn set_trimming_params(&mut self, params: TrimmingParams) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetTrimmingParams( @@ -328,6 +346,7 @@ pub trait Camera { } /// Returns the [`TrimmingParams`] set + #[doc(alias = "CAMU_GetTrimmingParams")] fn trimming_params(&self) -> crate::Result { unsafe { let mut x_start = 0; @@ -354,6 +373,7 @@ pub trait Camera { /// Sets the trimming parameters revolving around the center of the image. /// The new width will be `trim_width / 2` to the left and right of the center. /// The new height will be `trim_height / 2` above and below the center. + #[doc(alias = "CAMU_SetTrimmingParamsCenter")] fn set_trimming_params_center( &mut self, trim_width: i16, @@ -374,6 +394,7 @@ pub trait Camera { } /// Sets the exposure level of the camera + #[doc(alias = "CAMU_SetExposure")] fn set_exposure(&mut self, exposure: i8) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetExposure(self.camera_as_raw(), exposure))?; @@ -382,6 +403,7 @@ pub trait Camera { } /// Sets the white balance mod of the camera based on the passed [`WhiteBalance`] argument + #[doc(alias = "CAMU_SetWhiteBalance")] fn set_white_balance(&mut self, white_balance: WhiteBalance) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetWhiteBalance( @@ -394,6 +416,7 @@ pub trait Camera { /// Sets the white balance mode of the camera based on the passed [`WhiteBalance`] argument // TODO: Explain base up + #[doc(alias = "CAMU_SetWhiteBalanceWithoutBaseUp")] fn set_white_balance_without_base_up( &mut self, white_balance: WhiteBalance, @@ -408,6 +431,7 @@ pub trait Camera { } /// Sets the sharpness of the camera + #[doc(alias = "CAMU_SetSharpness")] fn set_sharpness(&mut self, sharpness: i8) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetSharpness(self.camera_as_raw(), sharpness))?; @@ -416,6 +440,7 @@ pub trait Camera { } /// Sets whether auto exposure is enabled or disabled for the camera + #[doc(alias = "CAMU_SetAutoExposure")] fn set_auto_exposure(&mut self, enabled: bool) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetAutoExposure( @@ -427,6 +452,7 @@ pub trait Camera { } /// Returns true if auto exposure is enabled for the camera + #[doc(alias = "CAMU_IsAutoExposure")] fn is_auto_exposure_enabled(&self) -> crate::Result { unsafe { let mut enabled = false; @@ -439,6 +465,7 @@ pub trait Camera { } /// Sets whether auto white balance is enabled or disabled for the camera + #[doc(alias = "CAMU_SetAutoWhiteBalance")] fn set_auto_white_balance(&mut self, enabled: bool) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetAutoWhiteBalance( @@ -450,6 +477,7 @@ pub trait Camera { } /// Returns true if auto white balance is enabled for the camera + #[doc(alias = "CAMU_IsAutoWhiteBalance")] fn is_auto_white_balance_enabled(&self) -> crate::Result { unsafe { let mut enabled = false; @@ -462,6 +490,7 @@ pub trait Camera { } /// Sets the flip direction of the camera's image based on the passed [`FlipMode`] argument + #[doc(alias = "CAMU_FlipImage")] fn flip_image(&mut self, flip: FlipMode) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_FlipImage( @@ -485,6 +514,7 @@ pub trait Camera { /// * `height` - height of the image /// * `crop_0` - The first crop point in which the image will be trimmed /// * `crop_0` - The second crop point in which the image will be trimmed + #[doc(alias = "CAMU_SetDetailSize")] fn set_detail_size( &mut self, width: i16, @@ -508,6 +538,7 @@ pub trait Camera { } /// Sets the view size of the camera based on the passed [`ViewSize`] argument. + #[doc(alias = "CAMU_SetSize")] fn set_view_size(&mut self, size: ViewSize) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetSize( @@ -520,6 +551,7 @@ pub trait Camera { } /// Sets the frame rate of the camera based on the passed [`FrameRate`] argument. + #[doc(alias = "CAMU_SetFrameRate")] fn set_frame_rate(&mut self, frame_rate: FrameRate) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetFrameRate( @@ -531,6 +563,7 @@ pub trait Camera { } /// Sets the photo mode of the camera based on the passed [`PhotoMode`] argument. + #[doc(alias = "CAMU_SetPhotoMode")] fn set_photo_mode(&mut self, photo_mode: PhotoMode) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetPhotoMode( @@ -544,6 +577,7 @@ pub trait Camera { /// Sets the effect of the camera based on the passed [`Effect`] argument. /// /// Multiple effects can be set at once by combining the bitflags of [`Effect`] + #[doc(alias = "CAMU_SetEffect")] fn set_effect(&mut self, effect: Effect) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetEffect( @@ -556,6 +590,7 @@ pub trait Camera { } /// Sets the contrast of the camera based on the passed [`Contrast`] argument. + #[doc(alias = "CAMU_SetContrast")] fn set_contrast(&mut self, contrast: Contrast) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetContrast( @@ -567,6 +602,7 @@ pub trait Camera { } /// Sets the lens correction of the camera based on the passed [`LensCorrection`] argument. + #[doc(alias = "CAMU_SetLensCorrection")] fn set_lens_correction(&mut self, lens_correction: LensCorrection) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetLensCorrection( @@ -578,6 +614,7 @@ pub trait Camera { } /// Sets the output format of the camera based on the passed [`OutputFormat`] argument. + #[doc(alias = "CAMU_SetOutputFormat")] fn set_output_format(&mut self, format: OutputFormat) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetOutputFormat( @@ -597,6 +634,7 @@ pub trait Camera { /// * `y` - Starting y coordinate of the window /// * `width` - Width of the window /// * `height` - Height of the window + #[doc(alias = "CAMU_SetAutoExposureWindow")] fn set_auto_exposure_window( &mut self, x: i16, @@ -624,6 +662,7 @@ pub trait Camera { /// * `y` - Starting y coordinate of the window /// * `width` - Width of the window /// * `height` - Height of the window + #[doc(alias = "CAMU_SetAutoWhiteBalanceWindow")] fn set_auto_white_balance_window( &mut self, x: i16, @@ -644,6 +683,7 @@ pub trait Camera { } /// Sets whether the noise filter should be enabled or disabled for the camera + #[doc(alias = "CAMU_SetNoiseFilter")] fn set_noise_filter(&mut self, enabled: bool) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetNoiseFilter(self.camera_as_raw(), enabled))?; @@ -653,6 +693,7 @@ pub trait Camera { /// Sets the image quality calibration data for the camera based on the passed in /// [`ImageQualityCalibrationData`] argument + #[doc(alias = "CAMU_SetImageQualityCalibrationData")] fn set_image_quality_calibration_data( &mut self, data: ImageQualityCalibrationData, @@ -664,6 +705,7 @@ pub trait Camera { } /// Returns the current [`ImageQualityCalibrationData`] for the camera + #[doc(alias = "CAMU_GetImageQualityCalibrationData")] fn image_quality_calibration_data(&self) -> crate::Result { unsafe { let mut data = ImageQualityCalibrationData::default(); @@ -674,6 +716,7 @@ pub trait Camera { /// Sets the camera as the current sleep camera // TODO: Explain sleep camera + #[doc(alias = "CAMU_SetSleepCamera")] fn set_sleep_camera(&mut self) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_SetSleepCamera(self.camera_as_raw()))?; @@ -771,6 +814,7 @@ impl Cam { /// This function will return an error if the service was unable to be initialized. /// Since this service requires no special or elevated permissions, errors are /// rare in practice. + #[doc(alias = "camInit")] pub fn new() -> crate::Result { unsafe { ResultCode(ctru_sys::camInit())?; @@ -784,6 +828,7 @@ impl Cam { } /// Plays the specified sound based on the [`ShutterSound`] argument + #[doc(alias = "CAMU_PlayShutterSound")] pub fn play_shutter_sound(&self, sound: ShutterSound) -> crate::Result<()> { unsafe { ResultCode(ctru_sys::CAMU_PlayShutterSound(sound.into()))?; @@ -793,6 +838,7 @@ impl Cam { } impl Drop for Cam { + #[doc(alias = "camExit")] fn drop(&mut self) { unsafe { ctru_sys::camExit() }; } diff --git a/ctru-rs/src/services/cfgu.rs b/ctru-rs/src/services/cfgu.rs index a9cc411b..661fdf9d 100644 --- a/ctru-rs/src/services/cfgu.rs +++ b/ctru-rs/src/services/cfgu.rs @@ -4,6 +4,7 @@ use crate::error::ResultCode; +#[doc(alias = "CFG_Region")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Region { @@ -16,6 +17,7 @@ pub enum Region { Taiwan = ctru_sys::CFG_REGION_TWN, } +#[doc(alias = "CFG_Language")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Language { @@ -33,6 +35,7 @@ pub enum Language { TraditionalChinese = ctru_sys::CFG_LANGUAGE_TW, } +#[doc(alias = "CFG_SystemModel")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum SystemModel { @@ -61,12 +64,14 @@ impl Cfgu { /// ctrulib services are reference counted, so this function may be called /// as many times as desired and the service will not exit until all /// instances of Cfgu drop out of scope. + #[doc(alias = "cfguInit")] pub fn new() -> crate::Result { ResultCode(unsafe { ctru_sys::cfguInit() })?; Ok(Cfgu(())) } /// Gets system region from secure info + #[doc(alias = "CFGU_SecureInfoGetRegion")] pub fn region(&self) -> crate::Result { let mut region: u8 = 0; @@ -75,6 +80,7 @@ impl Cfgu { } /// Gets system's model + #[doc(alias = "CFGU_GetSystemModel")] pub fn model(&self) -> crate::Result { let mut model: u8 = 0; @@ -83,6 +89,7 @@ impl Cfgu { } /// Gets system's language + #[doc(alias = "CFGU_GetSystemLanguage")] pub fn language(&self) -> crate::Result { let mut language: u8 = 0; @@ -91,6 +98,7 @@ impl Cfgu { } /// Checks if NFC is supported by the console + #[doc(alias = "CFGU_IsNFCSupported")] pub fn is_nfc_supported(&self) -> crate::Result { let mut supported: bool = false; @@ -99,6 +107,7 @@ impl Cfgu { } /// Check if the console is from the 2DS family (2DS, New2DS, New2DSXL) + #[doc(alias = "CFGU_GetModelNintendo2DS")] pub fn is_2ds_family(&self) -> crate::Result { let mut is_2ds_family: u8 = 0; @@ -108,6 +117,7 @@ impl Cfgu { } impl Drop for Cfgu { + #[doc(alias = "cfguExit")] fn drop(&mut self) { unsafe { ctru_sys::cfguExit(); diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index faa03e33..b498ee92 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -39,6 +39,7 @@ bitflags! { } } +#[doc(alias = "FS_MediaType")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum FsMediaType { @@ -47,6 +48,7 @@ pub enum FsMediaType { GameCard = ctru_sys::MEDIATYPE_GAME_CARD, } +#[doc(alias = "FS_PathType")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum PathType { @@ -57,6 +59,7 @@ pub enum PathType { UTF16 = ctru_sys::PATH_UTF16, } +#[doc(alias = "FS_ArchiveID")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum ArchiveID { @@ -391,6 +394,7 @@ impl File { /// # Errors /// /// This function will return an error if the file is not opened for writing. + #[doc(alias = "FSFILE_SetSize")] pub fn set_len(&mut self, size: u64) -> IoResult<()> { unsafe { let r = ctru_sys::FSFILE_SetSize(self.handle, size); @@ -426,6 +430,7 @@ impl File { } } + #[doc(alias = "FSFILE_Read")] fn read(&mut self, buf: &mut [u8]) -> IoResult { unsafe { let mut n_read = 0; @@ -449,6 +454,7 @@ impl File { unsafe { read_to_end_uninitialized(self, buf) } } + #[doc(alias = "FSFILE_Write")] fn write(&mut self, buf: &[u8]) -> IoResult { unsafe { let mut n_written = 0; @@ -576,6 +582,7 @@ impl OpenOptions { /// to the `archive` method. /// * Filesystem-level errors (full disk, etc). /// * Invalid combinations of open options. + #[doc(alias = "FSUSER_OpenFile")] pub fn open>(&mut self, path: P) -> IoResult { self._open(path.as_ref(), self.open_flags()) } @@ -694,6 +701,7 @@ impl<'a> DirEntry<'a> { /// but is not limited to just these cases: /// /// * User lacks permissions to create directory at `path` +#[doc(alias = "FSUSER_CreateDirectory")] pub fn create_dir>(arch: &mut Archive, path: P) -> IoResult<()> { unsafe { let path = to_utf16(path.as_ref()); @@ -720,6 +728,7 @@ pub fn create_dir>(arch: &mut Archive, path: P) -> IoResult<()> { /// /// * If any directory in the path specified by `path` does not already exist /// and it could not be created otherwise. +#[doc(alias = "FSUSER_CreateDirectory")] pub fn create_dir_all>(arch: &mut Archive, path: P) -> IoResult<()> { let path = path.as_ref(); let mut dir = PathBuf::new(); @@ -756,6 +765,7 @@ pub fn metadata>(arch: &Archive, path: P) -> IoResult { /// /// * The user lacks permissions to remove the directory at the provided path. /// * The directory isn't empty. +#[doc(alias = "FSUSER_DeleteDirectory")] pub fn remove_dir>(arch: &mut Archive, path: P) -> IoResult<()> { unsafe { let path = to_utf16(path.as_ref()); @@ -774,6 +784,7 @@ pub fn remove_dir>(arch: &mut Archive, path: P) -> IoResult<()> { /// # Errors /// /// see `file::remove_file` and `fs::remove_dir` +#[doc(alias = "FSUSER_DeleteDirectoryRecursively")] pub fn remove_dir_all>(arch: &mut Archive, path: P) -> IoResult<()> { unsafe { let path = to_utf16(path.as_ref()); @@ -798,6 +809,7 @@ pub fn remove_dir_all>(arch: &mut Archive, path: P) -> IoResult<( /// * The provided path doesn't exist. /// * The process lacks permissions to view the contents. /// * The path points at a non-directory file. +#[doc(alias = "FSUSER_OpenDirectory")] pub fn read_dir>(arch: &Archive, path: P) -> IoResult { unsafe { let mut handle = 0; @@ -826,6 +838,7 @@ pub fn read_dir>(arch: &Archive, path: P) -> IoResult { /// /// * path points to a directory. /// * The user lacks permissions to remove the file. +#[doc(alias = "FSUSER_DeleteFile")] pub fn remove_file>(arch: &mut Archive, path: P) -> IoResult<()> { unsafe { let path = to_utf16(path.as_ref()); @@ -849,6 +862,7 @@ pub fn remove_file>(arch: &mut Archive, path: P) -> IoResult<()> /// /// * from does not exist. /// * The user lacks permissions to view contents. +#[doc(alias = "FSUSER_RenameFile", alias = "FSUSER_RenameDirectory")] pub fn rename(arch: &mut Archive, from: P, to: Q) -> IoResult<()> where P: AsRef, @@ -972,6 +986,7 @@ impl Seek for File { } impl Drop for Fs { + #[doc(alias = "fsExit")] fn drop(&mut self) { unsafe { ctru_sys::fsExit(); @@ -980,6 +995,7 @@ impl Drop for Fs { } impl Drop for Archive { + #[doc(alias = "FSUSER_CloseArchive")] fn drop(&mut self) { unsafe { let _ = ctru_sys::FSUSER_CloseArchive(self.handle); @@ -988,6 +1004,7 @@ impl Drop for Archive { } impl Drop for File { + #[doc(alias = "FSFILE_Close")] fn drop(&mut self) { unsafe { let _ = ctru_sys::FSFILE_Close(self.handle); @@ -996,6 +1013,7 @@ impl Drop for File { } impl Drop for Dir { + #[doc(alias = "FSDIR_Close")] fn drop(&mut self) { unsafe { let _ = ctru_sys::FSDIR_Close(self.0); diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index dd6fbffa..5629cf67 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -23,6 +23,7 @@ mod private { /// This trait is implemented by the screen structs for working with frame buffers and /// drawing to the screens. Graphics-related code can be made generic over this /// trait to work with any of the given screens. +#[doc(alias = "gfxScreen_t")] pub trait Screen: private::Sealed { /// Returns the `libctru` value for the Screen kind. fn as_raw(&self) -> ctru_sys::gfxScreen_t; @@ -34,6 +35,7 @@ pub trait Screen: private::Sealed { /// /// Note that the pointer of the framebuffer returned by this function can /// change after each call to this function if double buffering is enabled. + #[doc(alias = "gfxGetFramebuffer")] fn raw_framebuffer(&mut self) -> RawFrameBuffer { let mut width: u16 = 0; let mut height: u16 = 0; @@ -52,11 +54,13 @@ pub trait Screen: private::Sealed { /// /// [`Swap::swap_buffers`] must be called after this function for the configuration /// change to take effect. + #[doc(alias = "gfxSetDoubleBuffering")] fn set_double_buffering(&mut self, enabled: bool) { unsafe { ctru_sys::gfxSetDoubleBuffering(self.as_raw(), enabled) } } /// Gets the framebuffer format. + #[doc(alias = "gfxGetScreenFormat")] fn framebuffer_format(&self) -> FramebufferFormat { unsafe { ctru_sys::gfxGetScreenFormat(self.as_raw()) }.into() } @@ -65,6 +69,7 @@ pub trait Screen: private::Sealed { /// /// [`Swap::swap_buffers`] must be called after this method for the configuration /// change to take effect. + #[doc(alias = "gfxSetScreenFormat")] fn set_framebuffer_format(&mut self, fmt: FramebufferFormat) { unsafe { ctru_sys::gfxSetScreenFormat(self.as_raw(), fmt.into()) } } @@ -94,6 +99,7 @@ pub trait Swap: private::Sealed { /// [`Screen::set_framebuffer_format`], [`Screen::set_double_buffering`]). /// /// This should be called once per frame at most. + #[doc(alias = "gfxScreenSwapBuffers")] fn swap_buffers(&mut self); } @@ -126,6 +132,7 @@ impl Swap for BottomScreen { pub trait Flush: private::Sealed { /// Flushes the video buffer(s) for this screen. Note that you must still call /// [`Swap::swap_buffers`] after this method for the buffer contents to be displayed. + #[doc(alias = "gfxFlushBuffers")] fn flush_buffers(&mut self); } @@ -184,11 +191,12 @@ pub struct RawFrameBuffer<'screen> { screen: PhantomData<&'screen mut dyn Screen>, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[repr(u32)] /// Side of top screen framebuffer /// /// The top screen of the 3DS can have two separate sets of framebuffers to support its 3D functionality +#[doc(alias = "gfx3dSide_t")] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(u32)] pub enum Side { /// The left framebuffer. This framebuffer is also the one used when 3D is disabled Left = ctru_sys::GFX_LEFT, @@ -215,6 +223,7 @@ impl Gfx { /// ``` /// Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false) /// ``` + #[doc(alias = "gfxInit")] pub fn new() -> Result { Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false) } @@ -223,6 +232,7 @@ impl Gfx { /// screens /// /// Use `Gfx::new()` instead of this function to initialize the module with default parameters + #[doc(alias = "gfxInit")] pub fn with_formats( top_fb_fmt: FramebufferFormat, bottom_fb_fmt: FramebufferFormat, @@ -269,6 +279,7 @@ impl TopScreen3D<'_> { } impl<'screen> From<&'screen RefCell> for TopScreen3D<'screen> { + #[doc(alias = "gfxSet3D")] fn from(top_screen: &'screen RefCell) -> Self { unsafe { ctru_sys::gfxSet3D(true); @@ -298,6 +309,7 @@ impl TopScreen { /// /// [`Swap::swap_buffers`] must be called after this method for the configuration /// to take effect. + #[doc(alias = "gfxSetWide")] pub fn set_wide_mode(&mut self, enable: bool) { unsafe { ctru_sys::gfxSetWide(enable); @@ -305,6 +317,7 @@ impl TopScreen { } /// Returns whether or not wide mode is enabled on the top screen. + #[doc(alias = "gfxIsWide")] pub fn is_wide(&self) -> bool { unsafe { ctru_sys::gfxIsWide() } } diff --git a/ctru-rs/src/services/gspgpu.rs b/ctru-rs/src/services/gspgpu.rs index 9f9219c2..1510b296 100644 --- a/ctru-rs/src/services/gspgpu.rs +++ b/ctru-rs/src/services/gspgpu.rs @@ -1,5 +1,6 @@ //! GSPGPU service +#[doc(alias = "GSPGPU_Event")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Event { @@ -12,6 +13,7 @@ pub enum Event { DMA = ctru_sys::GSPGPU_EVENT_DMA, } +#[doc(alias = "GSPGPU_FramebufferFormat")] /// Framebuffer formats supported by the 3DS #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] @@ -45,6 +47,7 @@ impl FramebufferFormat { /// Waits for a GSPGPU event to occur. /// /// `discard_current` determines whether to discard the current event and wait for the next event +#[doc(alias = "gspWaitForEvent")] pub fn wait_for_event(ev: Event, discard_current: bool) { unsafe { ctru_sys::gspWaitForEvent(ev.into(), discard_current); diff --git a/ctru-rs/src/services/hid.rs b/ctru-rs/src/services/hid.rs index fa916575..8de66a18 100644 --- a/ctru-rs/src/services/hid.rs +++ b/ctru-rs/src/services/hid.rs @@ -54,6 +54,7 @@ pub struct Hid(()); /// Since this service requires no special or elevated permissions, errors are /// rare in practice. impl Hid { + #[doc(alias = "hidInit")] pub fn new() -> crate::Result { unsafe { ResultCode(ctru_sys::hidInit())?; @@ -64,12 +65,14 @@ impl Hid { /// Scans the HID service for all user input occurring on the current /// frame. This function should be called on every frame when polling /// for user input. + #[doc(alias = "hidScanInput")] pub fn scan_input(&mut self) { unsafe { ctru_sys::hidScanInput() }; } /// Returns a bitflag struct representing which buttons have just been pressed /// on the current frame (and were not pressed on the previous frame). + #[doc(alias = "hidKeysDown")] pub fn keys_down(&self) -> KeyPad { unsafe { let keys = ctru_sys::hidKeysDown(); @@ -79,6 +82,7 @@ impl Hid { /// Returns a bitflag struct representing which buttons have been held down /// during the current frame. + #[doc(alias = "hidKeysHeld")] pub fn keys_held(&self) -> KeyPad { unsafe { let keys = ctru_sys::hidKeysHeld(); @@ -88,6 +92,7 @@ impl Hid { /// Returns a bitflag struct representing which buttons have just been released on /// the current frame. + #[doc(alias = "hidKeysUp")] pub fn keys_up(&self) -> KeyPad { unsafe { let keys = ctru_sys::hidKeysUp(); @@ -100,6 +105,7 @@ impl Hid { /// # Notes /// /// (0, 0) represents the top left corner of the screen. + #[doc(alias = "hidTouchRead")] pub fn touch_position(&mut self) -> (u16, u16) { let mut res = ctru_sys::touchPosition { px: 0, py: 0 }; @@ -114,6 +120,7 @@ impl Hid { /// # Notes /// /// (0, 0) represents the center of the circle pad. + #[doc(alias = "hidCircleRead")] pub fn circlepad_position(&mut self) -> (i16, i16) { let mut res = ctru_sys::circlePosition { dx: 0, dy: 0 }; @@ -125,6 +132,7 @@ impl Hid { } impl Drop for Hid { + #[doc(alias = "hidExit")] fn drop(&mut self) { unsafe { ctru_sys::hidExit() }; } diff --git a/ctru-rs/src/services/ndsp/mod.rs b/ctru-rs/src/services/ndsp/mod.rs index 72e2413f..7867048a 100644 --- a/ctru-rs/src/services/ndsp/mod.rs +++ b/ctru-rs/src/services/ndsp/mod.rs @@ -14,6 +14,7 @@ use std::sync::Mutex; const NUMBER_OF_CHANNELS: u8 = 24; +#[doc(alias = "ndspOutputMode")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum OutputMode { @@ -37,6 +38,7 @@ pub struct AudioMix { raw: [f32; 12], } +#[doc(alias = "ndspInterpType")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum InterpolationType { @@ -80,6 +82,7 @@ impl Ndsp { /// /// This function will return an error if an instance of the `Ndsp` struct already exists /// or if there are any issues during initialization. + #[doc(alias = "ndspInit")] pub fn new() -> crate::Result { let _service_handler = ServiceReference::new( &NDSP_ACTIVE, @@ -121,6 +124,7 @@ impl Ndsp { } /// Set the audio output mode. Defaults to `OutputMode::Stereo`. + #[doc(alias = "ndspSetOutputMode")] pub fn set_output_mode(&mut self, mode: OutputMode) { unsafe { ctru_sys::ndspSetOutputMode(mode.into()) }; } @@ -128,21 +132,25 @@ impl Ndsp { impl Channel<'_> { /// Reset the channel + #[doc(alias = "ndspChnReset")] pub fn reset(&mut self) { unsafe { ctru_sys::ndspChnReset(self.id.into()) }; } /// Initialize the channel's parameters + #[doc(alias = "ndspChnInitParams")] pub fn init_parameters(&self) { unsafe { ctru_sys::ndspChnInitParams(self.id.into()) }; } /// Returns whether the channel is playing any audio. + #[doc(alias = "ndspChnIsPlaying")] pub fn is_playing(&self) -> bool { unsafe { ctru_sys::ndspChnIsPlaying(self.id.into()) } } /// Returns whether the channel's playback is currently paused. + #[doc(alias = "ndspChnIsPaused")] pub fn is_paused(&self) -> bool { unsafe { ctru_sys::ndspChnIsPaused(self.id.into()) } } @@ -155,37 +163,44 @@ impl Channel<'_> { /// Returns the index of the currently played sample. /// /// Because of how fast this value changes, it should only be used as a rough estimate of the current progress. + #[doc(alias = "ndspChnGetSamplePos")] pub fn sample_position(&self) -> usize { (unsafe { ctru_sys::ndspChnGetSamplePos(self.id.into()) }) as usize } /// Returns the channel's current wave sequence's id. + #[doc(alias = "ndspChnGetWaveBufSeq")] pub fn wave_sequence_id(&self) -> u16 { unsafe { ctru_sys::ndspChnGetWaveBufSeq(self.id.into()) } } /// Pause or un-pause the channel's playback. + #[doc(alias = "ndspChnSetPaused")] pub fn set_paused(&mut self, state: bool) { unsafe { ctru_sys::ndspChnSetPaused(self.id.into(), state) }; } /// Set the channel's output format. /// Change this setting based on the used sample's format. + #[doc(alias = "ndspChnSetFormat")] pub fn set_format(&mut self, format: AudioFormat) { unsafe { ctru_sys::ndspChnSetFormat(self.id.into(), format.into()) }; } /// Set the channel's interpolation mode. + #[doc(alias = "ndspChnSetInterp")] pub fn set_interpolation(&mut self, interp_type: InterpolationType) { unsafe { ctru_sys::ndspChnSetInterp(self.id.into(), interp_type.into()) }; } /// Set the channel's volume mix. + #[doc(alias = "ndspChnSetMix")] pub fn set_mix(&mut self, mix: &AudioMix) { unsafe { ctru_sys::ndspChnSetMix(self.id.into(), mix.as_raw().as_ptr().cast_mut()) } } /// Set the channel's rate of sampling. + #[doc(alias = "ndspChnSetRate")] pub fn set_sample_rate(&mut self, rate: f32) { unsafe { ctru_sys::ndspChnSetRate(self.id.into(), rate) }; } @@ -195,6 +210,7 @@ impl Channel<'_> { // We suggest using other wave formats when developing homebrew applications. /// Clear the wave buffer queue and stop playback. + #[doc(alias = "ndspChnWaveBufClear")] pub fn clear_queue(&mut self) { unsafe { ctru_sys::ndspChnWaveBufClear(self.id.into()) }; } @@ -206,6 +222,7 @@ impl Channel<'_> { /// /// `libctru` expects the user to manually keep the info data (in this case [`Wave`]) alive during playback. /// To ensure safety, checks within [`Wave`] will clear the whole channel queue if any queued [`Wave`] is dropped prematurely. + #[doc(alias = "ndspChnWaveBufAdd")] pub fn queue_wave(&mut self, wave: &mut Wave) -> std::result::Result<(), NdspError> { match wave.status() { WaveStatus::Playing | WaveStatus::Queued => return Err(NdspError::WaveBusy(self.id)), @@ -225,6 +242,7 @@ impl Channel<'_> { /// Refer to [`libctru`](https://libctru.devkitpro.org/channel_8h.html#a1da3b363c2edfd318c92276b527daae6) for more info. impl Channel<'_> { /// Enables/disables monopole filters. + #[doc(alias = "ndspChnIirMonoSetEnable")] pub fn iir_mono_set_enabled(&mut self, enable: bool) { unsafe { ctru_sys::ndspChnIirMonoSetEnable(self.id.into(), enable) }; } @@ -234,6 +252,7 @@ impl Channel<'_> { /// # Notes /// /// This is a lower quality filter than the Biquad alternative. + #[doc(alias = "ndspChnIirMonoSetParamsHighPassFilter")] pub fn iir_mono_set_params_high_pass_filter(&mut self, cut_off_freq: f32) { unsafe { ctru_sys::ndspChnIirMonoSetParamsHighPassFilter(self.id.into(), cut_off_freq) }; } @@ -243,16 +262,19 @@ impl Channel<'_> { /// # Notes /// /// This is a lower quality filter than the Biquad alternative. + #[doc(alias = "ndspChnIirMonoSetParamsLowPassFilter")] pub fn iir_mono_set_params_low_pass_filter(&mut self, cut_off_freq: f32) { unsafe { ctru_sys::ndspChnIirMonoSetParamsLowPassFilter(self.id.into(), cut_off_freq) }; } /// Enables/disables biquad filters. + #[doc(alias = "ndspChnIirBiquadSetEnable")] pub fn iir_biquad_set_enabled(&mut self, enable: bool) { unsafe { ctru_sys::ndspChnIirBiquadSetEnable(self.id.into(), enable) }; } /// Sets the biquad to be a high pass filter. + #[doc(alias = "ndspChnIirBiquadSetParamsHighPassFilter")] pub fn iir_biquad_set_params_high_pass_filter(&mut self, cut_off_freq: f32, quality: f32) { unsafe { ctru_sys::ndspChnIirBiquadSetParamsHighPassFilter(self.id.into(), cut_off_freq, quality) @@ -260,6 +282,7 @@ impl Channel<'_> { } /// Sets the biquad to be a low pass filter. + #[doc(alias = "ndspChnIirBiquadSetParamsLowPassFilter")] pub fn iir_biquad_set_params_low_pass_filter(&mut self, cut_off_freq: f32, quality: f32) { unsafe { ctru_sys::ndspChnIirBiquadSetParamsLowPassFilter(self.id.into(), cut_off_freq, quality) @@ -267,6 +290,7 @@ impl Channel<'_> { } /// Sets the biquad to be a notch filter. + #[doc(alias = "ndspChnIirBiquadSetParamsNotchFilter")] pub fn iir_biquad_set_params_notch_filter(&mut self, notch_freq: f32, quality: f32) { unsafe { ctru_sys::ndspChnIirBiquadSetParamsNotchFilter(self.id.into(), notch_freq, quality) @@ -274,6 +298,7 @@ impl Channel<'_> { } /// Sets the biquad to be a band pass filter. + #[doc(alias = "ndspChnIirBiquadSetParamsBandPassFilter")] pub fn iir_biquad_set_params_band_pass_filter(&mut self, mid_freq: f32, quality: f32) { unsafe { ctru_sys::ndspChnIirBiquadSetParamsBandPassFilter(self.id.into(), mid_freq, quality) @@ -281,6 +306,7 @@ impl Channel<'_> { } /// Sets the biquad to be a peaking equalizer. + #[doc(alias = "ndspChnIirBiquadSetParamsPeakingEqualizer")] pub fn iir_biquad_set_params_peaking_equalizer( &mut self, central_freq: f32, @@ -448,6 +474,7 @@ impl fmt::Display for NdspError { impl error::Error for NdspError {} impl Drop for Ndsp { + #[doc(alias = "ndspExit")] fn drop(&mut self) { for i in 0..NUMBER_OF_CHANNELS { self.channel(i).unwrap().reset(); diff --git a/ctru-rs/src/services/ps.rs b/ctru-rs/src/services/ps.rs index 1d5bd698..ee962165 100644 --- a/ctru-rs/src/services/ps.rs +++ b/ctru-rs/src/services/ps.rs @@ -6,6 +6,7 @@ use crate::error::ResultCode; use crate::Result; +#[doc(alias = "PS_AESAlgorithm")] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum AESAlgorithm { @@ -17,6 +18,7 @@ pub enum AESAlgorithm { CcmDec = ctru_sys::PS_ALGORITHM_CCM_DEC, } +#[doc(alias = "PS_AESKeyType")] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum AESKeyType { @@ -35,6 +37,7 @@ pub enum AESKeyType { pub struct Ps(()); impl Ps { + #[doc(alias = "psInit")] pub fn new() -> Result { unsafe { ResultCode(ctru_sys::psInit())?; @@ -42,6 +45,7 @@ impl Ps { } } + #[doc(alias = "PS_GetLocalFriendCodeSeed")] pub fn local_friend_code_seed(&self) -> crate::Result { let mut seed: u64 = 0; @@ -49,6 +53,7 @@ impl Ps { Ok(seed) } + #[doc(alias = "PS_GetDeviceId")] pub fn device_id(&self) -> crate::Result { let mut id: u32 = 0; @@ -56,6 +61,7 @@ impl Ps { Ok(id) } + #[doc(alias = "PS_GenerateRandomBytes")] pub fn generate_random_bytes(&self, out: &mut [u8]) -> crate::Result<()> { ResultCode(unsafe { ctru_sys::PS_GenerateRandomBytes(out.as_mut_ptr().cast(), out.len()) @@ -65,6 +71,7 @@ impl Ps { } impl Drop for Ps { + #[doc(alias = "psExit")] fn drop(&mut self) { unsafe { ctru_sys::psExit(); diff --git a/ctru-rs/src/services/romfs.rs b/ctru-rs/src/services/romfs.rs index c87b8844..3c5afa89 100644 --- a/ctru-rs/src/services/romfs.rs +++ b/ctru-rs/src/services/romfs.rs @@ -25,6 +25,7 @@ pub struct RomFS { static ROMFS_ACTIVE: Mutex = Mutex::new(0); impl RomFS { + #[doc(alias = "romfsMountSelf")] pub fn new() -> crate::Result { let _service_handler = ServiceReference::new( &ROMFS_ACTIVE, @@ -44,6 +45,11 @@ impl RomFS { } } +impl Drop for RomFS { + #[doc(alias = "romfsUnmount")] + fn drop(&mut self) {} +} + #[cfg(test)] mod tests { use super::*; diff --git a/ctru-rs/src/services/soc.rs b/ctru-rs/src/services/soc.rs index 5b9c6962..2bbfe506 100644 --- a/ctru-rs/src/services/soc.rs +++ b/ctru-rs/src/services/soc.rs @@ -25,6 +25,7 @@ impl Soc { /// # Errors /// /// This function will return an error if the `Soc` service is already initialized + #[doc(alias = "socInit")] pub fn new() -> crate::Result { Self::init_with_buffer_size(0x100000) } @@ -35,6 +36,7 @@ impl Soc { /// # Errors /// /// This function will return an error if the `Soc` service is already initialized + #[doc(alias = "socInit")] pub fn init_with_buffer_size(num_bytes: usize) -> crate::Result { let _service_handler = ServiceReference::new( &SOC_ACTIVE, @@ -61,6 +63,7 @@ impl Soc { } /// IP Address of the Nintendo 3DS system. + #[doc(alias = "gethostid")] pub fn host_address(&self) -> Ipv4Addr { let raw_id = unsafe { libc::gethostid() }; Ipv4Addr::from(raw_id.to_ne_bytes()) @@ -73,6 +76,7 @@ impl Soc { /// /// Returns an error if a connection cannot be established to the server, or /// output was already previously redirected. + #[doc(alias = "link3dsConnectToHost")] pub fn redirect_to_3dslink(&mut self, stdout: bool, stderr: bool) -> crate::Result<()> { if self.sock_3dslink >= 0 { return Err(Error::OutputAlreadyRedirected); @@ -92,6 +96,7 @@ impl Soc { } impl Drop for Soc { + #[doc(alias = "socExit")] fn drop(&mut self) { if self.sock_3dslink >= 0 { unsafe { diff --git a/ctru-rs/src/services/sslc.rs b/ctru-rs/src/services/sslc.rs index 341155f2..d248f0ec 100644 --- a/ctru-rs/src/services/sslc.rs +++ b/ctru-rs/src/services/sslc.rs @@ -8,6 +8,7 @@ pub struct SslC(()); impl SslC { /// Initialize the service + #[doc(alias = "sslcInit")] pub fn new() -> crate::Result { unsafe { ResultCode(ctru_sys::sslcInit(0))?; @@ -17,6 +18,7 @@ impl SslC { } impl Drop for SslC { + #[doc(alias = "sslcExit")] fn drop(&mut self) { unsafe { ctru_sys::sslcExit() }; } From 61e20fa2dce4ac8eae95f741683025aa6aecae1d Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sat, 8 Jul 2023 19:19:53 +0200 Subject: [PATCH 07/39] Enum variants documentation + ide files ignored --- .gitignore | 1 + ctru-rs/src/applets/mii_selector.rs | 16 +++- ctru-rs/src/applets/swkbd.rs | 49 ++++++++-- ctru-rs/src/mii.rs | 133 +++++++++++++++++++++++----- ctru-rs/src/services/am.rs | 12 +-- ctru-rs/src/services/cam.rs | 63 +++++++++++-- ctru-rs/src/services/cfgu.rs | 30 ++++++- ctru-rs/src/services/fs.rs | 35 ++++++++ ctru-rs/src/services/gspgpu.rs | 10 ++- ctru-rs/src/services/hid.rs | 31 ++++++- ctru-rs/src/services/ndsp/mod.rs | 14 +++ ctru-rs/src/services/ndsp/wave.rs | 4 + ctru-rs/src/services/ps.rs | 18 ++++ ctru-rs/src/services/sslc.rs | 1 + 14 files changed, 365 insertions(+), 52 deletions(-) diff --git a/.gitignore b/.gitignore index 54f18383..f4d733bf 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ Cargo.lock # IDE files .idea +.vscode diff --git a/ctru-rs/src/applets/mii_selector.rs b/ctru-rs/src/applets/mii_selector.rs index eada7e33..577d0dfe 100644 --- a/ctru-rs/src/applets/mii_selector.rs +++ b/ctru-rs/src/applets/mii_selector.rs @@ -6,18 +6,26 @@ use crate::mii::MiiData; use bitflags::bitflags; use std::ffi::CString; -/// Index of a Mii used to configure some parameters of the Mii Selector -/// Can be either a single index, or _all_ Miis +/// Index of a Mii used to configure some parameters of the Mii Selector. #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum Index { + /// Specific Mii index. Index(u32), + /// All Miis. All, } /// The type of a Mii with their respective data #[derive(Debug, Clone, Eq, PartialEq)] pub enum MiiType { - Guest { index: u32, name: String }, + /// Guest Mii. + Guest { + /// Guest Mii index. + index: u32, + /// Guest Mii name. + name: String, + }, + /// User-made Mii. User, } @@ -56,7 +64,9 @@ pub struct MiiSelector { #[non_exhaustive] #[derive(Clone, Debug)] pub struct SelectionResult { + /// Data regarding the selected Mii. pub mii_data: MiiData, + /// Type of the selected Mii. pub mii_type: MiiType, } diff --git a/ctru-rs/src/applets/swkbd.rs b/ctru-rs/src/applets/swkbd.rs index 49a41039..e5e9c285 100644 --- a/ctru-rs/src/applets/swkbd.rs +++ b/ctru-rs/src/applets/swkbd.rs @@ -14,19 +14,19 @@ pub struct Swkbd { } /// The kind of keyboard to be initialized. -/// -/// Normal is the full keyboard with several pages (QWERTY/accents/symbol/mobile) -/// Qwerty is a QWERTY-only keyboard. -/// Numpad is a number pad. -/// Western is a text keyboard without japanese symbols (only applies to JPN systems). For other -/// systems it's the same as a Normal keyboard. #[doc(alias = "SwkbdType")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Kind { + /// Normal keyboard composed of several pages (QWERTY, accents, symbols, mobile). Normal = ctru_sys::SWKBD_TYPE_NORMAL, + /// Only QWERTY keyboard. Qwerty = ctru_sys::SWKBD_TYPE_QWERTY, + /// Only number pad. Numpad = ctru_sys::SWKBD_TYPE_NUMPAD, + /// On JPN systems: a keyboard without japanese input capablities. + /// + /// On any other region: same as [`Normal`](Kind::Normal). Western = ctru_sys::SWKBD_TYPE_WESTERN, } @@ -35,8 +35,11 @@ pub enum Kind { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Button { + /// Left button. Usually corresponds to "Cancel". Left = ctru_sys::SWKBD_BUTTON_LEFT, + /// Middle button. Usually corresponds to "I Forgot". Middle = ctru_sys::SWKBD_BUTTON_MIDDLE, + /// Right button. Usually corresponds to "OK". Right = ctru_sys::SWKBD_BUTTON_RIGHT, } @@ -45,49 +48,77 @@ pub enum Button { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(i32)] pub enum Error { + /// Invalid parameters inputted in the Software Keyboard. InvalidInput = ctru_sys::SWKBD_INVALID_INPUT, + /// Out of memory. OutOfMem = ctru_sys::SWKBD_OUTOFMEM, + /// Home button was pressed during execution. HomePressed = ctru_sys::SWKBD_HOMEPRESSED, + /// Reset button was pressed during execution. ResetPressed = ctru_sys::SWKBD_RESETPRESSED, + /// Power button was pressed during execution. PowerPressed = ctru_sys::SWKBD_POWERPRESSED, + /// The parental PIN was correct. ParentalOk = ctru_sys::SWKBD_PARENTAL_OK, + /// The parental PIN was incorrect. ParentalFail = ctru_sys::SWKBD_PARENTAL_FAIL, + /// Input triggered the filter. BannedInput = ctru_sys::SWKBD_BANNED_INPUT, } -/// Restrictions on keyboard input +/// Restrictions on keyboard input. #[doc(alias = "SwkbdValidInput")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum ValidInput { + /// All inputs are accepted. Anything = ctru_sys::SWKBD_ANYTHING, + /// Empty inputs are not accepted. NotEmpty = ctru_sys::SWKBD_NOTEMPTY, - NotEmptyNotBlank = ctru_sys::SWKBD_NOTEMPTY_NOTBLANK, + /// Blank (consisting only of whitespaces) inputs are not accepted. NotBlank = ctru_sys::SWKBD_NOTBLANK, + /// Neither empty inputs nor blank inputs are accepted. + NotEmptyNotBlank = ctru_sys::SWKBD_NOTEMPTY_NOTBLANK, + /// Input must have a fixed length. Maximum length can be specified with [`Swkbd::set_max_text_len`]; FixedLen = ctru_sys::SWKBD_FIXEDLEN, } bitflags! { - /// Keyboard feature flags + /// Keyboard feature flags. pub struct Features: u32 { + /// Parental PIN mode. const PARENTAL_PIN = ctru_sys::SWKBD_PARENTAL; + /// Darken top screen while the Software Keyboard is active. const DARKEN_TOP_SCREEN = ctru_sys::SWKBD_DARKEN_TOP_SCREEN; + /// Enable predictive input (necessary for Kanji on JPN consoles). const PREDICTIVE_INPUT = ctru_sys::SWKBD_PREDICTIVE_INPUT; + /// Enable multiline input. const MULTILINE = ctru_sys::SWKBD_MULTILINE; + /// Enable fixed-width mode. const FIXED_WIDTH = ctru_sys::SWKBD_FIXED_WIDTH; + /// Allow the usage of the Home Button while the Software Keyboard is active. const ALLOW_HOME = ctru_sys::SWKBD_ALLOW_HOME; + /// Allow the usage of the Reset Button while the Software Keyboard is active. const ALLOW_RESET = ctru_sys::SWKBD_ALLOW_RESET; + /// Allow the usage of the Power Button while the Software Keyboard is active. const ALLOW_POWER = ctru_sys::SWKBD_ALLOW_POWER; + /// Default to the QWERTY page when the Software Keyboard is shown. const DEFAULT_QWERTY = ctru_sys::SWKBD_DEFAULT_QWERTY; } /// Keyboard input filtering flags pub struct Filters: u32 { + /// Disallows the usage of numerical digits. const DIGITS = ctru_sys::SWKBD_FILTER_DIGITS; + /// Disallows the usage of the "at" (@) sign. const AT = ctru_sys::SWKBD_FILTER_AT; + /// Disallows the usage of the "percent" (%) sign. const PERCENT = ctru_sys::SWKBD_FILTER_PERCENT; + /// Disallows the usage of the "backslash" (\) sign. const BACKSLASH = ctru_sys::SWKBD_FILTER_BACKSLASH; + /// Disallows the use of profanity via Nintendo's profanity filter. const PROFANITY = ctru_sys::SWKBD_FILTER_PROFANITY; + /// Use a custom callback in order to filter the input. const CALLBACK = ctru_sys::SWKBD_FILTER_CALLBACK; } } diff --git a/ctru-rs/src/mii.rs b/ctru-rs/src/mii.rs index 120eee12..b5a2f039 100644 --- a/ctru-rs/src/mii.rs +++ b/ctru-rs/src/mii.rs @@ -3,171 +3,238 @@ //! This module contains the structs that represent all the data of a Mii. //! This data is given by the [``MiiSelector``](crate::applets::mii_selector::MiiSelector) -/// Represents the region lock of the console +/// Represents the region lock of the console. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum RegionLock { + /// No region-lock. None, + /// Japan region-lock. Japan, + /// USA region-lock. USA, + /// Europe region-lock. Europe, } -/// Represent the charset of the console +/// Represent the charset of the console. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Charset { + /// Japan-USA-Europe unified charset. JapanUSAEurope, + /// China charset. China, + /// Korea charset. Korea, + /// Taiwan charset. Taiwan, } -/// Represents the options of the Mii +/// Represents the options of the Mii. #[derive(Copy, Clone, Debug)] pub struct MiiDataOptions { + /// Whether it is allowed to copy the Mii. pub is_copying_allowed: bool, + /// Whether the profanity flag is active. pub is_profanity_flag_enabled: bool, + /// The Mii's active region-lock. pub region_lock: RegionLock, + /// The Mii's used charset. pub charset: Charset, } -/// Represents the position that the Mii has on the selector +/// Represents the position that the Mii has on the selector. #[derive(Copy, Clone, Debug)] pub struct SelectorPosition { + /// Index of the page where the Mii is found. pub page_index: u8, + /// Index of the slot (relative to the page) where the Mii is found. pub slot_index: u8, } -/// Represents the kind of origin console +/// Represents the console where the Mii originated from. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum OriginConsole { + /// Nintendo Wii. Wii, + /// Nintendo DSi. DSi, - /// Both New 3DS and Old 3DS + /// Nintendo 3DS (both New 3DS and Old 3DS). N3DS, + /// Nintendo WiiU/Switch. WiiUSwitch, } -/// Represents the identity of the origin console +/// Represents the identity of the origin console. #[derive(Copy, Clone, Debug)] pub struct ConsoleIdentity { + /// From which console the Mii originated from. pub origin_console: OriginConsole, } -/// Represents the sex of the Mii +/// Represents the sex of the Mii. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum MiiSex { + /// Male sex. Male, + /// Female sex. Female, } -/// Represents the details of the Mii +/// Represents the details of the Mii. #[derive(Copy, Clone, Debug)] pub struct Details { + /// Sex of the Mii. pub sex: MiiSex, + /// Birthday month. pub birthday_month: u8, + /// Birthday day. pub birthday_day: u8, + /// Color of the Mii's shirt. pub shirt_color: u8, + /// Whether the Mii is a favorite. pub is_favorite: bool, + /// Whether the Mii can be shared. + pub is_sharing_enabled: bool, } -/// Represents the face style of the Mii +/// Represents the face style of the Mii. #[derive(Copy, Clone, Debug)] pub struct FaceStyle { - pub is_sharing_enabled: bool, + /// Face shape. pub shape: u8, + /// Skin color. pub skin_color: u8, } -/// Represents the face details of the Mii +/// Represents the face details of the Mii. #[derive(Copy, Clone, Debug)] pub struct FaceDetails { + /// Face style. pub style: FaceStyle, + /// Wrinkles. pub wrinkles: u8, + /// Makeup. pub makeup: u8, } -/// Represents the hair details of the Mii +/// Represents the hair details of the Mii. #[derive(Copy, Clone, Debug)] pub struct HairDetails { + /// Hair style. pub style: u8, + /// Hair color. pub color: u8, + /// Whether the Mii's hair is flipped. pub is_flipped: bool, } -/// Represents the eye details of the Mii +/// Represents the eye details of the Mii. #[derive(Copy, Clone, Debug)] pub struct EyeDetails { + /// Eye style. pub style: u8, + /// Eye color. pub color: u8, + /// Eye scale. pub scale: u8, + /// Eye scale (y-axis). pub y_scale: u8, + /// Eye rotation. pub rotation: u8, - /// Spacing between the eyes + /// Spacing between the eyes. pub x_spacing: u8, + /// Eye height. pub y_position: u8, } /// Represents the eyebrow details of the Mii #[derive(Copy, Clone, Debug)] pub struct EyebrowDetails { + /// Eyebrow style. pub style: u8, + /// Eyebrow color. pub color: u8, + /// Eyebrow scale. pub scale: u8, + /// Eyebrow scale (y-axis). pub y_scale: u8, + /// Eyebrow rotation. pub rotation: u8, /// Spacing between the eyebrows pub x_spacing: u8, + /// Eyebrow height. pub y_position: u8, } /// Represents the details of the nose #[derive(Copy, Clone, Debug)] pub struct NoseDetails { + /// Nose style. pub style: u8, + /// Nose scale. pub scale: u8, + /// Nose height. pub y_position: u8, } /// Represents the details of the mouth #[derive(Copy, Clone, Debug)] pub struct MouthDetails { + /// Mouth style. pub style: u8, + /// Mouth color. pub color: u8, + /// Mouth scale. pub scale: u8, + /// Mouth scale (y-axis). pub y_scale: u8, + /// Mouth height. + pub y_position: u8, } /// Represents the details of the mustache #[derive(Copy, Clone, Debug)] pub struct MustacheDetails { - pub mouth_y_position: u8, + /// Mustache style. pub mustache_style: u8, } /// Represents the details of the beard #[derive(Copy, Clone, Debug)] pub struct BeardDetails { + /// Beard style pub style: u8, + /// Beard color. pub color: u8, + /// Beard scale. pub scale: u8, + /// Beard height. pub y_position: u8, } -/// Represents the details of the glass +/// Represents the details of the glasses #[derive(Copy, Clone, Debug)] -pub struct GlassDetails { +pub struct GlassesDetails { + /// Glasses style. pub style: u8, + /// Glasses color. pub color: u8, + /// Glasses scale. pub scale: u8, + /// Glasses height. pub y_position: u8, } -/// Represents the details of the mole +/// Represents the details of the mole. #[derive(Copy, Clone, Debug)] pub struct MoleDetails { + /// Whether the Mii has a mole. pub is_enabled: bool, + /// Mole scale. pub scale: u8, + /// Mole position (x-axis). pub x_position: u8, + /// Mole position (y-axis). pub y_position: u8, } @@ -177,34 +244,52 @@ pub struct MoleDetails { /// /// /// This struct is returned by the [`MiiSelector`](crate::applets::mii_selector::MiiSelector) -#[doc(alias = "MiiData")] #[derive(Clone, Debug)] pub struct MiiData { + /// Mii options. pub options: MiiDataOptions, + /// Position taken by the Mii on the Mii Selector screen. pub selector_position: SelectorPosition, + /// Console the Mii was created on. pub console_identity: ConsoleIdentity, /// Unique system ID, not dependant on the MAC address pub system_id: [u8; 8], + /// Console's MAC address. pub mac_address: [u8; 6], + /// General information about the Mii. pub details: Details, + /// Mii name. pub name: String, + /// Mii height. pub height: u8, + /// Mii width. pub width: u8, + /// Face details. pub face_details: FaceDetails, + /// Hair details. pub hair_details: HairDetails, + /// Eyes details. pub eye_details: EyeDetails, + /// Eyebrow details. pub eyebrow_details: EyebrowDetails, + /// Nose details. pub nose_details: NoseDetails, + /// Mouth details. pub mouth_details: MouthDetails, + /// Mustache details. pub mustache_details: MustacheDetails, + /// Beard details. pub beard_details: BeardDetails, - pub glass_details: GlassDetails, + /// Glasses details. + pub glass_details: GlassesDetails, + /// Mole details. pub mole_details: MoleDetails, + /// Name of the Mii's original author. pub author_name: String, } @@ -321,11 +406,11 @@ impl From for MiiData { birthday_day: partial_u8_bits_to_u8(&raw_details[5..=9]), shirt_color: partial_u8_bits_to_u8(&raw_details[10..=13]), is_favorite: raw_details[14], + is_sharing_enabled: !raw_face_style[0], }; let face_details = FaceDetails { style: FaceStyle { - is_sharing_enabled: !raw_face_style[0], shape: partial_u8_bits_to_u8(&raw_face_style[1..=4]), skin_color: partial_u8_bits_to_u8(&raw_face_style[5..=7]), }, @@ -372,10 +457,10 @@ impl From for MiiData { color: partial_u8_bits_to_u8(&raw_mouth_details[6..=8]), scale: partial_u8_bits_to_u8(&raw_mouth_details[9..=12]), y_scale: partial_u8_bits_to_u8(&raw_mouth_details[13..=15]), + y_position: partial_u8_bits_to_u8(&raw_mustache_details[0..=4]), }; let mustache_details = MustacheDetails { - mouth_y_position: partial_u8_bits_to_u8(&raw_mustache_details[0..=4]), mustache_style: partial_u8_bits_to_u8(&raw_mustache_details[5..=7]), }; @@ -386,7 +471,7 @@ impl From for MiiData { y_position: partial_u8_bits_to_u8(&raw_beard_details[10..=14]), }; - let glass_details = GlassDetails { + let glass_details = GlassesDetails { style: partial_u8_bits_to_u8(&raw_glass_details[0..=3]), color: partial_u8_bits_to_u8(&raw_glass_details[4..=6]), scale: partial_u8_bits_to_u8(&raw_glass_details[7..=10]), diff --git a/ctru-rs/src/services/am.rs b/ctru-rs/src/services/am.rs index 2af11520..9892bd76 100644 --- a/ctru-rs/src/services/am.rs +++ b/ctru-rs/src/services/am.rs @@ -62,9 +62,9 @@ impl<'a> Title<'a> { /// Returns the size of this title in bytes. pub fn size(&self) -> crate::Result { // Get the internal entry, or fill it if empty. - let entry = self.entry.get_or_try_init(|| -> crate::Result { - self.title_info() - })?; + let entry = self + .entry + .get_or_try_init(|| -> crate::Result { self.title_info() })?; Ok(entry.size) } @@ -72,9 +72,9 @@ impl<'a> Title<'a> { /// Returns the installed version of this title. pub fn version(&self) -> crate::Result { // Get the internal entry, or fill it if empty. - let entry = self.entry.get_or_try_init(|| -> crate::Result { - self.title_info() - })?; + let entry = self + .entry + .get_or_try_init(|| -> crate::Result { self.title_info() })?; Ok(entry.version) } diff --git a/ctru-rs/src/services/cam.rs b/ctru-rs/src/services/cam.rs index 0d18d896..de9ecb50 100644 --- a/ctru-rs/src/services/cam.rs +++ b/ctru-rs/src/services/cam.rs @@ -14,9 +14,13 @@ use std::time::Duration; /// This service requires no special permissions to use. #[non_exhaustive] pub struct Cam { + /// Inside-facing camera. pub inner_cam: InwardCam, + /// Outside-facing right camera. pub outer_right_cam: OutwardRightCam, + /// Outside-facing left camera. pub outer_left_cam: OutwardLeftCam, + /// Both outside-facing cameras (mainly used for 3D photos). pub both_outer_cams: BothOutwardCam, } @@ -25,9 +29,13 @@ pub struct Cam { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum FlipMode { + /// No flip applied. None = ctru_sys::FLIP_NONE, + /// Horizontal flip applied. Horizontal = ctru_sys::FLIP_HORIZONTAL, + /// Vertical flip applied. Vertical = ctru_sys::FLIP_VERTICAL, + /// Both vertical and horizontal flip applied. Reverse = ctru_sys::FLIP_REVERSE, } @@ -36,16 +44,25 @@ pub enum FlipMode { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum ViewSize { + /// Size of the 3DS' top screen. (400 × 240) + /// + /// Useful if the image is meant to be displayed immediately. TopLCD = ctru_sys::SIZE_CTR_TOP_LCD, - /// Equivalent to QVga + /// Size of the 3DS' bottom screen. (320 × 240) + /// + /// Equivalent to QVga. BottomLCD = ctru_sys::SIZE_CTR_BOTTOM_LCD, + /// VGA display size. (640 × 480) Vga = ctru_sys::SIZE_VGA, + /// QQVGA display size. (160 × 120) QQVga = ctru_sys::SIZE_QQVGA, + /// CIF display size. (352 × 288) Cif = ctru_sys::SIZE_CIF, + /// QCIF display size. (176 × 144) QCif = ctru_sys::SIZE_QCIF, - /// Nintendo DS Screen + /// Nintendo DS Screen size. (256 × 192) DS = ctru_sys::SIZE_DS_LCD, - /// Nintendo DS Screen x4 + /// Nintendo DS Screen size x4. (512 × 384) DSX4 = ctru_sys::SIZE_DS_LCDx4, } @@ -54,18 +71,31 @@ pub enum ViewSize { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum FrameRate { + /// 15 FPS. Fps15 = ctru_sys::FRAME_RATE_15, + /// 15 to 5 FPS. Fps15To5 = ctru_sys::FRAME_RATE_15_TO_5, + /// 15 to 2 FPS. Fps15To2 = ctru_sys::FRAME_RATE_15_TO_2, + /// 10 FPS. Fps10 = ctru_sys::FRAME_RATE_10, + /// 8.5 FPS. Fps8_5 = ctru_sys::FRAME_RATE_8_5, + /// 5 FPS. Fps5 = ctru_sys::FRAME_RATE_5, + /// 20 FPS. Fps20 = ctru_sys::FRAME_RATE_20, + /// 20 to 5 FPS. Fps20To5 = ctru_sys::FRAME_RATE_20_TO_5, + /// 30 FPS. Fps30 = ctru_sys::FRAME_RATE_30, + /// 30 to 5 FPS. Fps30To5 = ctru_sys::FRAME_RATE_30_TO_5, + /// 15 to 10 FPS. Fps15To10 = ctru_sys::FRAME_RATE_15_TO_10, + /// 20 to 10 FPS. Fps20To10 = ctru_sys::FRAME_RATE_20_TO_10, + /// 30 to 10 FPS. Fps30To10 = ctru_sys::FRAME_RATE_30_TO_10, } @@ -85,7 +115,7 @@ pub enum WhiteBalance { Temp5200K = ctru_sys::WHITE_BALANCE_5200K, /// Cloudy/Horizon Temp6000K = ctru_sys::WHITE_BALANCE_6000K, - ///Shade + /// Shade Temp7000K = ctru_sys::WHITE_BALANCE_7000K, } @@ -94,10 +124,15 @@ pub enum WhiteBalance { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum PhotoMode { + /// Normal mode. Normal = ctru_sys::PHOTO_MODE_NORMAL, + /// Portrait mode. Portrait = ctru_sys::PHOTO_MODE_PORTRAIT, + /// Landscape mode. Landscape = ctru_sys::PHOTO_MODE_LANDSCAPE, + /// NightView mode. NightView = ctru_sys::PHOTO_MODE_NIGHTVIEW, + /// Letter mode. Letter = ctru_sys::PHOTO_MODE_LETTER, } @@ -106,11 +141,17 @@ pub enum PhotoMode { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Effect { + /// No effects. None = ctru_sys::EFFECT_NONE, + /// Mono effect. Mono = ctru_sys::EFFECT_MONO, + /// Sepia effect. Sepia = ctru_sys::EFFECT_SEPIA, + /// Negative effect. Negative = ctru_sys::EFFECT_NEGATIVE, + /// Negative film effect. Negafilm = ctru_sys::EFFECT_NEGAFILM, + /// Sepia effect. (unknown difference) Sepia01 = ctru_sys::EFFECT_SEPIA01, } @@ -119,11 +160,11 @@ pub enum Effect { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Contrast { - /// OFF + /// Low contrast. Low = ctru_sys::CONTRAST_LOW, - /// Brightness ratio: 70 + /// Brightness ratio: 70. Normal = ctru_sys::CONTRAST_NORMAL, - /// Brightness ratio: 90 + /// Brightness ratio: 90. High = ctru_sys::CONTRAST_HIGH, } @@ -132,8 +173,11 @@ pub enum Contrast { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum LensCorrection { + /// No lens correction. Off = ctru_sys::LENS_CORRECTION_DARK, + /// Normal lens correction. Normal = ctru_sys::LENS_CORRECTION_NORMAL, + /// Bright lens correction. Bright = ctru_sys::LENS_CORRECTION_BRIGHT, } @@ -142,7 +186,9 @@ pub enum LensCorrection { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum OutputFormat { + /// YUV422 output format. 16 bits per pixel. Yuv422 = ctru_sys::OUTPUT_YUV_422, + /// RGB565 output format. 16 bits per pixel. Rgb565 = ctru_sys::OUTPUT_RGB_565, } @@ -151,8 +197,11 @@ pub enum OutputFormat { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum ShutterSound { + /// Normal shutter sound. Normal = ctru_sys::SHUTTER_SOUND_TYPE_NORMAL, + /// Shutter sound to begin a movie recording. Movie = ctru_sys::SHUTTER_SOUND_TYPE_MOVIE, + /// Shutter sound to finish a movie recording. MovieEnd = ctru_sys::SHUTTER_SOUND_TYPE_MOVIE_END, } diff --git a/ctru-rs/src/services/cfgu.rs b/ctru-rs/src/services/cfgu.rs index 661fdf9d..99ef505f 100644 --- a/ctru-rs/src/services/cfgu.rs +++ b/ctru-rs/src/services/cfgu.rs @@ -4,46 +4,74 @@ use crate::error::ResultCode; +/// Console's region. #[doc(alias = "CFG_Region")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Region { + /// Japan. Japan = ctru_sys::CFG_REGION_JPN, + /// USA. USA = ctru_sys::CFG_REGION_USA, + /// Europe. Europe = ctru_sys::CFG_REGION_EUR, + /// Australia. Australia = ctru_sys::CFG_REGION_AUS, + /// China. China = ctru_sys::CFG_REGION_CHN, + /// Korea. Korea = ctru_sys::CFG_REGION_KOR, + /// Taiwan. Taiwan = ctru_sys::CFG_REGION_TWN, } +/// Language set for the console's OS. #[doc(alias = "CFG_Language")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Language { + /// Japanese. Japanese = ctru_sys::CFG_LANGUAGE_JP, + /// English. English = ctru_sys::CFG_LANGUAGE_EN, + /// French. French = ctru_sys::CFG_LANGUAGE_FR, + /// German. German = ctru_sys::CFG_LANGUAGE_DE, + /// Italian. Italian = ctru_sys::CFG_LANGUAGE_IT, + /// Spanish. Spanish = ctru_sys::CFG_LANGUAGE_ES, - SimplifiedChinese = ctru_sys::CFG_LANGUAGE_ZH, + /// Korean. Korean = ctru_sys::CFG_LANGUAGE_KO, + /// Dutch. Dutch = ctru_sys::CFG_LANGUAGE_NL, + /// Portuguese. Portuguese = ctru_sys::CFG_LANGUAGE_PT, + /// Russian. Russian = ctru_sys::CFG_LANGUAGE_RU, + /// Simplified Chinese. + SimplifiedChinese = ctru_sys::CFG_LANGUAGE_ZH, + /// Traditional Chinese. TraditionalChinese = ctru_sys::CFG_LANGUAGE_TW, } +/// 3DS model. #[doc(alias = "CFG_SystemModel")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum SystemModel { + /// Old Nintendo 3DS. Old3DS = ctru_sys::CFG_MODEL_3DS, + /// Old Nintendo 3DS XL. Old3DSXL = ctru_sys::CFG_MODEL_3DSXL, + /// New Nintendo 3DS. New3DS = ctru_sys::CFG_MODEL_N3DS, + /// Old Nintendo 2DS. Old2DS = ctru_sys::CFG_MODEL_2DS, + /// New Nintendo 3DS XL. New3DSXL = ctru_sys::CFG_MODEL_N3DSXL, + /// New Nintendo 2DS XL. New2DSXL = ctru_sys::CFG_MODEL_N2DSXL, } diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index b498ee92..9b56ddde 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -39,51 +39,86 @@ bitflags! { } } +/// Media type used for storage. #[doc(alias = "FS_MediaType")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum FsMediaType { + /// Internal NAND memory. Nand = ctru_sys::MEDIATYPE_NAND, + /// External SD card. Sd = ctru_sys::MEDIATYPE_SD, + /// Game Cartridge. GameCard = ctru_sys::MEDIATYPE_GAME_CARD, } +/// Kind of file path. #[doc(alias = "FS_PathType")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum PathType { + /// Invalid path. Invalid = ctru_sys::PATH_INVALID, + /// Empty path. Empty = ctru_sys::PATH_EMPTY, + /// Binary path. + /// + /// Its meaning differs depending on the Archive it is used on. Binary = ctru_sys::PATH_BINARY, + /// ASCII path. ASCII = ctru_sys::PATH_ASCII, + /// UTF-16 path. UTF16 = ctru_sys::PATH_UTF16, } +/// Index of the various usable data archives. #[doc(alias = "FS_ArchiveID")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum ArchiveID { + /// Read-Only Memory File System. RomFS = ctru_sys::ARCHIVE_ROMFS, + /// Game save data. Savedata = ctru_sys::ARCHIVE_SAVEDATA, + /// Game ext data. Extdata = ctru_sys::ARCHIVE_EXTDATA, + /// Shared ext data. SharedExtdata = ctru_sys::ARCHIVE_SHARED_EXTDATA, + /// System save data. SystemSavedata = ctru_sys::ARCHIVE_SYSTEM_SAVEDATA, + /// SD card. Sdmc = ctru_sys::ARCHIVE_SDMC, + /// SD card (write-only). SdmcWriteOnly = ctru_sys::ARCHIVE_SDMC_WRITE_ONLY, + /// BOSS ext data. BossExtdata = ctru_sys::ARCHIVE_BOSS_EXTDATA, + /// Card SPI File System. CardSpiFS = ctru_sys::ARCHIVE_CARD_SPIFS, + /// Game ext data and BOSS data. ExtDataAndBossExtdata = ctru_sys::ARCHIVE_EXTDATA_AND_BOSS_EXTDATA, + /// System save data. SystemSaveData2 = ctru_sys::ARCHIVE_SYSTEM_SAVEDATA2, + /// Internal NAND (read-write). NandRW = ctru_sys::ARCHIVE_NAND_RW, + /// Internal NAND (read-only). NandRO = ctru_sys::ARCHIVE_NAND_RO, + /// Internal NAND (read-only write access). NandROWriteAccess = ctru_sys::ARCHIVE_NAND_RO_WRITE_ACCESS, + /// User save data and ExeFS/RomFS. SaveDataAndContent = ctru_sys::ARCHIVE_SAVEDATA_AND_CONTENT, + /// User save data and ExeFS/RomFS (only ExeFS for fs:LDR). SaveDataAndContent2 = ctru_sys::ARCHIVE_SAVEDATA_AND_CONTENT2, + /// NAND CTR File System. NandCtrFS = ctru_sys::ARCHIVE_NAND_CTR_FS, + /// TWL photo. TwlPhoto = ctru_sys::ARCHIVE_TWL_PHOTO, + /// NAND TWL File System. NandTwlFS = ctru_sys::ARCHIVE_NAND_TWL_FS, + /// Game card save data. GameCardSavedata = ctru_sys::ARCHIVE_GAMECARD_SAVEDATA, + /// User save data. UserSavedata = ctru_sys::ARCHIVE_USER_SAVEDATA, + /// Demo save data. DemoSavedata = ctru_sys::ARCHIVE_DEMO_SAVEDATA, } diff --git a/ctru-rs/src/services/gspgpu.rs b/ctru-rs/src/services/gspgpu.rs index 1510b296..cb3e67c5 100644 --- a/ctru-rs/src/services/gspgpu.rs +++ b/ctru-rs/src/services/gspgpu.rs @@ -1,20 +1,28 @@ //! GSPGPU service +/// GSPGPU events that can be awaited. #[doc(alias = "GSPGPU_Event")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum Event { + /// Memory fill completed. Psc0 = ctru_sys::GSPGPU_EVENT_PSC0, + /// TODO: Unknown. Psc1 = ctru_sys::GSPGPU_EVENT_PSC1, + /// TODO: Unknown. VBlank0 = ctru_sys::GSPGPU_EVENT_VBlank0, + /// TODO: Unknown. VBlank1 = ctru_sys::GSPGPU_EVENT_VBlank1, + /// Display transfer finished. PPF = ctru_sys::GSPGPU_EVENT_PPF, + /// Command list processing finished. P3D = ctru_sys::GSPGPU_EVENT_P3D, + /// TODO: Unknown. DMA = ctru_sys::GSPGPU_EVENT_DMA, } #[doc(alias = "GSPGPU_FramebufferFormat")] -/// Framebuffer formats supported by the 3DS +/// Framebuffer formats supported by the 3DS. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum FramebufferFormat { diff --git a/ctru-rs/src/services/hid.rs b/ctru-rs/src/services/hid.rs index 8de66a18..51bf63ae 100644 --- a/ctru-rs/src/services/hid.rs +++ b/ctru-rs/src/services/hid.rs @@ -9,33 +9,62 @@ bitflags::bitflags! { /// A set of flags corresponding to the button and directional pad /// inputs on the 3DS pub struct KeyPad: u32 { + /// A button. const A = ctru_sys::KEY_A; + /// B button. const B = ctru_sys::KEY_B; + /// Select button. const SELECT = ctru_sys::KEY_SELECT; + /// Start button. const START = ctru_sys::KEY_START; + /// D-Pad Right. const DPAD_RIGHT = ctru_sys::KEY_DRIGHT; + /// D-Pad Left. const DPAD_LEFT = ctru_sys::KEY_DLEFT; + /// D-Pad Up. const DPAD_UP = ctru_sys::KEY_DUP; + /// D-Pad Down. const DPAD_DOWN = ctru_sys::KEY_DDOWN; + /// R button. const R = ctru_sys::KEY_R; + /// L button. const L = ctru_sys::KEY_L; + /// X button. const X = ctru_sys::KEY_X; + /// Y button. const Y = ctru_sys::KEY_Y; + /// ZL button. const ZL = ctru_sys::KEY_ZL; + /// ZR button. const ZR = ctru_sys::KEY_ZR; + /// Touchscreen. const TOUCH = ctru_sys::KEY_TOUCH; + /// C-Stick Right. const CSTICK_RIGHT = ctru_sys::KEY_CSTICK_RIGHT; + /// C-Stick Left. const CSTICK_LEFT = ctru_sys::KEY_CSTICK_LEFT; + /// C-Stick Up. const CSTICK_UP = ctru_sys::KEY_CSTICK_UP; + /// C-Stick Down. const CSTICK_DOWN = ctru_sys::KEY_CSTICK_DOWN; + /// CirclePad Right. const CPAD_RIGHT = ctru_sys::KEY_CPAD_RIGHT; + /// CirclePad Left. const CPAD_LEFT = ctru_sys::KEY_CPAD_LEFT; + /// CirclePad Up. const CPAD_UP = ctru_sys::KEY_CPAD_UP; + /// CirclePad Down. const CPAD_DOWN = ctru_sys::KEY_CPAD_DOWN; - // Convenience catch-all for the dpad and cpad + + // Convenience catch-all for the D-Pad and the C-Pad + + /// Direction Up (either D-Pad or C-Pad). const UP = KeyPad::DPAD_UP.bits() | KeyPad::CPAD_UP.bits(); + /// Direction Down (either D-Pad or C-Pad). const DOWN = KeyPad::DPAD_DOWN.bits() | KeyPad::CPAD_DOWN.bits(); + /// Direction Left (either D-Pad or C-Pad). const LEFT = KeyPad::DPAD_LEFT.bits() | KeyPad::CPAD_LEFT.bits(); + /// Direction Right (either D-Pad or C-Pad).. const RIGHT = KeyPad::DPAD_RIGHT.bits() | KeyPad::CPAD_RIGHT.bits(); } } diff --git a/ctru-rs/src/services/ndsp/mod.rs b/ctru-rs/src/services/ndsp/mod.rs index 7867048a..2ff9d7b5 100644 --- a/ctru-rs/src/services/ndsp/mod.rs +++ b/ctru-rs/src/services/ndsp/mod.rs @@ -14,21 +14,30 @@ use std::sync::Mutex; const NUMBER_OF_CHANNELS: u8 = 24; +/// Audio output mode. #[doc(alias = "ndspOutputMode")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum OutputMode { + /// Single-Channel. Mono = ctru_sys::NDSP_OUTPUT_MONO, + /// Dual-Channel. Stereo = ctru_sys::NDSP_OUTPUT_STEREO, + /// Surround. Surround = ctru_sys::NDSP_OUTPUT_SURROUND, } +/// Audio PCM format. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum AudioFormat { + /// PCM 8bit single-channel. PCM8Mono = ctru_sys::NDSP_FORMAT_MONO_PCM8, + /// PCM 16bit single-channel. PCM16Mono = ctru_sys::NDSP_FORMAT_MONO_PCM16, + /// PCM 8bit dual-channel. PCM8Stereo = ctru_sys::NDSP_FORMAT_STEREO_PCM8, + /// PCM 16bit dual-channel. PCM16Stereo = ctru_sys::NDSP_FORMAT_STEREO_PCM16, } @@ -38,15 +47,20 @@ pub struct AudioMix { raw: [f32; 12], } +/// Interpolation used between audio frames. #[doc(alias = "ndspInterpType")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum InterpolationType { + /// Polyphase interpolation. Polyphase = ctru_sys::NDSP_INTERP_POLYPHASE, + /// Linear interpolation. Linear = ctru_sys::NDSP_INTERP_LINEAR, + /// No interpolation. None = ctru_sys::NDSP_INTERP_NONE, } +/// Error enum returned by NDSP methods. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum NdspError { /// Channel ID diff --git a/ctru-rs/src/services/ndsp/wave.rs b/ctru-rs/src/services/ndsp/wave.rs index 6cc58478..91946855 100644 --- a/ctru-rs/src/services/ndsp/wave.rs +++ b/ctru-rs/src/services/ndsp/wave.rs @@ -15,9 +15,13 @@ pub struct Wave { #[repr(u8)] /// Enum representing the playback status of a [`Wave`]. pub enum WaveStatus { + /// Wave has never been used. Free = ctru_sys::NDSP_WBUF_FREE as u8, + /// Wave is currently queued for usage. Queued = ctru_sys::NDSP_WBUF_QUEUED as u8, + /// Wave is currently playing. Playing = ctru_sys::NDSP_WBUF_PLAYING as u8, + /// Wave has finished playing. Done = ctru_sys::NDSP_WBUF_DONE as u8, } diff --git a/ctru-rs/src/services/ps.rs b/ctru-rs/src/services/ps.rs index ee962165..0673ce82 100644 --- a/ctru-rs/src/services/ps.rs +++ b/ctru-rs/src/services/ps.rs @@ -6,31 +6,49 @@ use crate::error::ResultCode; use crate::Result; +/// Kind of AES algorithm to use. #[doc(alias = "PS_AESAlgorithm")] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum AESAlgorithm { + /// CBC encryption. CbcEnc = ctru_sys::PS_ALGORITHM_CBC_ENC, + /// CBC decryption. CbcDec = ctru_sys::PS_ALGORITHM_CBC_DEC, + /// CTR encryption. CtrEnc = ctru_sys::PS_ALGORITHM_CTR_ENC, + /// CTR decryption. CtrDec = ctru_sys::PS_ALGORITHM_CTR_DEC, + /// CCM encryption. CcmEnc = ctru_sys::PS_ALGORITHM_CCM_ENC, + /// CCM decryption. CcmDec = ctru_sys::PS_ALGORITHM_CCM_DEC, } +/// PS Key slot to use. #[doc(alias = "PS_AESKeyType")] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum AESKeyType { + /// Keyslot 0x0D. Keyslot0D = ctru_sys::PS_KEYSLOT_0D, + /// Keyslot 0x2D. Keyslot2D = ctru_sys::PS_KEYSLOT_2D, + /// Keyslot 0x2E. Keyslot2E = ctru_sys::PS_KEYSLOT_2E, + /// Keyslot 0x31. Keyslot31 = ctru_sys::PS_KEYSLOT_31, + /// Keyslot 0x32. Keyslot32 = ctru_sys::PS_KEYSLOT_32, + /// Keyslot 0x36. Keyslot36 = ctru_sys::PS_KEYSLOT_36, + /// Keyslot 0x38. Keyslot38 = ctru_sys::PS_KEYSLOT_38, + /// Keyslot 0x39 (DLP). Keyslot39Dlp = ctru_sys::PS_KEYSLOT_39_DLP, + /// Keyslot 0x39 (NFC). Keyslot39Nfc = ctru_sys::PS_KEYSLOT_39_NFC, + /// Invalid keyslot. KeyslotInvalid = ctru_sys::PS_KEYSLOT_INVALID, } diff --git a/ctru-rs/src/services/sslc.rs b/ctru-rs/src/services/sslc.rs index d248f0ec..9b311e3d 100644 --- a/ctru-rs/src/services/sslc.rs +++ b/ctru-rs/src/services/sslc.rs @@ -4,6 +4,7 @@ use crate::error::ResultCode; +/// Handle to the SSLC service. pub struct SslC(()); impl SslC { From 4124df8612b8abcdb7ac481b0ace37ef541e644e Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sun, 9 Jul 2023 19:53:15 +0200 Subject: [PATCH 08/39] Fixed all compiler warnings for docs --- ctru-rs/src/applets/mii_selector.rs | 5 +++-- ctru-rs/src/applets/mod.rs | 5 +++++ ctru-rs/src/applets/swkbd.rs | 4 ++++ ctru-rs/src/console.rs | 16 ++++++++++++++++ ctru-rs/src/prelude.rs | 4 ++++ ctru-rs/src/services/gfx.rs | 2 ++ ctru-rs/src/services/hid.rs | 14 +++++++------- ctru-rs/src/services/ndsp/mod.rs | 19 ++++++++++++++++--- ctru-rs/src/services/ndsp/wave.rs | 2 ++ ctru-rs/src/services/ps.rs | 5 +++++ ctru-rs/src/services/romfs.rs | 7 +++++++ 11 files changed, 71 insertions(+), 12 deletions(-) diff --git a/ctru-rs/src/applets/mii_selector.rs b/ctru-rs/src/applets/mii_selector.rs index 577d0dfe..7cd0f816 100644 --- a/ctru-rs/src/applets/mii_selector.rs +++ b/ctru-rs/src/applets/mii_selector.rs @@ -1,6 +1,7 @@ -//! Mii Selector applet +//! Mii Selector applet. //! -//! This module contains the methods to launch the Mii Selector. +//! This applet opens a window on the console's bottom screen which lets the player/user choose a Mii from the ones present on their console. +//! The application can access the selected Mii's data via the use of the [`mii`](crate::mii) module. use crate::mii::MiiData; use bitflags::bitflags; diff --git a/ctru-rs/src/applets/mod.rs b/ctru-rs/src/applets/mod.rs index f5813ad4..57c9471e 100644 --- a/ctru-rs/src/applets/mod.rs +++ b/ctru-rs/src/applets/mod.rs @@ -1,2 +1,7 @@ +//! System Applets. +//! +//! Applets are small integrated programs that the OS makes available to the developer to streamline commonly needed functionality. +//! Thanks to these integrations the developer can avoid wasting time re-implementing common features and instead use a more reliable base for their application. + pub mod mii_selector; pub mod swkbd; diff --git a/ctru-rs/src/applets/swkbd.rs b/ctru-rs/src/applets/swkbd.rs index e5e9c285..d0f0fdf8 100644 --- a/ctru-rs/src/applets/swkbd.rs +++ b/ctru-rs/src/applets/swkbd.rs @@ -1,3 +1,7 @@ +//! Software Keyboard applet. +//! +//! This applet opens a virtual keyboard on the console's bottom screen which lets the player/user write UTF-16 valid text. + use bitflags::bitflags; use ctru_sys::{ self, swkbdInit, swkbdInputText, swkbdSetButton, swkbdSetFeatures, swkbdSetHintText, SwkbdState, diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index cd6b51f7..74b861ef 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -1,3 +1,5 @@ +//! Virtual text console. + use std::cell::RefMut; use std::default::Default; @@ -7,6 +9,20 @@ use crate::services::gfx::Screen; static mut EMPTY_CONSOLE: PrintConsole = unsafe { const_zero::const_zero!(PrintConsole) }; +/// Virtual printable console. +/// +/// [`Console`] lets the application redirect `stdout` to a simple text displayer on the 3DS screen. +/// This means that any text written to `stdout` (e.g. using [`println!`] or [`dbg!`]) will become visible in the area taken by the console. +/// +/// # Notes +/// +/// The console will take full possession of the screen handed to it as long as it stays alive. It also supports ANSI codes. +/// +/// # Alternatives +/// +/// If you'd like to see live `stdout` output while running the application but can't/don't want to show the text on the 3DS itself, +/// you can try using [`Soc::redirect_to_3dslink`](crate::services::soc::Soc::redirect_to_3dslink) while activating the `--server` flag for `3dslink` (also supported by `cargo-3ds`). +/// More info in the `cargo-3ds` docs. #[doc(alias = "PrintConsole")] pub struct Console<'screen> { context: Box, diff --git a/ctru-rs/src/prelude.rs b/ctru-rs/src/prelude.rs index 49095fa5..b765b658 100644 --- a/ctru-rs/src/prelude.rs +++ b/ctru-rs/src/prelude.rs @@ -1,3 +1,7 @@ +//! `use ctru::prelude::*;` to import common services, members and functions. +//! +//! Particularly useful when writing very small applications. + pub use crate::console::Console; pub use crate::services::{ apt::Apt, diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index 5629cf67..54ec061c 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -209,7 +209,9 @@ pub enum Side { /// /// The service exits when this struct is dropped. pub struct Gfx { + /// Top screen representation. pub top_screen: RefCell, + /// Bottom screen representation. pub bottom_screen: RefCell, _service_handler: ServiceReference, } diff --git a/ctru-rs/src/services/hid.rs b/ctru-rs/src/services/hid.rs index 51bf63ae..cb2550fe 100644 --- a/ctru-rs/src/services/hid.rs +++ b/ctru-rs/src/services/hid.rs @@ -75,14 +75,14 @@ bitflags::bitflags! { /// This service requires no special permissions to use. pub struct Hid(()); -/// Initializes the HID service. -/// -/// # Errors -/// -/// This function will return an error if the service was unable to be initialized. -/// Since this service requires no special or elevated permissions, errors are -/// rare in practice. impl Hid { + /// Initializes the HID service. + /// + /// # Errors + /// + /// This function will return an error if the service was unable to be initialized. + /// Since this service requires no special or elevated permissions, errors are + /// rare in practice. #[doc(alias = "hidInit")] pub fn new() -> crate::Result { unsafe { diff --git a/ctru-rs/src/services/ndsp/mod.rs b/ctru-rs/src/services/ndsp/mod.rs index 2ff9d7b5..e8325510 100644 --- a/ctru-rs/src/services/ndsp/mod.rs +++ b/ctru-rs/src/services/ndsp/mod.rs @@ -1,4 +1,4 @@ -//! NDSP (Audio) service +//! NDSP (Audio) service. pub mod wave; use wave::{Wave, WaveStatus}; @@ -73,6 +73,19 @@ pub enum NdspError { SampleCountOutOfBounds(usize, usize), } +/// NDSP Channel representation. +/// +/// There are 24 individual channels in total and each can play a different audio [`Wave`] simultaneuosly. +/// +/// # Default +/// +/// NDSP initialises all channels with default values on creation, but the developer is supposed to change these values to correctly work with the service. +/// +/// In particular: +/// - Default audio format is set to [`AudioFormat::PCM16Mono`]. +/// - Default sample rate is set to 1 Hz. +/// - Default interpolation type is set to [`InterpolationType::Polyphase`]. +/// - Default mix is set to [`AudioMix::default()`] pub struct Channel<'ndsp> { id: u8, _rf: RefMut<'ndsp, ()>, // we don't need to hold any data @@ -169,7 +182,7 @@ impl Channel<'_> { unsafe { ctru_sys::ndspChnIsPaused(self.id.into()) } } - // Returns the channel's id + /// Returns the channel's index. pub fn id(&self) -> u8 { self.id } @@ -458,8 +471,8 @@ impl AudioMix { } } -/// Returns an [`AudioMix`] object with "front left" and "front right" volumes set to 100%, and all other volumes set to 0%. impl Default for AudioMix { + /// Returns an [`AudioMix`] object with "front left" and "front right" volumes set to 100%, and all other volumes set to 0%. fn default() -> Self { let mut mix = AudioMix::zeroed(); mix.set_front(1.0, 1.0); diff --git a/ctru-rs/src/services/ndsp/wave.rs b/ctru-rs/src/services/ndsp/wave.rs index 91946855..2819dbdd 100644 --- a/ctru-rs/src/services/ndsp/wave.rs +++ b/ctru-rs/src/services/ndsp/wave.rs @@ -1,3 +1,5 @@ +//! Audio wave representation. + use super::{AudioFormat, NdspError}; use crate::linear::LinearAllocator; diff --git a/ctru-rs/src/services/ps.rs b/ctru-rs/src/services/ps.rs index 0673ce82..6f8c67c9 100644 --- a/ctru-rs/src/services/ps.rs +++ b/ctru-rs/src/services/ps.rs @@ -52,9 +52,11 @@ pub enum AESKeyType { KeyslotInvalid = ctru_sys::PS_KEYSLOT_INVALID, } +/// Handle to the PS service. pub struct Ps(()); impl Ps { + /// Initialize a new service handle. #[doc(alias = "psInit")] pub fn new() -> Result { unsafe { @@ -63,6 +65,7 @@ impl Ps { } } + /// Returns the console's local friend code seed. #[doc(alias = "PS_GetLocalFriendCodeSeed")] pub fn local_friend_code_seed(&self) -> crate::Result { let mut seed: u64 = 0; @@ -71,6 +74,7 @@ impl Ps { Ok(seed) } + /// Returns the console's devide ID. #[doc(alias = "PS_GetDeviceId")] pub fn device_id(&self) -> crate::Result { let mut id: u32 = 0; @@ -79,6 +83,7 @@ impl Ps { Ok(id) } + /// Generates cryptografically secure random bytes and writes them into the `out` buffer. #[doc(alias = "PS_GenerateRandomBytes")] pub fn generate_random_bytes(&self, out: &mut [u8]) -> crate::Result<()> { ResultCode(unsafe { diff --git a/ctru-rs/src/services/romfs.rs b/ctru-rs/src/services/romfs.rs index 3c5afa89..dae4ed3f 100644 --- a/ctru-rs/src/services/romfs.rs +++ b/ctru-rs/src/services/romfs.rs @@ -18,6 +18,12 @@ use std::sync::Mutex; use crate::services::ServiceReference; +/// Handle to the RomFS service. +/// +/// This service lets the application access a virtual mounted device created using a folder included within the application bundle. +/// `ctru` will include as RomFS the folder specified in the `Cargo.toml` manifest (or use `./romfs` by default). Look at the [`romfs`](self) module for more information. +/// +/// After mounting the RomFS file system, the included files and folders will be accessible exactly like any other file, just by using the drive prefix `romfs:/`. pub struct RomFS { _service_handler: ServiceReference, } @@ -25,6 +31,7 @@ pub struct RomFS { static ROMFS_ACTIVE: Mutex = Mutex::new(0); impl RomFS { + /// Mounts the specified RomFS folder as a virtual drive. #[doc(alias = "romfsMountSelf")] pub fn new() -> crate::Result { let _service_handler = ServiceReference::new( From 73d3f4064a7a36ebee322af323f05f9fb6050cec Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sun, 16 Jul 2023 17:19:21 +0200 Subject: [PATCH 09/39] Publish-ready Cargo manifests --- ctru-rs/Cargo.toml | 7 ++++--- ctru-sys/Cargo.toml | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ctru-rs/Cargo.toml b/ctru-rs/Cargo.toml index 69f88f41..16f4a3dd 100644 --- a/ctru-rs/Cargo.toml +++ b/ctru-rs/Cargo.toml @@ -1,13 +1,14 @@ [package] +name = "ctru-rs" +version = "0.7.1" authors = ["Rust3DS Org", "Ronald Kinard "] description = "A safe wrapper around libctru" +repository = "https://github.com/rust3ds/ctru-rs" keywords = ["3ds", "libctru"] categories = ["os", "api-bindings"] +exclude = ["examples"] license = "Zlib" -name = "ctru-rs" -version = "0.7.1" edition = "2021" -repository = "https://github.com/rust3ds/ctru-rs" rust-version = "1.70" [lib] diff --git a/ctru-sys/Cargo.toml b/ctru-sys/Cargo.toml index 03435b67..1420ebe6 100644 --- a/ctru-sys/Cargo.toml +++ b/ctru-sys/Cargo.toml @@ -3,12 +3,13 @@ name = "ctru-sys" version = "22.2.0+2.2.2-1" authors = [ "Rust3DS Org", "Ronald Kinard " ] description = "Raw bindings to libctru" +repository = "https://github.com/rust3ds/ctru-rs" keywords = ["3ds", "libctru"] categories = ["os", "external-ffi-bindings", "no-std"] +exclude = ["bindgen.sh", "src/.gitattributes"] license = "Zlib" links = "ctru" edition = "2021" -repository = "https://github.com/rust3ds/ctru-rs" [dependencies] libc = { version = "0.2.121", default-features = false } From 4a1c695dbe8f428a99db08978a4e7339b49133e0 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sun, 16 Jul 2023 17:42:48 +0200 Subject: [PATCH 10/39] Fixed only doc lint --- ctru-rs/src/services/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index 9b56ddde..f008954b 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -285,8 +285,8 @@ pub struct OpenOptions { /// Iterator over the entries in a directory. /// -/// This iterator is returned from the [`File::read_dir`] function of this module and -/// will yield instances of `Result`. Through a [`DirEntry`] +/// This iterator is returned from the [`read_dir`] function and +/// will yield instances of [`Result`]. Through a [`DirEntry`] /// information like the entry's path and possibly other metadata can be /// learned. /// From 10f70aa02687d6039cab95c5fb93e066614c5c7c Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Wed, 19 Jul 2023 10:27:11 +0200 Subject: [PATCH 11/39] New READMEs and fixed package labeling --- README.md | 32 +++++++++++++------------------- ctru-rs/README.md | 23 +++++++++++++++++++++++ ctru-rs/src/lib.rs | 9 +++++---- ctru-rs/src/services/am.rs | 2 +- ctru-rs/src/services/mod.rs | 4 ++-- ctru-rs/src/services/romfs.rs | 2 +- ctru-sys/README.md | 33 +++++++++++++++++++++++++++++++++ 7 files changed, 78 insertions(+), 27 deletions(-) create mode 100644 ctru-rs/README.md create mode 100644 ctru-sys/README.md diff --git a/README.md b/README.md index ae3e6c7b..8a061b47 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,27 @@ # ctru-rs -A Rust wrapper around [libctru](https://github.com/devkitPro/libctru). +This repository is home of the `ctru-rs` project, which aims to bring full control of the Nintendo 3DS console to homebrew developers using Rust. ## Structure This repository is organized as follows: -* `ctru-rs`: Safe, idiomatic wrapper around `ctru-sys` + * [`ctru-rs`](./ctru-rs/) - Safe, idiomatic wrapper around [`ctru-sys`](./ctru-sys/). + * [`ctru-sys`](./ctru-sys/) - Low-level, unsafe bindings to [`libctru`](https://github.com/devkitPro/libctru). -* `ctru-sys`: Low-level, unsafe bindings to `libctru`. +## Getting Started - This crate's version changes according to the version of `libctru` - used to generate the bindings, with the following convention: - - * `libctru` version `X.Y.Z-W` - * `ctru-sys` version `XY.Z.P+X.Y.Z-W` - - where `P` is usually 0 but may be incremented for fixes in e.g. - binding generation, `libc` dependency bump, etc. - - It may be possible to build this crate against a different version of `libctru`, - but you may encounter linker errors or ABI issues. A build-time Cargo warning - (displayed when built with `-vv`) will be issued if the build script detects - a mismatch or is unable to check the installed `libctru` version. +Specific information about how to use the crates is present in the individual README for each package. +Have a look at `ctru-rs`' [README.md](./ctru-rs/README.md) for a broad overview. ## Original version -This project is based on the efforts the original authors: - * [Eidolon](https://github.com/HybridEidolon) - * [FenrirWolf](https://github.com/FenrirWolf) +This project is based on the efforts of the original authors: + * [Eidolon](https://github.com/HybridEidolon) + * [FenrirWolf](https://github.com/FenrirWolf) The old version is archived [here](https://github.com/rust3ds/ctru-rs-old). + +## License + +This project is distributed under the Zlib license. diff --git a/ctru-rs/README.md b/ctru-rs/README.md new file mode 100644 index 00000000..297c8cce --- /dev/null +++ b/ctru-rs/README.md @@ -0,0 +1,23 @@ +# ctru-rs + +Safe and idiomatic Rust wrapper around [`libctru`](https://github.com/devkitPro/libctru). +This crate uses the bindings provided by [`ctru-sys`](../ctru-sys/). + +## Getting Started + +Thoroughly read the [`ctru-rs` wiki](https://github.com/rust3ds/ctru-rs/wiki/Getting-Started) to meet the requirements +and to understand what it takes to develop homebrew software on the Nintendo 3DS family of consoles. +After that, you can simply add the crate as a dependency to your project and build your final binary by using [`cargo-3ds`](https://github.com/rust3ds/cargo-3ds) +or by manually compiling for the `armv6k-nintendo-3ds` target. + +## Examples + +Many examples to demonstrate the `ctru-rs` functionality are available in the [`examples`](./examples/) folder. Simply run them via + +```bash +cargo 3ds run --example +``` + +## License + +This project is distributed under the Zlib license. diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index 37428f82..7e29748a 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -1,4 +1,4 @@ -//! Safe wrapper around `libctru`. +//! Safe and idiomatic Rust wrapper around [`libctru`](https://github.com/devkitPro/libctru). //! //! # About //! @@ -6,11 +6,12 @@ //! Thanks to it, developers can access the underlying system services and the console's hardware to develop userland applications //! (such as HID devices, network capabilities, graphics, built-in cameras, etc.). //! -//! Among these features, `ctru` also automatically includes functionality to properly integrate the Rust `std` with the console, which the developer would otherwise need to implement manually. +//! Among these features, `ctru-rs` also automatically includes functionality to properly integrate the Rust `std` with the console's operating system, +//! which the developer would otherwise need to implement manually. //! //! # Usage //! -//! Read thoroughly the official [`ctru` wiki](https://github.com/rust3ds/ctru-rs/wiki) which guides you through the setup needed to install the required toolchain and helpful tools. +//! Read thoroughly the official [`ctru-rs` wiki](https://github.com/rust3ds/ctru-rs/wiki) which guides you through the setup needed to install the required toolchain and helpful tools. //! After following the guide and understanding the many quirks of the Nintendo 3DS homebrew development environment, you can create a new project by including this crate as a dependency //! of your project in your `Cargo.toml` manifest and build your binaries either manually (for the `armv6k-nintendo-3ds` target) or via [`cargo-3ds`](https://github.com/rust3ds/cargo-3ds). //! @@ -57,7 +58,7 @@ macro_rules! from_impl { }; } -/// Activate the custom `ctru` panic handler. +/// Activate the custom `ctru-rs` panic handler. /// /// With this implementation, the main thread will stop and try to print debug info to an available [`Console`](console::Console). /// In case it fails to find an active [`Console`](console::Console) the program will just exit. diff --git a/ctru-rs/src/services/am.rs b/ctru-rs/src/services/am.rs index 9892bd76..31d46b54 100644 --- a/ctru-rs/src/services/am.rs +++ b/ctru-rs/src/services/am.rs @@ -4,7 +4,7 @@ //! - Read the installed applications on the console and their information (depending on the install location). //! - Install compatible applications to the console. //! -//! `ctru` doesn't support installing titles (yet). +//! `ctru-rs` doesn't support installing titles (yet). use crate::error::ResultCode; use crate::services::fs::FsMediaType; diff --git a/ctru-rs/src/services/mod.rs b/ctru-rs/src/services/mod.rs index a3879333..ab948b33 100644 --- a/ctru-rs/src/services/mod.rs +++ b/ctru-rs/src/services/mod.rs @@ -3,13 +3,13 @@ //! Most of the 3DS console's functionalities (when writing user-land homebrew) are accessible via services, //! which need to be initialized before accessing any particular feature. //! -//! To ensure safety measures when using the underlying services, `ctru` leverages Rust's lifetime model. +//! To ensure safety measures when using the underlying services, `ctru-rs` leverages Rust's lifetime model. //! After initializing the handle for a specific service (e.g. [`Apt`](apt::Apt)) the service will be accessible as long as there is at least one handle "alive". //! As such, handles should be dropped *after* the use of a specific service. This is particularly important for services which are necessary for functionality //! "outside" their associated methods, such as [`RomFS`](romfs::RomFS), which creates an accessible virtual filesystem, or [`Soc`](soc::Soc), //! which enables all network communications via sockets. //! -//! In `ctru` some services only allow a single handle to be created at a time, to ensure a safe and controlled environment. +//! In `ctru-rs` some services only allow a single handle to be created at a time, to ensure a safe and controlled environment. pub mod am; pub mod apt; diff --git a/ctru-rs/src/services/romfs.rs b/ctru-rs/src/services/romfs.rs index dae4ed3f..5d4a64be 100644 --- a/ctru-rs/src/services/romfs.rs +++ b/ctru-rs/src/services/romfs.rs @@ -21,7 +21,7 @@ use crate::services::ServiceReference; /// Handle to the RomFS service. /// /// This service lets the application access a virtual mounted device created using a folder included within the application bundle. -/// `ctru` will include as RomFS the folder specified in the `Cargo.toml` manifest (or use `./romfs` by default). Look at the [`romfs`](self) module for more information. +/// `ctru-rs` will include as RomFS the folder specified in the `Cargo.toml` manifest (or use `./romfs` by default). Look at the [`romfs`](self) module for more information. /// /// After mounting the RomFS file system, the included files and folders will be accessible exactly like any other file, just by using the drive prefix `romfs:/`. pub struct RomFS { diff --git a/ctru-sys/README.md b/ctru-sys/README.md new file mode 100644 index 00000000..280fd830 --- /dev/null +++ b/ctru-sys/README.md @@ -0,0 +1,33 @@ +# ctru-sys + +Raw Rust bindings over the [`libctru`](https://github.com/devkitPro/libctru) C library. + +## Requirements + +To use the bindings provided by this crate you will need to link against the [`libctru`](https://github.com/devkitPro/libctru) library. +Consult the [`ctru-rs` wiki](https://github.com/rust3ds/ctru-rs/wiki/Getting-Started) to learn how to obtain the required packages +to use this library. + +## Version + +This crate's version changes according to the version of `libctru` +used to generate the bindings, with the following convention: + + * [`libctru`](https://github.com/devkitPro/libctru) version `X.Y.Z-W` + * `ctru-sys` version `XY.Z.P+X.Y.Z-W` + + where `P` is usually 0 but may be incremented for fixes in e.g. + binding generation, `libc` dependency bump, etc. + +It may be possible to build this crate against a different version of [`libctru`](https://github.com/devkitPro/libctru), +but you may encounter linker errors or ABI issues. A build-time Cargo warning +(displayed when built with `-vv`) will be issued if the build script detects +a mismatch or is unable to check the installed [`libctru`](https://github.com/devkitPro/libctru) version. + +## Generating bindings + +Bindings of new versions of [`libctru`](https://github.com/devkitPro/libctru) can be built using the integrated [`bindgen.sh`](./bindgen.sh) script. + +## License + +This project is distributed under the Zlib license. From 9662b876bb7b974b25399c5fde8b2c97de306435 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Wed, 19 Jul 2023 10:33:55 +0200 Subject: [PATCH 12/39] Fmt --- ctru-rs/src/applets/mod.rs | 2 +- ctru-rs/src/applets/swkbd.rs | 2 +- ctru-rs/src/console.rs | 10 +++++----- ctru-rs/src/prelude.rs | 2 +- ctru-rs/src/services/ndsp/mod.rs | 8 ++++---- ctru-rs/src/services/romfs.rs | 4 ++-- ctru-sys/build.rs | 5 +++-- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/ctru-rs/src/applets/mod.rs b/ctru-rs/src/applets/mod.rs index 57c9471e..e8af7ca7 100644 --- a/ctru-rs/src/applets/mod.rs +++ b/ctru-rs/src/applets/mod.rs @@ -1,5 +1,5 @@ //! System Applets. -//! +//! //! Applets are small integrated programs that the OS makes available to the developer to streamline commonly needed functionality. //! Thanks to these integrations the developer can avoid wasting time re-implementing common features and instead use a more reliable base for their application. diff --git a/ctru-rs/src/applets/swkbd.rs b/ctru-rs/src/applets/swkbd.rs index d0f0fdf8..59c658df 100644 --- a/ctru-rs/src/applets/swkbd.rs +++ b/ctru-rs/src/applets/swkbd.rs @@ -1,5 +1,5 @@ //! Software Keyboard applet. -//! +//! //! This applet opens a virtual keyboard on the console's bottom screen which lets the player/user write UTF-16 valid text. use bitflags::bitflags; diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index 74b861ef..a468c02a 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -10,16 +10,16 @@ use crate::services::gfx::Screen; static mut EMPTY_CONSOLE: PrintConsole = unsafe { const_zero::const_zero!(PrintConsole) }; /// Virtual printable console. -/// +/// /// [`Console`] lets the application redirect `stdout` to a simple text displayer on the 3DS screen. /// This means that any text written to `stdout` (e.g. using [`println!`] or [`dbg!`]) will become visible in the area taken by the console. -/// +/// /// # Notes -/// +/// /// The console will take full possession of the screen handed to it as long as it stays alive. It also supports ANSI codes. -/// +/// /// # Alternatives -/// +/// /// If you'd like to see live `stdout` output while running the application but can't/don't want to show the text on the 3DS itself, /// you can try using [`Soc::redirect_to_3dslink`](crate::services::soc::Soc::redirect_to_3dslink) while activating the `--server` flag for `3dslink` (also supported by `cargo-3ds`). /// More info in the `cargo-3ds` docs. diff --git a/ctru-rs/src/prelude.rs b/ctru-rs/src/prelude.rs index b765b658..ee18eabf 100644 --- a/ctru-rs/src/prelude.rs +++ b/ctru-rs/src/prelude.rs @@ -1,5 +1,5 @@ //! `use ctru::prelude::*;` to import common services, members and functions. -//! +//! //! Particularly useful when writing very small applications. pub use crate::console::Console; diff --git a/ctru-rs/src/services/ndsp/mod.rs b/ctru-rs/src/services/ndsp/mod.rs index e8325510..f815fdb1 100644 --- a/ctru-rs/src/services/ndsp/mod.rs +++ b/ctru-rs/src/services/ndsp/mod.rs @@ -74,13 +74,13 @@ pub enum NdspError { } /// NDSP Channel representation. -/// +/// /// There are 24 individual channels in total and each can play a different audio [`Wave`] simultaneuosly. -/// +/// /// # Default -/// +/// /// NDSP initialises all channels with default values on creation, but the developer is supposed to change these values to correctly work with the service. -/// +/// /// In particular: /// - Default audio format is set to [`AudioFormat::PCM16Mono`]. /// - Default sample rate is set to 1 Hz. diff --git a/ctru-rs/src/services/romfs.rs b/ctru-rs/src/services/romfs.rs index 5d4a64be..c8719a2f 100644 --- a/ctru-rs/src/services/romfs.rs +++ b/ctru-rs/src/services/romfs.rs @@ -19,10 +19,10 @@ use std::sync::Mutex; use crate::services::ServiceReference; /// Handle to the RomFS service. -/// +/// /// This service lets the application access a virtual mounted device created using a folder included within the application bundle. /// `ctru-rs` will include as RomFS the folder specified in the `Cargo.toml` manifest (or use `./romfs` by default). Look at the [`romfs`](self) module for more information. -/// +/// /// After mounting the RomFS file system, the included files and folders will be accessible exactly like any other file, just by using the drive prefix `romfs:/`. pub struct RomFS { _service_handler: ServiceReference, diff --git a/ctru-sys/build.rs b/ctru-sys/build.rs index a695d471..7c55caa5 100644 --- a/ctru-sys/build.rs +++ b/ctru-sys/build.rs @@ -77,8 +77,9 @@ fn check_libctru_version() -> Result<(String, String, String), Box> { .output()?; for line in String::from_utf8_lossy(&stdout).split('\n') { - let Some((_pkg, file)) = line.split_once(char::is_whitespace) - else { continue }; + let Some((_pkg, file)) = line.split_once(char::is_whitespace) else { + continue; + }; println!("cargo:rerun-if-changed={file}"); } From afc74fdf47fc66aeb91d03a08f2bf79c25a1abde Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Wed, 19 Jul 2023 12:53:02 +0200 Subject: [PATCH 13/39] New doc changes and bump bitflags dependency --- ctru-rs/Cargo.toml | 2 +- ctru-rs/src/applets/mii_selector.rs | 116 +++++++++++++++++++--------- ctru-rs/src/applets/mod.rs | 3 + ctru-rs/src/applets/swkbd.rs | 6 +- ctru-rs/src/error.rs | 4 +- ctru-rs/src/lib.rs | 4 - ctru-rs/src/services/fs.rs | 6 +- ctru-rs/src/services/gfx.rs | 13 +++- ctru-rs/src/services/hid.rs | 5 +- 9 files changed, 108 insertions(+), 51 deletions(-) diff --git a/ctru-rs/Cargo.toml b/ctru-rs/Cargo.toml index 16f4a3dd..027a3cb0 100644 --- a/ctru-rs/Cargo.toml +++ b/ctru-rs/Cargo.toml @@ -22,7 +22,7 @@ const-zero = "0.1.0" shim-3ds = { git = "https://github.com/rust3ds/shim-3ds.git" } pthread-3ds = { git = "https://github.com/rust3ds/pthread-3ds.git" } libc = "0.2.121" -bitflags = "1.0.0" +bitflags = "2.3.3" widestring = "0.2.2" [build-dependencies] diff --git a/ctru-rs/src/applets/mii_selector.rs b/ctru-rs/src/applets/mii_selector.rs index 7cd0f816..fa690344 100644 --- a/ctru-rs/src/applets/mii_selector.rs +++ b/ctru-rs/src/applets/mii_selector.rs @@ -1,11 +1,11 @@ //! Mii Selector applet. //! //! This applet opens a window on the console's bottom screen which lets the player/user choose a Mii from the ones present on their console. -//! The application can access the selected Mii's data via the use of the [`mii`](crate::mii) module. +//! The selected Mii is readable as a [`MiiData`](crate::mii::MiiData). use crate::mii::MiiData; use bitflags::bitflags; -use std::ffi::CString; +use std::{ffi::CString, error::Error, fmt}; /// Index of a Mii used to configure some parameters of the Mii Selector. #[derive(Debug, Clone, Copy, Eq, PartialEq)] @@ -16,7 +16,7 @@ pub enum Index { All, } -/// The type of a Mii with their respective data +/// The type of a Mii. #[derive(Debug, Clone, Eq, PartialEq)] pub enum MiiType { /// Guest Mii. @@ -31,29 +31,56 @@ pub enum MiiType { } bitflags! { - /// Options for the Mii Selector + /// Options to configure the [MiiSelector]. + /// + ///

Example

+ /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::applets::mii_selector::{MiiSelector, Options}; + /// + /// // Setup a `MiiSelector` that can be cancelled and that makes Guest Miis available to select. + /// let opts = Options::ENABLE_CANCEL & Options::ENABLE_GUESTS; + /// + /// let mut mii_selector = MiiSelector::new(); + /// mii_selector.set_options(opts); + /// + /// let result = mii_selector.launch()?; + /// # + /// # Ok(()) + /// # } + /// ``` + #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] pub struct Options: u32 { - /// Show the cancel button - const MII_SELECTOR_CANCEL = ctru_sys::MIISELECTOR_CANCEL; - /// Make guest Miis selectable - const MII_SELECTOR_GUESTS = ctru_sys::MIISELECTOR_GUESTS; - /// Show on the top screen - const MII_SELECTOR_TOP = ctru_sys::MIISELECTOR_TOP; - /// Start on the guest's page - const MII_SELECTOR_GUEST_START = ctru_sys::MIISELECTOR_GUESTSTART; + /// Show the cancel button. + const ENABLE_CANCEL = ctru_sys::MIISELECTOR_CANCEL; + /// Make guest Miis available to select. + const ENABLE_GUESTS = ctru_sys::MIISELECTOR_GUESTS; + /// Show on the top screen. + const USE_TOP_SCREEN = ctru_sys::MIISELECTOR_TOP; + /// Start on the guests' page. Requires [Options::ENABLE_GUESTS]. + const START_WITH_GUESTS = ctru_sys::MIISELECTOR_GUESTSTART; } } -/// An instance of the Mii Selector +/// Configuration object to setup the Mii Selector applet. /// /// # Example -/// ``` +/// ```no_run +/// # use std::error::Error; +/// # fn main() -> Result<(), Box> { +/// # /// use ctru::applets::mii_selector::MiiSelector; /// /// let mut mii_selector = MiiSelector::new(); -/// mii_selector.set_title("Example Mii selector"); +/// mii_selector.set_title("Example Mii Selector"); /// -/// let result = mii_selector.launch().unwrap(); +/// let result = mii_selector.launch()?; +/// # +/// # Ok(()) +/// # } /// ``` #[doc(alias = "MiiSelectorConf")] #[derive(Clone, Debug)] @@ -61,27 +88,27 @@ pub struct MiiSelector { config: Box, } -/// Return value from a MiiSelector's launch +/// Return value of a successful [MiiSelector::launch()]. #[non_exhaustive] #[derive(Clone, Debug)] -pub struct SelectionResult { - /// Data regarding the selected Mii. +pub struct Selection { + /// Data of the selected Mii. pub mii_data: MiiData, /// Type of the selected Mii. pub mii_type: MiiType, } -/// Error type for the Mii selector +/// Error returned by an unsuccessful [MiiSelector::launch()]. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum LaunchError { - /// The selected Mii's data is corrupt in some way + /// The selected Mii's data is corrupt in some way. InvalidChecksum, - /// Either the user cancelled the selection (see [Options::MII_SELECTOR_CANCEL]), or no valid Miis were available to select + /// Either the user cancelled the selection (see [Options::ENABLE_CANCEL]), or no valid Miis were available to select. NoMiiSelected, } impl MiiSelector { - /// Initializes a Mii Selector + /// Initialize a new configuration for the Mii Selector applet. #[doc(alias = "miiSelectorInit")] pub fn new() -> Self { let mut config = Box::::default(); @@ -91,9 +118,9 @@ impl MiiSelector { Self { config } } - /// Set the title of the Mii Selector. + /// Set the title of the Mii Selector window. /// - /// This function would panic if the given ``&str`` contains NUL bytes. + /// This function will panic if the given `&str` contains NUL bytes. #[doc(alias = "miiSelectorSetTitle")] pub fn set_title(&mut self, text: &str) { // This can only fail if the text contains NUL bytes in the string... which seems @@ -104,13 +131,15 @@ impl MiiSelector { } } - /// Set the options of the Mii Selector + /// Set the options of the Mii Selector. + /// + /// This will overwrite any previously saved options. #[doc(alias = "miiSelectorSetOptions")] pub fn set_options(&mut self, options: Options) { - unsafe { ctru_sys::miiSelectorSetOptions(self.config.as_mut(), options.bits) } + unsafe { ctru_sys::miiSelectorSetOptions(self.config.as_mut(), options.bits()) } } - /// Whitelist a guest Mii + /// Whitelist a guest Mii based on its index. #[doc(alias = "miiSelectorWhitelistGuestMii")] pub fn whitelist_guest_mii(&mut self, mii_index: Index) { let index = match mii_index { @@ -121,7 +150,7 @@ impl MiiSelector { unsafe { ctru_sys::miiSelectorWhitelistGuestMii(self.config.as_mut(), index) } } - /// Blacklist a guest Mii + /// Blacklist a guest Mii based on its index. #[doc(alias = "miiSelectorBlacklistGuestMii")] pub fn blacklist_guest_mii(&mut self, mii_index: Index) { let index = match mii_index { @@ -132,7 +161,7 @@ impl MiiSelector { unsafe { ctru_sys::miiSelectorBlacklistGuestMii(self.config.as_mut(), index) } } - /// Whitelist a user Mii + /// Whitelist a user Mii based on its index. #[doc(alias = "miiSelectorWhitelistUserMii")] pub fn whitelist_user_mii(&mut self, mii_index: Index) { let index = match mii_index { @@ -143,7 +172,7 @@ impl MiiSelector { unsafe { ctru_sys::miiSelectorWhitelistUserMii(self.config.as_mut(), index) } } - /// Blacklist a user Mii + /// Blacklist a user Mii based on its index. #[doc(alias = "miiSelectorBlacklistUserMii")] pub fn blacklist_user_mii(&mut self, mii_index: Index) { let index = match mii_index { @@ -154,8 +183,9 @@ impl MiiSelector { unsafe { ctru_sys::miiSelectorBlacklistUserMii(self.config.as_mut(), index) } } - /// Set where the cursor will be. - /// If there's no Mii at that index, the cursor will start at the Mii with the index 0 + /// Set where the cursor will start at. + /// + /// If there's no Mii at that index, the cursor will start at the Mii with the index 0. pub fn set_initial_index(&mut self, index: usize) { // This function is static inline in libctru // https://github.com/devkitPro/libctru/blob/af5321c78ee5c72a55b526fd2ed0d95ca1c05af9/libctru/include/3ds/applets/miiselector.h#L155 @@ -163,9 +193,10 @@ impl MiiSelector { } /// Launch the Mii Selector. - /// Returns an error when the checksum of the Mii is invalid. + /// + /// Depending on the configuration, the Mii Selector window will appear either on the bottom screen (default behaviour) or the top screen (see [Options::USE_TOP_SCREEN]). #[doc(alias = "miiSelectorLaunch")] - pub fn launch(&mut self) -> Result { + pub fn launch(&mut self) -> Result { let mut return_val = Box::::default(); unsafe { ctru_sys::miiSelectorLaunch(self.config.as_mut(), return_val.as_mut()) } @@ -187,12 +218,23 @@ impl Default for MiiSelector { } } -impl From for SelectionResult { +impl fmt::Display for LaunchError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::InvalidChecksum => write!(f, "selected mii has invalid checksum"), + Self::NoMiiSelected => write!(f, "no mii was selected"), + } + } +} + +impl Error for LaunchError {} + +impl From for Selection { fn from(ret: ctru_sys::MiiSelectorReturn) -> Self { let raw_mii_data = ret.mii; let mut guest_mii_name = ret.guest_mii_name; - SelectionResult { + Selection { mii_data: raw_mii_data.into(), mii_type: if ret.guest_mii_index != 0xFFFFFFFF { MiiType::Guest { diff --git a/ctru-rs/src/applets/mod.rs b/ctru-rs/src/applets/mod.rs index e8af7ca7..15216faa 100644 --- a/ctru-rs/src/applets/mod.rs +++ b/ctru-rs/src/applets/mod.rs @@ -2,6 +2,9 @@ //! //! Applets are small integrated programs that the OS makes available to the developer to streamline commonly needed functionality. //! Thanks to these integrations the developer can avoid wasting time re-implementing common features and instead use a more reliable base for their application. +//! +//! Unlike [services](crate::services), applets aren't accessed via a system subprocess (which would require obtaining a special handle at runtime). +//! Instead, the user builds a configuration storing the various parameters which is then used to "launch" the applet. pub mod mii_selector; pub mod swkbd; diff --git a/ctru-rs/src/applets/swkbd.rs b/ctru-rs/src/applets/swkbd.rs index 59c658df..86f6357f 100644 --- a/ctru-rs/src/applets/swkbd.rs +++ b/ctru-rs/src/applets/swkbd.rs @@ -89,6 +89,7 @@ pub enum ValidInput { bitflags! { /// Keyboard feature flags. + #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] pub struct Features: u32 { /// Parental PIN mode. const PARENTAL_PIN = ctru_sys::SWKBD_PARENTAL; @@ -111,6 +112,7 @@ bitflags! { } /// Keyboard input filtering flags + #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] pub struct Filters: u32 { /// Disallows the usage of numerical digits. const DIGITS = ctru_sys::SWKBD_FILTER_DIGITS; @@ -183,13 +185,13 @@ impl Swkbd { /// Sets special features for this keyboard #[doc(alias = "swkbdSetFeatures")] pub fn set_features(&mut self, features: Features) { - unsafe { swkbdSetFeatures(self.state.as_mut(), features.bits) } + unsafe { swkbdSetFeatures(self.state.as_mut(), features.bits()) } } /// Configures input validation for this keyboard pub fn set_validation(&mut self, validation: ValidInput, filters: Filters) { self.state.valid_input = validation.into(); - self.state.filter_flags = filters.bits; + self.state.filter_flags = filters.bits(); } /// Configures the maximum number of digits that can be entered in the keyboard when the diff --git a/ctru-rs/src/error.rs b/ctru-rs/src/error.rs index 71c0f46b..895bed1c 100644 --- a/ctru-rs/src/error.rs +++ b/ctru-rs/src/error.rs @@ -21,7 +21,9 @@ pub type Result = ::std::result::Result; /// # Example /// /// ```no_run -/// pub fn hid_init() -> crate::Result<()> { +/// use ctru::error::{Result, ResultCode}; +/// +/// 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() }; /// diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index 7e29748a..64ef0fa0 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -14,10 +14,6 @@ //! Read thoroughly the official [`ctru-rs` wiki](https://github.com/rust3ds/ctru-rs/wiki) which guides you through the setup needed to install the required toolchain and helpful tools. //! After following the guide and understanding the many quirks of the Nintendo 3DS homebrew development environment, you can create a new project by including this crate as a dependency //! of your project in your `Cargo.toml` manifest and build your binaries either manually (for the `armv6k-nintendo-3ds` target) or via [`cargo-3ds`](https://github.com/rust3ds/cargo-3ds). -//! -//! # Examples -//! -//! You can check out the examples provided with this crate which dive into most of the implemented functionality. #![crate_type = "rlib"] #![crate_name = "ctru"] diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index f008954b..1f0fed71 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -17,20 +17,20 @@ use std::sync::Arc; use widestring::{WideCStr, WideCString}; bitflags! { - #[derive(Default)] + #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] struct FsOpen: u32 { const FS_OPEN_READ = 1; const FS_OPEN_WRITE = 2; const FS_OPEN_CREATE = 4; } - #[derive(Default)] + #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] struct FsWrite: u32 { const FS_WRITE_FLUSH = 1; const FS_WRITE_UPDATE_TIME = 256; } - #[derive(Default)] + #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] struct FsAttribute: u32 { const FS_ATTRIBUTE_DIRECTORY = 1; const FS_ATTRIBUTE_HIDDEN = 256; diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index 54ec061c..b1432f27 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -222,8 +222,17 @@ impl Gfx { /// Creates a new [`Gfx`] instance with default init values /// It's the same as calling: /// - /// ``` - /// Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false) + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// # use ctru::services::gfx::Gfx; + /// use ctru::services::gspgpu::FramebufferFormat; + /// + /// Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false); + /// # + /// # Ok(()) + /// # } /// ``` #[doc(alias = "gfxInit")] pub fn new() -> Result { diff --git a/ctru-rs/src/services/hid.rs b/ctru-rs/src/services/hid.rs index cb2550fe..b592f6a3 100644 --- a/ctru-rs/src/services/hid.rs +++ b/ctru-rs/src/services/hid.rs @@ -5,9 +5,12 @@ //! the accelerometer, and the gyroscope. use crate::error::ResultCode; -bitflags::bitflags! { +use bitflags::bitflags; + +bitflags! { /// A set of flags corresponding to the button and directional pad /// inputs on the 3DS + #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] pub struct KeyPad: u32 { /// A button. const A = ctru_sys::KEY_A; From fafe3c3dbf771bcc95fb494c6f373922cb3c833d Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Wed, 19 Jul 2023 13:38:31 +0200 Subject: [PATCH 14/39] Finish MiiSelector applet documentation --- ctru-rs/examples/mii-selector.rs | 2 +- ctru-rs/src/applets/mii_selector.rs | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ctru-rs/examples/mii-selector.rs b/ctru-rs/examples/mii-selector.rs index 4602e9b4..f6d3aa97 100644 --- a/ctru-rs/examples/mii-selector.rs +++ b/ctru-rs/examples/mii-selector.rs @@ -10,7 +10,7 @@ fn main() { let _console = Console::new(gfx.top_screen.borrow_mut()); let mut mii_selector = MiiSelector::new(); - mii_selector.set_options(Options::MII_SELECTOR_CANCEL); + mii_selector.set_options(Options::ENABLE_CANCEL); mii_selector.set_initial_index(3); mii_selector.blacklist_user_mii(0.into()); mii_selector.set_title("Great Mii Selector!"); diff --git a/ctru-rs/src/applets/mii_selector.rs b/ctru-rs/src/applets/mii_selector.rs index fa690344..2ccc42c0 100644 --- a/ctru-rs/src/applets/mii_selector.rs +++ b/ctru-rs/src/applets/mii_selector.rs @@ -5,9 +5,9 @@ use crate::mii::MiiData; use bitflags::bitflags; -use std::{ffi::CString, error::Error, fmt}; +use std::{error::Error, ffi::CString, fmt}; -/// Index of a Mii used to configure some parameters of the Mii Selector. +/// Index of a Mii on the Mii Selector interface. #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum Index { /// Specific Mii index. @@ -32,21 +32,21 @@ pub enum MiiType { bitflags! { /// Options to configure the [MiiSelector]. - /// + /// ///

Example

- /// + /// /// ```no_run /// # use std::error::Error; /// # fn main() -> Result<(), Box> { /// # /// use ctru::applets::mii_selector::{MiiSelector, Options}; - /// + /// /// // Setup a `MiiSelector` that can be cancelled and that makes Guest Miis available to select. /// let opts = Options::ENABLE_CANCEL & Options::ENABLE_GUESTS; - /// + /// /// let mut mii_selector = MiiSelector::new(); /// mii_selector.set_options(opts); - /// + /// /// let result = mii_selector.launch()?; /// # /// # Ok(()) @@ -58,14 +58,14 @@ bitflags! { const ENABLE_CANCEL = ctru_sys::MIISELECTOR_CANCEL; /// Make guest Miis available to select. const ENABLE_GUESTS = ctru_sys::MIISELECTOR_GUESTS; - /// Show on the top screen. + /// Show the Mii Selector window on the top screen. const USE_TOP_SCREEN = ctru_sys::MIISELECTOR_TOP; - /// Start on the guests' page. Requires [Options::ENABLE_GUESTS]. + /// Start the Mii Selector on the guests' page. Requires [Options::ENABLE_GUESTS]. const START_WITH_GUESTS = ctru_sys::MIISELECTOR_GUESTSTART; } } -/// Configuration object to setup the Mii Selector applet. +/// Configuration structure to setup the Mii Selector applet. /// /// # Example /// ```no_run @@ -132,7 +132,7 @@ impl MiiSelector { } /// Set the options of the Mii Selector. - /// + /// /// This will overwrite any previously saved options. #[doc(alias = "miiSelectorSetOptions")] pub fn set_options(&mut self, options: Options) { @@ -184,7 +184,7 @@ impl MiiSelector { } /// Set where the cursor will start at. - /// + /// /// If there's no Mii at that index, the cursor will start at the Mii with the index 0. pub fn set_initial_index(&mut self, index: usize) { // This function is static inline in libctru @@ -193,7 +193,7 @@ impl MiiSelector { } /// Launch the Mii Selector. - /// + /// /// Depending on the configuration, the Mii Selector window will appear either on the bottom screen (default behaviour) or the top screen (see [Options::USE_TOP_SCREEN]). #[doc(alias = "miiSelectorLaunch")] pub fn launch(&mut self) -> Result { From ab8a440e281b3891b9cfba54e790a40b0c47cf08 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Wed, 19 Jul 2023 23:41:11 +0200 Subject: [PATCH 15/39] Finalize applets --- ctru-rs/examples/file-explorer.rs | 4 +- ctru-rs/examples/mii-selector.rs | 6 +- ctru-rs/examples/software-keyboard.rs | 6 +- ctru-rs/src/applets/mii_selector.rs | 187 +++++++++++----- ctru-rs/src/applets/mod.rs | 4 +- ctru-rs/src/applets/swkbd.rs | 311 +++++++++++++++++++++----- 6 files changed, 397 insertions(+), 121 deletions(-) diff --git a/ctru-rs/examples/file-explorer.rs b/ctru-rs/examples/file-explorer.rs index 6d30590e..748a9379 100644 --- a/ctru-rs/examples/file-explorer.rs +++ b/ctru-rs/examples/file-explorer.rs @@ -1,7 +1,7 @@ //! A file explorer which shows off using standard library file system APIs to //! read the SD card. -use ctru::applets::swkbd::{Button, Swkbd}; +use ctru::applets::swkbd::{Button, SoftwareKeyboard}; use ctru::prelude::*; use std::fs::DirEntry; @@ -159,7 +159,7 @@ impl<'a> FileExplorer<'a> { } fn get_input_and_run(&mut self, action: impl FnOnce(&mut Self, String)) { - let mut keyboard = Swkbd::default(); + let mut keyboard = SoftwareKeyboard::default(); match keyboard.get_string(2048) { Ok((path, Button::Right)) => { diff --git a/ctru-rs/examples/mii-selector.rs b/ctru-rs/examples/mii-selector.rs index f6d3aa97..b12f217f 100644 --- a/ctru-rs/examples/mii-selector.rs +++ b/ctru-rs/examples/mii-selector.rs @@ -1,4 +1,4 @@ -use ctru::applets::mii_selector::{LaunchError, MiiSelector, Options}; +use ctru::applets::mii_selector::{Error, MiiSelector, Options}; use ctru::prelude::*; fn main() { @@ -25,8 +25,8 @@ fn main() { result.mii_data.mole_details.is_enabled ); } - Err(LaunchError::InvalidChecksum) => println!("Corrupt Mii selected"), - Err(LaunchError::NoMiiSelected) => println!("No Mii selected"), + Err(Error::InvalidChecksum) => println!("Corrupt Mii selected"), + Err(Error::NoMiiSelected) => println!("No Mii selected"), } // Main loop diff --git a/ctru-rs/examples/software-keyboard.rs b/ctru-rs/examples/software-keyboard.rs index 39b55494..4d7c4f2c 100644 --- a/ctru-rs/examples/software-keyboard.rs +++ b/ctru-rs/examples/software-keyboard.rs @@ -1,4 +1,4 @@ -use ctru::applets::swkbd::{Button, Swkbd}; +use ctru::applets::swkbd::{Button, SoftwareKeyboard}; use ctru::prelude::*; fn main() { @@ -18,9 +18,9 @@ fn main() { if hid.keys_down().contains(KeyPad::A) { // Prepares a software keyboard with two buttons: One to cancel input and one - // to accept it. You can also use `Swkbd::new()` to launch the keyboard in different + // to accept it. You can also use `SoftwareKeyboard::new()` to launch the keyboard in different // configurations. - let mut keyboard = Swkbd::default(); + let mut keyboard = SoftwareKeyboard::default(); // Raise the software keyboard. You can perform different actions depending on which // software button the user pressed diff --git a/ctru-rs/src/applets/mii_selector.rs b/ctru-rs/src/applets/mii_selector.rs index 2ccc42c0..16e885c9 100644 --- a/ctru-rs/src/applets/mii_selector.rs +++ b/ctru-rs/src/applets/mii_selector.rs @@ -1,16 +1,22 @@ //! Mii Selector applet. //! -//! This applet opens a window on the console's bottom screen which lets the player/user choose a Mii from the ones present on their console. +//! This applet opens a window which lets the player/user choose a Mii from the ones present on their console. //! The selected Mii is readable as a [`MiiData`](crate::mii::MiiData). use crate::mii::MiiData; use bitflags::bitflags; -use std::{error::Error, ffi::CString, fmt}; +use std::{ffi::CString, fmt}; -/// Index of a Mii on the Mii Selector interface. +/// Index of a Mii on the [`MiiSelector`] interface. +/// +/// See [`MiiSelector::whitelist_user_mii()`] and related functions for more information. #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum Index { /// Specific Mii index. + /// + /// # Notes + /// + /// Indexes start at 0. Index(u32), /// All Miis. All, @@ -31,64 +37,30 @@ pub enum MiiType { } bitflags! { - /// Options to configure the [MiiSelector]. - /// - ///

Example

- /// - /// ```no_run - /// # use std::error::Error; - /// # fn main() -> Result<(), Box> { - /// # - /// use ctru::applets::mii_selector::{MiiSelector, Options}; + /// Options to configure the [`MiiSelector`]. /// - /// // Setup a `MiiSelector` that can be cancelled and that makes Guest Miis available to select. - /// let opts = Options::ENABLE_CANCEL & Options::ENABLE_GUESTS; - /// - /// let mut mii_selector = MiiSelector::new(); - /// mii_selector.set_options(opts); - /// - /// let result = mii_selector.launch()?; - /// # - /// # Ok(()) - /// # } - /// ``` + /// See [`MiiSelector::set_options()`] to learn how to use them. #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] pub struct Options: u32 { /// Show the cancel button. const ENABLE_CANCEL = ctru_sys::MIISELECTOR_CANCEL; /// Make guest Miis available to select. const ENABLE_GUESTS = ctru_sys::MIISELECTOR_GUESTS; - /// Show the Mii Selector window on the top screen. + /// Show the [`MiiSelector`] window on the top screen. const USE_TOP_SCREEN = ctru_sys::MIISELECTOR_TOP; - /// Start the Mii Selector on the guests' page. Requires [Options::ENABLE_GUESTS]. + /// Start the [`MiiSelector`] on the guests' page. Requires [`Options::ENABLE_GUESTS`]. const START_WITH_GUESTS = ctru_sys::MIISELECTOR_GUESTSTART; } } /// Configuration structure to setup the Mii Selector applet. -/// -/// # Example -/// ```no_run -/// # use std::error::Error; -/// # fn main() -> Result<(), Box> { -/// # -/// use ctru::applets::mii_selector::MiiSelector; -/// -/// let mut mii_selector = MiiSelector::new(); -/// mii_selector.set_title("Example Mii Selector"); -/// -/// let result = mii_selector.launch()?; -/// # -/// # Ok(()) -/// # } -/// ``` #[doc(alias = "MiiSelectorConf")] #[derive(Clone, Debug)] pub struct MiiSelector { config: Box, } -/// Return value of a successful [MiiSelector::launch()]. +/// Return value of a successful [`MiiSelector::launch()`]. #[non_exhaustive] #[derive(Clone, Debug)] pub struct Selection { @@ -98,12 +70,12 @@ pub struct Selection { pub mii_type: MiiType, } -/// Error returned by an unsuccessful [MiiSelector::launch()]. +/// Error returned by an unsuccessful [`MiiSelector::launch()`]. #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum LaunchError { - /// The selected Mii's data is corrupt in some way. +pub enum Error { + /// The selected Mii's data is corrupt. InvalidChecksum, - /// Either the user cancelled the selection (see [Options::ENABLE_CANCEL]), or no valid Miis were available to select. + /// Either the user cancelled the selection (see [`Options::ENABLE_CANCEL`]) or no valid Miis were available to select. NoMiiSelected, } @@ -120,7 +92,18 @@ impl MiiSelector { /// Set the title of the Mii Selector window. /// + /// # Panics /// This function will panic if the given `&str` contains NUL bytes. + /// + /// # Example + /// ```no_run + /// # fn main() { + /// use ctru::applets::mii_selector::MiiSelector; + /// + /// let mut mii_selector = MiiSelector::new(); + /// mii_selector.set_title("Select a Mii!"); + /// # } + /// ``` #[doc(alias = "miiSelectorSetTitle")] pub fn set_title(&mut self, text: &str) { // This can only fail if the text contains NUL bytes in the string... which seems @@ -133,13 +116,42 @@ impl MiiSelector { /// Set the options of the Mii Selector. /// - /// This will overwrite any previously saved options. + /// This will overwrite any previously saved options. Use bitwise operations to set all your wanted options at once. + /// + /// # Example + /// ```no_run + /// # fn main() { + /// use ctru::applets::mii_selector::{MiiSelector, Options}; + /// let mut mii_selector = MiiSelector::new(); + /// + /// // Setup a `MiiSelector` that can be cancelled and that makes Guest Miis available to select. + /// let opts = Options::ENABLE_CANCEL & Options::ENABLE_GUESTS; + /// mii_selector.set_options(opts); + /// # } + /// ``` #[doc(alias = "miiSelectorSetOptions")] pub fn set_options(&mut self, options: Options) { unsafe { ctru_sys::miiSelectorSetOptions(self.config.as_mut(), options.bits()) } } /// Whitelist a guest Mii based on its index. + /// + /// # Notes + /// + /// Guest Mii's won't be available regardless of their whitelist/blacklist state if the [`MiiSelector`] is run without setting [`Options::ENABLE_GUESTS`]. + /// Look into [`MiiSelector::set_options()`] to see how to work with options. + /// + /// # Example + /// ```no_run + /// # fn main() { + /// # + /// use ctru::applets::mii_selector::{Index, MiiSelector}; + /// let mut mii_selector = MiiSelector::new(); + /// + /// // Whitelist the guest Mii at index 2. + /// mii_selector.whitelist_guest_mii(Index::Index(2)); + /// # } + /// ``` #[doc(alias = "miiSelectorWhitelistGuestMii")] pub fn whitelist_guest_mii(&mut self, mii_index: Index) { let index = match mii_index { @@ -151,6 +163,23 @@ impl MiiSelector { } /// Blacklist a guest Mii based on its index. + /// + /// # Notes + /// + /// Guest Mii's won't be available regardless of their whitelist/blacklist state if the [`MiiSelector`] is run without setting [`Options::ENABLE_GUESTS`]. + /// Look into [`MiiSelector::set_options()`] to see how to work with options. + /// + /// # Example + /// ```no_run + /// # fn main() { + /// # + /// use ctru::applets::mii_selector::{Index, MiiSelector}; + /// let mut mii_selector = MiiSelector::new(); + /// + /// // Blacklist the guest Mii at index 1 so that it cannot be selected. + /// mii_selector.blacklist_guest_mii(Index::Index(1)); + /// # } + /// ``` #[doc(alias = "miiSelectorBlacklistGuestMii")] pub fn blacklist_guest_mii(&mut self, mii_index: Index) { let index = match mii_index { @@ -161,7 +190,19 @@ impl MiiSelector { unsafe { ctru_sys::miiSelectorBlacklistGuestMii(self.config.as_mut(), index) } } - /// Whitelist a user Mii based on its index. + /// Whitelist a user-created Mii based on its index. + /// + /// # Example + /// ```no_run + /// # fn main() { + /// # + /// use ctru::applets::mii_selector::{Index, MiiSelector}; + /// let mut mii_selector = MiiSelector::new(); + /// + /// // Whitelist the user-created Mii at index 0. + /// mii_selector.whitelist_user_mii(Index::Index(0)); + /// # } + /// ``` #[doc(alias = "miiSelectorWhitelistUserMii")] pub fn whitelist_user_mii(&mut self, mii_index: Index) { let index = match mii_index { @@ -172,7 +213,19 @@ impl MiiSelector { unsafe { ctru_sys::miiSelectorWhitelistUserMii(self.config.as_mut(), index) } } - /// Blacklist a user Mii based on its index. + /// Blacklist a user-created Mii based on its index. + /// + /// # Example + /// ```no_run + /// # fn main() { + /// # + /// use ctru::applets::mii_selector::{Index, MiiSelector}; + /// let mut mii_selector = MiiSelector::new(); + /// + /// // Blacklist all user-created Miis so that they cannot be selected. + /// mii_selector.blacklist_user_mii(Index::All); + /// # } + /// ``` #[doc(alias = "miiSelectorBlacklistUserMii")] pub fn blacklist_user_mii(&mut self, mii_index: Index) { let index = match mii_index { @@ -183,9 +236,10 @@ impl MiiSelector { unsafe { ctru_sys::miiSelectorBlacklistUserMii(self.config.as_mut(), index) } } - /// Set where the cursor will start at. + /// Set where the GUI cursor will start at. /// /// If there's no Mii at that index, the cursor will start at the Mii with the index 0. + #[doc(alias = "miiSelectorSetInitialIndex")] pub fn set_initial_index(&mut self, index: usize) { // This function is static inline in libctru // https://github.com/devkitPro/libctru/blob/af5321c78ee5c72a55b526fd2ed0d95ca1c05af9/libctru/include/3ds/applets/miiselector.h#L155 @@ -194,20 +248,41 @@ impl MiiSelector { /// Launch the Mii Selector. /// - /// Depending on the configuration, the Mii Selector window will appear either on the bottom screen (default behaviour) or the top screen (see [Options::USE_TOP_SCREEN]). + /// Depending on the configuration, the Mii Selector window will appear either on the bottom screen (default behaviour) or the top screen (see [`Options::USE_TOP_SCREEN`]). + /// + /// TODO: UNSAFE OPERATION, LAUNCHING APPLETS REQUIRES GRAPHICS, WITHOUT AN ACTIVE GFX THIS WILL CAUSE A SEGMENTATION FAULT. + /// + /// # Example + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::applets::mii_selector::{MiiSelector, Options}; + /// + /// let mut mii_selector = MiiSelector::new(); + /// mii_selector.set_title("Select a Mii!"); + /// + /// let opts = Options::ENABLE_CANCEL & Options::ENABLE_GUESTS; + /// mii_selector.set_options(opts); + /// + /// let result = mii_selector.launch()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "miiSelectorLaunch")] - pub fn launch(&mut self) -> Result { + pub fn launch(&mut self) -> Result { let mut return_val = Box::::default(); unsafe { ctru_sys::miiSelectorLaunch(self.config.as_mut(), return_val.as_mut()) } if return_val.no_mii_selected != 0 { - return Err(LaunchError::NoMiiSelected); + return Err(Error::NoMiiSelected); } if unsafe { ctru_sys::miiSelectorChecksumIsValid(return_val.as_mut()) } { Ok((*return_val).into()) } else { - Err(LaunchError::InvalidChecksum) + Err(Error::InvalidChecksum) } } } @@ -218,7 +293,7 @@ impl Default for MiiSelector { } } -impl fmt::Display for LaunchError { +impl fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::InvalidChecksum => write!(f, "selected mii has invalid checksum"), @@ -227,7 +302,7 @@ impl fmt::Display for LaunchError { } } -impl Error for LaunchError {} +impl std::error::Error for Error {} impl From for Selection { fn from(ret: ctru_sys::MiiSelectorReturn) -> Self { diff --git a/ctru-rs/src/applets/mod.rs b/ctru-rs/src/applets/mod.rs index 15216faa..244fb74f 100644 --- a/ctru-rs/src/applets/mod.rs +++ b/ctru-rs/src/applets/mod.rs @@ -4,7 +4,9 @@ //! Thanks to these integrations the developer can avoid wasting time re-implementing common features and instead use a more reliable base for their application. //! //! Unlike [services](crate::services), applets aren't accessed via a system subprocess (which would require obtaining a special handle at runtime). -//! Instead, the user builds a configuration storing the various parameters which is then used to "launch" the applet. +//! Instead, the application builds a configuration storing the various parameters which is then used to "launch" the applet. +//! +//! Applets block execution of the thread that launches them as long as the user doesn't close the applet. pub mod mii_selector; pub mod swkbd; diff --git a/ctru-rs/src/applets/swkbd.rs b/ctru-rs/src/applets/swkbd.rs index 86f6357f..b399fb06 100644 --- a/ctru-rs/src/applets/swkbd.rs +++ b/ctru-rs/src/applets/swkbd.rs @@ -1,23 +1,28 @@ //! Software Keyboard applet. //! -//! This applet opens a virtual keyboard on the console's bottom screen which lets the player/user write UTF-16 valid text. +//! This applet opens a virtual keyboard on the console's bottom screen which lets the user write UTF-16 valid text. +// TODO: Implement remaining functionality (password mode, filter callbacks, etc.). Also improve "max text length" API. Improve `number of buttons` API when creating a new SoftwareKeyboard. +// TODO: Split the Parental PIN lock operations into a different type. use bitflags::bitflags; use ctru_sys::{ self, swkbdInit, swkbdInputText, swkbdSetButton, swkbdSetFeatures, swkbdSetHintText, SwkbdState, }; use libc; +use std::fmt::Display; use std::iter::once; use std::str; -/// An instance of the software keyboard. +/// Configuration structure to setup the Software Keyboard applet. #[doc(alias = "SwkbdState")] #[derive(Clone)] -pub struct Swkbd { +pub struct SoftwareKeyboard { state: Box, } -/// The kind of keyboard to be initialized. +/// The type of keyboard used by the [`SoftwareKeyboard`]. +/// +/// Can be set with [`SoftwareKeyboard::new()`] #[doc(alias = "SwkbdType")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] @@ -28,13 +33,15 @@ pub enum Kind { Qwerty = ctru_sys::SWKBD_TYPE_QWERTY, /// Only number pad. Numpad = ctru_sys::SWKBD_TYPE_NUMPAD, - /// On JPN systems: a keyboard without japanese input capablities. + /// On JPN systems: a keyboard without japanese input capabilities. /// /// On any other region: same as [`Normal`](Kind::Normal). Western = ctru_sys::SWKBD_TYPE_WESTERN, } -/// Represents which button the user pressed to close the software keyboard. +/// Represents which button the user pressed to close the [`SoftwareKeyboard`]. +/// +/// Button text and behaviour can be customized with [`SoftwareKeyboard::configure_button()`]. #[doc(alias = "SwkbdButton")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] @@ -47,30 +54,37 @@ pub enum Button { Right = ctru_sys::SWKBD_BUTTON_RIGHT, } -/// Error type for the software keyboard. +/// Error returned by an unsuccessful [`SoftwareKeyboard::get_string()`]. #[doc(alias = "SwkbdResult")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(i32)] pub enum Error { - /// Invalid parameters inputted in the Software Keyboard. - InvalidInput = ctru_sys::SWKBD_INVALID_INPUT, - /// Out of memory. + /// Invalid parameters given to the [`SoftwareKeyboard`] configuration. + InvalidParameters = ctru_sys::SWKBD_INVALID_INPUT, + /// [`SoftwareKeyboard`] ran out of memory. OutOfMem = ctru_sys::SWKBD_OUTOFMEM, - /// Home button was pressed during execution. + /// Home button was pressed while [`SoftwareKeyboard`] was running. HomePressed = ctru_sys::SWKBD_HOMEPRESSED, - /// Reset button was pressed during execution. + /// Reset button was pressed while [`SoftwareKeyboard`] was running. ResetPressed = ctru_sys::SWKBD_RESETPRESSED, - /// Power button was pressed during execution. + /// Power button was pressed while [`SoftwareKeyboard`] was running. PowerPressed = ctru_sys::SWKBD_POWERPRESSED, - /// The parental PIN was correct. + /// The parental lock PIN was correct. + /// + /// While this variant isn't *technically* considerable an error + /// the result of a Parental PIN operation won't return a string to the program, thus it's still exceptional behaviour. ParentalOk = ctru_sys::SWKBD_PARENTAL_OK, - /// The parental PIN was incorrect. + /// The parental lock PIN was incorrect. ParentalFail = ctru_sys::SWKBD_PARENTAL_FAIL, /// Input triggered the filter. + /// + /// You can have a look at [`Filters`] to activate custom filters. BannedInput = ctru_sys::SWKBD_BANNED_INPUT, } -/// Restrictions on keyboard input. +/// Restrictions to enforce rules on the keyboard input. +/// +/// See [`SoftwareKeyboard::set_validation()`] #[doc(alias = "SwkbdValidInput")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] @@ -79,71 +93,113 @@ pub enum ValidInput { Anything = ctru_sys::SWKBD_ANYTHING, /// Empty inputs are not accepted. NotEmpty = ctru_sys::SWKBD_NOTEMPTY, - /// Blank (consisting only of whitespaces) inputs are not accepted. + /// Blank inputs (consisting only of whitespaces) are not accepted. NotBlank = ctru_sys::SWKBD_NOTBLANK, /// Neither empty inputs nor blank inputs are accepted. NotEmptyNotBlank = ctru_sys::SWKBD_NOTEMPTY_NOTBLANK, - /// Input must have a fixed length. Maximum length can be specified with [`Swkbd::set_max_text_len`]; + /// Input must have a fixed length. Maximum length can be specified with [`SoftwareKeyboard::set_max_text_len()`]; FixedLen = ctru_sys::SWKBD_FIXEDLEN, } bitflags! { - /// Keyboard feature flags. + /// Special features that can be activated via [`SoftwareKeyboard::set_features()`]. #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] pub struct Features: u32 { /// Parental PIN mode. + /// + /// # Notes + /// + /// Refer to [`Error::ParentalOk`] and [`Error::ParentalFail`] to check whether the Parental PIN lock was successfully opened. const PARENTAL_PIN = ctru_sys::SWKBD_PARENTAL; - /// Darken top screen while the Software Keyboard is active. - const DARKEN_TOP_SCREEN = ctru_sys::SWKBD_DARKEN_TOP_SCREEN; + /// Darken top screen while the [`SoftwareKeyboard`] is active. + const DARKEN_TOP_SCREEN = ctru_sys::SWKBD_DARKEN_TOP_SCREEN; /// Enable predictive input (necessary for Kanji on JPN consoles). const PREDICTIVE_INPUT = ctru_sys::SWKBD_PREDICTIVE_INPUT; /// Enable multiline input. - const MULTILINE = ctru_sys::SWKBD_MULTILINE; + const MULTILINE = ctru_sys::SWKBD_MULTILINE; /// Enable fixed-width mode. const FIXED_WIDTH = ctru_sys::SWKBD_FIXED_WIDTH; - /// Allow the usage of the Home Button while the Software Keyboard is active. + /// Allow the usage of the Home Button while the [`SoftwareKeyboard`] is running. const ALLOW_HOME = ctru_sys::SWKBD_ALLOW_HOME; - /// Allow the usage of the Reset Button while the Software Keyboard is active. + /// Allow the usage of the Reset Button while the [`SoftwareKeyboard`] is running. const ALLOW_RESET = ctru_sys::SWKBD_ALLOW_RESET; - /// Allow the usage of the Power Button while the Software Keyboard is active. + /// Allow the usage of the Power Button while the [`SoftwareKeyboard`] is running. const ALLOW_POWER = ctru_sys::SWKBD_ALLOW_POWER; - /// Default to the QWERTY page when the Software Keyboard is shown. + /// Default to the QWERTY page when the [`SoftwareKeyboard`] is shown. const DEFAULT_QWERTY = ctru_sys::SWKBD_DEFAULT_QWERTY; } - /// Keyboard input filtering flags + /// Availble filters to disallow some types of input for the [`SoftwareKeyboard`]. + /// + /// See [`SoftwareKeyboard::set_validation()`] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] pub struct Filters: u32 { - /// Disallows the usage of numerical digits. + /// Disallow the usage of numerical digits. + /// + /// The maximum number of digits that are allowed to be used while this filter is active + /// can be configured with [`SoftwareKeyboard::set_max_digits()`] (default is 0). const DIGITS = ctru_sys::SWKBD_FILTER_DIGITS; - /// Disallows the usage of the "at" (@) sign. + /// Disallow the usage of the "at" (@) sign. const AT = ctru_sys::SWKBD_FILTER_AT; - /// Disallows the usage of the "percent" (%) sign. + /// Disallow the usage of the "percent" (%) sign. const PERCENT = ctru_sys::SWKBD_FILTER_PERCENT; - /// Disallows the usage of the "backslash" (\) sign. + /// Disallow the usage of the "backslash" (\) sign. const BACKSLASH = ctru_sys::SWKBD_FILTER_BACKSLASH; - /// Disallows the use of profanity via Nintendo's profanity filter. + /// Disallow the use of profanity via Nintendo's profanity filter. const PROFANITY = ctru_sys::SWKBD_FILTER_PROFANITY; /// Use a custom callback in order to filter the input. + /// + /// TODO: It's currently impossible to setup a custom filter callback. const CALLBACK = ctru_sys::SWKBD_FILTER_CALLBACK; } } -impl Swkbd { - /// Initializes a software keyboard of the specified type and the chosen number of buttons - /// (from 1-3). +impl SoftwareKeyboard { + /// Initialize a new configuration for the Software Keyboard applet depending on how many "exit" buttons are available to the user (1, 2 or 3). + /// + /// # Example + /// ```no_run + /// # fn main() { + /// # + /// use ctru::applets::swkbd::{SoftwareKeyboard, Kind}; + /// + /// // Standard keyboard. + /// let keyboard = SoftwareKeyboard::new(Kind::Normal, 2); + /// + /// // Numpad (with only the "confirm" button). + /// let keyboard = SoftwareKeyboard::new(Kind::Numpad, 1); + /// # + /// # } #[doc(alias = "swkbdInit")] pub fn new(keyboard_type: Kind, num_buttons: i32) -> Self { unsafe { let mut state = Box::::default(); swkbdInit(state.as_mut(), keyboard_type.into(), num_buttons, -1); - Swkbd { state } + SoftwareKeyboard { state } } } - /// Gets input from this keyboard and appends it to the provided string. + /// Launches the applet based on the given configuration and returns a string containing the text input. + /// + /// # Notes /// /// The text received from the keyboard will be truncated if it is longer than `max_bytes`. + /// + /// TODO: UNSAFE OPERATION, LAUNCHING APPLETS REQUIRES GRAPHICS, WITHOUT AN ACTIVE GFX THIS WILL CAUSE A SEGMENTATION FAULT. + /// + /// # Example + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::applets::swkbd::SoftwareKeyboard; + /// let mut keyboard = SoftwareKeyboard::default(); + /// + /// let (text, button) = keyboard.get_string(2048)?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "swkbdInputText")] pub fn get_string(&mut self, max_bytes: usize) -> Result<(String, Button), Error> { // Unfortunately the libctru API doesn't really provide a way to get the exact length @@ -167,8 +223,28 @@ impl Swkbd { /// Fills the provided buffer with a UTF-8 encoded, NUL-terminated sequence of bytes from /// this software keyboard. /// + /// # Notes + /// /// If the buffer is too small to contain the entire sequence received from the keyboard, - /// the output will be truncated but should still be well-formed UTF-8. + /// the output will be truncated. + /// + /// TODO: UNSAFE OPERATION, LAUNCHING APPLETS REQUIRES GRAPHICS, WITHOUT AN ACTIVE GFX THIS WILL CAUSE A SEGMENTATION FAULT. + /// + /// # Example + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::applets::swkbd::SoftwareKeyboard; + /// let mut keyboard = SoftwareKeyboard::default(); + /// + /// let mut buffer = vec![0; 100]; + /// + /// let button = keyboard.write_exact(&mut buffer)?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "swkbdInputText")] pub fn write_exact(&mut self, buf: &mut [u8]) -> Result { unsafe { @@ -182,26 +258,85 @@ impl Swkbd { } } - /// Sets special features for this keyboard + /// Set special features for this keyboard. + /// + /// # Example + /// ```no_run + /// # fn main() { + /// # + /// use ctru::applets::swkbd::{SoftwareKeyboard, Features}; + /// + /// let mut keyboard = SoftwareKeyboard::default(); + /// + /// let features = Features::DARKEN_TOP_SCREEN & Features::MULTILINE; + /// keyboard.set_features(features); + /// # + /// # } #[doc(alias = "swkbdSetFeatures")] pub fn set_features(&mut self, features: Features) { unsafe { swkbdSetFeatures(self.state.as_mut(), features.bits()) } } - /// Configures input validation for this keyboard + /// Configure input validation for this keyboard. + /// + /// # Example + /// ```no_run + /// # fn main() { + /// # + /// use ctru::applets::swkbd::{SoftwareKeyboard, ValidInput, Filters}; + /// let mut keyboard = SoftwareKeyboard::default(); + /// + /// // Disallow empty or blank input. + /// let validation = ValidInput::NotEmptyNotBlank; + /// + /// // Disallow the use of numerical digits and profanity. + /// let filters = Filters::DIGITS & Filters::PROFANITY; + /// keyboard.set_validation(validation, filters); + /// # + /// # } pub fn set_validation(&mut self, validation: ValidInput, filters: Filters) { self.state.valid_input = validation.into(); self.state.filter_flags = filters.bits(); } - /// Configures the maximum number of digits that can be entered in the keyboard when the - /// `Filters::DIGITS` flag is enabled + /// Configure the maximum number of digits that can be entered in the keyboard when the [`Filters::DIGITS`] flag is enabled. + /// + /// # Example + /// ```no_run + /// # fn main() { + /// # + /// use ctru::applets::swkbd::{SoftwareKeyboard, ValidInput, Filters}; + /// let mut keyboard = SoftwareKeyboard::default(); + /// + /// // Disallow empty or blank input. + /// let validation = ValidInput::NotEmptyNotBlank; + /// + /// // Disallow the use of numerical digits. This filter is customizable thanks to `set_max_digits`. + /// let filters = Filters::DIGITS; + /// keyboard.set_validation(validation, filters); + /// + /// // No more than 3 numbers are accepted. + /// keyboard.set_max_digits(3); + /// # + /// # } pub fn set_max_digits(&mut self, digits: u16) { self.state.max_digits = digits; } - /// Sets the hint text for this software keyboard (that is, the help text that is displayed - /// when the textbox is empty) + /// Set the hint text for this software keyboard. + /// + /// The hint text is the text shown in gray before any text gets written in the input box. + /// + /// # Example + /// ```no_run + /// # fn main() { + /// # + /// use ctru::applets::swkbd::SoftwareKeyboard; + /// let mut keyboard = SoftwareKeyboard::default(); + /// + /// keyboard.set_hint_text("Write here what you like!"); + /// # + /// # } #[doc(alias = "swkbdSetHintText")] pub fn set_hint_text(&mut self, text: &str) { unsafe { @@ -210,12 +345,30 @@ impl Swkbd { } } - /// Configures the look and behavior of a button for this keyboard. + /// Configure the look and behavior of a button for this keyboard. + /// + /// # Arguments + /// + /// - `button` - the [`Button`] to be configured based on the position. + /// - `text` - the text displayed in the button. + /// - `submit` - whether pressing the button will accept the keyboard's input or discard it. + /// + /// # Example + /// ```no_run + /// # fn main() { + /// # + /// use ctru::applets::swkbd::{SoftwareKeyboard, Button, Kind}; + /// + /// // We create a `SoftwareKeyboard` with left and right buttons. + /// let mut keyboard = SoftwareKeyboard::new(Kind::Normal, 2); /// - /// `button` is the `Button` to be configured - /// `text` configures the display text for the button - /// `submit` configures whether pressing the button will accept the keyboard's input or - /// discard it. + /// // Set the left button text to "Cancel" and pressing it will NOT return the user's input. + /// keyboard.configure_button(Button::Left, "Cancel", false); + /// + /// // Set the right button text to "Ok" and pressing it will return the user's input. + /// keyboard.configure_button(Button::Right, "Ok", true); + /// # + /// # } #[doc(alias = "swkbdSetButton")] pub fn configure_button(&mut self, button: Button, text: &str, submit: bool) { unsafe { @@ -229,19 +382,33 @@ impl Swkbd { } } - /// Configures the maximum number of UTF-16 code units that can be entered into the software - /// keyboard. By default the limit is 0xFDE8 code units. + /// Configure the maximum number of UTF-16 code units that can be entered into the software + /// keyboard. By default the limit is `0xFDE8` code units. + /// + /// # Notes /// - /// Note that keyboard input is converted from UTF-16 to UTF-8 before being handed to Rust, + /// Keyboard input is converted from UTF-16 to UTF-8 before being handed to Rust, /// so this code point limit does not necessarily equal the max number of UTF-8 code points - /// receivable by the `get_utf8` and `get_bytes` functions. + /// receivable by [`SoftwareKeyboard::get_string()`] and [`SoftwareKeyboard::write_exact()`]. + /// + /// # Example + /// ```no_run + /// # fn main() { + /// # + /// use ctru::applets::swkbd::{SoftwareKeyboard, Button, Kind}; + /// let mut keyboard = SoftwareKeyboard::default(); + /// + /// // Set the maximum text length to 18 UTF-16 code units. + /// keyboard.set_max_text_len(18); + /// # + /// # } pub fn set_max_text_len(&mut self, len: u16) { self.state.max_text_len = len; } fn parse_swkbd_error(&self) -> Error { match self.state.result { - ctru_sys::SWKBD_INVALID_INPUT => Error::InvalidInput, + ctru_sys::SWKBD_INVALID_INPUT => Error::InvalidParameters, ctru_sys::SWKBD_OUTOFMEM => Error::OutOfMem, ctru_sys::SWKBD_HOMEPRESSED => Error::HomePressed, ctru_sys::SWKBD_RESETPRESSED => Error::ResetPressed, @@ -254,12 +421,44 @@ impl Swkbd { } } -impl Default for Swkbd { +/// Creates a new [`SoftwareKeyboard`] configuration set to using a [`Kind::Normal`] keyboard and 2 [`Button`]s. +impl Default for SoftwareKeyboard { fn default() -> Self { - Swkbd::new(Kind::Normal, 2) + SoftwareKeyboard::new(Kind::Normal, 2) + } +} + +impl Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::InvalidParameters => write!( + f, + "software keyboard was configured with invalid parameters" + ), + Self::OutOfMem => write!(f, "software keyboard ran out of memory"), + Self::HomePressed => { + write!(f, "home button pressed while software keyboard was running") + } + Self::ResetPressed => write!( + f, + "reset button pressed while software keyboard was running" + ), + Self::PowerPressed => write!( + f, + "power button pressed while software keyboard was running" + ), + Self::ParentalOk => write!(f, "parental lock pin was correct"), + Self::ParentalFail => write!(f, "parental lock pin was incorrect"), + Self::BannedInput => write!( + f, + "input given to the software keyboard triggered the active filters" + ), + } } } +impl std::error::Error for Error {} + from_impl!(Kind, ctru_sys::SwkbdType); from_impl!(Button, ctru_sys::SwkbdButton); from_impl!(Error, ctru_sys::SwkbdResult); From 127eafdc4b067cbac47d71c73620f83cc30f17a8 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sat, 22 Jul 2023 13:31:14 +0200 Subject: [PATCH 16/39] Small changes and finalized AM service --- ctru-rs/examples/title-info.rs | 15 +--- ctru-rs/src/lib.rs | 5 +- ctru-rs/src/services/am.rs | 136 +++++++++++++++++++++------------ ctru-rs/src/services/mod.rs | 2 +- 4 files changed, 93 insertions(+), 65 deletions(-) diff --git a/ctru-rs/examples/title-info.rs b/ctru-rs/examples/title-info.rs index a03c0022..25b5c75f 100644 --- a/ctru-rs/examples/title-info.rs +++ b/ctru-rs/examples/title-info.rs @@ -80,18 +80,9 @@ fn main() { // Move cursor to top left println!("\x1b[1;1"); - match selected_title.size() { - Ok(size) => println!("Size: {} kB", size / 1024), - Err(e) => println!("Failed to get title size: {}", e), - } - match selected_title.version() { - Ok(version) => println!("Version: 0x{:x}", version), - Err(e) => println!("Failed to get title version: {}", e), - } - match selected_title.product_code() { - Ok(code) => println!("Product code: \"{code}\""), - Err(e) => println!("Failed to get product code: {}", e), - } + println!("Size: {} kB", selected_title.size() / 1024); + println!("Version: 0x{:x}", selected_title.version()); + println!("Product code: \"{}\"", selected_title.product_code()); println!("\x1b[26;0HPress START to exit"); if use_nand { diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index 64ef0fa0..b2267f0e 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -4,14 +4,14 @@ //! //! This crate behaves as the main tool to access system-specific functionality on the Nintendo 3DS when developing homebrew software in Rust. //! Thanks to it, developers can access the underlying system services and the console's hardware to develop userland applications -//! (such as HID devices, network capabilities, graphics, built-in cameras, etc.). +//! (such as [HID devices](crate::services::hid), [network capabilities](crate::services::soc), [graphics](crate::services::gfx), [built-in cameras](crate::services::cam), etc.). //! //! Among these features, `ctru-rs` also automatically includes functionality to properly integrate the Rust `std` with the console's operating system, //! which the developer would otherwise need to implement manually. //! //! # Usage //! -//! Read thoroughly the official [`ctru-rs` wiki](https://github.com/rust3ds/ctru-rs/wiki) which guides you through the setup needed to install the required toolchain and helpful tools. +//! Thoroughly read the official [`ctru-rs` wiki](https://github.com/rust3ds/ctru-rs/wiki) which guides you through the setup needed to install the required toolchain and helpful tools. //! After following the guide and understanding the many quirks of the Nintendo 3DS homebrew development environment, you can create a new project by including this crate as a dependency //! of your project in your `Cargo.toml` manifest and build your binaries either manually (for the `armv6k-nintendo-3ds` target) or via [`cargo-3ds`](https://github.com/rust3ds/cargo-3ds). @@ -21,7 +21,6 @@ #![feature(test)] #![feature(custom_test_frameworks)] #![feature(try_trait_v2)] -#![feature(once_cell_try)] #![feature(allocator_api)] #![test_runner(test_runner::run)] #![doc( diff --git a/ctru-rs/src/services/am.rs b/ctru-rs/src/services/am.rs index 31d46b54..d5705299 100644 --- a/ctru-rs/src/services/am.rs +++ b/ctru-rs/src/services/am.rs @@ -4,20 +4,19 @@ //! - Read the installed applications on the console and their information (depending on the install location). //! - Install compatible applications to the console. //! -//! `ctru-rs` doesn't support installing titles (yet). +//! TODO: `ctru-rs` doesn't support installing or uninstalling titles yet. use crate::error::ResultCode; use crate::services::fs::FsMediaType; -use std::cell::OnceCell; use std::marker::PhantomData; -use std::mem::MaybeUninit; -/// Struct holding general information about a specific title. +/// General information about a specific title entry. #[doc(alias = "AM_TitleEntry")] pub struct Title<'a> { id: u64, mediatype: FsMediaType, - entry: OnceCell, + size: u64, + version: u16, _am: PhantomData<&'a Am>, } @@ -29,54 +28,26 @@ impl<'a> Title<'a> { /// Returns this title's unique product code. #[doc(alias = "AM_GetTitleProductCode")] - pub fn product_code(&self) -> crate::Result { + pub fn product_code(&self) -> String { let mut buf: [u8; 16] = [0; 16]; + // This operation is safe as long as the title was correctly obtained via [`Am::title_list()`]. unsafe { - ResultCode(ctru_sys::AM_GetTitleProductCode( - self.mediatype.into(), - self.id, - buf.as_mut_ptr(), - ))?; + let _ = + ctru_sys::AM_GetTitleProductCode(self.mediatype.into(), self.id, buf.as_mut_ptr()); } - Ok(String::from_utf8_lossy(&buf).to_string()) - } - - /// Retrieves additional information on the title. - #[doc(alias = "AM_GetTitleInfo")] - fn title_info(&self) -> crate::Result { - let mut info = MaybeUninit::zeroed(); - - unsafe { - ResultCode(ctru_sys::AM_GetTitleInfo( - self.mediatype.into(), - 1, - &mut self.id.clone(), - info.as_mut_ptr() as _, - ))?; - Ok(info.assume_init()) - } + String::from_utf8_lossy(&buf).to_string() } /// Returns the size of this title in bytes. - pub fn size(&self) -> crate::Result { - // Get the internal entry, or fill it if empty. - let entry = self - .entry - .get_or_try_init(|| -> crate::Result { self.title_info() })?; - - Ok(entry.size) + pub fn size(&self) -> u64 { + self.size } /// Returns the installed version of this title. - pub fn version(&self) -> crate::Result { - // Get the internal entry, or fill it if empty. - let entry = self - .entry - .get_or_try_init(|| -> crate::Result { self.title_info() })?; - - Ok(entry.version) + pub fn version(&self) -> u16 { + self.version } } @@ -84,7 +55,20 @@ impl<'a> Title<'a> { pub struct Am(()); impl Am { - /// Initialize a new handle. + /// Initialize a new service handle. + /// + /// # Example + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::am::Am; + /// + /// let app_manager = Am::new()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "amInit")] pub fn new() -> crate::Result { unsafe { @@ -94,6 +78,24 @@ impl Am { } /// Returns the amount of titles currently installed in a specific install location. + /// + /// # Example + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::{fs::FsMediaType, am::Am}; + /// let app_manager = Am::new()?; + /// + /// // Number of titles installed on the Nand storage. + /// let nand_count = app_manager.title_count(FsMediaType::Nand); + /// + /// // Number of apps installed on the SD card storage + /// let sd_count = app_manager.title_count(FsMediaType::Sd); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "AM_GetTitleCount")] pub fn title_count(&self, mediatype: FsMediaType) -> crate::Result { unsafe { @@ -104,11 +106,30 @@ impl Am { } /// Returns the list of titles installed in a specific install location. + /// + /// # Example + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::{fs::FsMediaType, am::Am}; + /// let app_manager = Am::new()?; + /// + /// // Number of apps installed on the SD card storage + /// let sd_titles = app_manager.title_list(FsMediaType::Sd)?; + /// + /// // Unique product code identifier of the 5th installed title. + /// let product_code = sd_titles[4].product_code(); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "AM_GetTitleList")] pub fn title_list(&self, mediatype: FsMediaType) -> crate::Result> { let count = self.title_count(mediatype)?; let mut buf = vec![0; count as usize]; let mut read_amount = 0; + unsafe { ResultCode(ctru_sys::AM_GetTitleList( &mut read_amount, @@ -117,13 +138,30 @@ impl Am { buf.as_mut_ptr(), ))?; } - Ok(buf + + let mut info: Vec = Vec::with_capacity(count as _); + + unsafe { + ResultCode(ctru_sys::AM_GetTitleInfo( + mediatype.into(), + count, + buf.as_mut_ptr(), + info.as_mut_ptr() as _, + ))?; + + info.set_len(count as _); + }; + + Ok(info .into_iter() - .map(|id| Title { - id, - mediatype, - entry: OnceCell::new(), - _am: PhantomData, + .map(|title| { + Title { + id: title.titleID, + mediatype, + size: title.size, + version: title.version, + _am: PhantomData, + } }) .collect()) } diff --git a/ctru-rs/src/services/mod.rs b/ctru-rs/src/services/mod.rs index ab948b33..9ff975ea 100644 --- a/ctru-rs/src/services/mod.rs +++ b/ctru-rs/src/services/mod.rs @@ -3,7 +3,7 @@ //! Most of the 3DS console's functionalities (when writing user-land homebrew) are accessible via services, //! which need to be initialized before accessing any particular feature. //! -//! To ensure safety measures when using the underlying services, `ctru-rs` leverages Rust's lifetime model. +//! To ensure safety while using the underlying services, `ctru-rs` leverages Rust's lifetime model. //! After initializing the handle for a specific service (e.g. [`Apt`](apt::Apt)) the service will be accessible as long as there is at least one handle "alive". //! As such, handles should be dropped *after* the use of a specific service. This is particularly important for services which are necessary for functionality //! "outside" their associated methods, such as [`RomFS`](romfs::RomFS), which creates an accessible virtual filesystem, or [`Soc`](soc::Soc), From 30c3fb058522fb9dc8544bfed9ceffd4bf83ee63 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sat, 22 Jul 2023 16:41:42 +0200 Subject: [PATCH 17/39] Small example fmt --- ctru-rs/src/applets/mii_selector.rs | 7 +++++ ctru-rs/src/applets/swkbd.rs | 9 ++++++ ctru-rs/src/services/am.rs | 3 ++ ctru-rs/src/services/apt.rs | 43 +++++++++++++++++++++++++++-- ctru-rs/src/services/cam.rs | 6 ++-- ctru-rs/src/services/cfgu.rs | 4 +-- ctru-rs/src/services/fs.rs | 4 +-- ctru-rs/src/services/gfx.rs | 10 +++---- ctru-rs/src/services/hid.rs | 4 +-- ctru-rs/src/services/ps.rs | 4 ++- ctru-rs/src/services/romfs.rs | 4 +-- ctru-rs/src/services/soc.rs | 8 +++--- ctru-rs/src/services/sslc.rs | 4 +-- 13 files changed, 84 insertions(+), 26 deletions(-) diff --git a/ctru-rs/src/applets/mii_selector.rs b/ctru-rs/src/applets/mii_selector.rs index 16e885c9..0562777f 100644 --- a/ctru-rs/src/applets/mii_selector.rs +++ b/ctru-rs/src/applets/mii_selector.rs @@ -96,6 +96,7 @@ impl MiiSelector { /// This function will panic if the given `&str` contains NUL bytes. /// /// # Example + /// /// ```no_run /// # fn main() { /// use ctru::applets::mii_selector::MiiSelector; @@ -119,6 +120,7 @@ impl MiiSelector { /// This will overwrite any previously saved options. Use bitwise operations to set all your wanted options at once. /// /// # Example + /// /// ```no_run /// # fn main() { /// use ctru::applets::mii_selector::{MiiSelector, Options}; @@ -142,6 +144,7 @@ impl MiiSelector { /// Look into [`MiiSelector::set_options()`] to see how to work with options. /// /// # Example + /// /// ```no_run /// # fn main() { /// # @@ -170,6 +173,7 @@ impl MiiSelector { /// Look into [`MiiSelector::set_options()`] to see how to work with options. /// /// # Example + /// /// ```no_run /// # fn main() { /// # @@ -193,6 +197,7 @@ impl MiiSelector { /// Whitelist a user-created Mii based on its index. /// /// # Example + /// /// ```no_run /// # fn main() { /// # @@ -216,6 +221,7 @@ impl MiiSelector { /// Blacklist a user-created Mii based on its index. /// /// # Example + /// /// ```no_run /// # fn main() { /// # @@ -253,6 +259,7 @@ impl MiiSelector { /// TODO: UNSAFE OPERATION, LAUNCHING APPLETS REQUIRES GRAPHICS, WITHOUT AN ACTIVE GFX THIS WILL CAUSE A SEGMENTATION FAULT. /// /// # Example + /// /// ```no_run /// # use std::error::Error; /// # fn main() -> Result<(), Box> { diff --git a/ctru-rs/src/applets/swkbd.rs b/ctru-rs/src/applets/swkbd.rs index b399fb06..879c434b 100644 --- a/ctru-rs/src/applets/swkbd.rs +++ b/ctru-rs/src/applets/swkbd.rs @@ -158,6 +158,7 @@ impl SoftwareKeyboard { /// Initialize a new configuration for the Software Keyboard applet depending on how many "exit" buttons are available to the user (1, 2 or 3). /// /// # Example + /// /// ```no_run /// # fn main() { /// # @@ -188,6 +189,7 @@ impl SoftwareKeyboard { /// TODO: UNSAFE OPERATION, LAUNCHING APPLETS REQUIRES GRAPHICS, WITHOUT AN ACTIVE GFX THIS WILL CAUSE A SEGMENTATION FAULT. /// /// # Example + /// /// ```no_run /// # use std::error::Error; /// # fn main() -> Result<(), Box> { @@ -231,6 +233,7 @@ impl SoftwareKeyboard { /// TODO: UNSAFE OPERATION, LAUNCHING APPLETS REQUIRES GRAPHICS, WITHOUT AN ACTIVE GFX THIS WILL CAUSE A SEGMENTATION FAULT. /// /// # Example + /// /// ```no_run /// # use std::error::Error; /// # fn main() -> Result<(), Box> { @@ -261,6 +264,7 @@ impl SoftwareKeyboard { /// Set special features for this keyboard. /// /// # Example + /// /// ```no_run /// # fn main() { /// # @@ -280,6 +284,7 @@ impl SoftwareKeyboard { /// Configure input validation for this keyboard. /// /// # Example + /// /// ```no_run /// # fn main() { /// # @@ -302,6 +307,7 @@ impl SoftwareKeyboard { /// Configure the maximum number of digits that can be entered in the keyboard when the [`Filters::DIGITS`] flag is enabled. /// /// # Example + /// /// ```no_run /// # fn main() { /// # @@ -328,6 +334,7 @@ impl SoftwareKeyboard { /// The hint text is the text shown in gray before any text gets written in the input box. /// /// # Example + /// /// ```no_run /// # fn main() { /// # @@ -354,6 +361,7 @@ impl SoftwareKeyboard { /// - `submit` - whether pressing the button will accept the keyboard's input or discard it. /// /// # Example + /// /// ```no_run /// # fn main() { /// # @@ -392,6 +400,7 @@ impl SoftwareKeyboard { /// receivable by [`SoftwareKeyboard::get_string()`] and [`SoftwareKeyboard::write_exact()`]. /// /// # Example + /// /// ```no_run /// # fn main() { /// # diff --git a/ctru-rs/src/services/am.rs b/ctru-rs/src/services/am.rs index d5705299..d302448a 100644 --- a/ctru-rs/src/services/am.rs +++ b/ctru-rs/src/services/am.rs @@ -58,6 +58,7 @@ impl Am { /// Initialize a new service handle. /// /// # Example + /// /// ```no_run /// # use std::error::Error; /// # fn main() -> Result<(), Box> { @@ -80,6 +81,7 @@ impl Am { /// Returns the amount of titles currently installed in a specific install location. /// /// # Example + /// /// ```no_run /// # use std::error::Error; /// # fn main() -> Result<(), Box> { @@ -108,6 +110,7 @@ impl Am { /// Returns the list of titles installed in a specific install location. /// /// # Example + /// /// ```no_run /// # use std::error::Error; /// # fn main() -> Result<(), Box> { diff --git a/ctru-rs/src/services/apt.rs b/ctru-rs/src/services/apt.rs index 0f5eb25e..e885adf3 100644 --- a/ctru-rs/src/services/apt.rs +++ b/ctru-rs/src/services/apt.rs @@ -1,8 +1,10 @@ //! Applet service. //! -//! The APT service handles integration with some higher level OS features such as Sleep mode, the Home Menu and application switching. +//! The APT service handles integration with other applications, +//! including high-level OS features such as Sleep mode, the Home Menu and application switching. //! -//! It also handles running applets, small programs made available by the OS to streamline specific functionality. Those are implemented in the [`applets`](crate::applets) module. +//! It also handles running applets, small programs made available by the OS to streamline specific functionality. +//! Those are implemented in the [`applets`](crate::applets) module. use crate::error::ResultCode; @@ -10,7 +12,21 @@ use crate::error::ResultCode; pub struct Apt(()); impl Apt { - /// Initialize a new handle. + /// Initialize a new service handle. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::apt::Apt; + /// + /// let apt = Apt::new()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "aptInit")] pub fn new() -> crate::Result { unsafe { @@ -25,6 +41,27 @@ impl Apt { /// /// This function is called as such since it automatically handles all checks for Home Menu switching, Sleep mode and other events that could take away control from the application. /// For this reason, its main use is as the condition of a while loop that controls the main logic for your program. + /// + /// # Example + /// + /// ```no_run + /// use std::error::Error; + /// use ctru::services::apt::Apt; + /// + /// // In a simple `main` function, the structure should be the following. + /// fn main() -> Result<(), Box> { + /// + /// let apt = Apt::new()?; + /// + /// while apt.main_loop() { + /// // Main program logic should be written here. + /// } + /// + /// // Optional clean-ups after running the application should be written after the main loop. + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "aptMainLoop")] pub fn main_loop(&self) -> bool { unsafe { ctru_sys::aptMainLoop() } diff --git a/ctru-rs/src/services/cam.rs b/ctru-rs/src/services/cam.rs index de9ecb50..717694e6 100644 --- a/ctru-rs/src/services/cam.rs +++ b/ctru-rs/src/services/cam.rs @@ -1,6 +1,6 @@ -//! Camera service +//! Camera service. //! -//! The CAM service provides access to the cameras. Cameras can return images +//! The CAM service provides access to the built-in cameras. [`Camera`]s can return images //! in the form of byte vectors which can be displayed or used in other ways. use crate::error::{Error, ResultCode}; @@ -856,7 +856,7 @@ pub trait Camera { } impl Cam { - /// Initializes the CAM service. + /// Initialize a new service handle. /// /// # Errors /// diff --git a/ctru-rs/src/services/cfgu.rs b/ctru-rs/src/services/cfgu.rs index 99ef505f..9afbe7b8 100644 --- a/ctru-rs/src/services/cfgu.rs +++ b/ctru-rs/src/services/cfgu.rs @@ -1,4 +1,4 @@ -//! Configuration service +//! System Configuration service. //! //! This module contains basic methods to retrieve and change configuration from the console. @@ -82,7 +82,7 @@ pub enum SystemModel { pub struct Cfgu(()); impl Cfgu { - /// Initializes the CFGU service. + /// Initialize a new service handle. /// /// # Errors /// diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index 1f0fed71..446be7ed 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -1,4 +1,4 @@ -//! Filesystem service +//! FileSystem service. //! //! This module contains basic methods to manipulate the contents of the 3DS's filesystem. //! Only the SD card is currently supported. You should prefer using `std::fs`. @@ -320,7 +320,7 @@ unsafe impl Send for Dir {} unsafe impl Sync for Dir {} impl Fs { - /// Initializes the FS service. + /// Initialize a new service handle. /// /// # Errors /// diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index b1432f27..e6465e4b 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -1,4 +1,4 @@ -//! LCD screens manipulation helper +//! Graphics service. use std::cell::{Ref, RefCell, RefMut}; use std::marker::PhantomData; @@ -219,7 +219,8 @@ pub struct Gfx { static GFX_ACTIVE: Mutex = Mutex::new(0); impl Gfx { - /// Creates a new [`Gfx`] instance with default init values + /// Initialize a new default service handle. + /// /// It's the same as calling: /// /// ```no_run @@ -239,10 +240,9 @@ impl Gfx { Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false) } - /// Initialize the Gfx module with the chosen framebuffer formats for the top and bottom - /// screens + /// Initialize a new service handle with the chosen framebuffer formats for the top and bottom screens. /// - /// Use `Gfx::new()` instead of this function to initialize the module with default parameters + /// Use [`Gfx::new()`] instead of this function to initialize the module with default parameters #[doc(alias = "gfxInit")] pub fn with_formats( top_fb_fmt: FramebufferFormat, diff --git a/ctru-rs/src/services/hid.rs b/ctru-rs/src/services/hid.rs index b592f6a3..79bb6dfb 100644 --- a/ctru-rs/src/services/hid.rs +++ b/ctru-rs/src/services/hid.rs @@ -1,4 +1,4 @@ -//! HID service +//! Human-Interface Device service. //! //! The HID service provides access to user input such as button presses, touch screen presses, //! and circle pad information. It also provides information from the sound volume slider, @@ -79,7 +79,7 @@ bitflags! { pub struct Hid(()); impl Hid { - /// Initializes the HID service. + /// Initialize a new service handle. /// /// # Errors /// diff --git a/ctru-rs/src/services/ps.rs b/ctru-rs/src/services/ps.rs index 6f8c67c9..fc108fd4 100644 --- a/ctru-rs/src/services/ps.rs +++ b/ctru-rs/src/services/ps.rs @@ -1,4 +1,6 @@ -//! Process Services (PS) module. This is used for miscellaneous utility tasks, but +//! Process Services. +//! +//! This is used for miscellaneous utility tasks, but //! is particularly important because it is used to generate random data, which //! is required for common things like [`HashMap`](std::collections::HashMap). //! See also diff --git a/ctru-rs/src/services/romfs.rs b/ctru-rs/src/services/romfs.rs index c8719a2f..c1c2d9e2 100644 --- a/ctru-rs/src/services/romfs.rs +++ b/ctru-rs/src/services/romfs.rs @@ -1,4 +1,4 @@ -//! Read-Only Memory FileSystem +//! Read-Only Memory FileSystem service. //! //! This module only gets compiled if the configured RomFS directory is found and the `romfs` //! feature is enabled. @@ -31,7 +31,7 @@ pub struct RomFS { static ROMFS_ACTIVE: Mutex = Mutex::new(0); impl RomFS { - /// Mounts the specified RomFS folder as a virtual drive. + /// Mount the specified RomFS folder as a virtual drive. #[doc(alias = "romfsMountSelf")] pub fn new() -> crate::Result { let _service_handler = ServiceReference::new( diff --git a/ctru-rs/src/services/soc.rs b/ctru-rs/src/services/soc.rs index 2bbfe506..aa450bea 100644 --- a/ctru-rs/src/services/soc.rs +++ b/ctru-rs/src/services/soc.rs @@ -1,4 +1,4 @@ -//! Network Socket +//! Network Socket service. use libc::memalign; use std::net::Ipv4Addr; @@ -20,11 +20,11 @@ pub struct Soc { static SOC_ACTIVE: Mutex = Mutex::new(0); impl Soc { - /// Initialize the Soc service with a default buffer size of 0x100000 bytes + /// Initialize a new service handle using a socket buffer size of 0x100000 bytes. /// /// # Errors /// - /// This function will return an error if the `Soc` service is already initialized + /// This function will return an error if the [`Soc`] service is already initialized #[doc(alias = "socInit")] pub fn new() -> crate::Result { Self::init_with_buffer_size(0x100000) @@ -35,7 +35,7 @@ impl Soc { /// /// # Errors /// - /// This function will return an error if the `Soc` service is already initialized + /// This function will return an error if the [`Soc`] service is already initialized #[doc(alias = "socInit")] pub fn init_with_buffer_size(num_bytes: usize) -> crate::Result { let _service_handler = ServiceReference::new( diff --git a/ctru-rs/src/services/sslc.rs b/ctru-rs/src/services/sslc.rs index 9b311e3d..b13fac01 100644 --- a/ctru-rs/src/services/sslc.rs +++ b/ctru-rs/src/services/sslc.rs @@ -1,4 +1,4 @@ -//! SSLC (TLS) service +//! SSLC (TLS) service. // TODO: Implement remaining functions @@ -8,7 +8,7 @@ use crate::error::ResultCode; pub struct SslC(()); impl SslC { - /// Initialize the service + /// Initialize a new service handle. #[doc(alias = "sslcInit")] pub fn new() -> crate::Result { unsafe { From fde168cb17147be26394bd4a8e8a8f443cc217c0 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sat, 22 Jul 2023 17:41:23 +0200 Subject: [PATCH 18/39] Finish up SSLC, SOC, ROMFS and PS --- ctru-rs/src/applets/mii_selector.rs | 14 ++--- ctru-rs/src/applets/swkbd.rs | 18 +++--- ctru-rs/src/services/am.rs | 20 +++---- ctru-rs/src/services/apt.rs | 12 ++-- ctru-rs/src/services/gfx.rs | 2 +- ctru-rs/src/services/ps.rs | 75 +++++++++++++++++++++-- ctru-rs/src/services/romfs.rs | 33 ++++++++--- ctru-rs/src/services/soc.rs | 92 ++++++++++++++++++++++++----- ctru-rs/src/services/sslc.rs | 14 +++++ 9 files changed, 219 insertions(+), 61 deletions(-) diff --git a/ctru-rs/src/applets/mii_selector.rs b/ctru-rs/src/applets/mii_selector.rs index 0562777f..76a4d5ec 100644 --- a/ctru-rs/src/applets/mii_selector.rs +++ b/ctru-rs/src/applets/mii_selector.rs @@ -96,7 +96,7 @@ impl MiiSelector { /// This function will panic if the given `&str` contains NUL bytes. /// /// # Example - /// + /// /// ```no_run /// # fn main() { /// use ctru::applets::mii_selector::MiiSelector; @@ -120,7 +120,7 @@ impl MiiSelector { /// This will overwrite any previously saved options. Use bitwise operations to set all your wanted options at once. /// /// # Example - /// + /// /// ```no_run /// # fn main() { /// use ctru::applets::mii_selector::{MiiSelector, Options}; @@ -144,7 +144,7 @@ impl MiiSelector { /// Look into [`MiiSelector::set_options()`] to see how to work with options. /// /// # Example - /// + /// /// ```no_run /// # fn main() { /// # @@ -173,7 +173,7 @@ impl MiiSelector { /// Look into [`MiiSelector::set_options()`] to see how to work with options. /// /// # Example - /// + /// /// ```no_run /// # fn main() { /// # @@ -197,7 +197,7 @@ impl MiiSelector { /// Whitelist a user-created Mii based on its index. /// /// # Example - /// + /// /// ```no_run /// # fn main() { /// # @@ -221,7 +221,7 @@ impl MiiSelector { /// Blacklist a user-created Mii based on its index. /// /// # Example - /// + /// /// ```no_run /// # fn main() { /// # @@ -259,7 +259,7 @@ impl MiiSelector { /// TODO: UNSAFE OPERATION, LAUNCHING APPLETS REQUIRES GRAPHICS, WITHOUT AN ACTIVE GFX THIS WILL CAUSE A SEGMENTATION FAULT. /// /// # Example - /// + /// /// ```no_run /// # use std::error::Error; /// # fn main() -> Result<(), Box> { diff --git a/ctru-rs/src/applets/swkbd.rs b/ctru-rs/src/applets/swkbd.rs index 879c434b..f20819b9 100644 --- a/ctru-rs/src/applets/swkbd.rs +++ b/ctru-rs/src/applets/swkbd.rs @@ -158,7 +158,7 @@ impl SoftwareKeyboard { /// Initialize a new configuration for the Software Keyboard applet depending on how many "exit" buttons are available to the user (1, 2 or 3). /// /// # Example - /// + /// /// ```no_run /// # fn main() { /// # @@ -189,7 +189,7 @@ impl SoftwareKeyboard { /// TODO: UNSAFE OPERATION, LAUNCHING APPLETS REQUIRES GRAPHICS, WITHOUT AN ACTIVE GFX THIS WILL CAUSE A SEGMENTATION FAULT. /// /// # Example - /// + /// /// ```no_run /// # use std::error::Error; /// # fn main() -> Result<(), Box> { @@ -233,7 +233,7 @@ impl SoftwareKeyboard { /// TODO: UNSAFE OPERATION, LAUNCHING APPLETS REQUIRES GRAPHICS, WITHOUT AN ACTIVE GFX THIS WILL CAUSE A SEGMENTATION FAULT. /// /// # Example - /// + /// /// ```no_run /// # use std::error::Error; /// # fn main() -> Result<(), Box> { @@ -264,7 +264,7 @@ impl SoftwareKeyboard { /// Set special features for this keyboard. /// /// # Example - /// + /// /// ```no_run /// # fn main() { /// # @@ -284,7 +284,7 @@ impl SoftwareKeyboard { /// Configure input validation for this keyboard. /// /// # Example - /// + /// /// ```no_run /// # fn main() { /// # @@ -307,7 +307,7 @@ impl SoftwareKeyboard { /// Configure the maximum number of digits that can be entered in the keyboard when the [`Filters::DIGITS`] flag is enabled. /// /// # Example - /// + /// /// ```no_run /// # fn main() { /// # @@ -334,7 +334,7 @@ impl SoftwareKeyboard { /// The hint text is the text shown in gray before any text gets written in the input box. /// /// # Example - /// + /// /// ```no_run /// # fn main() { /// # @@ -361,7 +361,7 @@ impl SoftwareKeyboard { /// - `submit` - whether pressing the button will accept the keyboard's input or discard it. /// /// # Example - /// + /// /// ```no_run /// # fn main() { /// # @@ -400,7 +400,7 @@ impl SoftwareKeyboard { /// receivable by [`SoftwareKeyboard::get_string()`] and [`SoftwareKeyboard::write_exact()`]. /// /// # Example - /// + /// /// ```no_run /// # fn main() { /// # diff --git a/ctru-rs/src/services/am.rs b/ctru-rs/src/services/am.rs index d302448a..e67282e5 100644 --- a/ctru-rs/src/services/am.rs +++ b/ctru-rs/src/services/am.rs @@ -58,7 +58,7 @@ impl Am { /// Initialize a new service handle. /// /// # Example - /// + /// /// ```no_run /// # use std::error::Error; /// # fn main() -> Result<(), Box> { @@ -81,7 +81,7 @@ impl Am { /// Returns the amount of titles currently installed in a specific install location. /// /// # Example - /// + /// /// ```no_run /// # use std::error::Error; /// # fn main() -> Result<(), Box> { @@ -110,7 +110,7 @@ impl Am { /// Returns the list of titles installed in a specific install location. /// /// # Example - /// + /// /// ```no_run /// # use std::error::Error; /// # fn main() -> Result<(), Box> { @@ -157,14 +157,12 @@ impl Am { Ok(info .into_iter() - .map(|title| { - Title { - id: title.titleID, - mediatype, - size: title.size, - version: title.version, - _am: PhantomData, - } + .map(|title| Title { + id: title.titleID, + mediatype, + size: title.size, + version: title.version, + _am: PhantomData, }) .collect()) } diff --git a/ctru-rs/src/services/apt.rs b/ctru-rs/src/services/apt.rs index e885adf3..1fba0e54 100644 --- a/ctru-rs/src/services/apt.rs +++ b/ctru-rs/src/services/apt.rs @@ -13,9 +13,9 @@ pub struct Apt(()); impl Apt { /// Initialize a new service handle. - /// + /// /// # Example - /// + /// /// ```no_run /// # use std::error::Error; /// # fn main() -> Result<(), Box> { @@ -43,20 +43,20 @@ impl Apt { /// For this reason, its main use is as the condition of a while loop that controls the main logic for your program. /// /// # Example - /// + /// /// ```no_run /// use std::error::Error; /// use ctru::services::apt::Apt; - /// + /// /// // In a simple `main` function, the structure should be the following. /// fn main() -> Result<(), Box> { /// /// let apt = Apt::new()?; - /// + /// /// while apt.main_loop() { /// // Main program logic should be written here. /// } - /// + /// /// // Optional clean-ups after running the application should be written after the main loop. /// # /// # Ok(()) diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index e6465e4b..1e9a0481 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -220,7 +220,7 @@ static GFX_ACTIVE: Mutex = Mutex::new(0); impl Gfx { /// Initialize a new default service handle. - /// + /// /// It's the same as calling: /// /// ```no_run diff --git a/ctru-rs/src/services/ps.rs b/ctru-rs/src/services/ps.rs index fc108fd4..fc20a78c 100644 --- a/ctru-rs/src/services/ps.rs +++ b/ctru-rs/src/services/ps.rs @@ -1,14 +1,15 @@ -//! Process Services. -//! -//! This is used for miscellaneous utility tasks, but -//! is particularly important because it is used to generate random data, which -//! is required for common things like [`HashMap`](std::collections::HashMap). +//! Process Services. +//! +//! This service handles miscellaneous utility tasks used by the various processes. +//! However, it is particularly important because it is used to generate cryptographically secure random data, which +//! is required for commonly used functionality such as hashing (e.g. [`HashMap`](std::collections::HashMap) will not work without it). +//! //! See also use crate::error::ResultCode; use crate::Result; -/// Kind of AES algorithm to use. +/// Type of AES algorithm to use. #[doc(alias = "PS_AESAlgorithm")] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] @@ -59,6 +60,20 @@ pub struct Ps(()); impl Ps { /// Initialize a new service handle. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ps::Ps; + /// + /// let ps = Ps::new()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "psInit")] pub fn new() -> Result { unsafe { @@ -68,6 +83,21 @@ impl Ps { } /// Returns the console's local friend code seed. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ps::Ps; + /// let ps = Ps::new()?; + /// + /// let friend_code_seed = ps.local_friend_code_seed()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "PS_GetLocalFriendCodeSeed")] pub fn local_friend_code_seed(&self) -> crate::Result { let mut seed: u64 = 0; @@ -77,6 +107,21 @@ impl Ps { } /// Returns the console's devide ID. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ps::Ps; + /// let ps = Ps::new()?; + /// + /// let device_id = ps.device_id()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "PS_GetDeviceId")] pub fn device_id(&self) -> crate::Result { let mut id: u32 = 0; @@ -86,6 +131,24 @@ impl Ps { } /// Generates cryptografically secure random bytes and writes them into the `out` buffer. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ps::Ps; + /// let ps = Ps::new()?; + /// + /// let mut buffer = vec![0; 128]; + /// + /// // The buffer is now randomized! + /// ps.generate_random_bytes(&mut buffer)?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "PS_GenerateRandomBytes")] pub fn generate_random_bytes(&self, out: &mut [u8]) -> crate::Result<()> { ResultCode(unsafe { diff --git a/ctru-rs/src/services/romfs.rs b/ctru-rs/src/services/romfs.rs index c1c2d9e2..ad5429ff 100644 --- a/ctru-rs/src/services/romfs.rs +++ b/ctru-rs/src/services/romfs.rs @@ -1,9 +1,14 @@ //! Read-Only Memory FileSystem service. //! +//! This service lets the application access a virtual mounted device created using a folder included within the application bundle. +//! After mounting the RomFS file system, the included files and folders will be accessible exactly like any other file, just by using the drive prefix `romfs:/`. +//! +//! # Usage +//! //! This module only gets compiled if the configured RomFS directory is found and the `romfs` //! feature is enabled. //! -//! Configure the path in Cargo.toml (the default path is "romfs"). Paths are relative to the +//! Configure the path in your project's `Cargo.toml` manifest (the default path is "romfs"). Paths are relative to the //! `CARGO_MANIFEST_DIR` environment variable, which is the directory containing the manifest of //! your package. //! @@ -11,6 +16,8 @@ //! [package.metadata.cargo-3ds] //! romfs_dir = "romfs" //! ``` +//! +//! Alternatively, you can include the RomFS archive manually when building with `3dsxtool`. use crate::error::ResultCode; use std::ffi::CStr; @@ -19,11 +26,6 @@ use std::sync::Mutex; use crate::services::ServiceReference; /// Handle to the RomFS service. -/// -/// This service lets the application access a virtual mounted device created using a folder included within the application bundle. -/// `ctru-rs` will include as RomFS the folder specified in the `Cargo.toml` manifest (or use `./romfs` by default). Look at the [`romfs`](self) module for more information. -/// -/// After mounting the RomFS file system, the included files and folders will be accessible exactly like any other file, just by using the drive prefix `romfs:/`. pub struct RomFS { _service_handler: ServiceReference, } @@ -31,7 +33,24 @@ pub struct RomFS { static ROMFS_ACTIVE: Mutex = Mutex::new(0); impl RomFS { - /// Mount the specified RomFS folder as a virtual drive. + /// Mount the bundled RomFS archive as a virtual drive. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::romfs::RomFS; + /// + /// let romfs = RomFS::new()?; + /// + /// // Remember to include the RomFS archive and to use your actual files! + /// let contents = std::fs::read_to_string("romfs:/test-file.txt"); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "romfsMountSelf")] pub fn new() -> crate::Result { let _service_handler = ServiceReference::new( diff --git a/ctru-rs/src/services/soc.rs b/ctru-rs/src/services/soc.rs index aa450bea..f9cc2586 100644 --- a/ctru-rs/src/services/soc.rs +++ b/ctru-rs/src/services/soc.rs @@ -1,4 +1,7 @@ //! Network Socket service. +//! +//! By using this service the program enables the use of network sockets and utilities such as those found in `std::net`, which are completely inaccessible by default. +//! As such, remember to hold a handle to this service handle while using any network functionality, or else the `std::net` methods will return generic OS errors. use libc::memalign; use std::net::Ipv4Addr; @@ -8,10 +11,7 @@ use crate::error::ResultCode; use crate::services::ServiceReference; use crate::Error; -/// Network socket service -/// -/// Initializing this service will enable the use of network sockets and utilities -/// such as those found in `std::net`. The service will close once this struct gets dropped. +/// Handle to the Network Socket service. pub struct Soc { _service_handler: ServiceReference, sock_3dslink: libc::c_int, @@ -20,22 +20,51 @@ pub struct Soc { static SOC_ACTIVE: Mutex = Mutex::new(0); impl Soc { - /// Initialize a new service handle using a socket buffer size of 0x100000 bytes. + /// Initialize a new service handle using a socket buffer size of `0x100000` bytes. /// /// # Errors /// - /// This function will return an error if the [`Soc`] service is already initialized + /// This function will return an error if the [`Soc`] service is already being used. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::soc::Soc; + /// + /// let soc = Soc::new()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "socInit")] pub fn new() -> crate::Result { Self::init_with_buffer_size(0x100000) } - /// Initialize the Soc service with a custom buffer size in bytes. The size should be - /// 0x100000 bytes or greater. + /// Initialize a new service handle using a custom socket buffer size. + /// + /// The size should be `0x100000` bytes or greater. /// /// # Errors /// - /// This function will return an error if the [`Soc`] service is already initialized + /// This function will return an error if the [`Soc`] service is already being used. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::soc::Soc; + /// + /// let soc = Soc::init_with_buffer_size(0x100000)?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "socInit")] pub fn init_with_buffer_size(num_bytes: usize) -> crate::Result { let _service_handler = ServiceReference::new( @@ -62,20 +91,55 @@ impl Soc { }) } - /// IP Address of the Nintendo 3DS system. + /// Returns the local IP Address of the Nintendo 3DS system. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::soc::Soc; + /// let soc = Soc::new()?; + /// + /// let address = soc.host_address(); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "gethostid")] pub fn host_address(&self) -> Ipv4Addr { 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. + /// Redirect output streams (i.e. `println` and `eprintln`) to the `3dslink` server. + /// + /// Requires `3dslink` >= 0.6.1 and `new-hbmenu` >= 2.3.0 and the use of the `--server` flag. + /// The `--server` flag is also availble to use via `cargo-3ds` if the requirements are met. /// /// # Errors /// - /// Returns an error if a connection cannot be established to the server, or - /// output was already previously redirected. + /// Returns an error if a connection cannot be established to the server, + /// or if the output was already being redirected. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::soc::Soc; + /// let mut soc = Soc::new()?; + /// + /// // Redirect to the `3dslink` server that sent this program. + /// let address = soc.redirect_to_3dslink(true, true)?; + /// + /// println!("I'm visible from a PC!"); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "link3dsConnectToHost")] pub fn redirect_to_3dslink(&mut self, stdout: bool, stderr: bool) -> crate::Result<()> { if self.sock_3dslink >= 0 { diff --git a/ctru-rs/src/services/sslc.rs b/ctru-rs/src/services/sslc.rs index b13fac01..af8b65df 100644 --- a/ctru-rs/src/services/sslc.rs +++ b/ctru-rs/src/services/sslc.rs @@ -9,6 +9,20 @@ pub struct SslC(()); impl SslC { /// Initialize a new service handle. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::sslc::SslC; + /// + /// let sslc = SslC::new()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "sslcInit")] pub fn new() -> crate::Result { unsafe { From db2bb7c7658d394e1b627876980450f43768c883 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sat, 22 Jul 2023 18:07:45 +0200 Subject: [PATCH 19/39] Finished HID and CFGU --- ctru-rs/src/services/cfgu.rs | 117 +++++++++++++++++++++++---- ctru-rs/src/services/hid.rs | 150 +++++++++++++++++++++++++++++++---- 2 files changed, 234 insertions(+), 33 deletions(-) diff --git a/ctru-rs/src/services/cfgu.rs b/ctru-rs/src/services/cfgu.rs index 9afbe7b8..252b11fb 100644 --- a/ctru-rs/src/services/cfgu.rs +++ b/ctru-rs/src/services/cfgu.rs @@ -4,7 +4,7 @@ use crate::error::ResultCode; -/// Console's region. +/// Console region. #[doc(alias = "CFG_Region")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] @@ -56,7 +56,7 @@ pub enum Language { TraditionalChinese = ctru_sys::CFG_LANGUAGE_TW, } -/// 3DS model. +/// Specific model of the console. #[doc(alias = "CFG_SystemModel")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] @@ -75,30 +75,47 @@ pub enum SystemModel { New2DSXL = ctru_sys::CFG_MODEL_N2DSXL, } -/// Represents the configuration service. No actions can be performed -/// until an instance of this struct is created. -/// -/// The service exits when all instances of this struct go out of scope. +/// Handle to the System Configuration service. pub struct Cfgu(()); impl Cfgu { /// Initialize a new service handle. /// - /// # Errors + /// # Example /// - /// This function will return Err if there was an error initializing the - /// CFGU service. + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::cfgu::Cfgu; /// - /// ctrulib services are reference counted, so this function may be called - /// as many times as desired and the service will not exit until all - /// instances of Cfgu drop out of scope. + /// let cfgu = Cfgu::new()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "cfguInit")] pub fn new() -> crate::Result { ResultCode(unsafe { ctru_sys::cfguInit() })?; Ok(Cfgu(())) } - /// Gets system region from secure info + /// Returns the console's region from the system's secure info. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::cfgu::Cfgu; + /// let cfgu = Cfgu::new()?; + /// + /// let region = cfgu.region()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "CFGU_SecureInfoGetRegion")] pub fn region(&self) -> crate::Result { let mut region: u8 = 0; @@ -107,7 +124,22 @@ impl Cfgu { Ok(Region::try_from(region).unwrap()) } - /// Gets system's model + /// Returns the console's model. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::cfgu::Cfgu; + /// let cfgu = Cfgu::new()?; + /// + /// let model = cfgu.model()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "CFGU_GetSystemModel")] pub fn model(&self) -> crate::Result { let mut model: u8 = 0; @@ -116,7 +148,22 @@ impl Cfgu { Ok(SystemModel::try_from(model).unwrap()) } - /// Gets system's language + /// Returns the system language set for the console. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::cfgu::Cfgu; + /// let cfgu = Cfgu::new()?; + /// + /// let language = cfgu.language()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "CFGU_GetSystemLanguage")] pub fn language(&self) -> crate::Result { let mut language: u8 = 0; @@ -125,7 +172,24 @@ impl Cfgu { Ok(Language::try_from(language).unwrap()) } - /// Checks if NFC is supported by the console + /// Check if NFC is supported by the console. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::cfgu::Cfgu; + /// let cfgu = Cfgu::new()?; + /// + /// if cfgu.is_nfc_supported()? { + /// println!("NFC is available!"); + /// } + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "CFGU_IsNFCSupported")] pub fn is_nfc_supported(&self) -> crate::Result { let mut supported: bool = false; @@ -134,7 +198,26 @@ impl Cfgu { Ok(supported) } - /// Check if the console is from the 2DS family (2DS, New2DS, New2DSXL) + /// Check if the console is from the 2DS family ([`Old2DS`](SystemModel::Old2DS), [`New2DSXL`](SystemModel::New2DSXL)). + /// + /// Useful to avoid stereoscopic 3D rendering when working with 2DS consoles. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::cfgu::Cfgu; + /// let cfgu = Cfgu::new()?; + /// + /// if cfgu.is_2ds_family()? { + /// println!("Stereoscopic 3D is not supported."); + /// } + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "CFGU_GetModelNintendo2DS")] pub fn is_2ds_family(&self) -> crate::Result { let mut is_2ds_family: u8 = 0; diff --git a/ctru-rs/src/services/hid.rs b/ctru-rs/src/services/hid.rs index 79bb6dfb..fc73612b 100644 --- a/ctru-rs/src/services/hid.rs +++ b/ctru-rs/src/services/hid.rs @@ -1,15 +1,14 @@ -//! Human-Interface Device service. +//! Human Interface Device service. //! -//! The HID service provides access to user input such as button presses, touch screen presses, -//! and circle pad information. It also provides information from the sound volume slider, -//! the accelerometer, and the gyroscope. +//! The HID service provides read access to user input such as [button presses](Hid::keys_down), [touch screen presses](Hid::touch_position), +//! and [circle pad information](Hid::circlepad_position). It also provides information from the sound volume slider, the accelerometer, and the gyroscope. +// TODO: Implement volume slider, accelerometer and gyroscope + any other missing functionality. use crate::error::ResultCode; use bitflags::bitflags; bitflags! { - /// A set of flags corresponding to the button and directional pad - /// inputs on the 3DS + /// A set of flags corresponding to the button and directional pad inputs present on the 3DS. #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] pub struct KeyPad: u32 { /// A button. @@ -72,10 +71,7 @@ bitflags! { } } -/// A reference-counted handle to the HID service. The service is closed -/// when all instances of this struct fall out of scope. -/// -/// This service requires no special permissions to use. +/// Handle to the HID service. pub struct Hid(()); impl Hid { @@ -84,8 +80,21 @@ impl Hid { /// # Errors /// /// This function will return an error if the service was unable to be initialized. - /// Since this service requires no special or elevated permissions, errors are - /// rare in practice. + /// Since this service requires no special or elevated permissions, errors are rare in practice. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::hid::Hid; + /// + /// let hid = Hid::new()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "hidInit")] pub fn new() -> crate::Result { unsafe { @@ -94,9 +103,25 @@ impl Hid { } } - /// Scans the HID service for all user input occurring on the current - /// frame. This function should be called on every frame when polling + /// Scan the HID service for all user input occurring on the current frame. + /// + /// This function should be called on every frame when polling /// for user input. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::hid::Hid; + /// let mut hid = Hid::new()?; + /// + /// hid.scan_input(); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "hidScanInput")] pub fn scan_input(&mut self) { unsafe { ctru_sys::hidScanInput() }; @@ -104,6 +129,25 @@ impl Hid { /// Returns a bitflag struct representing which buttons have just been pressed /// on the current frame (and were not pressed on the previous frame). + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::hid::{Hid, KeyPad}; + /// let mut hid = Hid::new()?; + /// + /// hid.scan_input(); + /// + /// if hid.keys_down().contains(KeyPad::A) { + /// println!("You just pressed the A button!") + /// } + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "hidKeysDown")] pub fn keys_down(&self) -> KeyPad { unsafe { @@ -114,6 +158,25 @@ impl Hid { /// Returns a bitflag struct representing which buttons have been held down /// during the current frame. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::hid::{Hid, KeyPad}; + /// let mut hid = Hid::new()?; + /// + /// hid.scan_input(); + /// + /// if hid.keys_held().contains(KeyPad::START) { + /// println!("You are holding the START button!") + /// } + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "hidKeysHeld")] pub fn keys_held(&self) -> KeyPad { unsafe { @@ -124,6 +187,25 @@ impl Hid { /// Returns a bitflag struct representing which buttons have just been released on /// the current frame. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::hid::{Hid, KeyPad}; + /// let mut hid = Hid::new()?; + /// + /// hid.scan_input(); + /// + /// if hid.keys_held().contains(KeyPad::B) { + /// println!("You have released the B button!") + /// } + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "hidKeysUp")] pub fn keys_up(&self) -> KeyPad { unsafe { @@ -137,13 +219,31 @@ impl Hid { /// # Notes /// /// (0, 0) represents the top left corner of the screen. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::hid::Hid; + /// let mut hid = Hid::new()?; + /// + /// hid.scan_input(); + /// + /// let (touch_x, touch_y) = hid.touch_position(); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "hidTouchRead")] - pub fn touch_position(&mut self) -> (u16, u16) { + pub fn touch_position(&self) -> (u16, u16) { let mut res = ctru_sys::touchPosition { px: 0, py: 0 }; unsafe { ctru_sys::hidTouchRead(&mut res); } + (res.px, res.py) } @@ -152,13 +252,31 @@ impl Hid { /// # Notes /// /// (0, 0) represents the center of the circle pad. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::hid::Hid; + /// let mut hid = Hid::new()?; + /// + /// hid.scan_input(); + /// + /// let (pad_x, pad_y) = hid.circlepad_position(); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "hidCircleRead")] - pub fn circlepad_position(&mut self) -> (i16, i16) { + pub fn circlepad_position(&self) -> (i16, i16) { let mut res = ctru_sys::circlePosition { dx: 0, dy: 0 }; unsafe { ctru_sys::hidCircleRead(&mut res); } + (res.dx, res.dy) } } From 1245860abaedf6457e53f4396ba4975d44bb2f1b Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sat, 22 Jul 2023 20:03:01 +0200 Subject: [PATCH 20/39] Finish up GFX --- ctru-rs/src/services/fs.rs | 18 ++--- ctru-rs/src/services/gfx.rs | 138 ++++++++++++++++++++++++++++----- ctru-rs/src/services/gspgpu.rs | 2 +- 3 files changed, 127 insertions(+), 31 deletions(-) diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index 446be7ed..464d9801 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -19,23 +19,23 @@ use widestring::{WideCStr, WideCString}; bitflags! { #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] struct FsOpen: u32 { - const FS_OPEN_READ = 1; - const FS_OPEN_WRITE = 2; - const FS_OPEN_CREATE = 4; + const FS_OPEN_READ = ctru_sys::FS_OPEN_READ; + const FS_OPEN_WRITE = ctru_sys::FS_OPEN_WRITE; + const FS_OPEN_CREATE = ctru_sys::FS_OPEN_CREATE; } #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] struct FsWrite: u32 { - const FS_WRITE_FLUSH = 1; - const FS_WRITE_UPDATE_TIME = 256; + const FS_WRITE_FLUSH = ctru_sys::FS_WRITE_FLUSH; + const FS_WRITE_UPDATE_TIME = ctru_sys::FS_WRITE_UPDATE_TIME; } #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] struct FsAttribute: u32 { - const FS_ATTRIBUTE_DIRECTORY = 1; - const FS_ATTRIBUTE_HIDDEN = 256; - const FS_ATTRIBUTE_ARCHIVE = 65536; - const FS_ATTRIBUTE_READ_ONLY = 16777216; + const FS_ATTRIBUTE_DIRECTORY = ctru_sys::FS_ATTRIBUTE_DIRECTORY; + const FS_ATTRIBUTE_HIDDEN = ctru_sys::FS_ATTRIBUTE_HIDDEN; + const FS_ATTRIBUTE_ARCHIVE = ctru_sys::FS_ATTRIBUTE_ARCHIVE; + const FS_ATTRIBUTE_READ_ONLY = ctru_sys::FS_ATTRIBUTE_READ_ONLY; } } diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index 1e9a0481..5a2fc620 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -1,4 +1,7 @@ //! Graphics service. +//! +//! The GFX service controls (in a somewhat high-level way) the console's LCD screens. +//! The screens are subordinate to the GFX service handle and can be used by only one borrower at a time. use std::cell::{Ref, RefCell, RefMut}; use std::marker::PhantomData; @@ -20,6 +23,8 @@ mod private { impl Sealed for BottomScreen {} } +/// Trait to handle common functionality for all screens. +/// /// This trait is implemented by the screen structs for working with frame buffers and /// drawing to the screens. Graphics-related code can be made generic over this /// trait to work with any of the given screens. @@ -75,28 +80,33 @@ pub trait Screen: private::Sealed { } } -/// The top screen. Mutable access to this struct is required to write to the top -/// screen's frame buffer. To enable 3D mode, it can be converted into a [`TopScreen3D`]. +/// The top LCD screen. +/// +/// Mutable access to this struct is required to write to the top screen's frame buffer. +/// +/// To enable 3D mode, it can be converted into a [`TopScreen3D`]. pub struct TopScreen { left: TopScreenLeft, right: TopScreenRight, } +/// The top LCD screen set in stereoscopic 3D mode. +/// /// A helper container for both sides of the top screen. Once the [`TopScreen`] is /// converted into this, 3D mode will be enabled until this struct is dropped. pub struct TopScreen3D<'screen> { screen: &'screen RefCell, } -/// A screen that can have its frame buffers swapped, if double buffering is enabled. +/// Trait for screens that can have its frame buffers swapped, when double buffering is enabled. /// /// This trait applies to all [`Screen`]s that have swappable frame buffers. pub trait Swap: private::Sealed { /// Swaps the video buffers. /// - /// If double buffering is disabled, "swapping" the buffers has the side effect - /// of committing any configuration changes to the buffers (e.g. [`TopScreen::set_wide_mode`], - /// [`Screen::set_framebuffer_format`], [`Screen::set_double_buffering`]). + /// Even if double buffering is disabled, "swapping" the buffers has the side effect + /// of committing any configuration changes to the buffers (e.g. [`TopScreen::set_wide_mode()`], + /// [`Screen::set_framebuffer_format()`], [`Screen::set_double_buffering()`]), so it should still be used. /// /// This should be called once per frame at most. #[doc(alias = "gfxScreenSwapBuffers")] @@ -127,11 +137,13 @@ impl Swap for BottomScreen { } } -/// A screen with buffers that can be flushed. This trait applies to any [`Screen`] -/// that has data written to its frame buffer. +/// A screen with buffers that can be flushed. +/// +/// This trait applies to any [`Screen`] that has data written to its frame buffer. pub trait Flush: private::Sealed { - /// Flushes the video buffer(s) for this screen. Note that you must still call - /// [`Swap::swap_buffers`] after this method for the buffer contents to be displayed. + /// Flushes the video buffer(s) for this screen. + /// + /// Note that you must still call [`Swap::swap_buffers`] after this method for the buffer contents to be displayed. #[doc(alias = "gfxFlushBuffers")] fn flush_buffers(&mut self); } @@ -170,14 +182,16 @@ pub struct TopScreenLeft; #[non_exhaustive] pub struct TopScreenRight; -/// The bottom screen. Mutable access to this struct is required to write to the -/// bottom screen's frame buffer. +/// The bottom LCD screen. +/// +/// Mutable access to this struct is required to write to the bottom screen's frame buffer. #[derive(Debug)] #[non_exhaustive] pub struct BottomScreen; -/// Representation of a framebuffer for one [`Side`] of the top screen, or the -/// entire bottom screen. The inner pointer is only valid for one frame if double +/// Representation of a framebuffer for one [`Side`] of the top screen, or the entire bottom screen. +/// +/// The inner pointer is only valid for one frame if double /// buffering is enabled. Data written to `ptr` will be rendered to the screen. #[derive(Debug)] pub struct RawFrameBuffer<'screen> { @@ -191,7 +205,7 @@ pub struct RawFrameBuffer<'screen> { screen: PhantomData<&'screen mut dyn Screen>, } -/// Side of top screen framebuffer +/// Side of the [`TopScreen`]'s framebuffer. /// /// The top screen of the 3DS can have two separate sets of framebuffers to support its 3D functionality #[doc(alias = "gfx3dSide_t")] @@ -204,10 +218,10 @@ pub enum Side { Right = ctru_sys::GFX_RIGHT, } -/// A handle to libctru's gfx module. This module is a wrapper around the GSPGPU service that -/// provides helper functions and utilities for software rendering. +/// Handle to the GFX service. /// -/// The service exits when this struct is dropped. +/// This service is a wrapper around the lower-level [GSPGPU](crate::services::gspgpu) service that +/// provides helper functions and utilities for software rendering. pub struct Gfx { /// Top screen representation. pub top_screen: RefCell, @@ -221,6 +235,8 @@ static GFX_ACTIVE: Mutex = Mutex::new(0); impl Gfx { /// Initialize a new default service handle. /// + /// # Notes + /// /// It's the same as calling: /// /// ```no_run @@ -228,9 +244,23 @@ impl Gfx { /// # fn main() -> Result<(), Box> { /// # /// # use ctru::services::gfx::Gfx; - /// use ctru::services::gspgpu::FramebufferFormat; + /// # use ctru::services::gspgpu::FramebufferFormat; + /// # + /// Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false)?; + /// # + /// # Ok(()) + /// # } + /// ``` + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::gfx::Gfx; /// - /// Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false); + /// let gfx = Gfx::new()?; /// # /// # Ok(()) /// # } @@ -243,6 +273,22 @@ impl Gfx { /// Initialize a new service handle with the chosen framebuffer formats for the top and bottom screens. /// /// Use [`Gfx::new()`] instead of this function to initialize the module with default parameters + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::{gfx::Gfx, gspgpu::FramebufferFormat}; + /// + /// // Top screen uses RGBA8, bottom screen uses RGB565. + /// // The screen buffers are allocated in the standard HEAP memory, and not in VRAM. + /// let gfx = Gfx::with_formats(FramebufferFormat::Rgba8, FramebufferFormat::Rgb565, false)?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "gfxInit")] pub fn with_formats( top_fb_fmt: FramebufferFormat, @@ -267,9 +313,32 @@ impl Gfx { }) } - /// Waits for the vertical blank interrupt + /// Waits for the vertical blank event. /// /// Use this to synchronize your application with the refresh rate of the LCD screens + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::{apt::Apt, gfx::Gfx}; + /// let apt = Apt::new()?; + /// let gfx = Gfx::new()?; + /// + /// // Simple main loop. + /// while apt.main_loop() { + /// // Main program logic + /// + /// // Wait for the screens to refresh. + /// // This blocks the current thread to make it run at 60Hz. + /// gfx.wait_for_vblank(); + /// } + /// # + /// # Ok(()) + /// # } + /// ``` pub fn wait_for_vblank(&self) { gspgpu::wait_for_event(gspgpu::Event::VBlank0, true); } @@ -289,6 +358,33 @@ impl TopScreen3D<'_> { } } +/// Convert the [`TopScreen`] into a [`TopScreen3D`] and activate stereoscopic 3D. +/// +/// # Example +/// +/// ```no_run +/// # use std::error::Error; +/// # fn main() -> Result<(), Box> { +/// # +/// use ctru::services::gfx::{Gfx, TopScreen, TopScreen3D}; +/// let gfx = Gfx::new()?; +/// +/// let mut top_screen = TopScreen3D::from(&gfx.top_screen); +/// +/// let (left, right) = top_screen.split_mut(); +/// +/// // Rendering must be done twice for each side +/// // (with a slight variation in perspective to simulate the eye-to-eye distance). +/// render(left); +/// render(right); +/// # +/// # Ok(()) +/// # } +/// # +/// # use ctru::services::gfx::Screen; +/// # use std::cell::RefMut; +/// # fn render(screen: RefMut<'_, dyn Screen>) {} +/// ``` impl<'screen> From<&'screen RefCell> for TopScreen3D<'screen> { #[doc(alias = "gfxSet3D")] fn from(top_screen: &'screen RefCell) -> Self { diff --git a/ctru-rs/src/services/gspgpu.rs b/ctru-rs/src/services/gspgpu.rs index cb3e67c5..81872d04 100644 --- a/ctru-rs/src/services/gspgpu.rs +++ b/ctru-rs/src/services/gspgpu.rs @@ -22,7 +22,7 @@ pub enum Event { } #[doc(alias = "GSPGPU_FramebufferFormat")] -/// Framebuffer formats supported by the 3DS. +/// Framebuffer formats supported by the 3DS' screens. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum FramebufferFormat { From 3085b3e1c2c40d78a555b43fa8544e4dfeaef6be Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Tue, 25 Jul 2023 12:34:38 +0200 Subject: [PATCH 21/39] Docs-rs rules for ctru-sys --- ctru-sys/Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ctru-sys/Cargo.toml b/ctru-sys/Cargo.toml index 1420ebe6..c6bb12f7 100644 --- a/ctru-sys/Cargo.toml +++ b/ctru-sys/Cargo.toml @@ -16,3 +16,7 @@ libc = { version = "0.2.121", default-features = false } [build-dependencies] which = "4.4.0" + +[package.metadata.docs.rs] +default-target = "armv6k-nintendo-3ds" +cargo-args = ["-Z", "build-std"] From ef4860cf69b93d1438da93cccce2631c180b23a7 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Tue, 25 Jul 2023 16:01:47 +0200 Subject: [PATCH 22/39] Finalize NDSP and Wave --- ctru-rs/examples/audio-filters.rs | 4 +- ctru-rs/src/services/ndsp/mod.rs | 323 +++++++++++++++++++++++++++--- ctru-rs/src/services/ndsp/wave.rs | 61 +++++- 3 files changed, 347 insertions(+), 41 deletions(-) diff --git a/ctru-rs/examples/audio-filters.rs b/ctru-rs/examples/audio-filters.rs index 3ef76a6a..34fa470b 100644 --- a/ctru-rs/examples/audio-filters.rs +++ b/ctru-rs/examples/audio-filters.rs @@ -5,7 +5,7 @@ use std::f32::consts::PI; use ctru::linear::LinearAllocator; use ctru::prelude::*; use ctru::services::ndsp::{ - wave::{Wave, WaveStatus}, + wave::{Status, Wave}, AudioFormat, AudioMix, InterpolationType, Ndsp, OutputMode, }; @@ -146,7 +146,7 @@ fn main() { }; let status = current.status(); - if let WaveStatus::Done = status { + if let Status::Done = status { fill_buffer(current.get_buffer_mut().unwrap(), NOTEFREQ[note]); channel_zero.queue_wave(current).unwrap(); diff --git a/ctru-rs/src/services/ndsp/mod.rs b/ctru-rs/src/services/ndsp/mod.rs index f815fdb1..fc765846 100644 --- a/ctru-rs/src/services/ndsp/mod.rs +++ b/ctru-rs/src/services/ndsp/mod.rs @@ -1,7 +1,11 @@ //! NDSP (Audio) service. +//! +//! The NDSP service is used to handle communications to the DSP processor present on the console's motherboard. +//! Thanks to the DSP processor the program can play sound effects and music on the console's built-in speakers or to any audio device +//! connected via the audio jack. pub mod wave; -use wave::{Wave, WaveStatus}; +use wave::{Status, Wave}; use crate::error::ResultCode; use crate::services::ServiceReference; @@ -27,7 +31,7 @@ pub enum OutputMode { Surround = ctru_sys::NDSP_OUTPUT_SURROUND, } -/// Audio PCM format. +/// PCM formats supported by the audio engine. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum AudioFormat { @@ -35,13 +39,13 @@ pub enum AudioFormat { PCM8Mono = ctru_sys::NDSP_FORMAT_MONO_PCM8, /// PCM 16bit single-channel. PCM16Mono = ctru_sys::NDSP_FORMAT_MONO_PCM16, - /// PCM 8bit dual-channel. + /// PCM 8bit interleaved dual-channel. PCM8Stereo = ctru_sys::NDSP_FORMAT_STEREO_PCM8, - /// PCM 16bit dual-channel. + /// PCM 16bit interleaved dual-channel. PCM16Stereo = ctru_sys::NDSP_FORMAT_STEREO_PCM16, } -/// Representation of volume mix for a channel. +/// Representation of the volume mix for a channel. #[derive(Copy, Clone, Debug, PartialEq)] pub struct AudioMix { raw: [f32; 12], @@ -60,16 +64,16 @@ pub enum InterpolationType { None = ctru_sys::NDSP_INTERP_NONE, } -/// Error enum returned by NDSP methods. +/// Errors returned by [`ndsp`](self) functions. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum NdspError { - /// Channel ID + /// Channel with the specified ID does not exist. InvalidChannel(u8), - /// Channel ID + /// Channel with the specified ID is already being used. ChannelAlreadyInUse(u8), - /// Channel ID + /// The wave is already busy playing in the channel with the specified ID. WaveBusy(u8), - /// Sample amount requested, Max sample amount + /// The sample amount requested was larger than the maximum. SampleCountOutOfBounds(usize, usize), } @@ -79,13 +83,15 @@ pub enum NdspError { /// /// # Default /// -/// NDSP initialises all channels with default values on creation, but the developer is supposed to change these values to correctly work with the service. +/// NDSP initialises all channels with default values on initialization, but the developer is supposed to change these values to correctly work with the service. /// /// In particular: /// - Default audio format is set to [`AudioFormat::PCM16Mono`]. /// - Default sample rate is set to 1 Hz. /// - Default interpolation type is set to [`InterpolationType::Polyphase`]. /// - Default mix is set to [`AudioMix::default()`] +/// +/// The handle to a channel can be retrieved with [`Ndsp::channel()`] pub struct Channel<'ndsp> { id: u8, _rf: RefMut<'ndsp, ()>, // we don't need to hold any data @@ -93,10 +99,9 @@ pub struct Channel<'ndsp> { static NDSP_ACTIVE: Mutex = Mutex::new(0); -/// Handler of the DSP service and DSP processor. +/// Handle to the DSP service. /// -/// This is the main struct to handle audio playback using the 3DS' speakers and headphone jack. -/// Only one "instance" of this struct can exist at a time. +/// Only one handle for this service can exist at a time. pub struct Ndsp { _service_handler: ServiceReference, channel_flags: [RefCell<()>; NUMBER_OF_CHANNELS as usize], @@ -107,8 +112,22 @@ impl Ndsp { /// /// # Errors /// - /// This function will return an error if an instance of the `Ndsp` struct already exists + /// This function will return an error if an instance of the [`Ndsp`] struct already exists /// or if there are any issues during initialization. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ndsp::Ndsp; + /// + /// let ndsp = Ndsp::new()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "ndspInit")] pub fn new() -> crate::Result { let _service_handler = ServiceReference::new( @@ -135,6 +154,21 @@ impl Ndsp { /// # Errors /// /// An error will be returned if the channel ID is not between 0 and 23 or if the specified channel is already being used. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ndsp::Ndsp; + /// let ndsp = Ndsp::new()?; + /// + /// let channel_0 = ndsp.channel(0)?; + /// # + /// # Ok(()) + /// # } + /// ``` pub fn channel(&self, id: u8) -> std::result::Result { let in_bounds = self.channel_flags.get(id as usize); @@ -150,7 +184,23 @@ impl Ndsp { } } - /// Set the audio output mode. Defaults to `OutputMode::Stereo`. + /// Set the audio output mode. Defaults to [`OutputMode::Stereo`]. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ndsp::{Ndsp, OutputMode}; + /// let mut ndsp = Ndsp::new()?; + /// + /// // Use dual-channel output. + /// ndsp.set_output_mode(OutputMode::Stereo); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "ndspSetOutputMode")] pub fn set_output_mode(&mut self, mode: OutputMode) { unsafe { ctru_sys::ndspSetOutputMode(mode.into()) }; @@ -158,31 +208,114 @@ impl Ndsp { } impl Channel<'_> { - /// Reset the channel + /// Reset the channel (clear the queue and reset parameters). + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ndsp::Ndsp; + /// let ndsp = Ndsp::new()?; + /// let mut channel_0 = ndsp.channel(0)?; + /// + /// channel_0.reset(); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "ndspChnReset")] pub fn reset(&mut self) { unsafe { ctru_sys::ndspChnReset(self.id.into()) }; } - /// Initialize the channel's parameters + /// Initialize the channel's parameters with default values. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ndsp::Ndsp; + /// let ndsp = Ndsp::new()?; + /// let mut channel_0 = ndsp.channel(0)?; + /// + /// channel_0.init_parameters(); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "ndspChnInitParams")] - pub fn init_parameters(&self) { + pub fn init_parameters(&mut self) { unsafe { ctru_sys::ndspChnInitParams(self.id.into()) }; } /// Returns whether the channel is playing any audio. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ndsp::Ndsp; + /// let ndsp = Ndsp::new()?; + /// let mut channel_0 = ndsp.channel(0)?; + /// + /// // The channel is not playing any audio. + /// assert!(!channel_0.is_playing()); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "ndspChnIsPlaying")] pub fn is_playing(&self) -> bool { unsafe { ctru_sys::ndspChnIsPlaying(self.id.into()) } } /// Returns whether the channel's playback is currently paused. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ndsp::Ndsp; + /// let ndsp = Ndsp::new()?; + /// let mut channel_0 = ndsp.channel(0)?; + /// + /// // The channel is not paused. + /// assert!(!channel_0.is_paused()); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "ndspChnIsPaused")] pub fn is_paused(&self) -> bool { unsafe { ctru_sys::ndspChnIsPaused(self.id.into()) } } /// Returns the channel's index. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ndsp::Ndsp; + /// let ndsp = Ndsp::new()?; + /// let mut channel_0 = ndsp.channel(0)?; + /// + /// // The channel's index is 0. + /// assert_eq!(channel_0.id(), 0); + /// # + /// # Ok(()) + /// # } + /// ``` pub fn id(&self) -> u8 { self.id } @@ -202,41 +335,148 @@ impl Channel<'_> { } /// Pause or un-pause the channel's playback. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ndsp::Ndsp; + /// let ndsp = Ndsp::new()?; + /// let mut channel_0 = ndsp.channel(0)?; + /// + /// channel_0.set_paused(true); + /// + /// // The channel is paused. + /// assert!(channel_0.is_paused()); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "ndspChnSetPaused")] pub fn set_paused(&mut self, state: bool) { unsafe { ctru_sys::ndspChnSetPaused(self.id.into(), state) }; } /// Set the channel's output format. - /// Change this setting based on the used sample's format. + /// + /// Change this setting based on the used wave's format. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ndsp::{AudioFormat, Ndsp}; + /// let ndsp = Ndsp::new()?; + /// let mut channel_0 = ndsp.channel(0)?; + /// + /// // Use the PCM16 interleaved dual-channel audio format. + /// channel_0.set_format(AudioFormat::PCM16Stereo); + /// # + /// # Ok(()) + /// # } + /// ``` + // TODO: Channels treat all waves as equal and do not read their format when playing them. Another good reason to re-write the service. #[doc(alias = "ndspChnSetFormat")] pub fn set_format(&mut self, format: AudioFormat) { unsafe { ctru_sys::ndspChnSetFormat(self.id.into(), format.into()) }; } /// Set the channel's interpolation mode. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ndsp::{InterpolationType, Ndsp}; + /// let ndsp = Ndsp::new()?; + /// let mut channel_0 = ndsp.channel(0)?; + /// + /// // Use linear interpolation within frames. + /// channel_0.set_interpolation(InterpolationType::Linear); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "ndspChnSetInterp")] pub fn set_interpolation(&mut self, interp_type: InterpolationType) { unsafe { ctru_sys::ndspChnSetInterp(self.id.into(), interp_type.into()) }; } /// Set the channel's volume mix. + /// + /// Look at [`AudioMix`] for more information on the volume mix. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # use std::default::Default; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ndsp::{AudioMix, Ndsp}; + /// let ndsp = Ndsp::new()?; + /// let mut channel_0 = ndsp.channel(0)?; + /// + /// // Front-left and front-right channel maxed. + /// channel_0.set_mix(&AudioMix::default()); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "ndspChnSetMix")] pub fn set_mix(&mut self, mix: &AudioMix) { unsafe { ctru_sys::ndspChnSetMix(self.id.into(), mix.as_raw().as_ptr().cast_mut()) } } - /// Set the channel's rate of sampling. + /// Set the channel's rate of sampling in hertz. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ndsp::Ndsp; + /// let ndsp = Ndsp::new()?; + /// let mut channel_0 = ndsp.channel(0)?; + /// + /// // Standard CD sample rate. (44100 Hz) + /// channel_0.set_sample_rate(44100.); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "ndspChnSetRate")] pub fn set_sample_rate(&mut self, rate: f32) { unsafe { ctru_sys::ndspChnSetRate(self.id.into(), rate) }; } - // `ndspChnSetAdpcmCoefs` isn't wrapped on purpose. - // DSPADPCM is a proprietary format used by Nintendo, unavailable by "normal" means. - // We suggest using other wave formats when developing homebrew applications. + // TODO: wrap ADPCM format helpers. /// Clear the wave buffer queue and stop playback. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::ndsp::Ndsp; + /// let ndsp = Ndsp::new()?; + /// let mut channel_0 = ndsp.channel(0)?; + /// + /// // Clear the audio queue and stop playback. + /// channel_0.clear_queue(); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "ndspChnWaveBufClear")] pub fn clear_queue(&mut self) { unsafe { ctru_sys::ndspChnWaveBufClear(self.id.into()) }; @@ -249,10 +489,36 @@ impl Channel<'_> { /// /// `libctru` expects the user to manually keep the info data (in this case [`Wave`]) alive during playback. /// To ensure safety, checks within [`Wave`] will clear the whole channel queue if any queued [`Wave`] is dropped prematurely. + /// + /// # Example + /// + /// ```no_run + /// # #![feature(allocator_api)] + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// # use ctru::linear::LinearAllocator; + /// use ctru::services::ndsp::{AudioFormat, Ndsp, wave::Wave}; + /// let ndsp = Ndsp::new()?; + /// let mut channel_0 = ndsp.channel(0)?; + /// + /// # let _audio_data = Box::new_in([0u8; 96], LinearAllocator); + /// + /// // Provide your own audio data. + /// let mut wave = Wave::new(_audio_data, AudioFormat::PCM16Stereo, false); + /// + /// // Clear the audio queue and stop playback. + /// channel_0.queue_wave(&mut wave); + /// # + /// # Ok(()) + /// # } + /// ``` + // TODO: Find a better way to handle the wave lifetime problem. + // These "alive wave" shenanigans are the most substantial reason why I'd like to fully re-write this service in Rust. #[doc(alias = "ndspChnWaveBufAdd")] pub fn queue_wave(&mut self, wave: &mut Wave) -> std::result::Result<(), NdspError> { match wave.status() { - WaveStatus::Playing | WaveStatus::Queued => return Err(NdspError::WaveBusy(self.id)), + Status::Playing | Status::Queued => return Err(NdspError::WaveBusy(self.id)), _ => (), } @@ -354,9 +620,10 @@ impl Channel<'_> { impl AudioFormat { /// Returns the amount of bytes needed to store one sample /// - /// Eg. - /// 8 bit mono formats return 1 (byte) - /// 16 bit stereo (dual-channel) formats return 4 (bytes) + /// # Example + /// + /// - 8 bit mono formats return 1 (byte) + /// - 16 bit stereo (dual-channel) formats return 4 (bytes) pub const fn size(self) -> usize { match self { Self::PCM8Mono => 1, diff --git a/ctru-rs/src/services/ndsp/wave.rs b/ctru-rs/src/services/ndsp/wave.rs index 2819dbdd..72cee96f 100644 --- a/ctru-rs/src/services/ndsp/wave.rs +++ b/ctru-rs/src/services/ndsp/wave.rs @@ -1,9 +1,13 @@ -//! Audio wave representation. +//! Audio wave. +//! +//! This modules has all methods and structs required to work with audio waves meant to be played via the [`ndsp`](crate::services::ndsp) service. use super::{AudioFormat, NdspError}; use crate::linear::LinearAllocator; -/// Informational struct holding the raw audio data and playback info. This corresponds to [`ctru_sys::ndspWaveBuf`]. +/// Informational struct holding the raw audio data and playback info. +/// +/// You can play audio [`Wave`]s by using [`Channel::queue_wave()`](super::Channel::queue_wave). pub struct Wave { /// Data block of the audio wave (and its format information). buffer: Box<[u8], LinearAllocator>, @@ -15,8 +19,8 @@ pub struct Wave { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u8)] -/// Enum representing the playback status of a [`Wave`]. -pub enum WaveStatus { +/// Playback status of a [`Wave`]. +pub enum Status { /// Wave has never been used. Free = ctru_sys::NDSP_WBUF_FREE as u8, /// Wave is currently queued for usage. @@ -28,7 +32,23 @@ pub enum WaveStatus { } impl Wave { - /// Build a new playable wave object from a raw buffer on LINEAR memory and a some info. + /// Build a new playable wave object from a raw buffer on [LINEAR memory](`crate::linear`) and a some info. + /// + /// # Example + /// + /// ```no_run + /// # #![feature(allocator_api)] + /// # fn main() { + /// # + /// use ctru::linear::LinearAllocator; + /// use ctru::services::ndsp::{AudioFormat, wave::Wave}; + /// + /// // Zeroed box allocated in the LINEAR memory. + /// let audio_data = Box::new_in([0u8; 96], LinearAllocator); + /// + /// let wave = Wave::new(audio_data, AudioFormat::PCM16Stereo, false); + /// # } + /// ``` pub fn new( buffer: Box<[u8], LinearAllocator>, audio_format: AudioFormat, @@ -79,7 +99,7 @@ impl Wave { /// with the id to the channel in which it's queued. pub fn get_buffer_mut(&mut self) -> Result<&mut [u8], NdspError> { match self.status() { - WaveStatus::Playing | WaveStatus::Queued => { + Status::Playing | Status::Queued => { Err(NdspError::WaveBusy(self.played_on_channel.unwrap())) } _ => Ok(&mut self.buffer), @@ -87,7 +107,26 @@ impl Wave { } /// Return this wave's playback status. - pub fn status(&self) -> WaveStatus { + /// + /// # Example + /// + /// ```no_run + /// # #![feature(allocator_api)] + /// # fn main() { + /// # + /// # use ctru::linear::LinearAllocator; + /// # let _audio_data = Box::new_in([0u8; 96], LinearAllocator); + /// # + /// use ctru::services::ndsp::{AudioFormat, wave::{Wave, Status}}; + /// + /// // Provide your own audio data. + /// let wave = Wave::new(_audio_data, AudioFormat::PCM16Stereo, false); + /// + /// // The `Wave` is free if never played before. + /// assert!(matches!(wave.status(), Status::Free)); + /// # } + /// ``` + pub fn status(&self) -> Status { self.raw_data.status.try_into().unwrap() } @@ -118,7 +157,7 @@ impl Wave { /// # Note /// /// Operations of this kind are particularly useful to allocate memory pools - /// for VBR (Variable BitRate) Formats, like OGG Vorbis. + /// for VBR (Variable BitRate) formats, like OGG Vorbis. /// /// # Errors /// @@ -126,7 +165,7 @@ impl Wave { /// or if the [`Wave`] is currently queued. pub fn set_sample_count(&mut self, sample_count: usize) -> Result<(), NdspError> { match self.status() { - WaveStatus::Playing | WaveStatus::Queued => { + Status::Playing | Status::Queued => { return Err(NdspError::WaveBusy(self.played_on_channel.unwrap())); } _ => (), @@ -144,7 +183,7 @@ impl Wave { } } -impl TryFrom for WaveStatus { +impl TryFrom for Status { type Error = &'static str; fn try_from(value: u8) -> Result { @@ -163,7 +202,7 @@ impl Drop for Wave { // This was the only way I found I could check for improper drops of `Wave`. // A panic was considered, but it would cause issues with drop order against `Ndsp`. match self.status() { - WaveStatus::Free | WaveStatus::Done => (), + Status::Free | Status::Done => (), // If the status flag is "unfinished" _ => { // The unwrap is safe, since it must have a value in the case the status is "unfinished". From 3d3a59a084c9430d33aad12677ea6734e8c95ee9 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Wed, 26 Jul 2023 13:39:46 +0200 Subject: [PATCH 23/39] Finalize CAM service --- ctru-rs/src/services/cam.rs | 343 +++++++++++++++++++++++++----------- ctru-rs/src/services/fs.rs | 1 + 2 files changed, 244 insertions(+), 100 deletions(-) diff --git a/ctru-rs/src/services/cam.rs b/ctru-rs/src/services/cam.rs index 717694e6..ff9bd5bc 100644 --- a/ctru-rs/src/services/cam.rs +++ b/ctru-rs/src/services/cam.rs @@ -1,17 +1,14 @@ //! Camera service. //! //! The CAM service provides access to the built-in cameras. [`Camera`]s can return images -//! in the form of byte vectors which can be displayed or used in other ways. +//! in the form of byte vectors which can be displayed to the screen or used in other ways. use crate::error::{Error, ResultCode}; use crate::services::gspgpu::FramebufferFormat; use ctru_sys::Handle; use std::time::Duration; -/// A reference-counted handle to the CAM service and the usable cameras. -/// The service is closed when all instances of this struct fall out of scope. -/// -/// This service requires no special permissions to use. +/// Handle to the Camera service. #[non_exhaustive] pub struct Cam { /// Inside-facing camera. @@ -24,22 +21,26 @@ pub struct Cam { pub both_outer_cams: BothOutwardCam, } -/// Flag to pass to [`Camera::flip_image`] +/// Different kinds of flip modes. +/// +/// See [`Camera::flip_image()`] to learn how to use this. #[doc(alias = "CAMU_Flip")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum FlipMode { - /// No flip applied. + /// No flip. None = ctru_sys::FLIP_NONE, - /// Horizontal flip applied. + /// Horizontal flip. Horizontal = ctru_sys::FLIP_HORIZONTAL, - /// Vertical flip applied. + /// Vertical flip. Vertical = ctru_sys::FLIP_VERTICAL, - /// Both vertical and horizontal flip applied. + /// Both vertical and horizontal flip. Reverse = ctru_sys::FLIP_REVERSE, } -/// Flag to pass to [`Camera::set_view_size`] +/// Size of the camera view. +/// +/// See [`Camera::set_view_size()`] to learn how to use this. #[doc(alias = "CAMU_Size")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] @@ -66,7 +67,9 @@ pub enum ViewSize { DSX4 = ctru_sys::SIZE_DS_LCDx4, } -/// Flag to pass to [`Camera::set_frame_rate`] +/// Framerate settings. +/// +/// See [`Camera::set_frame_rate()`] to learn how to use this. #[doc(alias = "CAMU_FramRate")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] @@ -99,27 +102,30 @@ pub enum FrameRate { Fps30To10 = ctru_sys::FRAME_RATE_30_TO_10, } -/// Flag to pass to [`Camera::set_white_balance`] or -/// [`Camera::set_white_balance_without_base_up`] +/// White balance settings. +/// +/// See [`Camera::set_white_balance()`] and [`Camera::set_white_balance_without_base_up()`] to learn how to use this. #[doc(alias = "CAMU_WhiteBalance")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum WhiteBalance { - /// Normal + /// Automatic white balance. Auto = ctru_sys::WHITE_BALANCE_AUTO, - /// Tungsten + /// Tungsten. Temp3200K = ctru_sys::WHITE_BALANCE_3200K, - /// Fluorescent Light + /// Fluorescent Light. Temp4150K = ctru_sys::WHITE_BALANCE_4150K, - /// Daylight + /// Daylight. Temp5200K = ctru_sys::WHITE_BALANCE_5200K, - /// Cloudy/Horizon + /// Cloudy/Horizon. Temp6000K = ctru_sys::WHITE_BALANCE_6000K, - /// Shade + /// Shade. Temp7000K = ctru_sys::WHITE_BALANCE_7000K, } -/// Flag to pass to [`Camera::set_photo_mode`] +/// Photo mode settings. +/// +/// See [`Camera::set_photo_mode()`] to learn how to use this. #[doc(alias = "CAMU_PhotoMode")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] @@ -136,7 +142,9 @@ pub enum PhotoMode { Letter = ctru_sys::PHOTO_MODE_LETTER, } -/// Flag to pass to [`Camera::set_effect`] +/// Special camera effects. +/// +/// See [`Camera::set_effect()`] to learn how to use this. #[doc(alias = "CAMU_Effect")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] @@ -151,11 +159,15 @@ pub enum Effect { Negative = ctru_sys::EFFECT_NEGATIVE, /// Negative film effect. Negafilm = ctru_sys::EFFECT_NEGAFILM, - /// Sepia effect. (unknown difference) + /// Sepia effect. + /// + /// The difference between this and [`Sepia`](Effect::Sepia) is unknown. Sepia01 = ctru_sys::EFFECT_SEPIA01, } -/// Flag to pass to [`Camera::set_contrast`] +/// Contrast settings. +/// +/// See [`Camera::set_contrast()`] to learn how to use this. #[doc(alias = "CAMU_Contrast")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] @@ -168,7 +180,9 @@ pub enum Contrast { High = ctru_sys::CONTRAST_HIGH, } -/// Flag to pass to [`Camera::set_lens_correction`] +/// Lens correction settings. +/// +/// See [`Camera::set_lens_correction()`] to learn how to use this. #[doc(alias = "CAMU_LensCorrection")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] @@ -181,7 +195,9 @@ pub enum LensCorrection { Bright = ctru_sys::LENS_CORRECTION_BRIGHT, } -/// Flag to pass to [`Camera::set_output_format`] +/// Image output format. +/// +/// See [`Camera::set_output_format()`] to learn how to use this. #[doc(alias = "CAMU_OutputFormat")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] @@ -192,12 +208,14 @@ pub enum OutputFormat { Rgb565 = ctru_sys::OUTPUT_RGB_565, } -/// Flag to pass to [`Cam::play_shutter_sound`] +/// Playable shutter sounds. +/// +/// See [`Cam::play_shutter_sound()`] to learn how to use this. #[doc(alias = "CAMU_ShutterSoundType")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] pub enum ShutterSound { - /// Normal shutter sound. + /// Photo shutter sound. Normal = ctru_sys::SHUTTER_SOUND_TYPE_NORMAL, /// Shutter sound to begin a movie recording. Movie = ctru_sys::SHUTTER_SOUND_TYPE_MOVIE, @@ -205,29 +223,9 @@ pub enum ShutterSound { MovieEnd = ctru_sys::SHUTTER_SOUND_TYPE_MOVIE_END, } -impl TryFrom for OutputFormat { - type Error = (); - - fn try_from(value: FramebufferFormat) -> Result { - match value { - FramebufferFormat::Rgb565 => Ok(OutputFormat::Rgb565), - _ => Err(()), - } - } -} - -impl TryFrom for FramebufferFormat { - type Error = (); - - fn try_from(value: OutputFormat) -> Result { - match value { - OutputFormat::Rgb565 => Ok(FramebufferFormat::Rgb565), - _ => Err(()), - } - } -} - -/// Struct containing coordinates passed to [`Camera::set_trimming_params`]. +/// Parameters to handle image trimming. +/// +/// See [`Camera::set_trimming_params()`] to learn how to use this. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct TrimmingParams { x_start: i16, @@ -239,8 +237,10 @@ pub struct TrimmingParams { impl TrimmingParams { /// Creates a new [`TrimmingParams`] and guarantees the start coordinates are less than or /// equal to the end coordinates. + /// + /// # Panics /// - /// `x_start <= x_end && y_start <= y_end` + /// This function panics if the start coordinates are larger than the end coordinates (for each axis). pub fn new(x_start: i16, y_start: i16, x_end: i16, y_end: i16) -> TrimmingParams { assert!(x_start <= x_end && y_start <= y_end); Self { @@ -252,17 +252,20 @@ impl TrimmingParams { } } -/// Represents data used by the camera to calibrate image quality +/// Data used by the camera to calibrate image quality for a single camera. #[doc(alias = "CAMU_ImageQualityCalibrationData")] #[derive(Default, Clone, Copy, Debug)] pub struct ImageQualityCalibrationData(pub ctru_sys::CAMU_ImageQualityCalibrationData); -/// Represents data used by the camera to calibrate image quality when using both outward cameras +/// Data used by the camera to calibrate image quality when using both outward cameras. +// TODO: Implement Stereo camera calibration. #[doc(alias = "CAMU_StereoCameraCalibrationData")] #[derive(Default, Clone, Copy, Debug)] pub struct StereoCameraCalibrationData(pub ctru_sys::CAMU_StereoCameraCalibrationData); -/// Represents the camera on the inside of the 3DS +/// Inward camera representation (facing the user of the 3DS). +/// +/// Usually used for selfies. #[non_exhaustive] pub struct InwardCam; @@ -272,8 +275,7 @@ impl Camera for InwardCam { } } -/// Represents the the outer right camera when the 3DS is open and the dual cameras are pointed -/// away from the user +/// Right-side outward camera representation. #[non_exhaustive] pub struct OutwardRightCam; @@ -283,8 +285,7 @@ impl Camera for OutwardRightCam { } } -/// Represents the the outer left camera when the 3DS is open and the dual cameras are pointed -/// away from the user +/// Left-side outward camera representation. #[non_exhaustive] pub struct OutwardLeftCam; @@ -294,7 +295,9 @@ impl Camera for OutwardLeftCam { } } -/// Represents the both outer cameras combined +/// Both outer cameras combined. +/// +/// Usually used for 3D photos. #[non_exhaustive] pub struct BothOutwardCam; @@ -325,17 +328,36 @@ impl Camera for BothOutwardCam { } } -/// Represents a camera and its functionality +/// Generic functionality common to all cameras. +// TODO: Change "set true/set parameters" scheme (classic of C code) into a single "set parameter" scheme using enums. This is valid for stuff such as [`TrimmingParams`] pub trait Camera { - /// Returns the raw value of the selected camera + /// Returns the raw value of the selected camera. fn camera_as_raw(&self) -> ctru_sys::u32_; - /// Returns the raw port of the selected camera + /// Returns the raw port of the selected camera. fn port_as_raw(&self) -> ctru_sys::u32_ { ctru_sys::PORT_CAM1 } - /// Returns true if the camera is busy (receiving data) + /// Returns `true` if the camera is busy (receiving data). + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::cam::{Cam, Camera}; + /// let cam = Cam::new()?; + /// + /// let inward = &cam.inner_cam; + /// + /// // Inward cam is not busy since it is not being used. + /// assert!(!inward.is_busy()?); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "CAMU_IsBusy")] fn is_busy(&self) -> crate::Result { unsafe { @@ -346,7 +368,25 @@ pub trait Camera { } /// Returns the maximum amount of transfer bytes based on the view size, trimming, and other - /// modifications set to the camera + /// modifications set to the camera. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::cam::{Cam, Camera}; + /// let cam = Cam::new()?; + /// + /// let inward = &cam.inner_cam; + /// + /// // Inward cam is not busy since it is not being used. + /// let transfer_count = inward.transfer_byte_count(); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "CAMU_GetTransferBytes")] fn transfer_byte_count(&self) -> crate::Result { unsafe { @@ -359,8 +399,9 @@ pub trait Camera { } } - /// Sets whether or not the camera should trim the image based on parameters set by - /// [`Camera::set_trimming_params`] + /// Set whether or not the camera should trim the image. + /// + /// [`TrimmingParams`] can be set via [`Camera::set_trimming_params`]. #[doc(alias = "CAMU_SetTrimming")] fn set_trimming(&mut self, enabled: bool) -> crate::Result<()> { unsafe { @@ -369,7 +410,7 @@ pub trait Camera { } } - /// Returns whether or not trimming is currently enabled for the camera + /// Returns whether or not trimming is currently enabled for the camera. #[doc(alias = "CAMU_IsTrimming")] fn is_trimming_enabled(&self) -> crate::Result { unsafe { @@ -379,7 +420,9 @@ pub trait Camera { } } - /// Sets trimming parameters based on coordinates specified inside a [`TrimmingParams`] + /// Set trimming bounds based on image coordinates. + /// + /// For trimming to take effect it is required to pass `true` into [`Camera::set_trimming()`]. #[doc(alias = "CAMU_SetTrimmingParams")] fn set_trimming_params(&mut self, params: TrimmingParams) -> crate::Result<()> { unsafe { @@ -394,7 +437,7 @@ pub trait Camera { } } - /// Returns the [`TrimmingParams`] set + /// Returns the [`TrimmingParams`] currently set. #[doc(alias = "CAMU_GetTrimmingParams")] fn trimming_params(&self) -> crate::Result { unsafe { @@ -419,9 +462,13 @@ pub trait Camera { } } - /// Sets the trimming parameters revolving around the center of the image. + /// Set the trimming bounds relatively to the center of the image. + /// + /// # Notes + /// /// The new width will be `trim_width / 2` to the left and right of the center. /// The new height will be `trim_height / 2` above and below the center. + // TODO: This function doesn't use `TrimmingParams`. It'd be better to merge it with `set_trimming_params()` and change the `TrimmingParams` representation. #[doc(alias = "CAMU_SetTrimmingParamsCenter")] fn set_trimming_params_center( &mut self, @@ -442,7 +489,7 @@ pub trait Camera { } } - /// Sets the exposure level of the camera + /// Set the exposure level of the camera.å #[doc(alias = "CAMU_SetExposure")] fn set_exposure(&mut self, exposure: i8) -> crate::Result<()> { unsafe { @@ -451,7 +498,7 @@ pub trait Camera { } } - /// Sets the white balance mod of the camera based on the passed [`WhiteBalance`] argument + /// Set the white balance of the camera. #[doc(alias = "CAMU_SetWhiteBalance")] fn set_white_balance(&mut self, white_balance: WhiteBalance) -> crate::Result<()> { unsafe { @@ -463,8 +510,8 @@ pub trait Camera { } } - /// Sets the white balance mode of the camera based on the passed [`WhiteBalance`] argument - // TODO: Explain base up + /// Set the white balance of the camera. + // TODO: Explain what "without base up" means. #[doc(alias = "CAMU_SetWhiteBalanceWithoutBaseUp")] fn set_white_balance_without_base_up( &mut self, @@ -479,7 +526,7 @@ pub trait Camera { } } - /// Sets the sharpness of the camera + /// Set the sharpness of the camera. #[doc(alias = "CAMU_SetSharpness")] fn set_sharpness(&mut self, sharpness: i8) -> crate::Result<()> { unsafe { @@ -488,7 +535,7 @@ pub trait Camera { } } - /// Sets whether auto exposure is enabled or disabled for the camera + /// Set whether auto exposure is enabled or disabled for the camera. #[doc(alias = "CAMU_SetAutoExposure")] fn set_auto_exposure(&mut self, enabled: bool) -> crate::Result<()> { unsafe { @@ -500,7 +547,7 @@ pub trait Camera { } } - /// Returns true if auto exposure is enabled for the camera + /// Returns `true` if auto exposure is enabled for the camera. #[doc(alias = "CAMU_IsAutoExposure")] fn is_auto_exposure_enabled(&self) -> crate::Result { unsafe { @@ -525,7 +572,7 @@ pub trait Camera { } } - /// Returns true if auto white balance is enabled for the camera + /// Returns `true` if auto white balance is enabled for the camera. #[doc(alias = "CAMU_IsAutoWhiteBalance")] fn is_auto_white_balance_enabled(&self) -> crate::Result { unsafe { @@ -538,7 +585,7 @@ pub trait Camera { } } - /// Sets the flip direction of the camera's image based on the passed [`FlipMode`] argument + /// Set the flip mode of the camera's image. #[doc(alias = "CAMU_FlipImage")] fn flip_image(&mut self, flip: FlipMode) -> crate::Result<()> { unsafe { @@ -551,7 +598,7 @@ pub trait Camera { } } - /// Sets the image resolution of the camera in detail + /// Set the image resolution of the camera in detail. /// /// # Errors /// @@ -559,10 +606,11 @@ pub trait Camera { /// coordinates of the second crop point. /// /// # Arguments + /// /// * `width` - Width of the image /// * `height` - height of the image /// * `crop_0` - The first crop point in which the image will be trimmed - /// * `crop_0` - The second crop point in which the image will be trimmed + /// * `crop_1` - The second crop point in which the image will be trimmed #[doc(alias = "CAMU_SetDetailSize")] fn set_detail_size( &mut self, @@ -586,7 +634,7 @@ pub trait Camera { } } - /// Sets the view size of the camera based on the passed [`ViewSize`] argument. + /// Set the view size of the camera. #[doc(alias = "CAMU_SetSize")] fn set_view_size(&mut self, size: ViewSize) -> crate::Result<()> { unsafe { @@ -599,7 +647,7 @@ pub trait Camera { } } - /// Sets the frame rate of the camera based on the passed [`FrameRate`] argument. + /// Set the frame rate of the camera. #[doc(alias = "CAMU_SetFrameRate")] fn set_frame_rate(&mut self, frame_rate: FrameRate) -> crate::Result<()> { unsafe { @@ -611,7 +659,7 @@ pub trait Camera { } } - /// Sets the photo mode of the camera based on the passed [`PhotoMode`] argument. + /// Sets the photo mode of the camera. #[doc(alias = "CAMU_SetPhotoMode")] fn set_photo_mode(&mut self, photo_mode: PhotoMode) -> crate::Result<()> { unsafe { @@ -623,9 +671,12 @@ pub trait Camera { } } - /// Sets the effect of the camera based on the passed [`Effect`] argument. - /// - /// Multiple effects can be set at once by combining the bitflags of [`Effect`] + /// Sets the effect of the camera. + /// + /// # Notes + /// + /// This operation will override any previously set [`Effect`]s. + /// Multiple effects can be set at once by combining the bitflags of [`Effect`]. #[doc(alias = "CAMU_SetEffect")] fn set_effect(&mut self, effect: Effect) -> crate::Result<()> { unsafe { @@ -638,7 +689,7 @@ pub trait Camera { } } - /// Sets the contrast of the camera based on the passed [`Contrast`] argument. + /// Set the contrast of the camera. #[doc(alias = "CAMU_SetContrast")] fn set_contrast(&mut self, contrast: Contrast) -> crate::Result<()> { unsafe { @@ -650,7 +701,7 @@ pub trait Camera { } } - /// Sets the lens correction of the camera based on the passed [`LensCorrection`] argument. + /// Set the lens correction of the camera. #[doc(alias = "CAMU_SetLensCorrection")] fn set_lens_correction(&mut self, lens_correction: LensCorrection) -> crate::Result<()> { unsafe { @@ -662,7 +713,7 @@ pub trait Camera { } } - /// Sets the output format of the camera based on the passed [`OutputFormat`] argument. + /// Set the output format of the camera. #[doc(alias = "CAMU_SetOutputFormat")] fn set_output_format(&mut self, format: OutputFormat) -> crate::Result<()> { unsafe { @@ -675,7 +726,7 @@ pub trait Camera { } } - /// Sets the region in which auto exposure should be based on. + /// Set the region in which auto exposure should be based on. /// /// # Arguments /// @@ -703,7 +754,7 @@ pub trait Camera { } } - /// Sets the region in which auto white balance should be based on. + /// Set the region in which auto white balance should be based on. /// /// # Arguments /// @@ -711,6 +762,10 @@ pub trait Camera { /// * `y` - Starting y coordinate of the window /// * `width` - Width of the window /// * `height` - Height of the window + /// + /// # Notes + /// + /// To activate automatic white balance, you must pass [`WhiteBalance::Auto`] into [`Camera::set_white_balance()`]. #[doc(alias = "CAMU_SetAutoWhiteBalanceWindow")] fn set_auto_white_balance_window( &mut self, @@ -731,7 +786,7 @@ pub trait Camera { } } - /// Sets whether the noise filter should be enabled or disabled for the camera + /// Set whether the noise filter should be enabled or disabled for the camera. #[doc(alias = "CAMU_SetNoiseFilter")] fn set_noise_filter(&mut self, enabled: bool) -> crate::Result<()> { unsafe { @@ -740,8 +795,7 @@ pub trait Camera { } } - /// Sets the image quality calibration data for the camera based on the passed in - /// [`ImageQualityCalibrationData`] argument + /// Set the [`ImageQualityCalibrationData`] for the camera. #[doc(alias = "CAMU_SetImageQualityCalibrationData")] fn set_image_quality_calibration_data( &mut self, @@ -753,7 +807,7 @@ pub trait Camera { } } - /// Returns the current [`ImageQualityCalibrationData`] for the camera + /// Returns the current [`ImageQualityCalibrationData`] for the camera. #[doc(alias = "CAMU_GetImageQualityCalibrationData")] fn image_quality_calibration_data(&self) -> crate::Result { unsafe { @@ -763,7 +817,7 @@ pub trait Camera { } } - /// Sets the camera as the current sleep camera + /// Set the camera as the current sleep camera. // TODO: Explain sleep camera #[doc(alias = "CAMU_SetSleepCamera")] fn set_sleep_camera(&mut self) -> crate::Result<()> { @@ -773,17 +827,48 @@ pub trait Camera { } } - /// Requests the camera to take a picture and write it in a buffer. + /// Request the camera to take a picture and write it in a buffer. /// /// # Errors /// - /// This will error if the camera is busy or if the timeout duration is reached. + /// This function will return an error if the camera is busy or if the timeout duration gets reached. /// /// # Arguments /// /// * `width` - Width of the desired image /// * `height` - Height of the desired image /// * `timeout` - Duration to wait for the image + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # use std::time::Duration; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::cam::{Cam, Camera, ViewSize, OutputFormat}; + /// let mut cam = Cam::new()?; + /// + /// // We borrow the inward facing `Camera`. + /// let inward = &mut cam.inner_cam; + /// + /// inward.set_view_size(ViewSize::TopLCD)?; + /// inward.set_output_format(OutputFormat::Rgb565)?; + /// inward.set_noise_filter(true)?; + /// inward.set_auto_exposure(true)?; + /// inward.set_auto_white_balance(true)?; + /// + /// // Size of the top screen buffer at 2 bytes per pixel (RGB565). + /// let mut buffer = vec![0; 400*240*2]; + /// + /// // Take picture with 3 seconds of timeout. + /// inward.take_picture(&mut buffer, 400, 240, Duration::from_secs(3)); + /// # + /// # Ok(()) + /// # } + /// ``` + // TODO: This should use the value passed within `set_view_size` rather than arbitrary `width` and `height` values. + // Furthermore, it's pretty unclear what the "default" view size is. What happens if the user doesn't set it before taking the picture? fn take_picture( &mut self, buffer: &mut [u8], @@ -863,6 +948,20 @@ impl Cam { /// This function will return an error if the service was unable to be initialized. /// Since this service requires no special or elevated permissions, errors are /// rare in practice. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::cam::Cam; + /// + /// let cam = Cam::new()?; + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "camInit")] pub fn new() -> crate::Result { unsafe { @@ -877,6 +976,28 @@ impl Cam { } /// Plays the specified sound based on the [`ShutterSound`] argument + /// + /// # Notes + /// + /// Playing the shutter sound does not require a liviving handle to the [`Ndsp`](crate::services::ndsp::Ndsp) service. + /// Volume will always be maxed out to ensure everyone within photo range can hear the picture being taken (as by japanese law). + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::cam::{Cam, ShutterSound}; + /// let cam = Cam::new()?; + /// + /// // We play the shutter sound on the console's speakers! + /// // (even though we aren't taking a photo :P) + /// cam.play_shutter_sound(ShutterSound::Normal); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "CAMU_PlayShutterSound")] pub fn play_shutter_sound(&self, sound: ShutterSound) -> crate::Result<()> { unsafe { @@ -893,6 +1014,28 @@ impl Drop for Cam { } } +impl TryFrom for OutputFormat { + type Error = (); + + fn try_from(value: FramebufferFormat) -> Result { + match value { + FramebufferFormat::Rgb565 => Ok(OutputFormat::Rgb565), + _ => Err(()), + } + } +} + +impl TryFrom for FramebufferFormat { + type Error = (); + + fn try_from(value: OutputFormat) -> Result { + match value { + OutputFormat::Rgb565 => Ok(FramebufferFormat::Rgb565), + _ => Err(()), + } + } +} + from_impl!(FlipMode, ctru_sys::CAMU_Flip); from_impl!(ViewSize, ctru_sys::CAMU_Size); from_impl!(FrameRate, ctru_sys::CAMU_FrameRate); diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index 464d9801..d5d79165 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -2,6 +2,7 @@ //! //! This module contains basic methods to manipulate the contents of the 3DS's filesystem. //! Only the SD card is currently supported. You should prefer using `std::fs`. +// TODO: Refactor service to accomodate for various changes (such as SMDH support). Properly document the public API. use bitflags::bitflags; use std::ffi::OsString; From ccb0676f3c0e5aa9d2c96e9afa1e8ce2c0b477ca Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Wed, 26 Jul 2023 18:37:44 +0200 Subject: [PATCH 24/39] More generic doc changes --- ctru-rs/README.md | 1 - ctru-rs/src/error.rs | 11 ++++++----- ctru-rs/src/lib.rs | 4 ++-- ctru-rs/src/linear.rs | 18 ++++++++++-------- ctru-rs/src/services/am.rs | 2 +- ctru-rs/src/services/mod.rs | 4 ++-- 6 files changed, 21 insertions(+), 19 deletions(-) diff --git a/ctru-rs/README.md b/ctru-rs/README.md index 297c8cce..0cc8a79f 100644 --- a/ctru-rs/README.md +++ b/ctru-rs/README.md @@ -1,7 +1,6 @@ # ctru-rs Safe and idiomatic Rust wrapper around [`libctru`](https://github.com/devkitPro/libctru). -This crate uses the bindings provided by [`ctru-sys`](../ctru-sys/). ## Getting Started diff --git a/ctru-rs/src/error.rs b/ctru-rs/src/error.rs index 895bed1c..becfaefe 100644 --- a/ctru-rs/src/error.rs +++ b/ctru-rs/src/error.rs @@ -1,6 +1,7 @@ //! Error handling interface. //! -//! This module holds the generic error and result types to interface with [`ctru_sys`] and the safe wrapper. +//! This module holds the generic error and result types to interface with `ctru_sys` and the [`ctru-rs`](crate) safe wrapper. + use std::borrow::Cow; use std::error; use std::ffi::CStr; @@ -9,12 +10,12 @@ use std::ops::{ControlFlow, FromResidual, Try}; use ctru_sys::result::{R_DESCRIPTION, R_LEVEL, R_MODULE, R_SUMMARY}; -/// Custom type alias for generic `ctru` operations. +/// Custom type alias for generic [`ctru-rs`](crate) operations. /// -/// This type is compatible with `ctru-sys` result codes. +/// This type is compatible with `ctru-sys::Result` codes. pub type Result = ::std::result::Result; -/// Validity checker of raw [`ctru_sys::Result`] codes. +/// Validity checker of raw `ctru_sys::Result` codes. /// /// This struct supports the "try" syntax (`?`) to convert to an [`Error::Os`]. /// @@ -72,7 +73,7 @@ impl FromResidual for Result { } } -/// The generic error enum returned by `ctru` functions. +/// The generic error enum returned by [`ctru-rs`](crate) functions. /// /// This error enum supports parsing and displaying [`ctru_sys::Result`] codes. #[non_exhaustive] diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index b2267f0e..3686578b 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -6,7 +6,7 @@ //! Thanks to it, developers can access the underlying system services and the console's hardware to develop userland applications //! (such as [HID devices](crate::services::hid), [network capabilities](crate::services::soc), [graphics](crate::services::gfx), [built-in cameras](crate::services::cam), etc.). //! -//! Among these features, `ctru-rs` also automatically includes functionality to properly integrate the Rust `std` with the console's operating system, +//! Among these features, [`ctru-rs`](crate) also automatically includes functionality to properly integrate the Rust `std` with the console's operating system, //! which the developer would otherwise need to implement manually. //! //! # Usage @@ -53,7 +53,7 @@ macro_rules! from_impl { }; } -/// Activate the custom `ctru-rs` panic handler. +/// Activate the custom [`ctru-rs`](crate) panic handler. /// /// With this implementation, the main thread will stop and try to print debug info to an available [`Console`](console::Console). /// In case it fails to find an active [`Console`](console::Console) the program will just exit. diff --git a/ctru-rs/src/linear.rs b/ctru-rs/src/linear.rs index d0164c0a..fd776be0 100644 --- a/ctru-rs/src/linear.rs +++ b/ctru-rs/src/linear.rs @@ -1,11 +1,12 @@ -//! Linear memory allocator +//! LINEAR memory allocator. //! -//! Linear memory is a sector of the 3DS' RAM that binds virtual addresses exactly to the physical address. -//! As such, it is used for fast and safe memory sharing between services (and is especially needed for GPU and DSP). +//! LINEAR memory is a sector of the 3DS' RAM that binds virtual addresses exactly to the physical address. +//! As such, it is used for fast and safe memory sharing between hardware processors (such as the GPU and the DSP). //! -//! Resources:
-//!
-//! +//! # Additional Resources +//! +//! -
+//! - use std::alloc::{AllocError, Allocator, Layout}; use std::ptr::NonNull; @@ -15,13 +16,14 @@ use std::ptr::NonNull; // Sadly the linear memory allocator included in `libctru` doesn't implement `linearRealloc` at the time of these additions, // but the default fallback of the `std` will take care of that for us. -/// [`Allocator`](std::alloc::Allocator) struct for LINEAR memory +/// [`Allocator`](std::alloc::Allocator) struct for LINEAR memory. +/// /// To use this struct the main crate must activate the `allocator_api` unstable feature. #[derive(Copy, Clone, Default, Debug)] pub struct LinearAllocator; impl LinearAllocator { - /// Returns the amount of free space left in the LINEAR sector + /// Returns the amount of free space left in the LINEAR memory sector. #[doc(alias = "linearSpaceFree")] pub fn free_space() -> u32 { unsafe { ctru_sys::linearSpaceFree() } diff --git a/ctru-rs/src/services/am.rs b/ctru-rs/src/services/am.rs index e67282e5..ee5a4800 100644 --- a/ctru-rs/src/services/am.rs +++ b/ctru-rs/src/services/am.rs @@ -4,7 +4,7 @@ //! - Read the installed applications on the console and their information (depending on the install location). //! - Install compatible applications to the console. //! -//! TODO: `ctru-rs` doesn't support installing or uninstalling titles yet. +//! TODO: [`ctru-rs`](crate) doesn't support installing or uninstalling titles yet. use crate::error::ResultCode; use crate::services::fs::FsMediaType; diff --git a/ctru-rs/src/services/mod.rs b/ctru-rs/src/services/mod.rs index 9ff975ea..8aadf877 100644 --- a/ctru-rs/src/services/mod.rs +++ b/ctru-rs/src/services/mod.rs @@ -3,13 +3,13 @@ //! Most of the 3DS console's functionalities (when writing user-land homebrew) are accessible via services, //! which need to be initialized before accessing any particular feature. //! -//! To ensure safety while using the underlying services, `ctru-rs` leverages Rust's lifetime model. +//! To ensure safety while using the underlying services, [`ctru-rs`](crate) leverages Rust's lifetime model. //! After initializing the handle for a specific service (e.g. [`Apt`](apt::Apt)) the service will be accessible as long as there is at least one handle "alive". //! As such, handles should be dropped *after* the use of a specific service. This is particularly important for services which are necessary for functionality //! "outside" their associated methods, such as [`RomFS`](romfs::RomFS), which creates an accessible virtual filesystem, or [`Soc`](soc::Soc), //! which enables all network communications via sockets. //! -//! In `ctru-rs` some services only allow a single handle to be created at a time, to ensure a safe and controlled environment. +//! In [`ctru-rs`](crate) some services only allow a single handle to be created at a time, to ensure a safe and controlled environment. pub mod am; pub mod apt; From acb1d3fbb8a11842aea88349122140ecfb303a88 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Wed, 26 Jul 2023 18:47:41 +0200 Subject: [PATCH 25/39] Finalize Mii module --- ctru-rs/src/applets/mii_selector.rs | 6 +-- ctru-rs/src/linear.rs | 4 +- ctru-rs/src/mii.rs | 76 +++++++++++++------------- ctru-rs/src/services/cam.rs | 82 ++++++++++++++--------------- 4 files changed, 85 insertions(+), 83 deletions(-) diff --git a/ctru-rs/src/applets/mii_selector.rs b/ctru-rs/src/applets/mii_selector.rs index 76a4d5ec..bd0e4b4e 100644 --- a/ctru-rs/src/applets/mii_selector.rs +++ b/ctru-rs/src/applets/mii_selector.rs @@ -1,9 +1,9 @@ //! Mii Selector applet. //! //! This applet opens a window which lets the player/user choose a Mii from the ones present on their console. -//! The selected Mii is readable as a [`MiiData`](crate::mii::MiiData). +//! The selected Mii is readable as a [`Mii`](crate::mii::Mii). -use crate::mii::MiiData; +use crate::mii::Mii; use bitflags::bitflags; use std::{ffi::CString, fmt}; @@ -65,7 +65,7 @@ pub struct MiiSelector { #[derive(Clone, Debug)] pub struct Selection { /// Data of the selected Mii. - pub mii_data: MiiData, + pub mii_data: Mii, /// Type of the selected Mii. pub mii_type: MiiType, } diff --git a/ctru-rs/src/linear.rs b/ctru-rs/src/linear.rs index fd776be0..8c0639aa 100644 --- a/ctru-rs/src/linear.rs +++ b/ctru-rs/src/linear.rs @@ -4,7 +4,7 @@ //! As such, it is used for fast and safe memory sharing between hardware processors (such as the GPU and the DSP). //! //! # Additional Resources -//! +//! //! -
//! - @@ -17,7 +17,7 @@ use std::ptr::NonNull; // but the default fallback of the `std` will take care of that for us. /// [`Allocator`](std::alloc::Allocator) struct for LINEAR memory. -/// +/// /// To use this struct the main crate must activate the `allocator_api` unstable feature. #[derive(Copy, Clone, Default, Debug)] pub struct LinearAllocator; diff --git a/ctru-rs/src/mii.rs b/ctru-rs/src/mii.rs index b5a2f039..beccd4e9 100644 --- a/ctru-rs/src/mii.rs +++ b/ctru-rs/src/mii.rs @@ -1,9 +1,10 @@ -//! Mii Data +//! Mii data. //! //! This module contains the structs that represent all the data of a Mii. -//! This data is given by the [``MiiSelector``](crate::applets::mii_selector::MiiSelector) +//! +//! Have a look at the [`MiiSelector`](crate::applets::mii_selector::MiiSelector) applet to learn how to ask the user for a specific Mii. -/// Represents the region lock of the console. +/// Region lock of the Mii. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum RegionLock { /// No region-lock. @@ -16,7 +17,7 @@ pub enum RegionLock { Europe, } -/// Represent the charset of the console. +/// Charset of the Mii. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Charset { /// Japan-USA-Europe unified charset. @@ -29,9 +30,9 @@ pub enum Charset { Taiwan, } -/// Represents the options of the Mii. +/// Generic options of the Mii. #[derive(Copy, Clone, Debug)] -pub struct MiiDataOptions { +pub struct Options { /// Whether it is allowed to copy the Mii. pub is_copying_allowed: bool, /// Whether the profanity flag is active. @@ -42,7 +43,7 @@ pub struct MiiDataOptions { pub charset: Charset, } -/// Represents the position that the Mii has on the selector. +/// Positional Index that the Mii has on the [`MiiSelector`](crate::applets::mii_selector::MiiSelector) window. #[derive(Copy, Clone, Debug)] pub struct SelectorPosition { /// Index of the page where the Mii is found. @@ -51,40 +52,42 @@ pub struct SelectorPosition { pub slot_index: u8, } -/// Represents the console where the Mii originated from. +/// Console model from which the Mii originated. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum OriginConsole { /// Nintendo Wii. Wii, /// Nintendo DSi. DSi, - /// Nintendo 3DS (both New 3DS and Old 3DS). + /// Nintendo 3DS. + /// + /// This includes all consoles of the 3DS family (3DS, 2DS, and their respective "New" or "XL" variants). N3DS, - /// Nintendo WiiU/Switch. + /// Nintendo Wii U/Switch. WiiUSwitch, } -/// Represents the identity of the origin console. +/// Identity of the origin console. #[derive(Copy, Clone, Debug)] pub struct ConsoleIdentity { /// From which console the Mii originated from. pub origin_console: OriginConsole, } -/// Represents the sex of the Mii. +/// Sex of the Mii. #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum MiiSex { +pub enum Sex { /// Male sex. Male, /// Female sex. Female, } -/// Represents the details of the Mii. +/// Generic details of the Mii. #[derive(Copy, Clone, Debug)] pub struct Details { /// Sex of the Mii. - pub sex: MiiSex, + pub sex: Sex, /// Birthday month. pub birthday_month: u8, /// Birthday day. @@ -97,7 +100,7 @@ pub struct Details { pub is_sharing_enabled: bool, } -/// Represents the face style of the Mii. +/// Face style of the Mii. #[derive(Copy, Clone, Debug)] pub struct FaceStyle { /// Face shape. @@ -106,7 +109,7 @@ pub struct FaceStyle { pub skin_color: u8, } -/// Represents the face details of the Mii. +/// Face details of the Mii. #[derive(Copy, Clone, Debug)] pub struct FaceDetails { /// Face style. @@ -117,7 +120,7 @@ pub struct FaceDetails { pub makeup: u8, } -/// Represents the hair details of the Mii. +/// Hair details of the Mii. #[derive(Copy, Clone, Debug)] pub struct HairDetails { /// Hair style. @@ -128,7 +131,7 @@ pub struct HairDetails { pub is_flipped: bool, } -/// Represents the eye details of the Mii. +/// Eye details of the Mii. #[derive(Copy, Clone, Debug)] pub struct EyeDetails { /// Eye style. @@ -147,7 +150,7 @@ pub struct EyeDetails { pub y_position: u8, } -/// Represents the eyebrow details of the Mii +/// Eyebrow details of the Mii. #[derive(Copy, Clone, Debug)] pub struct EyebrowDetails { /// Eyebrow style. @@ -166,7 +169,7 @@ pub struct EyebrowDetails { pub y_position: u8, } -/// Represents the details of the nose +/// Nose details of the Mii. #[derive(Copy, Clone, Debug)] pub struct NoseDetails { /// Nose style. @@ -177,7 +180,7 @@ pub struct NoseDetails { pub y_position: u8, } -/// Represents the details of the mouth +/// Mouth details of the Mii. #[derive(Copy, Clone, Debug)] pub struct MouthDetails { /// Mouth style. @@ -192,14 +195,14 @@ pub struct MouthDetails { pub y_position: u8, } -/// Represents the details of the mustache +/// Mustache details of the Mii. #[derive(Copy, Clone, Debug)] pub struct MustacheDetails { /// Mustache style. pub mustache_style: u8, } -/// Represents the details of the beard +/// Beard details of the Mii. #[derive(Copy, Clone, Debug)] pub struct BeardDetails { /// Beard style @@ -212,7 +215,7 @@ pub struct BeardDetails { pub y_position: u8, } -/// Represents the details of the glasses +/// Glasses details of the Mii. #[derive(Copy, Clone, Debug)] pub struct GlassesDetails { /// Glasses style. @@ -225,7 +228,7 @@ pub struct GlassesDetails { pub y_position: u8, } -/// Represents the details of the mole. +/// Mole details of the Mii. #[derive(Copy, Clone, Debug)] pub struct MoleDetails { /// Whether the Mii has a mole. @@ -238,16 +241,15 @@ pub struct MoleDetails { pub y_position: u8, } -/// Represents all the data of a Mii +/// Full Mii data representation. /// -/// Some values are not ordered _like_ the Mii Editor UI. The mapped values can be seen here: -/// +/// Some values are not ordered *like* the Mii Editor UI. The mapped values can be seen [here](https://www.3dbrew.org/wiki/Mii#Mapped_Editor_.3C-.3E_Hex_values). /// -/// This struct is returned by the [`MiiSelector`](crate::applets::mii_selector::MiiSelector) +/// This struct can be retrieved by [`MiiSelector::lauch()`](crate::applets::mii_selector::MiiSelector::launch). #[derive(Clone, Debug)] -pub struct MiiData { +pub struct Mii { /// Mii options. - pub options: MiiDataOptions, + pub options: Options, /// Position taken by the Mii on the Mii Selector screen. pub selector_position: SelectorPosition, /// Console the Mii was created on. @@ -293,7 +295,7 @@ pub struct MiiData { pub author_name: String, } -impl From for MiiData { +impl From for Mii { fn from(mii_data: ctru_sys::MiiData) -> Self { let raw_mii_data = mii_data._bindgen_opaque_blob; // Source for the representation and what each thing means: https://www.3dbrew.org/wiki/Mii @@ -358,7 +360,7 @@ impl From for MiiData { let name = utf16_byte_pairs_to_string(raw_utf16_name); let author_name = utf16_byte_pairs_to_string(raw_utf16_author); - let options = MiiDataOptions { + let options = Options { is_copying_allowed: raw_options[0], is_profanity_flag_enabled: raw_options[1], region_lock: { @@ -398,8 +400,8 @@ impl From for MiiData { let details = Details { sex: { match raw_details[0] { - true => MiiSex::Female, - false => MiiSex::Male, + true => Sex::Female, + false => Sex::Male, } }, birthday_month: partial_u8_bits_to_u8(&raw_details[1..=4]), @@ -485,7 +487,7 @@ impl From for MiiData { y_position: partial_u8_bits_to_u8(&raw_mole_details[10..=14]), }; - MiiData { + Mii { options, selector_position, console_identity, diff --git a/ctru-rs/src/services/cam.rs b/ctru-rs/src/services/cam.rs index ff9bd5bc..dd4437b1 100644 --- a/ctru-rs/src/services/cam.rs +++ b/ctru-rs/src/services/cam.rs @@ -22,7 +22,7 @@ pub struct Cam { } /// Different kinds of flip modes. -/// +/// /// See [`Camera::flip_image()`] to learn how to use this. #[doc(alias = "CAMU_Flip")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -39,7 +39,7 @@ pub enum FlipMode { } /// Size of the camera view. -/// +/// /// See [`Camera::set_view_size()`] to learn how to use this. #[doc(alias = "CAMU_Size")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -68,7 +68,7 @@ pub enum ViewSize { } /// Framerate settings. -/// +/// /// See [`Camera::set_frame_rate()`] to learn how to use this. #[doc(alias = "CAMU_FramRate")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -103,7 +103,7 @@ pub enum FrameRate { } /// White balance settings. -/// +/// /// See [`Camera::set_white_balance()`] and [`Camera::set_white_balance_without_base_up()`] to learn how to use this. #[doc(alias = "CAMU_WhiteBalance")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -124,7 +124,7 @@ pub enum WhiteBalance { } /// Photo mode settings. -/// +/// /// See [`Camera::set_photo_mode()`] to learn how to use this. #[doc(alias = "CAMU_PhotoMode")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -143,7 +143,7 @@ pub enum PhotoMode { } /// Special camera effects. -/// +/// /// See [`Camera::set_effect()`] to learn how to use this. #[doc(alias = "CAMU_Effect")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -160,13 +160,13 @@ pub enum Effect { /// Negative film effect. Negafilm = ctru_sys::EFFECT_NEGAFILM, /// Sepia effect. - /// + /// /// The difference between this and [`Sepia`](Effect::Sepia) is unknown. Sepia01 = ctru_sys::EFFECT_SEPIA01, } /// Contrast settings. -/// +/// /// See [`Camera::set_contrast()`] to learn how to use this. #[doc(alias = "CAMU_Contrast")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -181,7 +181,7 @@ pub enum Contrast { } /// Lens correction settings. -/// +/// /// See [`Camera::set_lens_correction()`] to learn how to use this. #[doc(alias = "CAMU_LensCorrection")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -196,7 +196,7 @@ pub enum LensCorrection { } /// Image output format. -/// +/// /// See [`Camera::set_output_format()`] to learn how to use this. #[doc(alias = "CAMU_OutputFormat")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -209,7 +209,7 @@ pub enum OutputFormat { } /// Playable shutter sounds. -/// +/// /// See [`Cam::play_shutter_sound()`] to learn how to use this. #[doc(alias = "CAMU_ShutterSoundType")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -224,7 +224,7 @@ pub enum ShutterSound { } /// Parameters to handle image trimming. -/// +/// /// See [`Camera::set_trimming_params()`] to learn how to use this. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct TrimmingParams { @@ -237,7 +237,7 @@ pub struct TrimmingParams { impl TrimmingParams { /// Creates a new [`TrimmingParams`] and guarantees the start coordinates are less than or /// equal to the end coordinates. - /// + /// /// # Panics /// /// This function panics if the start coordinates are larger than the end coordinates (for each axis). @@ -264,7 +264,7 @@ pub struct ImageQualityCalibrationData(pub ctru_sys::CAMU_ImageQualityCalibratio pub struct StereoCameraCalibrationData(pub ctru_sys::CAMU_StereoCameraCalibrationData); /// Inward camera representation (facing the user of the 3DS). -/// +/// /// Usually used for selfies. #[non_exhaustive] pub struct InwardCam; @@ -296,7 +296,7 @@ impl Camera for OutwardLeftCam { } /// Both outer cameras combined. -/// +/// /// Usually used for 3D photos. #[non_exhaustive] pub struct BothOutwardCam; @@ -340,7 +340,7 @@ pub trait Camera { } /// Returns `true` if the camera is busy (receiving data). - /// + /// /// # Example /// /// ```no_run @@ -349,9 +349,9 @@ pub trait Camera { /// # /// use ctru::services::cam::{Cam, Camera}; /// let cam = Cam::new()?; - /// + /// /// let inward = &cam.inner_cam; - /// + /// /// // Inward cam is not busy since it is not being used. /// assert!(!inward.is_busy()?); /// # @@ -369,7 +369,7 @@ pub trait Camera { /// Returns the maximum amount of transfer bytes based on the view size, trimming, and other /// modifications set to the camera. - /// + /// /// # Example /// /// ```no_run @@ -378,9 +378,9 @@ pub trait Camera { /// # /// use ctru::services::cam::{Cam, Camera}; /// let cam = Cam::new()?; - /// + /// /// let inward = &cam.inner_cam; - /// + /// /// // Inward cam is not busy since it is not being used. /// let transfer_count = inward.transfer_byte_count(); /// # @@ -400,7 +400,7 @@ pub trait Camera { } /// Set whether or not the camera should trim the image. - /// + /// /// [`TrimmingParams`] can be set via [`Camera::set_trimming_params`]. #[doc(alias = "CAMU_SetTrimming")] fn set_trimming(&mut self, enabled: bool) -> crate::Result<()> { @@ -421,7 +421,7 @@ pub trait Camera { } /// Set trimming bounds based on image coordinates. - /// + /// /// For trimming to take effect it is required to pass `true` into [`Camera::set_trimming()`]. #[doc(alias = "CAMU_SetTrimmingParams")] fn set_trimming_params(&mut self, params: TrimmingParams) -> crate::Result<()> { @@ -463,9 +463,9 @@ pub trait Camera { } /// Set the trimming bounds relatively to the center of the image. - /// + /// /// # Notes - /// + /// /// The new width will be `trim_width / 2` to the left and right of the center. /// The new height will be `trim_height / 2` above and below the center. // TODO: This function doesn't use `TrimmingParams`. It'd be better to merge it with `set_trimming_params()` and change the `TrimmingParams` representation. @@ -606,7 +606,7 @@ pub trait Camera { /// coordinates of the second crop point. /// /// # Arguments - /// + /// /// * `width` - Width of the image /// * `height` - height of the image /// * `crop_0` - The first crop point in which the image will be trimmed @@ -672,9 +672,9 @@ pub trait Camera { } /// Sets the effect of the camera. - /// + /// /// # Notes - /// + /// /// This operation will override any previously set [`Effect`]s. /// Multiple effects can be set at once by combining the bitflags of [`Effect`]. #[doc(alias = "CAMU_SetEffect")] @@ -762,9 +762,9 @@ pub trait Camera { /// * `y` - Starting y coordinate of the window /// * `width` - Width of the window /// * `height` - Height of the window - /// + /// /// # Notes - /// + /// /// To activate automatic white balance, you must pass [`WhiteBalance::Auto`] into [`Camera::set_white_balance()`]. #[doc(alias = "CAMU_SetAutoWhiteBalanceWindow")] fn set_auto_white_balance_window( @@ -838,9 +838,9 @@ pub trait Camera { /// * `width` - Width of the desired image /// * `height` - Height of the desired image /// * `timeout` - Duration to wait for the image - /// + /// /// # Example - /// + /// /// ```no_run /// # use std::error::Error; /// # use std::time::Duration; @@ -848,19 +848,19 @@ pub trait Camera { /// # /// use ctru::services::cam::{Cam, Camera, ViewSize, OutputFormat}; /// let mut cam = Cam::new()?; - /// + /// /// // We borrow the inward facing `Camera`. /// let inward = &mut cam.inner_cam; - /// + /// /// inward.set_view_size(ViewSize::TopLCD)?; /// inward.set_output_format(OutputFormat::Rgb565)?; /// inward.set_noise_filter(true)?; /// inward.set_auto_exposure(true)?; /// inward.set_auto_white_balance(true)?; - /// + /// /// // Size of the top screen buffer at 2 bytes per pixel (RGB565). /// let mut buffer = vec![0; 400*240*2]; - /// + /// /// // Take picture with 3 seconds of timeout. /// inward.take_picture(&mut buffer, 400, 240, Duration::from_secs(3)); /// # @@ -948,7 +948,7 @@ impl Cam { /// This function will return an error if the service was unable to be initialized. /// Since this service requires no special or elevated permissions, errors are /// rare in practice. - /// + /// /// # Example /// /// ```no_run @@ -976,12 +976,12 @@ impl Cam { } /// Plays the specified sound based on the [`ShutterSound`] argument - /// + /// /// # Notes - /// + /// /// Playing the shutter sound does not require a liviving handle to the [`Ndsp`](crate::services::ndsp::Ndsp) service. /// Volume will always be maxed out to ensure everyone within photo range can hear the picture being taken (as by japanese law). - /// + /// /// # Example /// /// ```no_run @@ -990,7 +990,7 @@ impl Cam { /// # /// use ctru::services::cam::{Cam, ShutterSound}; /// let cam = Cam::new()?; - /// + /// /// // We play the shutter sound on the console's speakers! /// // (even though we aren't taking a photo :P) /// cam.play_shutter_sound(ShutterSound::Normal); From a184e7a159c99f8021cb88fa4beee306c299a167 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Thu, 27 Jul 2023 13:38:59 +0200 Subject: [PATCH 26/39] Finalize Console docs --- ctru-rs/src/console.rs | 119 ++++++++++++++++++++++++++++++++---- ctru-rs/src/services/soc.rs | 5 +- 2 files changed, 110 insertions(+), 14 deletions(-) diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index a468c02a..8eb3ebce 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -1,4 +1,9 @@ //! Virtual text console. +//! +//! The [`Console`] works as a virtual shell that renders on screen all output of `stdout`. As such, it is useful as a basic interface to show info to the user, +//! such as in simple "Hello World" applications or more complex software that does not need much user interaction. +//! +//! Have a look at [`Soc::redirect_to_3dslink()`](crate::services::soc::Soc::redirect_to_3dslink) for a better alternative when debugging applications. use std::cell::RefMut; use std::default::Default; @@ -9,10 +14,10 @@ use crate::services::gfx::Screen; static mut EMPTY_CONSOLE: PrintConsole = unsafe { const_zero::const_zero!(PrintConsole) }; -/// Virtual printable console. +/// Virtual text console. /// /// [`Console`] lets the application redirect `stdout` to a simple text displayer on the 3DS screen. -/// This means that any text written to `stdout` (e.g. using [`println!`] or [`dbg!`]) will become visible in the area taken by the console. +/// This means that any text written to `stdout` (e.g. using `println!` or `dbg!`) will become visible in the area taken by the console. /// /// # Notes /// @@ -20,7 +25,7 @@ static mut EMPTY_CONSOLE: PrintConsole = unsafe { const_zero::const_zero!(PrintC /// /// # Alternatives /// -/// If you'd like to see live `stdout` output while running the application but can't/don't want to show the text on the 3DS itself, +/// If you'd like to see live `stdout` output while running the application but cannnot/do not want to show the text on the 3DS itself, /// you can try using [`Soc::redirect_to_3dslink`](crate::services::soc::Soc::redirect_to_3dslink) while activating the `--server` flag for `3dslink` (also supported by `cargo-3ds`). /// More info in the `cargo-3ds` docs. #[doc(alias = "PrintConsole")] @@ -30,13 +35,37 @@ pub struct Console<'screen> { } impl<'screen> Console<'screen> { - /// Initialize a console on the chosen screen, overwriting whatever was on the screen - /// previously (including other consoles). The new console is automatically selected for - /// printing. + /// Initialize a console on the chosen screen. /// /// # Notes /// + /// This operation overwrites whatever was on the screen before the inizialization (including other [`Console`]s) + /// and changes the [`FramebufferFormat`](crate::services::gspgpu::FramebufferFormat) of the selected screen to better suit the [`Console`]. + /// + /// The new console is automatically selected for printing. + /// /// [`Console`] automatically takes care of flushing and swapping buffers for its screen when printing. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::gfx::Gfx; + /// use ctru::console::Console; + /// + /// // Initialize graphics. + /// let gfx = Gfx::new()?; + /// + /// // Create a `Console` that takes control of the upper LCD screen. + /// let top_console = Console::new(gfx.top_screen.borrow_mut()); + /// + /// println!("I'm on the top screen!"); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "consoleInit")] pub fn new(screen: RefMut<'screen, dyn Screen>) -> Self { let mut context = Box::::default(); @@ -49,7 +78,35 @@ impl<'screen> Console<'screen> { } } - /// Returns true if a valid Console to print on is selected + /// Returns `true` if a valid [`Console`] to print on is currently selected. + /// + /// # Notes + /// + /// This function is used to check whether one of the two screens has an existing (and selected) [`Console`], + /// so that the program can be sure its output will be shown *somewhere*. + /// + /// The main use of this is within the [`ctru::use_panic_handler()`](crate::use_panic_handler()) hook, + /// since it will only stop the program's execution if the user is able to see the panic information output on screen. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// # use ctru::services::gfx::Gfx; + /// # // Initialize graphics. + /// # let gfx = Gfx::new()?; + /// # + /// use ctru::console::Console; + /// let top_console = Console::new(gfx.top_screen.borrow_mut()); + /// + /// // There is at least one selected `Console`. + /// assert!(Console::exists()); + /// # + /// # Ok(()) + /// # } + /// ``` pub fn exists() -> bool { unsafe { let current_console = ctru_sys::consoleSelect(&mut EMPTY_CONSOLE); @@ -62,7 +119,39 @@ impl<'screen> Console<'screen> { } } - /// Select this console as the current target for stdout + /// Select this console as the current target for `stdout`. + /// + /// # Notes + /// + /// Any previously selected console will be unhooked and will not show the `stdout` output. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// # use ctru::services::gfx::Gfx; + /// # let gfx = Gfx::new()?; + /// # + /// use ctru::console::Console; + /// + /// // Create a `Console` that takes control of the upper LCD screen. + /// let top_console = Console::new(gfx.top_screen.borrow_mut()); + /// + /// // Create a `Console` that takes control of the lower LCD screen. + /// let bottom_console = Console::new(gfx.bottom_screen.borrow_mut()); + /// + /// // Remember that `Console::new` automatically selects the new `Console` for ouput. + /// println!("I'm on the bottom screen!"); + /// + /// top_console.select(); + /// + /// println!("Being on the upper screen is much better!"); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "consoleSelect")] pub fn select(&self) { unsafe { @@ -70,20 +159,24 @@ impl<'screen> Console<'screen> { } } - /// Clears all text from the console + /// Clear all text from the console. #[doc(alias = "consoleClear")] pub fn clear(&self) { unsafe { consoleClear() } } - /// Resizes the active console to fit in a smaller portion of the screen. + /// Resize the console to fit in a smaller portion of the screen. + /// + /// # Notes /// /// The first two arguments are the desired coordinates of the top-left corner - /// of the console, and the second pair is the new width and height + /// of the console, and the second pair is the new width and height. /// /// # Safety - /// This function is unsafe because it does not validate that the input will produce - /// a console that actually fits on the screen + /// + /// This function is unsafe because it does not validate whether the input will produce + /// a console that actually fits on the screen. + // TODO: Wrap this safely. #[doc(alias = "consoleSetWindow")] pub unsafe fn set_window(&mut self, x: i32, y: i32, width: i32, height: i32) { consoleSetWindow(self.context.as_mut(), x, y, width, height); diff --git a/ctru-rs/src/services/soc.rs b/ctru-rs/src/services/soc.rs index f9cc2586..00a7a5c6 100644 --- a/ctru-rs/src/services/soc.rs +++ b/ctru-rs/src/services/soc.rs @@ -113,7 +113,10 @@ impl Soc { Ipv4Addr::from(raw_id.to_ne_bytes()) } - /// Redirect output streams (i.e. `println` and `eprintln`) to the `3dslink` server. + /// Redirect output streams (i.e. `stdout` and `stderr`) to the `3dslink` server. + /// + /// With this redirection it is possible to send (and view in real time) the output of `stdout` operations, + /// such as `println!` or `dbg!`. /// /// Requires `3dslink` >= 0.6.1 and `new-hbmenu` >= 2.3.0 and the use of the `--server` flag. /// The `--server` flag is also availble to use via `cargo-3ds` if the requirements are met. From 9c955441dc6d5ce6b96b37dbe2520a4295e0abd3 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Thu, 27 Jul 2023 19:55:11 +0200 Subject: [PATCH 27/39] Finalize examples --- ctru-rs/examples/audio-filters.rs | 35 +++++++++++---- ctru-rs/examples/buttons.rs | 24 +++++----- ctru-rs/examples/camera-image.rs | 22 ++++++--- ctru-rs/examples/file-explorer.rs | 20 ++++++--- ctru-rs/examples/gfx-3d-mode.rs | 26 ++++++----- ctru-rs/examples/gfx-bitmap.rs | 29 ++++++------ ctru-rs/examples/gfx-wide-mode.rs | 12 +++++ ctru-rs/examples/graphics-bitmap.rs | 57 ------------------------ ctru-rs/examples/hashmaps.rs | 11 ++++- ctru-rs/examples/hello-both-screens.rs | 11 +++-- ctru-rs/examples/hello-world.rs | 20 +++++++-- ctru-rs/examples/linear-memory.rs | 15 ++++--- ctru-rs/examples/mii-selector.rs | 13 ++++-- ctru-rs/examples/network-sockets.rs | 21 ++++++--- ctru-rs/examples/output-3dslink.rs | 9 ++-- ctru-rs/examples/romfs.rs | 20 +++++---- ctru-rs/examples/software-keyboard.rs | 20 ++++++--- ctru-rs/examples/system-configuration.rs | 14 ++++-- ctru-rs/examples/thread-basic.rs | 2 + ctru-rs/examples/thread-info.rs | 2 +- ctru-rs/examples/thread-locals.rs | 2 +- ctru-rs/examples/time-rtc.rs | 25 ++++------- ctru-rs/examples/title-info.rs | 30 +++++++++---- ctru-rs/examples/touch-screen.rs | 14 +++--- ctru-rs/src/services/gfx.rs | 4 ++ 25 files changed, 267 insertions(+), 191 deletions(-) delete mode 100644 ctru-rs/examples/graphics-bitmap.rs diff --git a/ctru-rs/examples/audio-filters.rs b/ctru-rs/examples/audio-filters.rs index 34fa470b..75941b7b 100644 --- a/ctru-rs/examples/audio-filters.rs +++ b/ctru-rs/examples/audio-filters.rs @@ -1,3 +1,7 @@ +//! Audio Filters example. +//! +//! This example showcases basic audio functionality using [`Ndsp`]. + #![feature(allocator_api)] use std::f32::consts::PI; @@ -9,17 +13,18 @@ use ctru::services::ndsp::{ AudioFormat, AudioMix, InterpolationType, Ndsp, OutputMode, }; +// Configuration for the NDSP process and channels. const SAMPLE_RATE: usize = 22050; const SAMPLES_PER_BUF: usize = SAMPLE_RATE / 10; // 2205 const BYTES_PER_SAMPLE: usize = AudioFormat::PCM16Stereo.size(); const AUDIO_WAVE_LENGTH: usize = SAMPLES_PER_BUF * BYTES_PER_SAMPLE; -// Note Frequencies +// Note frequencies. const NOTEFREQ: [f32; 7] = [220., 440., 880., 1760., 3520., 7040., 14080.]; -// The audio format is Stereo PCM16 -// As such, a sample is made up of 2 "Mono" samples (2 * i16 = u32), one for each channel (left and right) fn fill_buffer(audio_data: &mut [u8], frequency: f32) { + // The audio format is Stereo PCM16. + // As such, a sample is made up of 2 "Mono" samples (2 * i16), one for each channel (left and right). let formatted_data = bytemuck::cast_slice_mut::<_, [i16; 2]>(audio_data); for (i, chunk) in formatted_data.iter_mut().enumerate() { @@ -44,8 +49,7 @@ fn main() { let mut note: usize = 4; - // Filters - + // Filter names to display. let filter_names = [ "None", "Low-Pass", @@ -60,19 +64,26 @@ fn main() { // We set up two wave buffers and alternate between the two, // effectively streaming an infinitely long sine wave. + // We create a buffer on the LINEAR memory that will hold our audio data. + // It's necessary for the buffer to live on the LINEAR memory sector since it needs to be accessed by the DSP processor. let mut audio_data1 = Box::new_in([0u8; AUDIO_WAVE_LENGTH], LinearAllocator); + + // Fill the buffer with the first set of data. This simply writes a sine wave into the buffer. fill_buffer(audio_data1.as_mut_slice(), NOTEFREQ[4]); + // Clone the original buffer to obtain an equal buffer on the LINEAR memory used for double buffering. let audio_data2 = audio_data1.clone(); + // Setup two wave info objects with the correct configuration and ownership of the audio data. let mut wave_info1 = Wave::new(audio_data1, AudioFormat::PCM16Stereo, false); let mut wave_info2 = Wave::new(audio_data2, AudioFormat::PCM16Stereo, false); - let mut ndsp = Ndsp::new().expect("Couldn't obtain NDSP controller"); + // Setup the NDSP service and its configuration. - // This line isn't needed since the default NDSP configuration already sets the output mode to `Stereo` + let mut ndsp = Ndsp::new().expect("Couldn't obtain NDSP controller"); ndsp.set_output_mode(OutputMode::Stereo); + // Channel configuration. We use channel zero but any channel would do just fine. let mut channel_zero = ndsp.channel(0).unwrap(); channel_zero.set_interpolation(InterpolationType::Linear); channel_zero.set_sample_rate(SAMPLE_RATE as f32); @@ -82,6 +93,7 @@ fn main() { let mix = AudioMix::default(); channel_zero.set_mix(&mix); + // First set of queueing for the two buffers. The second one will only play after the first one has ended. channel_zero.queue_wave(&mut wave_info1).unwrap(); channel_zero.queue_wave(&mut wave_info2).unwrap(); @@ -93,6 +105,8 @@ fn main() { filter_names[filter as usize] ); + println!("\x1b[29;16HPress Start to exit"); + let mut altern = true; // true is wave_info1, false is wave_info2 while apt.main_loop() { @@ -101,14 +115,16 @@ fn main() { if keys_down.contains(KeyPad::START) { break; - } // break in order to return to hbmenu + } + // Note frequency controller using the buttons. if keys_down.intersects(KeyPad::DOWN) { note = note.saturating_sub(1); } else if keys_down.intersects(KeyPad::UP) { note = std::cmp::min(note + 1, NOTEFREQ.len() - 1); } + // Filter controller using the buttons. let mut update_params = false; if keys_down.intersects(KeyPad::LEFT) { filter -= 1; @@ -139,12 +155,14 @@ fn main() { } } + // Double buffer alternation depending on the one used. let current: &mut Wave = if altern { &mut wave_info1 } else { &mut wave_info2 }; + // If the current buffer has finished playing, we can refill it with new data and re-queue it. let status = current.status(); if let Status::Done = status { fill_buffer(current.get_buffer_mut().unwrap(), NOTEFREQ[note]); @@ -154,7 +172,6 @@ fn main() { altern = !altern; } - //Wait for VBlank gfx.wait_for_vblank(); } } diff --git a/ctru-rs/examples/buttons.rs b/ctru-rs/examples/buttons.rs index 8bba6c78..0de9e7c9 100644 --- a/ctru-rs/examples/buttons.rs +++ b/ctru-rs/examples/buttons.rs @@ -1,3 +1,7 @@ +//! Buttons example. +//! +//! This example showcases how to retrieve button inputs from the console's HID. + use ctru::prelude::*; fn main() { @@ -18,28 +22,28 @@ fn main() { // Scan for user input on the current frame. hid.scan_input(); - // Get information about which keys were held down on this frame + // Get information about which keys were held down on this frame. let keys = hid.keys_held(); // We only want to print when the keys we're holding now are different - // from what they were on the previous frame + // from what they were on the previous frame. if keys != old_keys { - // Clear the screen + // Clear the screen. console.clear(); - // We print these again because we just cleared the screen above + // We print these again because we just cleared the screen above. println!("Hi there! Try pressing a button"); println!("\x1b[29;16HPress Start to exit"); - // Move the cursor back to the top of the screen + // Move the cursor back to the top of the screen. println!("\x1b[3;0H"); // Print to the screen depending on which keys were held. // - // The .contains() method checks for all of the provided keys, - // and the .intersects() method checks for any of the provided keys. + // The `.contains()` method checks for all of the provided keys, + // and the `.intersects()` method checks for any of the provided keys. // - // You can also use the .bits() method to do direct comparisons on + // You can also use the `.bits()` method to do direct comparisons on // the underlying bits if keys.contains(KeyPad::A) { @@ -54,13 +58,13 @@ fn main() { if keys.intersects(KeyPad::L | KeyPad::R | KeyPad::ZL | KeyPad::ZR) { println!("You held a shoulder button!"); } - if keys.intersects(KeyPad::START) { + if keys.contains(KeyPad::START) { println!("See ya!"); break; } } - // Save our current key presses for the next frame + // Save our current key presses for the next frame. old_keys = keys; gfx.wait_for_vblank(); diff --git a/ctru-rs/examples/camera-image.rs b/ctru-rs/examples/camera-image.rs index 00425999..40c5f755 100644 --- a/ctru-rs/examples/camera-image.rs +++ b/ctru-rs/examples/camera-image.rs @@ -1,3 +1,7 @@ +//! Camera image example. +//! +//! This example demonstrates how to use the built-in cameras to take a picture and display it to the screen. + use ctru::prelude::*; use ctru::services::cam::{Cam, Camera, OutputFormat, ShutterSound, ViewSize}; use ctru::services::gfx::{Flush, Screen, Swap}; @@ -8,7 +12,7 @@ use std::time::Duration; const WIDTH: usize = 400; const HEIGHT: usize = 240; -// The screen size is the width and height multiplied by 2 (RGB565 store pixels in 2 bytes) +// The screen size is the width and height multiplied by 2 (RGB565 store pixels in 2 bytes). const BUF_SIZE: usize = WIDTH * HEIGHT * 2; const WAIT_TIMEOUT: Duration = Duration::from_millis(300); @@ -26,12 +30,11 @@ fn main() { let _console = Console::new(gfx.bottom_screen.borrow_mut()); - let mut keys_down; - println!("Initializing camera"); let mut cam = Cam::new().expect("Failed to initialize CAM service."); + // Camera setup. { let camera = &mut cam.outer_right_cam; @@ -58,21 +61,23 @@ fn main() { let mut buf = vec![0u8; BUF_SIZE]; println!("\nPress R to take a new picture"); - println!("Press Start to exit to Homebrew Launcher"); + println!("\x1b[29;16HPress Start to exit"); while apt.main_loop() { hid.scan_input(); - keys_down = hid.keys_down(); + let keys_down = hid.keys_down(); if keys_down.contains(KeyPad::START) { break; } + // If the user presses the R button. if keys_down.contains(KeyPad::R) { println!("Capturing new image"); let camera = &mut cam.outer_right_cam; + // Take a picture and write it to the buffer. camera .take_picture( &mut buf, @@ -82,12 +87,14 @@ fn main() { ) .expect("Failed to take picture"); + // Play the normal shutter sound. cam.play_shutter_sound(ShutterSound::Normal) .expect("Failed to play shutter sound"); + // Rotate the image and correctly display it on the screen. rotate_image_to_screen(&buf, top_screen.raw_framebuffer().ptr, WIDTH, HEIGHT); - // We will only flush the "camera" screen, since the other screen is handled by `Console` + // We will only flush and swap the "camera" screen, since the other screen is handled by the `Console`. top_screen.flush_buffers(); top_screen.swap_buffers(); @@ -99,6 +106,7 @@ fn main() { // The 3DS' screens are 2 vertical LCD panels rotated by 90 degrees. // As such, we'll need to write a "vertical" image to the framebuffer to have it displayed properly. // This functions rotates an horizontal image by 90 degrees to the right. +// This function is only supposed to be used in this example. In a real world application, the program should use the GPU to draw to the screen. fn rotate_image_to_screen(src: &[u8], framebuf: *mut u8, width: usize, height: usize) { for j in 0..height { for i in 0..width { @@ -115,7 +123,7 @@ fn rotate_image_to_screen(src: &[u8], framebuf: *mut u8, width: usize, height: u let draw_index = (draw_x * height + draw_y) * 2; // This 2 stands for the number of bytes per pixel (16 bits) unsafe { - // We'll work with pointers since the frambuffer is a raw pointer regardless. + // We'll work with pointers since the framebuffer is a raw pointer regardless. // The offsets are completely safe as long as the width and height are correct. let pixel_pointer = framebuf.offset(draw_index as isize); pixel_pointer.copy_from(src.as_ptr().offset(read_index as isize), 2); diff --git a/ctru-rs/examples/file-explorer.rs b/ctru-rs/examples/file-explorer.rs index 748a9379..4a7fbdae 100644 --- a/ctru-rs/examples/file-explorer.rs +++ b/ctru-rs/examples/file-explorer.rs @@ -1,5 +1,7 @@ -//! A file explorer which shows off using standard library file system APIs to -//! read the SD card. +//! File Explorer example. +//! +//! This (rather complex) example creates a working text-based file explorer which shows off using standard library file system APIs to +//! read the SD card and RomFS (if properly read via the `romfs:/` prefix). use ctru::applets::swkbd::{Button, SoftwareKeyboard}; use ctru::prelude::*; @@ -15,6 +17,7 @@ fn main() { let mut hid = Hid::new().unwrap(); let gfx = Gfx::new().unwrap(); + // Mount the RomFS if available. #[cfg(all(feature = "romfs", romfs_exists))] let _romfs = ctru::services::romfs::RomFS::new().unwrap(); @@ -50,6 +53,7 @@ impl<'a> FileExplorer<'a> { fn run(&mut self) { self.running = true; + // Print the file explorer commands. self.print_menu(); while self.running && self.apt.main_loop() { @@ -62,8 +66,10 @@ impl<'a> FileExplorer<'a> { self.path.pop(); self.console.clear(); self.print_menu(); + // Open a directory/file to read. } else if input.contains(KeyPad::A) { self.get_input_and_run(Self::set_next_path); + // Open a specific path using the `SoftwareKeyboard` applet. } else if input.contains(KeyPad::X) { self.get_input_and_run(Self::set_exact_path); } @@ -100,7 +106,7 @@ impl<'a> FileExplorer<'a> { } }; - println!("Start to exit, A to select an entry by number, B to go up a directory, X to set the path."); + println!("Press Start to exit, A to select an entry by number, B to go up a directory, X to set the path."); } fn print_dir_entries(&mut self) { @@ -137,7 +143,7 @@ impl<'a> FileExplorer<'a> { } } - /// Paginate output + /// Paginate output.' fn wait_for_page_down(&mut self) { println!("Press A to go to next page, or Start to exit"); @@ -163,14 +169,14 @@ impl<'a> FileExplorer<'a> { match keyboard.get_string(2048) { Ok((path, Button::Right)) => { - // Clicked "OK" + // Clicked "OK". action(self, path); } Ok((_, Button::Left)) => { - // Clicked "Cancel" + // Clicked "Cancel". } Ok((_, Button::Middle)) => { - // This button wasn't shown + // This button wasn't shown. unreachable!() } Err(e) => { diff --git a/ctru-rs/examples/gfx-3d-mode.rs b/ctru-rs/examples/gfx-3d-mode.rs index 582994ef..c5b9de80 100644 --- a/ctru-rs/examples/gfx-3d-mode.rs +++ b/ctru-rs/examples/gfx-3d-mode.rs @@ -1,10 +1,15 @@ +//! 3D Graphics example. +//! +//! This example showcases 3D mode rendering (using the CPU). +//! In a normal application, all rendering should be hanlded via the GPU. + use ctru::prelude::*; use ctru::services::gfx::{Flush, Screen, Side, Swap, TopScreen3D}; -/// See `graphics-bitmap.rs` for details on how the image is generated. -/// -/// WARNING: this example uses 3D mode in a rather unnatural way, and should -/// probably not be viewed for too long or at all if you are photosensitive. +// See `graphics-bitmap.rs` for details on how the image is generated. +// +// WARNING: this example uses 3D mode in a rather unnatural way, and should +// probably not be viewed for too long or at all if you are photosensitive. const IMAGE: &[u8] = include_bytes!("assets/ferris.rgb"); static ZERO: &[u8] = &[0; IMAGE.len()]; @@ -17,7 +22,8 @@ fn main() { let apt = Apt::new().expect("Couldn't obtain APT controller"); let _console = Console::new(gfx.bottom_screen.borrow_mut()); - println!("Press Start to exit.\nPress A to switch sides (be sure to have 3D mode enabled)."); + println!("Press A to switch sides (be sure to have set the 3D slider correctly)."); + println!("\x1b[29;16HPress Start to exit"); gfx.top_screen.borrow_mut().set_double_buffering(true); @@ -25,39 +31,40 @@ fn main() { let mut current_side = Side::Left; - // 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::START) { break; } + // Split the TopScreen3D to get references to the two render surfaces. let (mut left, mut right) = top_screen.split_mut(); let left_buf = left.raw_framebuffer(); let right_buf = right.raw_framebuffer(); - // Clear both buffers every time, in case the user switches sides this loop + // Clear both buffers every time, in case the user switches sides this loop. unsafe { left_buf.ptr.copy_from(ZERO.as_ptr(), ZERO.len()); right_buf.ptr.copy_from(ZERO.as_ptr(), ZERO.len()); } if hid.keys_down().contains(KeyPad::A) { - // flip which buffer we're writing to + // Switch which buffer we're writing to. current_side = match current_side { Side::Left => Side::Right, Side::Right => Side::Left, }; } + // Obtain the framebuffer of the currently rendered side. let buf = match current_side { Side::Left => left_buf.ptr, Side::Right => right_buf.ptr, }; + // Render the image to the surface's buffer. unsafe { buf.copy_from(IMAGE.as_ptr(), IMAGE.len()); } @@ -67,7 +74,6 @@ fn main() { top_screen.flush_buffers(); top_screen.swap_buffers(); - //Wait for VBlank gfx.wait_for_vblank(); } } diff --git a/ctru-rs/examples/gfx-bitmap.rs b/ctru-rs/examples/gfx-bitmap.rs index f680ff22..39634c2b 100644 --- a/ctru-rs/examples/gfx-bitmap.rs +++ b/ctru-rs/examples/gfx-bitmap.rs @@ -1,3 +1,6 @@ +/// Bitmap Graphics example. +/// +/// This example uses the CPU to render a simple bitmap image to the screen. use ctru::prelude::*; use ctru::services::gfx::{Flush, Screen, Swap}; @@ -22,7 +25,8 @@ fn main() { let apt = Apt::new().expect("Couldn't obtain APT controller"); let _console = Console::new(gfx.top_screen.borrow_mut()); - println!("\x1b[21;4HPress Start to exit, or A to flip the image."); + println!("\x1b[21;4HPress A to flip the image."); + println!("\x1b[29;16HPress Start to exit"); let mut bottom_screen = gfx.bottom_screen.borrow_mut(); @@ -37,18 +41,23 @@ fn main() { let mut image_bytes = IMAGE; - // Main loop + // We assume the image is the correct size already, so we drop width + height. + let frame_buffer = bottom_screen.raw_framebuffer(); + + // We copy the image to the framebuffer. + unsafe { + frame_buffer + .ptr + .copy_from(image_bytes.as_ptr(), image_bytes.len()); + } + 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::START) { break; } - // We assume the image is the correct size already, so we drop width + height. - let frame_buffer = bottom_screen.raw_framebuffer(); - if hid.keys_down().contains(KeyPad::A) { image_bytes = if std::ptr::eq(image_bytes, IMAGE) { &flipped_image[..] @@ -57,18 +66,10 @@ fn main() { }; } - // this copies more than necessary (once per frame) but it's fine... - unsafe { - frame_buffer - .ptr - .copy_from(image_bytes.as_ptr(), image_bytes.len()); - } - // Flush framebuffers. Since we're not using double buffering, // this will render the pixels immediately bottom_screen.flush_buffers(); - //Wait for VBlank gfx.wait_for_vblank(); } } diff --git a/ctru-rs/examples/gfx-wide-mode.rs b/ctru-rs/examples/gfx-wide-mode.rs index 80365384..109169d7 100644 --- a/ctru-rs/examples/gfx-wide-mode.rs +++ b/ctru-rs/examples/gfx-wide-mode.rs @@ -1,3 +1,10 @@ +//! Wide-Mode Graphics example. +//! +//! This example demonstrates the wide-mode capability of the top screen +//! which doubles the horizontal resolution of the screen by merging the 2 stereoscopic 3D sides. +//! +//! Beware, wide-mode doesn't work on Old 2DS consoles. + use ctru::prelude::*; fn main() { @@ -9,6 +16,7 @@ fn main() { let mut console = Console::new(gfx.top_screen.borrow_mut()); println!("Press A to enable/disable wide screen mode."); + println!("\x1b[29;16HPress Start to exit"); while apt.main_loop() { hid.scan_input(); @@ -17,14 +25,18 @@ fn main() { break; } + // Since we can't set wide-mode while running the console (since that would break the currently displayed text), + // we need to rebuild the console each time we want to make the switch. if hid.keys_down().contains(KeyPad::A) { drop(console); + // Switch the state of the wide-mode. let wide_mode = gfx.top_screen.borrow().is_wide(); gfx.top_screen.borrow_mut().set_wide_mode(!wide_mode); console = Console::new(gfx.top_screen.borrow_mut()); println!("Press A to enable/disable wide screen mode."); + println!("\x1b[29;16HPress Start to exit"); } gfx.wait_for_vblank(); diff --git a/ctru-rs/examples/graphics-bitmap.rs b/ctru-rs/examples/graphics-bitmap.rs deleted file mode 100644 index df9ce11f..00000000 --- a/ctru-rs/examples/graphics-bitmap.rs +++ /dev/null @@ -1,57 +0,0 @@ -use ctru::prelude::*; -use ctru::services::gfx::{Flush, Screen, Swap}; - -/// Ferris image taken from and scaled down to 320x240px. -/// To regenerate the data, you will need to install `imagemagick` and run this -/// command from the `examples` directory: -/// -/// ```sh -/// magick assets/ferris.png -channel-fx "red<=>blue" -rotate 90 assets/ferris.rgb -/// ``` -/// -/// This creates an image appropriate for the default frame buffer format of -/// [`Bgr8`](ctru::services::gspgpu::FramebufferFormat::Bgr8) -/// and rotates the image 90° to account for the portrait mode screen. -static IMAGE: &[u8] = include_bytes!("assets/ferris.rgb"); - -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()); - - println!("\x1b[21;16HPress Start to exit."); - - let mut bottom_screen = gfx.bottom_screen.borrow_mut(); - - // We don't need double buffering in this example. - // In this way we can draw our image only once on screen. - bottom_screen.set_double_buffering(false); - - // We assume the image is the correct size already, so we drop width + height. - let frame_buffer = bottom_screen.raw_framebuffer(); - - // Copy the image into the frame buffer - unsafe { - frame_buffer.ptr.copy_from(IMAGE.as_ptr(), IMAGE.len()); - } - - // 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::START) { - break; - } - - // Flush and swap framebuffers - bottom_screen.flush_buffers(); - bottom_screen.swap_buffers(); - - //Wait for VBlank - gfx.wait_for_vblank(); - } -} diff --git a/ctru-rs/examples/hashmaps.rs b/ctru-rs/examples/hashmaps.rs index 7d4d8c43..e5630688 100644 --- a/ctru-rs/examples/hashmaps.rs +++ b/ctru-rs/examples/hashmaps.rs @@ -1,10 +1,16 @@ +//! Hashmap example. +//! +//! This example showcases using Hashmaps on the 3DS console using the functionality implemented by the standard library. +//! While it may seem inappropriate for such a simple (and somewhat out-of-scope) example to be included here, it's important to note how +//! normally Hashmaps wouldn't work on the console, and are only capable to because of the internal implementations made by `ctru-rs`. +//! +//! As such, this example functions more closely to a test than a demonstration. + use ctru::prelude::*; fn main() { ctru::use_panic_handler(); - // Initialize services - // // HashMaps generate hashes thanks to the 3DS' cryptografically secure generator. // This generator is only active when activating the `PS` service. // This service is automatically initialized. @@ -19,6 +25,7 @@ fn main() { map.remove("A Key!"); println!("{map:#?}"); + println!("\x1b[29;16HPress Start to exit"); while apt.main_loop() { gfx.wait_for_vblank(); diff --git a/ctru-rs/examples/hello-both-screens.rs b/ctru-rs/examples/hello-both-screens.rs index f2007f1e..1f2b3839 100644 --- a/ctru-rs/examples/hello-both-screens.rs +++ b/ctru-rs/examples/hello-both-screens.rs @@ -1,3 +1,7 @@ +//! Hello World example using both screens. +//! +//! This is similar to the `hello-world` example, with the main difference of using 2 virtual `Console`s that can be alternated to print on both screens. + use ctru::prelude::*; fn main() { @@ -11,14 +15,15 @@ fn main() { let top_screen = Console::new(gfx.top_screen.borrow_mut()); // Start a console on the bottom screen. - // The most recently initialized console will be active by default + // The most recently initialized console will be active by default. let bottom_screen = Console::new(gfx.bottom_screen.borrow_mut()); - // Let's print on the top screen first + // Let's print on the top screen first. + // Since the bottom screen is currently selected (being created afterwards), it is required to select the top screen console first. top_screen.select(); println!("This is the top screen! We have a lot of space up here!"); - // Now let's print something on the bottom screen + // Now let's print something on the bottom screen. bottom_screen.select(); println!("\x1b[14;00HThis is the bottom screen."); println!("There's not as much space down here, but that's okay."); diff --git a/ctru-rs/examples/hello-world.rs b/ctru-rs/examples/hello-world.rs index a92cb90a..92104844 100644 --- a/ctru-rs/examples/hello-world.rs +++ b/ctru-rs/examples/hello-world.rs @@ -1,15 +1,25 @@ -use ctru::prelude::*; +//! Hello World example. +//! +//! Simple "Hello World" application to showcase the basic setup needed for any user-oriented app to work. +use ctru::prelude::*; use std::io::BufWriter; fn main() { + // Setup the custom panic handler in case any errors arise. + // Thanks to it the user will get promptly notified of any panics. ctru::use_panic_handler(); + // Setup Graphics, Controller Inputs, Application runtime. + // These is standard setup any app would need. 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"); + + // Create a Console to print our "Hello, World!" to. let _console = Console::new(gfx.top_screen.borrow_mut()); + // Snazzy message created via `ferris_says`. let out = b"Hello fellow Rustaceans, I'm on the Nintendo 3DS!"; let width = 24; @@ -21,16 +31,18 @@ fn main() { String::from_utf8_lossy(&writer.into_inner().unwrap()) ); - // Main loop + println!("\x1b[29;16HPress Start to exit"); + + // Main application loop. This checks whether the app is normally running in the foreground. while apt.main_loop() { - //Scan all the inputs. This should be done once for each frame + // Scan all the controller inputs. hid.scan_input(); if hid.keys_down().contains(KeyPad::START) { break; } - //Wait for VBlank + // Use VSync to cap the framerate at the same speed as the LCD screen's refresh rate (60 fps). gfx.wait_for_vblank(); } } diff --git a/ctru-rs/examples/linear-memory.rs b/ctru-rs/examples/linear-memory.rs index e6c18dc9..de653e6b 100644 --- a/ctru-rs/examples/linear-memory.rs +++ b/ctru-rs/examples/linear-memory.rs @@ -1,3 +1,9 @@ +//! LINEAR memory example. +//! +//! This example showcases simple allocation on the LINEAR memory sector. +//! Using LINEAR memory is required when sending data to the GPU or DSP processor. + +// You will need to activate this unstable feature to use custom allocators. #![feature(allocator_api)] use ctru::linear::LinearAllocator; @@ -11,11 +17,13 @@ fn main() { let apt = Apt::new().expect("Couldn't obtain APT controller"); let _console = Console::new(gfx.top_screen.borrow_mut()); + // The `LinearAllocator` is always available for use. + // Luckily, we can always read how much memory is available to be allocated on it. let linear_space_before = LinearAllocator::free_space(); - // Normal `Box` on the heap + // Normal `Box` on the heap. let heap_box = Box::new(1492); - // `Box` living on the linear memory sector + // `Box` living on the LINEAR memory. let linear_box: Box = Box::new_in(2022, LinearAllocator); println!("This value is from the heap: {heap_box}"); @@ -29,16 +37,13 @@ fn main() { println!("\x1b[29;16HPress Start to 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::START) { break; } - //Wait for VBlank gfx.wait_for_vblank(); } } diff --git a/ctru-rs/examples/mii-selector.rs b/ctru-rs/examples/mii-selector.rs index b12f217f..db3a9ea9 100644 --- a/ctru-rs/examples/mii-selector.rs +++ b/ctru-rs/examples/mii-selector.rs @@ -1,3 +1,7 @@ +//! Mii Selector example. +//! +//! This example showcases the use of the MiiSelector applet to obtain Mii data from the user's input. + use ctru::applets::mii_selector::{Error, MiiSelector, Options}; use ctru::prelude::*; @@ -9,12 +13,16 @@ fn main() { let apt = Apt::new().expect("Couldn't obtain APT controller"); let _console = Console::new(gfx.top_screen.borrow_mut()); + // Setup the Mii Selector configuration. let mut mii_selector = MiiSelector::new(); + // The Mii Selector window can be closed without selecting a Mii. mii_selector.set_options(Options::ENABLE_CANCEL); mii_selector.set_initial_index(3); + // The first user-made Mii cannot be used. mii_selector.blacklist_user_mii(0.into()); mii_selector.set_title("Great Mii Selector!"); + // Launch the Mii Selector and use its result to print the selected Mii's information. match mii_selector.launch() { Ok(result) => { println!("Mii type: {:?}", result.mii_type); @@ -29,16 +37,15 @@ fn main() { Err(Error::NoMiiSelected) => println!("No Mii selected"), } - // Main loop + println!("\x1b[29;16HPress Start to exit"); + 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::START) { break; } - //Wait for VBlank gfx.wait_for_vblank(); } } diff --git a/ctru-rs/examples/network-sockets.rs b/ctru-rs/examples/network-sockets.rs index bbea5102..0cc70ad9 100644 --- a/ctru-rs/examples/network-sockets.rs +++ b/ctru-rs/examples/network-sockets.rs @@ -1,3 +1,7 @@ +//! Network Sockets example. +//! +//! This example showcases the use of network sockets via the `Soc` service and the standard library's implementations. + use ctru::prelude::*; use std::io::{self, Read, Write}; @@ -14,20 +18,27 @@ fn main() { println!("\nlibctru sockets demo\n"); + // Owning a living handle to the `Soc` service is required to use network functionalities. let soc = Soc::new().unwrap(); + // Listen on the standard HTTP port (80). let server = TcpListener::bind("0.0.0.0:80").unwrap(); server.set_nonblocking(true).unwrap(); println!("Point your browser to http://{}/\n", soc.host_address()); + println!("\x1b[29;16HPress Start to exit"); while apt.main_loop() { - gfx.wait_for_vblank(); + hid.scan_input(); + if hid.keys_down().contains(KeyPad::START) { + break; + }; match server.accept() { Ok((mut stream, socket_addr)) => { println!("Got connection from {socket_addr}"); + // Print the HTTP request sent by the client (most likely, a web browser). let mut buf = [0u8; 4096]; match stream.read(&mut buf) { Ok(_) => { @@ -43,15 +54,18 @@ fn main() { } } + // Return a HTML page with a simple "Hello World!". let response = b"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\nHello world\r\n"; if let Err(e) = stream.write(response) { println!("Error writing http response: {e}"); } + // Shutdown the stream (depending on the web browser used to view the page, this might cause some issues). stream.shutdown(Shutdown::Both).unwrap(); } Err(e) => match e.kind() { + // If the TCP socket would block execution, just try again. std::io::ErrorKind::WouldBlock => {} _ => { println!("Error accepting connection: {e}"); @@ -60,9 +74,6 @@ fn main() { }, } - hid.scan_input(); - if hid.keys_down().contains(KeyPad::START) { - break; - }; + gfx.wait_for_vblank(); } } diff --git a/ctru-rs/examples/output-3dslink.rs b/ctru-rs/examples/output-3dslink.rs index 8314efa7..9df3f3d7 100644 --- a/ctru-rs/examples/output-3dslink.rs +++ b/ctru-rs/examples/output-3dslink.rs @@ -1,4 +1,6 @@ -//! Use the `3dslink --server` option for redirecting output from the 3DS back +//! Output redirection example. +//! +//! This example uses the `3dslink --server` option for redirecting output from the 3DS back //! to the device that sent the executable. //! //! For now, `cargo 3ds run` does not support this flag, so to run this example @@ -17,24 +19,23 @@ fn main() { let mut hid = Hid::new().expect("Couldn't obtain HID controller"); let apt = Apt::new().expect("Couldn't obtain APT controller"); + // We need to use network sockets to send the data stream back. let mut soc = Soc::new().expect("Couldn't obtain SOC controller"); + // Set the output to be redirected to the `3dslink` server. 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::START) { break; } - //Wait for VBlank gfx.wait_for_vblank(); } } diff --git a/ctru-rs/examples/romfs.rs b/ctru-rs/examples/romfs.rs index 11382035..490a785c 100644 --- a/ctru-rs/examples/romfs.rs +++ b/ctru-rs/examples/romfs.rs @@ -1,3 +1,7 @@ +//! RomFS example. +//! +//! This example showcases the RomFS service and how to mount it to include a read-only filesystem within the application bundle. + use ctru::prelude::*; fn main() { @@ -9,35 +13,35 @@ fn main() { let _console = Console::new(gfx.top_screen.borrow_mut()); cfg_if::cfg_if! { - // Run this code if RomFS are wanted and available - // This never fails as `ctru-rs` examples inherit all of the `ctru` features, - // but it might if a normal user application wasn't setup correctly + // Run this code if RomFS are wanted and available. + // This never fails as `ctru-rs` examples inherit all of the `ctru-rs` features, + // but it might if a normal user application wasn't setup correctly. if #[cfg(all(feature = "romfs", romfs_exists))] { + // Mount the romfs volume. let _romfs = ctru::services::romfs::RomFS::new().unwrap(); + // Open a simple text file present in the RomFS volume. + // Remember to use the `romfs:/` prefix when working with `RomFS`. let f = std::fs::read_to_string("romfs:/test-file.txt").unwrap(); println!("Contents of test-file.txt: \n{f}\n"); let f = std::fs::read_to_string("romfs:/ファイル.txt").unwrap(); - // While RomFS supports UTF-16 file paths, `Console` doesn't... + // While `RomFS` supports UTF-16 file paths, `Console` does not, so we'll use a placeholder for the text. println!("Contents of [UTF-16 File]: \n{f}\n"); } else { println!("No RomFS was found, are you sure you included it?") } } - println!("\nPress START to exit"); + println!("\x1b[29;16HPress Start to 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::START) { break; } - //Wait for VBlank gfx.wait_for_vblank(); } } diff --git a/ctru-rs/examples/software-keyboard.rs b/ctru-rs/examples/software-keyboard.rs index 4d7c4f2c..269ccf09 100644 --- a/ctru-rs/examples/software-keyboard.rs +++ b/ctru-rs/examples/software-keyboard.rs @@ -1,3 +1,7 @@ +//! Software Keyboard example. +//! +//! This example showcases the use of the Software Keyboard applet to receive text input from the user. + use ctru::applets::swkbd::{Button, SoftwareKeyboard}; use ctru::prelude::*; @@ -9,13 +13,17 @@ fn main() { let gfx = Gfx::new().unwrap(); let _console = Console::new(gfx.top_screen.borrow_mut()); - println!("Press A to enter some text or press Start to quit"); + println!("Press A to enter some text."); + println!("\x1b[29;16HPress Start to exit"); while apt.main_loop() { - gfx.wait_for_vblank(); - hid.scan_input(); + if hid.keys_down().contains(KeyPad::START) { + break; + } + + // If the user request to write some input. if hid.keys_down().contains(KeyPad::A) { // Prepares a software keyboard with two buttons: One to cancel input and one // to accept it. You can also use `SoftwareKeyboard::new()` to launch the keyboard in different @@ -23,7 +31,7 @@ fn main() { let mut keyboard = SoftwareKeyboard::default(); // Raise the software keyboard. You can perform different actions depending on which - // software button the user pressed + // software button the user pressed. match keyboard.get_string(2048) { Ok((text, Button::Right)) => println!("You entered: {text}"), Ok((_, Button::Left)) => println!("Cancelled"), @@ -32,8 +40,6 @@ fn main() { } } - if hid.keys_down().contains(KeyPad::START) { - break; - } + gfx.wait_for_vblank(); } } diff --git a/ctru-rs/examples/system-configuration.rs b/ctru-rs/examples/system-configuration.rs index 001233df..f1748f7b 100644 --- a/ctru-rs/examples/system-configuration.rs +++ b/ctru-rs/examples/system-configuration.rs @@ -1,3 +1,8 @@ +//! System Configuration example. +//! +//! This example showcases the CFGU service to retrieve information about the console that the application is running on, +//! such as the model, region and used language. + use ctru::prelude::*; use ctru::services::cfgu::Cfgu; @@ -7,23 +12,24 @@ fn main() { 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 cfgu = Cfgu::new().expect("Couldn't obtain CFGU controller"); let _console = Console::new(gfx.top_screen.borrow_mut()); + // Initialize the CFGU service to retrieve all wanted information. + let cfgu = Cfgu::new().expect("Couldn't obtain CFGU controller"); + println!("\x1b[0;0HRegion: {:?}", cfgu.region().unwrap()); println!("\x1b[10;0HLanguage: {:?}", cfgu.language().unwrap()); println!("\x1b[20;0HModel: {:?}", cfgu.model().unwrap()); - // Main loop + println!("\x1b[29;16HPress Start to exit"); + 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::START) { break; } - //Wait for VBlank gfx.wait_for_vblank(); } } diff --git a/ctru-rs/examples/thread-basic.rs b/ctru-rs/examples/thread-basic.rs index 33a8ea98..3e4604b2 100644 --- a/ctru-rs/examples/thread-basic.rs +++ b/ctru-rs/examples/thread-basic.rs @@ -33,6 +33,8 @@ fn main() { println!("Created thread {ix}"); } + println!("\x1b[29;16HPress Start to exit"); + while apt.main_loop() { gfx.wait_for_vblank(); diff --git a/ctru-rs/examples/thread-info.rs b/ctru-rs/examples/thread-info.rs index 28297ac6..46d34d3c 100644 --- a/ctru-rs/examples/thread-info.rs +++ b/ctru-rs/examples/thread-info.rs @@ -36,7 +36,7 @@ fn main() { .unwrap(); println!("sys thread exited"); - println!("\nPress Start to exit"); + println!("\x1b[29;16HPress Start to exit"); while apt.main_loop() { hid.scan_input(); diff --git a/ctru-rs/examples/thread-locals.rs b/ctru-rs/examples/thread-locals.rs index 80d85085..72458c92 100644 --- a/ctru-rs/examples/thread-locals.rs +++ b/ctru-rs/examples/thread-locals.rs @@ -52,7 +52,7 @@ fn main() { ); }); - println!("Press Start to exit"); + println!("\x1b[29;16HPress Start to exit"); while apt.main_loop() { hid.scan_input(); diff --git a/ctru-rs/examples/time-rtc.rs b/ctru-rs/examples/time-rtc.rs index 377fd5c1..e8c3a950 100644 --- a/ctru-rs/examples/time-rtc.rs +++ b/ctru-rs/examples/time-rtc.rs @@ -1,3 +1,8 @@ +//! Time Clock example. +//! +//! This example showcases how to retrieve the local time set in the console's configuration +//! using the implementations of the standard library. + use ctru::prelude::*; fn main() { @@ -9,11 +14,9 @@ fn main() { let _console = Console::new(gfx.top_screen.borrow_mut()); - print!("\x1b[30;16HPress Start to exit."); + println!("\x1b[29;16HPress Start to 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::START) { @@ -21,22 +24,12 @@ fn main() { } // Technically, this actually just gets local time and assumes it's UTC, - // since the 3DS doesn't seem to support timezones... + // since the 3DS doesn't seem to support timezones. let cur_time = time::OffsetDateTime::now_utc(); - let hours = cur_time.hour(); - let minutes = cur_time.minute(); - let seconds = cur_time.second(); - - let weekday = cur_time.weekday().to_string(); - let month = cur_time.month().to_string(); - let day = cur_time.day(); - let year = cur_time.year(); - - println!("\x1b[1;1H{hours:0>2}:{minutes:0>2}:{seconds:0>2}"); - println!("{weekday} {month} {day} {year}"); + // Display the retrieved information. + println!("\x1b[1;1H{cur_time}"); - //Wait for VBlank gfx.wait_for_vblank(); } } diff --git a/ctru-rs/examples/title-info.rs b/ctru-rs/examples/title-info.rs index 25b5c75f..9cb4db82 100644 --- a/ctru-rs/examples/title-info.rs +++ b/ctru-rs/examples/title-info.rs @@ -1,3 +1,8 @@ +//! Title Info example. +//! +//! This example showcases how to retrieve information about the titles installed on the console running the application +//! via the Application Manager (Am) service. + use ctru::prelude::*; use ctru::services::am::Am; use ctru::services::fs::FsMediaType; @@ -8,20 +13,27 @@ fn main() { 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 am = Am::new().expect("Couldn't obtain AM controller"); + let top_screen = Console::new(gfx.top_screen.borrow_mut()); let bottom_screen = Console::new(gfx.bottom_screen.borrow_mut()); + // Setup the AM service to retrieve the wanted information. + let am = Am::new().expect("Couldn't obtain AM controller"); + + // Amount of titles installed on the SD card. let sd_count = am .title_count(FsMediaType::Sd) .expect("Failed to get sd title count"); + // List of titles installed on the SD card. let sd_list = am .title_list(FsMediaType::Sd) .expect("Failed to get sd title list"); + // Amount of titles installed on the NAND storage. let nand_count = am .title_count(FsMediaType::Nand) .expect("Failed to get nand title count"); + // List of titles installed on the NAND storage. let nand_list = am .title_list(FsMediaType::Nand) .expect("Failed to get nand title list"); @@ -30,9 +42,7 @@ fn main() { let mut refresh = true; let mut use_nand = false; - // 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::START) { @@ -58,13 +68,15 @@ fn main() { } } + // Render the title list via a scrollable text UI. if refresh { let mut selected_title = cur_list.iter().skip(offset).next().unwrap(); - // Clear top screen and write title ids to it + + // Clear the top screen and write title IDs to it. top_screen.select(); print!("\x1b[2J"); - // Top screen seems to have only 30 rows + // Top screen has 30 rows. for (i, title) in cur_list.iter().skip(offset).take(29).enumerate() { if i == 0 { selected_title = title; @@ -74,17 +86,18 @@ fn main() { } } - // Clear bottom screen and write properties of selected title to it + // Clear the bottom screen and write the properties of selected title to it. bottom_screen.select(); println!("\x1b[2J"); - // Move cursor to top left + + // Move cursor to top left. println!("\x1b[1;1"); println!("Size: {} kB", selected_title.size() / 1024); println!("Version: 0x{:x}", selected_title.version()); println!("Product code: \"{}\"", selected_title.product_code()); - println!("\x1b[26;0HPress START to exit"); + println!("\x1b[29;16HPress Start to exit"); if use_nand { println!("Press SELECT to choose SD Card"); println!("Current medium: NAND"); @@ -98,7 +111,6 @@ fn main() { refresh = false; } - //Wait for VBlank gfx.wait_for_vblank(); } } diff --git a/ctru-rs/examples/touch-screen.rs b/ctru-rs/examples/touch-screen.rs index 204f324f..a7850555 100644 --- a/ctru-rs/examples/touch-screen.rs +++ b/ctru-rs/examples/touch-screen.rs @@ -1,3 +1,7 @@ +//! Touch Screen example. +//! +//! This example showcases how to retrieve the touch screen's touch information via the HID service. + use ctru::prelude::*; fn main() { @@ -9,7 +13,7 @@ fn main() { let console = Console::new(gfx.top_screen.borrow_mut()); - // We'll hold the previous touch position for comparison. + // We'll save the previous touch position for comparison. let mut old_touch: (u16, u16) = (0, 0); println!("\x1b[29;16HPress Start to exit"); @@ -26,22 +30,22 @@ fn main() { let touch: (u16, u16) = hid.touch_position(); // We only want to print the position when it's different - // from what it was on the previous frame + // from what it was on the previous frame. if touch != old_touch { // Special case for when the user lifts the stylus/finger from the screen. // This is done to avoid some screen tearing. if touch == (0, 0) { console.clear(); - // Print again because we just cleared the screen + // Print again because we just cleared the screen. println!("\x1b[29;16HPress Start to exit"); } - // Move the cursor back to the top of the screen and print the coordinates + // Move the cursor back to the top of the screen and print the coordinates. print!("\x1b[1;1HTouch Screen position: {:#?}", touch); } - // Save our current touch position for the next frame + // Save our current touch position for the next frame. old_touch = touch; gfx.wait_for_vblank(); diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index 5a2fc620..0769b811 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -414,8 +414,12 @@ impl TopScreen { /// Enable or disable wide mode on the top screen. /// + /// # Notes + /// /// [`Swap::swap_buffers`] must be called after this method for the configuration /// to take effect. + /// + /// Wide mode does NOT work on Old 2DS models (but still does on New 2DS XL models). #[doc(alias = "gfxSetWide")] pub fn set_wide_mode(&mut self, enable: bool) { unsafe { From 2af0268f8965a29a1fe92b55d0377fed403eeccf Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Fri, 28 Jul 2023 14:11:58 +0200 Subject: [PATCH 28/39] Fix examples after thorough testing --- ctru-rs/examples/camera-image.rs | 2 +- ctru-rs/examples/gfx-3d-mode.rs | 6 +++--- ctru-rs/examples/gfx-bitmap.rs | 9 +++++++++ ctru-rs/examples/network-sockets.rs | 12 +++++++----- ctru-rs/examples/software-keyboard.rs | 5 ++--- ctru-rs/examples/time-rtc.rs | 13 +++++++++++-- ctru-rs/examples/title-info.rs | 4 ++-- ctru-rs/examples/touch-screen.rs | 6 +++--- ctru-rs/src/console.rs | 4 +++- 9 files changed, 41 insertions(+), 20 deletions(-) diff --git a/ctru-rs/examples/camera-image.rs b/ctru-rs/examples/camera-image.rs index 40c5f755..851aa2a8 100644 --- a/ctru-rs/examples/camera-image.rs +++ b/ctru-rs/examples/camera-image.rs @@ -61,7 +61,7 @@ fn main() { let mut buf = vec![0u8; BUF_SIZE]; println!("\nPress R to take a new picture"); - println!("\x1b[29;16HPress Start to exit"); + println!("Press Start to exit"); while apt.main_loop() { hid.scan_input(); diff --git a/ctru-rs/examples/gfx-3d-mode.rs b/ctru-rs/examples/gfx-3d-mode.rs index c5b9de80..32d7af1b 100644 --- a/ctru-rs/examples/gfx-3d-mode.rs +++ b/ctru-rs/examples/gfx-3d-mode.rs @@ -10,7 +10,6 @@ use ctru::services::gfx::{Flush, Screen, Side, Swap, TopScreen3D}; // // WARNING: this example uses 3D mode in a rather unnatural way, and should // probably not be viewed for too long or at all if you are photosensitive. - const IMAGE: &[u8] = include_bytes!("assets/ferris.rgb"); static ZERO: &[u8] = &[0; IMAGE.len()]; @@ -22,8 +21,9 @@ fn main() { let apt = Apt::new().expect("Couldn't obtain APT controller"); let _console = Console::new(gfx.bottom_screen.borrow_mut()); - println!("Press A to switch sides (be sure to have set the 3D slider correctly)."); - println!("\x1b[29;16HPress Start to exit"); + println!("Press A to switch sides."); + println!("Make sure to have set the 3D slider correctly"); + println!("\x1b[29;12HPress Start to exit"); gfx.top_screen.borrow_mut().set_double_buffering(true); diff --git a/ctru-rs/examples/gfx-bitmap.rs b/ctru-rs/examples/gfx-bitmap.rs index 39634c2b..8efb2beb 100644 --- a/ctru-rs/examples/gfx-bitmap.rs +++ b/ctru-rs/examples/gfx-bitmap.rs @@ -64,6 +64,15 @@ fn main() { } else { IMAGE }; + + let frame_buffer = bottom_screen.raw_framebuffer(); + + // We render the newly switched image to the framebuffer. + unsafe { + frame_buffer + .ptr + .copy_from(image_bytes.as_ptr(), image_bytes.len()); + } } // Flush framebuffers. Since we're not using double buffering, diff --git a/ctru-rs/examples/network-sockets.rs b/ctru-rs/examples/network-sockets.rs index 0cc70ad9..d55e29c2 100644 --- a/ctru-rs/examples/network-sockets.rs +++ b/ctru-rs/examples/network-sockets.rs @@ -12,12 +12,9 @@ fn main() { ctru::use_panic_handler(); let gfx = Gfx::new().unwrap(); - let _console = Console::new(gfx.top_screen.borrow_mut()); let mut hid = Hid::new().unwrap(); let apt = Apt::new().unwrap(); - println!("\nlibctru sockets demo\n"); - // Owning a living handle to the `Soc` service is required to use network functionalities. let soc = Soc::new().unwrap(); @@ -25,8 +22,12 @@ fn main() { let server = TcpListener::bind("0.0.0.0:80").unwrap(); server.set_nonblocking(true).unwrap(); - println!("Point your browser to http://{}/\n", soc.host_address()); - println!("\x1b[29;16HPress Start to exit"); + let _bottom_console = Console::new(gfx.bottom_screen.borrow_mut()); + + println!("Point your browser at:\nhttp://{}/\n", soc.host_address()); + println!("\x1b[29;12HPress Start to exit"); + + let _top_console = Console::new(gfx.top_screen.borrow_mut()); while apt.main_loop() { hid.scan_input(); @@ -34,6 +35,7 @@ fn main() { break; }; + // Receive any incoming connections. match server.accept() { Ok((mut stream, socket_addr)) => { println!("Got connection from {socket_addr}"); diff --git a/ctru-rs/examples/software-keyboard.rs b/ctru-rs/examples/software-keyboard.rs index 269ccf09..e7547816 100644 --- a/ctru-rs/examples/software-keyboard.rs +++ b/ctru-rs/examples/software-keyboard.rs @@ -13,8 +13,7 @@ fn main() { let gfx = Gfx::new().unwrap(); let _console = Console::new(gfx.top_screen.borrow_mut()); - println!("Press A to enter some text."); - println!("\x1b[29;16HPress Start to exit"); + println!("Press A to enter some text or press Start to exit."); while apt.main_loop() { hid.scan_input(); @@ -23,7 +22,7 @@ fn main() { break; } - // If the user request to write some input. + // Check if the user request to write some input. if hid.keys_down().contains(KeyPad::A) { // Prepares a software keyboard with two buttons: One to cancel input and one // to accept it. You can also use `SoftwareKeyboard::new()` to launch the keyboard in different diff --git a/ctru-rs/examples/time-rtc.rs b/ctru-rs/examples/time-rtc.rs index e8c3a950..ca4709a7 100644 --- a/ctru-rs/examples/time-rtc.rs +++ b/ctru-rs/examples/time-rtc.rs @@ -27,8 +27,17 @@ fn main() { // since the 3DS doesn't seem to support timezones. let cur_time = time::OffsetDateTime::now_utc(); - // Display the retrieved information. - println!("\x1b[1;1H{cur_time}"); + let hours = cur_time.hour(); + let minutes = cur_time.minute(); + let seconds = cur_time.second(); + + let weekday = cur_time.weekday().to_string(); + let month = cur_time.month().to_string(); + let day = cur_time.day(); + let year = cur_time.year(); + + println!("\x1b[1;1H{hours:0>2}:{minutes:0>2}:{seconds:0>2}"); + println!("{weekday} {month} {day} {year}"); gfx.wait_for_vblank(); } diff --git a/ctru-rs/examples/title-info.rs b/ctru-rs/examples/title-info.rs index 9cb4db82..d2898aca 100644 --- a/ctru-rs/examples/title-info.rs +++ b/ctru-rs/examples/title-info.rs @@ -88,7 +88,8 @@ fn main() { // Clear the bottom screen and write the properties of selected title to it. bottom_screen.select(); - println!("\x1b[2J"); + bottom_screen.clear(); + println!("Press Start to exit"); // Move cursor to top left. println!("\x1b[1;1"); @@ -97,7 +98,6 @@ fn main() { println!("Version: 0x{:x}", selected_title.version()); println!("Product code: \"{}\"", selected_title.product_code()); - println!("\x1b[29;16HPress Start to exit"); if use_nand { println!("Press SELECT to choose SD Card"); println!("Current medium: NAND"); diff --git a/ctru-rs/examples/touch-screen.rs b/ctru-rs/examples/touch-screen.rs index a7850555..135de2b0 100644 --- a/ctru-rs/examples/touch-screen.rs +++ b/ctru-rs/examples/touch-screen.rs @@ -32,6 +32,9 @@ fn main() { // We only want to print the position when it's different // from what it was on the previous frame. if touch != old_touch { + // Move the cursor back to the top of the screen and print the coordinates. + print!("\x1b[1;1HTouch Screen position: {:#?}", touch); + // Special case for when the user lifts the stylus/finger from the screen. // This is done to avoid some screen tearing. if touch == (0, 0) { @@ -40,9 +43,6 @@ fn main() { // Print again because we just cleared the screen. println!("\x1b[29;16HPress Start to exit"); } - - // Move the cursor back to the top of the screen and print the coordinates. - print!("\x1b[1;1HTouch Screen position: {:#?}", touch); } // Save our current touch position for the next frame. diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index 8eb3ebce..32fbe108 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -21,7 +21,9 @@ static mut EMPTY_CONSOLE: PrintConsole = unsafe { const_zero::const_zero!(PrintC /// /// # Notes /// -/// The console will take full possession of the screen handed to it as long as it stays alive. It also supports ANSI codes. +/// The [`Console`] will take full possession of the screen handed to it as long as it stays alive. It also supports ANSI codes. +/// The [`Console`]'s window will have a size of 40x30 on the bottom screen, 50x30 on the normal top screen and +/// 100x30 on the top screen when wide mode is enabled. /// /// # Alternatives /// From 99d1b9128cafac79d5fc2d1b68b53e3390e45814 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Fri, 28 Jul 2023 16:56:40 +0200 Subject: [PATCH 29/39] Fixed clippy warnings --- ctru-rs/src/services/fs.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index d5d79165..b7636eb9 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -413,7 +413,7 @@ impl File { /// let mut sdmc_archive = fs.sdmc().unwrap(); /// let mut f = File::create(&mut sdmc_archive, "/foo.txt").unwrap(); /// ``` - pub fn create>(arch: &mut Archive, path: P) -> IoResult { + pub fn create>(arch: &Archive, path: P) -> IoResult { OpenOptions::new() .write(true) .create(true) @@ -738,7 +738,7 @@ impl<'a> DirEntry<'a> { /// /// * User lacks permissions to create directory at `path` #[doc(alias = "FSUSER_CreateDirectory")] -pub fn create_dir>(arch: &mut Archive, path: P) -> IoResult<()> { +pub fn create_dir>(arch: &Archive, path: P) -> IoResult<()> { unsafe { let path = to_utf16(path.as_ref()); let fs_path = ctru_sys::fsMakePath(PathType::UTF16.into(), path.as_ptr() as _); @@ -765,7 +765,7 @@ pub fn create_dir>(arch: &mut Archive, path: P) -> IoResult<()> { /// * If any directory in the path specified by `path` does not already exist /// and it could not be created otherwise. #[doc(alias = "FSUSER_CreateDirectory")] -pub fn create_dir_all>(arch: &mut Archive, path: P) -> IoResult<()> { +pub fn create_dir_all>(arch: &Archive, path: P) -> IoResult<()> { let path = path.as_ref(); let mut dir = PathBuf::new(); let mut result = Ok(()); @@ -802,7 +802,7 @@ pub fn metadata>(arch: &Archive, path: P) -> IoResult { /// * The user lacks permissions to remove the directory at the provided path. /// * The directory isn't empty. #[doc(alias = "FSUSER_DeleteDirectory")] -pub fn remove_dir>(arch: &mut Archive, path: P) -> IoResult<()> { +pub fn remove_dir>(arch: &Archive, path: P) -> IoResult<()> { unsafe { let path = to_utf16(path.as_ref()); let fs_path = ctru_sys::fsMakePath(PathType::UTF16.into(), path.as_ptr() as _); @@ -821,7 +821,7 @@ pub fn remove_dir>(arch: &mut Archive, path: P) -> IoResult<()> { /// /// see `file::remove_file` and `fs::remove_dir` #[doc(alias = "FSUSER_DeleteDirectoryRecursively")] -pub fn remove_dir_all>(arch: &mut Archive, path: P) -> IoResult<()> { +pub fn remove_dir_all>(arch: &Archive, path: P) -> IoResult<()> { unsafe { let path = to_utf16(path.as_ref()); let fs_path = ctru_sys::fsMakePath(PathType::UTF16.into(), path.as_ptr() as _); @@ -875,7 +875,7 @@ pub fn read_dir>(arch: &Archive, path: P) -> IoResult { /// * path points to a directory. /// * The user lacks permissions to remove the file. #[doc(alias = "FSUSER_DeleteFile")] -pub fn remove_file>(arch: &mut Archive, path: P) -> IoResult<()> { +pub fn remove_file>(arch: &Archive, path: P) -> IoResult<()> { unsafe { let path = to_utf16(path.as_ref()); let fs_path = ctru_sys::fsMakePath(PathType::UTF16.into(), path.as_ptr() as _); @@ -899,7 +899,7 @@ pub fn remove_file>(arch: &mut Archive, path: P) -> IoResult<()> /// * from does not exist. /// * The user lacks permissions to view contents. #[doc(alias = "FSUSER_RenameFile", alias = "FSUSER_RenameDirectory")] -pub fn rename(arch: &mut Archive, from: P, to: Q) -> IoResult<()> +pub fn rename(arch: &Archive, from: P, to: Q) -> IoResult<()> where P: AsRef, Q: AsRef, From 1640e201e931021da56a6a5d21d722daf7c62b52 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Fri, 28 Jul 2023 18:02:17 +0200 Subject: [PATCH 30/39] Finishing touches after complete revision --- ctru-rs/src/console.rs | 2 +- ctru-rs/src/lib.rs | 6 +++--- ctru-rs/src/linear.rs | 4 ++-- ctru-rs/src/services/apt.rs | 2 +- ctru-rs/src/services/cam.rs | 11 +++++------ ctru-rs/src/services/cfgu.rs | 2 +- ctru-rs/src/services/fs.rs | 12 +++++------ ctru-rs/src/services/gfx.rs | 33 +++++++++++++++++++++---------- ctru-rs/src/services/hid.rs | 2 +- ctru-rs/src/services/ndsp/mod.rs | 22 ++++++++++----------- ctru-rs/src/services/ndsp/wave.rs | 16 +++++++-------- 11 files changed, 62 insertions(+), 50 deletions(-) diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index 32fbe108..ca3681d8 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -127,7 +127,7 @@ impl<'screen> Console<'screen> { /// /// Any previously selected console will be unhooked and will not show the `stdout` output. /// - /// # Example + /// # Example /// /// ```no_run /// # use std::error::Error; diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index 3686578b..ecc7dd94 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -3,7 +3,7 @@ //! # About //! //! This crate behaves as the main tool to access system-specific functionality on the Nintendo 3DS when developing homebrew software in Rust. -//! Thanks to it, developers can access the underlying system services and the console's hardware to develop userland applications +//! Thanks to it, developers can develop userland applications by accessing access the underlying system services and the console's hardware //! (such as [HID devices](crate::services::hid), [network capabilities](crate::services::soc), [graphics](crate::services::gfx), [built-in cameras](crate::services::cam), etc.). //! //! Among these features, [`ctru-rs`](crate) also automatically includes functionality to properly integrate the Rust `std` with the console's operating system, @@ -13,7 +13,7 @@ //! //! Thoroughly read the official [`ctru-rs` wiki](https://github.com/rust3ds/ctru-rs/wiki) which guides you through the setup needed to install the required toolchain and helpful tools. //! After following the guide and understanding the many quirks of the Nintendo 3DS homebrew development environment, you can create a new project by including this crate as a dependency -//! of your project in your `Cargo.toml` manifest and build your binaries either manually (for the `armv6k-nintendo-3ds` target) or via [`cargo-3ds`](https://github.com/rust3ds/cargo-3ds). +//! in your `Cargo.toml` manifest and build your binaries either manually (for the `armv6k-nintendo-3ds` target) or via [`cargo-3ds`](https://github.com/rust3ds/cargo-3ds). #![crate_type = "rlib"] #![crate_name = "ctru"] @@ -60,7 +60,7 @@ macro_rules! from_impl { /// /// # Notes /// -/// When ´test´ is enabled, this function will not do anything, as it should be overridden by the ´test´ environment. +/// When `test` is enabled, this function will not do anything, as its behaviour should be overridden by the `test` environment. pub fn use_panic_handler() { #[cfg(not(test))] panic_hook_setup(); diff --git a/ctru-rs/src/linear.rs b/ctru-rs/src/linear.rs index 8c0639aa..269e5dd6 100644 --- a/ctru-rs/src/linear.rs +++ b/ctru-rs/src/linear.rs @@ -1,11 +1,11 @@ //! LINEAR memory allocator. //! //! LINEAR memory is a sector of the 3DS' RAM that binds virtual addresses exactly to the physical address. -//! As such, it is used for fast and safe memory sharing between hardware processors (such as the GPU and the DSP). +//! As such, it is used for fast and safe memory sharing between different hardware components (such as the GPU and the DSP processor). //! //! # Additional Resources //! -//! -
+//! - //! - use std::alloc::{AllocError, Allocator, Layout}; diff --git a/ctru-rs/src/services/apt.rs b/ctru-rs/src/services/apt.rs index 1fba0e54..b30be858 100644 --- a/ctru-rs/src/services/apt.rs +++ b/ctru-rs/src/services/apt.rs @@ -67,7 +67,7 @@ impl Apt { unsafe { ctru_sys::aptMainLoop() } } - /// Sets (in percentage) the amount of time to lend to the application thread spawned on the syscore (core #1). + /// Set (in percentage) the amount of time to lend to the application thread spawned on the syscore (core #1). /// /// # Notes /// diff --git a/ctru-rs/src/services/cam.rs b/ctru-rs/src/services/cam.rs index dd4437b1..23316c17 100644 --- a/ctru-rs/src/services/cam.rs +++ b/ctru-rs/src/services/cam.rs @@ -302,8 +302,7 @@ impl Camera for OutwardLeftCam { pub struct BothOutwardCam; impl BothOutwardCam { - /// Sets whether to enable or disable synchronization - /// of brightness for both left and right cameras + /// Set whether to enable or disable brightness synchronization between the two cameras. #[doc(alias = "CAMU_SetBrightnessSynchronization")] pub fn set_brightness_synchronization( &mut self, @@ -560,7 +559,7 @@ pub trait Camera { } } - /// Sets whether auto white balance is enabled or disabled for the camera + /// Set whether auto white balance is enabled or disabled for the camera. #[doc(alias = "CAMU_SetAutoWhiteBalance")] fn set_auto_white_balance(&mut self, enabled: bool) -> crate::Result<()> { unsafe { @@ -659,7 +658,7 @@ pub trait Camera { } } - /// Sets the photo mode of the camera. + /// Set the photo mode of the camera. #[doc(alias = "CAMU_SetPhotoMode")] fn set_photo_mode(&mut self, photo_mode: PhotoMode) -> crate::Result<()> { unsafe { @@ -671,7 +670,7 @@ pub trait Camera { } } - /// Sets the effect of the camera. + /// Set the effect of the camera. /// /// # Notes /// @@ -975,7 +974,7 @@ impl Cam { } } - /// Plays the specified sound based on the [`ShutterSound`] argument + /// Play the specified sound based on the [`ShutterSound`] argument /// /// # Notes /// diff --git a/ctru-rs/src/services/cfgu.rs b/ctru-rs/src/services/cfgu.rs index 252b11fb..d63f2274 100644 --- a/ctru-rs/src/services/cfgu.rs +++ b/ctru-rs/src/services/cfgu.rs @@ -1,6 +1,6 @@ //! System Configuration service. //! -//! This module contains basic methods to retrieve and change configuration from the console. +//! This module contains basic methods to retrieve the console's system configuration. use crate::error::ResultCode; diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index b7636eb9..f168e321 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -542,7 +542,7 @@ impl OpenOptions { Self::default() } - /// Sets the option for read access. + /// Set the option for read access. /// /// This option, when true, will indicate that the file should be /// `read`-able if opened. @@ -551,7 +551,7 @@ impl OpenOptions { self } - /// Sets the option for write access. + /// Set the option for write access. /// /// This option, when true, will indicate that the file should be /// `write`-able if opened. @@ -563,7 +563,7 @@ impl OpenOptions { self } - /// Sets the option for the append mode. + /// Set the option for the append mode. /// /// This option, when true, means that writes will append to a file instead /// of overwriting previous contents. Note that setting .write(true).append(true) @@ -575,7 +575,7 @@ impl OpenOptions { self } - /// Sets the option for truncating a previous file. + /// Set the option for truncating a previous file. /// /// If a file is successfully opened with this option set it will truncate /// the file to 0 length if it already exists. @@ -586,7 +586,7 @@ impl OpenOptions { self } - /// Sets the option for creating a new file. + /// Set the option for creating a new file. /// /// This option indicates whether a new file will be created /// if the file does not yet already @@ -598,7 +598,7 @@ impl OpenOptions { self } - /// Sets which archive the file is to be opened in. + /// Set which archive the file is to be opened in. /// /// Failing to pass in an archive will result in the file failing to open. pub fn archive(&mut self, archive: &Archive) -> &mut OpenOptions { diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index 0769b811..e1b27c79 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -55,15 +55,6 @@ pub trait Screen: private::Sealed { } } - /// Sets whether to use double buffering. Enabled by default. - /// - /// [`Swap::swap_buffers`] must be called after this function for the configuration - /// change to take effect. - #[doc(alias = "gfxSetDoubleBuffering")] - fn set_double_buffering(&mut self, enabled: bool) { - unsafe { ctru_sys::gfxSetDoubleBuffering(self.as_raw(), enabled) } - } - /// Gets the framebuffer format. #[doc(alias = "gfxGetScreenFormat")] fn framebuffer_format(&self) -> FramebufferFormat { @@ -106,11 +97,21 @@ pub trait Swap: private::Sealed { /// /// Even if double buffering is disabled, "swapping" the buffers has the side effect /// of committing any configuration changes to the buffers (e.g. [`TopScreen::set_wide_mode()`], - /// [`Screen::set_framebuffer_format()`], [`Screen::set_double_buffering()`]), so it should still be used. + /// [`Screen::set_framebuffer_format()`], [`Swap::set_double_buffering()`]), so it should still be used. /// /// This should be called once per frame at most. #[doc(alias = "gfxScreenSwapBuffers")] fn swap_buffers(&mut self); + + /// Set whether to use double buffering. + /// + /// # Notes + /// + /// Double buffering is enabled by default. + /// [`Swap::swap_buffers`] must be called after this function for the configuration + /// change to take effect. + #[doc(alias = "gfxSetDoubleBuffering")] + fn set_double_buffering(&mut self, enabled: bool); } impl Swap for TopScreen3D<'_> { @@ -119,6 +120,10 @@ impl Swap for TopScreen3D<'_> { ctru_sys::gfxScreenSwapBuffers(ctru_sys::GFX_TOP, true); } } + + fn set_double_buffering(&mut self, enabled: bool) { + unsafe { ctru_sys::gfxSetDoubleBuffering(ctru_sys::GFX_TOP, enabled) } + } } impl Swap for TopScreen { @@ -127,6 +132,10 @@ impl Swap for TopScreen { ctru_sys::gfxScreenSwapBuffers(ctru_sys::GFX_TOP, false); } } + + fn set_double_buffering(&mut self, enabled: bool) { + unsafe { ctru_sys::gfxSetDoubleBuffering(ctru_sys::GFX_TOP, enabled) } + } } impl Swap for BottomScreen { @@ -135,6 +144,10 @@ impl Swap for BottomScreen { ctru_sys::gfxScreenSwapBuffers(ctru_sys::GFX_BOTTOM, false); } } + + fn set_double_buffering(&mut self, enabled: bool) { + unsafe { ctru_sys::gfxSetDoubleBuffering(ctru_sys::GFX_BOTTOM, enabled) } + } } /// A screen with buffers that can be flushed. diff --git a/ctru-rs/src/services/hid.rs b/ctru-rs/src/services/hid.rs index fc73612b..c790131f 100644 --- a/ctru-rs/src/services/hid.rs +++ b/ctru-rs/src/services/hid.rs @@ -142,7 +142,7 @@ impl Hid { /// hid.scan_input(); /// /// if hid.keys_down().contains(KeyPad::A) { - /// println!("You just pressed the A button!") + /// println!("You have pressed the A button!") /// } /// # /// # Ok(()) diff --git a/ctru-rs/src/services/ndsp/mod.rs b/ctru-rs/src/services/ndsp/mod.rs index fc765846..eb9328db 100644 --- a/ctru-rs/src/services/ndsp/mod.rs +++ b/ctru-rs/src/services/ndsp/mod.rs @@ -540,7 +540,7 @@ impl Channel<'_> { unsafe { ctru_sys::ndspChnIirMonoSetEnable(self.id.into(), enable) }; } - /// Sets the monopole to be a high pass filter. + /// Set the monopole to be a high pass filter. /// /// # Notes /// @@ -550,7 +550,7 @@ impl Channel<'_> { unsafe { ctru_sys::ndspChnIirMonoSetParamsHighPassFilter(self.id.into(), cut_off_freq) }; } - /// Sets the monopole to be a low pass filter. + /// Set the monopole to be a low pass filter. /// /// # Notes /// @@ -566,7 +566,7 @@ impl Channel<'_> { unsafe { ctru_sys::ndspChnIirBiquadSetEnable(self.id.into(), enable) }; } - /// Sets the biquad to be a high pass filter. + /// Set the biquad to be a high pass filter. #[doc(alias = "ndspChnIirBiquadSetParamsHighPassFilter")] pub fn iir_biquad_set_params_high_pass_filter(&mut self, cut_off_freq: f32, quality: f32) { unsafe { @@ -574,7 +574,7 @@ impl Channel<'_> { }; } - /// Sets the biquad to be a low pass filter. + /// Set the biquad to be a low pass filter. #[doc(alias = "ndspChnIirBiquadSetParamsLowPassFilter")] pub fn iir_biquad_set_params_low_pass_filter(&mut self, cut_off_freq: f32, quality: f32) { unsafe { @@ -582,7 +582,7 @@ impl Channel<'_> { }; } - /// Sets the biquad to be a notch filter. + /// Set the biquad to be a notch filter. #[doc(alias = "ndspChnIirBiquadSetParamsNotchFilter")] pub fn iir_biquad_set_params_notch_filter(&mut self, notch_freq: f32, quality: f32) { unsafe { @@ -590,7 +590,7 @@ impl Channel<'_> { }; } - /// Sets the biquad to be a band pass filter. + /// Set the biquad to be a band pass filter. #[doc(alias = "ndspChnIirBiquadSetParamsBandPassFilter")] pub fn iir_biquad_set_params_band_pass_filter(&mut self, mid_freq: f32, quality: f32) { unsafe { @@ -598,7 +598,7 @@ impl Channel<'_> { }; } - /// Sets the biquad to be a peaking equalizer. + /// Set the biquad to be a peaking equalizer. #[doc(alias = "ndspChnIirBiquadSetParamsPeakingEqualizer")] pub fn iir_biquad_set_params_peaking_equalizer( &mut self, @@ -681,7 +681,7 @@ impl AudioMix { (self.raw[index], self.raw[index + 1]) } - /// Sets the values for the "front" volume mix (left and right channel). + /// Set the values for the "front" volume mix (left and right channel). /// /// # Notes /// @@ -692,7 +692,7 @@ impl AudioMix { self.raw[1] = right; } - /// Sets the values for the "back" volume mix (left and right channel). + /// Set the values for the "back" volume mix (left and right channel). /// /// # Notes /// @@ -703,7 +703,7 @@ impl AudioMix { self.raw[3] = right; } - /// Sets the values for the "front" volume mix (left and right channel) for the specified auxiliary output device (either 0 or 1). + /// Set the values for the "front" volume mix (left and right channel) for the specified auxiliary output device (either 0 or 1). /// /// # Notes /// @@ -720,7 +720,7 @@ impl AudioMix { self.raw[index + 1] = right; } - /// Sets the values for the "back" volume mix (left and right channel) for the specified auxiliary output device (either 0 or 1). + /// Set the values for the "back" volume mix (left and right channel) for the specified auxiliary output device (either 0 or 1). /// /// # Notes /// diff --git a/ctru-rs/src/services/ndsp/wave.rs b/ctru-rs/src/services/ndsp/wave.rs index 72cee96f..91712780 100644 --- a/ctru-rs/src/services/ndsp/wave.rs +++ b/ctru-rs/src/services/ndsp/wave.rs @@ -32,7 +32,7 @@ pub enum Status { } impl Wave { - /// Build a new playable wave object from a raw buffer on [LINEAR memory](`crate::linear`) and a some info. + /// Build a new playable wave object from a raw buffer on [LINEAR memory](`crate::linear`) and some info. /// /// # Example /// @@ -86,12 +86,12 @@ impl Wave { } } - /// Return a slice to the audio data (on the LINEAR memory). + /// Returns a slice to the audio data (on the LINEAR memory). pub fn get_buffer(&self) -> &[u8] { &self.buffer } - /// Return a mutable slice to the audio data (on the LINEAR memory). + /// Returns a mutable slice to the audio data (on the LINEAR memory). /// /// # Errors /// @@ -106,7 +106,7 @@ impl Wave { } } - /// Return this wave's playback status. + /// Returns this wave's playback status. /// /// # Example /// @@ -130,7 +130,7 @@ impl Wave { self.raw_data.status.try_into().unwrap() } - /// Get the amounts of samples *read* by the NDSP process. + /// Returns the amount of samples *read* by the NDSP process. /// /// # Notes /// @@ -139,7 +139,7 @@ impl Wave { self.raw_data.nsamples as usize } - /// Get the format of the audio data. + /// Returns the format of the audio data. pub fn format(&self) -> AudioFormat { self.audio_format } @@ -152,11 +152,11 @@ impl Wave { } /// Set the amount of samples to be read. - /// This function doesn't resize the internal buffer. /// /// # Note + /// /// - /// Operations of this kind are particularly useful to allocate memory pools + /// This function doesn't resize the internal buffer. Operations of this kind are particularly useful to allocate memory pools /// for VBR (Variable BitRate) formats, like OGG Vorbis. /// /// # Errors From 8328721b5b0a66ccf792000fb30bffe37dc54761 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Fri, 28 Jul 2023 18:17:22 +0200 Subject: [PATCH 31/39] Fmt --- ctru-rs/examples/touch-screen.rs | 2 +- ctru-rs/src/services/gfx.rs | 4 ++-- ctru-rs/src/services/ndsp/wave.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ctru-rs/examples/touch-screen.rs b/ctru-rs/examples/touch-screen.rs index 135de2b0..fe2409d6 100644 --- a/ctru-rs/examples/touch-screen.rs +++ b/ctru-rs/examples/touch-screen.rs @@ -34,7 +34,7 @@ fn main() { if touch != old_touch { // Move the cursor back to the top of the screen and print the coordinates. print!("\x1b[1;1HTouch Screen position: {:#?}", touch); - + // Special case for when the user lifts the stylus/finger from the screen. // This is done to avoid some screen tearing. if touch == (0, 0) { diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index e1b27c79..2769c855 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -104,9 +104,9 @@ pub trait Swap: private::Sealed { fn swap_buffers(&mut self); /// Set whether to use double buffering. - /// + /// /// # Notes - /// + /// /// Double buffering is enabled by default. /// [`Swap::swap_buffers`] must be called after this function for the configuration /// change to take effect. diff --git a/ctru-rs/src/services/ndsp/wave.rs b/ctru-rs/src/services/ndsp/wave.rs index 91712780..1a383ca2 100644 --- a/ctru-rs/src/services/ndsp/wave.rs +++ b/ctru-rs/src/services/ndsp/wave.rs @@ -154,7 +154,7 @@ impl Wave { /// Set the amount of samples to be read. /// /// # Note - /// + /// /// /// This function doesn't resize the internal buffer. Operations of this kind are particularly useful to allocate memory pools /// for VBR (Variable BitRate) formats, like OGG Vorbis. From 354b9e3cdd180654fa325dde5882952f0a3fed8a Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Fri, 28 Jul 2023 19:13:24 +0200 Subject: [PATCH 32/39] Change Actions minimum nightly --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de60e6bb..ee97cccc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: matrix: toolchain: # Run against a "known good" nightly - - nightly-2023-01-13 + - nightly-2023-05-31 # Check for breakage on latest nightly - nightly @@ -57,7 +57,7 @@ jobs: strategy: matrix: toolchain: - - nightly-2023-01-13 + - nightly-2023-05-31 - nightly continue-on-error: ${{ matrix.toolchain == 'nightly' }} runs-on: ubuntu-latest From 47e3a73e144e963ea078897cbb7e0eec35e571b3 Mon Sep 17 00:00:00 2001 From: Meziu <55318903+Meziu@users.noreply.github.com> Date: Sat, 29 Jul 2023 11:44:18 +0200 Subject: [PATCH 33/39] Fix typo in play_shutter_sound docs Co-authored-by: FenrirWolf --- ctru-rs/src/services/cam.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctru-rs/src/services/cam.rs b/ctru-rs/src/services/cam.rs index 23316c17..1a4d6ad7 100644 --- a/ctru-rs/src/services/cam.rs +++ b/ctru-rs/src/services/cam.rs @@ -978,7 +978,7 @@ impl Cam { /// /// # Notes /// - /// Playing the shutter sound does not require a liviving handle to the [`Ndsp`](crate::services::ndsp::Ndsp) service. + /// Playing the shutter sound does not require a living handle to the [`Ndsp`](crate::services::ndsp::Ndsp) service. /// Volume will always be maxed out to ensure everyone within photo range can hear the picture being taken (as by japanese law). /// /// # Example From 79e0d04da6a1ba0da5015c9a4153bc5e31db4157 Mon Sep 17 00:00:00 2001 From: Meziu <55318903+Meziu@users.noreply.github.com> Date: Fri, 4 Aug 2023 23:15:12 +0200 Subject: [PATCH 34/39] Update ctru-rs/examples/file-explorer.rs Co-authored-by: Ian Chamberlain --- ctru-rs/examples/file-explorer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctru-rs/examples/file-explorer.rs b/ctru-rs/examples/file-explorer.rs index 4a7fbdae..6fa1183a 100644 --- a/ctru-rs/examples/file-explorer.rs +++ b/ctru-rs/examples/file-explorer.rs @@ -143,7 +143,7 @@ impl<'a> FileExplorer<'a> { } } - /// Paginate output.' + // Paginate output. fn wait_for_page_down(&mut self) { println!("Press A to go to next page, or Start to exit"); From f260e943a3eadb5ab9284b0be6a6412f8c36e3f8 Mon Sep 17 00:00:00 2001 From: Meziu <55318903+Meziu@users.noreply.github.com> Date: Fri, 4 Aug 2023 23:15:33 +0200 Subject: [PATCH 35/39] Update ctru-rs/examples/gfx-3d-mode.rs Co-authored-by: Ian Chamberlain --- ctru-rs/examples/gfx-3d-mode.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctru-rs/examples/gfx-3d-mode.rs b/ctru-rs/examples/gfx-3d-mode.rs index 32d7af1b..6ad75e5f 100644 --- a/ctru-rs/examples/gfx-3d-mode.rs +++ b/ctru-rs/examples/gfx-3d-mode.rs @@ -1,7 +1,7 @@ //! 3D Graphics example. //! //! This example showcases 3D mode rendering (using the CPU). -//! In a normal application, all rendering should be hanlded via the GPU. +//! In a normal application, all rendering should be handled via the GPU. use ctru::prelude::*; use ctru::services::gfx::{Flush, Screen, Side, Swap, TopScreen3D}; From fde132a11117b18aec55988beb5dff6466918e1a Mon Sep 17 00:00:00 2001 From: Meziu <55318903+Meziu@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:28:38 +0200 Subject: [PATCH 36/39] Apply suggestions from code review Co-authored-by: Ian Chamberlain --- ctru-rs/src/console.rs | 10 +++++----- ctru-rs/src/mii.rs | 2 +- ctru-rs/src/services/cam.rs | 2 +- ctru-rs/src/services/hid.rs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index ca3681d8..ecbde9f6 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -21,15 +21,15 @@ static mut EMPTY_CONSOLE: PrintConsole = unsafe { const_zero::const_zero!(PrintC /// /// # Notes /// -/// The [`Console`] will take full possession of the screen handed to it as long as it stays alive. It also supports ANSI codes. +/// The [`Console`] will take full possession of the screen handed to it as long as it stays alive. It also supports some ANSI codes, such as text color and cursor positioning. /// The [`Console`]'s window will have a size of 40x30 on the bottom screen, 50x30 on the normal top screen and /// 100x30 on the top screen when wide mode is enabled. /// /// # Alternatives /// -/// If you'd like to see live `stdout` output while running the application but cannnot/do not want to show the text on the 3DS itself, +/// If you'd like to see live `stdout` output while running the application but cannot or do not want to show the text on the 3DS itself, /// you can try using [`Soc::redirect_to_3dslink`](crate::services::soc::Soc::redirect_to_3dslink) while activating the `--server` flag for `3dslink` (also supported by `cargo-3ds`). -/// More info in the `cargo-3ds` docs. +/// More info in the [`cargo-3ds` docs](https://github.com/rust3ds/cargo-3ds#running-executables). #[doc(alias = "PrintConsole")] pub struct Console<'screen> { context: Box, @@ -41,7 +41,7 @@ impl<'screen> Console<'screen> { /// /// # Notes /// - /// This operation overwrites whatever was on the screen before the inizialization (including other [`Console`]s) + /// This operation overwrites whatever was on the screen before the initialization (including other [`Console`]s) /// and changes the [`FramebufferFormat`](crate::services::gspgpu::FramebufferFormat) of the selected screen to better suit the [`Console`]. /// /// The new console is automatically selected for printing. @@ -144,7 +144,7 @@ impl<'screen> Console<'screen> { /// // Create a `Console` that takes control of the lower LCD screen. /// let bottom_console = Console::new(gfx.bottom_screen.borrow_mut()); /// - /// // Remember that `Console::new` automatically selects the new `Console` for ouput. + /// // Remember that `Console::new` automatically selects the new `Console` for output. /// println!("I'm on the bottom screen!"); /// /// top_console.select(); diff --git a/ctru-rs/src/mii.rs b/ctru-rs/src/mii.rs index beccd4e9..78fef805 100644 --- a/ctru-rs/src/mii.rs +++ b/ctru-rs/src/mii.rs @@ -245,7 +245,7 @@ pub struct MoleDetails { /// /// Some values are not ordered *like* the Mii Editor UI. The mapped values can be seen [here](https://www.3dbrew.org/wiki/Mii#Mapped_Editor_.3C-.3E_Hex_values). /// -/// This struct can be retrieved by [`MiiSelector::lauch()`](crate::applets::mii_selector::MiiSelector::launch). +/// This struct can be retrieved by [`MiiSelector::launch()`](crate::applets::mii_selector::MiiSelector::launch). #[derive(Clone, Debug)] pub struct Mii { /// Mii options. diff --git a/ctru-rs/src/services/cam.rs b/ctru-rs/src/services/cam.rs index 1a4d6ad7..1e643224 100644 --- a/ctru-rs/src/services/cam.rs +++ b/ctru-rs/src/services/cam.rs @@ -979,7 +979,7 @@ impl Cam { /// # Notes /// /// Playing the shutter sound does not require a living handle to the [`Ndsp`](crate::services::ndsp::Ndsp) service. - /// Volume will always be maxed out to ensure everyone within photo range can hear the picture being taken (as by japanese law). + /// Volume will always be maxed out to ensure everyone within photo range can hear the picture being taken (as by Japanese law). /// /// # Example /// diff --git a/ctru-rs/src/services/hid.rs b/ctru-rs/src/services/hid.rs index c790131f..d972e001 100644 --- a/ctru-rs/src/services/hid.rs +++ b/ctru-rs/src/services/hid.rs @@ -66,7 +66,7 @@ bitflags! { const DOWN = KeyPad::DPAD_DOWN.bits() | KeyPad::CPAD_DOWN.bits(); /// Direction Left (either D-Pad or C-Pad). const LEFT = KeyPad::DPAD_LEFT.bits() | KeyPad::CPAD_LEFT.bits(); - /// Direction Right (either D-Pad or C-Pad).. + /// Direction Right (either D-Pad or C-Pad). const RIGHT = KeyPad::DPAD_RIGHT.bits() | KeyPad::CPAD_RIGHT.bits(); } } From 414b760bd7181adb820acff108882746c56a2c52 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sat, 5 Aug 2023 18:52:06 +0200 Subject: [PATCH 37/39] Easy fixes to review suggestions --- ctru-rs/Cargo.toml | 3 ++- ctru-rs/examples/gfx-3d-mode.rs | 11 +++++++---- ctru-rs/src/applets/swkbd.rs | 2 +- ctru-rs/src/console.rs | 16 +++++++++------- ctru-rs/src/error.rs | 6 +++--- ctru-rs/src/services/hid.rs | 10 +++++----- ctru-rs/src/services/romfs.rs | 5 ----- ctru-sys/Cargo.toml | 3 ++- 8 files changed, 29 insertions(+), 27 deletions(-) diff --git a/ctru-rs/Cargo.toml b/ctru-rs/Cargo.toml index 027a3cb0..0523b27a 100644 --- a/ctru-rs/Cargo.toml +++ b/ctru-rs/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Rust3DS Org", "Ronald Kinard "] description = "A safe wrapper around libctru" repository = "https://github.com/rust3ds/ctru-rs" keywords = ["3ds", "libctru"] -categories = ["os", "api-bindings"] +categories = ["os", "api-bindings", "hardware-support"] exclude = ["examples"] license = "Zlib" edition = "2021" @@ -51,6 +51,7 @@ romfs_dir = "examples/romfs" [package.metadata.docs.rs] default-target = "armv6k-nintendo-3ds" +targets = [] cargo-args = ["-Z", "build-std"] [[example]] diff --git a/ctru-rs/examples/gfx-3d-mode.rs b/ctru-rs/examples/gfx-3d-mode.rs index 6ad75e5f..71760859 100644 --- a/ctru-rs/examples/gfx-3d-mode.rs +++ b/ctru-rs/examples/gfx-3d-mode.rs @@ -2,14 +2,17 @@ //! //! This example showcases 3D mode rendering (using the CPU). //! In a normal application, all rendering should be handled via the GPU. +//! +//! See `gfx-bitmap.rs` for details on how the image is generated. +//! +//! # Warning +//! +//! This example uses 3D mode in a rather unnatural way, and should +//! probably not be viewed for too long or at all if you are photosensitive. use ctru::prelude::*; use ctru::services::gfx::{Flush, Screen, Side, Swap, TopScreen3D}; -// See `graphics-bitmap.rs` for details on how the image is generated. -// -// WARNING: this example uses 3D mode in a rather unnatural way, and should -// probably not be viewed for too long or at all if you are photosensitive. const IMAGE: &[u8] = include_bytes!("assets/ferris.rgb"); static ZERO: &[u8] = &[0; IMAGE.len()]; diff --git a/ctru-rs/src/applets/swkbd.rs b/ctru-rs/src/applets/swkbd.rs index f20819b9..36413c6b 100644 --- a/ctru-rs/src/applets/swkbd.rs +++ b/ctru-rs/src/applets/swkbd.rs @@ -391,7 +391,7 @@ impl SoftwareKeyboard { } /// Configure the maximum number of UTF-16 code units that can be entered into the software - /// keyboard. By default the limit is `0xFDE8` code units. + /// keyboard. By default the limit is `65000` code units. /// /// # Notes /// diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index ecbde9f6..6768d47f 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -16,18 +16,20 @@ static mut EMPTY_CONSOLE: PrintConsole = unsafe { const_zero::const_zero!(PrintC /// Virtual text console. /// -/// [`Console`] lets the application redirect `stdout` to a simple text displayer on the 3DS screen. -/// This means that any text written to `stdout` (e.g. using `println!` or `dbg!`) will become visible in the area taken by the console. +/// [`Console`] lets the application redirect `stdout` and `stderr` to a simple text displayer on the 3DS screen. +/// This means that any text written to `stdout` and `stderr` (e.g. using `println!`, `eprintln!` or `dbg!`) will become visible in the area taken by the console. /// /// # Notes /// /// The [`Console`] will take full possession of the screen handed to it as long as it stays alive. It also supports some ANSI codes, such as text color and cursor positioning. -/// The [`Console`]'s window will have a size of 40x30 on the bottom screen, 50x30 on the normal top screen and -/// 100x30 on the top screen when wide mode is enabled. +/// The [`Console`]'s window size will be: +/// - 40x30 on the [`BottomScreen`](crate::services::gfx::BottomScreen). +/// - 50x30 on the normal [`TopScreen`](crate::services::gfx::TopScreen). +/// - 100x30 on the [`TopScreen`](crate::services::gfx::TopScreen) when wide mode is enabled. /// /// # Alternatives /// -/// If you'd like to see live `stdout` output while running the application but cannot or do not want to show the text on the 3DS itself, +/// If you'd like to see live standard output while running the application but cannot or do not want to show the text on the 3DS itself, /// you can try using [`Soc::redirect_to_3dslink`](crate::services::soc::Soc::redirect_to_3dslink) while activating the `--server` flag for `3dslink` (also supported by `cargo-3ds`). /// More info in the [`cargo-3ds` docs](https://github.com/rust3ds/cargo-3ds#running-executables). #[doc(alias = "PrintConsole")] @@ -121,11 +123,11 @@ impl<'screen> Console<'screen> { } } - /// Select this console as the current target for `stdout`. + /// Select this console as the current target for standard output. /// /// # Notes /// - /// Any previously selected console will be unhooked and will not show the `stdout` output. + /// Any previously selected console will be unhooked and will not show the `stdout` and `stderr` output. /// /// # Example /// diff --git a/ctru-rs/src/error.rs b/ctru-rs/src/error.rs index becfaefe..41b09f87 100644 --- a/ctru-rs/src/error.rs +++ b/ctru-rs/src/error.rs @@ -12,10 +12,10 @@ use ctru_sys::result::{R_DESCRIPTION, R_LEVEL, R_MODULE, R_SUMMARY}; /// Custom type alias for generic [`ctru-rs`](crate) operations. /// -/// This type is compatible with `ctru-sys::Result` codes. +/// This type is compatible with [`ctru_sys::Result`] codes. pub type Result = ::std::result::Result; -/// Validity checker of raw `ctru_sys::Result` codes. +/// Validity checker of raw [`ctru_sys::Result`] codes. /// /// This struct supports the "try" syntax (`?`) to convert to an [`Error::Os`]. /// @@ -80,7 +80,7 @@ impl FromResidual for Result { pub enum Error { /// Raw [`ctru_sys::Result`] codes. Os(ctru_sys::Result), - /// Generic `libc` error codes. + /// Generic [`libc`] errors. Libc(String), /// Requested service is already active and cannot be activated again. ServiceAlreadyActive, diff --git a/ctru-rs/src/services/hid.rs b/ctru-rs/src/services/hid.rs index d972e001..a136a94e 100644 --- a/ctru-rs/src/services/hid.rs +++ b/ctru-rs/src/services/hid.rs @@ -58,15 +58,15 @@ bitflags! { /// CirclePad Down. const CPAD_DOWN = ctru_sys::KEY_CPAD_DOWN; - // Convenience catch-all for the D-Pad and the C-Pad + // Convenience catch-all for the D-Pad and the CirclePad - /// Direction Up (either D-Pad or C-Pad). + /// Direction Up (either D-Pad or CirclePad). const UP = KeyPad::DPAD_UP.bits() | KeyPad::CPAD_UP.bits(); - /// Direction Down (either D-Pad or C-Pad). + /// Direction Down (either D-Pad or CirclePad). const DOWN = KeyPad::DPAD_DOWN.bits() | KeyPad::CPAD_DOWN.bits(); - /// Direction Left (either D-Pad or C-Pad). + /// Direction Left (either D-Pad or CirclePad). const LEFT = KeyPad::DPAD_LEFT.bits() | KeyPad::CPAD_LEFT.bits(); - /// Direction Right (either D-Pad or C-Pad). + /// Direction Right (either D-Pad or CirclePad). const RIGHT = KeyPad::DPAD_RIGHT.bits() | KeyPad::CPAD_RIGHT.bits(); } } diff --git a/ctru-rs/src/services/romfs.rs b/ctru-rs/src/services/romfs.rs index ad5429ff..7b686fa5 100644 --- a/ctru-rs/src/services/romfs.rs +++ b/ctru-rs/src/services/romfs.rs @@ -71,11 +71,6 @@ impl RomFS { } } -impl Drop for RomFS { - #[doc(alias = "romfsUnmount")] - fn drop(&mut self) {} -} - #[cfg(test)] mod tests { use super::*; diff --git a/ctru-sys/Cargo.toml b/ctru-sys/Cargo.toml index c6bb12f7..0041d0cf 100644 --- a/ctru-sys/Cargo.toml +++ b/ctru-sys/Cargo.toml @@ -5,7 +5,7 @@ authors = [ "Rust3DS Org", "Ronald Kinard " ] description = "Raw bindings to libctru" repository = "https://github.com/rust3ds/ctru-rs" keywords = ["3ds", "libctru"] -categories = ["os", "external-ffi-bindings", "no-std"] +categories = ["os", "external-ffi-bindings", "no-std", "hardware-support"] exclude = ["bindgen.sh", "src/.gitattributes"] license = "Zlib" links = "ctru" @@ -19,4 +19,5 @@ which = "4.4.0" [package.metadata.docs.rs] default-target = "armv6k-nintendo-3ds" +targets = [] cargo-args = ["-Z", "build-std"] From 00f264be8c2bfff677382b316c7a88cb8b0a21f4 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sat, 5 Aug 2023 20:04:49 +0200 Subject: [PATCH 38/39] Module doc aliases --- ctru-rs/src/applets/swkbd.rs | 1 + ctru-rs/src/services/am.rs | 2 ++ ctru-rs/src/services/cam.rs | 1 + ctru-rs/src/services/cfgu.rs | 1 + ctru-rs/src/services/fs.rs | 1 + ctru-rs/src/services/gfx.rs | 1 + ctru-rs/src/services/hid.rs | 3 +++ ctru-rs/src/services/ndsp/mod.rs | 1 + ctru-rs/src/services/romfs.rs | 2 ++ ctru-rs/src/services/soc.rs | 2 ++ 10 files changed, 15 insertions(+) diff --git a/ctru-rs/src/applets/swkbd.rs b/ctru-rs/src/applets/swkbd.rs index 36413c6b..9eda97e9 100644 --- a/ctru-rs/src/applets/swkbd.rs +++ b/ctru-rs/src/applets/swkbd.rs @@ -3,6 +3,7 @@ //! This applet opens a virtual keyboard on the console's bottom screen which lets the user write UTF-16 valid text. // TODO: Implement remaining functionality (password mode, filter callbacks, etc.). Also improve "max text length" API. Improve `number of buttons` API when creating a new SoftwareKeyboard. // TODO: Split the Parental PIN lock operations into a different type. +#[doc(alias = "keyboard")] use bitflags::bitflags; use ctru_sys::{ diff --git a/ctru-rs/src/services/am.rs b/ctru-rs/src/services/am.rs index ee5a4800..c1205415 100644 --- a/ctru-rs/src/services/am.rs +++ b/ctru-rs/src/services/am.rs @@ -5,6 +5,8 @@ //! - Install compatible applications to the console. //! //! TODO: [`ctru-rs`](crate) doesn't support installing or uninstalling titles yet. +#[doc(alias = "app")] +#[doc(alias = "manager")] use crate::error::ResultCode; use crate::services::fs::FsMediaType; diff --git a/ctru-rs/src/services/cam.rs b/ctru-rs/src/services/cam.rs index 1e643224..57966f8f 100644 --- a/ctru-rs/src/services/cam.rs +++ b/ctru-rs/src/services/cam.rs @@ -2,6 +2,7 @@ //! //! The CAM service provides access to the built-in cameras. [`Camera`]s can return images //! in the form of byte vectors which can be displayed to the screen or used in other ways. +#[doc(alias = "camera")] use crate::error::{Error, ResultCode}; use crate::services::gspgpu::FramebufferFormat; diff --git a/ctru-rs/src/services/cfgu.rs b/ctru-rs/src/services/cfgu.rs index d63f2274..9f90935d 100644 --- a/ctru-rs/src/services/cfgu.rs +++ b/ctru-rs/src/services/cfgu.rs @@ -1,6 +1,7 @@ //! System Configuration service. //! //! This module contains basic methods to retrieve the console's system configuration. +#[doc(alias = "configuration")] use crate::error::ResultCode; diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index f168e321..d79d73f1 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -3,6 +3,7 @@ //! This module contains basic methods to manipulate the contents of the 3DS's filesystem. //! Only the SD card is currently supported. You should prefer using `std::fs`. // TODO: Refactor service to accomodate for various changes (such as SMDH support). Properly document the public API. +#[doc(alias = "filesystem")] use bitflags::bitflags; use std::ffi::OsString; diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index 2769c855..73bb60a3 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -2,6 +2,7 @@ //! //! The GFX service controls (in a somewhat high-level way) the console's LCD screens. //! The screens are subordinate to the GFX service handle and can be used by only one borrower at a time. +#[doc(alias = "graphics")] use std::cell::{Ref, RefCell, RefMut}; use std::marker::PhantomData; diff --git a/ctru-rs/src/services/hid.rs b/ctru-rs/src/services/hid.rs index a136a94e..74c69c61 100644 --- a/ctru-rs/src/services/hid.rs +++ b/ctru-rs/src/services/hid.rs @@ -3,6 +3,9 @@ //! The HID service provides read access to user input such as [button presses](Hid::keys_down), [touch screen presses](Hid::touch_position), //! and [circle pad information](Hid::circlepad_position). It also provides information from the sound volume slider, the accelerometer, and the gyroscope. // TODO: Implement volume slider, accelerometer and gyroscope + any other missing functionality. +#[doc(alias = "input")] +#[doc(alias = "controller")] +#[doc(alias = "gamepad")] use crate::error::ResultCode; use bitflags::bitflags; diff --git a/ctru-rs/src/services/ndsp/mod.rs b/ctru-rs/src/services/ndsp/mod.rs index eb9328db..b109c98b 100644 --- a/ctru-rs/src/services/ndsp/mod.rs +++ b/ctru-rs/src/services/ndsp/mod.rs @@ -3,6 +3,7 @@ //! The NDSP service is used to handle communications to the DSP processor present on the console's motherboard. //! Thanks to the DSP processor the program can play sound effects and music on the console's built-in speakers or to any audio device //! connected via the audio jack. +#[doc(alias = "audio")] pub mod wave; use wave::{Status, Wave}; diff --git a/ctru-rs/src/services/romfs.rs b/ctru-rs/src/services/romfs.rs index 7b686fa5..7b0f34f9 100644 --- a/ctru-rs/src/services/romfs.rs +++ b/ctru-rs/src/services/romfs.rs @@ -18,6 +18,8 @@ //! ``` //! //! Alternatively, you can include the RomFS archive manually when building with `3dsxtool`. +#[doc(alias = "embed")] +#[doc(alias = "filesystem")] use crate::error::ResultCode; use std::ffi::CStr; diff --git a/ctru-rs/src/services/soc.rs b/ctru-rs/src/services/soc.rs index 00a7a5c6..b17cd86f 100644 --- a/ctru-rs/src/services/soc.rs +++ b/ctru-rs/src/services/soc.rs @@ -2,6 +2,8 @@ //! //! By using this service the program enables the use of network sockets and utilities such as those found in `std::net`, which are completely inaccessible by default. //! As such, remember to hold a handle to this service handle while using any network functionality, or else the `std::net` methods will return generic OS errors. +#[doc(alias = "socket")] +#[doc(alias = "network")] use libc::memalign; use std::net::Ipv4Addr; From 869cd50d06e18864c9cdb43f838de494dd1d55d9 Mon Sep 17 00:00:00 2001 From: Andrea Ciliberti Date: Sat, 5 Aug 2023 20:19:10 +0200 Subject: [PATCH 39/39] Fixed romfs suggestions --- ctru-rs/src/applets/swkbd.rs | 2 +- ctru-rs/src/services/am.rs | 4 ++-- ctru-rs/src/services/cam.rs | 2 +- ctru-rs/src/services/cfgu.rs | 2 +- ctru-rs/src/services/fs.rs | 2 +- ctru-rs/src/services/gfx.rs | 2 +- ctru-rs/src/services/hid.rs | 6 +++--- ctru-rs/src/services/ndsp/mod.rs | 2 +- ctru-rs/src/services/romfs.rs | 10 ++++++++-- ctru-rs/src/services/soc.rs | 4 ++-- 10 files changed, 21 insertions(+), 15 deletions(-) diff --git a/ctru-rs/src/applets/swkbd.rs b/ctru-rs/src/applets/swkbd.rs index 9eda97e9..8861aced 100644 --- a/ctru-rs/src/applets/swkbd.rs +++ b/ctru-rs/src/applets/swkbd.rs @@ -3,7 +3,7 @@ //! This applet opens a virtual keyboard on the console's bottom screen which lets the user write UTF-16 valid text. // TODO: Implement remaining functionality (password mode, filter callbacks, etc.). Also improve "max text length" API. Improve `number of buttons` API when creating a new SoftwareKeyboard. // TODO: Split the Parental PIN lock operations into a different type. -#[doc(alias = "keyboard")] +#![doc(alias = "keyboard")] use bitflags::bitflags; use ctru_sys::{ diff --git a/ctru-rs/src/services/am.rs b/ctru-rs/src/services/am.rs index c1205415..68b3af3e 100644 --- a/ctru-rs/src/services/am.rs +++ b/ctru-rs/src/services/am.rs @@ -5,8 +5,8 @@ //! - Install compatible applications to the console. //! //! TODO: [`ctru-rs`](crate) doesn't support installing or uninstalling titles yet. -#[doc(alias = "app")] -#[doc(alias = "manager")] +#![doc(alias = "app")] +#![doc(alias = "manager")] use crate::error::ResultCode; use crate::services::fs::FsMediaType; diff --git a/ctru-rs/src/services/cam.rs b/ctru-rs/src/services/cam.rs index 57966f8f..8d4af7bc 100644 --- a/ctru-rs/src/services/cam.rs +++ b/ctru-rs/src/services/cam.rs @@ -2,7 +2,7 @@ //! //! The CAM service provides access to the built-in cameras. [`Camera`]s can return images //! in the form of byte vectors which can be displayed to the screen or used in other ways. -#[doc(alias = "camera")] +#![doc(alias = "camera")] use crate::error::{Error, ResultCode}; use crate::services::gspgpu::FramebufferFormat; diff --git a/ctru-rs/src/services/cfgu.rs b/ctru-rs/src/services/cfgu.rs index 9f90935d..b1cbe76f 100644 --- a/ctru-rs/src/services/cfgu.rs +++ b/ctru-rs/src/services/cfgu.rs @@ -1,7 +1,7 @@ //! System Configuration service. //! //! This module contains basic methods to retrieve the console's system configuration. -#[doc(alias = "configuration")] +#![doc(alias = "configuration")] use crate::error::ResultCode; diff --git a/ctru-rs/src/services/fs.rs b/ctru-rs/src/services/fs.rs index d79d73f1..821b8b95 100644 --- a/ctru-rs/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -3,7 +3,7 @@ //! This module contains basic methods to manipulate the contents of the 3DS's filesystem. //! Only the SD card is currently supported. You should prefer using `std::fs`. // TODO: Refactor service to accomodate for various changes (such as SMDH support). Properly document the public API. -#[doc(alias = "filesystem")] +#![doc(alias = "filesystem")] use bitflags::bitflags; use std::ffi::OsString; diff --git a/ctru-rs/src/services/gfx.rs b/ctru-rs/src/services/gfx.rs index 73bb60a3..68ac9578 100644 --- a/ctru-rs/src/services/gfx.rs +++ b/ctru-rs/src/services/gfx.rs @@ -2,7 +2,7 @@ //! //! The GFX service controls (in a somewhat high-level way) the console's LCD screens. //! The screens are subordinate to the GFX service handle and can be used by only one borrower at a time. -#[doc(alias = "graphics")] +#![doc(alias = "graphics")] use std::cell::{Ref, RefCell, RefMut}; use std::marker::PhantomData; diff --git a/ctru-rs/src/services/hid.rs b/ctru-rs/src/services/hid.rs index 74c69c61..56a60352 100644 --- a/ctru-rs/src/services/hid.rs +++ b/ctru-rs/src/services/hid.rs @@ -3,9 +3,9 @@ //! The HID service provides read access to user input such as [button presses](Hid::keys_down), [touch screen presses](Hid::touch_position), //! and [circle pad information](Hid::circlepad_position). It also provides information from the sound volume slider, the accelerometer, and the gyroscope. // TODO: Implement volume slider, accelerometer and gyroscope + any other missing functionality. -#[doc(alias = "input")] -#[doc(alias = "controller")] -#[doc(alias = "gamepad")] +#![doc(alias = "input")] +#![doc(alias = "controller")] +#![doc(alias = "gamepad")] use crate::error::ResultCode; use bitflags::bitflags; diff --git a/ctru-rs/src/services/ndsp/mod.rs b/ctru-rs/src/services/ndsp/mod.rs index b109c98b..8cda8025 100644 --- a/ctru-rs/src/services/ndsp/mod.rs +++ b/ctru-rs/src/services/ndsp/mod.rs @@ -3,7 +3,7 @@ //! The NDSP service is used to handle communications to the DSP processor present on the console's motherboard. //! Thanks to the DSP processor the program can play sound effects and music on the console's built-in speakers or to any audio device //! connected via the audio jack. -#[doc(alias = "audio")] +#![doc(alias = "audio")] pub mod wave; use wave::{Status, Wave}; diff --git a/ctru-rs/src/services/romfs.rs b/ctru-rs/src/services/romfs.rs index 7b0f34f9..e6f1c3bb 100644 --- a/ctru-rs/src/services/romfs.rs +++ b/ctru-rs/src/services/romfs.rs @@ -18,8 +18,14 @@ //! ``` //! //! Alternatively, you can include the RomFS archive manually when building with `3dsxtool`. -#[doc(alias = "embed")] -#[doc(alias = "filesystem")] +//! +//! # Notes +//! +//! `std::path` has problems when parsing file paths that include the `romfs:` prefix. +//! As such, it's suggested to use the paths directly or to do simple append operations to avoid unexpected behaviour. +//! Related [issue](https://github.com/rust-lang/rust/issues/52331). +#![doc(alias = "embed")] +#![doc(alias = "filesystem")] use crate::error::ResultCode; use std::ffi::CStr; diff --git a/ctru-rs/src/services/soc.rs b/ctru-rs/src/services/soc.rs index b17cd86f..d4189193 100644 --- a/ctru-rs/src/services/soc.rs +++ b/ctru-rs/src/services/soc.rs @@ -2,8 +2,8 @@ //! //! By using this service the program enables the use of network sockets and utilities such as those found in `std::net`, which are completely inaccessible by default. //! As such, remember to hold a handle to this service handle while using any network functionality, or else the `std::net` methods will return generic OS errors. -#[doc(alias = "socket")] -#[doc(alias = "network")] +#![doc(alias = "socket")] +#![doc(alias = "network")] use libc::memalign; use std::net::Ipv4Addr;