// Copyright Open Logistics Foundation // // Licensed under the Open Logistics Foundation License 1.3. // For details on the licensing terms, see the LICENSE file. // SPDX-License-Identifier: OLFL-1.3 //! This example attempts to connect to the public leshan lwm2m test server at //! with the endpoint name "coap_zero_example". //! After registration, it can be controlled at //! . //! //! It will provide one instance of a time object //! (3333, ) //! with the only mandatory field "current time". This object can be accessed at //! . //! //! The example will run and reply to a GET on the current time resource. //! Other requests will be answered with [ServerErrorCode::NotImplemented]. //! //! After 120 seconds, the logical lwm2m connection will be closed (no update implemented in this example), //! but the example will still run until terminated by hand. use std::{ fs::File, io::Read, time::{Duration, SystemTime}, }; use coap_zero::{ endpoint::{CoapEndpoint, TransmissionParameters}, message::{ codes::RequestCode, options::{CoapOption, CoapOptionName}, }, }; use embedded_timers::clock::{Clock, ClockError, Instant}; use heapless::Vec; use std_embedded_nal::Stack; #[derive(Debug)] pub struct Random; impl embedded_hal::blocking::rng::Read for Random { type Error = std::io::Error; fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> { File::open("/dev/urandom")?.read_exact(buf) } } #[derive(Debug)] struct SystemClock; impl Clock for SystemClock { fn try_now(&self) -> Result { SystemTime::now().elapsed().map_err(|_| ClockError::Unknown) } } static CLOCK: SystemClock = SystemClock; fn main() { simple_logger::SimpleLogger::new().env().init().unwrap(); let mut stack = Stack::default(); let mut receive_buffer = [0_u8; coap_zero::DEFAULT_COAP_MESSAGE_SIZE]; let mut endpoint: CoapEndpoint< '_, Stack, Random, SystemClock, 8, // OptionCount 32, // OptionSize 128, // IncomingCommunicationBuffer 128, // OutgoingCommunicationBuffer //{ coap_zero::DEFAULT_COAP_MESSAGE_SIZE }, // ReceiveBuffer > = CoapEndpoint::try_new( TransmissionParameters::default(), Random {}, &CLOCK, &mut receive_buffer, ) .unwrap(); endpoint .connect_to_url(&mut stack, "coap://leshan.eclipseprojects.io:5683") .unwrap(); let uri_path = CoapOption { name: CoapOptionName::UriPath, value: b"rd", }; let content_format = CoapOption { name: CoapOptionName::ContentFormat, value: &[0x28_u8], }; let query_lwm2m_version = CoapOption { name: CoapOptionName::UriQuery, value: b"lwm2m=1.0", }; let query_endpoint_name = CoapOption { name: CoapOptionName::UriQuery, value: b"ep=coap_zero_example", }; let query_lifetime = CoapOption { name: CoapOptionName::UriQuery, value: b"lt=120", }; let mut options_vec: heapless::Vec, { coap_zero::DEFAULT_MAX_OPTION_COUNT }> = heapless::Vec::new(); options_vec.push(uri_path).unwrap(); options_vec.push(content_format).unwrap(); options_vec.push(query_lwm2m_version).unwrap(); options_vec.push(query_endpoint_name).unwrap(); options_vec.push(query_lifetime).unwrap(); let payload = b""; endpoint .outgoing() .schedule_con( RequestCode::Post, options_vec, Some(&payload[..]), Duration::from_secs(5), ) .unwrap(); loop { std::thread::sleep(Duration::from_millis(25)); let (in_event, _outgoing, _endpoint) = endpoint.process(&mut stack).unwrap(); use coap_zero::endpoint::incoming::IncomingEvent::*; match in_event { Ok(Request(_confirmable, message)) => { log::info!("incoming state: Received"); let uri_path_segments: std::vec::Vec = message .options_iter() .unwrap() .map(|o| o.unwrap()) .filter(|o| o.name == CoapOptionName::UriPath) .collect(); // We need to check if we get a Get for 3333/0/5506 // Others will be answered with 5.01 (Not Implemented) if uri_path_segments.len() == 3 && uri_path_segments[0].value == b"3333" && uri_path_segments[1].value == b"0" && uri_path_segments[2].value == b"5506" { let now = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .unwrap(); let payload = format!("{}", now.as_secs()); let content_format: CoapOption<'_> = CoapOption { name: CoapOptionName::ContentFormat, value: &[0_u8], // Text }; let mut additional_options: heapless::Vec< CoapOption<'_>, { coap_zero::DEFAULT_MAX_OPTION_COUNT }, > = heapless::Vec::new(); additional_options.push(content_format).unwrap(); endpoint .incoming() .schedule_response( coap_zero::message::codes::SuccessCode::Content.into(), additional_options, Some(payload.as_bytes()), ) .unwrap(); } else { endpoint .incoming() .schedule_response( coap_zero::message::codes::ServerErrorCode::NotImplemented.into(), Vec::new(), None, ) .unwrap(); } } Ok(Nothing) => {} Ok(ev) => { log::info!("Event received: {ev:?}"); } Err(e) => { log::warn!("Error: {e:?}"); } } } }