fix: fix dfu id mismatch because stale notification
This commit is contained in:
@ -527,10 +527,33 @@ class FirmwareUpdateService {
|
|||||||
Future<DfuBootloaderStatus> _sendStartAndWaitForStatus(
|
Future<DfuBootloaderStatus> _sendStartAndWaitForStatus(
|
||||||
BootloaderDfuStartPayload payload, {
|
BootloaderDfuStartPayload payload, {
|
||||||
required Duration timeout,
|
required Duration timeout,
|
||||||
}) {
|
}) async {
|
||||||
return _writeControlAndWaitForStatus(
|
final eventCount = _statusEventCount;
|
||||||
BootloaderDfuProtocol.encodeStartPayload(payload),
|
final encodedPayload = BootloaderDfuProtocol.encodeStartPayload(payload);
|
||||||
|
_log.fine(
|
||||||
|
'Writing DFU START command for session ${payload.sessionId} '
|
||||||
|
'(len=${encodedPayload.length})',
|
||||||
|
);
|
||||||
|
final result = await _transport.writeControl(encodedPayload);
|
||||||
|
if (result.isErr()) {
|
||||||
|
_log.warning('DFU START write failed: ${result.unwrapErr()}');
|
||||||
|
throw _DfuFailure(
|
||||||
|
'Failed to write bootloader control command: ${result.unwrapErr()}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return _waitForStatus(
|
||||||
|
afterEventCount: eventCount,
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
|
acceptStatus: (status) {
|
||||||
|
if (status.sessionId == payload.sessionId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
_log.fine(
|
||||||
|
'Ignoring stale START status for session ${status.sessionId}; '
|
||||||
|
'waiting for session ${payload.sessionId}',
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,6 +731,7 @@ class FirmwareUpdateService {
|
|||||||
required int afterEventCount,
|
required int afterEventCount,
|
||||||
required Duration timeout,
|
required Duration timeout,
|
||||||
bool recoverable = false,
|
bool recoverable = false,
|
||||||
|
bool Function(DfuBootloaderStatus status)? acceptStatus,
|
||||||
}) async {
|
}) async {
|
||||||
final deadline = DateTime.now().add(timeout);
|
final deadline = DateTime.now().add(timeout);
|
||||||
var observedEvents = afterEventCount;
|
var observedEvents = afterEventCount;
|
||||||
@ -722,7 +746,12 @@ class FirmwareUpdateService {
|
|||||||
'session=${_latestStatus!.sessionId}, offset=${_latestStatus!.expectedOffset}, '
|
'session=${_latestStatus!.sessionId}, offset=${_latestStatus!.expectedOffset}, '
|
||||||
'code=${_statusLabel(_latestStatus!)}',
|
'code=${_statusLabel(_latestStatus!)}',
|
||||||
);
|
);
|
||||||
return _latestStatus!;
|
final status = _latestStatus!;
|
||||||
|
if (acceptStatus == null || acceptStatus(status)) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
observedEvents = _statusEventCount;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final remaining = deadline.difference(DateTime.now());
|
final remaining = deadline.difference(DateTime.now());
|
||||||
|
|||||||
@ -307,6 +307,33 @@ void main() {
|
|||||||
await transport.dispose();
|
await transport.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('ignores stale previous-session status while waiting for START',
|
||||||
|
() async {
|
||||||
|
final image = _validImage(80);
|
||||||
|
final transport = _FakeFirmwareUpdateTransport(
|
||||||
|
totalBytes: image.length,
|
||||||
|
staleStartStatusSessionId: 20,
|
||||||
|
);
|
||||||
|
final service = FirmwareUpdateService(
|
||||||
|
transport: transport,
|
||||||
|
defaultStatusTimeout: const Duration(milliseconds: 100),
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = await service.startUpdate(
|
||||||
|
imageBytes: image,
|
||||||
|
sessionId: 21,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.isOk(), isTrue);
|
||||||
|
expect(
|
||||||
|
transport.controlWrites.first.first, universalShifterDfuOpcodeStart);
|
||||||
|
expect(transport.dataWrites.first[0], 21);
|
||||||
|
expect(service.currentProgress.state, DfuUpdateState.completed);
|
||||||
|
|
||||||
|
await service.dispose();
|
||||||
|
await transport.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
test('fails with bootloader status error on rejected START', () async {
|
test('fails with bootloader status error on rejected START', () async {
|
||||||
final image = _validImage(40);
|
final image = _validImage(40);
|
||||||
final transport = _FakeFirmwareUpdateTransport(
|
final transport = _FakeFirmwareUpdateTransport(
|
||||||
@ -410,6 +437,7 @@ class _FakeFirmwareUpdateTransport implements FirmwareUpdateTransport {
|
|||||||
this.suppressFirstDataStatus = false,
|
this.suppressFirstDataStatus = false,
|
||||||
this.failDataWriteAtOffsetOnce,
|
this.failDataWriteAtOffsetOnce,
|
||||||
this.resetSessionOnRecoveryStatus = false,
|
this.resetSessionOnRecoveryStatus = false,
|
||||||
|
this.staleStartStatusSessionId,
|
||||||
this.suppressFinishStatus = false,
|
this.suppressFinishStatus = false,
|
||||||
this.disconnectAfterFinish = true,
|
this.disconnectAfterFinish = true,
|
||||||
this.finishStatusCode = DfuBootloaderStatusCode.ok,
|
this.finishStatusCode = DfuBootloaderStatusCode.ok,
|
||||||
@ -425,6 +453,7 @@ class _FakeFirmwareUpdateTransport implements FirmwareUpdateTransport {
|
|||||||
final bool suppressFirstDataStatus;
|
final bool suppressFirstDataStatus;
|
||||||
final int? failDataWriteAtOffsetOnce;
|
final int? failDataWriteAtOffsetOnce;
|
||||||
final bool resetSessionOnRecoveryStatus;
|
final bool resetSessionOnRecoveryStatus;
|
||||||
|
final int? staleStartStatusSessionId;
|
||||||
final bool suppressFinishStatus;
|
final bool suppressFinishStatus;
|
||||||
final bool disconnectAfterFinish;
|
final bool disconnectAfterFinish;
|
||||||
final DfuBootloaderStatusCode finishStatusCode;
|
final DfuBootloaderStatusCode finishStatusCode;
|
||||||
@ -502,6 +531,10 @@ class _FakeFirmwareUpdateTransport implements FirmwareUpdateTransport {
|
|||||||
if (opcode == universalShifterDfuOpcodeStart) {
|
if (opcode == universalShifterDfuOpcodeStart) {
|
||||||
_sessionId = payload[17];
|
_sessionId = payload[17];
|
||||||
_expectedOffset = 0;
|
_expectedOffset = 0;
|
||||||
|
final staleSessionId = staleStartStatusSessionId;
|
||||||
|
if (staleSessionId != null) {
|
||||||
|
_scheduleStatus(DfuBootloaderStatusCode.ok, staleSessionId, 0);
|
||||||
|
}
|
||||||
_scheduleStatus(startStatusCode, _sessionId, 0);
|
_scheduleStatus(startStatusCode, _sessionId, 0);
|
||||||
} else if (opcode == universalShifterDfuOpcodeGetStatus) {
|
} else if (opcode == universalShifterDfuOpcodeGetStatus) {
|
||||||
if (resetSessionOnRecoveryStatus && _connectCount > 1) {
|
if (resetSessionOnRecoveryStatus && _connectCount > 1) {
|
||||||
|
|||||||
Reference in New Issue
Block a user