Meziu
9 months ago
committed by
GitHub
6 changed files with 1687 additions and 1 deletions
@ -0,0 +1,301 @@ |
|||||||
|
//! Local networking example.
|
||||||
|
//!
|
||||||
|
//! This example showcases local networking using the UDS module.
|
||||||
|
|
||||||
|
use ctru::prelude::*; |
||||||
|
use ctru::services::uds::*; |
||||||
|
|
||||||
|
fn handle_status_event(uds: &Uds, prev_node_mask: u16) -> ctru::Result<u16> { |
||||||
|
println!("Connection status event signalled"); |
||||||
|
let status = uds.connection_status()?; |
||||||
|
println!("Status: {status:#02X?}"); |
||||||
|
let left = prev_node_mask & (status.node_bitmask() ^ prev_node_mask); |
||||||
|
let joined = status.node_bitmask() & (status.node_bitmask() ^ prev_node_mask); |
||||||
|
for i in 0..16 { |
||||||
|
if left & (1 << i) != 0 { |
||||||
|
println!("Node {} disconnected", i + 1); |
||||||
|
} |
||||||
|
} |
||||||
|
for i in 0..16 { |
||||||
|
if joined & (1 << i) != 0 { |
||||||
|
println!( |
||||||
|
"Node {} connected: {:?}", |
||||||
|
i + 1, |
||||||
|
uds.node_info(NodeID::Node(i + 1)) |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
Ok(status.node_bitmask()) |
||||||
|
} |
||||||
|
|
||||||
|
fn main() -> Result<(), Error> { |
||||||
|
let apt = Apt::new().unwrap(); |
||||||
|
let mut hid = Hid::new().unwrap(); |
||||||
|
let gfx = Gfx::new().unwrap(); |
||||||
|
let console = Console::new(gfx.top_screen.borrow_mut()); |
||||||
|
|
||||||
|
println!("Local networking demo"); |
||||||
|
|
||||||
|
let mut uds = Uds::new(None).unwrap(); |
||||||
|
|
||||||
|
println!("UDS initialised"); |
||||||
|
|
||||||
|
enum State { |
||||||
|
Initialised, |
||||||
|
Scanning, |
||||||
|
DrawList, |
||||||
|
List, |
||||||
|
Connect, |
||||||
|
Connected, |
||||||
|
Create, |
||||||
|
Created, |
||||||
|
} |
||||||
|
|
||||||
|
let mut state = State::Initialised; |
||||||
|
|
||||||
|
println!("Press A to start scanning or B to create a new network"); |
||||||
|
|
||||||
|
let mut networks = vec![]; |
||||||
|
let mut selected_network = 0; |
||||||
|
|
||||||
|
let mut mode = ConnectionType::Client; |
||||||
|
|
||||||
|
let mut channel = 0; |
||||||
|
let data_channel = 1; |
||||||
|
|
||||||
|
let mut prev_node_mask = 0; |
||||||
|
|
||||||
|
while apt.main_loop() { |
||||||
|
gfx.wait_for_vblank(); |
||||||
|
|
||||||
|
hid.scan_input(); |
||||||
|
if hid.keys_down().contains(KeyPad::START) { |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
match state { |
||||||
|
State::Initialised => { |
||||||
|
if hid.keys_down().contains(KeyPad::A) { |
||||||
|
state = State::Scanning; |
||||||
|
console.clear(); |
||||||
|
prev_node_mask = 0; |
||||||
|
} else if hid.keys_down().contains(KeyPad::B) { |
||||||
|
state = State::Create; |
||||||
|
console.clear(); |
||||||
|
prev_node_mask = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
State::Scanning => { |
||||||
|
println!("Scanning..."); |
||||||
|
|
||||||
|
let nwks = uds.scan(b"HBW\x10", None, None); |
||||||
|
|
||||||
|
match nwks { |
||||||
|
Ok(n) => { |
||||||
|
if n.is_empty() { |
||||||
|
state = State::Initialised; |
||||||
|
console.clear(); |
||||||
|
println!("Scanned successfully; no networks found"); |
||||||
|
println!("Press A to start scanning or B to create a new network"); |
||||||
|
} else { |
||||||
|
networks = n; |
||||||
|
selected_network = 0; |
||||||
|
state = State::DrawList; |
||||||
|
} |
||||||
|
} |
||||||
|
Err(e) => { |
||||||
|
state = State::Initialised; |
||||||
|
console.clear(); |
||||||
|
eprintln!("Error while scanning: {e}"); |
||||||
|
println!("Press A to start scanning or B to create a new network"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
State::DrawList => { |
||||||
|
console.clear(); |
||||||
|
|
||||||
|
println!( |
||||||
|
"Scanned successfully; {} network{} found", |
||||||
|
networks.len(), |
||||||
|
if networks.len() == 1 { "" } else { "s" } |
||||||
|
); |
||||||
|
|
||||||
|
println!("D-Pad to select, A to connect as client, R + A to connect as spectator, B to create a new network"); |
||||||
|
|
||||||
|
for (index, n) in networks.iter().enumerate() { |
||||||
|
println!( |
||||||
|
"{} Username: {}", |
||||||
|
if index == selected_network { ">" } else { " " }, |
||||||
|
n.nodes()[0].unwrap().username() |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
state = State::List; |
||||||
|
} |
||||||
|
State::List => { |
||||||
|
if hid.keys_down().contains(KeyPad::UP) && selected_network > 0 { |
||||||
|
selected_network -= 1; |
||||||
|
state = State::DrawList; |
||||||
|
} else if hid.keys_down().contains(KeyPad::DOWN) |
||||||
|
&& selected_network < networks.len() - 1 |
||||||
|
{ |
||||||
|
selected_network += 1; |
||||||
|
state = State::DrawList; |
||||||
|
} else if hid.keys_down().contains(KeyPad::A) { |
||||||
|
state = State::Connect; |
||||||
|
mode = if hid.keys_held().contains(KeyPad::R) { |
||||||
|
ConnectionType::Spectator |
||||||
|
} else { |
||||||
|
ConnectionType::Client |
||||||
|
}; |
||||||
|
} else if hid.keys_down().contains(KeyPad::B) { |
||||||
|
state = State::Create; |
||||||
|
} |
||||||
|
} |
||||||
|
State::Connect => { |
||||||
|
let appdata = uds.network_appdata(&networks[selected_network], None)?; |
||||||
|
println!("App data: {:02X?}", appdata); |
||||||
|
|
||||||
|
if let Err(e) = uds.connect_network( |
||||||
|
&networks[selected_network], |
||||||
|
b"udsdemo passphrase c186093cd2652741\0", |
||||||
|
mode, |
||||||
|
data_channel, |
||||||
|
) { |
||||||
|
console.clear(); |
||||||
|
eprintln!("Error while connecting to network: {e}"); |
||||||
|
state = State::Initialised; |
||||||
|
println!("Press A to start scanning or B to create a new network"); |
||||||
|
} else { |
||||||
|
channel = uds.channel()?; |
||||||
|
println!("Connected using channel {}", channel); |
||||||
|
|
||||||
|
let appdata = uds.appdata(None)?; |
||||||
|
println!("App data: {:02X?}", appdata); |
||||||
|
|
||||||
|
if uds.wait_status_event(false, false)? { |
||||||
|
prev_node_mask = handle_status_event(&uds, prev_node_mask)?; |
||||||
|
} |
||||||
|
|
||||||
|
println!("Press A to stop data transfer"); |
||||||
|
state = State::Connected; |
||||||
|
} |
||||||
|
} |
||||||
|
State::Connected => { |
||||||
|
let packet = uds.pull_packet(); |
||||||
|
|
||||||
|
match packet { |
||||||
|
Ok(p) => { |
||||||
|
if let Some((pkt, node)) = p { |
||||||
|
println!( |
||||||
|
"{:02X}{:02X}{:02X}{:02X} from {:?}", |
||||||
|
pkt[0], pkt[1], pkt[2], pkt[3], node |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
if uds.wait_status_event(false, false)? { |
||||||
|
prev_node_mask = handle_status_event(&uds, prev_node_mask)?; |
||||||
|
} |
||||||
|
|
||||||
|
if hid.keys_down().contains(KeyPad::A) { |
||||||
|
uds.disconnect_network()?; |
||||||
|
state = State::Initialised; |
||||||
|
console.clear(); |
||||||
|
println!("Press A to start scanning or B to create a new network"); |
||||||
|
} else if !hid.keys_down().is_empty() || !hid.keys_up().is_empty() { |
||||||
|
let transfer_data = hid.keys_held().bits(); |
||||||
|
if mode != ConnectionType::Spectator { |
||||||
|
uds.send_packet( |
||||||
|
&transfer_data.to_le_bytes(), |
||||||
|
NodeID::Broadcast, |
||||||
|
data_channel, |
||||||
|
SendFlags::Default, |
||||||
|
)?; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
Err(e) => { |
||||||
|
uds.disconnect_network()?; |
||||||
|
console.clear(); |
||||||
|
eprintln!("Error while grabbing packet from network: {e}"); |
||||||
|
state = State::Initialised; |
||||||
|
println!("Press A to start scanning or B to create a new network"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
State::Create => { |
||||||
|
console.clear(); |
||||||
|
println!("Creating network..."); |
||||||
|
|
||||||
|
match uds.create_network( |
||||||
|
b"HBW\x10", |
||||||
|
None, |
||||||
|
None, |
||||||
|
b"udsdemo passphrase c186093cd2652741\0", |
||||||
|
data_channel, |
||||||
|
) { |
||||||
|
Ok(_) => { |
||||||
|
let appdata = [0x69u8, 0x8a, 0x05, 0x5c] |
||||||
|
.into_iter() |
||||||
|
.chain((*b"Test appdata.").into_iter()) |
||||||
|
.chain(std::iter::repeat(0).take(3)) |
||||||
|
.collect::<Vec<_>>(); |
||||||
|
|
||||||
|
uds.set_appdata(&appdata)?; |
||||||
|
|
||||||
|
println!("Press A to stop data transfer"); |
||||||
|
state = State::Created; |
||||||
|
} |
||||||
|
Err(e) => { |
||||||
|
console.clear(); |
||||||
|
eprintln!("Error while creating network: {e}"); |
||||||
|
state = State::Initialised; |
||||||
|
println!("Press A to start scanning or B to create a new network"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
State::Created => { |
||||||
|
let packet = uds.pull_packet(); |
||||||
|
|
||||||
|
match packet { |
||||||
|
Ok(p) => { |
||||||
|
if let Some((pkt, node)) = p { |
||||||
|
println!( |
||||||
|
"{:02X}{:02X}{:02X}{:02X} from {:?}", |
||||||
|
pkt[0], pkt[1], pkt[2], pkt[3], node |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
if uds.wait_status_event(false, false)? { |
||||||
|
prev_node_mask = handle_status_event(&uds, prev_node_mask)?; |
||||||
|
} |
||||||
|
|
||||||
|
if hid.keys_down().contains(KeyPad::A) { |
||||||
|
uds.destroy_network()?; |
||||||
|
state = State::Initialised; |
||||||
|
console.clear(); |
||||||
|
println!("Press A to start scanning or B to create a new network"); |
||||||
|
} else if !hid.keys_down().is_empty() || !hid.keys_up().is_empty() { |
||||||
|
let transfer_data = hid.keys_held().bits(); |
||||||
|
uds.send_packet( |
||||||
|
&transfer_data.to_le_bytes(), |
||||||
|
NodeID::Broadcast, |
||||||
|
data_channel, |
||||||
|
SendFlags::Default, |
||||||
|
)?; |
||||||
|
} |
||||||
|
} |
||||||
|
Err(e) => { |
||||||
|
uds.destroy_network()?; |
||||||
|
console.clear(); |
||||||
|
eprintln!("Error while grabbing packet from network: {e}"); |
||||||
|
state = State::Initialised; |
||||||
|
println!("Press A to start scanning or B to create a new network"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Ok(()) |
||||||
|
} |
Loading…
Reference in new issue