Browse Source

Small changes and finalized AM service

pull/134/head
Andrea Ciliberti 1 year ago
parent
commit
127eafdc4b
  1. 15
      ctru-rs/examples/title-info.rs
  2. 5
      ctru-rs/src/lib.rs
  3. 132
      ctru-rs/src/services/am.rs
  4. 2
      ctru-rs/src/services/mod.rs

15
ctru-rs/examples/title-info.rs

@ -80,18 +80,9 @@ fn main() { @@ -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 {

5
ctru-rs/src/lib.rs

@ -4,14 +4,14 @@ @@ -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 @@ @@ -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(

132
ctru-rs/src/services/am.rs

@ -4,20 +4,19 @@ @@ -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<ctru_sys::AM_TitleEntry>,
size: u64,
version: u16,
_am: PhantomData<&'a Am>,
}
@ -29,54 +28,26 @@ impl<'a> Title<'a> { @@ -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<String> {
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<ctru_sys::AM_TitleEntry> {
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<u64> {
// Get the internal entry, or fill it if empty.
let entry = self
.entry
.get_or_try_init(|| -> crate::Result<ctru_sys::AM_TitleEntry> { 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<u16> {
// Get the internal entry, or fill it if empty.
let entry = self
.entry
.get_or_try_init(|| -> crate::Result<ctru_sys::AM_TitleEntry> { self.title_info() })?;
Ok(entry.version)
pub fn version(&self) -> u16 {
self.version
}
}
@ -84,7 +55,20 @@ impl<'a> Title<'a> { @@ -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<dyn Error>> {
/// #
/// use ctru::services::am::Am;
///
/// let app_manager = Am::new()?;
/// #
/// # Ok(())
/// # }
/// ```
#[doc(alias = "amInit")]
pub fn new() -> crate::Result<Am> {
unsafe {
@ -94,6 +78,24 @@ impl Am { @@ -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<dyn Error>> {
/// #
/// 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<u32> {
unsafe {
@ -104,11 +106,30 @@ impl Am { @@ -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<dyn Error>> {
/// #
/// 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<Vec<Title>> {
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 { @@ -117,13 +138,30 @@ impl Am {
buf.as_mut_ptr(),
))?;
}
Ok(buf
let mut info: Vec<ctru_sys::AM_TitleEntry> = 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,
.map(|title| {
Title {
id: title.titleID,
mediatype,
entry: OnceCell::new(),
size: title.size,
version: title.version,
_am: PhantomData,
}
})
.collect())
}

2
ctru-rs/src/services/mod.rs

@ -3,7 +3,7 @@ @@ -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),

Loading…
Cancel
Save