Browse Source

Merge pull request #50 from Meziu/fix/duplicate-services

Fixed duplicate services and constistency in naming
pull/54/head
Meziu 3 years ago committed by GitHub
parent
commit
cdc96d2eeb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      ctru-rs/Cargo.toml
  2. 2
      ctru-rs/examples/buttons.rs
  3. 4
      ctru-rs/examples/file-explorer.rs
  4. 2
      ctru-rs/examples/futures-basic.rs
  5. 2
      ctru-rs/examples/futures-tokio.rs
  6. 2
      ctru-rs/examples/gfx-wide-mode.rs
  7. 2
      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/network-sockets.rs
  12. 4
      ctru-rs/examples/romfs.rs
  13. 2
      ctru-rs/examples/software-keyboard.rs
  14. 2
      ctru-rs/examples/thread-basic.rs
  15. 2
      ctru-rs/examples/thread-locals.rs
  16. 2
      ctru-rs/examples/time-rtc.rs
  17. 3
      ctru-rs/src/error.rs
  18. 56
      ctru-rs/src/gfx.rs
  19. 16
      ctru-rs/src/lib.rs
  20. 55
      ctru-rs/src/romfs.rs
  21. 3
      ctru-rs/src/services/mod.rs
  22. 44
      ctru-rs/src/services/reference.rs
  23. 63
      ctru-rs/src/services/soc.rs
  24. 2
      ctru-rs/src/test_runner.rs

1
ctru-rs/Cargo.toml

@ -19,6 +19,7 @@ pthread-3ds = { git = "https://github.com/Meziu/pthread-3ds.git" } @@ -19,6 +19,7 @@ pthread-3ds = { git = "https://github.com/Meziu/pthread-3ds.git" }
libc = "0.2.116"
bitflags = "1.0.0"
widestring = "0.2.2"
once_cell = "1.10.0"
[build-dependencies]
toml = "0.5"

2
ctru-rs/examples/buttons.rs

@ -8,7 +8,7 @@ fn main() { @@ -8,7 +8,7 @@ fn main() {
ctru::init();
let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap();
let gfx = Gfx::default();
let gfx = Gfx::init().unwrap();
let console = Console::init(gfx.top_screen.borrow_mut());
println!("Hi there! Try pressing a button");

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

@ -14,10 +14,10 @@ fn main() { @@ -14,10 +14,10 @@ fn main() {
ctru::init();
let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap();
let gfx = Gfx::default();
let gfx = Gfx::init().unwrap();
#[cfg(all(feature = "romfs", romfs_exists))]
let _romfs = ctru::romfs::RomFS::new().unwrap();
let _romfs = ctru::romfs::RomFS::init().unwrap();
FileExplorer::init(&apt, &hid, &gfx).run();
}

2
ctru-rs/examples/futures-basic.rs

@ -16,7 +16,7 @@ use std::os::horizon::thread::BuilderExt; @@ -16,7 +16,7 @@ use std::os::horizon::thread::BuilderExt;
fn main() {
ctru::init();
let gfx = Gfx::default();
let gfx = Gfx::init().expect("Couldn't obtain GFX controller");
let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller");
let _console = Console::init(gfx.top_screen.borrow_mut());

2
ctru-rs/examples/futures-tokio.rs

@ -9,7 +9,7 @@ use std::time::Duration; @@ -9,7 +9,7 @@ use std::time::Duration;
fn main() {
ctru::init();
let gfx = Gfx::default();
let gfx = Gfx::init().expect("Couldn't obtain GFX controller");
let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller");
let _console = Console::init(gfx.top_screen.borrow_mut());

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

@ -7,7 +7,7 @@ fn main() { @@ -7,7 +7,7 @@ fn main() {
ctru::init();
let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap();
let gfx = Gfx::default();
let gfx = Gfx::init().unwrap();
let mut console = Console::init(gfx.top_screen.borrow_mut());
println!("Press A to enable/disable wide screen mode.");

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

@ -19,7 +19,7 @@ static IMAGE: &[u8] = include_bytes!("assets/ferris.rgb"); @@ -19,7 +19,7 @@ static IMAGE: &[u8] = include_bytes!("assets/ferris.rgb");
fn main() {
ctru::init();
let gfx = Gfx::default();
let gfx = Gfx::init().expect("Couldn't obtain GFX controller");
let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller");
let _console = Console::init(gfx.top_screen.borrow_mut());

2
ctru-rs/examples/hashmaps.rs

@ -12,7 +12,7 @@ fn main() { @@ -12,7 +12,7 @@ fn main() {
ctru::init();
let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap();
let gfx = Gfx::default();
let gfx = Gfx::init().unwrap();
let _console = Console::init(gfx.top_screen.borrow_mut());
let mut map = std::collections::HashMap::new();

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

@ -8,7 +8,7 @@ fn main() { @@ -8,7 +8,7 @@ fn main() {
ctru::init();
let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap();
let gfx = Gfx::default();
let gfx = Gfx::init().unwrap();
// Start a console on the top screen
let top_screen = Console::init(gfx.top_screen.borrow_mut());

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

@ -7,7 +7,7 @@ use std::io::BufWriter; @@ -7,7 +7,7 @@ use std::io::BufWriter;
fn main() {
ctru::init();
let gfx = Gfx::default();
let gfx = Gfx::init().expect("Couldn't obtain GFX controller");
let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller");
let _console = Console::init(gfx.top_screen.borrow_mut());

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

@ -10,7 +10,7 @@ use std::time::Duration; @@ -10,7 +10,7 @@ use std::time::Duration;
fn main() {
ctru::init();
let gfx = Gfx::default();
let gfx = Gfx::init().unwrap();
let _console = Console::init(gfx.top_screen.borrow_mut());
let hid = Hid::init().unwrap();
let apt = Apt::init().unwrap();

4
ctru-rs/examples/romfs.rs

@ -5,7 +5,7 @@ use ctru::services::hid::{Hid, KeyPad}; @@ -5,7 +5,7 @@ use ctru::services::hid::{Hid, KeyPad};
fn main() {
ctru::init();
let gfx = Gfx::default();
let gfx = Gfx::init().expect("Couldn't obtain GFX controller");
let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller");
let _console = Console::init(gfx.top_screen.borrow_mut());
@ -15,7 +15,7 @@ fn main() { @@ -15,7 +15,7 @@ fn main() {
// 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
if #[cfg(all(feature = "romfs", romfs_exists))] {
let _romfs = ctru::romfs::RomFS::new().unwrap();
let _romfs = ctru::romfs::RomFS::init().unwrap();
let f = std::fs::read_to_string("romfs:/test-file.txt").unwrap();
println!("Contents of test-file.txt: \n{f}\n");

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

@ -8,7 +8,7 @@ fn main() { @@ -8,7 +8,7 @@ fn main() {
ctru::init();
let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap();
let gfx = Gfx::default();
let gfx = Gfx::init().unwrap();
let _console = Console::init(gfx.top_screen.borrow_mut());
println!("Press A to enter some text or press Start to quit");

2
ctru-rs/examples/thread-basic.rs

@ -12,7 +12,7 @@ fn main() { @@ -12,7 +12,7 @@ fn main() {
ctru::init();
let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap();
let gfx = Gfx::default();
let gfx = Gfx::init().unwrap();
let _console = Console::init(gfx.top_screen.borrow_mut());
let prio = std::os::horizon::thread::current_priority();

2
ctru-rs/examples/thread-locals.rs

@ -13,7 +13,7 @@ std::thread_local! { @@ -13,7 +13,7 @@ std::thread_local! {
fn main() {
ctru::init();
let gfx = Gfx::default();
let gfx = Gfx::init().expect("Couldn't obtain GFX controller");
gfx.top_screen.borrow_mut().set_wide_mode(true);
let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller");

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

@ -6,7 +6,7 @@ use ctru::services::hid::{Hid, KeyPad}; @@ -6,7 +6,7 @@ use ctru::services::hid::{Hid, KeyPad};
fn main() {
ctru::init();
let gfx = Gfx::default();
let gfx = Gfx::init().expect("Couldn't obtain GFX controller");
let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller");

3
ctru-rs/src/error.rs

@ -9,6 +9,7 @@ pub type Result<T> = ::std::result::Result<T, Error>; @@ -9,6 +9,7 @@ pub type Result<T> = ::std::result::Result<T, Error>;
#[non_exhaustive]
pub enum Error {
Os(ctru_sys::Result),
ServiceAlreadyActive,
}
impl From<ctru_sys::Result> for Error {
@ -28,6 +29,7 @@ impl fmt::Debug for Error { @@ -28,6 +29,7 @@ impl fmt::Debug for Error {
.field("summary", &R_SUMMARY(err))
.field("level", &R_LEVEL(err))
.finish(),
Error::ServiceAlreadyActive => f.debug_tuple("ServiceAlreadyActive").finish(),
}
}
}
@ -39,6 +41,7 @@ impl fmt::Display for Error { @@ -39,6 +41,7 @@ impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Os(err) => write!(f, "libctru result code: 0x{:08X}", err),
Error::ServiceAlreadyActive => write!(f, "Service already active"),
}
}
}

56
ctru-rs/src/gfx.rs

@ -1,11 +1,13 @@ @@ -1,11 +1,13 @@
//! LCD screens manipulation helper
use once_cell::sync::Lazy;
use std::cell::RefCell;
use std::default::Default;
use std::marker::PhantomData;
use std::ops::Drop;
use std::sync::Mutex;
use crate::error::Result;
use crate::services::gspgpu::{self, FramebufferFormat};
use crate::services::ServiceReference;
/// Trait implemented by TopScreen and BottomScreen for common methods
pub trait Screen {
@ -71,25 +73,43 @@ pub enum Side { @@ -71,25 +73,43 @@ pub enum Side {
pub struct Gfx {
pub top_screen: RefCell<TopScreen>,
pub bottom_screen: RefCell<BottomScreen>,
_service_handler: ServiceReference,
}
static GFX_ACTIVE: Lazy<Mutex<usize>> = Lazy::new(|| Mutex::new(0));
impl Gfx {
/// Initialize the Gfx module with the chosen framebuffer formats for the top and bottom
/// screens
///
/// Use `Gfx::default()` instead of this function to initialize the module with default parameters
pub fn new(
/// Use `Gfx::init()` instead of this function to initialize the module with default parameters
pub fn with_formats(
top_fb_fmt: FramebufferFormat,
bottom_fb_fmt: FramebufferFormat,
use_vram_buffers: bool,
) -> Self {
unsafe {
) -> Result<Self> {
let _service_handler = ServiceReference::new(
&GFX_ACTIVE,
false,
|| unsafe {
ctru_sys::gfxInit(top_fb_fmt.into(), bottom_fb_fmt.into(), use_vram_buffers);
}
Gfx {
Ok(())
},
|| unsafe { ctru_sys::gfxExit() },
)?;
Ok(Self {
top_screen: RefCell::new(TopScreen),
bottom_screen: RefCell::new(BottomScreen),
_service_handler,
})
}
/// Creates a new Gfx instance with default init values
/// It's the same as calling: `Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false)
pub fn init() -> Result<Self> {
Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false)
}
/// Flushes the current framebuffers
@ -197,18 +217,14 @@ impl From<Side> for ctru_sys::gfx3dSide_t { @@ -197,18 +217,14 @@ impl From<Side> for ctru_sys::gfx3dSide_t {
}
}
impl Default for Gfx {
fn default() -> Self {
unsafe { ctru_sys::gfxInitDefault() };
Gfx {
top_screen: RefCell::new(TopScreen),
bottom_screen: RefCell::new(BottomScreen),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Error;
impl Drop for Gfx {
fn drop(&mut self) {
unsafe { ctru_sys::gfxExit() };
#[test]
fn gfx_duplicate() {
// We don't need to build a `Gfx` because the test runner has one already
assert!(matches!(Gfx::init(), Err(Error::ServiceAlreadyActive)))
}
}

16
ctru-rs/src/lib.rs

@ -26,6 +26,13 @@ pub fn init() { @@ -26,6 +26,13 @@ pub fn init() {
libc::atexit(services_deinit);
}
#[cfg(not(test))]
panic_hook_setup();
}
#[cfg(not(test))]
fn panic_hook_setup() {
use crate::services::hid::{Hid, KeyPad};
use std::panic::PanicInfo;
let main_thread = std::thread::current().id();
@ -38,13 +45,16 @@ pub fn init() { @@ -38,13 +45,16 @@ pub fn init() {
// Only for panics in the main thread
if main_thread == std::thread::current().id() && console::Console::exists() {
println!("\nPress SELECT to exit the software");
let hid = services::hid::Hid::init().unwrap();
loop {
match Hid::init() {
Ok(hid) => loop {
hid.scan_input();
if hid.keys_down().contains(services::hid::KeyPad::KEY_SELECT) {
let keys = hid.keys_down();
if keys.contains(KeyPad::KEY_SELECT) {
break;
}
},
Err(e) => println!("Error while intializing Hid controller during panic: {e}"),
}
}
});

55
ctru-rs/src/romfs.rs

@ -10,27 +10,58 @@ @@ -10,27 +10,58 @@
//! romfs_dir = "romfs"
//! ```
use once_cell::sync::Lazy;
use std::ffi::CStr;
use std::sync::Mutex;
use crate::services::ServiceReference;
#[non_exhaustive]
pub struct RomFS;
pub struct RomFS {
_service_handler: ServiceReference,
}
static ROMFS_ACTIVE: Lazy<Mutex<usize>> = Lazy::new(|| Mutex::new(0));
impl RomFS {
pub fn new() -> crate::Result<Self> {
pub fn init() -> crate::Result<Self> {
let _service_handler = ServiceReference::new(
&ROMFS_ACTIVE,
true,
|| {
let mount_name = CStr::from_bytes_with_nul(b"romfs\0").unwrap();
let result = unsafe { ctru_sys::romfsMountSelf(mount_name.as_ptr()) };
if result < 0 {
Err(result.into())
} else {
Ok(Self)
}
}
let r = unsafe { ctru_sys::romfsMountSelf(mount_name.as_ptr()) };
if r < 0 {
return Err(r.into());
}
impl Drop for RomFS {
fn drop(&mut self) {
Ok(())
},
|| {
let mount_name = CStr::from_bytes_with_nul(b"romfs\0").unwrap();
unsafe { ctru_sys::romfsUnmount(mount_name.as_ptr()) };
},
)?;
Ok(Self { _service_handler })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn romfs_counter() {
let _romfs = RomFS::init().unwrap();
let value = *ROMFS_ACTIVE.lock().unwrap();
assert_eq!(value, 1);
drop(_romfs);
let value = *ROMFS_ACTIVE.lock().unwrap();
assert_eq!(value, 0);
}
}

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

@ -3,9 +3,12 @@ pub mod fs; @@ -3,9 +3,12 @@ pub mod fs;
pub mod gspgpu;
pub mod hid;
pub mod ps;
mod reference;
pub mod soc;
pub mod sslc;
pub use self::apt::Apt;
pub use self::hid::Hid;
pub use self::sslc::SslC;
pub(crate) use self::reference::ServiceReference;

44
ctru-rs/src/services/reference.rs

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
use crate::Error;
use std::sync::Mutex;
pub(crate) struct ServiceReference {
counter: &'static Mutex<usize>,
close: Box<dyn Fn() + Send + Sync>,
}
impl ServiceReference {
pub fn new<S, E>(
counter: &'static Mutex<usize>,
allow_multiple: bool,
start: S,
close: E,
) -> crate::Result<Self>
where
S: FnOnce() -> crate::Result<()>,
E: Fn() + Send + Sync + 'static,
{
let mut value = counter.lock().expect("Mutex Counter for ServiceReference is poisoned"); // todo: handle poisoning
if *value == 0 {
start()?;
} else if !allow_multiple {
return Err(Error::ServiceAlreadyActive);
}
*value += 1;
Ok(Self {
counter,
close: Box::new(close),
})
}
}
impl Drop for ServiceReference {
fn drop(&mut self) {
let mut value = self.counter.lock().expect("Mutex Counter for ServiceReference is poisoned"); // todo: handle poisoning
*value -= 1;
if *value == 0 {
(self.close)();
}
}
}

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

@ -1,21 +1,27 @@ @@ -1,21 +1,27 @@
use ctru_sys::{socExit, socInit};
use libc::{free, memalign};
use libc::memalign;
use once_cell::sync::Lazy;
use std::net::Ipv4Addr;
use std::sync::Mutex;
use crate::services::ServiceReference;
/// Soc service. Initializing this service will enable the use of network sockets and utilities
/// such as those found in `std::net`. The service will be closed when this struct is is dropped.
#[non_exhaustive]
pub struct Soc {
soc_mem: *mut u32,
_service_handler: ServiceReference,
}
static SOC_ACTIVE: Lazy<Mutex<usize>> = Lazy::new(|| Mutex::new(0));
impl Soc {
/// Initialize the Soc service with a default buffer size of 0x100000 bytes
///
/// # Errors
///
/// This function will return an error if the `Soc` service is already initialized
pub fn init() -> crate::Result<Soc> {
Soc::init_with_buffer_size(0x100000)
pub fn init() -> crate::Result<Self> {
Self::init_with_buffer_size(0x100000)
}
/// Initialize the Soc service with a custom buffer size in bytes. The size should be
@ -24,18 +30,29 @@ impl Soc { @@ -24,18 +30,29 @@ impl Soc {
/// # Errors
///
/// This function will return an error if the `Soc` service is already initialized
pub fn init_with_buffer_size(num_bytes: usize) -> crate::Result<Soc> {
unsafe {
let soc_mem = memalign(0x1000, num_bytes) as *mut u32;
let r = socInit(soc_mem, num_bytes as u32);
pub fn init_with_buffer_size(num_bytes: usize) -> crate::Result<Self> {
let _service_handler = ServiceReference::new(
&SOC_ACTIVE,
false,
|| {
let soc_mem = unsafe { memalign(0x1000, num_bytes) } as *mut u32;
let r = unsafe { ctru_sys::socInit(soc_mem, num_bytes as u32) };
if r < 0 {
free(soc_mem as *mut _);
Err(r.into())
} else {
Ok(Soc { soc_mem })
}
return Err(r.into());
}
Ok(())
},
// `socExit` returns an error code. There is no documentantion of when errors could happen,
// but we wouldn't be able to handle them in the `Drop` implementation anyways.
// Surely nothing bad will happens :D
|| unsafe {
// The socket buffer is freed automatically by `socExit`
ctru_sys::socExit();
},
)?;
Ok(Self { _service_handler })
}
/// IP Address of the Nintendo 3DS system.
@ -45,11 +62,15 @@ impl Soc { @@ -45,11 +62,15 @@ impl Soc {
}
}
impl Drop for Soc {
fn drop(&mut self) {
unsafe {
socExit();
free(self.soc_mem as *mut _);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Error;
#[test]
fn soc_duplicate() {
let _soc = Soc::init().unwrap();
assert!(matches!(Soc::init(), Err(Error::ServiceAlreadyActive)))
}
}

2
ctru-rs/src/test_runner.rs

@ -17,7 +17,7 @@ use crate::services::Apt; @@ -17,7 +17,7 @@ use crate::services::Apt;
pub(crate) fn run(tests: &[&TestDescAndFn]) {
crate::init();
let gfx = Gfx::default();
let gfx = Gfx::init().unwrap();
let hid = Hid::init().unwrap();
let apt = Apt::init().unwrap();

Loading…
Cancel
Save