Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,14 @@ engine.begin(cfg); // begins normally; begin() clamps automatically

`validateConfig()` is a free inline function in the `politician` namespace — zero allocations, zero dependencies.

`begin()` rejects a smart-hopping configuration whose minimum dwell cannot be
represented after the `min + 50 ms` correction. Calling `begin()` on an already
initialized engine stops the previous runtime first, so rebegin is deterministic.
Calling `stop()` is safe more than once; it disables capture, unregisters the
instance, and releases the worker resources. The destructor also stops an active
engine. WiFi driver ownership remains process-wide and is reused by later
instances.

### Configuration

```cpp
Expand Down Expand Up @@ -291,6 +299,26 @@ void setPacketLogger(PacketCb cb); // Raw promiscuous-mode frames
void setLogger(LogCb cb); // Redirect internal log output
```

Callbacks run on the engine worker task while the engine state is protected.
They should do short, non-blocking work and must not call blocking Politician
methods or retain references to callback records. In particular,
`EspNowRecord::payload` points into the current receive buffer and is valid only
for the duration of the callback; copy it when it must outlive the callback.

ESP-NOW capture is enabled by default unless `POLITICIAN_NO_ESPNOW` is defined.
The parser accepts Espressif vendor-specific action frames and reports the
source, destination, channel, RSSI, timestamp, and payload through
`setEspNowCallback()`.

### Regulatory domain

Regulatory-domain selection is intentionally not implemented yet. The current
channel helper contains common 2.4 GHz and 5 GHz channels but has no authoritative
country source, DFS/CAC state, or API for selecting a country. A future change
should add an explicit country/domain configuration backed by the ESP-IDF WiFi
country API, filter channels from that result, and define behavior for DFS and
unsupported regions before exposing it publicly.

### Engine Control

```cpp
Expand Down
46 changes: 46 additions & 0 deletions docs/delivery/ChangeSummary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Change Summary

## Changes

- Added `EspNowCapture` to the example build matrix and restored its example.
- Added the ESP-NOW callback record/parser contract.
- Added deterministic host-side `Config` validation tests.
- Added idempotent stop/rebegin cleanup for per-instance task, ring buffer, and
mutex resources.
- Made `begin()` transactional after instance registration, including Wi-Fi
driver teardown when that attempt initialized Wi-Fi.
- Added an ISR-safe shutdown barrier: registry removal and shutdown marking are
serialized, in-flight callbacks drain, and the worker exits before its
ringbuffer and mutex are destroyed.
- Removed the duplicate `[env:esp32]` section from `EspNowCapture`.
- Masked ESP-NOW MACs and disabled payload printing by default in the example;
complete payload diagnostics are compile-time opt-in.
- Documented lifecycle and callback contracts.

## Breaking Changes

None. Existing public methods and callback signatures remain compatible.

## Migration Scope

None. ESP-NOW is available by default and can be excluded with
`POLITICIAN_NO_ESPNOW`.

## Rollback Strategy

Revert the commits in reverse order. No database, persistent storage, or
external state migration is introduced.

## Known Limitations

- PlatformIO is not installed in the local environment, so ESP32 builds were
not run locally.
- Regulatory-domain selection is documented as a proposal only.
- The host test covers public configuration validation, not ESP32 FreeRTOS
scheduling or WiFi-driver behavior.
- PlatformIO is unavailable in the local environment; the native test was
compiled and executed directly with Clang, while the ESP32 example build was
not run locally.
- `stop()` must not be called from a Politician callback running on the worker
task, because waiting for that same worker would deadlock. Callbacks should
signal application state and let the main/application task perform stop.
26 changes: 26 additions & 0 deletions docs/delivery/ImplementationPlan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Implementation Plan

Base: `upstream/main`
Branch: `feat/core-reliability`

1. Add the existing ESP-NOW capture example to the PlatformIO CI matrix.
2. Add deterministic host-side coverage for public `Config` validation without
including Arduino or ESP32 runtime headers.
3. Preserve the public API while making `begin()` validation reject an unsafe
dwell correction and making stop/rebegin release per-instance runtime
resources.
4. Document lifecycle, callback lifetime/threading constraints, compatibility,
and the regulatory-domain proposal.

Security remediation completed on the current branch:

5. Make `begin()` roll back registry, Wi-Fi, mutex, ringbuffer, and worker
resources on every post-registration failure.
6. Make `stop()` mark shutdown and unregister under an ISR-safe critical
section, wait for in-flight callbacks, then wait for the worker before
deleting the ringbuffer and mutex.
7. Keep the ESP-NOW example's MAC output masked and payload output disabled by
default. Full payload diagnostics require `ESP_NOW_DIAGNOSTICS=1`.

Regulatory-domain behavior remains intentionally out of scope until a country
source and DFS policy can be defined safely.
Loading
Loading