Skip to content

feat(coap): envelope ↔ CoAP payload translation#40

Merged
rodrigopex merged 1 commit into
mainfrom
feat/30-coap-translate
May 21, 2026
Merged

feat(coap): envelope ↔ CoAP payload translation#40
rodrigopex merged 1 commit into
mainfrom
feat/30-coap-translate

Conversation

@rodrigopex
Copy link
Copy Markdown
Owner

Summary

Phase 2 of the CoAP-frontend umbrella (#27). Adds the pure, transport-free envelope ↔ CoAP payload translation layer plus the return_code → CoAP class mapping table. No dependency on coap_service, sockets, or zbus — the helpers operate on raw buffers and pre-initialised struct coap_packet instances, so they are unit-testable in isolation.

Wire format

Request and response bodies are nanopb-encoded protobuf messages described by the same pb_msgdesc_t descriptors the per-zephlet _interface.c already references. Content-Format ZEPHLET_COAP_CT_NANOPB (65001) tags outbound payloads; the verbatim raw POSIX errno rides every response via custom option ZEPHLET_COAP_OPT_ERRNO (65052) so the (lossy) class mapping never erases the precise handler return code.

What landed

  • frontends/coap/include/zephlet_coap_translate.h — public API: zephlet_coap_map_return_code, _decode_request, _encode_response.
  • frontends/coap/zephlet_coap_translate.c — implementation.
  • frontends/coap/include/zephlet_coap_types.hstruct zephlet_coap_method gains req_max_size / resp_max_size (size_t) — codegen-emitted, see below.
  • codegen/templates/zephlet_coap_interface.c.jinja — emits the two new fields from nanopb's compile-time <MSG>_SIZE macros (zero for Empty).
  • frontends/coap/CMakeLists.txt — adds the new TU to the frontend library.
  • tests/coap_translate/ — new twister target (harness: ztest, mps2/an385 + native_sim) with a tiny local test_msg.proto. Compiles zephlet_coap_translate.c directly so the test does not have to enable CONFIG_ZEPHLETS_COAP (no networking/sockets pulled in).

Why codegen-derived per-method bounds vs. a Kconfig cap

The decoder enforces len > m->req_max_size → -EMSGSIZE (→ 4.13). The bound is the exact nanopb-computed maximum encoded size of the method's request message, so an Empty-typed method rejects any inbound body through the same path (req_max_size == 0). No single tuning knob to keep in sync with the protos — adding a method whose nanopb size exceeds the old default would have been a silent regression.

return_code → CoAP class table

rc class
0 (with payload) 2.05 Content
0 (no payload) 2.04 Changed
-EINVAL 4.00 Bad Request
-ENODEV 4.04 Not Found
-ENOSYS 4.05 Method Not Allowed
-EALREADY 4.09 Conflict
-EMSGSIZE 4.13 Request Entity Too Large
-EBUSY / -EAGAIN 5.03 Service Unavailable
-ETIMEDOUT 5.04 Gateway Timeout
-ENOMEM / any other negative 5.00 Internal Server Error

-EMSGSIZE → 4.13 was the only addition vs. the plan's locked-decisions table — confirmed EMSGSIZE is defined in zephyr/lib/libc/minimal/include/errno.h:106.

Test results (local, mps2/an385 + QEMU 10.0.2)

  • New tests/coap_translate/: 22/22 ztest cases pass in 0.014s.
  • Existing tests/codegen/ pytest suite: 6/6 pass (codegen-template change validated).
  • Existing app integration suite (tick / ui / tampering): 23/23 pass.
  • App build with CONFIG_ZEPHLETS_COAP=n (default): clean — =n section-hash gate inherits unchanged because the new TU only compiles under =y.

Out of scope (deferred to later phases)

Test plan

  • west twister tests/coap_translate green (mps2/an385).
  • tests/codegen/ pytest green (codegen template regression).
  • App build clean with CONFIG_ZEPHLETS_COAP=n.
  • App just test green (no integration-test regression).

Closes #30

Pure transport-free decode/encode helpers + return_code → CoAP class
mapping table for the CoAP frontend. No dependency on coap_service,
sockets, or zbus — the helpers operate on raw buffers and pre-
initialised struct coap_packet instances, so they are unit-testable
in isolation.

Codegen now emits per-method req_max_size / resp_max_size from
nanopb's compile-time <MSG>_SIZE constants, so the decoder enforces
the exact per-method envelope (no global Kconfig cap) and the
Phase 3 dispatcher can size per-type response scratch from a single
codegen-derived ceiling.

Test target tests/coap_translate/ (harness: ztest, mps2/an385 +
native_sim) covers: the full mapping table (success ± payload,
each mapped errno, default 5.00 fallback), decode happy/malformed/
oversize/empty paths, and encode for resp-present / resp-empty /
zero-encoded / errno-verbatim cases.

Refs #30
@rodrigopex rodrigopex force-pushed the feat/30-coap-translate branch from 8b1afc9 to bd2944f Compare May 21, 2026 14:23
@rodrigopex rodrigopex merged commit 82deb64 into main May 21, 2026
4 checks passed
@rodrigopex rodrigopex deleted the feat/30-coap-translate branch May 21, 2026 14:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(coap): Phase 2 — envelope ↔ CoAP payload translation (pure)

1 participant