Skip to content

Commit

Permalink
feat(coap): Initial riot-rs-coap code moved from example
Browse files Browse the repository at this point in the history
  • Loading branch information
chrysn committed Oct 28, 2024
1 parent 81393a4 commit 49a793f
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 109 deletions.
21 changes: 15 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 4 additions & 15 deletions examples/coap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ workspace = true
[dependencies]
embassy-executor = { workspace = true, default-features = false }
embassy-net = { workspace = true, features = ["udp"] }
embassy-sync.workspace = true
embassy-time = { workspace = true, default-features = false }
embedded-io-async = "0.6.1"
heapless = { workspace = true }
riot-rs = { path = "../../src/riot-rs", features = [
"override-network-config",
Expand All @@ -23,29 +23,18 @@ riot-rs = { path = "../../src/riot-rs", features = [
"csprng",
] }
riot-rs-boards = { path = "../../src/riot-rs-boards" }

coapcore.path = "../../src/lib/coapcore/"

# for the udp_nal mod
embedded-nal-async = "0.7"
embassy-futures = "0.1.1"
embedded-nal-coap = "0.1.0-alpha.2"
coap-request = "0.2.0-alpha.2"
coap-message = "0.3.2"
embassy-futures = "0.1.1"
coap-message-demos = { version = "0.4.0", default-features = false }
coap-request-implementations = "0.1.0-alpha.4"
lakers = { version = "0.6.0", default-features = false }
lakers-crypto-rustcrypto = "0.6.0"
coap-handler = "0.2.0"
coap-handler-implementations = "0.5.0"
hexlit = "0.5.5"

static-alloc = { version = "0.2.5", features = ["polyfill"] }
coap-scroll-ring-server = "0.2.0"
scroll-ring = "0.1.1"

[features]
default = ["proto-ipv4"] # shame
# actually embedded-nal features, we have to match them here while developing udp_nal in here
proto-ipv4 = ["embassy-net/proto-ipv4"]
proto-ipv6 = ["embassy-net/proto-ipv6"]
# FIXME: Where should this be pulled through?
riot-rs-coap = { workspace = true, features = ["proto-ipv4"] }
115 changes: 27 additions & 88 deletions examples/coap/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@

use riot_rs::{debug::log::*, 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;

use coapcore::seccontext;

// because coapcore depends on it temporarily
extern crate alloc;
use static_alloc::Bump;
Expand All @@ -21,55 +14,6 @@ static A: Bump<[u8; 1 << 16]> = Bump::uninit();

#[riot_rs::task(autostart)]
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 socket = UdpSocket::new(
stack,
&mut rx_meta,
&mut rx_buffer,
&mut tx_meta,
&mut tx_buffer,
);

info!("Starting up CoAP server");

// 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 unconnected = udp_nal::UnconnectedUdp::bind_multiple(socket, local_any)
.await
.unwrap();

run(unconnected).await;
}

// FIXME: So far, this is necessary boiler plate; see ../README.md#networking for details
#[riot_rs::config(network)]
fn network_config() -> embassy_net::Config {
use embassy_net::Ipv4Address;

embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
address: embassy_net::Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
dns_servers: heapless::Vec::new(),
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<S>(mut sock: S)
where
S: embedded_nal_async::UnconnectedUdp,
{
use coap_handler_implementations::{HandlerBuilder, ReportingHandlerBuilder};

let log = None;
Expand All @@ -87,39 +31,17 @@ where
writeln!(stdout, "We have our own stdout now.").unwrap();
writeln!(stdout, "With rings and atomics.").unwrap();

use hexlit::hex;
const R: &[u8] = &hex!("72cc4761dbd4c78f758931aa589d348d1ef874a7e303ede2f140dcf3e6aa4aac");
let own_identity = (
&lakers::CredentialRPK::new(lakers::EdhocMessageBuffer::new_from_slice(&hex!("A2026008A101A5010202410A2001215820BBC34960526EA4D32E940CAD2A234148DDC21791A12AFBCBAC93622046DD44F02258204519E257236B2A0CE2023F0931F1F386CA7AFDA64FCDE0108C224C51EABF6072")).expect("Credential should be small enough")).expect("Credential should be processable"),
R,
);

let handler = coap_message_demos::full_application_tree(log)
.at(
&["stdout"],
coap_scroll_ring_server::BufferHandler::new(&buffer),
)
.with_wkc();

let mut handler = seccontext::OscoreEdhocHandler::new(own_identity, handler, stdout, || {
lakers_crypto_rustcrypto::Crypto::new(riot_rs::random::crypto_rng())
});

info!("Server is ready.");
let handler = coap_message_demos::full_application_tree(log).at(
&["stdout"],
coap_scroll_ring_server::BufferHandler::new(&buffer),
);

let coap = embedded_nal_coap::CoAPShared::<3>::new();
let (client, server) = coap.split();
let client_signal = embassy_sync::signal::Signal::new();

// 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
// going with an embassy_futures join instead of RIOT-rs's spawn b/c CoAPShared is not Sync.
embassy_futures::join::join(
async {
server
.run(&mut sock, &mut handler, &mut riot_rs::random::fast_rng())
.await
.expect("UDP error")
},
run_client_operations(client),
riot_rs::coap::coap_run(handler, stdout, &client_signal),
run_client_operations(&client_signal),
)
.await;
}
Expand All @@ -128,9 +50,14 @@ where
///
/// This doubles as an experimentation ground for the client side of embedded_nal_coap and
/// coap-request in general.
async fn run_client_operations<const N: usize>(
client: embedded_nal_coap::CoAPRuntimeClient<'_, N>,
async fn run_client_operations(
client_in: &embassy_sync::signal::Signal<
embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex,
&'static embedded_nal_coap::CoAPRuntimeClient<'static, 3>,
>,
) {
let client = client_in.wait().await;

// shame
let addr = "10.42.0.1:1234";
let demoserver = addr.clone().parse().unwrap();
Expand Down Expand Up @@ -162,3 +89,15 @@ async fn run_client_operations<const N: usize>(
let response = response.await;
info!("Response {:?}", response.map_err(|_| "TransportError"));
}

// FIXME: So far, this is necessary boiler plate; see ../README.md#networking for details
#[riot_rs::config(network)]
fn network_config() -> embassy_net::Config {
use embassy_net::Ipv4Address;

embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
address: embassy_net::Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
dns_servers: heapless::Vec::new(),
gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
})
}
17 changes: 17 additions & 0 deletions src/riot-rs-coap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,26 @@ repository.workspace = true

[dependencies]
coapcore.path = "../lib/coapcore"
coap-handler = "0.2.0"
coap-handler-implementations = "0.5.0"
critical-section.workspace = true
embassy-futures = "0.1.1"
embassy-net = { workspace = true, features = ["udp"] }
embassy-sync.workspace = true
embedded-nal-async = "0.7"
embedded-nal-coap = "0.1.0-alpha.2"
lakers-crypto-rustcrypto = "0.6.0"
lakers = { version = "0.6.0", default-features = false }
riot-rs-debug.workspace = true
riot-rs-embassy.workspace = true
riot-rs-random.workspace = true
static_cell = "2.1.0"

# FIXME: Should go out eventually
hexlit = "0.5.5"

# For the udp_nal
embedded-io-async = "0.6.1"

[lints]
workspace = true
Expand Down
86 changes: 86 additions & 0 deletions src/riot-rs-coap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,89 @@
#![no_std]
#![deny(missing_docs)]
#![deny(clippy::pedantic)]

// Moving work from https://github.com/embassy-rs/embassy/pull/2519 in here for the time being
mod udp_nal;

use coap_handler_implementations::{HandlerBuilder, ReportingHandlerBuilder};
use coapcore::seccontext;
use critical_section::Mutex;
use embassy_net::udp::{PacketMetadata, UdpSocket};
use riot_rs_debug::log::*;
use static_cell::StaticCell;

const CONCURRENT_REQUESTS: usize = 3;

// FIXME: log_stdout is not something we want to have here
// FIXME: I'd rather have the client_out available anywhere, but at least the way CoAPRuntimeClient
// is set up right now, server and client have to run in the same thread.
/// Run a CoAP server with the given handler on the system's CoAP transports.
pub async fn coap_run(
handler: impl coap_handler::Handler + coap_handler::Reporting,
log_stdout: impl core::fmt::Write,
client_out: &embassy_sync::signal::Signal<
embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex,
&'static embedded_nal_coap::CoAPRuntimeClient<'static, CONCURRENT_REQUESTS>,
>,
) {
let stack = riot_rs_embassy::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 socket = UdpSocket::new(
stack,
&mut rx_meta,
&mut rx_buffer,
&mut tx_meta,
&mut tx_buffer,
);
use embedded_nal_async::UnconnectedUdp;

info!("Starting up CoAP server");

// 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();

use hexlit::hex;
const R: &[u8] = &hex!("72cc4761dbd4c78f758931aa589d348d1ef874a7e303ede2f140dcf3e6aa4aac");
let own_identity = (
&lakers::CredentialRPK::new(lakers::EdhocMessageBuffer::new_from_slice(&hex!("A2026008A101A5010202410A2001215820BBC34960526EA4D32E940CAD2A234148DDC21791A12AFBCBAC93622046DD44F02258204519E257236B2A0CE2023F0931F1F386CA7AFDA64FCDE0108C224C51EABF6072")).expect("Credential should be small enough")).expect("Credential should be processable"),
R,
);

// FIXME: Should we allow users to override that? After all, this is just convenience and may
// be limiting in special applications.
let handler = handler.with_wkc();
let mut handler =
seccontext::OscoreEdhocHandler::new(own_identity, handler, log_stdout, || {
lakers_crypto_rustcrypto::Crypto::new(riot_rs_random::crypto_rng())
});

info!("Server is ready.");

static COAP: StaticCell<embedded_nal_coap::CoAPShared<CONCURRENT_REQUESTS>> = StaticCell::new();
let coap = COAP.init_with(|| embedded_nal_coap::CoAPShared::new());
static CLIENT: StaticCell<embedded_nal_coap::CoAPRuntimeClient<'static, CONCURRENT_REQUESTS>> =
StaticCell::new();
let (client, server) = coap.split();
let client = CLIENT.init_with(|| client);

client_out.signal(client);

server
.run(
&mut unconnected,
&mut handler,
&mut riot_rs_random::fast_rng(),
)
.await
.expect("UDP error")
}
File renamed without changes.
File renamed without changes.

0 comments on commit 49a793f

Please sign in to comment.