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. 301
      ctru-rs/examples/ir-user.rs

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

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

Loading…
Cancel
Save