diff --git a/examples/coap/Cargo.toml b/examples/coap/Cargo.toml index a5d0fad16..a5b2962cc 100644 --- a/examples/coap/Cargo.toml +++ b/examples/coap/Cargo.toml @@ -19,6 +19,13 @@ embedded-nal-async = "0.7" # actually patched with https://github.com/smoltcp-rs/smoltcp/pull/904 but # patch.crates-io takes care of that smoltcp = { version = "0.11", default-features = false } +embedded-nal-coap = "0.1.0-alpha.2" +coap-request = "0.2.0-alpha.2" +coap-message = "0.3.1" +embassy-futures = "0.1.1" +coap-message-demos = { version = "0.4.0", default-features = false } +coap-request-implementations = "0.1.0-alpha.4" +rand = { version = "0.8.5", default-features = false, features = [ "small_rng" ] } [features] default = [ "proto-ipv4" ] # shame diff --git a/examples/coap/src/main.rs b/examples/coap/src/main.rs index 24ac3dac3..6ac352e11 100644 --- a/examples/coap/src/main.rs +++ b/examples/coap/src/main.rs @@ -5,13 +5,43 @@ use riot_rs::{debug::println, embassy::network}; +use embassy_net::udp::{PacketMetadata, UdpSocket}; + +// Moving work from https://github.com/embassy-rs/embassy/pull/2519 in here for the time being +mod udp_nal; + #[riot_rs::task(autostart)] -async fn udp_echo() { +async fn coap_run() { let stack = network::network_stack().await.unwrap(); + // FIXME trim to CoAP requirements + let mut rx_meta = [PacketMetadata::EMPTY; 16]; + let mut rx_buffer = [0; 4096]; + let mut tx_meta = [PacketMetadata::EMPTY; 16]; + let mut tx_buffer = [0; 4096]; + let mut buf = [0; 4096]; + + let mut socket = UdpSocket::new( + stack, + &mut rx_meta, + &mut rx_buffer, + &mut tx_meta, + &mut tx_buffer, + ); + println!("Starting up CoAP server"); - todo!("Work with {stack:p}"); + // Can't that even bind to the Any address?? + // let local_any = "0.0.0.0:5683".parse().unwrap(); // shame + let local_any = "10.42.0.61:5683".parse().unwrap(); // shame + let mut unconnected = udp_nal::UnconnectedUdp::bind_multiple(socket, local_any) + .await + .unwrap(); + + // NAL time + use embedded_nal_async::UnconnectedUdp; + + run(unconnected).await; } // FIXME: So far, this is necessary boiler plate; see ../README.md#networking for details @@ -25,3 +55,81 @@ fn network_config() -> embassy_net::Config { gateway: Some(Ipv4Address::new(10, 42, 0, 1)), }) } + +// Rest is from coap-message-demos/examples/std_embedded_nal_coap.rs + +/// This function works on *any* UdpFullStack, including embedded ones -- only main() is what makes +/// this use POSIX sockets. (It does make use of a std based RNG, but that could be passed in just +/// as well for no_std operation). +async fn run(mut sock: S) +where + S: embedded_nal_async::UnconnectedUdp, +{ + let log = None; + + let mut handler = coap_message_demos::full_application_tree(log); + + println!("Server is ready."); + + let coap = embedded_nal_coap::CoAPShared::<3>::new(); + let (client, server) = coap.split(); + + // going with an embassy_futures join instead of an async_std::task::spawn b/c CoAPShared is not + // Sync, and async_std expects to work in multiple threads + embassy_futures::join::join( + async { + let mut rand = rand::rngs::SmallRng::seed_from_u64(4); + use rand::SeedableRng; + server + .run( + &mut sock, + &mut handler, + &mut rand, + ) + .await + .expect("UDP error") + }, + run_client_operations(client), + ) + .await; +} + +/// In parallel to server operation, this function performs some operations as a client. +/// +/// This doubles as an experimentation ground for the client side of embedded_nal_coap and +/// coap-request in general. +async fn run_client_operations( + client: embedded_nal_coap::CoAPRuntimeClient<'_, N>, +) { + use coap_message::Code; + + // shame + let demoserver = "10.42.0.1:1234".parse().unwrap(); + + use coap_request::Stack; + println!("Sending GET to {}...", demoserver); + let response = client + .to(demoserver) + .request( + coap_request_implementations::Code::get() + .with_path("/other/separate") + .processing_response_payload_through(|p| { + println!("Got payload {:?}", p); + }), + ) + .await; + println!("Response {:?}", response); + + let req = coap_request_implementations::Code::post().with_path("/uppercase"); + + println!("Sending POST..."); + let mut response = client.to(demoserver); + let response = response.request( + req.with_request_payload_slice(b"Set time to 1955-11-05") + .processing_response_payload_through(|p| { + println!("Uppercase is {}", core::str::from_utf8(p).unwrap()) + }), + ); + let response = response.await; + println!("Response {:?}", response); +}