# obu-firmware — setup & flashing notes ## Two toolchains - use a dedicated terminal for each 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 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`. The build also needs the colleague's `microbu-esp32c5` tree, which this repository carries as ordinary files in `microbu-esp32c5/`: vanetza-idf is taken from its `external/vanetza-idf`. Pass `-DVANETZA_IDF_DIR=` to `idf.py` if it lives elsewhere. The first build downloads `espressif/esp-boost` into `managed_components/`. `microbu-esp32c5/` is a copy, not a submodule: nothing is fetched from or pushed to the colleague's repository (HAW GitLab, urban-mobility-lab/microbu/ microbu-esp32c5). It was taken at their commit cf4b99f plus our V2X2MAP signature verification (local commit 428a386; that repository's history is kept outside this one in `..\microbu-esp32c5-colleague.git`). To take a newer version of their tree, copy it over this folder, rebuild and test, and commit it here. ## Every new PowerShell session ```powershell Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass $env:IDF_TOOLS_PATH = "C:\Espressif" C:\Espressif\frameworks\esp-idf-v6.0.2\export.ps1 idf.py --version # v6.0.2 ``` ## Going back to the previous firmware `firmware-backups/` in the repository root (gitignored) holds a full-flash image of the COM3 board as it was before the port, with the esptool command to write it back in its README.txt. ## Build & flash ```powershell cd C:\Users\Ashin\AndroidStudioProjects\MicrOBU\obu-firmware idf.py set-target esp32c5 # only needed once per clean build folder idf.py build idf.py -p COM5 -b 921600 flash monitor ``` Swap `COM5` for whatever port the ESP32-C5 enumerates as (Device Manager → Ports). `monitor` opens the serial console after flashing — `Ctrl+]` to exit. ## 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 is where the phone plugs in via USB-OTG. The CAM serial link (`serial_link.c`) runs over the ESP32-C5's native USB Serial/JTAG peripheral on this port, enumerating as a CDC-ACM device under Espressif's 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. 1. **Flash and install together.** `SERIAL_LINK_MAX_PAYLOAD` is 512 on both sides. A phone at 512 talking to firmware still at 160 (or vice versa) silently rejects every large frame at the `length exceeds max, resync` branch. Never update one side alone. 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. 4. **Is the link alive?** The firmware sends a STATUS heartbeat 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. 5. **If it connects but no CAM_RX ever arrives** — suspect DTR. The app now 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 / oversize-drop / CRC-error totals from the heartbeat. A rising `tx fail` means CAMs reach the ESP32 but `esp_wifi_80211_tx` rejects them — a radio problem, not a link problem. ## 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:`. ## Notes - No `git submodule update` needed here — obu-firmware has no pinned submodule of its own, unlike its-g5-receiver-firmware. - 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.