Browse Source

Refactor the ir-user example

pull/129/head
Mark Drobnak 2 years ago
parent
commit
d8593088c2
No known key found for this signature in database
GPG Key ID: 47A133F3BF9D03D3
  1. 157
      ctru-rs/examples/ir-user.rs

157
ctru-rs/examples/ir-user.rs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
use ctru::prelude::*;
use ctru::services::ir_user::{CirclePadProInputResponse, IrDeviceId, IrUser};
use ctru_sys::Handle;
use std::io::Write;
use std::time::Duration;
@ -20,6 +21,59 @@ fn main() { @@ -20,6 +21,59 @@ fn main() {
let top_console = Console::init(gfx.top_screen.borrow_mut());
let bottom_console = Console::init(gfx.bottom_screen.borrow_mut());
let demo = CirclePadProDemo::new(top_console, bottom_console);
demo.print_status_info();
println!("Press A to connect to the CPP");
let mut is_connected = false;
while apt.main_loop() {
hid.scan_input();
// Check if we need to exit
if hid.keys_held().contains(KeyPad::KEY_START) {
break;
}
// Check if we've received a packet from the circle pad pro
let packet_received =
IrUser::wait_for_event(demo.receive_packet_event, Duration::ZERO).is_ok();
if packet_received {
demo.handle_packets();
}
// Check if we should start the connection
if hid.keys_down().contains(KeyPad::KEY_A) && !is_connected {
println!("Attempting to connect to the CPP");
match demo.connect_to_cpp(&hid) {
ConnectionResult::Connected => is_connected = true,
ConnectionResult::Canceled => break,
}
}
gfx.flush_buffers();
gfx.swap_buffers();
gfx.wait_for_vblank();
}
}
struct CirclePadProDemo<'screen> {
top_console: Console<'screen>,
bottom_console: Console<'screen>,
ir_user: IrUser,
connection_status_event: Handle,
receive_packet_event: Handle,
}
enum ConnectionResult {
Connected,
Canceled,
}
impl<'screen> CirclePadProDemo<'screen> {
fn new(top_console: Console<'screen>, bottom_console: Console<'screen>) -> Self {
bottom_console.select();
println!("Welcome to the ir:USER / Circle Pad Pro Demo");
println!("Starting up ir:USER service");
@ -30,78 +84,68 @@ fn main() { @@ -30,78 +84,68 @@ fn main() {
PACKET_COUNT,
)
.expect("Couldn't initialize ir:USER service");
println!("ir:USER service initialized\nPress A to connect to the CPP");
let print_status_info = || {
top_console.select();
top_console.clear();
println!("{:#x?}", ir_user.get_status_info());
bottom_console.select();
};
println!("ir:USER service initialized");
// Get event handles
let conn_status_event = ir_user
let connection_status_event = ir_user
.get_connection_status_event()
.expect("Couldn't get ir:USER connection status event");
let recv_event = ir_user
let receive_packet_event = ir_user
.get_recv_event()
.expect("Couldn't get ir:USER recv event");
print_status_info();
let mut is_connected = false;
'main_loop: while apt.main_loop() {
hid.scan_input();
// Check if we need to exit
if hid.keys_held().contains(KeyPad::KEY_START) {
break;
Self {
top_console,
bottom_console,
ir_user,
connection_status_event,
receive_packet_event,
}
// Check if we've received a packet from the circle pad pro
let packet_received = IrUser::wait_for_event(recv_event, Duration::ZERO).is_ok();
if packet_received {
handle_packet(&ir_user, &top_console, &bottom_console);
}
// Check if we should start the connection
if hid.keys_down().contains(KeyPad::KEY_A) && !is_connected {
println!("Attempting to connect to the CPP");
fn print_status_info(&self) {
self.top_console.select();
self.top_console.clear();
println!("{:#x?}", self.ir_user.get_status_info());
self.bottom_console.select();
}
fn connect_to_cpp(&self, hid: &Hid) -> ConnectionResult {
// Connection loop
loop {
hid.scan_input();
if hid.keys_held().contains(KeyPad::KEY_START) {
break 'main_loop;
return ConnectionResult::Canceled;
}
// Start the connection process
ir_user
self.ir_user
.require_connection(IrDeviceId::CirclePadPro)
.expect("Couldn't initialize circle pad pro connection");
// Wait for the connection to establish
if let Err(e) =
IrUser::wait_for_event(conn_status_event, Duration::from_millis(100))
IrUser::wait_for_event(self.connection_status_event, Duration::from_millis(100))
{
if !e.is_timeout() {
panic!("Couldn't initialize circle pad pro connection: {e}");
}
}
print_status_info();
if ir_user.get_status_info().connection_status == 2 {
self.print_status_info();
if self.ir_user.get_status_info().connection_status == 2 {
println!("Connected!");
break;
}
// If not connected (ex. timeout), disconnect so we can retry
ir_user
self.ir_user
.disconnect()
.expect("Failed to disconnect circle pad pro connection");
// Wait for the disconnect to go through
if let Err(e) =
IrUser::wait_for_event(conn_status_event, Duration::from_millis(100))
IrUser::wait_for_event(self.connection_status_event, Duration::from_millis(100))
{
if !e.is_timeout() {
panic!("Couldn't initialize circle pad pro connection: {e}");
@ -113,45 +157,46 @@ fn main() { @@ -113,45 +157,46 @@ fn main() {
loop {
hid.scan_input();
if hid.keys_held().contains(KeyPad::KEY_START) {
break 'main_loop;
return ConnectionResult::Canceled;
}
// Send a request for input to the CPP
if let Err(e) = ir_user.request_input_polling(CPP_CONNECTION_POLLING_PERIOD_MS) {
if let Err(e) = self
.ir_user
.request_input_polling(CPP_CONNECTION_POLLING_PERIOD_MS)
{
println!("Error: {e:?}");
}
print_status_info();
self.print_status_info();
// Wait for the response
let recv_event_result =
IrUser::wait_for_event(recv_event, Duration::from_millis(100));
print_status_info();
IrUser::wait_for_event(self.receive_packet_event, Duration::from_millis(100));
self.print_status_info();
if recv_event_result.is_ok() {
println!("Got first packet from CPP");
handle_packet(&ir_user, &top_console, &bottom_console);
self.handle_packets();
break;
}
// We didn't get a response in time, so loop and retry
}
is_connected = true;
ConnectionResult::Connected
}
gfx.flush_buffers();
gfx.swap_buffers();
gfx.wait_for_vblank();
}
}
fn handle_packets(&self) {
let packets = self.ir_user.get_packets();
let packet_count = packets.len();
let Some(last_packet) = packets.last() else { return };
fn handle_packet(ir_user: &IrUser, top_console: &Console, bottom_console: &Console) {
// Use a buffer to avoid flickering the screen (write all output at once)
let mut output_buffer = Vec::with_capacity(0x1000);
writeln!(&mut output_buffer, "{:x?}", ir_user.get_status_info()).unwrap();
writeln!(&mut output_buffer, "{:x?}", self.ir_user.get_status_info()).unwrap();
ir_user.process_shared_memory(|ir_mem| {
self.ir_user.process_shared_memory(|ir_mem| {
writeln!(&mut output_buffer, "\nReceiveBufferInfo:").unwrap();
write_buffer_as_hex(&ir_mem[0x10..0x20], &mut output_buffer);
@ -160,10 +205,7 @@ fn handle_packet(ir_user: &IrUser, top_console: &Console, bottom_console: &Conso @@ -160,10 +205,7 @@ fn handle_packet(ir_user: &IrUser, top_console: &Console, bottom_console: &Conso
writeln!(&mut output_buffer).unwrap();
});
let packets = ir_user.get_packets();
let packet_count = packets.len();
writeln!(&mut output_buffer, "\nPacket count: {packet_count}").unwrap();
let last_packet = packets.last().unwrap();
writeln!(&mut output_buffer, "{last_packet:02x?}").unwrap();
let cpp_response = CirclePadProInputResponse::try_from(last_packet)
@ -171,21 +213,22 @@ fn handle_packet(ir_user: &IrUser, top_console: &Console, bottom_console: &Conso @@ -171,21 +213,22 @@ fn handle_packet(ir_user: &IrUser, top_console: &Console, bottom_console: &Conso
writeln!(&mut output_buffer, "\n{cpp_response:#02x?}").unwrap();
// Write output to top screen
top_console.select();
top_console.clear();
self.top_console.select();
self.top_console.clear();
std::io::stdout().write_all(&output_buffer).unwrap();
bottom_console.select();
self.bottom_console.select();
// Done handling the packet, release it
ir_user
// Done handling the packets, release them
self.ir_user
.release_received_data(packet_count as u32)
.expect("Failed to release ir:USER packet");
// Remind the CPP that we're still listening
if let Err(e) = ir_user.request_input_polling(CPP_POLLING_PERIOD_MS) {
if let Err(e) = self.ir_user.request_input_polling(CPP_POLLING_PERIOD_MS) {
println!("Error: {e:?}");
}
}
}
fn write_buffer_as_hex(buffer: &[u8], output: &mut Vec<u8>) {
let mut counter = 0;

Loading…
Cancel
Save