2026-08-10 14:09:18 +02:00
|
|
|
# obu-firmware — setup & flashing notes
|
|
|
|
|
|
2026-08-11 14:50:35 +02:00
|
|
|
## Two toolchains - use a dedicated terminal for each
|
|
|
|
|
|
2026-09-23 17:27:54 +02:00
|
|
|
Since 2026-09-23 this project builds against ESP-IDF **6.0.2** exactly
|
|
|
|
|
(`C:\Espressif\frameworks\esp-idf-v6.0.2`): it is the vanetza-idf port (see
|
|
|
|
|
NOTES.md), and vanetza-idf's `radio_c5.cmake` refuses any other version because
|
|
|
|
|
the raw TX path pokes private Wi-Fi driver structures only validated there. The
|
|
|
|
|
previous C firmware used the receiver firmware's IDF **6.1**; the separate
|
|
|
|
|
`obu-cam-transmistter` project builds against the global ESP-IDF **5.5.4**.
|
|
|
|
|
Exporting two of them in one PowerShell window fails: the second export
|
2026-08-11 14:50:35 +02:00
|
|
|
inherits the first's `IDF_PYTHON_ENV_PATH` and reports every Python dependency
|
|
|
|
|
as unmet. Don't run `install.bat` to "fix" that - open a fresh terminal, or
|
|
|
|
|
clear the state with `$env:IDF_PYTHON_ENV_PATH = $null; $env:IDF_PATH = $null`.
|
|
|
|
|
|
2026-09-24 10:56:16 +02:00
|
|
|
The build is self-contained: the C-ITS library comes from
|
|
|
|
|
`obu-firmware/external/vanetza-idf`, a copy of `external/vanetza-idf` from the
|
|
|
|
|
colleague's microbu-esp32c5 repository (their commit cf4b99f, unchanged). Pass
|
|
|
|
|
`-DVANETZA_IDF_DIR=<path>` to `idf.py` to build against another checkout. The
|
|
|
|
|
first build downloads `espressif/esp-boost` into `managed_components/`.
|
|
|
|
|
|
|
|
|
|
Nothing is fetched from or pushed to the colleague's repository (HAW GitLab,
|
|
|
|
|
urban-mobility-lab/microbu/microbu-esp32c5). To take a newer vanetza-idf from
|
|
|
|
|
it, copy their `external/vanetza-idf` over this folder, rebuild and test, and
|
|
|
|
|
commit it here. The rest of their tree (their own VAM firmware, PKI tooling,
|
|
|
|
|
station-link Python tools, the V2X2MAP bridge) is not part of this repository.
|
2026-08-10 14:09:18 +02:00
|
|
|
|
2026-09-23 17:27:54 +02:00
|
|
|
## Every new PowerShell session
|
2026-08-10 14:09:18 +02:00
|
|
|
|
|
|
|
|
```powershell
|
|
|
|
|
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
|
2026-09-23 17:27:54 +02:00
|
|
|
$env:IDF_TOOLS_PATH = "C:\Espressif"
|
|
|
|
|
C:\Espressif\frameworks\esp-idf-v6.0.2\export.ps1
|
|
|
|
|
idf.py --version # v6.0.2
|
2026-08-10 14:09:18 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Build & flash
|
|
|
|
|
|
2026-09-24 10:56:16 +02:00
|
|
|
Flash over the board's **UART-bridge port** (CH343; COM3 for the production OBU
|
|
|
|
|
on the bench), not the native port the phone uses.
|
|
|
|
|
|
2026-08-10 14:09:18 +02:00
|
|
|
```powershell
|
|
|
|
|
cd C:\Users\Ashin\AndroidStudioProjects\MicrOBU\obu-firmware
|
|
|
|
|
idf.py set-target esp32c5 # only needed once per clean build folder
|
|
|
|
|
idf.py build
|
2026-09-24 10:56:16 +02:00
|
|
|
idf.py -p COM3 -b 921600 flash monitor
|
2026-08-10 14:09:18 +02:00
|
|
|
```
|
|
|
|
|
|
2026-09-24 10:56:16 +02:00
|
|
|
Swap `COM3` for whatever port the ESP32-C5's bridge enumerates as (Device Manager →
|
2026-08-10 14:09:18 +02:00
|
|
|
Ports). `monitor` opens the serial console after flashing — `Ctrl+]` to exit.
|
2026-09-24 10:56:16 +02:00
|
|
|
Use `flash` (bootloader + partition table + app), not `app-flash`, whenever the
|
|
|
|
|
partition table may differ from what the board has.
|
|
|
|
|
|
|
|
|
|
### First flash onto a board with the previous firmware
|
|
|
|
|
|
|
|
|
|
The partition table changed with the port (NVS 24 KB → 80 KB, app 0x10000 →
|
|
|
|
|
0x20000), and the old NVS is full of Wi-Fi settings the previous firmware left
|
|
|
|
|
behind. Erase the whole new NVS range once, then do a full flash:
|
|
|
|
|
|
|
|
|
|
```powershell
|
|
|
|
|
python -m esptool --chip esp32c5 -p COM3 -b 921600 erase-region 0x9000 0x15000
|
|
|
|
|
idf.py -p COM3 -b 921600 flash
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Without the erase, the board cannot store the BLE bond and the phone has to pair
|
|
|
|
|
on every connection (2026-09-23). After it:
|
|
|
|
|
|
|
|
|
|
- the boot log shows `0 bonded phone(s) in NVS`, `BLE advertising started as
|
|
|
|
|
'micrOBU-XXXX'` and `station task ready`; the radio stays off until the app
|
|
|
|
|
connects;
|
|
|
|
|
- on the first Connect the app provisions the demo credentials once (the card
|
|
|
|
|
says "Provisioning the demo credentials"); they stay in NVS from then on;
|
|
|
|
|
- a phone that was paired with the board before must forget `micrOBU-XXXX` in
|
|
|
|
|
Android's Bluetooth settings and pair again (passkey 123456).
|
|
|
|
|
|
|
|
|
|
Erasing NVS later (e.g. after a partition change) has the same effects.
|
|
|
|
|
|
|
|
|
|
## Going back to the previous firmware
|
|
|
|
|
|
|
|
|
|
The previous, unsigned C firmware (frame types 0x01-0x05, CAM over USB only)
|
|
|
|
|
can come back two ways. The app detects it and falls back to its protocol.
|
|
|
|
|
|
|
|
|
|
- **Image:** `firmware-backups/` in the repository root (gitignored, on the lab
|
|
|
|
|
laptop only) holds a full-flash image of the COM3 board as it was before the
|
|
|
|
|
port, with the esptool command in its README.txt. It restores the old
|
|
|
|
|
partition table and NVS too.
|
|
|
|
|
- **Source:** commit `7285fa1` is the last one before the port. Check it out in
|
|
|
|
|
a separate worktree and build it with the receiver firmware's IDF 6.1
|
|
|
|
|
(`its-g5-receiver-firmware\esp-idf\export.ps1`). Erase the NVS range as above
|
|
|
|
|
first, then `flash` (full, since the partition table differs); erasing after
|
|
|
|
|
flashing would wipe the start of the old app, which sits at 0x10000.
|
2026-08-10 14:09:18 +02:00
|
|
|
|
|
|
|
|
## If the build fails
|
|
|
|
|
|
|
|
|
|
- **"includes X.h, provided by Y component(s)... not in the requirements
|
|
|
|
|
list"** — IDF 5.x split the old monolithic `driver` component apart
|
|
|
|
|
(`esp_driver_gpio`, `esp_driver_uart`, etc.). Add the named component to
|
|
|
|
|
`REQUIRES` in `main/CMakeLists.txt` and rebuild. Already fixed once for
|
|
|
|
|
`esp_driver_gpio` + `esp_driver_uart` — if a new header comes up, same fix.
|
|
|
|
|
- Otherwise, start clean before re-building:
|
|
|
|
|
```powershell
|
|
|
|
|
idf.py fullclean
|
|
|
|
|
idf.py build
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Connecting the phone (ESP32-C5-WIFI6-KIT)
|
|
|
|
|
|
|
|
|
|
The board has two USB-C ports — use the right one:
|
|
|
|
|
|
|
|
|
|
- **Native USB-C port** (labeled for JTAG/native USB, up to 12 Mbps) — this
|
2026-09-24 10:56:16 +02:00
|
|
|
is where the phone plugs in via USB-OTG. The station link
|
|
|
|
|
(`serial_link.cpp`: station-link messages as frame type 0x10 in the 0xAA55
|
|
|
|
|
framing) runs over the ESP32-C5's native USB Serial/JTAG peripheral on this port, enumerating as a CDC-ACM device under Espressif's
|
2026-08-10 14:09:18 +02:00
|
|
|
VID/PID (0x303A/0x1001).
|
|
|
|
|
- **UART-bridge port** (labeled for flashing) — this is what you use for
|
|
|
|
|
`idf.py flash monitor` from your PC. Leave the phone unplugged from this
|
|
|
|
|
one; it only carries `idf.py`'s flashing protocol and the ESP_LOG console.
|
|
|
|
|
|
|
|
|
|
The app recognizes the ESP32-C5's VID/PID via a custom probe table in
|
|
|
|
|
`UsbSerialTransport.kt` (the default `usb-serial-for-android` prober doesn't
|
|
|
|
|
know Espressif's device IDs). If the phone doesn't detect anything when
|
|
|
|
|
plugged into the native port, first confirm with a tool like "USB Device
|
|
|
|
|
Info" (or `adb shell dumpsys usb` from a PC) that Android sees a USB device
|
|
|
|
|
at all — that isolates a bad/charge-only OTG cable from an app-side issue.
|
|
|
|
|
|
|
|
|
|
## Bring-up checklist (phone <-> ESP32-C5 link)
|
|
|
|
|
|
|
|
|
|
Work down this list — each step isolates the layer below it.
|
|
|
|
|
|
2026-09-24 10:56:16 +02:00
|
|
|
1. **Flash and install together.** The app detects the firmware generation by
|
|
|
|
|
its heartbeat and speaks either protocol, but only an app from 2026-09-23 on
|
|
|
|
|
knows the station-link protocol; messages are at most 512 octets on both
|
|
|
|
|
sides.
|
2026-08-10 14:09:18 +02:00
|
|
|
2. **Does Android see the device at all?** Plug the phone into the **native**
|
|
|
|
|
USB-C port, hit Connect, and read logcat for `UsbSerialTransport`. It logs
|
|
|
|
|
every attached device *and* each device's interfaces. Empty list = cable /
|
|
|
|
|
OTG / wrong port, below the app entirely.
|
|
|
|
|
3. **Did the right interface get claimed?** The C5's USB Serial/JTAG is a
|
|
|
|
|
composite device — expect CDC control (class 2) + CDC data (class 10) +
|
|
|
|
|
vendor-specific JTAG (class 255) in that dump. Compare against the `ports=`
|
|
|
|
|
count on the `matched device` line.
|
2026-09-24 10:56:16 +02:00
|
|
|
4. **Is the link alive?** The firmware sends a STATUS at 1 Hz regardless of
|
|
|
|
|
radio traffic, and the app marks the link ERROR after ~3.5 s of silence.
|
|
|
|
|
Connected-and-staying-connected means device→host actually works. The board
|
|
|
|
|
starts its radio only after the app's STATION_CONFIGURE, so nothing is
|
|
|
|
|
received before Connect.
|
|
|
|
|
5. **If it connects but no V2X_RX ever arrives** — suspect DTR. The app now
|
2026-08-10 14:09:18 +02:00
|
|
|
asserts DTR/RTS on open (`openDevice()` in `UsbSerialTransport.kt`), because
|
|
|
|
|
`CdcAcmSerialDriver` doesn't do it by default and the ESP32's USB Serial/JTAG
|
|
|
|
|
endpoint may gate TX on the host opening the CDC line. **This is still
|
|
|
|
|
unverified on real hardware** — test it both ways (with the `setDTR(true)`
|
|
|
|
|
call and with it commented out) and record the answer in `serial_link.h`
|
|
|
|
|
next to the VID/PID note, so nobody has to guess again.
|
|
|
|
|
6. **Watch the counters, not just "Sent: N".** The CAM Pinger card shows
|
|
|
|
|
consecutive write failures (phone side) and the firmware's tx-failure /
|
2026-09-24 10:56:16 +02:00
|
|
|
RX-queue-drop / CRC-error totals from the heartbeat; the connection card
|
|
|
|
|
shows tickets, signed and refused counts. A rising `tx fail` means messages
|
|
|
|
|
reach the ESP32 but the radio refuses them — a radio problem, not a link
|
|
|
|
|
problem. A rising `refused` with signing on usually means no ticket (NVS
|
|
|
|
|
erased: reconnect so the app provisions again).
|
2026-08-10 14:09:18 +02:00
|
|
|
|
2026-09-23 17:27:54 +02:00
|
|
|
## Connecting over Bluetooth instead
|
|
|
|
|
|
|
|
|
|
Settings > Connection > ESP32-C5 > link: Bluetooth, then Connect. The board
|
|
|
|
|
advertises as `micrOBU-XXXX` (last two bytes of its BT MAC; `micrOBU-4AFA` on
|
|
|
|
|
COM3), but only while nothing uses its native USB port. Android asks to pair
|
|
|
|
|
the first time: passkey **123456** (fixed in `simple_ble.cpp`). The bond is kept
|
|
|
|
|
on both sides; the board keeps one bond, so pairing a second phone or a PC
|
|
|
|
|
replaces the first. Log lines on the console start with `cits_ble:`.
|
|
|
|
|
|
2026-08-10 14:09:18 +02:00
|
|
|
## Notes
|
|
|
|
|
|
|
|
|
|
- No `git submodule update` needed here — obu-firmware has no pinned
|
|
|
|
|
submodule of its own, unlike its-g5-receiver-firmware.
|
2026-09-23 17:27:54 +02:00
|
|
|
- Don't use the global "ESP-IDF 5.5 PowerShell" shortcut or the receiver
|
|
|
|
|
firmware's 6.1 checkout — export from `esp-idf-v6.0.2`, the version the
|
|
|
|
|
vanetza-idf radio's undocumented driver internals were verified against.
|
|
|
|
|
- The console (ESP_LOG, boot messages, panics) stays on the UART-bridge port.
|
|
|
|
|
Opening it resets the board; do that only while nothing else depends on the
|
|
|
|
|
session.
|