Skip to content

Commit

Permalink
feat(coap): Allow independently getting a CoAP client
Browse files Browse the repository at this point in the history
  • Loading branch information
chrysn committed Oct 30, 2024
1 parent e33094c commit 41571dc
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 25 deletions.
19 changes: 6 additions & 13 deletions examples/coap/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,11 @@ async fn coap_run() {
coap_scroll_ring_server::BufferHandler::new(&buffer),
);

let client_signal = embassy_sync::signal::Signal::new();

// going with an embassy_futures join instead of RIOT-rs's spawn b/c CoAPShared is not Sync.
// going with an embassy_futures join instead of RIOT-rs's spawn to avoid the need for making
// stdout static.
embassy_futures::join::join(
riot_rs::coap::coap_run(handler, &client_signal),
run_client_operations(&client_signal, stdout),
riot_rs::coap::coap_run(handler),
run_client_operations(stdout),
)
.await;
}
Expand All @@ -48,14 +47,8 @@ async fn coap_run() {
///
/// 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_in: &embassy_sync::signal::Signal<
embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex,
&'static embedded_nal_coap::CoAPRuntimeClient<'static, 3>,
>,
mut stdout: impl core::fmt::Write,
) {
let client = client_in.wait().await;
async fn run_client_operations(mut stdout: impl core::fmt::Write) {
let client = riot_rs::coap::coap_client().await;

// shame
let addr = "10.42.0.1:1234";
Expand Down
45 changes: 33 additions & 12 deletions src/riot-rs-coap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,24 @@ mod udp_nal;
use coap_handler_implementations::ReportingHandlerBuilder;
use coapcore::seccontext;
use embassy_net::udp::{PacketMetadata, UdpSocket};
use embassy_sync::once_lock::OnceLock;
use riot_rs_debug::log::*;
use riot_rs_embassy::sendcell::SendCell;
use static_cell::StaticCell;

const CONCURRENT_REQUESTS: usize = 3;

static CLIENT: OnceLock<
SendCell<embedded_nal_coap::CoAPRuntimeClient<'static, CONCURRENT_REQUESTS>>,
> = OnceLock::new();

// 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,
client_out: &embassy_sync::signal::Signal<
embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex,
&'static embedded_nal_coap::CoAPRuntimeClient<'static, CONCURRENT_REQUESTS>,
>,
) -> ! {
///
/// As the CoAP stack gets ready, it also unblocks [`coap_client`].
pub async fn coap_run(handler: impl coap_handler::Handler + coap_handler::Reporting) -> ! {
let stack = riot_rs_embassy::network::network_stack().await.unwrap();

// FIXME trim to CoAP requirements
Expand Down Expand Up @@ -74,12 +76,11 @@ pub async fn coap_run(

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);
CLIENT
.init(SendCell::new_async(client).await)
.ok()
.expect("CLIENT can not be populated when COAP was just not populated.");

server
.run(
Expand All @@ -91,3 +92,23 @@ pub async fn coap_run(
.expect("UDP error");
unreachable!("embassy-net's sockets do not get closed (but embedded-nal-coap can't know that)");
}

/// Get a CoAP client requester.
///
/// This asynchronously blocks until [`coap_run`] has been called, and the CoAP stack is
/// operational.
///
/// ## Panics
///
/// This is currently only available from the thread that hosts the network stack, and panics
/// otherwise. This restriction will be lifted in the future (by generalization in
/// [`embedded_nal_coap`] to allow different mutexes).
pub async fn coap_client(
) -> &'static embedded_nal_coap::CoAPRuntimeClient<'static, CONCURRENT_REQUESTS> {
CLIENT
.get()
.await
.get_async()
.await // Not an actual await, just a convenient way to see which executor is running
.expect("CoAP client can currently only be used from the thread the network is bound to")
}

0 comments on commit 41571dc

Please sign in to comment.