Skip to content

Commit 0580689

Browse files
malysclaude
andcommitted
feat(saic): read the remaining distance in metres on SWI68
A parked capture with guidance running answered: status 1, remaining 9788, remaining time 25, road "Rue de la Fontaine". MapService logs that second value as remainingMinutes, so 9788 metres is 23,5 km/h to the destination and 9788 kilometres is not a number about a car. Metres is the only reading that survives. remainingDistanceKm is gated per generation like every other unit here. One observation is enough to list SWI68 and not enough to guess at anything else, so an unlisted firmware keeps the raw value and no kilometres are claimed. Refs: CP-040 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 977538d commit 0580689

2 files changed

Lines changed: 46 additions & 0 deletions

File tree

‎lib/src/main/java/com/evsuite/hardware/saic/NavGuidance.kt‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.evsuite.hardware.saic
22

3+
import com.evsuite.hardware.FirmwareInfo
4+
35
/**
46
* What the head unit's navigation stack last said about the trip in progress.
57
*
@@ -31,8 +33,27 @@ data class NavGuidance(
3133
/** Monotonic time of the last accepted callback, or null before the first one. */
3234
val updatedAtElapsedMs: Long? = null,
3335
) {
36+
/**
37+
* Remaining distance to the destination in km, when the raw value's unit is known.
38+
*
39+
* The adapter names no unit. A capture on 2026-09-04, SWI68-29958-1300R67, read 9788
40+
* against a remaining time of 25 — and `MapService` logs that second value as
41+
* `remainingMinutes`, so 9788 metres is 23,5 km/h to the destination and 9788 kilometres
42+
* is not a number about a car. Metres is the only reading that survives.
43+
*
44+
* One observation, so this is gated per generation like every other unit here: an
45+
* unlisted firmware keeps the raw value and no kilometres are claimed. A drive confirms
46+
* it by comparing against the odometer span.
47+
*/
48+
fun remainingDistanceKm(generation: FirmwareInfo.Gen): Double? =
49+
remainingDistanceRaw
50+
?.takeIf { generation in REPORTS_METRES }
51+
?.let { it / 1000.0 }
3452
companion object {
3553
val EMPTY = NavGuidance()
54+
55+
/** Generations observed to report `getRemainingDistance` in metres. */
56+
private val REPORTS_METRES = setOf(FirmwareInfo.Gen.SWI68)
3657
}
3758
}
3859

‎lib/src/test/java/com/evsuite/hardware/saic/NavGuidanceReducerTest.kt‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,28 @@ class TransactionCensusTest {
111111
assertEquals(0, census.beyondCeiling)
112112
}
113113
}
114+
115+
class NavGuidanceDistanceUnitTest {
116+
117+
/** The 2026-09-04 capture: 9788 remaining, 25 minutes, "Rue de la Fontaine". */
118+
private val seen = NavGuidance(remainingDistanceRaw = 9788, remainingMinutes = 25)
119+
120+
@Test fun `a metres generation reports kilometres`() {
121+
val km = seen.remainingDistanceKm(com.evsuite.hardware.FirmwareInfo.Gen.SWI68)!!
122+
assertEquals(9.788, km, 1e-9)
123+
// The reading that makes it metres: 9.788 km in 25 minutes is a plausible town route.
124+
assertEquals(23.5, km / (25.0 / 60.0), 0.1)
125+
}
126+
127+
@Test fun `an unlisted generation claims no kilometres at all`() {
128+
com.evsuite.hardware.FirmwareInfo.Gen.entries
129+
.filterNot { it == com.evsuite.hardware.FirmwareInfo.Gen.SWI68 }
130+
.forEach { assertNull("$it", seen.remainingDistanceKm(it)) }
131+
}
132+
133+
@Test fun `no raw distance means no kilometres`() {
134+
assertNull(
135+
NavGuidance.EMPTY.remainingDistanceKm(com.evsuite.hardware.FirmwareInfo.Gen.SWI68)
136+
)
137+
}
138+
}

0 commit comments

Comments
 (0)