@@ -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