Browse Source

Merge pull request #107 from rust3ds/improve/api

Improve general API
pull/114/head
Meziu 2 years ago committed by GitHub
parent
commit
474cb2e0c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      ctru-rs/examples/audio-filters.rs
  2. 10
      ctru-rs/examples/buttons.rs
  3. 16
      ctru-rs/examples/camera-image.rs
  4. 25
      ctru-rs/examples/file-explorer.rs
  5. 10
      ctru-rs/examples/gfx-3d-mode.rs
  6. 6
      ctru-rs/examples/gfx-wide-mode.rs
  7. 6
      ctru-rs/examples/graphics-bitmap.rs
  8. 2
      ctru-rs/examples/hashmaps.rs
  9. 2
      ctru-rs/examples/hello-both-screens.rs
  10. 2
      ctru-rs/examples/hello-world.rs
  11. 2
      ctru-rs/examples/linear-memory.rs
  12. 2
      ctru-rs/examples/mii-selector.rs
  13. 2
      ctru-rs/examples/network-sockets.rs
  14. 2
      ctru-rs/examples/output-3dslink.rs
  15. 4
      ctru-rs/examples/romfs.rs
  16. 15
      ctru-rs/examples/software-keyboard.rs
  17. 8
      ctru-rs/examples/system-configuration.rs
  18. 2
      ctru-rs/examples/time-rtc.rs
  19. 20
      ctru-rs/examples/title-info.rs
  20. 4
      ctru-rs/src/applets/mii_selector.rs
  21. 109
      ctru-rs/src/applets/swkbd.rs
  22. 2
      ctru-rs/src/console.rs
  23. 36
      ctru-rs/src/lib.rs
  24. 3
      ctru-rs/src/prelude.rs
  25. 18
      ctru-rs/src/services/am.rs
  26. 387
      ctru-rs/src/services/cam.rs
  27. 22
      ctru-rs/src/services/cfgu.rs
  28. 109
      ctru-rs/src/services/fs.rs
  29. 22
      ctru-rs/src/services/gfx.rs
  30. 59
      ctru-rs/src/services/gspgpu.rs
  31. 56
      ctru-rs/src/services/hid.rs
  32. 20
      ctru-rs/src/services/mod.rs
  33. 10
      ctru-rs/src/services/ndsp/mod.rs
  34. 35
      ctru-rs/src/services/ps.rs
  35. 2
      ctru-rs/src/services/romfs.rs
  36. 8
      ctru-rs/src/services/soc.rs
  37. 4
      ctru-rs/src/services/sslc.rs
  38. 7
      ctru-rs/src/test_runner.rs

10
ctru-rs/examples/audio-filters.rs

@ -99,23 +99,23 @@ fn main() {
hid.scan_input(); hid.scan_input();
let keys_down = hid.keys_down(); let keys_down = hid.keys_down();
if keys_down.contains(KeyPad::KEY_START) { if keys_down.contains(KeyPad::START) {
break; break;
} // break in order to return to hbmenu } // break in order to return to hbmenu
if keys_down.intersects(KeyPad::KEY_DOWN) { if keys_down.intersects(KeyPad::DOWN) {
note = note.saturating_sub(1); note = note.saturating_sub(1);
} else if keys_down.intersects(KeyPad::KEY_UP) { } else if keys_down.intersects(KeyPad::UP) {
note = std::cmp::min(note + 1, NOTEFREQ.len() - 1); note = std::cmp::min(note + 1, NOTEFREQ.len() - 1);
} }
let mut update_params = false; let mut update_params = false;
if keys_down.intersects(KeyPad::KEY_LEFT) { if keys_down.intersects(KeyPad::LEFT) {
filter -= 1; filter -= 1;
filter = filter.rem_euclid(filter_names.len() as _); filter = filter.rem_euclid(filter_names.len() as _);
update_params = true; update_params = true;
} else if keys_down.intersects(KeyPad::KEY_RIGHT) { } else if keys_down.intersects(KeyPad::RIGHT) {
filter += 1; filter += 1;
filter = filter.rem_euclid(filter_names.len() as _); filter = filter.rem_euclid(filter_names.len() as _);

10
ctru-rs/examples/buttons.rs

@ -42,19 +42,19 @@ fn main() {
// 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 // the underlying bits
if keys.contains(KeyPad::KEY_A) { if keys.contains(KeyPad::A) {
println!("You held A!"); println!("You held A!");
} }
if keys.bits() & KeyPad::KEY_B.bits() != 0 { if keys.bits() & KeyPad::B.bits() != 0 {
println!("You held B!"); println!("You held B!");
} }
if keys.contains(KeyPad::KEY_X | KeyPad::KEY_Y) { if keys.contains(KeyPad::X | KeyPad::Y) {
println!("You held X and Y!"); println!("You held X and Y!");
} }
if keys.intersects(KeyPad::KEY_L | KeyPad::KEY_R | KeyPad::KEY_ZL | KeyPad::KEY_ZR) { if keys.intersects(KeyPad::L | KeyPad::R | KeyPad::ZL | KeyPad::ZR) {
println!("You held a shoulder button!"); println!("You held a shoulder button!");
} }
if keys.intersects(KeyPad::KEY_START) { if keys.intersects(KeyPad::START) {
println!("See ya!"); println!("See ya!");
break; break;
} }

16
ctru-rs/examples/camera-image.rs

@ -1,6 +1,6 @@
use ctru::gfx::Screen;
use ctru::prelude::*; use ctru::prelude::*;
use ctru::services::cam::{Cam, CamOutputFormat, CamShutterSoundType, CamSize, Camera}; use ctru::services::cam::{Cam, Camera, OutputFormat, ShutterSound, ViewSize};
use ctru::services::gfx::Screen;
use ctru::services::gspgpu::FramebufferFormat; use ctru::services::gspgpu::FramebufferFormat;
use std::time::Duration; use std::time::Duration;
@ -37,10 +37,10 @@ fn main() {
let camera = &mut cam.outer_right_cam; let camera = &mut cam.outer_right_cam;
camera camera
.set_view_size(CamSize::CTR_TOP_LCD) .set_view_size(ViewSize::TopLCD)
.expect("Failed to set camera size"); .expect("Failed to set camera size");
camera camera
.set_output_format(CamOutputFormat::RGB_565) .set_output_format(OutputFormat::Rgb565)
.expect("Failed to set camera output format"); .expect("Failed to set camera output format");
camera camera
.set_noise_filter(true) .set_noise_filter(true)
@ -65,11 +65,11 @@ fn main() {
hid.scan_input(); hid.scan_input();
keys_down = hid.keys_down(); keys_down = hid.keys_down();
if keys_down.contains(KeyPad::KEY_START) { if keys_down.contains(KeyPad::START) {
break; break;
} }
if keys_down.contains(KeyPad::KEY_R) { if keys_down.contains(KeyPad::R) {
println!("Capturing new image"); println!("Capturing new image");
let camera = &mut cam.outer_right_cam; let camera = &mut cam.outer_right_cam;
@ -83,12 +83,12 @@ fn main() {
) )
.expect("Failed to take picture"); .expect("Failed to take picture");
cam.play_shutter_sound(CamShutterSoundType::NORMAL) cam.play_shutter_sound(ShutterSound::Normal)
.expect("Failed to play shutter sound"); .expect("Failed to play shutter sound");
rotate_image_to_screen( rotate_image_to_screen(
&buf, &buf,
gfx.top_screen.borrow_mut().get_raw_framebuffer().ptr, gfx.top_screen.borrow_mut().raw_framebuffer().ptr,
WIDTH, WIDTH,
HEIGHT, HEIGHT,
); );

25
ctru-rs/examples/file-explorer.rs

@ -16,7 +16,7 @@ fn main() {
let gfx = Gfx::init().unwrap(); let gfx = Gfx::init().unwrap();
#[cfg(all(feature = "romfs", romfs_exists))] #[cfg(all(feature = "romfs", romfs_exists))]
let _romfs = ctru::romfs::RomFS::init().unwrap(); let _romfs = ctru::services::romfs::RomFS::init().unwrap();
FileExplorer::init(&apt, &hid, &gfx).run(); FileExplorer::init(&apt, &hid, &gfx).run();
} }
@ -56,15 +56,15 @@ impl<'a> FileExplorer<'a> {
self.hid.scan_input(); self.hid.scan_input();
let input = self.hid.keys_down(); let input = self.hid.keys_down();
if input.contains(KeyPad::KEY_START) { if input.contains(KeyPad::START) {
break; break;
} else if input.contains(KeyPad::KEY_B) && self.path.components().count() > 1 { } else if input.contains(KeyPad::B) && self.path.components().count() > 1 {
self.path.pop(); self.path.pop();
self.console.clear(); self.console.clear();
self.print_menu(); self.print_menu();
} else if input.contains(KeyPad::KEY_A) { } else if input.contains(KeyPad::A) {
self.get_input_and_run(Self::set_next_path); self.get_input_and_run(Self::set_next_path);
} else if input.contains(KeyPad::KEY_X) { } else if input.contains(KeyPad::X) {
self.get_input_and_run(Self::set_exact_path); self.get_input_and_run(Self::set_exact_path);
} }
@ -147,11 +147,11 @@ impl<'a> FileExplorer<'a> {
self.hid.scan_input(); self.hid.scan_input();
let input = self.hid.keys_down(); let input = self.hid.keys_down();
if input.contains(KeyPad::KEY_A) { if input.contains(KeyPad::A) {
break; break;
} }
if input.contains(KeyPad::KEY_START) { if input.contains(KeyPad::START) {
self.running = false; self.running = false;
return; return;
} }
@ -162,17 +162,16 @@ impl<'a> FileExplorer<'a> {
fn get_input_and_run(&mut self, action: impl FnOnce(&mut Self, String)) { fn get_input_and_run(&mut self, action: impl FnOnce(&mut Self, String)) {
let mut keyboard = Swkbd::default(); let mut keyboard = Swkbd::default();
let mut new_path_str = String::new();
match keyboard.get_utf8(&mut new_path_str) { match keyboard.get_string(2048) {
Ok(Button::Right) => { Ok((path, Button::Right)) => {
// Clicked "OK" // Clicked "OK"
action(self, new_path_str); action(self, path);
} }
Ok(Button::Left) => { Ok((_, Button::Left)) => {
// Clicked "Cancel" // Clicked "Cancel"
} }
Ok(Button::Middle) => { Ok((_, Button::Middle)) => {
// This button wasn't shown // This button wasn't shown
unreachable!() unreachable!()
} }

10
ctru-rs/examples/gfx-3d-mode.rs

@ -1,5 +1,5 @@
use ctru::gfx::{Screen, Side, TopScreen3D};
use ctru::prelude::*; use ctru::prelude::*;
use ctru::services::gfx::{Screen, Side, TopScreen3D};
/// See `graphics-bitmap.rs` for details on how the image is generated. /// See `graphics-bitmap.rs` for details on how the image is generated.
/// ///
@ -31,12 +31,12 @@ fn main() {
//Scan all the inputs. This should be done once for each frame //Scan all the inputs. This should be done once for each frame
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }
let left_buf = left.get_raw_framebuffer(); let left_buf = left.raw_framebuffer();
let right_buf = right.get_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 { unsafe {
@ -44,7 +44,7 @@ fn main() {
right_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::KEY_A) { if hid.keys_down().contains(KeyPad::A) {
// flip which buffer we're writing to // flip which buffer we're writing to
current_side = match current_side { current_side = match current_side {
Side::Left => Side::Right, Side::Left => Side::Right,

6
ctru-rs/examples/gfx-wide-mode.rs

@ -13,14 +13,14 @@ fn main() {
while apt.main_loop() { while apt.main_loop() {
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }
if hid.keys_down().contains(KeyPad::KEY_A) { if hid.keys_down().contains(KeyPad::A) {
drop(console); drop(console);
let wide_mode = gfx.top_screen.borrow().get_wide_mode(); let wide_mode = gfx.top_screen.borrow().is_wide();
gfx.top_screen.borrow_mut().set_wide_mode(!wide_mode); gfx.top_screen.borrow_mut().set_wide_mode(!wide_mode);
console = Console::init(gfx.top_screen.borrow_mut()); console = Console::init(gfx.top_screen.borrow_mut());

6
ctru-rs/examples/graphics-bitmap.rs

@ -1,5 +1,5 @@
use ctru::gfx::Screen as _;
use ctru::prelude::*; use ctru::prelude::*;
use ctru::services::gfx::Screen;
/// Ferris image taken from <https://rustacean.net> and scaled down to 320x240px. /// Ferris image taken from <https://rustacean.net> and scaled down to 320x240px.
/// To regenerate the data, you will need to install `imagemagick` and run this /// To regenerate the data, you will need to install `imagemagick` and run this
@ -31,7 +31,7 @@ fn main() {
bottom_screen.set_double_buffering(false); bottom_screen.set_double_buffering(false);
// We assume the image is the correct size already, so we drop width + height. // We assume the image is the correct size already, so we drop width + height.
let frame_buffer = bottom_screen.get_raw_framebuffer(); let frame_buffer = bottom_screen.raw_framebuffer();
// Copy the image into the frame buffer // Copy the image into the frame buffer
unsafe { unsafe {
@ -43,7 +43,7 @@ fn main() {
//Scan all the inputs. This should be done once for each frame //Scan all the inputs. This should be done once for each frame
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }

2
ctru-rs/examples/hashmaps.rs

@ -26,7 +26,7 @@ fn main() {
gfx.wait_for_vblank(); gfx.wait_for_vblank();
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }
} }

2
ctru-rs/examples/hello-both-screens.rs

@ -32,7 +32,7 @@ fn main() {
gfx.wait_for_vblank(); gfx.wait_for_vblank();
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }
} }

2
ctru-rs/examples/hello-world.rs

@ -26,7 +26,7 @@ fn main() {
//Scan all the inputs. This should be done once for each frame //Scan all the inputs. This should be done once for each frame
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }
// Flush and swap framebuffers // Flush and swap framebuffers

2
ctru-rs/examples/linear-memory.rs

@ -34,7 +34,7 @@ fn main() {
//Scan all the inputs. This should be done once for each frame //Scan all the inputs. This should be done once for each frame
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }
// Flush and swap framebuffers // Flush and swap framebuffers

2
ctru-rs/examples/mii-selector.rs

@ -30,7 +30,7 @@ fn main() {
//Scan all the inputs. This should be done once for each frame //Scan all the inputs. This should be done once for each frame
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }
// Flush and swap framebuffers // Flush and swap framebuffers

2
ctru-rs/examples/network-sockets.rs

@ -61,7 +61,7 @@ fn main() {
} }
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
}; };
} }

2
ctru-rs/examples/output-3dslink.rs

@ -30,7 +30,7 @@ fn main() {
//Scan all the inputs. This should be done once for each frame //Scan all the inputs. This should be done once for each frame
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }
// Flush and swap framebuffers // Flush and swap framebuffers

4
ctru-rs/examples/romfs.rs

@ -13,7 +13,7 @@ fn main() {
// This never fails as `ctru-rs` examples inherit all of the `ctru` features, // 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 // but it might if a normal user application wasn't setup correctly
if #[cfg(all(feature = "romfs", romfs_exists))] { if #[cfg(all(feature = "romfs", romfs_exists))] {
let _romfs = ctru::romfs::RomFS::init().unwrap(); let _romfs = ctru::services::romfs::RomFS::init().unwrap();
let f = std::fs::read_to_string("romfs:/test-file.txt").unwrap(); let f = std::fs::read_to_string("romfs:/test-file.txt").unwrap();
println!("Contents of test-file.txt: \n{f}\n"); println!("Contents of test-file.txt: \n{f}\n");
@ -33,7 +33,7 @@ fn main() {
//Scan all the inputs. This should be done once for each frame //Scan all the inputs. This should be done once for each frame
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }
// Flush and swap framebuffers // Flush and swap framebuffers

15
ctru-rs/examples/software-keyboard.rs

@ -18,26 +18,23 @@ fn main() {
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_A) { if hid.keys_down().contains(KeyPad::A) {
// Prepares a software keyboard with two buttons: One to cancel input and one // Prepares a software keyboard with two buttons: One to cancel input and one
// to accept it. You can also use `Swkbd::init()` to launch the keyboard in different // to accept it. You can also use `Swkbd::init()` to launch the keyboard in different
// configurations. // configurations.
let mut keyboard = Swkbd::default(); let mut keyboard = Swkbd::default();
// String used to store text received from the keyboard
let mut text = String::new();
// Raise the software keyboard. You can perform different actions depending on which // 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_utf8(&mut text) { match keyboard.get_string(2048) {
Ok(Button::Right) => println!("You entered: {text}"), Ok((text, Button::Right)) => println!("You entered: {text}"),
Ok(Button::Left) => println!("Cancelled"), Ok((_, Button::Left)) => println!("Cancelled"),
Ok(Button::Middle) => println!("How did you even press this?"), Ok((_, Button::Middle)) => println!("How did you even press this?"),
Err(_) => println!("Oh noes, an error happened!"), Err(_) => println!("Oh noes, an error happened!"),
} }
} }
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }
} }

8
ctru-rs/examples/system-configuration.rs

@ -10,16 +10,16 @@ fn main() {
let cfgu = Cfgu::init().expect("Couldn't obtain CFGU controller"); let cfgu = Cfgu::init().expect("Couldn't obtain CFGU controller");
let _console = Console::init(gfx.top_screen.borrow_mut()); let _console = Console::init(gfx.top_screen.borrow_mut());
println!("\x1b[0;0HRegion: {:?}", cfgu.get_region().unwrap()); println!("\x1b[0;0HRegion: {:?}", cfgu.region().unwrap());
println!("\x1b[10;0HLanguage: {:?}", cfgu.get_language().unwrap()); println!("\x1b[10;0HLanguage: {:?}", cfgu.language().unwrap());
println!("\x1b[20;0HModel: {:?}", cfgu.get_model().unwrap()); println!("\x1b[20;0HModel: {:?}", cfgu.model().unwrap());
// Main loop // Main loop
while apt.main_loop() { while apt.main_loop() {
//Scan all the inputs. This should be done once for each frame //Scan all the inputs. This should be done once for each frame
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }
// Flush and swap framebuffers // Flush and swap framebuffers

2
ctru-rs/examples/time-rtc.rs

@ -16,7 +16,7 @@ fn main() {
// Scan all the inputs. This should be done once for each frame // Scan all the inputs. This should be done once for each frame
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }

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

@ -13,17 +13,17 @@ fn main() {
let bottom_screen = Console::init(gfx.bottom_screen.borrow_mut()); let bottom_screen = Console::init(gfx.bottom_screen.borrow_mut());
let sd_count = am let sd_count = am
.get_title_count(FsMediaType::Sd) .title_count(FsMediaType::Sd)
.expect("Failed to get sd title count"); .expect("Failed to get sd title count");
let sd_list = am let sd_list = am
.get_title_list(FsMediaType::Sd) .title_list(FsMediaType::Sd)
.expect("Failed to get sd title list"); .expect("Failed to get sd title list");
let nand_count = am let nand_count = am
.get_title_count(FsMediaType::Nand) .title_count(FsMediaType::Nand)
.expect("Failed to get nand title count"); .expect("Failed to get nand title count");
let nand_list = am let nand_list = am
.get_title_list(FsMediaType::Nand) .title_list(FsMediaType::Nand)
.expect("Failed to get nand title list"); .expect("Failed to get nand title list");
let mut offset = 0; let mut offset = 0;
@ -35,10 +35,10 @@ fn main() {
//Scan all the inputs. This should be done once for each frame //Scan all the inputs. This should be done once for each frame
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }
if hid.keys_down().contains(KeyPad::KEY_SELECT) { if hid.keys_down().contains(KeyPad::SELECT) {
refresh = true; refresh = true;
offset = 0; offset = 0;
use_nand = !use_nand; use_nand = !use_nand;
@ -46,12 +46,12 @@ fn main() {
let cur_list = if use_nand { &nand_list } else { &sd_list }; let cur_list = if use_nand { &nand_list } else { &sd_list };
if hid.keys_down().intersects(KeyPad::KEY_DOWN) { if hid.keys_down().intersects(KeyPad::DOWN) {
if offset + 1 < cur_list.len() { if offset + 1 < cur_list.len() {
offset = offset + 1; offset = offset + 1;
refresh = true; refresh = true;
} }
} else if hid.keys_down().intersects(KeyPad::KEY_UP) { } else if hid.keys_down().intersects(KeyPad::UP) {
if offset > 0 { if offset > 0 {
offset = offset - 1; offset = offset - 1;
refresh = true; refresh = true;
@ -80,14 +80,14 @@ fn main() {
// Move cursor to top left // Move cursor to top left
println!("\x1b[1;1"); println!("\x1b[1;1");
match selected_title.get_title_info() { match selected_title.title_info() {
Ok(info) => { Ok(info) => {
println!("Size: {} KB", info.size_bytes() / 1024); println!("Size: {} KB", info.size_bytes() / 1024);
println!("Version: 0x{:x}", info.version()); println!("Version: 0x{:x}", info.version());
} }
Err(e) => println!("Failed to get title info: {}", e), Err(e) => println!("Failed to get title info: {}", e),
} }
match selected_title.get_product_code() { match selected_title.product_code() {
Ok(code) => println!("Product code: \"{code}\""), Ok(code) => println!("Product code: \"{code}\""),
Err(e) => println!("Failed to get product code: {}", e), Err(e) => println!("Failed to get product code: {}", e),
} }

4
ctru-rs/src/applets/mii_selector.rs

@ -135,10 +135,10 @@ impl MiiSelector {
/// Set where the cursor will be. /// 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 /// 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: u32) { pub fn set_initial_index(&mut self, index: usize) {
// This function is static inline in libctru // This function is static inline in libctru
// https://github.com/devkitPro/libctru/blob/af5321c78ee5c72a55b526fd2ed0d95ca1c05af9/libctru/include/3ds/applets/miiselector.h#L155 // https://github.com/devkitPro/libctru/blob/af5321c78ee5c72a55b526fd2ed0d95ca1c05af9/libctru/include/3ds/applets/miiselector.h#L155
self.config.initial_index = index self.config.initial_index = index as u32;
} }
/// Launch the Mii Selector. /// Launch the Mii Selector.

109
ctru-rs/src/applets/swkbd.rs

@ -19,68 +19,70 @@ pub struct Swkbd {
/// Western is a text keyboard without japanese symbols (only applies to JPN systems). For other /// Western is a text keyboard without japanese symbols (only applies to JPN systems). For other
/// systems it's the same as a Normal keyboard. /// systems it's the same as a Normal keyboard.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum Kind { pub enum Kind {
Normal, Normal = ctru_sys::SWKBD_TYPE_NORMAL,
Qwerty, Qwerty = ctru_sys::SWKBD_TYPE_QWERTY,
Numpad, Numpad = ctru_sys::SWKBD_TYPE_NUMPAD,
Western, 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 software keyboard.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum Button { pub enum Button {
Left, Left = ctru_sys::SWKBD_BUTTON_LEFT,
Middle, Middle = ctru_sys::SWKBD_BUTTON_MIDDLE,
Right, Right = ctru_sys::SWKBD_BUTTON_RIGHT,
} }
/// Error type for the software keyboard. /// Error type for the software keyboard.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[repr(i32)]
pub enum Error { pub enum Error {
InvalidInput, InvalidInput = ctru_sys::SWKBD_INVALID_INPUT,
OutOfMem, OutOfMem = ctru_sys::SWKBD_OUTOFMEM,
HomePressed, HomePressed = ctru_sys::SWKBD_HOMEPRESSED,
ResetPressed, ResetPressed = ctru_sys::SWKBD_RESETPRESSED,
PowerPressed, PowerPressed = ctru_sys::SWKBD_POWERPRESSED,
ParentalOk, ParentalOk = ctru_sys::SWKBD_PARENTAL_OK,
ParentalFail, ParentalFail = ctru_sys::SWKBD_PARENTAL_FAIL,
BannedInput, BannedInput = ctru_sys::SWKBD_BANNED_INPUT,
} }
/// Restrictions on keyboard input /// Restrictions on keyboard input
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum ValidInput { pub enum ValidInput {
Anything, Anything = ctru_sys::SWKBD_ANYTHING,
NotEmpty, NotEmpty = ctru_sys::SWKBD_NOTEMPTY,
NotEmptyNotBlank, NotEmptyNotBlank = ctru_sys::SWKBD_NOTEMPTY_NOTBLANK,
NotBlank, NotBlank = ctru_sys::SWKBD_NOTBLANK,
FixedLen, FixedLen = ctru_sys::SWKBD_FIXEDLEN,
} }
bitflags! { bitflags! {
/// Keyboard feature flags /// Keyboard feature flags
pub struct Features: u32 { pub struct Features: u32 {
const PARENTAL_PIN = 1 << 0; const PARENTAL_PIN = ctru_sys::SWKBD_PARENTAL;
const DARKEN_TOP_SCREEN = 1 << 1; const DARKEN_TOP_SCREEN = ctru_sys::SWKBD_DARKEN_TOP_SCREEN;
const PREDICTIVE_INPUT = 1 << 2; const PREDICTIVE_INPUT = ctru_sys::SWKBD_PREDICTIVE_INPUT;
const MULTILINE = 1 << 3; const MULTILINE = ctru_sys::SWKBD_MULTILINE;
const FIXED_WIDTH = 1 << 4; const FIXED_WIDTH = ctru_sys::SWKBD_FIXED_WIDTH;
const ALLOW_HOME = 1 << 5; const ALLOW_HOME = ctru_sys::SWKBD_ALLOW_HOME;
const ALLOW_RESET = 1 << 6; const ALLOW_RESET = ctru_sys::SWKBD_ALLOW_RESET;
const ALLOW_POWER = 1 << 7; const ALLOW_POWER = ctru_sys::SWKBD_ALLOW_POWER;
const DEFAULT_QWERTY = 1 << 8; const DEFAULT_QWERTY = ctru_sys::SWKBD_DEFAULT_QWERTY;
}
} }
bitflags! {
/// Keyboard input filtering flags /// Keyboard input filtering flags
pub struct Filters: u32 { pub struct Filters: u32 {
const DIGITS = 1 << 0; const DIGITS = ctru_sys::SWKBD_FILTER_DIGITS;
const AT = 1 << 1; const AT = ctru_sys::SWKBD_FILTER_AT;
const PERCENT = 1 << 2; const PERCENT = ctru_sys::SWKBD_FILTER_PERCENT;
const BACKSLASH = 1 << 3; const BACKSLASH = ctru_sys::SWKBD_FILTER_BACKSLASH;
const PROFANITY = 1 << 4; const PROFANITY = ctru_sys::SWKBD_FILTER_PROFANITY;
const CALLBACK = 1 << 5; const CALLBACK = ctru_sys::SWKBD_FILTER_CALLBACK;
} }
} }
@ -90,41 +92,39 @@ impl Swkbd {
pub fn init(keyboard_type: Kind, num_buttons: i32) -> Self { pub fn init(keyboard_type: Kind, num_buttons: i32) -> Self {
unsafe { unsafe {
let mut state = Box::<SwkbdState>::default(); let mut state = Box::<SwkbdState>::default();
swkbdInit(state.as_mut(), keyboard_type as u32, num_buttons, -1); swkbdInit(state.as_mut(), keyboard_type.into(), num_buttons, -1);
Swkbd { state } Swkbd { state }
} }
} }
/// Gets input from this keyboard and appends it to the provided string. /// Gets input from this keyboard and appends it to the provided string.
/// ///
/// The text received from the keyboard will be truncated if it is greater than 2048 bytes /// The text received from the keyboard will be truncated if it is longer than `max_bytes`.
/// in length. pub fn get_string(&mut self, max_bytes: usize) -> Result<(String, Button), Error> {
pub fn get_utf8(&mut self, buf: &mut String) -> Result<Button, Error> {
// Unfortunately the libctru API doesn't really provide a way to get the exact length // 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 // of the string that it receieves from the software keyboard. Instead it expects you
// to pass in a buffer and hope that it's big enough to fit the entire string, so // to pass in a buffer and hope that it's big enough to fit the entire string, so
// you have to set some upper limit on the potential size of the user's input. // you have to set some upper limit on the potential size of the user's input.
const MAX_BYTES: usize = 2048; let mut tmp = vec![0u8; max_bytes];
let mut tmp = [0u8; MAX_BYTES]; let button = self.write_exact(&mut tmp)?;
let button = self.get_bytes(&mut tmp)?;
// libctru does, however, seem to ensure that the buffer will always contain a properly // libctru does, however, seem to ensure that the buffer will always contain a properly
// terminated UTF-8 sequence even if the input has to be truncated, so these operations // terminated UTF-8 sequence even if the input has to be truncated, so these operations
// should be safe. // should be safe.
let len = unsafe { libc::strlen(tmp.as_ptr()) }; let len = unsafe { libc::strlen(tmp.as_ptr()) };
let utf8 = unsafe { str::from_utf8_unchecked(&tmp[..len]) }; tmp.truncate(len);
// Copy the input into the user's `String` let res = unsafe { String::from_utf8_unchecked(tmp) };
*buf += utf8;
Ok(button) Ok((res, button))
} }
/// Fills the provided buffer with a UTF-8 encoded, NUL-terminated sequence of bytes from /// Fills the provided buffer with a UTF-8 encoded, NUL-terminated sequence of bytes from
/// this software keyboard. /// this software keyboard.
/// ///
/// If the buffer is too small to contain the entire sequence received from the keyboard, /// 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 but should still be well-formed UTF-8.
pub fn get_bytes(&mut self, buf: &mut [u8]) -> Result<Button, Error> { pub fn write_exact(&mut self, buf: &mut [u8]) -> Result<Button, Error> {
unsafe { unsafe {
match swkbdInputText(self.state.as_mut(), buf.as_mut_ptr(), buf.len()) { match swkbdInputText(self.state.as_mut(), buf.as_mut_ptr(), buf.len()) {
ctru_sys::SWKBD_BUTTON_NONE => Err(self.parse_swkbd_error()), ctru_sys::SWKBD_BUTTON_NONE => Err(self.parse_swkbd_error()),
@ -143,7 +143,7 @@ impl Swkbd {
/// Configures input validation for this keyboard /// Configures input validation for this keyboard
pub fn set_validation(&mut self, validation: ValidInput, filters: Filters) { pub fn set_validation(&mut self, validation: ValidInput, filters: Filters) {
self.state.valid_input = validation as i32; self.state.valid_input = validation.into();
self.state.filter_flags = filters.bits; self.state.filter_flags = filters.bits;
} }
@ -173,7 +173,7 @@ impl Swkbd {
let nul_terminated: String = text.chars().chain(once('\0')).collect(); let nul_terminated: String = text.chars().chain(once('\0')).collect();
swkbdSetButton( swkbdSetButton(
self.state.as_mut(), self.state.as_mut(),
button as u32, button.into(),
nul_terminated.as_ptr(), nul_terminated.as_ptr(),
submit, submit,
); );
@ -210,3 +210,8 @@ impl Default for Swkbd {
Swkbd::init(Kind::Normal, 2) Swkbd::init(Kind::Normal, 2)
} }
} }
from_impl!(Kind, ctru_sys::SwkbdType);
from_impl!(Button, ctru_sys::SwkbdButton);
from_impl!(Error, ctru_sys::SwkbdResult);
from_impl!(ValidInput, i32);

2
ctru-rs/src/console.rs

@ -3,7 +3,7 @@ use std::default::Default;
use ctru_sys::{consoleClear, consoleInit, consoleSelect, consoleSetWindow, PrintConsole}; use ctru_sys::{consoleClear, consoleInit, consoleSelect, consoleSetWindow, PrintConsole};
use crate::gfx::Screen; use crate::services::gfx::Screen;
static mut EMPTY_CONSOLE: PrintConsole = unsafe { const_zero::const_zero!(PrintConsole) }; static mut EMPTY_CONSOLE: PrintConsole = unsafe { const_zero::const_zero!(PrintConsole) };

36
ctru-rs/src/lib.rs

@ -15,10 +15,20 @@ extern crate pthread_3ds;
#[cfg(feature = "big-stack")] #[cfg(feature = "big-stack")]
static __stacksize__: usize = 2 * 1024 * 1024; // 2MB static __stacksize__: usize = 2 * 1024 * 1024; // 2MB
/// Activate ´ctru-rs´' default panic handler. macro_rules! from_impl {
($from_type:ty, $into_type:ty) => {
impl From<$from_type> for $into_type {
fn from(v: $from_type) -> Self {
v as $into_type
}
}
};
}
/// Activate the default panic handler.
/// ///
/// With this implementation, the main thread will stop and try to print debug info to an available [console::Console]. /// 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. /// In case it fails to find an active [console::Console] the program will just exit.
/// ///
/// # Notes /// # Notes
/// ///
@ -48,7 +58,7 @@ fn panic_hook_setup() {
Ok(hid) => loop { Ok(hid) => loop {
hid.scan_input(); hid.scan_input();
let keys = hid.keys_down(); let keys = hid.keys_down();
if keys.contains(KeyPad::KEY_SELECT) { if keys.contains(KeyPad::SELECT) {
break; break;
} }
}, },
@ -62,31 +72,11 @@ fn panic_hook_setup() {
pub mod applets; pub mod applets;
pub mod console; pub mod console;
pub mod error; pub mod error;
pub mod gfx;
pub mod linear; pub mod linear;
pub mod mii; pub mod mii;
pub mod prelude; pub mod prelude;
pub mod services; pub mod services;
cfg_if::cfg_if! {
if #[cfg(all(feature = "romfs", romfs_exists))] {
pub mod romfs;
} else {
pub mod romfs {
//! The RomFS folder has not been detected and/or the `romfs` feature has not been enabled.
//!
//! Configure the path in Cargo.toml (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.
//!
//! ```toml
//! [package.metadata.cargo-3ds]
//! romfs_dir = "romfs"
//! ```
}
}
}
#[cfg(test)] #[cfg(test)]
mod test_runner; mod test_runner;

3
ctru-rs/src/prelude.rs

@ -1,3 +1,2 @@
pub use crate::console::Console; pub use crate::console::Console;
pub use crate::gfx::Gfx; pub use crate::services::{gfx::Gfx, hid::KeyPad, soc::Soc, Apt, Hid};
pub use crate::services::{hid::KeyPad, soc::Soc, Apt, Hid};

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

@ -29,12 +29,12 @@ impl<'a> Title<'a> {
self.id self.id
} }
pub fn get_product_code(&self) -> crate::Result<String> { pub fn product_code(&self) -> crate::Result<String> {
let mut buf: [u8; 16] = [0; 16]; let mut buf: [u8; 16] = [0; 16];
unsafe { unsafe {
ResultCode(ctru_sys::AM_GetTitleProductCode( ResultCode(ctru_sys::AM_GetTitleProductCode(
self.mediatype as u32, self.mediatype.into(),
self.id, self.id,
buf.as_mut_ptr(), buf.as_mut_ptr(),
))?; ))?;
@ -42,12 +42,12 @@ impl<'a> Title<'a> {
Ok(String::from_utf8_lossy(&buf).to_string()) Ok(String::from_utf8_lossy(&buf).to_string())
} }
pub fn get_title_info(&self) -> crate::Result<TitleInfo> { pub fn title_info(&self) -> crate::Result<TitleInfo> {
let mut info = MaybeUninit::zeroed(); let mut info = MaybeUninit::zeroed();
unsafe { unsafe {
ResultCode(ctru_sys::AM_GetTitleInfo( ResultCode(ctru_sys::AM_GetTitleInfo(
self.mediatype as u32, self.mediatype.into(),
1, 1,
&mut self.id.clone(), &mut self.id.clone(),
info.as_mut_ptr() as _, info.as_mut_ptr() as _,
@ -68,22 +68,22 @@ impl Am {
} }
} }
pub fn get_title_count(&self, mediatype: FsMediaType) -> crate::Result<u32> { pub fn title_count(&self, mediatype: FsMediaType) -> crate::Result<u32> {
unsafe { unsafe {
let mut count = 0; let mut count = 0;
ResultCode(ctru_sys::AM_GetTitleCount(mediatype as u32, &mut count))?; ResultCode(ctru_sys::AM_GetTitleCount(mediatype.into(), &mut count))?;
Ok(count) Ok(count)
} }
} }
pub fn get_title_list(&self, mediatype: FsMediaType) -> crate::Result<Vec<Title>> { pub fn title_list(&self, mediatype: FsMediaType) -> crate::Result<Vec<Title>> {
let count = self.get_title_count(mediatype)?; let count = self.title_count(mediatype)?;
let mut buf = vec![0; count as usize]; let mut buf = vec![0; count as usize];
let mut read_amount = 0; let mut read_amount = 0;
unsafe { unsafe {
ResultCode(ctru_sys::AM_GetTitleList( ResultCode(ctru_sys::AM_GetTitleList(
&mut read_amount, &mut read_amount,
mediatype as u32, mediatype.into(),
count, count,
buf.as_mut_ptr(), buf.as_mut_ptr(),
))?; ))?;

387
ctru-rs/src/services/cam.rs

@ -1,11 +1,10 @@
//! CAM service //! Camera service
//! //!
//! The CAM service provides access to the cameras. Cameras can return 2D images //! The CAM service provides access to the cameras. Cameras can return images
//! in the form of byte vectors which can be used for display or other usages. //! in the form of byte vectors which can be displayed or used in other ways.
use crate::error::{Error, ResultCode}; use crate::error::{Error, ResultCode};
use crate::services::gspgpu::FramebufferFormat; use crate::services::gspgpu::FramebufferFormat;
use bitflags::bitflags;
use ctru_sys::Handle; use ctru_sys::Handle;
use std::time::Duration; use std::time::Duration;
@ -21,191 +20,168 @@ pub struct Cam {
pub both_outer_cams: BothOutwardCam, pub both_outer_cams: BothOutwardCam,
} }
bitflags! { /// Flag to pass to [Camera::flip_image]
/// A set of flags to be passed to [Camera::flip_image] #[derive(Copy, Clone, Debug)]
#[derive(Default)] #[repr(u32)]
pub struct CamFlip: u32 { pub enum FlipMode {
const NONE = ctru_sys::FLIP_NONE; None = ctru_sys::FLIP_NONE,
const HORIZONTAL = ctru_sys::FLIP_HORIZONTAL; Horizontal = ctru_sys::FLIP_HORIZONTAL,
const VERTICAL = ctru_sys::FLIP_VERTICAL; Vertical = ctru_sys::FLIP_VERTICAL,
const REVERSE = ctru_sys::FLIP_REVERSE; Reverse = ctru_sys::FLIP_REVERSE,
} }
}
/// Flag to pass to [Camera::set_view_size]
bitflags! { #[derive(Copy, Clone, Debug)]
/// A set of flags to be passed to [Camera::set_view_size] #[repr(u32)]
#[derive(Default)] pub enum ViewSize {
pub struct CamSize: u32 { TopLCD = ctru_sys::SIZE_CTR_TOP_LCD,
const VGA = ctru_sys::SIZE_VGA; /// Equivalent to QVga
const QVGA = ctru_sys::SIZE_QVGA; BottomLCD = ctru_sys::SIZE_CTR_BOTTOM_LCD,
const QQVGA = ctru_sys::SIZE_QQVGA; Vga = ctru_sys::SIZE_VGA,
const CIF = ctru_sys::SIZE_CIF; QQVga = ctru_sys::SIZE_QQVGA,
const QCIF = ctru_sys::SIZE_QCIF; Cif = ctru_sys::SIZE_CIF,
const DS_LCD = ctru_sys::SIZE_DS_LCD; QCif = ctru_sys::SIZE_QCIF,
const DS_LCD_X4 = ctru_sys::SIZE_DS_LCDx4; /// Nintendo DS Screen
const CTR_TOP_LCD = ctru_sys::SIZE_CTR_TOP_LCD; DS = ctru_sys::SIZE_DS_LCD,
const CTR_BOTTOM_LCD = ctru_sys::SIZE_CTR_BOTTOM_LCD; /// Nintendo DS Screen x4
} DSX4 = ctru_sys::SIZE_DS_LCDx4,
} }
bitflags! { /// Flag to pass to [Camera::set_frame_rate]
/// A set of flags to be passed to [Camera::set_frame_rate] #[derive(Copy, Clone, Debug)]
#[derive(Default)] #[repr(u32)]
pub struct CamFrameRate: u32 { pub enum FrameRate {
const RATE_15 = ctru_sys::FRAME_RATE_15; Fps15 = ctru_sys::FRAME_RATE_15,
const RATE_15_TO_5 = ctru_sys::FRAME_RATE_15_TO_5; Fps15To5 = ctru_sys::FRAME_RATE_15_TO_5,
const RATE_15_TO_2 = ctru_sys::FRAME_RATE_15_TO_2; Fps15To2 = ctru_sys::FRAME_RATE_15_TO_2,
const RATE_10 = ctru_sys::FRAME_RATE_10; Fps10 = ctru_sys::FRAME_RATE_10,
const RATE_8_5 = ctru_sys::FRAME_RATE_8_5; Fps8_5 = ctru_sys::FRAME_RATE_8_5,
const RATE_5 = ctru_sys::FRAME_RATE_5; Fps5 = ctru_sys::FRAME_RATE_5,
const RATE_20 = ctru_sys::FRAME_RATE_20; Fps20 = ctru_sys::FRAME_RATE_20,
const RATE_20_TO_5 = ctru_sys::FRAME_RATE_20_TO_5; Fps20To5 = ctru_sys::FRAME_RATE_20_TO_5,
const RATE_30 = ctru_sys::FRAME_RATE_30; Fps30 = ctru_sys::FRAME_RATE_30,
const RATE_30_TO_5 = ctru_sys::FRAME_RATE_30_TO_5; Fps30To5 = ctru_sys::FRAME_RATE_30_TO_5,
const RATE_15_TO_10 = ctru_sys::FRAME_RATE_15_TO_10; Fps15To10 = ctru_sys::FRAME_RATE_15_TO_10,
const RATE_20_TO_10 = ctru_sys::FRAME_RATE_20_TO_10; Fps20To10 = ctru_sys::FRAME_RATE_20_TO_10,
const RATE_30_TO_10 = ctru_sys::FRAME_RATE_30_TO_10; Fps30To10 = ctru_sys::FRAME_RATE_30_TO_10,
} }
}
/// Flag to pass to [Camera::set_white_balance] or
bitflags! {
/// A set of flags to be passed to [Camera::set_white_balance] or
/// [Camera::set_white_balance_without_base_up] /// [Camera::set_white_balance_without_base_up]
#[derive(Default)] #[derive(Copy, Clone, Debug)]
pub struct CamWhiteBalance: u32 { #[repr(u32)]
const AUTO = ctru_sys::WHITE_BALANCE_AUTO; pub enum WhiteBalance {
const BALANCE_3200K = ctru_sys::WHITE_BALANCE_3200K; /// Normal
const BALANCE_4150K = ctru_sys::WHITE_BALANCE_4150K; Auto = ctru_sys::WHITE_BALANCE_AUTO,
const BALANCE_5200K = ctru_sys::WHITE_BALANCE_5200K; /// Tungsten
const BALANCE_6000K = ctru_sys::WHITE_BALANCE_6000K; Temp3200K = ctru_sys::WHITE_BALANCE_3200K,
const BALANCE_7000K = ctru_sys::WHITE_BALANCE_7000K; /// Fluorescent Light
Temp4150K = ctru_sys::WHITE_BALANCE_4150K,
const NORMAL = ctru_sys::WHITE_BALANCE_NORMAL; /// Daylight
const TUNGSTEN = ctru_sys::WHITE_BALANCE_TUNGSTEN; Temp5200K = ctru_sys::WHITE_BALANCE_5200K,
const WHITE_FLUORESCENT_LIGHT = ctru_sys::WHITE_BALANCE_WHITE_FLUORESCENT_LIGHT; /// Cloudy/Horizon
const DAYLIGHT = ctru_sys::WHITE_BALANCE_DAYLIGHT; Temp6000K = ctru_sys::WHITE_BALANCE_6000K,
const CLOUDY = ctru_sys::WHITE_BALANCE_CLOUDY; ///Shade
const HORIZON = ctru_sys::WHITE_BALANCE_HORIZON; Temp7000K = ctru_sys::WHITE_BALANCE_7000K,
const SHADE = ctru_sys::WHITE_BALANCE_SHADE; }
}
} /// Flag to pass to [Camera::set_photo_mode]
#[derive(Copy, Clone, Debug)]
bitflags! { #[repr(u32)]
/// A set of flags to be passed to [Camera::set_photo_mode] pub enum PhotoMode {
#[derive(Default)] Normal = ctru_sys::PHOTO_MODE_NORMAL,
pub struct CamPhotoMode: u32 { Portrait = ctru_sys::PHOTO_MODE_PORTRAIT,
const NORMAL = ctru_sys::PHOTO_MODE_NORMAL; Landscape = ctru_sys::PHOTO_MODE_LANDSCAPE,
const PORTRAIT = ctru_sys::PHOTO_MODE_PORTRAIT; NightView = ctru_sys::PHOTO_MODE_NIGHTVIEW,
const LANDSCAPE = ctru_sys::PHOTO_MODE_LANDSCAPE; Letter = ctru_sys::PHOTO_MODE_LETTER,
const NIGHTVIEW = ctru_sys::PHOTO_MODE_NIGHTVIEW; }
const LETTER = ctru_sys::PHOTO_MODE_LETTER;
} /// Flag to pass to [Camera::set_effect]
} #[derive(Copy, Clone, Debug)]
#[repr(u32)]
bitflags! { pub enum Effect {
/// A set of flags to be passed to [Camera::set_effect] None = ctru_sys::EFFECT_NONE,
#[derive(Default)] Mono = ctru_sys::EFFECT_MONO,
pub struct CamEffect: u32 { Sepia = ctru_sys::EFFECT_SEPIA,
const NONE = ctru_sys::EFFECT_NONE; Negative = ctru_sys::EFFECT_NEGATIVE,
const MONO = ctru_sys::EFFECT_MONO; Negafilm = ctru_sys::EFFECT_NEGAFILM,
const SEPIA = ctru_sys::EFFECT_SEPIA; Sepia01 = ctru_sys::EFFECT_SEPIA01,
const NEGATIVE = ctru_sys::EFFECT_NEGATIVE; }
const NEGAFILM = ctru_sys::EFFECT_NEGAFILM;
const SEPIA01 = ctru_sys::EFFECT_SEPIA01; /// Flag to pass to [Camera::set_contrast]
} #[derive(Copy, Clone, Debug)]
} #[repr(u32)]
pub enum Contrast {
bitflags! { /// OFF
/// A set of flags to be passed to [Camera::set_contrast] Low = ctru_sys::CONTRAST_LOW,
#[derive(Default)] /// Brightness ratio: 70
pub struct CamContrast: u32 { Normal = ctru_sys::CONTRAST_NORMAL,
const PATTERN_01 = ctru_sys::CONTRAST_PATTERN_01; /// Brightness ratio: 90
const PATTERN_02 = ctru_sys::CONTRAST_PATTERN_02; High = ctru_sys::CONTRAST_HIGH,
const PATTERN_03 = ctru_sys::CONTRAST_PATTERN_03; }
const PATTERN_04 = ctru_sys::CONTRAST_PATTERN_04;
const PATTERN_05 = ctru_sys::CONTRAST_PATTERN_05; /// Flag to pass to [Camera::set_lens_correction]
const PATTERN_06 = ctru_sys::CONTRAST_PATTERN_06; #[derive(Copy, Clone, Debug)]
const PATTERN_07 = ctru_sys::CONTRAST_PATTERN_07; #[repr(u32)]
const PATTERN_08 = ctru_sys::CONTRAST_PATTERN_08; pub enum LensCorrection {
const PATTERN_09 = ctru_sys::CONTRAST_PATTERN_09; Off = ctru_sys::LENS_CORRECTION_DARK,
const PATTERN_10 = ctru_sys::CONTRAST_PATTERN_10; Normal = ctru_sys::LENS_CORRECTION_NORMAL,
const PATTERN_11 = ctru_sys::CONTRAST_PATTERN_11; Bright = ctru_sys::LENS_CORRECTION_BRIGHT,
}
const LOW = ctru_sys::CONTRAST_LOW;
const NORMAL = ctru_sys::CONTRAST_NORMAL; /// Flag to pass to [Camera::set_output_format]
const HIGH = ctru_sys::CONTRAST_HIGH; #[derive(Copy, Clone, Debug)]
} #[repr(u32)]
} pub enum OutputFormat {
Yuv422 = ctru_sys::OUTPUT_YUV_422,
bitflags! { Rgb565 = ctru_sys::OUTPUT_RGB_565,
/// A set of flags to be passed to [Camera::set_lens_correction] }
#[derive(Default)]
pub struct CamLensCorrection: u32 { /// Flag to pass to [Cam::play_shutter_sound]
const OFF = ctru_sys::LENS_CORRECTION_OFF; #[derive(Copy, Clone, Debug)]
const ON_70 = ctru_sys::LENS_CORRECTION_ON_70; #[repr(u32)]
const ON_90 = ctru_sys::LENS_CORRECTION_ON_90; pub enum ShutterSound {
Normal = ctru_sys::SHUTTER_SOUND_TYPE_NORMAL,
const DARK = ctru_sys::LENS_CORRECTION_DARK; Movie = ctru_sys::SHUTTER_SOUND_TYPE_MOVIE,
const NORMAL = ctru_sys::LENS_CORRECTION_NORMAL; MovieEnd = ctru_sys::SHUTTER_SOUND_TYPE_MOVIE_END,
const BRIGHT = ctru_sys::LENS_CORRECTION_BRIGHT; }
}
} impl TryFrom<FramebufferFormat> for OutputFormat {
bitflags! {
/// A set of flags to be passed to [Camera::set_output_format]
#[derive(Default)]
pub struct CamOutputFormat: u32 {
const YUV_422 = ctru_sys::OUTPUT_YUV_422;
const RGB_565 = ctru_sys::OUTPUT_RGB_565;
}
}
impl TryFrom<FramebufferFormat> for CamOutputFormat {
type Error = (); type Error = ();
fn try_from(value: FramebufferFormat) -> Result<Self, Self::Error> { fn try_from(value: FramebufferFormat) -> Result<Self, Self::Error> {
match value { match value {
FramebufferFormat::Rgb565 => Ok(CamOutputFormat::RGB_565), FramebufferFormat::Rgb565 => Ok(OutputFormat::Rgb565),
_ => Err(()), _ => Err(()),
} }
} }
} }
impl TryFrom<CamOutputFormat> for FramebufferFormat { impl TryFrom<OutputFormat> for FramebufferFormat {
type Error = (); type Error = ();
fn try_from(value: CamOutputFormat) -> Result<Self, Self::Error> { fn try_from(value: OutputFormat) -> Result<Self, Self::Error> {
match value { match value {
CamOutputFormat::RGB_565 => Ok(FramebufferFormat::Rgb565), OutputFormat::Rgb565 => Ok(FramebufferFormat::Rgb565),
_ => Err(()), _ => Err(()),
} }
} }
} }
bitflags! {
/// A set of flags to be passed to [Cam::play_shutter_sound]
#[derive(Default)]
pub struct CamShutterSoundType: u32 {
const NORMAL = ctru_sys::SHUTTER_SOUND_TYPE_NORMAL;
const MOVIE = ctru_sys::SHUTTER_SOUND_TYPE_MOVIE;
const MOVIE_END = ctru_sys::SHUTTER_SOUND_TYPE_MOVIE_END;
}
}
/// Struct containing coordinates passed to [Camera::set_trimming_params]. /// Struct containing coordinates passed to [Camera::set_trimming_params].
pub struct CamTrimmingParams { pub struct TrimmingParams {
x_start: i16, x_start: i16,
y_start: i16, y_start: i16,
x_end: i16, x_end: i16,
y_end: i16, y_end: i16,
} }
impl CamTrimmingParams { impl TrimmingParams {
/// Creates a new [CamTrimmingParams] and guarantees the start coordinates are less than or /// Creates a new [CamTrimmingParams] and guarantees the start coordinates are less than or
/// equal to the end coordinates. /// equal to the end coordinates.
/// ///
/// `x_start <= x_end && y_start <= y_end` /// `x_start <= x_end && y_start <= y_end`
pub fn new(x_start: i16, y_start: i16, x_end: i16, y_end: i16) -> CamTrimmingParams { 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); assert!(x_start <= x_end && y_start <= y_end);
Self { Self {
x_start, x_start,
@ -307,7 +283,7 @@ pub trait Camera {
/// Returns the maximum amount of transfer bytes based on the view size, trimming, and other /// 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
fn get_transfer_bytes(&self) -> crate::Result<u32> { fn transfer_byte_count(&self) -> crate::Result<u32> {
unsafe { unsafe {
let mut transfer_bytes = 0; let mut transfer_bytes = 0;
ResultCode(ctru_sys::CAMU_GetTransferBytes( ResultCode(ctru_sys::CAMU_GetTransferBytes(
@ -336,8 +312,8 @@ pub trait Camera {
} }
} }
/// Sets trimming parameters based on coordinates specified inside a [CamTrimmingParams] /// Sets trimming parameters based on coordinates specified inside a [TrimmingParams]
fn set_trimming_params(&mut self, params: CamTrimmingParams) -> crate::Result<()> { fn set_trimming_params(&mut self, params: TrimmingParams) -> crate::Result<()> {
unsafe { unsafe {
ResultCode(ctru_sys::CAMU_SetTrimmingParams( ResultCode(ctru_sys::CAMU_SetTrimmingParams(
self.port_as_raw(), self.port_as_raw(),
@ -350,8 +326,8 @@ pub trait Camera {
} }
} }
/// Returns the set [CamTrimmingParams] from the camera /// Returns the [TrimmingParams] set
fn get_trimming_params(&self) -> crate::Result<CamTrimmingParams> { fn trimming_params(&self) -> crate::Result<TrimmingParams> {
unsafe { unsafe {
let mut x_start = 0; let mut x_start = 0;
let mut y_start = 0; let mut y_start = 0;
@ -365,7 +341,7 @@ pub trait Camera {
self.port_as_raw(), self.port_as_raw(),
))?; ))?;
Ok(CamTrimmingParams { Ok(TrimmingParams {
x_start, x_start,
y_start, y_start,
x_end, x_end,
@ -404,27 +380,27 @@ pub trait Camera {
} }
} }
/// Sets the white balance mod of the camera based on the passed [CamWhiteBalance] argument /// Sets the white balance mod of the camera based on the passed [WhiteBalance] argument
fn set_white_balance(&mut self, white_balance: CamWhiteBalance) -> crate::Result<()> { fn set_white_balance(&mut self, white_balance: WhiteBalance) -> crate::Result<()> {
unsafe { unsafe {
ResultCode(ctru_sys::CAMU_SetWhiteBalance( ResultCode(ctru_sys::CAMU_SetWhiteBalance(
self.camera_as_raw(), self.camera_as_raw(),
white_balance.bits(), white_balance.into(),
))?; ))?;
Ok(()) Ok(())
} }
} }
/// Sets the white balance mode of the camera based on the passed [CamWhiteBalance] argument /// Sets the white balance mode of the camera based on the passed [WhiteBalance] argument
// TODO: Explain base up // TODO: Explain base up
fn set_white_balance_without_base_up( fn set_white_balance_without_base_up(
&mut self, &mut self,
white_balance: CamWhiteBalance, white_balance: WhiteBalance,
) -> crate::Result<()> { ) -> crate::Result<()> {
unsafe { unsafe {
ResultCode(ctru_sys::CAMU_SetWhiteBalanceWithoutBaseUp( ResultCode(ctru_sys::CAMU_SetWhiteBalanceWithoutBaseUp(
self.camera_as_raw(), self.camera_as_raw(),
white_balance.bits(), white_balance.into(),
))?; ))?;
Ok(()) Ok(())
} }
@ -484,12 +460,12 @@ pub trait Camera {
} }
} }
/// Sets the flip direction of the camera's image based on the passed [CamFlip] argument /// Sets the flip direction of the camera's image based on the passed [FlipMode] argument
fn flip_image(&mut self, flip: CamFlip) -> crate::Result<()> { fn flip_image(&mut self, flip: FlipMode) -> crate::Result<()> {
unsafe { unsafe {
ResultCode(ctru_sys::CAMU_FlipImage( ResultCode(ctru_sys::CAMU_FlipImage(
self.camera_as_raw(), self.camera_as_raw(),
flip.bits(), flip.into(),
ctru_sys::CONTEXT_A, ctru_sys::CONTEXT_A,
))?; ))?;
Ok(()) Ok(())
@ -530,82 +506,82 @@ pub trait Camera {
} }
} }
/// Sets the view size of the camera based on the passed [CamSize] argument. /// Sets the view size of the camera based on the passed [ViewSize] argument.
fn set_view_size(&mut self, size: CamSize) -> crate::Result<()> { fn set_view_size(&mut self, size: ViewSize) -> crate::Result<()> {
unsafe { unsafe {
ResultCode(ctru_sys::CAMU_SetSize( ResultCode(ctru_sys::CAMU_SetSize(
self.camera_as_raw(), self.camera_as_raw(),
size.bits(), size.into(),
ctru_sys::CONTEXT_A, ctru_sys::CONTEXT_A,
))?; ))?;
Ok(()) Ok(())
} }
} }
/// Sets the frame rate of the camera based on the passed [CamFrameRate] argument. /// Sets the frame rate of the camera based on the passed [FrameRate] argument.
fn set_frame_rate(&mut self, frame_rate: CamFrameRate) -> crate::Result<()> { fn set_frame_rate(&mut self, frame_rate: FrameRate) -> crate::Result<()> {
unsafe { unsafe {
ResultCode(ctru_sys::CAMU_SetFrameRate( ResultCode(ctru_sys::CAMU_SetFrameRate(
self.camera_as_raw(), self.camera_as_raw(),
frame_rate.bits(), frame_rate.into(),
))?; ))?;
Ok(()) Ok(())
} }
} }
/// Sets the photo mode of the camera based on the passed [CamPhotoMode] argument. /// Sets the photo mode of the camera based on the passed [PhotoMode] argument.
fn set_photo_mode(&mut self, photo_mode: CamPhotoMode) -> crate::Result<()> { fn set_photo_mode(&mut self, photo_mode: PhotoMode) -> crate::Result<()> {
unsafe { unsafe {
ResultCode(ctru_sys::CAMU_SetPhotoMode( ResultCode(ctru_sys::CAMU_SetPhotoMode(
self.camera_as_raw(), self.camera_as_raw(),
photo_mode.bits(), photo_mode.into(),
))?; ))?;
Ok(()) Ok(())
} }
} }
/// Sets the effect of the camera based on the passed [CamEffect] 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 [CamEffect]
fn set_effect(&mut self, effect: CamEffect) -> crate::Result<()> { fn set_effect(&mut self, effect: Effect) -> crate::Result<()> {
unsafe { unsafe {
ResultCode(ctru_sys::CAMU_SetEffect( ResultCode(ctru_sys::CAMU_SetEffect(
self.camera_as_raw(), self.camera_as_raw(),
effect.bits(), effect.into(),
ctru_sys::CONTEXT_A, ctru_sys::CONTEXT_A,
))?; ))?;
Ok(()) Ok(())
} }
} }
/// Sets the contrast of the camera based on the passed [CamContrast] argument. /// Sets the contrast of the camera based on the passed [Contrast] argument.
fn set_contrast(&mut self, contrast: CamContrast) -> crate::Result<()> { fn set_contrast(&mut self, contrast: Contrast) -> crate::Result<()> {
unsafe { unsafe {
ResultCode(ctru_sys::CAMU_SetContrast( ResultCode(ctru_sys::CAMU_SetContrast(
self.camera_as_raw(), self.camera_as_raw(),
contrast.bits(), contrast.into(),
))?; ))?;
Ok(()) Ok(())
} }
} }
/// Sets the lens correction of the camera based on the passed [CamLensCorrection] argument. /// Sets the lens correction of the camera based on the passed [LensCorrection] argument.
fn set_lens_correction(&mut self, lens_correction: CamLensCorrection) -> crate::Result<()> { fn set_lens_correction(&mut self, lens_correction: LensCorrection) -> crate::Result<()> {
unsafe { unsafe {
ResultCode(ctru_sys::CAMU_SetLensCorrection( ResultCode(ctru_sys::CAMU_SetLensCorrection(
self.camera_as_raw(), self.camera_as_raw(),
lens_correction.bits(), lens_correction.into(),
))?; ))?;
Ok(()) Ok(())
} }
} }
/// Sets the output format of the camera based on the passed [CamOutputFormat] argument. /// Sets the output format of the camera based on the passed [OutputFormat] argument.
fn set_output_format(&mut self, format: CamOutputFormat) -> crate::Result<()> { fn set_output_format(&mut self, format: OutputFormat) -> crate::Result<()> {
unsafe { unsafe {
ResultCode(ctru_sys::CAMU_SetOutputFormat( ResultCode(ctru_sys::CAMU_SetOutputFormat(
self.camera_as_raw(), self.camera_as_raw(),
format.bits(), format.into(),
ctru_sys::CONTEXT_A, ctru_sys::CONTEXT_A,
))?; ))?;
Ok(()) Ok(())
@ -687,7 +663,7 @@ pub trait Camera {
} }
/// Returns the current [ImageQualityCalibrationData] for the camera /// Returns the current [ImageQualityCalibrationData] for the camera
fn get_image_quality_calibration_data(&self) -> crate::Result<ImageQualityCalibrationData> { fn image_quality_calibration_data(&self) -> crate::Result<ImageQualityCalibrationData> {
unsafe { unsafe {
let mut data = ImageQualityCalibrationData::default(); let mut data = ImageQualityCalibrationData::default();
ResultCode(ctru_sys::CAMU_GetImageQualityCalibrationData(&mut data.0))?; ResultCode(ctru_sys::CAMU_GetImageQualityCalibrationData(&mut data.0))?;
@ -806,10 +782,10 @@ impl Cam {
} }
} }
/// Plays the specified sound based on the [CamShutterSoundType] argument /// Plays the specified sound based on the [ShutterSound] argument
pub fn play_shutter_sound(&self, sound: CamShutterSoundType) -> crate::Result<()> { pub fn play_shutter_sound(&self, sound: ShutterSound) -> crate::Result<()> {
unsafe { unsafe {
ResultCode(ctru_sys::CAMU_PlayShutterSound(sound.bits()))?; ResultCode(ctru_sys::CAMU_PlayShutterSound(sound.into()))?;
Ok(()) Ok(())
} }
} }
@ -820,3 +796,14 @@ impl Drop for Cam {
unsafe { ctru_sys::camExit() }; unsafe { ctru_sys::camExit() };
} }
} }
from_impl!(FlipMode, ctru_sys::CAMU_Flip);
from_impl!(ViewSize, ctru_sys::CAMU_Size);
from_impl!(FrameRate, ctru_sys::CAMU_FrameRate);
from_impl!(WhiteBalance, ctru_sys::CAMU_WhiteBalance);
from_impl!(PhotoMode, ctru_sys::CAMU_PhotoMode);
from_impl!(Effect, ctru_sys::CAMU_Effect);
from_impl!(Contrast, ctru_sys::CAMU_Contrast);
from_impl!(LensCorrection, ctru_sys::CAMU_LensCorrection);
from_impl!(OutputFormat, ctru_sys::CAMU_OutputFormat);
from_impl!(ShutterSound, ctru_sys::CAMU_ShutterSoundType);

22
ctru-rs/src/services/cfgu.rs

@ -67,7 +67,7 @@ impl Cfgu {
} }
/// Gets system region from secure info /// Gets system region from secure info
pub fn get_region(&self) -> crate::Result<Region> { pub fn region(&self) -> crate::Result<Region> {
let mut region: u8 = 0; let mut region: u8 = 0;
ResultCode(unsafe { ctru_sys::CFGU_SecureInfoGetRegion(&mut region) })?; ResultCode(unsafe { ctru_sys::CFGU_SecureInfoGetRegion(&mut region) })?;
@ -75,7 +75,7 @@ impl Cfgu {
} }
/// Gets system's model /// Gets system's model
pub fn get_model(&self) -> crate::Result<SystemModel> { pub fn model(&self) -> crate::Result<SystemModel> {
let mut model: u8 = 0; let mut model: u8 = 0;
ResultCode(unsafe { ctru_sys::CFGU_GetSystemModel(&mut model) })?; ResultCode(unsafe { ctru_sys::CFGU_GetSystemModel(&mut model) })?;
@ -83,7 +83,7 @@ impl Cfgu {
} }
/// Gets system's language /// Gets system's language
pub fn get_language(&self) -> crate::Result<Language> { pub fn language(&self) -> crate::Result<Language> {
let mut language: u8 = 0; let mut language: u8 = 0;
ResultCode(unsafe { ctru_sys::CFGU_GetSystemLanguage(&mut language) })?; ResultCode(unsafe { ctru_sys::CFGU_GetSystemLanguage(&mut language) })?;
@ -115,19 +115,9 @@ impl Drop for Cfgu {
} }
} }
macro_rules! from_type_to_u8 { from_impl!(Region, u8);
($from_type:ty) => { from_impl!(Language, u8);
impl From<$from_type> for u8 { from_impl!(SystemModel, u8);
fn from(v: $from_type) -> Self {
v as u8
}
}
};
}
from_type_to_u8!(Region);
from_type_to_u8!(Language);
from_type_to_u8!(SystemModel);
impl TryFrom<u8> for Region { impl TryFrom<u8> for Region {
type Error = (); type Error = ();

109
ctru-rs/src/services/fs.rs

@ -1,7 +1,7 @@
//! Filesystem service //! Filesystem service
//! //!
//! This module contains basic methods to manipulate the contents of the 3DS's filesystem. //! This module contains basic methods to manipulate the contents of the 3DS's filesystem.
//! Only the SD card is currently supported. //! Only the SD card is currently supported. You should prefer using `std::fs`.
use bitflags::bitflags; use bitflags::bitflags;
use std::ffi::OsString; use std::ffi::OsString;
@ -52,38 +52,40 @@ pub enum FsMediaType {
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum PathType { pub enum PathType {
Invalid, Invalid = ctru_sys::PATH_INVALID,
Empty, Empty = ctru_sys::PATH_EMPTY,
Binary, Binary = ctru_sys::PATH_BINARY,
ASCII, ASCII = ctru_sys::PATH_ASCII,
UTF16, UTF16 = ctru_sys::PATH_UTF16,
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum ArchiveID { pub enum ArchiveID {
RomFS, RomFS = ctru_sys::ARCHIVE_ROMFS,
Savedata, Savedata = ctru_sys::ARCHIVE_SAVEDATA,
Extdata, Extdata = ctru_sys::ARCHIVE_EXTDATA,
SharedExtdata, SharedExtdata = ctru_sys::ARCHIVE_SHARED_EXTDATA,
SystemSavedata, SystemSavedata = ctru_sys::ARCHIVE_SYSTEM_SAVEDATA,
Sdmc, Sdmc = ctru_sys::ARCHIVE_SDMC,
SdmcWriteOnly, SdmcWriteOnly = ctru_sys::ARCHIVE_SDMC_WRITE_ONLY,
BossExtdata, BossExtdata = ctru_sys::ARCHIVE_BOSS_EXTDATA,
CardSpiFS, CardSpiFS = ctru_sys::ARCHIVE_CARD_SPIFS,
ExtDataAndBossExtdata, ExtDataAndBossExtdata = ctru_sys::ARCHIVE_EXTDATA_AND_BOSS_EXTDATA,
SystemSaveData2, SystemSaveData2 = ctru_sys::ARCHIVE_SYSTEM_SAVEDATA2,
NandRW, NandRW = ctru_sys::ARCHIVE_NAND_RW,
NandRO, NandRO = ctru_sys::ARCHIVE_NAND_RO,
NandROWriteAccess, NandROWriteAccess = ctru_sys::ARCHIVE_NAND_RO_WRITE_ACCESS,
SaveDataAndContent, SaveDataAndContent = ctru_sys::ARCHIVE_SAVEDATA_AND_CONTENT,
SaveDataAndContent2, SaveDataAndContent2 = ctru_sys::ARCHIVE_SAVEDATA_AND_CONTENT2,
NandCtrFS, NandCtrFS = ctru_sys::ARCHIVE_NAND_CTR_FS,
TwlPhoto, TwlPhoto = ctru_sys::ARCHIVE_TWL_PHOTO,
NandTwlFS, NandTwlFS = ctru_sys::ARCHIVE_NAND_TWL_FS,
GameCardSavedata, GameCardSavedata = ctru_sys::ARCHIVE_GAMECARD_SAVEDATA,
UserSavedata, UserSavedata = ctru_sys::ARCHIVE_USER_SAVEDATA,
DemoSavedata, DemoSavedata = ctru_sys::ARCHIVE_DEMO_SAVEDATA,
} }
/// Represents the filesystem service. No file IO can be performed /// Represents the filesystem service. No file IO can be performed
@ -327,7 +329,7 @@ impl Archive {
/// Retrieves an Archive's [`ArchiveID`] /// Retrieves an Archive's [`ArchiveID`]
/// ///
/// [`ArchiveID`]: enum.ArchiveID.html /// [`ArchiveID`]: enum.ArchiveID.html
pub fn get_id(&self) -> ArchiveID { pub fn id(&self) -> ArchiveID {
self.id self.id
} }
} }
@ -587,7 +589,7 @@ impl OpenOptions {
/// ///
/// [`Archive`]: struct.Archive.html /// [`Archive`]: struct.Archive.html
pub fn open<P: AsRef<Path>>(&self, path: P) -> IoResult<File> { pub fn open<P: AsRef<Path>>(&self, path: P) -> IoResult<File> {
self._open(path.as_ref(), self.get_open_flags()) self._open(path.as_ref(), self.open_flags())
} }
fn _open(&self, path: &Path, flags: FsOpen) -> IoResult<File> { fn _open(&self, path: &Path, flags: FsOpen) -> IoResult<File> {
@ -626,7 +628,7 @@ impl OpenOptions {
} }
} }
fn get_open_flags(&self) -> FsOpen { fn open_flags(&self) -> FsOpen {
match (self.read, self.write || self.append, self.create) { match (self.read, self.write || self.append, self.create) {
(true, false, false) => FsOpen::FS_OPEN_READ, (true, false, false) => FsOpen::FS_OPEN_READ,
(false, true, false) => FsOpen::FS_OPEN_WRITE, (false, true, false) => FsOpen::FS_OPEN_WRITE,
@ -1016,45 +1018,6 @@ impl Drop for Dir {
} }
} }
impl From<PathType> for ctru_sys::FS_PathType { from_impl!(FsMediaType, ctru_sys::FS_MediaType);
fn from(p: PathType) -> Self { from_impl!(PathType, ctru_sys::FS_PathType);
use self::PathType::*; from_impl!(ArchiveID, ctru_sys::FS_ArchiveID);
match p {
Invalid => ctru_sys::PATH_INVALID,
Empty => ctru_sys::PATH_EMPTY,
Binary => ctru_sys::PATH_BINARY,
ASCII => ctru_sys::PATH_ASCII,
UTF16 => ctru_sys::PATH_UTF16,
}
}
}
impl From<ArchiveID> for ctru_sys::FS_ArchiveID {
fn from(a: ArchiveID) -> Self {
use self::ArchiveID::*;
match a {
RomFS => ctru_sys::ARCHIVE_ROMFS,
Savedata => ctru_sys::ARCHIVE_SAVEDATA,
Extdata => ctru_sys::ARCHIVE_EXTDATA,
SharedExtdata => ctru_sys::ARCHIVE_SHARED_EXTDATA,
SystemSavedata => ctru_sys::ARCHIVE_SYSTEM_SAVEDATA,
Sdmc => ctru_sys::ARCHIVE_SDMC,
SdmcWriteOnly => ctru_sys::ARCHIVE_SDMC_WRITE_ONLY,
BossExtdata => ctru_sys::ARCHIVE_BOSS_EXTDATA,
CardSpiFS => ctru_sys::ARCHIVE_CARD_SPIFS,
ExtDataAndBossExtdata => ctru_sys::ARCHIVE_EXTDATA_AND_BOSS_EXTDATA,
SystemSaveData2 => ctru_sys::ARCHIVE_SYSTEM_SAVEDATA2,
NandRW => ctru_sys::ARCHIVE_NAND_RW,
NandRO => ctru_sys::ARCHIVE_NAND_RO,
NandROWriteAccess => ctru_sys::ARCHIVE_NAND_RO_WRITE_ACCESS,
SaveDataAndContent => ctru_sys::ARCHIVE_SAVEDATA_AND_CONTENT,
SaveDataAndContent2 => ctru_sys::ARCHIVE_SAVEDATA_AND_CONTENT2,
NandCtrFS => ctru_sys::ARCHIVE_NAND_CTR_FS,
TwlPhoto => ctru_sys::ARCHIVE_TWL_PHOTO,
NandTwlFS => ctru_sys::ARCHIVE_NAND_TWL_FS,
GameCardSavedata => ctru_sys::ARCHIVE_GAMECARD_SAVEDATA,
UserSavedata => ctru_sys::ARCHIVE_USER_SAVEDATA,
DemoSavedata => ctru_sys::ARCHIVE_DEMO_SAVEDATA,
}
}
}

22
ctru-rs/src/gfx.rs → ctru-rs/src/services/gfx.rs

@ -33,7 +33,7 @@ pub trait Screen: private::Sealed {
/// ///
/// Note that the pointer of the framebuffer returned by this function can /// Note that the pointer of the framebuffer returned by this function can
/// change after each call to this function if double buffering is enabled. /// change after each call to this function if double buffering is enabled.
fn get_raw_framebuffer(&mut self) -> RawFrameBuffer { fn raw_framebuffer(&mut self) -> RawFrameBuffer {
let mut width = 0; let mut width = 0;
let mut height = 0; let mut height = 0;
let ptr = unsafe { let ptr = unsafe {
@ -56,8 +56,8 @@ pub trait Screen: private::Sealed {
} }
/// Gets the framebuffer format /// Gets the framebuffer format
fn get_framebuffer_format(&self) -> FramebufferFormat { fn framebuffer_format(&self) -> FramebufferFormat {
unsafe { ctru_sys::gfxGetScreenFormat(self.as_raw()).into() } unsafe { ctru_sys::gfxGetScreenFormat(self.as_raw()) }.into()
} }
/// Change the framebuffer format /// Change the framebuffer format
@ -104,14 +104,15 @@ pub struct RawFrameBuffer<'screen> {
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[repr(u32)]
/// Side of top screen framebuffer /// Side of top screen framebuffer
/// ///
/// The top screen of the 3DS can have two separate sets of framebuffers to support its 3D functionality /// The top screen of the 3DS can have two separate sets of framebuffers to support its 3D functionality
pub enum Side { pub enum Side {
/// The left framebuffer. This framebuffer is also the one used when 3D is disabled /// The left framebuffer. This framebuffer is also the one used when 3D is disabled
Left, Left = ctru_sys::GFX_LEFT,
/// The right framebuffer /// The right framebuffer
Right, Right = ctru_sys::GFX_RIGHT,
} }
/// A handle to libctru's gfx module. This module is a wrapper around the GSPGPU service that /// A handle to libctru's gfx module. This module is a wrapper around the GSPGPU service that
@ -238,7 +239,7 @@ impl TopScreen {
} }
/// Returns whether or not wide mode is enabled on the top screen. /// Returns whether or not wide mode is enabled on the top screen.
pub fn get_wide_mode(&self) -> bool { pub fn is_wide(&self) -> bool {
unsafe { ctru_sys::gfxIsWide() } unsafe { ctru_sys::gfxIsWide() }
} }
} }
@ -283,14 +284,7 @@ impl Screen for BottomScreen {
} }
} }
impl From<Side> for ctru_sys::gfx3dSide_t { from_impl!(Side, ctru_sys::gfx3dSide_t);
fn from(s: Side) -> ctru_sys::gfx3dSide_t {
match s {
Side::Left => ctru_sys::GFX_LEFT,
Side::Right => ctru_sys::GFX_RIGHT,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

59
ctru-rs/src/services/gspgpu.rs

@ -1,31 +1,31 @@
//! GSPGPU service //! GSPGPU service
use std::convert::From;
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum Event { pub enum Event {
Psc0, Psc0 = ctru_sys::GSPGPU_EVENT_PSC0,
Psc1, Psc1 = ctru_sys::GSPGPU_EVENT_PSC1,
VBlank0, VBlank0 = ctru_sys::GSPGPU_EVENT_VBlank0,
VBlank1, VBlank1 = ctru_sys::GSPGPU_EVENT_VBlank1,
PPF, PPF = ctru_sys::GSPGPU_EVENT_PPF,
P3D, P3D = ctru_sys::GSPGPU_EVENT_P3D,
DMA, DMA = ctru_sys::GSPGPU_EVENT_DMA,
} }
/// The different framebuffer formats supported by the 3DS /// Framebuffer formats supported by the 3DS
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum FramebufferFormat { pub enum FramebufferFormat {
/// RGBA8. 4 bytes per pixel /// RGBA8. 4 bytes per pixel
Rgba8, Rgba8 = ctru_sys::GSP_RGBA8_OES,
/// BGR8. 3 bytes per pixel /// BGR8. 3 bytes per pixel
Bgr8, Bgr8 = ctru_sys::GSP_BGR8_OES,
/// RGB565. 2 bytes per pixel /// RGB565. 2 bytes per pixel
Rgb565, Rgb565 = ctru_sys::GSP_RGB565_OES,
/// RGB5A1. 2 bytes per pixel /// RGB5A1. 2 bytes per pixel
Rgb5A1, Rgb5A1 = ctru_sys::GSP_RGB5_A1_OES,
/// RGBA4. 2 bytes per pixel /// RGBA4. 2 bytes per pixel
Rgba4, Rgba4 = ctru_sys::GSP_RGBA4_OES,
} }
impl FramebufferFormat { impl FramebufferFormat {
@ -65,30 +65,5 @@ impl From<ctru_sys::GSPGPU_FramebufferFormat> for FramebufferFormat {
} }
} }
impl From<FramebufferFormat> for ctru_sys::GSPGPU_FramebufferFormat { from_impl!(FramebufferFormat, ctru_sys::GSPGPU_FramebufferFormat);
fn from(g: FramebufferFormat) -> Self { from_impl!(Event, ctru_sys::GSPGPU_Event);
use self::FramebufferFormat::*;
match g {
Rgba8 => ctru_sys::GSP_RGBA8_OES,
Bgr8 => ctru_sys::GSP_BGR8_OES,
Rgb565 => ctru_sys::GSP_RGB565_OES,
Rgb5A1 => ctru_sys::GSP_RGB5_A1_OES,
Rgba4 => ctru_sys::GSP_RGBA4_OES,
}
}
}
impl From<Event> for ctru_sys::GSPGPU_Event {
fn from(ev: Event) -> Self {
use self::Event::*;
match ev {
Psc0 => ctru_sys::GSPGPU_EVENT_PSC0,
Psc1 => ctru_sys::GSPGPU_EVENT_PSC1,
VBlank0 => ctru_sys::GSPGPU_EVENT_VBlank0,
VBlank1 => ctru_sys::GSPGPU_EVENT_VBlank1,
PPF => ctru_sys::GSPGPU_EVENT_PPF,
P3D => ctru_sys::GSPGPU_EVENT_P3D,
DMA => ctru_sys::GSPGPU_EVENT_DMA,
}
}
}

56
ctru-rs/src/services/hid.rs

@ -10,34 +10,34 @@ bitflags::bitflags! {
/// inputs on the 3DS /// inputs on the 3DS
#[derive(Default)] #[derive(Default)]
pub struct KeyPad: u32 { pub struct KeyPad: u32 {
const KEY_A = 1u32 << 0; const A = ctru_sys::KEY_A;
const KEY_B = 1u32 << 1; const B = ctru_sys::KEY_B;
const KEY_SELECT = 1u32 << 2; const SELECT = ctru_sys::KEY_SELECT;
const KEY_START = 1u32 << 3; const START = ctru_sys::KEY_START;
const KEY_DRIGHT = 1u32 << 4; const DRIGHT = ctru_sys::KEY_DRIGHT;
const KEY_DLEFT = 1u32 << 5; const DLEFT = ctru_sys::KEY_DLEFT;
const KEY_DUP = 1u32 << 6; const DUP = ctru_sys::KEY_DUP;
const KEY_DDOWN = 1u32 << 7; const DDOWN = ctru_sys::KEY_DDOWN;
const KEY_R = 1u32 << 8; const R = ctru_sys::KEY_R;
const KEY_L = 1u32 << 9; const L = ctru_sys::KEY_L;
const KEY_X = 1u32 << 10; const X = ctru_sys::KEY_X;
const KEY_Y = 1u32 << 11; const Y = ctru_sys::KEY_Y;
const KEY_ZL = 1u32 << 14; const ZL = ctru_sys::KEY_ZL;
const KEY_ZR = 1u32 << 15; const ZR = ctru_sys::KEY_ZR;
const KEY_TOUCH = 1u32 << 20; const TOUCH = ctru_sys::KEY_TOUCH;
const KEY_CSTICK_RIGHT = 1u32 << 24; const CSTICK_RIGHT = ctru_sys::KEY_CSTICK_RIGHT;
const KEY_CSTICK_LEFT = 1u32 << 25; const CSTICK_LEFT = ctru_sys::KEY_CSTICK_LEFT;
const KEY_CSTICK_UP = 1u32 << 26; const CSTICK_UP = ctru_sys::KEY_CSTICK_UP;
const KEY_CSTICK_DOWN = 1u32 << 27; const CSTICK_DOWN = ctru_sys::KEY_CSTICK_DOWN;
const KEY_CPAD_RIGHT = 1u32 << 28; const CPAD_RIGHT = ctru_sys::KEY_CPAD_RIGHT;
const KEY_CPAD_LEFT = 1u32 << 29; const CPAD_LEFT = ctru_sys::KEY_CPAD_LEFT;
const KEY_CPAD_UP = 1u32 << 30; const CPAD_UP = ctru_sys::KEY_CPAD_UP;
const KEY_CPAD_DOWN = 1u32 << 31; const CPAD_DOWN = ctru_sys::KEY_CPAD_DOWN;
// convenience catch-all for the dpad and cpad // Convenience catch-all for the dpad and cpad
const KEY_UP = KeyPad::KEY_DUP.bits | KeyPad::KEY_CPAD_UP.bits; const UP = KeyPad::DUP.bits() | KeyPad::CPAD_UP.bits();
const KEY_DOWN = KeyPad::KEY_DDOWN.bits | KeyPad::KEY_CPAD_DOWN.bits; const DOWN = KeyPad::DDOWN.bits() | KeyPad::CPAD_DOWN.bits();
const KEY_LEFT = KeyPad::KEY_DLEFT.bits | KeyPad::KEY_CPAD_LEFT.bits; const LEFT = KeyPad::DLEFT.bits() | KeyPad::CPAD_LEFT.bits();
const KEY_RIGHT = KeyPad::KEY_DRIGHT.bits | KeyPad::KEY_CPAD_RIGHT.bits; const RIGHT = KeyPad::DRIGHT.bits() | KeyPad::CPAD_RIGHT.bits();
} }
} }

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

@ -10,6 +10,7 @@ pub mod apt;
pub mod cam; pub mod cam;
pub mod cfgu; pub mod cfgu;
pub mod fs; pub mod fs;
pub mod gfx;
pub mod gspgpu; pub mod gspgpu;
pub mod hid; pub mod hid;
pub mod ndsp; pub mod ndsp;
@ -18,6 +19,25 @@ mod reference;
pub mod soc; pub mod soc;
pub mod sslc; pub mod sslc;
cfg_if::cfg_if! {
if #[cfg(all(feature = "romfs", romfs_exists))] {
pub mod romfs;
} else {
pub mod romfs {
//! The RomFS folder has not been detected and/or the `romfs` feature has not been enabled.
//!
//! Configure the path in Cargo.toml (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.
//!
//! ```toml
//! [package.metadata.cargo-3ds]
//! romfs_dir = "romfs"
//! ```
}
}
}
pub use self::apt::Apt; pub use self::apt::Apt;
pub use self::hid::Hid; pub use self::hid::Hid;

10
ctru-rs/src/services/ndsp/mod.rs

@ -122,7 +122,7 @@ impl Ndsp {
/// Set the audio output mode. Defaults to `OutputMode::Stereo`. /// Set the audio output mode. Defaults to `OutputMode::Stereo`.
pub fn set_output_mode(&mut self, mode: OutputMode) { pub fn set_output_mode(&mut self, mode: OutputMode) {
unsafe { ctru_sys::ndspSetOutputMode(mode as u32) }; unsafe { ctru_sys::ndspSetOutputMode(mode.into()) };
} }
} }
@ -172,12 +172,12 @@ impl Channel<'_> {
/// Set the channel's output format. /// Set the channel's output format.
/// Change this setting based on the used sample's format. /// Change this setting based on the used sample's format.
pub fn set_format(&self, format: AudioFormat) { pub fn set_format(&self, format: AudioFormat) {
unsafe { ctru_sys::ndspChnSetFormat(self.id.into(), format as u16) }; unsafe { ctru_sys::ndspChnSetFormat(self.id.into(), format.into()) };
} }
/// Set the channel's interpolation mode. /// Set the channel's interpolation mode.
pub fn set_interpolation(&self, interp_type: InterpolationType) { pub fn set_interpolation(&self, interp_type: InterpolationType) {
unsafe { ctru_sys::ndspChnSetInterp(self.id.into(), interp_type as u32) }; unsafe { ctru_sys::ndspChnSetInterp(self.id.into(), interp_type.into()) };
} }
/// Set the channel's volume mix. /// Set the channel's volume mix.
@ -454,3 +454,7 @@ impl Drop for Ndsp {
} }
} }
} }
from_impl!(InterpolationType, ctru_sys::ndspInterpType);
from_impl!(OutputMode, ctru_sys::ndspOutputMode);
from_impl!(AudioFormat, u16);

35
ctru-rs/src/services/ps.rs

@ -8,26 +8,26 @@ use crate::Result;
#[repr(u32)] #[repr(u32)]
pub enum AESAlgorithm { pub enum AESAlgorithm {
CbcEnc, CbcEnc = ctru_sys::PS_ALGORITHM_CBC_ENC,
CbcDec, CbcDec = ctru_sys::PS_ALGORITHM_CBC_DEC,
CtrEnc, CtrEnc = ctru_sys::PS_ALGORITHM_CTR_ENC,
CtrDec, CtrDec = ctru_sys::PS_ALGORITHM_CTR_DEC,
CcmEnc, CcmEnc = ctru_sys::PS_ALGORITHM_CCM_ENC,
CcmDec, CcmDec = ctru_sys::PS_ALGORITHM_CCM_DEC,
} }
#[repr(u32)] #[repr(u32)]
pub enum AESKeyType { pub enum AESKeyType {
Keyslot0D, Keyslot0D = ctru_sys::PS_KEYSLOT_0D,
Keyslot2D, Keyslot2D = ctru_sys::PS_KEYSLOT_2D,
Keyslot31, Keyslot2E = ctru_sys::PS_KEYSLOT_2E,
Keyslot38, Keyslot31 = ctru_sys::PS_KEYSLOT_31,
Keyslot32, Keyslot32 = ctru_sys::PS_KEYSLOT_32,
Keyslot39Dlp, Keyslot36 = ctru_sys::PS_KEYSLOT_36,
Keyslot2E, Keyslot38 = ctru_sys::PS_KEYSLOT_38,
KeyslotInvalid, Keyslot39Dlp = ctru_sys::PS_KEYSLOT_39_DLP,
Keyslot36, Keyslot39Nfc = ctru_sys::PS_KEYSLOT_39_NFC,
Keyslot39Nfc, KeyslotInvalid = ctru_sys::PS_KEYSLOT_INVALID,
} }
pub struct Ps(()); pub struct Ps(());
@ -70,6 +70,9 @@ impl Drop for Ps {
} }
} }
from_impl!(AESAlgorithm, ctru_sys::PS_AESAlgorithm);
from_impl!(AESKeyType, ctru_sys::PS_AESKeyType);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::collections::HashMap; use std::collections::HashMap;

2
ctru-rs/src/romfs.rs → ctru-rs/src/services/romfs.rs

@ -1,3 +1,5 @@
//! Read-Only Memory FileSystem
//!
//! This module only gets compiled if the configured RomFS directory is found and the `romfs` //! This module only gets compiled if the configured RomFS directory is found and the `romfs`
//! feature is enabled. //! feature is enabled.
//! //!

8
ctru-rs/src/services/soc.rs

@ -1,3 +1,5 @@
//! Network Socket
use libc::memalign; use libc::memalign;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use std::sync::Mutex; use std::sync::Mutex;
@ -6,8 +8,10 @@ use crate::error::ResultCode;
use crate::services::ServiceReference; use crate::services::ServiceReference;
use crate::Error; use crate::Error;
/// Soc service. Initializing this service will enable the use of network sockets and utilities /// Network socket service
/// such as those found in `std::net`. The service will be closed when this struct is is dropped. ///
/// 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.
pub struct Soc { pub struct Soc {
_service_handler: ServiceReference, _service_handler: ServiceReference,
sock_3dslink: libc::c_int, sock_3dslink: libc::c_int,

4
ctru-rs/src/services/sslc.rs

@ -1,3 +1,5 @@
//! SSLC (TLS) service
// TODO: Implement remaining functions // TODO: Implement remaining functions
use crate::error::ResultCode; use crate::error::ResultCode;
@ -5,7 +7,7 @@ use crate::error::ResultCode;
pub struct SslC(()); pub struct SslC(());
impl SslC { impl SslC {
/// Initialize sslc /// Initialize the service
pub fn init() -> crate::Result<Self> { pub fn init() -> crate::Result<Self> {
unsafe { unsafe {
ResultCode(ctru_sys::sslcInit(0))?; ResultCode(ctru_sys::sslcInit(0))?;

7
ctru-rs/src/test_runner.rs

@ -6,10 +6,7 @@ use std::io;
use test::{ColorConfig, OutputFormat, TestDescAndFn, TestFn, TestOpts}; use test::{ColorConfig, OutputFormat, TestDescAndFn, TestFn, TestOpts};
use crate::console::Console; use crate::prelude::*;
use crate::gfx::Gfx;
use crate::services::hid::{Hid, KeyPad};
use crate::services::Apt;
/// A custom runner to be used with `#[test_runner]`. This simple implementation /// A custom runner to be used with `#[test_runner]`. This simple implementation
/// runs all tests in series, "failing" on the first one to panic (really, the /// runs all tests in series, "failing" on the first one to panic (really, the
@ -47,7 +44,7 @@ pub(crate) fn run(tests: &[&TestDescAndFn]) {
gfx.wait_for_vblank(); gfx.wait_for_vblank();
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::START) {
break; break;
} }
} }

Loading…
Cancel
Save