# coap-zero This crate provides a heapless `no_std` implementation for the CoAP protocol. It aims to be zero-copy as much as feasible without sacrificing usability too much. The implemented CoAP endpoint implements automatic retransmissions for reliable message transmission (for confirmable messages) and message de-duplication. The endpoint automatically responds to specific messages, e.g. it sends out reset messages when appropriate or retransmits the last response if a duplicated request is detected. The implementation is fixed to NSTART=1, i.e. only a single incoming request and a single outgoing request may be processed at the same time. Currently, only the base CoAP specification is implemented. In the future, it is planned to also support CoAP Observe which is required for LwM2M, the PATCH, FETCH and iPATCH methods which significantly improve LwM2M capabilities and Block-Wise transfers which are required for firmware upgrades in LwM2M. ## Resources - [RFC 7252 - The Constrained Application Protocol (CoAP)](https://www.rfc-editor.org/rfc/rfc7252) - [RFC 7641 - Observing Resources in the Constrained Application Protocol (CoAP)](https://www.rfc-editor.org/rfc/rfc7641) - [RFC 7959 - Block-Wise Transfers in the Constrained Application Protocol (CoAP)](https://www.rfc-editor.org/rfc/rfc7959) - [RFC 8132 - PATCH and FETCH Methods for the Constrained Application Protocol (CoAP)](https://www.rfc-editor.org/rfc/rfc8132.html) ## Usage The main structure is the `coap_zero::endpoint::CoapEndpoint` type. It manages the connection to another coap endpoint via an `embedded_nal::UdpClientStack` (not owned). It contains two separate types, `OutgoingCommunication` and `IncomingCommunication`, to handle the two communication paths separately. All operations are driven by internal state machines. Therefore, all calls are non-blocking and the user has to call the `CoapEndpoint::process` method repeatedly in order to send/receive CoAP messages. Whenever one of the state machines makes progress, a corresponding event is returned. Some events _must_ be handled by the user in order to not get stuck in a specific wait state. For example, an incoming request _must_ be responded to by the user although this decision may be postponed or may involve sending a reset message. If only message parsing is required, the message submodule can be used. ## Usage Example For more detailed examples, refer to the examples in the examples folder. ```rust static CLOCK: SystemClock = SystemClock; let mut stack = Stack; let mut receive_buffer = [0_u8; coap_zero::DEFAULT_COAP_MESSAGE_SIZE]; let mut endpoint: CoapEndpoint<'_, Stack, Rng, SystemClock> = CoapEndpoint::try_new( TransmissionParameters::default(), Rng, &CLOCK, &mut receive_buffer, ) .unwrap(); endpoint .connect_to_url(&mut stack, "coap://coap.me:5683") .unwrap(); let outgoing = endpoint.outgoing(); outgoing .schedule_con( RequestCode::Get, outgoing .parse_options("coap://coap.me:5683/hello", Vec::new()) .unwrap(), None, Duration::from_secs(5), ) .unwrap(); loop { let (incoming_event, outgoing_event, endpoint_event) = endpoint.process(&mut stack).unwrap(); match incoming_event.unwrap() { IncomingEvent::Nothing => { // Whenever nothing else happens, the Nothing event is generated. Ignore it // silently. } IncomingEvent::Request(_confirmable, _message) => { // Handle request } event => println!("Other incoming event: {event:?}"), } match outgoing_event.unwrap() { OutgoingEvent::Nothing => {} OutgoingEvent::Success(response) => println!("Request succeeded: {response:?}"), OutgoingEvent::Timeout | OutgoingEvent::PiggybackedWrongToken | OutgoingEvent::ResetReceived => { println!("Request failed"); } event => println!("Other outgoing event: {event:?}"), } match endpoint_event { EndpointEvent::Nothing => {} EndpointEvent::MsgFormatErr(_err) => { // A message format error was detected. This is reported as an event instead of // an error because it is caused by the other endpoint. println!("endpoint event MsgFormatErr"); } EndpointEvent::Ping => { println!("A ping has been received and a response has been sent"); } EndpointEvent::Unhandled(message) => { println!("Unhandled message received: {message:?}"); } } } ``` ## Examples Multiple examples are provided. They use [coap.me](https://coap.me/) as coap test server. The lwm2m example shows the usage in the lightweight m2m context using the [Leshan](https://leshan.eclipseprojects.io) public test server. - ping - Sends a ping and terminates when the expected reset was received - simple_get - Sends a CON Get and receives a piggy-backed response - get_separate_response - Sends a CON Get and received a separate response - lwm2m - Registers to the leshan server and supplies the time object current time resource. The registration won't update and will be silently closed after 120 seconds. ## License Open Logistics Foundation License\ Version 1.3, January 2023 See the LICENSE file in the top-level directory. ## Contact Fraunhofer IML Embedded Rust Group -