Ashin Walpola 0ccb867228 DENM over-the-air receive on the ESP32-C5 path
The firmware forwarded CAM only: gn_unwrap_cam accepted single-hop broadcast
(HT=5) and BTP port 2001, so every DENM was dropped before it reached the phone.
Real OBUs disseminate DENM by GeoBroadcast (HT=4), whose 44-byte extended header
also carries the hazard's relevance area - materially more useful on a map than
the sender's own position, since a sender may be relaying for someone else.

Firmware
- gn_unwrap_cam -> gn_unwrap_its: accepts GeoBroadcast alongside TSB/SHB, and
  BTP ports 2001 and 2002, extracting the GeoBroadcast destination area. Both
  extended-header lengths were measured against live air capture rather than
  read off a spec table. Secured packets (Basic Header NextHeader=2) are
  rejected rather than misparsed.
- SERIAL_MSG_CAM_RX (0x02) superseded by SERIAL_MSG_V2X_RX (0x04): a 14-byte
  prefix carrying BTP port, RSSI and the destination area. Adding MAPEM later
  needs a decoder on the phone but no protocol change. 0x02 stays reserved so
  the numbering is not silently reused.
- Promiscuous RX capture buffer 400 -> 800 bytes. A real GeoBroadcast DENM is
  around 500 bytes on air and was being truncated mid-payload, which no amount
  of correct unwrapping downstream could have recovered from.
- geonet_wrap_shb, both firmwares: the SHB extended header is 28 bytes, not 24.
  The Source Position Vector is followed by a 4-byte reserved field; without it
  a standards-strict receiver reads the CAM payload's first two bytes as the BTP
  destination port.

App
- DenmUperCodec: UPER decoder for the ManagementContainer and the
  SituationContainer's eventType. ValidityDuration is 17 bits, not 16, and
  ManagementContainer, SituationContainer and CauseCode each carry their own
  extension bit - a single wrong bit made a real frame read causeCode 47
  instead of 94.
- DenmEvent gains actionID (originatingStationID + sequenceNumber), stationType,
  termination, detectionTime, relevance radius and RSSI. Dedup keys on actionID
  where available, so a termination lands on the event it ends instead of
  creating a second pin.
- denmEvents merges the MQTT and over-the-air sources and drops terminated
  events. The V2X list view now shows hazards above the CAM stations; it
  previously took no DENM parameter at all, so hazards reached the map but never
  the list.
- DenmParser: the Use Case API sends causeCode as a string enum, so reading it
  as an Int always yielded null.

Testing
- DenmAirReceiveTest covers the V2X_RX prefix and the decoder using real frames
  from a live capture as fixtures. Expected values were cross-checked against
  the ETSI ASN.1 modules via asn1tools, which agreed on all 1885 decodable
  DENMs across the capture set, every field including detectionTime.
- Verified on hardware: a CiT One HLN-SV DENM decodes as cause 94/0 with a
  1000 m relevance radius at 1 Hz alongside CAM, with no decode failures and no
  unexpected BTP ports.

Also replaces em dashes with hyphens throughout the user-facing strings,
including the German translation.
2026-08-17 18:42:48 +02:00
2026-08-10 11:38:01 +02:00
2026-07-24 11:41:29 +02:00
2026-06-03 14:51:31 +02:00
2026-06-03 14:51:31 +02:00
2026-06-08 16:23:08 +02:00

MicrOBU Android App

Android companion app for the micrOBU; a compact V2X on-board unit developed by HAW Hamburg and consider it GmbH for vulnerable road users (cyclists, e-bike riders, pedestrians).

The app serves as the HMI for the micrOBU hardware, handling V2X message display, sensor data collection, trip recording, and OBU communication over USB-C, Wi-Fi (dev), and Bluetooth (upcoming).

Platform: Android (Kotlin) · Min SDK: 29 (Android 10) · Target SDK: 36

What it does

Real-time V2X monitoring; subscribes to the OBU's MQTT broker and displays live CAM, DENM, SPAT, MAP, and CPM messages grouped by topic with pretty-printed JSON and TX/RX badges.

DENM transmission; triggers DENM use cases (e.g. stationary vehicle warning hln-sv) on the OBU via the consider it Use Case API (v2x-uca/input/denmtrg) with a single tap.

Sensor monitoring; live readout of phone GNSS, accelerometer, gyroscope, magnetometer, and barometer alongside OBU GNSS for cross-reference.

Trip recording; foreground service records all sensor streams and detects cycling events (braking, turning, stopping) using orientation-independent signal processing. Works fully offline with no OBU connected.

Trip review; past trips displayed on an OpenStreetMap layer with detected events overlaid as coloured pins. Tap any pin for event details.

CSV export; every sensor sample written to a timestamped CSV in real time during a session. Shareable via the standard Android share sheet.

Architecture

MVVM with Repository pattern throughout. Jetpack Compose for all UI (no XML layouts). Hilt for dependency injection.

ui/screens/         Compose screens (Dashboard, V2X Monitor, Sensors, Recording, Trip History, Settings…)
ui/navigation/      Navigation graph and bottom nav bar
viewmodel/          MqttViewModel, SensorViewModel, TripRecordingViewModel
data/mqtt/          MQTT repository, Paho client, exponential-backoff reconnection
data/transport/     USB tethering detection and gateway IP resolution
data/db/            Room database (sessions, trips, detected events)
data/               SensorRepository, TripRepository, CsvExporter
domain/detection/   EventDetector, RunningStats sliding window (orientation-independent)
service/            TripRecordingService (foreground service)

Connectivity

The app uses a phased transport strategy. The MQTT client, topic subscriptions, and all UI are identical across transports; only the underlying network path changes.

Phase Transport Status
Phase 01 Wi-Fi Complete
Phase 02 USB-C tethering Active
Phase 03 Bluetooth BLE Future

The MQTT broker runs on the OBU hardware (Mosquitto 2.0.11, port 1883). In Phase 02, Android USB tethering exposes the OBU as a virtual Ethernet interface at 192.168.42.x. The app auto-detects the gateway IP on plug-in.

Key dependencies

Library Purpose
Jetpack Compose + Material3 UI
Eclipse Paho MQTT OBU communication
Room Local database
Hilt Dependency injection
OSMDroid Trip review map
DataStore Settings persistence
FusedLocationProviderClient GNSS

Getting started

  1. Open in Android Studio (Hedgehog or newer).
  2. Connect a device running Android 10+ (API 29).
  3. Build and run the app module.
  4. For Phase 02 testing: plug the phone into the OBU via USB-C, enable USB tethering on the phone, and the app will detect the interface and connect automatically. Broker IP can be overridden manually in Settings → Connection.
  5. For standalone trip recording: no OBU required. Go to the Record tab and tap Record.

The Wi-Fi transport (Phase 01 broker at 192.168.3.202) remains available in developer builds and can be toggled in Settings → Developer.

Project context

The micrOBU project is funded under the ZIM program (BMWK) and targets micromobility users in Hamburg. The companion app offloads processing from the compact OBU hardware to the smartphone; GNSS fusion, event detection, and future antenna coordination all run on the phone to keep the OBU lightweight and power-efficient.

V2X communication uses ITS-G5 (IEEE 802.11p / DSRC) at 5.9 GHz. The app communicates with the OBU exclusively via the consider it MQTT API v6 (processed JSON messages); no ASN.1 encoding in the app.

Owner: HAW Hamburg

S
Description
No description provided
Readme
21 MiB
Languages
Kotlin 64.3%
C 19.5%
C++ 12.6%
Python 2.6%
CMake 0.5%
Other 0.5%