AzureMarker
3 years ago
6 changed files with 202 additions and 0 deletions
@ -1,3 +1,6 @@ |
|||||||
target |
target |
||||||
Cargo.lock |
Cargo.lock |
||||||
.cargo |
.cargo |
||||||
|
|
||||||
|
# IDE files |
||||||
|
.idea |
||||||
|
@ -0,0 +1,73 @@ |
|||||||
|
//! This example runs a basic future executor from the `futures` library.
|
||||||
|
//! Every 60 frames (about 1 second) it prints "Tick" to the console.
|
||||||
|
//! The executor runs on a separate thread. Internally it yields when it has no more work to do,
|
||||||
|
//! allowing other threads to run.
|
||||||
|
//! The example also implements clean shutdown by using a oneshot channel to end the future, thus
|
||||||
|
//! ending the executor and the thread it runs on.
|
||||||
|
|
||||||
|
use ctru::console::Console; |
||||||
|
use ctru::services::hid::KeyPad; |
||||||
|
use ctru::services::{Apt, Hid}; |
||||||
|
use ctru::Gfx; |
||||||
|
use futures::StreamExt; |
||||||
|
|
||||||
|
fn main() { |
||||||
|
ctru::init(); |
||||||
|
let gfx = Gfx::default(); |
||||||
|
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()); |
||||||
|
|
||||||
|
// Give ourselves up to 30% of the system core's time
|
||||||
|
apt.set_app_cpu_time_limit(30) |
||||||
|
.expect("Failed to enable system core"); |
||||||
|
|
||||||
|
println!("Starting executor..."); |
||||||
|
|
||||||
|
let (exit_sender, mut exit_receiver) = futures::channel::oneshot::channel(); |
||||||
|
let (mut timer_sender, mut timer_receiver) = futures::channel::mpsc::channel(0); |
||||||
|
let executor_thread = ctru::thread::Builder::new() |
||||||
|
.affinity(1) |
||||||
|
.spawn(move || { |
||||||
|
let mut executor = futures::executor::LocalPool::new(); |
||||||
|
|
||||||
|
executor.run_until(async move { |
||||||
|
loop { |
||||||
|
futures::select! { |
||||||
|
_ = exit_receiver => break, |
||||||
|
_ = timer_receiver.next() => { |
||||||
|
println!("Tick"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
}) |
||||||
|
.expect("Failed to create executor thread"); |
||||||
|
|
||||||
|
println!("Executor started!"); |
||||||
|
|
||||||
|
let mut frame_count = 0; |
||||||
|
while apt.main_loop() { |
||||||
|
hid.scan_input(); |
||||||
|
|
||||||
|
if hid.keys_down().contains(KeyPad::KEY_START) { |
||||||
|
println!("Shutting down..."); |
||||||
|
let _ = exit_sender.send(()); |
||||||
|
let _ = executor_thread.join(); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
frame_count += 1; |
||||||
|
|
||||||
|
if frame_count == 60 { |
||||||
|
if let Err(e) = timer_sender.try_send(()) { |
||||||
|
println!("Error sending timer message: {e}"); |
||||||
|
} |
||||||
|
frame_count = 0; |
||||||
|
} |
||||||
|
|
||||||
|
gfx.flush_buffers(); |
||||||
|
gfx.swap_buffers(); |
||||||
|
gfx.wait_for_vblank(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,39 @@ |
|||||||
|
use ctru::console::Console; |
||||||
|
use ctru::gfx::Gfx; |
||||||
|
use ctru::services::apt::Apt; |
||||||
|
use ctru::services::hid::{Hid, KeyPad}; |
||||||
|
use ctru::services::ps::Ps; |
||||||
|
|
||||||
|
fn main() { |
||||||
|
// Initialize services
|
||||||
|
ctru::init(); |
||||||
|
let apt = Apt::init().unwrap(); |
||||||
|
let hid = Hid::init().unwrap(); |
||||||
|
let gfx = Gfx::default(); |
||||||
|
let _console = Console::init(gfx.top_screen.borrow_mut()); |
||||||
|
|
||||||
|
// HashMaps generate hashes thanks to the 3DS' criptografically secure generator.
|
||||||
|
// Sadly, this generator is only active when activating the `Ps` service.
|
||||||
|
// To do this, we have to make sure the `Ps` service handle is alive for the whole
|
||||||
|
// run time (or at least, when `HashMaps` are used).
|
||||||
|
// Not having a living `Ps` instance when using `HashMap`s results in a panic
|
||||||
|
let _ps = Ps::init().unwrap(); |
||||||
|
|
||||||
|
let mut map = std::collections::HashMap::new(); |
||||||
|
map.insert("A Key!", 102); |
||||||
|
map.insert("Another key?", 543); |
||||||
|
map.remove("A Key!"); |
||||||
|
|
||||||
|
println!("{:#?}", map); |
||||||
|
|
||||||
|
while apt.main_loop() { |
||||||
|
gfx.flush_buffers(); |
||||||
|
gfx.swap_buffers(); |
||||||
|
gfx.wait_for_vblank(); |
||||||
|
|
||||||
|
hid.scan_input(); |
||||||
|
if hid.keys_down().contains(KeyPad::KEY_START) { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,85 @@ |
|||||||
|
//! Process Services (PS) module. This is used for miscellaneous utility tasks, but
|
||||||
|
//! is particularly important because it is used to generate random data, which
|
||||||
|
//! is required for common things like [`HashMap`](std::collections::HashMap).
|
||||||
|
//! See also <https://www.3dbrew.org/wiki/Process_Services>
|
||||||
|
|
||||||
|
/// PS handle. This must not be dropped in order for random generation
|
||||||
|
/// to work (in most cases, the lifetime of an application).
|
||||||
|
#[non_exhaustive] |
||||||
|
pub struct Ps; |
||||||
|
|
||||||
|
#[repr(u32)] |
||||||
|
pub enum AESAlgorithm { |
||||||
|
CbcEnc, |
||||||
|
CbcDec, |
||||||
|
CtrEnc, |
||||||
|
CtrDec, |
||||||
|
CcmEnc, |
||||||
|
CcmDec, |
||||||
|
} |
||||||
|
|
||||||
|
#[repr(u32)] |
||||||
|
pub enum AESKeyType { |
||||||
|
Keyslot0D, |
||||||
|
Keyslot2D, |
||||||
|
Keyslot31, |
||||||
|
Keyslot38, |
||||||
|
Keyslot32, |
||||||
|
Keyslot39Dlp, |
||||||
|
Keyslot2E, |
||||||
|
KeyslotInvalid, |
||||||
|
Keyslot36, |
||||||
|
Keyslot39Nfc, |
||||||
|
} |
||||||
|
|
||||||
|
impl Ps { |
||||||
|
/// Initialize the PS module.
|
||||||
|
pub fn init() -> crate::Result<Self> { |
||||||
|
let r = unsafe { ctru_sys::psInit() }; |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(Self) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn local_friend_code_seed(&self) -> crate::Result<u64> { |
||||||
|
let mut seed: u64 = 0; |
||||||
|
|
||||||
|
let r = unsafe { ctru_sys::PS_GetLocalFriendCodeSeed(&mut seed) }; |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(seed) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn device_id(&self) -> crate::Result<u32> { |
||||||
|
let mut id: u32 = 0; |
||||||
|
|
||||||
|
let r = unsafe { ctru_sys::PS_GetDeviceId(&mut id) }; |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(id) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn generate_random_bytes(&self, out: &mut [u8]) -> crate::Result<()> { |
||||||
|
let r = |
||||||
|
unsafe { ctru_sys::PS_GenerateRandomBytes(out as *mut _ as *mut _, out.len() as u32) }; |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Drop for Ps { |
||||||
|
fn drop(&mut self) { |
||||||
|
unsafe { |
||||||
|
ctru_sys::psExit(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue