Lightweight Named Data Networking (NDN) protocol stack for embedded systems, designed as an ESP-IDF component.
Real-time camera streaming over NDN with ESP-NOW
Features
- Full NDN packet encoding/decoding — Interest, Data, Name with TLV wire format (NDN Packet Format Specification v0.3)
- Forwarding engine — Forwarder with PIT, CS (Content Store with LRU eviction), and FIB (longest-prefix match)
- ESP-NOW Face — Zero-configuration peer-to-peer communication over ESP-NOW
- ECDSA P-256 signatures — Data signing and verification using mbedTLS
- X.509 certificate support — NDN Certificate v2 format encoding/decoding
- Link object support — Forwarding hints for multi-hop routing
- No dynamic allocation — All data structures use fixed-size arrays; no
new/delete
- No exceptions — Error handling via
Result<T> return types
- C++23 — Modern C++ with
std::optional, std::array, std::string_view
- 214 unit tests — Comprehensive test coverage with ESP-IDF Unity framework
Requirements
- ESP-IDF v5.0 or later
- Target: ESP32, ESP32-S3, ESP32-C3, or ESP32-C6
Installation
As an ESP-IDF component (recommended)
cd your_project
mkdir -p components
cd components
git clone https://github.com/sou1118/ndn-embeds.git ndn
Via ESP Component Registry
idf.py add-dependency "sou1118/ndn-embeds"
Quick Start
Consumer
extern "C" void app_main() {
ndn::initialize();
auto& fwd = ndn::getForwarder();
fwd.addFace(&face);
interest.
setName(
"/sensor/temperature")
fwd.expressInterest(interest,
printf("Received: %.*s\n",
},
printf("Timeout\n");
}
);
while (true) {
fwd.processEvents();
vTaskDelay(pdMS_TO_TICKS(10));
}
}
size_t contentSize() const
Get the content size.
const uint8_t * content() const
Get a pointer to the content data.
Error start() override
Initialize and start ESP-NOW.
void processReceiveQueue()
Process receive events.
Interest & setLifetime(uint32_t lifetimeMs)
Set the InterestLifetime.
Interest & generateNonce()
Generate and set a random Nonce.
Interest & setName(const Name &name)
Set the Name (supports method chaining)
NDN Protocol Stack for ESP32 - Main include file.
Producer
extern "C" void app_main() {
ndn::initialize();
auto& fwd = ndn::getForwarder();
fwd.addFace(&face);
fwd.registerPrefix("/sensor/temperature",
ndn::putData(data);
}
);
while (true) {
fwd.processEvents();
vTaskDelay(pdMS_TO_TICKS(10));
}
}
Data & setFreshnessPeriod(uint32_t periodMs)
Set the FreshnessPeriod.
Error setContent(const uint8_t *data, size_t size)
Set binary data as content.
Data & setName(const Name &name)
Set the Name (supports method chaining)
const Name & name() const
Get the Name (const reference)
uint16_t FaceId
Face identifier.
Architecture
block-beta
columns 1
block:app
A["Application Layer"]
end
block:api
B["NDN API Layer\nexpressInterest() / registerPrefix()"]
end
block:core
columns 4
C["TLV\nEncoder"]
D["PIT\nManager"]
E["CS\nManager"]
F["FIB\nManager"]
end
block:fwd
G["Forwarder"]
end
block:face
H["Face (Base)"]
I["EspNowFace"]
end
block:transport
J["ESP-NOW API"]
end
block:hw
K["Wi-Fi Driver"]
end
app --> api
api --> core
core --> fwd
fwd --> face
face --> transport
transport --> hw
API Overview
Constraints
| Resource | Limit |
| ESP-NOW max payload | 250 bytes |
| Name max length | 128 bytes |
| Name max components | 10 |
| Data max content size | 200 bytes |
| PIT entries | 50 |
| CS entries | 20 |
| FIB entries | 30 |
| Interest default lifetime | 4000 ms |
Documentation
API documentation is available at **https://sou1118.github.io/ndn-embeds/**
Generated automatically from source comments using Doxygen on each push to main.
Running Tests
cd test_app
idf.py set-target esp32s3
idf.py build
idf.py -p /dev/ttyUSB0 flash monitor
License
Apache License 2.0. See [LICENSE](LICENSE) for details.