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

Move CoAP server setup into module #348

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion .github/workflows/build-deploy-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:

- name: Build rustdoc docs
run: |
cargo doc -p riot-rs --features no-boards,bench,threading,random,csprng,hwrng
cargo doc -p riot-rs --features no-boards,bench,threading,random,csprng,hwrng,coap
echo "<meta http-equiv=\"refresh\" content=\"0; url=riot_rs\">" > target/doc/index.html
mkdir -p ./_site/dev/docs/api && mv target/doc/* ./_site/dev/docs/api

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ jobs:
args: --verbose --locked --features no-boards -p riot-rs -p riot-rs-boards -p riot-rs-chips -p riot-rs-debug -p riot-rs-embassy -p riot-rs-macros -p riot-rs-random -p riot-rs-rt -p riot-rs-threads -p riot-rs-utils

- name: rustdoc
run: RUSTDOCFLAGS='-D warnings' cargo doc -p riot-rs --features no-boards,bench,external-interrupts,threading,random,csprng,hwrng
run: RUSTDOCFLAGS='-D warnings' cargo doc -p riot-rs --features no-boards,bench,external-interrupts,threading,random,csprng,hwrng,coap,net,usb-ethernet
Copy link
Collaborator

@ROMemories ROMemories Aug 20, 2024

Choose a reason for hiding this comment

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

Suggested change
run: RUSTDOCFLAGS='-D warnings' cargo doc -p riot-rs --features no-boards,bench,external-interrupts,threading,random,csprng,hwrng,coap,net,usb-ethernet
run: RUSTDOCFLAGS='-D warnings' cargo doc -p riot-rs --features no-boards,bench,external-interrupts,threading,random,csprng,hwrng,coap,net

I don't think the usb-ethernet feature should be enabled for documentation, as it does not expose any new items; it's only used for internal behavior selection I think. (Regarding the net feature, I'm not sure yet.)


- name: rustfmt
run: cargo fmt --check --all
Expand Down
29 changes: 22 additions & 7 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ members = [
"src/riot-rs-boards/nrf52",
"src/riot-rs-boards/nrf52840dk",
"src/riot-rs-chips",
"src/riot-rs-coap",
"src/riot-rs-debug",
"src/riot-rs-macros",
"src/riot-rs-random",
Expand Down
18 changes: 2 additions & 16 deletions examples/coap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,26 @@ workspace = true
embassy-executor = { workspace = true, default-features = false }
embassy-net = { workspace = true, features = ["udp"] }
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",
"coap",
# to be removed later once coap pulls them in
"random",
"csprng",
] }
riot-rs-boards = { path = "../../src/riot-rs-boards" }

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

# for the udp_nal mod
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.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 = "0.2.5"
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 = []
proto-ipv6 = []
190 changes: 69 additions & 121 deletions examples/coap/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,9 @@
#![feature(type_alias_impl_trait)]
#![feature(used_with_arg)]

use riot_rs::{debug::log::*, embassy::network};
use core::fmt::Write;

use embassy_net::udp::{PacketMetadata, UdpSocket};
use embedded_nal_coap::TransportError;

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

use coapcore::seccontext;
use riot_rs::embassy::embassy_net;

// because coapcore depends on it temporarily
extern crate alloc;
Expand All @@ -20,36 +14,6 @@ use static_alloc::Bump;
#[global_allocator]
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 {
Expand All @@ -62,104 +26,88 @@ fn network_config() -> embassy_net::Config {
})
}

// Rest is from coap-message-demos/examples/std_embedded_nal_coap.rs
// This is adjusted 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,
{
// FIXME: Why doesn't scroll_ring provide that?
#[derive(Clone)]
struct Stdout<'a, const N: usize>(&'a scroll_ring::Buffer<N>);
impl<'a, const N: usize> Write for Stdout<'a, N> {
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
self.0.write(s.as_bytes());
Ok(())
}
}

#[riot_rs::task(autostart)]
async fn run() {
use coap_handler_implementations::{HandlerBuilder, ReportingHandlerBuilder};

let log = None;
let buffer = scroll_ring::Buffer::<512>::default();
// FIXME: Why doesn't scroll_ring provide that?
struct Stdout<'a>(&'a scroll_ring::Buffer<512>);
impl<'a> core::fmt::Write for Stdout<'a> {
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
self.0.write(s.as_bytes());
Ok(())
}
}
let mut stdout = Stdout(&buffer);
use core::fmt::Write;
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 mut handler = coap_message_demos::full_application_tree(log)
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 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 {
server
.run(&mut sock, &mut handler, &mut riot_rs::random::fast_rng())
.await
.expect("UDP error")
},
run_client_operations(client),
)
.await;
writeln!(stdout, "Server is ready.").unwrap();

riot_rs::coap::coap_task(handler, Client(stdout.clone()), &mut stdout).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<const N: usize>(
client: embedded_nal_coap::CoAPRuntimeClient<'_, N>,
) {
// shame
let addr = "10.42.0.1:1234";
let demoserver = addr.clone().parse().unwrap();

use coap_request::Stack;
info!("Sending GET to {}...", addr);
let response = client
.to(demoserver)
.request(
coap_request_implementations::Code::get()
.with_path("/other/separate")
.processing_response_payload_through(|p| {
info!("Got payload {:?}", p);
}),
)
.await;
info!("Response {:?}", response.map_err(|_| "TransportError"));

let req = coap_request_implementations::Code::post().with_path("/uppercase");

info!("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| {
info!("Uppercase is {}", core::str::from_utf8(p).unwrap())
}),
);
let response = response.await;
info!("Response {:?}", response.map_err(|_| "TransportError"));
struct Client<W: core::fmt::Write + Clone>(W);

impl<W: core::fmt::Write + Clone> Client<W> {
async fn run_logging(
mut self,
client: embedded_nal_coap::CoAPRuntimeClient<'_, 3>,
) -> Result<(), &'static str> {
// shame
let demoserver = "10.42.0.1:1234"
.parse()
.map_err(|_| "Error parsing demo server address")?;

use coap_request::Stack;
writeln!(self.0, "Sending GET to {}...", demoserver).unwrap();

let response = client
.to(demoserver)
.request(
coap_request_implementations::Code::get()
.with_path("/other/separate")
.processing_response_payload_through(|p| {
writeln!(
self.0,
"Got payload {:?} length {}",
&p[..core::cmp::min(10, p.len())],
p.len()
)
.unwrap();
}),
)
.await
.map_err(|_| "Error while trying to GET /other/separate")?;
writeln!(self.0, "Response {:?}", response).unwrap();

Ok(())
}
}

impl<W: core::fmt::Write + Clone> coapcore::ClientRunner<3> for Client<W> {
/// 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(self, client: embedded_nal_coap::CoAPRuntimeClient<'_, 3>) {
let mut stdout = self.0.clone();
match self.run_logging(client).await {
Ok(_) => writeln!(stdout, "Client process completed").unwrap(),
Err(e) => writeln!(stdout, "Client process erred out: {e}").unwrap(),
}
}
}
8 changes: 8 additions & 0 deletions src/lib/coapcore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@ workspace = true
# public
coap-handler = "0.2.0"
coap-message = "0.3.2"
# public because we take a credential
lakers = { version = "0.6.0", default-features = false }
# public because the callback provides a type from there
embedded-nal-coap = "0.1.0-alpha.2"
# public because we take a socket
embedded-nal-async = "0.7"
# public because we take a RngCor
rand_core = "0.6.4"

# private
arrayvec = { version = "0.7.4", default-features = false }
Expand All @@ -32,3 +39,4 @@ liboscore-msgbackend = { git = "https://gitlab.com/oscore/liboscore/", features
], rev = "e7a4ecd037cbb9c7f085047fec5896f4bdc68d50" }
minicbor = "0.23.0"
heapless = "0.8.0"
embassy-futures = "0.1.1"
Loading
Loading