firmware/sagas: implement restoring official firmware

Closes: https://github.com/pybricks/pybricks-code/issues/1104
This commit is contained in:
David Lechner
2022-11-18 19:28:00 -06:00
committed by David Lechner
parent cf99ab223d
commit b5b857bca5
5 changed files with 86 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
Official LEGO firmware is redistributed with permission for the express purpose
of restoring the firmware on LEGO hardware. Any other use is governed by the
LEGO EULA in the respective official LEGO apps.
Binary file not shown.
+78
View File
@@ -34,6 +34,7 @@ import {
alertsHideAlert,
alertsShowAlert,
} from '../alerts/actions';
import { Hub } from '../components/hubPicker';
import {
checksumRequest,
checksumResponse,
@@ -72,9 +73,12 @@ import {
didProgress,
didStart,
firmwareDidFailToFlashUsbDfu,
firmwareDidFailToRestoreOfficialDfu,
firmwareDidFlashUsbDfu,
firmwareDidRestoreOfficialDfu,
firmwareFlashUsbDfu,
firmwareInstallPybricks,
firmwareRestoreOfficialDfu,
flashFirmware,
} from './actions';
import {
@@ -899,8 +903,82 @@ function* handleInstallPybricks(): Generator {
}
}
function getUrlForHubType(hub: Hub): URL {
switch (hub) {
case Hub.Prime:
case Hub.Inventor:
return new URL('./assets/prime-v1.3.00.0000-e8c274a.bin', import.meta.url);
case Hub.Essential:
return new URL(
'./assets/essential-v1.0.00.0071-191f3ad.bin',
import.meta.url,
);
default:
throw new Error(`unsupported hub: ${hub}`);
}
}
function getHubTypeForHub(hub: Hub): HubType {
switch (hub) {
case Hub.Prime:
case Hub.Inventor:
return HubType.PrimeHub;
case Hub.Essential:
return HubType.EssentialHub;
default:
throw new Error(`unsupported hub: ${hub}`);
}
}
function* handleRestoreOfficialDfu(
action: ReturnType<typeof firmwareRestoreOfficialDfu>,
): Generator {
try {
const url = getUrlForHubType(action.hub);
const response = yield* call(() => fetch(url));
if (!response.ok) {
// TODO: replace with proper alert
// istanbul ignore if
if (process.env.NODE_ENV !== 'test') {
console.error(response);
}
throw new Error('failed to fetch');
}
const firmwareBlob = yield* call(() => response.blob());
const firmware = yield* call(() => firmwareBlob.arrayBuffer());
yield* put(firmwareFlashUsbDfu(firmware, getHubTypeForHub(action.hub)));
const { didFailToFlash } = yield* race({
didFlash: take(firmwareDidFlashUsbDfu),
didFailToFlash: take(firmwareDidFailToFlashUsbDfu),
});
if (didFailToFlash) {
yield* put(firmwareDidFailToRestoreOfficialDfu());
return;
}
yield* put(firmwareDidRestoreOfficialDfu());
} catch (err) {
// istanbul ignore if
if (process.env.NODE_ENV !== 'test') {
console.error(err);
}
yield* put(
alertsShowAlert('alerts', 'unexpectedError', { error: ensureError(err) }),
);
yield* put(firmwareDidFailToRestoreOfficialDfu());
}
}
export default function* (): Generator {
yield* takeEvery(flashFirmware, handleFlashFirmware);
yield* takeEvery(firmwareFlashUsbDfu, handleFlashUsbDfu);
yield* takeEvery(firmwareInstallPybricks, handleInstallPybricks);
yield* takeEvery(firmwareRestoreOfficialDfu, handleRestoreOfficialDfu);
}