Skip to content

Conversation

carl-tud
Copy link
Contributor

@carl-tud carl-tud commented Apr 8, 2025

This PR is the first in a series to introduce unicoap, a unified and modular CoAP implementation for RIOT. An overview of all PRs related to unicoap is presented in #21389, including reasons why unicoap is needed.

What does this PR include?

  • New RIOT module unicoap, including config/Kconfig support
  • Message API of unicoap, including parsing/serializing support for RFC 7252
  • Unittests for options and parser
  • Example application showcasing the message APIs as well as parsing and serializing with unicoap
  • Structured documentation, including an article on internals and a walk-through of the sample application

The new API aims to reduce the need for in-depth protocol knowledge and minimizes necessary boilerplate. CoAP options can now be inserted in any order, which was not possible before. For example,

// Allocate options buffer with capacity of 200 bytes
UNICOAP_OPTIONS_ALLOC(options, 200);

// Use typed accessors for predefined options
unicoap_options_set_content_format(&options, UNICOAP_FORMAT_TEXT);

// Add multiple instances of repeatable options
unicoap_options_add_uri_queries_string(&options, "unit=C&tolerance=2&flag=1");

// Use generic accessors for custom options
uint8_t value[] = { 0xc0, 0xff, 0xee };
unicoap_options_add(&options, 64999, value, sizeof(value));

unicoap_message_t message;
unicoap_request_init_string_with_options(&message, UNICOAP_METHOD_POST, "Hello, World!", &options);

More in the documentation.

Lines of code (C code in sources and headers, Makefiles): ≈ 3500
plus, ≈ 5000 lines of SVG, ≈ 700 in Markdown files, ≈ 3700 lines of comments

Performance Analysis

The following figures compare unicoap with nanoCoAP in terms of execution time. Even though unicoap is more flexible, it is not necessarily slower.

Click to expand the analysis:


In this experiment, we measured the time to execute get, add/insert, and remove, given a message with a specified number of options. The results show the average time over multiple runs using the same parameter set relative to the number of existing options.

For each of the operations get, add/insert, and remove, we differentiate between a trivial case (i.e., the option is located at the end of the options buffer) and a complex case (i.e., the option is located in between other options).

The step effects occurring in (a) – (d) are artifacts of the 1 microsecond visualization resolution.

Getter

The average time needed to retrieve an option value grows linearly with the number of options present in the buffer, see (a) and (b). Both implementations require slightly less time when the option is present in the middle, see (b), because of the linear search, i.e., the algorithm finds an option in the middle earlier than at the end. The growth rate of unicoap is marginally higher in both cases because of sanity checks in unicoap.

Setter

In nanoCoAP (coap_opt_add_opaque method), when adding options, the timing is independent of the number of options already present. In unicoap, the timing scales linearly, see (c). The reason for this behavior is the following. nanoCoAP requires options to be inserted in-order and thus does not need to check whether there are adjacent options. unicoap, however, does not introduce such a requirement and, therefore, must first iterate over the list of options until the correct insertion slot is found. Moreover, unicoap implements safeguard checks to prevent adding options without sufficient buffer capacity.

Figure (d) shows the results when trailing options change and must be moved. These results do not contain data for nanoCoAP because inserting options out of order is not supported.

Remove

When removing CoAP options from message buffers, unicoap outperforms nanoCoAP, see Figures (e) and (f). On average, unicoapis faster by more than 45 microseconds. The cause of the outliers visible in Figure (f) has not been identified yet.

Parser

unicoap performs slightly better than nanoCoAP, in particular in cases of multiple options, see Figure (g).

@github-actions github-actions bot added Area: network Area: Networking Area: doc Area: Documentation Area: tests Area: tests and testing framework Area: build system Area: Build system Area: CoAP Area: Constrained Application Protocol implementations Area: sys Area: System Area: examples Area: Example Applications Area: Kconfig Area: Kconfig integration labels Apr 8, 2025
@mguetschow mguetschow added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Apr 8, 2025
@riot-ci
Copy link

riot-ci commented Apr 8, 2025

Murdock results

✔️ PASSED

5e353a3 net/unicoap: add documentation

Success Failures Total Runtime
10522 0 10522 17m:27s

Artifacts

Copy link
Member

@maribu maribu left a comment

Choose a reason for hiding this comment

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

Thanks for doing this.

It is good for getting an impression for what the goal of a PR series is if the complete code is already available. But for the actual in-depth reviewing this is way too large.

Could you split out the basic message and option parsing plus unit testing into a single PR? It would be sufficient to start with just URI-Path and maybe some numeric Option (Max-Age?) in that PR. That way a quick and thorough review of one of the basic building blocks can be done and parts of this can get upstream quickly.

/**
* @brief Marks the boundary between header and payload
*/
#define UNICOAP_PAYLOAD_MARKER (0xFF)
Copy link
Member

Choose a reason for hiding this comment

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

Defines of these constants do not contain any design decisions and can be shared between different CoAP implementations regardless of how different their design goals and use cases are. We already have sys/include/net/coap.h for such a knowledge base of constants. Please just use that and extend it as needed.

Copy link
Contributor Author

@carl-tud carl-tud Jul 2, 2025

Choose a reason for hiding this comment

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

I do prefer having everything in one place, especially if eventually, someday we're going to deprecate GCoAP, nanoCoAP, nanoCoAP Sock. Plus, having this here keeps documentation in one place. After all, what we want is a single, unified CoAP suite that does not build on other, prior CoAP modules, like GCoAP does. Referencing nanoCoAP again does not contribute -- IMO -- to that single-documentation, single-module experience I am aiming for.

@Teufelchen1
Copy link
Contributor

Teufelchen1 commented Apr 11, 2025

@carl-tud hey, the images in the performance analysis are 404 to me.

I also took the audacity to refactor your PR description a bit, to increase its accessibility.

@miri64
Copy link
Member

miri64 commented Apr 11, 2025

@carl-tud hey, the images in the performance analysis are 404 to me.

I think they are still in your private repository.

@carl-tud
Copy link
Contributor Author

@miri64 @Teufelchen1 Thanks, they should be visible now.

@miri64
Copy link
Member

miri64 commented Apr 11, 2025

Could you split out the basic message and option parsing plus unit testing into a single PR? It would be sufficient to start with just URI-Path and maybe some numeric Option (Max-Age?) in that PR.

While I like this idea, I am not sure this would make things better. The bulk of this PR is documentation, which would still be part of the basic message PR. If we go for a split, I would rather go for an opaque (byte sequence) options to keep in this PR, as they should be the easiest ones to create and parse.

@carl-tud carl-tud force-pushed the unicoap-01-parser-message branch from 879d85f to 170fefb Compare April 11, 2025 17:43
@Teufelchen1
Copy link
Contributor

How long can you / do you intend to provide maintenance for this code?

@carl-tud
Copy link
Contributor Author

How long can you / do you intend to provide maintenance for this code?

Definitely over the summer until October. After that, I think I am going to need some help (1–2 people) maintaining it. Nevertheless, if someone was willing to help from the get-go, then that would also be great.

@Teufelchen1
Copy link
Contributor

Do you happen to have a size (RAM/ROM) comparison with either nanocoap or gcoap?

@carl-tud carl-tud force-pushed the unicoap-01-parser-message branch from 1a8a3dc to 189abc4 Compare July 7, 2025 15:34
@carl-tud
Copy link
Contributor Author

carl-tud commented Jul 7, 2025

ready

@mguetschow mguetschow added this pull request to the merge queue Jul 8, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jul 8, 2025
@mguetschow mguetschow added CI: full build disable CI build filter CI: no fast fail don't abort PR build after first error CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Jul 8, 2025
@crasbe
Copy link
Contributor

crasbe commented Jul 8, 2025

I ran make -C examples/networking/coap/unicoap-message generate-Makefile.ci locally and this is the Makefile.ci it generated:

BOARD_INSUFFICIENT_MEMORY := \
    arduino-duemilanove \
    arduino-nano \
    arduino-uno \
    atmega328p \
    atmega328p-xplained-mini \
    atmega8 \
    #

@crasbe
Copy link
Contributor

crasbe commented Jul 8, 2025

@carl-tud when you add the examples/networking/coap/unicoap-message/Makefile.ci file, you can squash the commit directly.

@crasbe crasbe removed CI: full build disable CI build filter CI: no fast fail don't abort PR build after first error labels Jul 8, 2025
@carl-tud
Copy link
Contributor Author

carl-tud commented Jul 8, 2025

Okay, will do, but tomorrow

@carl-tud carl-tud force-pushed the unicoap-01-parser-message branch from 189abc4 to 5e353a3 Compare July 8, 2025 20:42
@carl-tud
Copy link
Contributor Author

carl-tud commented Jul 8, 2025

@crasbe thanks. done.

@mguetschow mguetschow enabled auto-merge July 8, 2025 22:19
@mguetschow mguetschow added this pull request to the merge queue Jul 9, 2025
Merged via the queue into RIOT-OS:master with commit fc3acd4 Jul 9, 2025
25 checks passed
@Teufelchen1
Copy link
Contributor

Congrats! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: build system Area: Build system Area: CoAP Area: Constrained Application Protocol implementations Area: doc Area: Documentation Area: examples Area: Example Applications Area: Kconfig Area: Kconfig integration Area: network Area: Networking Area: sys Area: System Area: tests Area: tests and testing framework CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants