Skip to content

Commit 1031787

Browse files
committed
electric window feature
1 parent e02b95a commit 1031787

13 files changed

Lines changed: 847 additions & 303 deletions

File tree

‎app/src/main/java/com/mg4/control/hardware/MG4Hardware.kt‎

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -297,23 +297,6 @@ object MG4Hardware {
297297
*/
298298
fun lastVehicleIgnitionState(): Int = sLastVcmIgnitionState
299299

300-
// ── Portes avant : écouteurs de changement (fermeture auto des vitres) ─────────────────
301-
private val doorListeners = java.util.concurrent.CopyOnWriteArrayList<(area: Int, previous: Int?, value: Int) -> Unit>()
302-
303-
/**
304-
* S'abonne aux changements de DLOCK_DOOR_OPEN_STS des portes avant (area 0x1 gauche, 0x4 droite ;
305-
* 1 = ouverte). Lance la connexion au watcher porte si besoin, indépendamment de la baisse de
306-
* volume. [previous] null = première lecture (pas un front). Appelé sur le fil principal.
307-
*/
308-
fun addDoorListener(listener: (area: Int, previous: Int?, value: Int) -> Unit) {
309-
doorListeners.add(listener)
310-
connectCarProperty()
311-
}
312-
313-
fun removeDoorListener(listener: (area: Int, previous: Int?, value: Int) -> Unit) {
314-
doorListeners.remove(listener)
315-
}
316-
317300
/**
318301
* Lit l'état d'allumage courant via CarPropertyManager.
319302
* Retourne -1 si CPM non prêt, 0 si propriété non supportée.
@@ -1467,6 +1450,31 @@ object MG4Hardware {
14671450
return if (gear < 0) null else gear == GEAR_PARK_VALUE
14681451
}
14691452

1453+
// ── État READY (SENSOR_EPTRDY) : fermeture auto des vitres en quittant la voiture ──────
1454+
// • SWI133 : VPM getIntProperty(0x5030048) — SENSOR_TYPE_EPTRDY (VehiclePropertyID vehiclesettings SWI133)
1455+
// • SWI68/165 : VehicleConditionManager.getEngineState() — lit SENSOR_EPTRDY 0x2140157c
1456+
// • A9 (132/131/69): CarStateClient.getSensorEptrdyState() — voie de winclose (validée SWI69)
1457+
private const val PROP_EPTRDY_VPM = 0x5030048
1458+
1459+
/**
1460+
* Valeur brute de l'état READY, sans journal (lue chaque seconde) ; null si le canal du firmware
1461+
* n'est pas prêt. Interprétation : [com.mg4.control.model.WindowAutoCloseTrigger.readyFromRaw].
1462+
*/
1463+
fun readEptReadyRaw(): Int? {
1464+
val gen = FirmwareInfo.getGeneration()
1465+
return when {
1466+
gen == FirmwareInfo.Gen.SWI133 ->
1467+
if (sVpm == null) null else getIntPropertyVpm(PROP_EPTRDY_VPM)
1468+
FirmwareInfo.isNewGenVsm() || gen == FirmwareInfo.Gen.SWI132 ->
1469+
a9CarState()?.let { cs ->
1470+
runCatching { cs.javaClass.getMethod("getSensorEptrdyState").invoke(cs) as? Int }.getOrNull()
1471+
}
1472+
gen == FirmwareInfo.Gen.SWI68 || gen == FirmwareInfo.Gen.SWI165 ->
1473+
sVcm?.let { vcm -> runCatching { vcm.javaClass.getMethod("getEngineState").invoke(vcm) as? Int }.getOrNull() }
1474+
else -> null
1475+
}
1476+
}
1477+
14701478
// ── Lecture gear SWI68/165 (poll direct) + A9 (CarStateClient) ───────────
14711479
private const val CAR_STATE_CLIENT_CLASS = "com.saicmotor.carapi.client.CarStateClient"
14721480
private const val CAR_STATE_SERVICE_CODE = 0xb
@@ -1484,22 +1492,34 @@ object MG4Hardware {
14841492

14851493
/** A9 : CarStateClient.getGearState() via CarAdapterClient.queryClient(0xb). */
14861494
private fun readA9GearState(): Int {
1487-
val cl = sVsm?.javaClass?.classLoader ?: return Int.MIN_VALUE
1495+
val cs = a9CarState() ?: return Int.MIN_VALUE
14881496
return try {
1489-
if (sCarState == null) {
1490-
val adapterClass = cl.loadClass(CAR_ADAPTER_CLIENT_CLASS)
1491-
val adapter = adapterClass.getMethod("getInstance", Context::class.java).invoke(null, sAppContext)
1492-
val binder = adapterClass.getMethod("queryClient", Int::class.javaPrimitiveType)
1493-
.invoke(adapter, CAR_STATE_SERVICE_CODE) as? android.os.IBinder ?: return Int.MIN_VALUE
1494-
val stateClass = cl.loadClass(CAR_STATE_CLIENT_CLASS)
1495-
sCarState = stateClass.getConstructor(android.os.IBinder::class.java).newInstance(binder)
1496-
}
1497-
(sCarState!!.javaClass.getMethod("getGearState").invoke(sCarState) as? Int) ?: Int.MIN_VALUE
1497+
(cs.javaClass.getMethod("getGearState").invoke(cs) as? Int) ?: Int.MIN_VALUE
14981498
} catch (e: Exception) {
14991499
AppLogger.w(TAG, " A9 getGearState err: ${e.javaClass.simpleName}: ${e.message}"); Int.MIN_VALUE
15001500
}
15011501
}
15021502

1503+
/** A9 : CarStateClient (rapport, READY), créé à la première demande ; null si indisponible. */
1504+
private fun a9CarState(): Any? {
1505+
sCarState?.let { return it }
1506+
val cl = sVsm?.javaClass?.classLoader ?: return null
1507+
return try {
1508+
val adapterClass = cl.loadClass(CAR_ADAPTER_CLIENT_CLASS)
1509+
val adapter = adapterClass.getMethod("getInstance", Context::class.java).invoke(null, sAppContext)
1510+
val binder = adapterClass.getMethod("queryClient", Int::class.javaPrimitiveType)
1511+
.invoke(adapter, CAR_STATE_SERVICE_CODE) as? android.os.IBinder ?: return null
1512+
val stateClass = cl.loadClass(CAR_STATE_CLIENT_CLASS)
1513+
stateClass.getConstructor(android.os.IBinder::class.java).newInstance(binder).also { sCarState = it }
1514+
} catch (e: Exception) {
1515+
// READY est lu chaque seconde : une seule trace, pas une par tentative.
1516+
if (!sCarStateErrLogged) AppLogger.w(TAG, " A9 CarStateClient err: ${e.javaClass.simpleName}: ${e.message}")
1517+
sCarStateErrLogged = true
1518+
null
1519+
}
1520+
}
1521+
@Volatile private var sCarStateErrLogged = false
1522+
15031523
private fun getMixIntProperty(propId: Int): Int {
15041524
val vpm = sVpm ?: return -1
15051525
return try {
@@ -5531,8 +5551,6 @@ object MG4Hardware {
55315551
if (prev == null || prev != v) {
55325552
sDoorReadLast[area] = v
55335553
AppLogger.i(DOORWATCH_TAG, "area=0x${area.toString(16)} ${prev ?: "?"} → $v")
5534-
val listeners = doorListeners.toList()
5535-
if (listeners.isNotEmpty()) Handler(Looper.getMainLooper()).post { listeners.forEach { it(area, prev, v) } }
55365554
}
55375555
evaluateDoorTrigger()
55385556
}

0 commit comments

Comments
 (0)