Browse Source

Am, Apt and refactoring to streamline the API and docs

pull/134/head
Andrea Ciliberti 1 year ago
parent
commit
39829e1820
  1. 13
      ctru-rs/examples/title-info.rs
  2. 5
      ctru-rs/src/lib.rs
  3. 64
      ctru-rs/src/services/am.rs
  4. 24
      ctru-rs/src/services/apt.rs
  5. 12
      ctru-rs/src/services/mod.rs

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

@ -80,12 +80,13 @@ fn main() { @@ -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}\""),

5
ctru-rs/src/lib.rs

@ -24,6 +24,7 @@ @@ -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; @@ -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

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

@ -1,35 +1,34 @@ @@ -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<ctru_sys::AM_TitleEntry>,
_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<String> {
let mut buf: [u8; 16] = [0; 16];
@ -43,7 +42,9 @@ impl<'a> Title<'a> { @@ -43,7 +42,9 @@ impl<'a> Title<'a> {
Ok(String::from_utf8_lossy(&buf).to_string())
}
pub fn title_info(&self) -> crate::Result<TitleInfo> {
/// 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 {
@ -57,11 +58,34 @@ impl<'a> Title<'a> { @@ -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<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)
}
/// 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)
}
}
/// Handle to the Application Manager service.
pub struct Am(());
impl Am {
/// Initialize a new handle.
#[doc(alias = "amInit")]
pub fn new() -> crate::Result<Am> {
unsafe {
ResultCode(ctru_sys::amInit())?;
@ -69,6 +93,8 @@ impl Am { @@ -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<u32> {
unsafe {
let mut count = 0;
@ -77,6 +103,8 @@ impl Am { @@ -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<Vec<Title>> {
let count = self.title_count(mediatype)?;
let mut buf = vec![0; count as usize];
@ -94,6 +122,7 @@ impl Am { @@ -94,6 +122,7 @@ impl Am {
.map(|id| Title {
id,
mediatype,
entry: OnceCell::new(),
_am: PhantomData,
})
.collect())
@ -101,6 +130,7 @@ impl Am { @@ -101,6 +130,7 @@ impl Am {
}
impl Drop for Am {
#[doc(alias = "amExit")]
fn drop(&mut self) {
unsafe { ctru_sys::amExit() };
}

24
ctru-rs/src/services/apt.rs

@ -1,8 +1,17 @@ @@ -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<Apt> {
unsafe {
ResultCode(ctru_sys::aptInit())?;
@ -10,10 +19,24 @@ impl Apt { @@ -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 { @@ -23,6 +46,7 @@ impl Apt {
}
impl Drop for Apt {
#[doc(alias = "aptExit")]
fn drop(&mut self) {
unsafe { ctru_sys::aptExit() };
}

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

@ -1,9 +1,15 @@ @@ -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;

Loading…
Cancel
Save