Retry a timed-out waypoint upload and wait for the route to be ready

On the Mavic Pro in the simulator a waypoint mission failed with "Execution
of this process has timed out". The bridge now resends a timed-out upload
with retryUploadMission (up to 3 times) and only reports the upload done once
the operator is READY_TO_EXECUTE, and the error now says whether the upload
or the start failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
tajniak81andClaude Opus 5.5 committed 2026-10-22 09:25:28 +02:00
1 parent 91520560a7
commit 9cca65019f
2 files changed
+41 -5

No files matched your search

@@ -20,6 +20,7 @@ import dji.common.mission.waypoint.WaypointMissionFlightPathMode
import dji.common.mission.waypoint.WaypointMissionGotoWaypointMode
import dji.common.mission.waypoint.WaypointMissionHeadingMode
import dji.common.mission.waypoint.WaypointMissionInterruption
import dji.common.mission.waypoint.WaypointMissionState
import dji.common.mission.waypoint.WaypointMissionUploadEvent
import dji.common.mission.waypoint.WaypointTurnMode
import dji.common.model.LocationCoordinate2D
@@ -417,9 +418,36 @@ class MissionBridge(private val ctx: BridgeCtx) : SubBridge {
ctx.fail(result, loadErr.description)
return
}
// Completes once every waypoint is on the aircraft; progress arrives
// through the listener meanwhile.
op.uploadMission(ctx.completion(result))
// Completes once every waypoint is on the aircraft and the operator is
// ready to start; progress arrives through the listener meanwhile.
uploadWithRetry(op, result, retriesLeft = UPLOAD_RETRIES)
}
/**
* A waypoint packet that times out fails the whole upload with
* COMMON_TIMEOUT (seen on a Mavic Pro in the simulator); MSDK's answer is
* `retryUploadMission`, which resends only what is missing.
*/
private fun uploadWithRetry(op: WaypointMissionOperator, result: MethodChannel.Result, retriesLeft: Int, retry: Boolean = false) {
val done = CommonCallbacks.CompletionCallback<DJIError> { error ->
ctx.mainHandler.post {
when {
error == null -> whenReady(op, result, READY_WAIT_MS)
error.errorCode == DJIError.COMMON_TIMEOUT.errorCode && retriesLeft > 0 -> uploadWithRetry(op, result, retriesLeft - 1, retry = true)
else -> result.error("DJI_ERROR", error.description, null)
}
}
}
if (retry) op.retryUploadMission(done) else op.uploadMission(done)
}
/** The upload callback can land before the state says READY_TO_EXECUTE; a start then times out. */
private fun whenReady(op: WaypointMissionOperator, result: MethodChannel.Result, waitMs: Long) {
when {
op.currentState == WaypointMissionState.READY_TO_EXECUTE -> result.success(null)
waitMs <= 0 -> result.error("DJI_ERROR", "The aircraft never reported the route ready (${op.currentState?.name})", null)
else -> ctx.mainHandler.postDelayed({ whenReady(op, result, waitMs - READY_POLL_MS) }, READY_POLL_MS)
}
}
private fun startActiveTrack(call: MethodCall, result: MethodChannel.Result) {
@@ -474,3 +502,10 @@ class MissionBridge(private val ctx: BridgeCtx) : SubBridge {
@Volatile private var v2Active = false
private val v2 = WaypointV2(ctx) { v2Active = it }
}
/** How often a timed-out waypoint upload is resent before giving up. */
private const val UPLOAD_RETRIES = 3
/** How long an uploaded route may take to reach READY_TO_EXECUTE, polled every [READY_POLL_MS]. */
private const val READY_WAIT_MS = 5000L
private const val READY_POLL_MS = 200L
@@ -39,9 +39,10 @@ Future<void> startWaypointFlow(
),
);
if (r == null) return;
bool uploaded = false;
try {
await gate.startWaypointMission(spec, limits: limits, rthHeight: r.number);
await gate.startWaypointMission(spec, limits: limits, rthHeight: r.number, onUploaded: () => uploaded = true);
} catch (e) {
onError('Waypoint mission', e);
onError(uploaded ? 'Waypoint start' : 'Waypoint upload', e);
}
}