1 unstable release
0.3.0 | Feb 16, 2024 |
---|
#999 in Embedded development
240KB
4.5K
SLoC
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)
- RFC 7641 - Observing Resources in the Constrained Application Protocol (CoAP)
- RFC 7959 - Block-Wise Transfers in the Constrained Application Protocol (CoAP)
- RFC 8132 - PATCH and FETCH Methods for the Constrained Application Protocol (CoAP)
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.
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 as coap test server. The lwm2m example shows the usage in the lightweight m2m context using the Leshan 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 - embedded-rust@iml.fraunhofer.de
Dependencies
~3MB
~63K SLoC