feat: smarter firmware confirm via reconnect
This commit is contained in:
@ -196,15 +196,11 @@ class FirmwareUpdateService {
|
||||
);
|
||||
|
||||
_emitProgress(state: DfuUpdateState.finishing);
|
||||
final finishStatus = await _writeControlAndWaitForStatus(
|
||||
BootloaderDfuProtocol.encodeFinishPayload(normalizedSessionId),
|
||||
timeout: effectiveStatusTimeout,
|
||||
);
|
||||
_requireOkStatus(
|
||||
finishStatus,
|
||||
await _writeFinishAndWaitForReset(
|
||||
sessionId: normalizedSessionId,
|
||||
expectedOffset: imageBytes.length,
|
||||
operation: 'FINISH',
|
||||
statusTimeout: effectiveStatusTimeout,
|
||||
resetTimeout: effectivePostFinishResetTimeout,
|
||||
);
|
||||
|
||||
await _statusSubscription?.cancel();
|
||||
@ -212,15 +208,6 @@ class FirmwareUpdateService {
|
||||
|
||||
_emitProgress(
|
||||
state: DfuUpdateState.rebooting, sentBytes: imageBytes.length);
|
||||
final resetDisconnectResult =
|
||||
await _transport.waitForBootloaderDisconnect(
|
||||
timeout: effectivePostFinishResetTimeout,
|
||||
);
|
||||
if (resetDisconnectResult.isErr()) {
|
||||
throw _DfuFailure(
|
||||
'Bootloader did not perform the expected post-FINISH reset disconnect: ${resetDisconnectResult.unwrapErr()}',
|
||||
);
|
||||
}
|
||||
|
||||
if (!verifyAfterFinish) {
|
||||
_emitProgress(
|
||||
@ -554,6 +541,76 @@ class FirmwareUpdateService {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _writeFinishAndWaitForReset({
|
||||
required int sessionId,
|
||||
required int expectedOffset,
|
||||
required Duration statusTimeout,
|
||||
required Duration resetTimeout,
|
||||
}) async {
|
||||
final eventCount = _statusEventCount;
|
||||
final result = await _transport.writeControl(
|
||||
BootloaderDfuProtocol.encodeFinishPayload(sessionId),
|
||||
);
|
||||
if (result.isErr()) {
|
||||
throw _DfuFailure(
|
||||
'Failed to write bootloader control command: ${result.unwrapErr()}',
|
||||
);
|
||||
}
|
||||
|
||||
final deadline = DateTime.now().add(resetTimeout);
|
||||
var observedEvents = eventCount;
|
||||
while (true) {
|
||||
_throwIfCancelled();
|
||||
_throwIfStatusStreamErrored();
|
||||
|
||||
if (_statusEventCount > observedEvents && _latestStatus != null) {
|
||||
final status = _latestStatus!;
|
||||
_requireOkStatus(
|
||||
status,
|
||||
sessionId: sessionId,
|
||||
expectedOffset: expectedOffset,
|
||||
operation: 'FINISH',
|
||||
);
|
||||
final remaining = deadline.difference(DateTime.now());
|
||||
final resetDisconnectResult =
|
||||
await _transport.waitForBootloaderDisconnect(
|
||||
timeout: remaining > Duration.zero ? remaining : Duration.zero,
|
||||
);
|
||||
if (resetDisconnectResult.isErr()) {
|
||||
throw _DfuFailure(
|
||||
'Bootloader did not perform the expected post-FINISH reset disconnect: ${resetDisconnectResult.unwrapErr()}',
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final disconnectResult = await _transport.waitForBootloaderDisconnect(
|
||||
timeout: Duration.zero,
|
||||
);
|
||||
if (disconnectResult.isOk()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final remaining = deadline.difference(DateTime.now());
|
||||
if (remaining <= Duration.zero) {
|
||||
throw _DfuFailure(
|
||||
'Bootloader did not perform the expected post-FINISH reset disconnect within ${resetTimeout.inMilliseconds}ms.',
|
||||
);
|
||||
}
|
||||
|
||||
final waitDuration =
|
||||
remaining < statusTimeout ? remaining : statusTimeout;
|
||||
final gotEvent = await _waitForNextStatusEvent(
|
||||
afterEventCount: observedEvents,
|
||||
timeout: waitDuration,
|
||||
recoverable: false,
|
||||
);
|
||||
if (gotEvent) {
|
||||
observedEvents = _statusEventCount - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<DfuBootloaderStatus> _waitForStatus({
|
||||
required int afterEventCount,
|
||||
required Duration timeout,
|
||||
|
||||
Reference in New Issue
Block a user