2 Commits
Author SHA1 Message Date
Ashin Walpola ca57e5702b Flashing notes: first flash of the signed firmware, and the way back
FLASHING.md still described flashing as for the previous firmware. The port
changed the partition table (NVS 24 KB -> 80 KB, app 0x10000 -> 0x20000), so a
board coming from the previous firmware needs its NVS range erased once and a
full flash, not app-flash; without the erase the BLE bond cannot be stored and
the phone pairs on every connection. Documented that, what the boot log and
the app show afterwards (credentials provisioned on first Connect, stale phone
pairings to forget), both ways back to the previous firmware (the backup image,
or commit 7285fa1 built with IDF 6.1), the production board's port (COM3,
UART bridge), and the station-link names in the phone and bring-up sections.
2026-09-23 18:14:41 +02:00
Ashin Walpola 0e9525162d Keep the colleague's microbu-esp32c5 tree in this repository
obu-firmware builds against vanetza-idf from microbu-esp32c5/external, but
that tree was gitignored, so a clone of this repository could not build the
firmware it ships. It is now committed here as ordinary files in its own
folder, microbu-esp32c5/: the colleague's commit cf4b99f plus the V2X2MAP
bridge's signature verification (--trust) used on the bench. Nothing is
fetched from or pushed to the colleague's repository; this repository and
its remotes carry everything. The folder's own .gitignore keeps build output,
downloaded components and private key material out, as it did there; the
committed file set is identical to that repository's tracked files.

The ESP32-C5 is still flashed from obu-firmware/, which only takes
vanetza-idf from microbu-esp32c5/, so the two stay separate folders.
FLASHING.md says how to take a newer version of the colleague's tree (copy
it over the folder, rebuild, test, commit).
2026-09-23 17:46:40 +02:00
9885 changed files with 22078 additions and 37 deletions
-9
View File
@@ -54,12 +54,3 @@ sdkconfig.old
# ESP-IDF component manager downloads (espressif/esp-boost for obu-firmware's vanetza-idf), ~125 MB.
# dependencies.lock beside the project pins them and is committed; this is its cache.
managed_components/
# The colleague's standalone ESP32-C5 VRU station (its own repository, HAW GitLab
# urban-mobility-lab/microbu/microbu-esp32c5). Kept beside the project on the lab laptop, for
# reference and because the V2X2MAP bridge runs from its tools/, but not part of this repository:
# obu-firmware only needs its vanetza-idf, which is copied to obu-firmware/external/vanetza-idf.
/microbu-esp32c5/
# draw.io keeps a backup beside an open diagram.
*.drawio.bkp
+1 -1
View File
@@ -75,7 +75,7 @@ resets the board, the phone is on the other port.
Signed CAMs from the pinger already show "signature verified" live. Switch to VAM with signing
on: the VAM must be decoded (cyclist, position) and show "signature verified" too.
Confirmed by the user 2026-09-23: signed VAMs decode and verify.
- [x] **VAM.** Transmit VAM: BTP port 2018, psid 638; with `tools/wireshark/psid-vru.lua` from the colleague's microbu-esp32c5 repository
- [x] **VAM.** Transmit VAM: BTP port 2018, psid 638; with `microbu-esp32c5/tools/wireshark/psid-vru.lua`
Wireshark decodes the VAM (stationType cyclist, bicyclist profile in every ~2 s VAM). Rate:
≥1 per 5 s standing still, about one per GNSS fix while riding.
Covered by the V2X2MAP check above (decoded VAM, psid 638); Wireshark not needed.
+5 -5
View File
@@ -35,10 +35,10 @@ fit together, how it was verified, and what is still open. Hardware checks still
## Firmware (obu-firmware)
obu-firmware is now a port of `microbu-esp32c5/firmware`, from the colleague's own repository
(not part of this one; nothing is pushed there). The C-ITS library it needs is copied into this
repository as `obu-firmware/external/vanetza-idf` (their commit cf4b99f, unchanged), so
obu-firmware builds from a plain clone. It builds
obu-firmware is now a port of `microbu-esp32c5/firmware`: the colleague's repository, of which
this repository keeps a copy in `microbu-esp32c5/` (their commit cf4b99f plus our V2X2MAP signature
verification; nothing is pushed to their repository). vanetza-idf is taken from
`microbu-esp32c5/external/vanetza-idf`. It builds
with **ESP-IDF 6.0.2 only**: the raw-TX path uses private Wi-Fi driver structures that vanetza-idf
pins to that version. The previous C firmware (IDF 6.1) is backed up as a full flash image in
`firmware-backups/` (gitignored, restore command in its README.txt); its sources stay on disk,
@@ -64,7 +64,7 @@ Main changes against the colleague's firmware:
## Link protocol
Station-link v1 (colleague's repository, `station-link/README.md`): `[opcode][flags][sequence LE][body]`,
Station-link v1 (`microbu-esp32c5/station-link/README.md`): `[opcode][flags][sequence LE][body]`,
little-endian, at most 512 octets. Over USB each message is one `0xAA55` frame of type `0x10`
(the old framing and CRC). Over BLE each message is one GATT value on service
`0000C175-BA5E-4C17-8000-00805F9B34FB` (the README describes a different, Nordic-UART layout; the
File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 660 KiB

+43
View File
@@ -0,0 +1,43 @@
# --- ESP-IDF build output ---
firmware/build/
firmware/build-*/
firmware/managed_components/
firmware/.cache/
firmware/.vscode/
firmware/sdkconfig
firmware/sdkconfig.old
firmware/*.log
firmware/rf_characterization_output/
# --- Secrets: never commit real private key material ---
# (this repo only ever ships the disposable, non-registered demo chain)
*.vkey
*.ekey
private/
*_private_encrypted.pem
*_RCA_NEW_*/
# --- PKI reference-generator: regenerate locally, do not commit ---
# (vendored Rust crates for the offline/deterministic c-its build path; see
# pki/uml-l0-rca/reference-generator/README.md to rebuild with `cargo vendor`)
pki/uml-l0-rca/reference-generator/vendor/
pki/uml-l0-rca/reference-generator/_build_cits/
pki/uml-l0-rca/reference-generator/_cargo_vendor/
# --- Python ---
__pycache__/
*.pyc
*.egg-info/
.venv/
venv/
# --- v2x2map bridge local artifacts ---
tools/v2x2map-0.3.0/bridge/recordings/
tools/v2x2map-0.3.0/bridge/dist/
tools/v2x2map-0.3.0/bridge/build/
*.pcap
# --- OS / editor ---
.DS_Store
Thumbs.db
*.swp
+155
View File
@@ -0,0 +1,155 @@
# micrOBU ESP32-C5
A standalone ITS-G5 (802.11p) VRU (Vulnerable Road User) ITS-S station on the
ESP32-C5: firmware, the embedded [Vanetza](https://github.com/riebl/vanetza)
C-ITS protocol stack (`external/vanetza-idf/`, see
[PROVENANCE.md](external/vanetza-idf/PROVENANCE.md)), a phone-emulator
example for the station-internal link, a localhost PKI reference chain, a
Wireshark VAM dissector and the [V2X2MAP](https://github.com/711it/v2x2map)
receiver bridge.
A fresh clone can send a real, signed VAM (VRU Awareness Message) over the
air in a handful of commands — see [Send a signed VAM](#4-send-a-signed-vam-in-a-few-commands)
below. `station-link/python/demo-chain.vcr` is a disposable, **non-EU-registered**
test credential chain generated specifically for this purpose (see
[Security note on credentials](#security-note-on-credentials)); it carries no
real-world trust and is safe to ship.
## Quickstart
### 1. Build & flash the ESP32-C5 firmware
Requires [ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c5/get-started/) 6.0.2 with the `esp32c5` target.
```powershell
cd firmware
idf.py set-target esp32c5
idf.py build
idf.py -p COM<PORT> flash monitor
```
### 2. Install the Wireshark VAM dissector
Wireshark decodes IEEE 1609.2 / ETSI TS 103 097 secured packets only down to
`unsecuredData` unless the PSID is registered in its dissector table. **PSID
638** (VRU Awareness Service, ETSI TS 102 965) is not registered by default
in Wireshark 4.x, so signed VAM traffic stops decoding at the security
envelope without this plugin.
```powershell
# Windows
Copy-Item tools\wireshark\psid-vru.lua "$env:APPDATA\Wireshark\plugins\"
```
```bash
# Linux
mkdir -p ~/.local/lib/wireshark/plugins && cp tools/wireshark/psid-vru.lua ~/.local/lib/wireshark/plugins/
# macOS
mkdir -p ~/.config/wireshark/plugins && cp tools/wireshark/psid-vru.lua ~/.config/wireshark/plugins/
```
Verify under **Help → About Wireshark → Plugins**, or use it directly with `tshark`:
```bash
tshark -X lua_script:tools/wireshark/psid-vru.lua -r capture.pcap
```
See [tools/wireshark/README.md](tools/wireshark/README.md) for details.
### 3. Install Python dependencies
```bash
pip install -r station-link/python/requirements.txt
pip install -r tools/v2x2map-0.3.0/bridge/requirements.txt
```
### 4. Send a signed VAM in a few commands
With the firmware flashed (step 1) and the ESP32-C5 connected over USB
Serial/JTAG, the phone emulator provisions the disposable demo credential
chain and starts a small VRU basic service that assembles and transmits
VAMs:
```bash
python station-link/python/phone_emulator.py \
--port COM<PORT> --bundle station-link/python/demo-chain.vcr \
--radio txrx --duration 30
```
That's it — the micrOBU signs every VAM with the demo AT ticket (VRU ITS-AID
638, `psid 638 ssp 01`) and transmits it over ITS-G5. Capture it with a
second ITS-G5-capable radio (or the [V2X2MAP bridge](#5-run-the-v2x2map-receiver-bridge-optional)
below) and decode it with the [Wireshark dissector](#2-install-the-wireshark-vam-dissector)
from step 2.
To provision over BLE instead of USB, or to mirror packets to a `.pcap`
without radiating, see the header of
[`phone_emulator.py`](station-link/python/phone_emulator.py) for the
`--ble`, `--radio off --divert --pcap` and full `--pki-*` (real online TS
102 941 enrolment/authorization) variants, and
[station-link/README.md](station-link/README.md) for the link protocol
itself.
### 5. Run the V2X2MAP receiver bridge (optional)
A second ESP32-C5 flashed with the receiver firmware in
[`tools/v2x2map-0.3.0/bridge/firmware/`](tools/v2x2map-0.3.0/bridge/firmware/)
can feed a live web dashboard:
```bash
python tools/v2x2map-0.3.0/bridge/its_g5_bridge.py --port COM<PORT> --dashboard-port 8080 --open-browser
```
Open `http://localhost:8080` if it doesn't open automatically. This tool
decodes VAMs for display but does **not** verify signatures (see
[tools/v2x2map-0.3.0/README.md](tools/v2x2map-0.3.0/README.md)).
## Repository layout
| Path | Contents |
|---|---|
| `firmware/` | ESP-IDF firmware project for the ESP32-C5 VRU ITS-S |
| `external/vanetza-idf/` | Vanetza C-ITS stack + ESP-IDF port (upstream provenance in [PROVENANCE.md](external/vanetza-idf/PROVENANCE.md)) |
| `station-link/` | Station-internal link protocol, Python client library, phone emulator |
| `pki/` | Localhost PKI reference chain (root/AA/AT tooling); see [security note](#security-note-on-credentials) |
| `tools/wireshark/` | PSID 638 (VRU) Wireshark Lua dissector |
| `tools/v2x2map-0.3.0/` | Vendored [V2X2MAP](https://github.com/711it/v2x2map) receiver bridge and live dashboard |
## Security note on credentials
`pki/uml-l0-rca/` documents the tooling for a **real, EU CCMS L0 ECTL-registered**
root CA used elsewhere in the wider micrOBU project. Its private key material
is intentionally **not** in this repository — `.gitignore` also backstops
this (`*.vkey`, `*.ekey`, `private/`).
`station-link/python/demo-chain.vcr` is unrelated: a separate, throwaway,
**non-registered** root/AA/AT chain generated specifically for this repo's
quickstart with `pki/uml-l0-rca/bin/windows/vidf_issue.exe`. Its
`HashedId8` values do not match the registered root, it grants no real-world
trust, and regenerating it is safe:
```powershell
$pool = "<some scratch directory>"
$exe = "pki\uml-l0-rca\bin\windows\vidf_issue.exe"
openssl ecparam -name prime256v1 -genkey -noout -out "$pool\demo_root_key.pem"
& $exe root --key "$pool\demo_root_key.pem" --name "Demo Root (NOT REGISTERED)" --id DEMO_RCA --out $pool --years 10
& $exe authority --issuer "$pool\DEMO_RCA.oer" --issuer-key "$pool\demo_root_key.pem" --name "Demo AA" --id DEMO_AA --out $pool --years 5
& $exe ticket --issuer "$pool\DEMO_AA.oer" --issuer-key "$pool\DEMO_AA.vkey" --id DEMO_AT --out $pool --hours 8760 --root "$pool\DEMO_RCA.oer"
python external\vanetza-idf\ports\esp_idf\tools\credential_bundle.py build `
--pool $pool --root DEMO_RCA --aa DEMO_AA --at DEMO_AT --out station-link\python\demo-chain.vcr
```
`pki/uml-l0-rca/reference-generator/` cross-validates certificate generation
against an independent Rust implementation ([`TheEnbyperor/c-its`](https://github.com/TheEnbyperor/c-its),
pinned commit in [`reference-generator/README.md`](pki/uml-l0-rca/reference-generator/README.md)).
Its vendored crates (`vendor/`) are excluded from this repository by
`.gitignore` for size; regenerate with `cargo vendor` from that directory's
`Cargo.lock`, or use `vidf_issue` directly as shown above — the vendor tree
is only needed for that independent cross-check, not for ordinary use.
## License / provenance
- Vanetza and its ESP-IDF port: BSD-3-Clause, see
[external/vanetza-idf/LICENSE.md](external/vanetza-idf/LICENSE.md) and
[external/vanetza-idf/PROVENANCE.md](external/vanetza-idf/PROVENANCE.md).
- V2X2MAP bridge: MIT, see
[tools/v2x2map-0.3.0/LICENSE](tools/v2x2map-0.3.0/LICENSE).

Some files were not shown because too many files have changed in this diff Show More