Skip to content

Commit c36c1ae

Browse files
committed
firmware: Flash the whole EV3 at once.
Research in pybricks/support#2375 (comment) and below shows that erasing the firmware and writing it sector by sector causes hangs during the flashing process. Instead, we should erase the whole firmware at once, and flash it at once. This successfully loads new EV3 firmware without hangs.
1 parent 44237e0 commit c36c1ae

File tree

1 file changed

+49
-35
lines changed

1 file changed

+49
-35
lines changed

src/firmware/sagas.ts

Lines changed: 49 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,63 +1238,77 @@ function* handleFlashEV3(action: ReturnType<typeof firmwareFlashEV3>): Generator
12381238
// FIXME: should be called much earlier.
12391239
yield* put(didStart());
12401240

1241-
const sectorSize = 64 * 1024; // flash memory sector size
12421241
const maxPayloadSize = 1018; // maximum payload size for EV3 commands
12431242

1244-
for (let i = 0; i < action.firmware.byteLength; i += sectorSize) {
1245-
const sectorData = action.firmware.slice(i, i + sectorSize);
1246-
assert(sectorData.byteLength <= sectorSize, 'sector data too large');
1243+
const erasePayload = new DataView(new ArrayBuffer(8));
1244+
erasePayload.setUint32(0, 0, true); // start address
1245+
erasePayload.setUint32(4, action.firmware.byteLength, true); // size
1246+
console.debug(`Erasing bytes [0x0, ${hex(action.firmware.byteLength, 0)})`);
12471247

1248-
const erasePayload = new DataView(new ArrayBuffer(8));
1249-
erasePayload.setUint32(0, i, true);
1250-
erasePayload.setUint32(4, sectorData.byteLength, true);
1251-
const [, eraseError] = yield* sendCommand(
1252-
0xf0,
1253-
new Uint8Array(erasePayload.buffer),
1248+
yield* put(
1249+
alertsShowAlert(
1250+
'firmware',
1251+
'flashProgress',
1252+
{
1253+
action: 'erase',
1254+
progress: undefined,
1255+
},
1256+
firmwareBleProgressToastId,
1257+
true,
1258+
),
1259+
);
1260+
1261+
const [, eraseError] = yield* sendCommand(
1262+
0xf0,
1263+
new Uint8Array(erasePayload.buffer),
1264+
);
1265+
1266+
if (eraseError) {
1267+
yield* put(
1268+
alertsShowAlert('alerts', 'unexpectedError', {
1269+
error: eraseError,
1270+
}),
1271+
);
1272+
// FIXME: should have a better error reason
1273+
yield* put(didFailToFinish(FailToFinishReasonType.Unknown, eraseError));
1274+
yield* put(firmwareDidFailToFlashEV3());
1275+
yield* cleanup();
1276+
return;
1277+
}
1278+
1279+
// If we don't write an exact multiple of the sector size, the flash process
1280+
// will hang on the last write we send.
1281+
const firmware = action.firmware;
1282+
for (let i = 0; i < firmware.byteLength; i += maxPayloadSize) {
1283+
const payload = firmware.slice(i, i + maxPayloadSize);
1284+
console.debug(
1285+
`Programming bytes [${hex(i, 0)}, ${hex(i + maxPayloadSize, 0)})`,
12541286
);
12551287

1256-
if (eraseError) {
1288+
const [, sendError] = yield* sendCommand(0xf2, new Uint8Array(payload));
1289+
if (sendError) {
12571290
yield* put(
12581291
alertsShowAlert('alerts', 'unexpectedError', {
1259-
error: eraseError,
1292+
error: sendError,
12601293
}),
12611294
);
12621295
// FIXME: should have a better error reason
1263-
yield* put(didFailToFinish(FailToFinishReasonType.Unknown, eraseError));
1296+
yield* put(didFailToFinish(FailToFinishReasonType.Unknown, sendError));
12641297
yield* put(firmwareDidFailToFlashEV3());
12651298
yield* cleanup();
12661299
return;
12671300
}
12681301

1269-
for (let j = 0; j < sectorData.byteLength; j += maxPayloadSize) {
1270-
const payload = sectorData.slice(j, j + maxPayloadSize);
1271-
1272-
const [, sendError] = yield* sendCommand(0xf2, new Uint8Array(payload));
1273-
if (sendError) {
1274-
yield* put(
1275-
alertsShowAlert('alerts', 'unexpectedError', {
1276-
error: sendError,
1277-
}),
1278-
);
1279-
// FIXME: should have a better error reason
1280-
yield* put(didFailToFinish(FailToFinishReasonType.Unknown, sendError));
1281-
yield* put(firmwareDidFailToFlashEV3());
1282-
yield* cleanup();
1283-
return;
1284-
}
1285-
}
1286-
1287-
yield* put(
1288-
didProgress((i + sectorData.byteLength) / action.firmware.byteLength),
1289-
);
1302+
const progress = (i + payload.byteLength) / firmware.byteLength;
1303+
yield* put(didProgress(progress));
12901304

12911305
yield* put(
12921306
alertsShowAlert(
12931307
'firmware',
12941308
'flashProgress',
12951309
{
12961310
action: 'flash',
1297-
progress: (i + sectorData.byteLength) / action.firmware.byteLength,
1311+
progress: progress,
12981312
},
12991313
firmwareBleProgressToastId,
13001314
true,

0 commit comments

Comments
 (0)