Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement UDS service with example #156

Merged
merged 14 commits into from
Apr 9, 2024
Merged
1 change: 1 addition & 0 deletions ctru-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pthread-3ds = { git = "https://github.com/rust3ds/pthread-3ds.git" }
libc = "0.2.121"
bitflags = "2.3.3"
macaddr = "1.0.1"
widestring = "1.0.2"

[build-dependencies]
toml = "0.5"
Expand Down
87 changes: 53 additions & 34 deletions ctru-rs/examples/local-networking.rs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, this is a pretty intense example but it seems necessary given how many features there are in the uds service. I was wondering if some of this functionality could go onto Uds itself instead of just in this example, but honestly on first read I don't see any obvious things that make sense, so 👍 good with me

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,30 @@
use ctru::prelude::*;
use ctru::services::uds::*;

fn main() {
fn handle_status_event(uds: &Uds, prev_node_mask: u16) -> ctru::Result<u16> {
println!("Connection status event signalled");
let status = uds.get_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.get_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();
Expand Down Expand Up @@ -37,9 +60,11 @@

let mut mode = ConnectionType::Client;

let mut channel = 0;

Check warning on line 63 in ctru-rs/examples/local-networking.rs

View workflow job for this annotation

GitHub Actions / lint (nightly-2024-02-18)

value assigned to `channel` is never read
let data_channel = 1;

let mut prev_node_mask = 0;

while apt.main_loop() {
gfx.wait_for_vblank();

Expand All @@ -53,9 +78,11 @@
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 => {
Expand Down Expand Up @@ -99,7 +126,7 @@
println!(
"{} Username: {}",
if index == selected_network { ">" } else { " " },
n.nodes[0].as_ref().unwrap().username
n.nodes()[0].unwrap().username()
);
}

Expand All @@ -126,9 +153,7 @@
}
}
State::Connect => {
let appdata = uds
.get_network_appdata(&networks[selected_network], None)
.unwrap();
let appdata = uds.get_network_appdata(&networks[selected_network], None)?;
println!("App data: {:02X?}", appdata);

if let Err(e) = uds.connect_network(
Expand All @@ -142,16 +167,14 @@
state = State::Initialised;
println!("Press A to start scanning or B to create a new network");
} else {
channel = uds.get_channel().unwrap();
channel = uds.get_channel()?;
println!("Connected using channel {}", channel);

let appdata = uds.get_appdata(None).unwrap();
let appdata = uds.get_appdata(None)?;
println!("App data: {:02X?}", appdata);

if uds.wait_status_event(false, false).unwrap() {
println!("Connection status event signalled");
let status = uds.get_connection_status().unwrap();
println!("Status: {status:#02X?}");
if uds.wait_status_event(false, false)? {
prev_node_mask = handle_status_event(&uds, prev_node_mask)?;
}

println!("Press A to stop data transfer");
Expand All @@ -165,19 +188,17 @@
Ok(p) => {
if let Some((pkt, node)) = p {
println!(
"{:02X}{:02X}{:02X}{:02X} from {:04X}",
"{:02X}{:02X}{:02X}{:02X} from {:?}",
pkt[0], pkt[1], pkt[2], pkt[3], node
);
}

if uds.wait_status_event(false, false).unwrap() {
println!("Connection status event signalled");
let status = uds.get_connection_status().unwrap();
println!("Status: {status:#02X?}");
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().unwrap();
uds.disconnect_network()?;
state = State::Initialised;
console.clear();
println!("Press A to start scanning or B to create a new network");
Expand All @@ -186,18 +207,17 @@
if mode != ConnectionType::Spectator {
uds.send_packet(
&transfer_data.to_le_bytes(),
ctru_sys::UDS_BROADCAST_NETWORKNODEID as _,
NodeID::Broadcast,
data_channel,
SendFlags::Default,
)
.unwrap();
)?;
}
}
}
Err(e) => {
uds.disconnect_network().unwrap();
uds.disconnect_network()?;
console.clear();
eprintln!("Error while grabbing packet from network: {e:#?}");
eprintln!("Error while grabbing packet from network: {e}");
state = State::Initialised;
println!("Press A to start scanning or B to create a new network");
}
Expand All @@ -221,7 +241,7 @@
.chain(std::iter::repeat(0).take(3))
.collect::<Vec<_>>();

uds.set_appdata(&appdata).unwrap();
uds.set_appdata(&appdata)?;

println!("Press A to stop data transfer");
state = State::Created;
Expand All @@ -241,42 +261,41 @@
Ok(p) => {
if let Some((pkt, node)) = p {
println!(
"{:02X}{:02X}{:02X}{:02X} from {:04X}",
"{:02X}{:02X}{:02X}{:02X} from {:?}",
pkt[0], pkt[1], pkt[2], pkt[3], node
);
}

if uds.wait_status_event(false, false).unwrap() {
println!("Connection status event signalled");
let status = uds.get_connection_status().unwrap();
println!("Status: {status:#02X?}");
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().unwrap();
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(),
ctru_sys::UDS_BROADCAST_NETWORKNODEID as _,
NodeID::Broadcast,
data_channel,
SendFlags::Default,
)
.unwrap();
)?;
}
}
Err(e) => {
uds.destroy_network().unwrap();
uds.destroy_network()?;
console.clear();
eprintln!("Error while grabbing packet from network: {e:#?}");
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
Loading