From 002e484d8074a3f80d3c103915fb2ee36a9568a0 Mon Sep 17 00:00:00 2001 From: tajniak81 <13187254+tajniak81@users.noreply.github.com> Date: Thu, 16 Jul 2026 15:32:17 +0200 Subject: [PATCH] Fix Fly App reporting the flight controller's firmware as the aircraft's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The About panel and home card showed 01.03.0800 on a Mavic Pro whose firmware is 03.02.35.05, sometimes flipping from the correct value to the wrong one seconds after connect. Cause was the component-level fallback I added in ec4b1bc. It is not a slower route to the same value: BaseComponent.getFirmwareVersion() reports the component's OWN firmware, so the flight controller answers 01.03.0800 while the aircraft is 03.02.35.05. Because it resolves quickly and getFirmwarePackageVersion() stays null for far longer than assumed, the fallback consistently won the race, published a wrong version, and — since the poll stopped once firmware was non-null — ended the search for the real one. Remove it. getFirmwarePackageVersion() is the only source for this field, so the value can now only be the aircraft's or absent, and the wrong version has no source in the codebase at all. The field stays blank until the package version is readable, which is the pre-existing behaviour and strictly better than showing something wrong. Widen the poll window to 60s as a best-effort head start now that nothing fills the gap early. It is not a guarantee: a Mavic Pro was still null after a minute, and whenever the window expires first the next connection event carries the version through connectionMap, as it did before this feature existed. Found by testing against a real Mavic Pro; two earlier attempts to fix this by re-ordering the fallback were both disproved on the aircraft. The serial number this feature added is verified working (08RDE1J00103H1). This fix is not yet confirmed on hardware — the controller needed charging. Co-Authored-By: Claude Opus 4.8 --- .../flutter/dji_msdk_sample/DjiSdkBridge.kt | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/Fly App/android/app/src/main/kotlin/com/dji/flutter/dji_msdk_sample/DjiSdkBridge.kt b/Fly App/android/app/src/main/kotlin/com/dji/flutter/dji_msdk_sample/DjiSdkBridge.kt index d21d6a8..8b25187 100644 --- a/Fly App/android/app/src/main/kotlin/com/dji/flutter/dji_msdk_sample/DjiSdkBridge.kt +++ b/Fly App/android/app/src/main/kotlin/com/dji/flutter/dji_msdk_sample/DjiSdkBridge.kt @@ -38,9 +38,15 @@ class DjiSdkBridge( private const val METHOD_CHANNEL = "dji_msdk/methods" private const val EVENT_CHANNEL = "dji_msdk/events" - /** Serial/firmware polling: the SDK reports null until it has talked to the aircraft. */ + /** + * Serial/firmware polling: the SDK reports null until it has talked to the + * aircraft. The serial lands within seconds; the firmware package version can + * take far longer (a Mavic Pro was still null after a minute), so this window + * is a best-effort head start, not a guarantee — whenever it expires first, the + * next `connection` event still carries the version through [connectionMap]. + */ private const val IDENTITY_RETRY_MS = 2_000L - private const val IDENTITY_MAX_ATTEMPTS = 6 + private const val IDENTITY_MAX_ATTEMPTS = 30 } private val mainHandler = Handler(Looper.getMainLooper()) @@ -230,8 +236,10 @@ class DjiSdkBridge( * Neither is readable the instant a product connects — `getFirmwarePackageVersion` * returns null and the flight controller's callbacks fail until the SDK has * finished handshaking — so this re-checks every [IDENTITY_RETRY_MS] until both - * are known or [IDENTITY_MAX_ATTEMPTS] is reached. Each resolved value is emitted - * as it arrives, so the UI fills in the serial even if firmware never resolves. + * are known or [IDENTITY_MAX_ATTEMPTS] is reached. Each value is emitted as it + * arrives and the two resolve on very different timescales: the serial lands in + * seconds, while the firmware may outlast the whole window (see the constants). + * The UI shows the serial regardless, and firmware stays blank rather than wrong. * * [generation] guards against overlapping chains: a product change or disconnect * bumps [identityGeneration], stranding any retry still queued for the old product. @@ -262,18 +270,12 @@ class DjiSdkBridge( override fun onFailure(error: DJIError?) = Unit }) } - // Component-level firmware is the fallback when the product-level package - // version stays null (some aircraft only report the former). - if (firmwareVersion == null) { - controller.getFirmwareVersion(object : CommonCallbacks.CompletionCallbackWith { - override fun onSuccess(value: String?) { - if (value.isNullOrBlank()) return - mainHandler.post { setFirmware(generation, value) } - } - - override fun onFailure(error: DJIError?) = Unit - }) - } + // Deliberately NOT falling back to controller.getFirmwareVersion(): a + // component reports its own firmware, which is a different quantity from + // the aircraft's. On a Mavic Pro the flight controller says 01.03.0800 + // where the aircraft is 03.02.35.05, so using it as a stand-in publishes a + // wrong version and pre-empts the real one (seen live). The package version + // is the only source for this field — leave it blank until it is readable. } if ((serialNumber == null || firmwareVersion == null) && attempt + 1 < IDENTITY_MAX_ATTEMPTS) { @@ -281,6 +283,7 @@ class DjiSdkBridge( } } + /** Publishes the product-level package version — the aircraft firmware. */ private fun setFirmware(generation: Int, value: String) { if (generation != identityGeneration || firmwareVersion == value) return firmwareVersion = value