Skip to content

Commit d1681a4

Browse files
committed
ev3: Fix issues with flashing (some?) EV3s.
Flash the EV3 all in one go rather than sector-by-sector. This appears to resolve issues we had with flashing (some?) EV3s, and mirrors what we do in pybricksdev.
1 parent 4516cc8 commit d1681a4

1 file changed

Lines changed: 51 additions & 40 deletions

File tree

src/firmware/sagas.ts

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,73 +1219,84 @@ function* handleFlashEV3(action: ReturnType<typeof firmwareFlashEV3>): Generator
12191219

12201220
defined(version);
12211221

1222-
console.debug(
1223-
`EV3 bootloader version: ${version.getUint32(
1224-
0,
1225-
true,
1226-
)}, HW version: ${version.getUint32(4, true)}`,
1227-
);
1222+
try {
1223+
console.debug(
1224+
`EV3 bootloader version: ${version.getUint32(
1225+
0,
1226+
true,
1227+
)}, HW version: ${version.getUint32(4, true)}`,
1228+
);
1229+
} catch (err) {
1230+
console.error(`Failed to parse ev3 version response: ${ensureError(err)}`);
1231+
}
12281232

12291233
// FIXME: should be called much earlier.
12301234
yield* put(didStart());
12311235

12321236
const sectorSize = 64 * 1024; // flash memory sector size
12331237
const maxPayloadSize = 1018; // maximum payload size for EV3 commands
12341238

1235-
for (let i = 0; i < action.firmware.byteLength; i += sectorSize) {
1236-
const sectorData = action.firmware.slice(i, i + sectorSize);
1237-
assert(sectorData.byteLength <= sectorSize, 'sector data too large');
1239+
console.info(`Firmware size: ${action.firmware.byteLength} bytes`);
1240+
1241+
// Extend firmware to sector alignment
1242+
const numSectors = Math.ceil(action.firmware.byteLength / sectorSize);
1243+
const alignedSize = numSectors * sectorSize;
1244+
const alignedFirmware = new Uint8Array(alignedSize);
1245+
alignedFirmware.set(new Uint8Array(action.firmware));
1246+
// Remaining bytes are already zeroed by Uint8Array constructor
12381247

1239-
const erasePayload = new DataView(new ArrayBuffer(8));
1240-
erasePayload.setUint32(0, i, true);
1241-
erasePayload.setUint32(4, sectorData.byteLength, true);
1242-
const [, eraseError] = yield* sendCommand(
1243-
0xf0,
1244-
new Uint8Array(erasePayload.buffer),
1248+
console.info(`Aligned firmware size: ${alignedSize} bytes (${numSectors} sectors)`);
1249+
1250+
// Erase all sectors at once
1251+
const erasePayload = new DataView(new ArrayBuffer(8));
1252+
erasePayload.setUint32(0, 0, true); // start address
1253+
erasePayload.setUint32(4, alignedSize, true); // size
1254+
const [, eraseError] = yield* sendCommand(
1255+
0xf0,
1256+
new Uint8Array(erasePayload.buffer),
1257+
);
1258+
1259+
if (eraseError) {
1260+
yield* put(
1261+
alertsShowAlert('alerts', 'unexpectedError', {
1262+
error: eraseError,
1263+
}),
12451264
);
1265+
// FIXME: should have a better error reason
1266+
yield* put(didFailToFinish(FailToFinishReasonType.Unknown, eraseError));
1267+
yield* put(firmwareDidFailToFlashEV3());
1268+
yield* cleanup();
1269+
return;
1270+
}
1271+
1272+
// Flash the whole firmware in chunks
1273+
for (let i = 0; i < alignedFirmware.byteLength; i += maxPayloadSize) {
1274+
const payload = alignedFirmware.slice(i, i + maxPayloadSize);
12461275

1247-
if (eraseError) {
1276+
const [, sendError] = yield* sendCommand(0xf2, payload);
1277+
if (sendError) {
12481278
yield* put(
12491279
alertsShowAlert('alerts', 'unexpectedError', {
1250-
error: eraseError,
1280+
error: sendError,
12511281
}),
12521282
);
12531283
// FIXME: should have a better error reason
1254-
yield* put(didFailToFinish(FailToFinishReasonType.Unknown, eraseError));
1284+
yield* put(didFailToFinish(FailToFinishReasonType.Unknown, sendError));
12551285
yield* put(firmwareDidFailToFlashEV3());
12561286
yield* cleanup();
12571287
return;
12581288
}
12591289

1260-
for (let j = 0; j < sectorData.byteLength; j += maxPayloadSize) {
1261-
const payload = sectorData.slice(j, j + maxPayloadSize);
1262-
1263-
const [, sendError] = yield* sendCommand(0xf2, new Uint8Array(payload));
1264-
if (sendError) {
1265-
yield* put(
1266-
alertsShowAlert('alerts', 'unexpectedError', {
1267-
error: sendError,
1268-
}),
1269-
);
1270-
// FIXME: should have a better error reason
1271-
yield* put(didFailToFinish(FailToFinishReasonType.Unknown, sendError));
1272-
yield* put(firmwareDidFailToFlashEV3());
1273-
yield* cleanup();
1274-
return;
1275-
}
1276-
}
1277-
1278-
yield* put(
1279-
didProgress((i + sectorData.byteLength) / action.firmware.byteLength),
1280-
);
1290+
const progress = (i + payload.byteLength) / alignedFirmware.byteLength;
1291+
yield* put(didProgress(progress));
12811292

12821293
yield* put(
12831294
alertsShowAlert(
12841295
'firmware',
12851296
'flashProgress',
12861297
{
12871298
action: 'flash',
1288-
progress: (i + sectorData.byteLength) / action.firmware.byteLength,
1299+
progress: progress,
12891300
},
12901301
firmwareBleProgressToastId,
12911302
true,

0 commit comments

Comments
 (0)