Show roadside units in the station list; log ESP32 drop counters
Bench test on 2026-08-25 against live RSU and CiT One traffic found that 611 RSU CAMs decoded correctly and none of them were ever displayed. Excluding RSUs from UseCaseDetectionEngine - correct, since a permanently stationary station at a fixed point trips the stopped-vehicle use case for as long as it is in range - also removed them from the map and station list, because remotePositions is the engine's own map. RSUs are now tracked in a separate rsuStations flow and merged with the engine's road users for display only. Expiry is clock-driven for the same reason as hazards and signals: an RSU going out of range simply stops transmitting, and no further emission would arrive to recompute the list. Cleared on link-down alongside engine.reset(), so a stale RSU cannot outlive an unplug. The kinematics line is suppressed for them. An RSU's CAM uses rsuContainerHighFrequency, which carries no kinematics at all, so the zeroes in the model are placeholders - printing "0.0 km/h - heading 0" would assert a stationary vehicle pointing due north. Also logs the ESP32's STATUS heartbeat counters whenever one changes. They previously reached only the CAM Pinger card, so a bench run captured through logcat had no record of whether the firmware dropped anything. Logged on change rather than per beat: the interesting event is a drop appearing, and a once-per-second line would bury it. Test report in 05-obu-bench-test-2026-08-25.md.
This commit is contained in:
@@ -230,6 +230,10 @@ class MqttViewModel @Inject constructor(
|
||||
*/
|
||||
const val SPAT_TTL_MS = 15_000L
|
||||
const val SPAT_EXPIRY_TICK_MS = 2_000L
|
||||
|
||||
/** RSU CAMs arrive at ~2 Hz, same as any other station, so the same window applies. */
|
||||
const val RSU_TTL_MS = 15_000L
|
||||
const val RSU_EXPIRY_TICK_MS = 2_000L
|
||||
}
|
||||
|
||||
// ── DENM transmission ─────────────────────────────────────────────────────
|
||||
@@ -262,6 +266,24 @@ class MqttViewModel @Inject constructor(
|
||||
/** Latest known CAM per tracked remote road user, for the live map view (Section 13). */
|
||||
val remoteCamPositions: StateFlow<Map<Long, com.hawhamburg.micr0bu.domain.cam.Cam>> = camUseCaseRepository.remotePositions
|
||||
|
||||
/**
|
||||
* Every station to draw: road users from the detection engine, plus roadside units, which are
|
||||
* tracked outside it (see [com.hawhamburg.micr0bu.data.cam.CamUseCaseRepository.rsuStations]).
|
||||
*
|
||||
* The engine prunes its own stale entries; nothing prunes the RSU map, so the staleness window
|
||||
* is applied here. As with hazards and signals, expiry has to be clock-driven - an RSU that
|
||||
* goes out of range simply stops transmitting, and no further emission would arrive to
|
||||
* recompute the list.
|
||||
*/
|
||||
val stationsInRange: StateFlow<Map<Long, com.hawhamburg.micr0bu.domain.cam.Cam>> = combine(
|
||||
camUseCaseRepository.remotePositions,
|
||||
camUseCaseRepository.rsuStations,
|
||||
tickerFlow(RSU_EXPIRY_TICK_MS),
|
||||
) { roadUsers, rsus, _ ->
|
||||
val now = System.currentTimeMillis()
|
||||
roadUsers + rsus.filterValues { now - it.timestamp <= RSU_TTL_MS }
|
||||
}.stateIn(viewModelScope, SharingStarted.Eagerly, emptyMap())
|
||||
|
||||
/** True if [stationId] is the ego OBU's own — used for OWN/REMOTE badges in the raw message list. */
|
||||
fun isOwnStationId(stationId: Long): Boolean = camUseCaseRepository.isOwnStationId(stationId)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user