Skip to content

Commit f68c451

Browse files
WaylandYangclaude
andcommitted
fix: correct firmware footprint to measured 27.6 KB flash / 0.6 KB RAM
The "~14 KB" DCP-layer footprint claimed across the README, paper, firmware docs, and figures was never backed by a reproducible measurement — the README even referenced a measurement script that did not exist. This commit measures it properly and corrects every public claim. New: docs/paper/figures/measure_footprint.py compiles a baseline empty Arduino sketch and the lamp example with the same FQBN and differences them. Result, written to footprint_data.json: baseline empty sketch : 266,740 B flash / 22,068 B globals lamp example (w/ DCP) : 295,007 B flash / 22,712 B globals DCP layer delta : 28,267 B flash / 644 B globals = 27.6 KB flash / 0.6 KB RAM So the DCP layer is 27.6 KB of flash, not ~14 KB. The "~14 KB" was an optimistic pre-measurement estimate, most likely from before the on-device HMAC-SHA256 path (DCPCrypto) was added. The flash figure is above the original <16 KB design target; the target predates on-device crypto and is not met. Reported honestly as such. The RAM figure is the good news: 0.6 KB. That is the number worth leading with — RAM is the scarce resource on an MCU, and for context IoT-MCP reports 74 KB peak memory. Corrected across: - README.md: intro tagline, "Validated on real hardware" section, footprint figure caption - docs/paper/main.tex: abstract, footprint paragraph, fig:footprint text + caption, and the IoT-MCP comparison (was "roughly 1/5 the memory" — now the measured 0.6 KB vs 74 KB) - docs/RATIONALE.md, firmware/esp32/README.md, firmware/esp32/src/DCP.cpp comment, docs/QUICKSTART_VIDEO.md, .github/RELEASE_NOTES_v0.3.0.md - CHANGELOG.md: new Fixed entry; dropped an unverified "~1 KB of code" claim for DCPCrypto - figures/README.md: footprint marked measured fig_footprint() rewritten: was a 4-protocol synthetic flash+RAM matrix with the DCP bar hatched as "target". Now an honest 2-bar static-RAM comparison — DCP's measured 0.6 KB vs IoT-MCP's reported 74 KB peak memory, the one RAM-vs-RAM axis the two projects can be compared on. Flash is stated in text, not plotted: IoT-MCP reports no flash figure. arch diagram device label "< 16 KB MCU" -> "commodity MCU". social_preview hero stat "<16 KB firmware" -> "<1 KB of RAM". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 37e7d8d commit f68c451

18 files changed

Lines changed: 239 additions & 73 deletions

.github/RELEASE_NOTES_v0.3.0.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ future work (see `docs/RATIONALE.md §7` and `docs/paper/main.tex §7`).
1414
- **10 / 10** round-trip tests pass against ESP32-WROOM-32 (CH340, 115 200 baud)
1515
- **Frame size:** 19 bytes for a typical `set_brightness(50)` call;
1616
35 bytes with the optional HMAC tail
17-
- **Firmware footprint:** ~14 KB of pure DCP over an empty Arduino sketch
17+
- **Firmware footprint:** the DCP layer measures 27.6 KB flash and
18+
0.6 KB RAM over an empty Arduino sketch (measured)
1819
- **Five transports** ship: loopback, UART (COBS + CRC-16), MQTT,
1920
BLE GATT, in-process simulator. Plus the MCP server wrapper that
2021
surfaces every intent to any MCP host

CHANGELOG.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ it reaches 1.0. Pre-1.0 releases may break compatibility.
1414
optional 16-byte truncated signature appended to every frame. Both Bridge
1515
and device must agree; no in-band downgrade marker by design.
1616
- **Self-contained SHA-256 + HMAC-SHA256** in the ESP32 firmware
17-
(`DCPCrypto.h`/`.cpp`) — no mbedtls/ESP-IDF dependency, ~1 KB of code.
17+
(`DCPCrypto.h`/`.cpp`) — no mbedtls/ESP-IDF dependency.
1818
- **DCPBle**: ESP32 BLE peripheral via NimBLE-Arduino. Same intent table as
1919
`DCP`; one service, c2d/d2c characteristics derived from service UUID by
2020
convention (`0xC1` / `0xD1` last byte).
@@ -28,6 +28,21 @@ it reaches 1.0. Pre-1.0 releases may break compatibility.
2828

2929
- `Bridge` constructor takes `wire_secret=` for per-frame signing.
3030

31+
### Fixed
32+
33+
- **Footprint numbers corrected to measured values.** Earlier docs
34+
claimed the DCP layer was "~14 KB" of flash and cited a `<16 KB`
35+
design target. A reproducible measurement
36+
(`docs/paper/figures/measure_footprint.py`, differencing the lamp
37+
example against an empty Arduino sketch) shows the DCP layer is
38+
**27.6 KB of flash and 0.6 KB of RAM** on ESP32. The flash figure is
39+
above the original `<16 KB` target — the target predated the
40+
on-device HMAC-SHA256 path — and is now reported as measured across
41+
the README, paper, and firmware docs. The RAM figure (0.6 KB) came in
42+
well under target.
43+
- **Latency figure is now measured**, not illustrative
44+
(`tools/bench_latency.py`, 1000 round-trips per transport).
45+
3146
## [0.2.0] - 2026-05-12
3247

3348
### Added

README.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
> down to dollar-class microcontrollers.
1111
>
1212
> Intent-level, transport-agnostic, capability-scoped. Compact wire format
13-
> (sub-50-byte frames). Self-contained firmware under 16 KB.
13+
> (sub-50-byte frames). Self-contained firmware: under 1 KB of RAM,
14+
> ~28 KB of flash.
1415
>
1516
> Complementary to [MCP](https://modelcontextprotocol.io) — a reference
1617
> Bridge translates DCP ↔ MCP so any MCP host (Claude Desktop, Claude Code,
@@ -80,19 +81,23 @@ and an ESP32-S3 (LILYGO T-Panel S3) over the S3's native USB-Serial/JTAG
8081

8182
- 13/13 round-trip tests pass on each board (`tools/test_uart_roundtrip.py`)
8283
- 88/88 Python unit & conformance tests pass
83-
- Compiled firmware: 294 KB flash, 22.7 KB globals on WROOM-32;
84-
322 KB / 22.7 KB on the S3 (Arduino-ESP32 core 3.3.8)
85-
- The pure DCP layer is approximately 14 KB over a baseline empty
86-
sketch (measurement script in `docs/paper/figures/`)
84+
- Full lamp firmware: 295 KB flash, 22.7 KB globals on WROOM-32 — most
85+
of which is the Arduino-ESP32 runtime + FreeRTOS, not DCP
86+
- **The DCP layer itself measures 27.6 KB of flash and 0.6 KB of RAM**
87+
over a baseline empty sketch — reproduce with
88+
`docs/paper/figures/measure_footprint.py`. The flash figure is over
89+
the original `<16 KB` design target (set before on-device HMAC was
90+
added); the RAM figure is well under it.
8791
- The S3 run also exercises DCP over a native-USB CDC link rather
8892
than a USB-UART bridge chip — same firmware, no transport-specific
8993
code
9094

91-
![Memory footprint: DCP target vs IoT-MCP measured vs Direct MCP vs Matter](docs/paper/figures/footprint.png)
95+
![Static RAM footprint: measured DCP layer vs IoT-MCP reported peak memory](docs/paper/figures/footprint.png)
9296

93-
*DCP design target sits roughly 5× under IoT-MCP and 20× under Matter on
94-
the same class of MCU. Hatched bars are design targets, plain bars are
95-
measured / typical of the cited sources.*
97+
*Static RAM is the scarce resource on an MCU. The DCP layer's measured
98+
0.6 KB of RAM sits two orders of magnitude under IoT-MCP's reported
99+
74 KB peak memory. DCP's flash cost (27.6 KB, measured) is not plotted
100+
— IoT-MCP does not report a comparable flash figure.*
96101

97102
See [docs/RATIONALE.md §7](docs/RATIONALE.md) for what the hardware
98103
validation does and does not prove.

docs/QUICKSTART_VIDEO.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ dcp::Status handle_set_brightness(uint8_t kind, dcp::CborReader& p, ...) {
100100
}
101101
```
102102

103-
> "And the device side is plain C++. CBOR map in, action out. Under 16 KB
104-
> of flash on a $5 ESP32."
103+
> "And the device side is plain C++. CBOR map in, action out. The DCP
104+
> layer is 27.6 KB of flash and under 1 KB of RAM on a $5 ESP32."
105105

106106
## Live demo (2:10 – 3:30)
107107

docs/RATIONALE.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,12 @@ out of the box.
3636

3737
The decisive numbers are RAM and code size. A minimal MCP-over-WebSocket
3838
implementation on ESP32 lands around 80–120 KB of code and tens of KB of
39-
working RAM. DCP's reference firmware targets <16 KB of flash and <2 KB of
40-
RAM. **That difference is the difference between every IoT device and only
41-
the expensive ones.**
39+
working RAM. DCP's reference firmware measures 27.6 KB of flash and
40+
0.6 KB of RAM (the DCP layer over a baseline empty sketch — the flash
41+
came in above the original <16 KB target once on-device HMAC was added;
42+
the RAM came in well under). **That RAM difference — under 1 KB versus
43+
tens of KB — is the difference between every IoT device and only the
44+
expensive ones.**
4245

4346
## Why not W3C Web of Things (WoT)?
4447

docs/paper/figures/README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ README / web preview) into this directory.
3232
`latency_data.json`, produced by `tools/bench_latency.py`: 1000 timed
3333
round-trips per transport, median + IQR. Currently covers loopback,
3434
ESP32-WROOM-32 (CH340), and ESP32-S3 (native USB).
35-
- **Fig. 3 (footprint)** — partially synthetic. The DCP bar is a design
36-
target; the IoT-MCP / Direct-MCP / Matter bars are cited or typical.
37-
Needs a rework: the DCP layer is now measured (~14 KB over an empty
38-
sketch) and the figure should distinguish measured-DCP from cited
39-
baselines cleanly, including the flash-vs-RAM axis.
35+
- **Fig. 3 (footprint)****measured.** `fig_footprint()` reads
36+
`footprint_data.json`, produced by `measure_footprint.py`: the DCP
37+
layer is 27.6 KB flash / 0.6 KB RAM over a baseline empty sketch. The
38+
figure plots DCP's measured static RAM against IoT-MCP's reported
39+
74 KB peak memory — the one apples-to-apples (RAM-vs-RAM) comparison
40+
available. IoT-MCP does not report a flash figure, so flash is given
41+
in text, not plotted.
4042
- **Fig. 4 (hallucination)** — synthetic, and labelled as such in the
4143
figure footnote. Making it real needs an LLM adversarial-call
4244
benchmark (≈1000 generated calls per baseline, with a defined

docs/paper/figures/arch.pdf

-1.4 KB
Binary file not shown.

docs/paper/figures/arch.png

266 Bytes
Loading

docs/paper/figures/footprint.pdf

19.7 KB
Binary file not shown.

docs/paper/figures/footprint.png

12.6 KB
Loading

0 commit comments

Comments
 (0)