Skip to content

Commit 22304be

Browse files
malysclaude
andcommitted
feat(saic): read the current guidance instead of waiting for a change
The five callbacks registered on the adapter are change notifications. A car standing still with a guidance already running publishes nothing, because nothing changed — so the first vehicle capture could not tell "the adapter says nothing" from "nothing happened to say", which is exactly the question CP-040 turns on. IGeneralService answers getGuideStatus, getRemainingTimes, getRemainingDistance and getRoadName synchronously, on the binder this already binds. SaicNav's note that the head unit offers no synchronous read of remaining distance was read off IMapService; the general service does answer. readNow reports the current trip and keeps whatever the listener has already seen where a getter answers nothing. A distance or time of zero reads as unknown: the service initialises both to zero and answers zero before any guidance has run, and a remaining distance of exactly zero is not a case any forecast needs. Transaction codes from saicadapterservice_overseas_eh32; the census still guards against an R67 shift. Refs: CP-040 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 26b3d45 commit 22304be

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@ All notable changes to this project are documented here. Format follows
66

77
## [Unreleased]
88

9+
### Added
10+
11+
- **Guidance can be read, not only waited for.** The five listener callbacks are change
12+
notifications, so a car standing still with a guidance already running publishes nothing —
13+
which made a parked capture unable to tell "the adapter says nothing" from "nothing happened
14+
to say". `IGeneralService` answers `getGuideStatus`, `getRemainingTimes`, `getRemainingDistance`
15+
and `getRoadName` synchronously on the binder already bound, so `SaicNavGuidance.readNow`
16+
reports the current trip on demand. `SaicNav`'s note that the head unit answers no synchronous
17+
question about a trip was read off `IMapService`; the general service does answer. A distance
18+
or time of zero is treated as unreadable, as the service returns zero before any guidance has
19+
run.
20+
921
### Fixed
1022

1123
- **`PERF_VEHICLE_SPEED` already reports km/h on SWI68, and was being converted a second time.**

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ object SaicNavGuidance {
4444
private const val TX_REGISTER_LISTENER = 1
4545
private const val TX_UNREGISTER_LISTENER = 2
4646

47+
// Synchronous getters on the same interface. SaicNav's note that the head unit answers no
48+
// synchronous question about a trip was read off IMapService; IGeneralService does answer.
49+
private const val TX_GET_ROAD_NAME = 29
50+
private const val TX_GET_GUIDE_STATUS = 31
51+
private const val TX_GET_REMAINING_TIMES = 33
52+
private const val TX_GET_REMAINING_DISTANCE = 34
53+
4754
private val service = SaicService.byComponent(PACKAGE, CLASS, "nav-guidance")
4855

4956
/**
@@ -81,6 +88,38 @@ object SaicNavGuidance {
8188
*/
8289
fun latest(): NavGuidance = state
8390

91+
/**
92+
* The current guidance, read rather than waited for.
93+
*
94+
* The five callbacks are change notifications: a car standing still with a guidance
95+
* already running publishes nothing, because nothing changed. That made a parked capture
96+
* unable to tell "the adapter says nothing" from "nothing happened to say", which is the
97+
* distinction CP-040 turns on. These getters answer on demand instead.
98+
*
99+
* Values seen so far by the listener are kept where a getter answers nothing, so a caller
100+
* gets the best of both without choosing between them.
101+
*/
102+
fun readNow(): NavGuidance {
103+
val target = binder() ?: return state
104+
fun int(code: Int) = SaicAidl.callInt(target, DESCRIPTOR, code)
105+
// The service initialises these to 0 and answers 0 before any guidance has run, which
106+
// is the same answer an arrived route would give. Unknown is the cheaper reading: a
107+
// remaining distance of exactly zero is not a case any forecast needs.
108+
val distance = int(TX_GET_REMAINING_DISTANCE)?.takeIf { it > 0 }
109+
val minutes = int(TX_GET_REMAINING_TIMES)?.takeIf { it > 0 }
110+
val status = int(TX_GET_GUIDE_STATUS)
111+
val road = SaicAidl.callString(target, DESCRIPTOR, TX_GET_ROAD_NAME)?.takeIf {
112+
it.isNotBlank()
113+
}
114+
val seen = state
115+
return seen.copy(
116+
guideStatus = status ?: seen.guideStatus,
117+
remainingDistanceRaw = distance ?: seen.remainingDistanceRaw,
118+
remainingMinutes = minutes ?: seen.remainingMinutes,
119+
road = road ?: seen.road,
120+
)
121+
}
122+
84123
/** Transaction codes seen so far, with counts. See [TransactionCensus]. */
85124
fun census(): Map<Int, Int> = census.snapshot()
86125

0 commit comments

Comments
 (0)