App 2.22.2: gear badge shows P, R, N and D

Codes read on the owner's car with 2.22.1: 1 P, 2 R, 3 N, 4 D. Gear
maps them (unit-tested); other codes show no letter, unread "—". The
temporary gear list on the Logs tab is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
This commit is contained in:
2026-10-24 19:10:03 +02:00
co-authored by Claude Opus 5.5
parent 16cc2746ef
commit c6643e7df2
12 changed files with 33 additions and 94 deletions
@@ -2118,9 +2118,9 @@ object EVHardware {
fun isVehicleInPark(): Boolean? = getGearRaw()?.let { it == GEAR_PARK_VALUE }
/**
* The gear as the car's own code, null if unreadable. Only P = 1 is established (see
* [isVehicleInPark]); the other codes are passed on unnamed so the app can show them and
* the driver can match them to R, N and D.
* The gear as the car's own code, null if unreadable. P = 1 on every studied firmware (see
* [isVehicleInPark]); on an MG4 with SWI68 (SWI68-29958-1300R69) the owner read 1 P, 2 R,
* 3 N, 4 D by shifting through the lever.
*/
fun getGearRaw(): Int? {
val gen = FirmwareInfo.getGeneration()
@@ -585,7 +585,8 @@ object SaicVehicleControl {
* own `GEAR_PARK_VALUE`, two head-unit apps using `carGear == 1` as the condition for playing
* video on the centre screen (`UsbVideoView`, `VideoListFragment`), and
* `IBackUpBinder.isSecureForBackUp`, which accepts gears 1 and 3 alongside `speed == 0`.
* Nothing pins 2, 3 and 4, so nothing here names them.
* Nothing in the code pins 2, 3 and 4; on an MG4 with SWI68-29958-1300R69 the owner read them
* off the lever as 2 R, 3 N, 4 D (the app's `Gear` names them; this layer passes codes on).
*
* `getCarSpeed` is on this interface too and is deliberately unused: the binder returns a
* float with no unit in any source, and a speed read in the wrong unit would open the write
@@ -48,7 +48,7 @@ data class EnergySnapshot(
*/
val driveModeRaw: Int? = null,
val regenLevelRaw: Int? = null,
/** The gear's raw code, unmapped beyond P = 1; null where the car did not answer. */
/** The gear's raw code (MG4 SWI68: 1 P, 2 R, 3 N, 4 D); null where the car did not answer. */
val gearRaw: Int? = null,
) {
val hasVehicleData: Boolean
@@ -27,7 +27,7 @@ interface EnergySignalSource {
fun vehicleConsumedKwh(): Float? = null
fun vehicleRegeneratedKwh(): Float? = null
fun parked(): Boolean?
/** The gear's raw code; only 1 (P) is named. Null where unread. */
/** The gear's raw code (MG4 SWI68: 1 P, 2 R, 3 N, 4 D). Null where unread. */
fun gearRaw(): Int? = null
fun batteryVoltageV(): Float? = null
fun batteryCurrentA(): Float? = null