Files
MicrOBU/obu-cam-transmistter/NOTES.md
T
Ashin Walpola 277c6b20f4 Record the on-air verification and how to run the bench beacon
Both firmware fixes are now confirmed over the air, with the sniffer board
capturing and asn1tools judging the result.

GN lifetime: our station transmits 0x05 (1 s), the value both bench stations
use, where the August captures show 0x83 (3200 s) for the same frames. 397 CAMs
from station 999999 decode and re-encode byte-identically, so the whole
transmit chain is right on the wire, not only in the host tests.

yawRateConfidence: the bench beacon, flashed to a spare board, sends CAMs that
decode and re-encode byte-identically as well (72 of 72 from station
0x0BADC0DE). NOTES.md now says how to flash that beacon and how to check what
it sends, including that it shares the phone pinger's MAC and the two are told
apart by station ID.

The new firmware also runs on the OBU with the phone attached: CAM, DENM and
SPATEM from the bench stations all keep decoding in the app now that messages
are cut to the length their header declares.

Signed reception stays open. The CiT One transmits unsigned and nothing else
here signs, so it needs real roadside traffic, the CiT One switched to signed
mode, or a replay firmware on a spare board.

Two bench facts worth not rediscovering are recorded too: opening COM3's
console resets the OBU and drops the phone's USB link, and every capture taken
before today is truncated at its first corrupted record, because the receiver's
console inserts a CR before every 0x0a byte of the binary pcap stream.
live_capture.py now undoes that, a change that lives in the receiver repo and
is not part of this commit.
2026-09-14 13:33:47 +02:00

4.5 KiB

OBU transmit firmware - Phase 2 (in progress: HLN-SV DENM beacon)

Started. See docs/04-transmit-setup.md in the project root for build/flash steps and how to validate this against your own sniffer.

Toolchain: use a dedicated terminal (ESP-IDF 5.5.4)

This project builds against the global ESP-IDF 5.5.4, NOT the 6.1 checkout that obu-firmware uses. Keep one terminal per toolchain and never export both in the same window - the second export inherits the first's IDF_PYTHON_ENV_PATH and then fails every dependency check (click, esptool, cryptography, ... "not met"). That is env-var bleed, not a broken install: do not run install.bat to "fix" it, that damages one of the two environments.

Terminal Export Project
Transmitter C:\Espressif\frameworks\esp-idf-v5.5.4\export.ps1 this one
OBU ...\micrOBU_workspace\its-g5-receiver-firmware\esp-idf\export.ps1 obu-firmware

If a terminal has already been used for the other IDF, clear the state first:

$env:IDF_PYTHON_ENV_PATH = $null; $env:IDF_PATH = $null

Also note build/ here was regenerated from scratch (its CMake cache still referenced an older source path under micrOBU_workspace/v2x-obu-esp32c5/, which makes idf.py fullclean refuse to run). If that error reappears, delete build/ manually rather than fighting it.

CAM encoding

main/cam.c IS compiled here (unlike obu-firmware's copy, which is a reference only). It must stay bit-identical to obu-firmware/main/cam.c and the app's CamUperCodec.kt - all three encode the same wire format, and a one-bit divergence in any of them is invisible on the bench but wrong against real equipment. See the CurvatureCalculationMode comment in that file.

Implements one profile so far: HLN-SV (aftermarket stationary recovery vehicle), causeCode 94 (stationaryVehicle), subCauseCode 0, active while the hazard-light GPIO is grounded. No location/alacarte containers.

  • main/main.c - entry point, the phy_11p_set/phy_change_channel(5900,...) register hack, GPIO polling, TX loop
  • main/denm.c / .h - ASN.1 UPER encoding of a minimal DENM
  • main/geonet.c / .h - GeoNetworking Basic/Common/SHB headers + BTP-B
  • main/dot11p.c / .h - 802.11 OCB (QoS Data, broadcast) frame + LLC/SNAP

Known gaps, tracked as TODOs in the source: no real GNSS (lat/long hardcoded 0), no real time source (detectionTime/referenceTime hardcoded 0, decodes as 2004-01-01), fixed (non-rotating) pseudonym MAC, SHB instead of GeoBroadcast (no multi-hop forwarding), unsecured (no IEEE 1609.2 signing).

Running it as a bench beacon

This firmware needs no phone: it beacons a CAM every second by itself (TX_INTERVAL_MS) from station 0x0BADC0DE (195936478), stationType 5 (passengerCar), at the hardcoded bench position, under the fixed MAC 02:00:00:00:00:01, on 5900 MHz. That makes it the quickest way to put known, repeatable traffic on air, and it is how the 4-bit yawRateConfidence encoding was confirmed over the air on 2026-09-14.

A board with only one USB-C port is fine. This firmware's console is on UART0, so such a board shows no log output, but nothing here needs the console.

Flash it from the toolchain terminal (ESP-IDF 5.5.4, see the table above):

cd C:\Users\Ashin\AndroidStudioProjects\MicrOBU\obu-cam-transmistter
idf.py -p COM10 -b 921600 flash

Or flash the existing build without any toolchain terminal:

cd obu-cam-transmistter\build
C:\Espressif\python_env\idf5.5_py3.11_env\Scripts\python.exe -m esptool --chip esp32c5 -p COM10 -b 921600 write_flash --flash_mode dio --flash_freq 80m --flash_size 2MB 0x2000 bootloader/bootloader.bin 0x8000 partition_table/partition-table.bin 0x10000 obu_firmware.bin

It starts beaconing as soon as it boots, so there is nothing to start by hand, and unplugging it is how you stop it.

It transmits under the same MAC as the phone's CAM pinger, so on air the two are told apart by station ID (195936478 here, 999999 for the pinger), never by source address.

To see what it is sending, capture on the sniffer board and decode:

cd its-g5-receiver-firmware
py -3.11 live_capture.py COM8
py -3.11 ..\obu-firmware\test\pcap_gn_tally.py recordings\capture_<timestamp>.pcap

The tally lists it as SHB / port 2001 / lifetime 0x05. For the message itself, decode the payload with asn1tools against asn1/cam_1_4_1.asn + asn1/cdd_1_3_1_1.asn; re-encoding must return the identical bytes. On 2026-09-14, 72 of 72 frames did.