mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-07-28 04:08:05 +00:00
firmware: add UI for EV3 firmware flashing
This is just the UI bits (new file template, Pybricks firmware install, official firmware restore). The Pybricks firmware flashing hangs because we don't have a EV3 firmware yet in @pybricks/firmware. Official firmware restore has an alert() placeholder so at least it does something.
This commit is contained in:
+1
-1
@@ -13,7 +13,7 @@
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.11",
|
||||
"@pybricks/firmware": "7.22.0",
|
||||
"@pybricks/ide-docs": "2.20.0",
|
||||
"@pybricks/images": "^1.3.0",
|
||||
"@pybricks/images": "^1.4.0",
|
||||
"@pybricks/jedi": "1.17.0",
|
||||
"@pybricks/mpy-cross-v5": "^2.0.0",
|
||||
"@pybricks/mpy-cross-v6": "^2.0.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022-2023 The Pybricks Authors
|
||||
// Copyright (c) 2022-2025 The Pybricks Authors
|
||||
|
||||
import './hubPicker.scss';
|
||||
import { Radio, RadioGroup } from '@blueprintjs/core';
|
||||
@@ -66,6 +66,12 @@ export const HubPicker: React.FunctionComponent<HubPickerProps> = ({ disabled })
|
||||
label="MINDSTORMS Robot Inventor Hub"
|
||||
/>
|
||||
</Radio>
|
||||
<Radio value={Hub.EV3}>
|
||||
<HubIcon
|
||||
url={new URL('@pybricks/images/hub-ev3.png', import.meta.url)}
|
||||
label="MINDSTORMS EV3"
|
||||
/>
|
||||
</Radio>
|
||||
</RadioGroup>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
// Copyright (c) 2022-2025 The Pybricks Authors
|
||||
|
||||
/** Supported hub types. */
|
||||
export enum Hub {
|
||||
@@ -15,6 +15,8 @@ export enum Hub {
|
||||
Prime = 'primehub',
|
||||
/** SPIKE Essential hub */
|
||||
Essential = 'essentialhub',
|
||||
/** MINDSTORMS EV3 hub */
|
||||
EV3 = 'ev3',
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -25,6 +27,7 @@ export function hubHasUSB(hub: Hub): boolean {
|
||||
case Hub.Prime:
|
||||
case Hub.Essential:
|
||||
case Hub.Inventor:
|
||||
case Hub.EV3:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -52,6 +55,7 @@ export function hubHasExternalFlash(hub: Hub): boolean {
|
||||
case Hub.Prime:
|
||||
case Hub.Essential:
|
||||
case Hub.Inventor:
|
||||
case Hub.EV3:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -69,5 +73,7 @@ export function hubBootloaderType(hub: Hub) {
|
||||
case Hub.City:
|
||||
case Hub.Technic:
|
||||
return 'ble-lwp3-bootloader';
|
||||
case Hub.EV3:
|
||||
return 'usb-ev3';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +309,9 @@ export const language = <monaco.languages.IMonarchLanguage>{
|
||||
*/
|
||||
function createTemplate(hubClassName: string, deviceClassNames: string[]): string {
|
||||
return `from pybricks.hubs import ${hubClassName}
|
||||
from pybricks.pupdevices import ${deviceClassNames.join(', ')}
|
||||
from pybricks.${
|
||||
hubClassName === 'EV3Brick' ? 'ev3devices' : 'pupdevices'
|
||||
} import ${deviceClassNames.join(', ')}
|
||||
from pybricks.parameters import Button, Color, Direction, Port, Side, Stop
|
||||
from pybricks.robotics import DriveBase
|
||||
from pybricks.tools import wait, StopWatch
|
||||
@@ -325,7 +327,8 @@ type HubLabel =
|
||||
| 'technichub'
|
||||
| 'inventorhub'
|
||||
| 'primehub'
|
||||
| 'essentialhub';
|
||||
| 'essentialhub'
|
||||
| 'ev3';
|
||||
|
||||
const templateSnippets: Array<
|
||||
Required<
|
||||
@@ -375,6 +378,18 @@ const templateSnippets: Array<
|
||||
'ColorLightMatrix',
|
||||
]),
|
||||
},
|
||||
{
|
||||
label: 'ev3',
|
||||
documentation: 'Template for MINDSTORMS EV3 program.',
|
||||
insertText: createTemplate('EV3Brick', [
|
||||
'Motor',
|
||||
'ColorSensor',
|
||||
'GyroSensor',
|
||||
'InfraredSensor',
|
||||
'TouchSensor',
|
||||
'UltrasonicSensor',
|
||||
]),
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
+37
-1
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
// Copyright (c) 2020-2025 The Pybricks Authors
|
||||
|
||||
import { FirmwareReaderError, HubType } from '@pybricks/firmware';
|
||||
import { createAction } from '../actions';
|
||||
@@ -429,3 +429,39 @@ export const firmwareDidRestoreOfficialDfu = createAction(() => ({
|
||||
export const firmwareDidFailToRestoreOfficialDfu = createAction(() => ({
|
||||
type: 'firmware.action.didFailToRestoreOfficialDfu',
|
||||
}));
|
||||
|
||||
/**
|
||||
* Versions of official LEGO EV3 firmware available for restore.
|
||||
*/
|
||||
export enum EV3OfficialFirmwareVersion {
|
||||
/** Official LEGO EV3 firmware version 1.09H (Home edition). */
|
||||
home = '1.09H',
|
||||
/** Official LEGO EV3 firmware version 1.09E (Education edition). */
|
||||
education = '1.09E',
|
||||
/** Official LEGO EV3 firmware version 1.10E (only useful for Microsoft MakeCode). */
|
||||
makecode = '1.10E',
|
||||
}
|
||||
|
||||
/**
|
||||
* Action that triggers the restore official EV3 firmware saga.
|
||||
*/
|
||||
export const firmwareRestoreOfficialEV3 = createAction(
|
||||
(version: EV3OfficialFirmwareVersion) => ({
|
||||
type: 'firmware.action.restoreOfficialEV3',
|
||||
version,
|
||||
}),
|
||||
);
|
||||
|
||||
/**
|
||||
* Action that indicates {@link firmwareRestoreOfficialEV3} succeeded.
|
||||
*/
|
||||
export const firmwareDidRestoreOfficialEV3 = createAction(() => ({
|
||||
type: 'firmware.action.didRestoreOfficialEV3',
|
||||
}));
|
||||
|
||||
/**
|
||||
* Action that indicates {@link firmwareRestoreOfficialEV3} failed.
|
||||
*/
|
||||
export const firmwareDidFailToRestoreOfficialEV3 = createAction(() => ({
|
||||
type: 'firmware.action.didFailToRestoreOfficialEV3',
|
||||
}));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022-2023 The Pybricks Authors
|
||||
// Copyright (c) 2022-2025 The Pybricks Authors
|
||||
|
||||
import './bootloaderInstructions.scss';
|
||||
import { Callout, Intent } from '@blueprintjs/core';
|
||||
@@ -117,7 +117,11 @@ const BootloaderInstructions: React.FunctionComponent<BootloaderInstructionsProp
|
||||
const { button, light, lightPattern } = useMemo(() => {
|
||||
return {
|
||||
button: i18n.translate(
|
||||
hubHasBluetoothButton(hubType) ? 'button.bluetooth' : 'button.power',
|
||||
hubType === Hub.EV3
|
||||
? 'button.right'
|
||||
: hubHasBluetoothButton(hubType)
|
||||
? 'button.bluetooth'
|
||||
: 'button.power',
|
||||
),
|
||||
light: i18n.translate(
|
||||
hubHasBluetoothButton(hubType) ? 'light.bluetooth' : 'light.status',
|
||||
@@ -163,13 +167,16 @@ const BootloaderInstructions: React.FunctionComponent<BootloaderInstructionsProp
|
||||
const prepareSteps = useMemo(
|
||||
() => (
|
||||
<>
|
||||
<li>
|
||||
{i18n.translate(
|
||||
hubHasUSB(hubType)
|
||||
? 'instructionGroup.prepare.usb'
|
||||
: 'instructionGroup.prepare.batteries',
|
||||
)}
|
||||
</li>
|
||||
{hubType !== Hub.EV3 && (
|
||||
<li>
|
||||
{i18n.translate(
|
||||
hubHasUSB(hubType)
|
||||
? 'instructionGroup.prepare.usb'
|
||||
: 'instructionGroup.prepare.batteries',
|
||||
)}
|
||||
</li>
|
||||
)}
|
||||
|
||||
<li>{i18n.translate('instructionGroup.prepare.turnOff')}</li>
|
||||
{/* For non-usb recovery, show step about official app */}
|
||||
{recovery && !hubHasUSB(hubType) && (
|
||||
@@ -179,6 +186,12 @@ const BootloaderInstructions: React.FunctionComponent<BootloaderInstructionsProp
|
||||
})}
|
||||
</li>
|
||||
)}
|
||||
|
||||
{hubType === Hub.EV3 && (
|
||||
<li>
|
||||
{i18n.translate('instructionGroup.bootloaderMode.connectUsb')}
|
||||
</li>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
[i18n, recovery, hubType],
|
||||
@@ -210,7 +223,37 @@ const BootloaderInstructions: React.FunctionComponent<BootloaderInstructionsProp
|
||||
|
||||
{/* not strictly necessary, but order is swapped in the video,
|
||||
so we match it here. */}
|
||||
{hubType !== Hub.Essential && hubHasUSB(hubType) && (
|
||||
{(hubType === Hub.Prime || hubType === Hub.Inventor) &&
|
||||
hubHasUSB(hubType) && (
|
||||
<li
|
||||
className={classNames(
|
||||
activeStep === 'connect-usb' && 'pb-active-step',
|
||||
)}
|
||||
>
|
||||
{i18n.translate(
|
||||
'instructionGroup.bootloaderMode.connectUsb',
|
||||
)}
|
||||
</li>
|
||||
)}
|
||||
|
||||
{hubType !== Hub.EV3 && (
|
||||
<li
|
||||
className={classNames(
|
||||
activeStep === 'wait-for-light' && 'pb-active-step',
|
||||
)}
|
||||
>
|
||||
{i18n.translate(
|
||||
'instructionGroup.bootloaderMode.waitForLight',
|
||||
{
|
||||
button,
|
||||
light,
|
||||
lightPattern,
|
||||
},
|
||||
)}
|
||||
</li>
|
||||
)}
|
||||
|
||||
{hubType === Hub.Essential && hubHasUSB(hubType) && (
|
||||
<li
|
||||
className={classNames(
|
||||
activeStep === 'connect-usb' && 'pb-active-step',
|
||||
@@ -220,25 +263,15 @@ const BootloaderInstructions: React.FunctionComponent<BootloaderInstructionsProp
|
||||
</li>
|
||||
)}
|
||||
|
||||
<li
|
||||
className={classNames(
|
||||
activeStep === 'wait-for-light' && 'pb-active-step',
|
||||
)}
|
||||
>
|
||||
{i18n.translate('instructionGroup.bootloaderMode.waitForLight', {
|
||||
button,
|
||||
light,
|
||||
lightPattern,
|
||||
})}
|
||||
</li>
|
||||
|
||||
{hubType === Hub.Essential && hubHasUSB(hubType) && (
|
||||
{hubType === Hub.EV3 && (
|
||||
<li
|
||||
className={classNames(
|
||||
activeStep === 'connect-usb' && 'pb-active-step',
|
||||
activeStep === 'press-power-button' && 'pb-active-step',
|
||||
)}
|
||||
>
|
||||
{i18n.translate('instructionGroup.bootloaderMode.connectUsb')}
|
||||
{i18n.translate(
|
||||
'instructionGroup.bootloaderMode.pressPowerButtonEV3',
|
||||
)}
|
||||
</li>
|
||||
)}
|
||||
|
||||
@@ -262,7 +295,9 @@ const BootloaderInstructions: React.FunctionComponent<BootloaderInstructionsProp
|
||||
)}
|
||||
>
|
||||
{i18n.translate(
|
||||
'instructionGroup.bootloaderMode.releaseButton',
|
||||
hubType === Hub.EV3
|
||||
? 'instructionGroup.bootloaderMode.releaseButtonsEV3'
|
||||
: 'instructionGroup.bootloaderMode.releaseButton',
|
||||
{
|
||||
button,
|
||||
},
|
||||
@@ -342,6 +377,13 @@ const BootloaderInstructions: React.FunctionComponent<BootloaderInstructionsProp
|
||||
1
|
||||
}
|
||||
>
|
||||
{hubType === Hub.EV3 && (
|
||||
<li>
|
||||
{i18n.translate(
|
||||
'instructionGroup.connect.selectEV3FirmwareType',
|
||||
)}
|
||||
</li>
|
||||
)}
|
||||
<li>
|
||||
{i18n.translate(
|
||||
'instructionGroup.connect.clickConnectAndFlash',
|
||||
@@ -389,7 +431,7 @@ const BootloaderInstructions: React.FunctionComponent<BootloaderInstructionsProp
|
||||
</Callout>
|
||||
)}
|
||||
|
||||
{hubHasUSB(hubType) && isWindows() && (
|
||||
{hubHasUSB(hubType) && hubType !== Hub.EV3 && isWindows() && (
|
||||
<Callout intent={Intent.WARNING} icon={<WarningSign />}>
|
||||
{i18n.translate('warning.windows.message', {
|
||||
instructions: (
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
},
|
||||
"button": {
|
||||
"bluetooth": "Bluetooth button",
|
||||
"power": "button"
|
||||
"power": "button",
|
||||
"right": "right button"
|
||||
},
|
||||
"light": {
|
||||
"bluetooth": "Bluetooth light",
|
||||
@@ -37,10 +38,13 @@
|
||||
"waitForLight": "Wait for the {light} to start blinking {lightPattern}.",
|
||||
"waitAppConnect": "The app will automatically connect and start restoring the firmware.",
|
||||
"releaseButton": "Release the {button}.",
|
||||
"keepHolding": "Keep holding the {button} in the next steps. We'll tell you when to let go."
|
||||
"keepHolding": "Keep holding the {button} in the next steps. We'll tell you when to let go.",
|
||||
"pressPowerButtonEV3": "Press the center button to turn on the EV3.",
|
||||
"releaseButtonsEV3": "When the screen says \"Updating...\", release both buttons."
|
||||
},
|
||||
"connect": {
|
||||
"title": "Install:",
|
||||
"selectEV3FirmwareType": "Select the version of firmware to restore below.",
|
||||
"clickConnectAndFlash": "Click the {flashButton} button below.",
|
||||
"selectDevice": "In the pop-up dialog, select {deviceName} and click {connectButton}.",
|
||||
"connectButton": "Connect"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022-2023 The Pybricks Authors
|
||||
// Copyright (c) 2022-2025 The Pybricks Authors
|
||||
|
||||
import './installPybricksDialog.scss';
|
||||
import {
|
||||
@@ -142,11 +142,6 @@ const UnsupportedHubs: React.FunctionComponent = () => {
|
||||
'selectHubPanel.notOnListButton.info.mindstorms.nxt',
|
||||
)}
|
||||
</li>
|
||||
<li>
|
||||
{i18n.translate(
|
||||
'selectHubPanel.notOnListButton.info.mindstorms.ev3',
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
<h4>
|
||||
{i18n.translate('selectHubPanel.notOnListButton.info.poweredUp.title')}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
// Copyright (c) 2022-2025 The Pybricks Authors
|
||||
|
||||
import { createAction } from '../../actions';
|
||||
|
||||
@@ -8,7 +8,7 @@ export const firmwareInstallPybricksDialogShow = createAction(() => ({
|
||||
type: 'firmware.installPybricksDialog.action.show',
|
||||
}));
|
||||
|
||||
type FlashMethod = 'ble-lwp3-bootloader' | 'usb-lego-dfu';
|
||||
type FlashMethod = 'ble-lwp3-bootloader' | 'usb-lego-dfu' | 'usb-ev3';
|
||||
|
||||
/**
|
||||
* Action that indicates the user accepted the install Pybricks firmware dialog.
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
"sponsor": "sponsor"
|
||||
},
|
||||
"rcx": "RCX: Might work in streaming mode.",
|
||||
"nxt": "NXT: We have tested this. It could work!",
|
||||
"ev3": "EV3: Supported using Visual Studio Code."
|
||||
"nxt": "NXT: We have tested this. It could work!"
|
||||
},
|
||||
"poweredUp": {
|
||||
"title": "Other hubs",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022-2023 The Pybricks Authors
|
||||
// Copyright (c) 2022-2025 The Pybricks Authors
|
||||
|
||||
import {
|
||||
Button,
|
||||
@@ -7,10 +7,13 @@ import {
|
||||
DialogStep,
|
||||
Intent,
|
||||
MultistepDialog,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
} from '@blueprintjs/core';
|
||||
import classNames from 'classnames';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useLocalStorage } from 'usehooks-ts';
|
||||
import {
|
||||
legoEducationSpikeRegisteredTrademark,
|
||||
legoMindstormsRegisteredTrademark,
|
||||
@@ -20,7 +23,11 @@ import { Hub, hubHasUSB } from '../../components/hubPicker';
|
||||
import { HubPicker } from '../../components/hubPicker/HubPicker';
|
||||
import { useHubPickerSelectedHub } from '../../components/hubPicker/hooks';
|
||||
import { useSelector } from '../../reducers';
|
||||
import { firmwareRestoreOfficialDfu } from '../actions';
|
||||
import {
|
||||
EV3OfficialFirmwareVersion,
|
||||
firmwareRestoreOfficialDfu,
|
||||
firmwareRestoreOfficialEV3,
|
||||
} from '../actions';
|
||||
import BootloaderInstructions from '../bootloaderInstructions/BootloaderInstructions';
|
||||
import { firmwareRestoreOfficialDialogHide } from './actions';
|
||||
import { useI18n } from './i18n';
|
||||
@@ -51,11 +58,20 @@ const RestoreFirmwarePanel: React.FunctionComponent = () => {
|
||||
s.firmware.isFirmwareFlashUsbDfuInProgress ||
|
||||
s.firmware.isFirmwareRestoreOfficialDfuInProgress,
|
||||
);
|
||||
const [ev3OfficialFirmwareVersion, setEv3OfficialFirmwareVersion] =
|
||||
useLocalStorage<EV3OfficialFirmwareVersion>(
|
||||
'ev3OfficialFirmwareVersion',
|
||||
EV3OfficialFirmwareVersion.home,
|
||||
);
|
||||
|
||||
const handleRestoreButtonClick = useCallback(() => {
|
||||
const handleRestoreDfuButtonClick = useCallback(() => {
|
||||
dispatch(firmwareRestoreOfficialDfu(hubType));
|
||||
}, [dispatch, hubType]);
|
||||
|
||||
const handleRestoreEV3ButtonClick = useCallback(() => {
|
||||
dispatch(firmwareRestoreOfficialEV3(ev3OfficialFirmwareVersion));
|
||||
}, [dispatch, ev3OfficialFirmwareVersion]);
|
||||
|
||||
return (
|
||||
<div className={classNames(Classes.DIALOG_BODY, Classes.RUNNING_TEXT)}>
|
||||
<BootloaderInstructions
|
||||
@@ -63,32 +79,103 @@ const RestoreFirmwarePanel: React.FunctionComponent = () => {
|
||||
recovery
|
||||
flashButtonText={i18n.translate('restoreFirmwarePanel.flashButton')}
|
||||
/>
|
||||
{hubHasUSB(hubType) ? (
|
||||
<>
|
||||
<p>
|
||||
{i18n.translate('restoreFirmwarePanel.instruction2.updateApp', {
|
||||
app:
|
||||
hubType === Hub.Inventor
|
||||
? legoMindstormsRegisteredTrademark
|
||||
: legoEducationSpikeRegisteredTrademark,
|
||||
})}{' '}
|
||||
{hubType !== Hub.Inventor
|
||||
? i18n.translate(
|
||||
'restoreFirmwarePanel.instruction2.updateAppVersion',
|
||||
)
|
||||
: ''}
|
||||
</p>
|
||||
<div className="pb-spacer" />
|
||||
{hubType === Hub.EV3 ? (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-evenly',
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
disabled={inProgress}
|
||||
onClick={handleRestoreButtonClick}
|
||||
onClick={handleRestoreEV3ButtonClick}
|
||||
>
|
||||
{i18n.translate('restoreFirmwarePanel.flashButton')}
|
||||
</Button>
|
||||
</>
|
||||
<RadioGroup
|
||||
selectedValue={ev3OfficialFirmwareVersion}
|
||||
onChange={(event) =>
|
||||
setEv3OfficialFirmwareVersion(
|
||||
event.currentTarget.value as EV3OfficialFirmwareVersion,
|
||||
)
|
||||
}
|
||||
>
|
||||
<Radio
|
||||
value={EV3OfficialFirmwareVersion.home}
|
||||
checked={
|
||||
ev3OfficialFirmwareVersion ===
|
||||
EV3OfficialFirmwareVersion.home
|
||||
}
|
||||
>
|
||||
{i18n.translate(
|
||||
'restoreFirmwarePanel.ev3FirmwareType.home',
|
||||
)}
|
||||
</Radio>
|
||||
<Radio
|
||||
value={EV3OfficialFirmwareVersion.education}
|
||||
checked={
|
||||
ev3OfficialFirmwareVersion ===
|
||||
EV3OfficialFirmwareVersion.education
|
||||
}
|
||||
>
|
||||
{i18n.translate(
|
||||
'restoreFirmwarePanel.ev3FirmwareType.education',
|
||||
)}
|
||||
</Radio>
|
||||
<Radio
|
||||
value={EV3OfficialFirmwareVersion.makecode}
|
||||
checked={
|
||||
ev3OfficialFirmwareVersion ===
|
||||
EV3OfficialFirmwareVersion.makecode
|
||||
}
|
||||
>
|
||||
{i18n.translate(
|
||||
'restoreFirmwarePanel.ev3FirmwareType.makecode',
|
||||
)}
|
||||
</Radio>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
) : (
|
||||
<p>{i18n.translate('restoreFirmwarePanel.instruction2.ble.message')}</p>
|
||||
<>
|
||||
{hubHasUSB(hubType) ? (
|
||||
<>
|
||||
<p>
|
||||
{i18n.translate(
|
||||
'restoreFirmwarePanel.instruction2.updateApp',
|
||||
{
|
||||
app:
|
||||
hubType === Hub.Inventor
|
||||
? legoMindstormsRegisteredTrademark
|
||||
: legoEducationSpikeRegisteredTrademark,
|
||||
},
|
||||
)}{' '}
|
||||
{hubType !== Hub.Inventor
|
||||
? i18n.translate(
|
||||
'restoreFirmwarePanel.instruction2.updateAppVersion',
|
||||
)
|
||||
: ''}
|
||||
</p>
|
||||
<div className="pb-spacer" />
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
disabled={inProgress}
|
||||
onClick={handleRestoreDfuButtonClick}
|
||||
>
|
||||
{i18n.translate('restoreFirmwarePanel.flashButton')}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<p>
|
||||
{i18n.translate(
|
||||
'restoreFirmwarePanel.instruction2.ble.message',
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
"updateApp": "Once the recovery is complete, use the {app} app to get the latest official firmware.",
|
||||
"updateAppVersion": "You can use version 2 (legacy) or version 3 to do so."
|
||||
},
|
||||
"flashButton": "Restore"
|
||||
"flashButton": "Restore",
|
||||
"ev3FirmwareType": {
|
||||
"home": "Home edition (v1.09H)",
|
||||
"education": "Education edition (v1.09E)",
|
||||
"makecode": "Microsoft MakeCode (v1.10E)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-1
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2024 The Pybricks Authors
|
||||
// Copyright (c) 2020-2025 The Pybricks Authors
|
||||
|
||||
import {
|
||||
FirmwareReader,
|
||||
@@ -73,11 +73,13 @@ import {
|
||||
didStart,
|
||||
firmwareDidFailToFlashUsbDfu,
|
||||
firmwareDidFailToRestoreOfficialDfu,
|
||||
firmwareDidFailToRestoreOfficialEV3,
|
||||
firmwareDidFlashUsbDfu,
|
||||
firmwareDidRestoreOfficialDfu,
|
||||
firmwareFlashUsbDfu,
|
||||
firmwareInstallPybricks,
|
||||
firmwareRestoreOfficialDfu,
|
||||
firmwareRestoreOfficialEV3,
|
||||
flashFirmware,
|
||||
} from './actions';
|
||||
import { firmwareDfuWindowsDriverInstallDialogDialogShow } from './dfuWindowsDriverInstallDialog/actions';
|
||||
@@ -912,6 +914,10 @@ function* handleInstallPybricks(): Generator {
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'usb-ev3':
|
||||
// TODO: implement flashing via EV3 USB
|
||||
console.error('Flashing via EV3 USB is not implemented yet');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -988,9 +994,18 @@ function* handleRestoreOfficialDfu(
|
||||
}
|
||||
}
|
||||
|
||||
function* handleRestoreOfficialEV3(
|
||||
action: ReturnType<typeof firmwareRestoreOfficialEV3>,
|
||||
): Generator {
|
||||
action;
|
||||
alert('Flashing via EV3 USB is not implemented yet');
|
||||
yield* put(firmwareDidFailToRestoreOfficialEV3());
|
||||
}
|
||||
|
||||
export default function* (): Generator {
|
||||
yield* takeEvery(flashFirmware, handleFlashFirmware);
|
||||
yield* takeEvery(firmwareFlashUsbDfu, handleFlashUsbDfu);
|
||||
yield* takeEvery(firmwareInstallPybricks, handleInstallPybricks);
|
||||
yield* takeEvery(firmwareRestoreOfficialDfu, handleRestoreOfficialDfu);
|
||||
yield* takeEvery(firmwareRestoreOfficialEV3, handleRestoreOfficialEV3);
|
||||
}
|
||||
|
||||
@@ -2939,10 +2939,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@pybricks/images@npm:^1.3.0":
|
||||
version: 1.3.0
|
||||
resolution: "@pybricks/images@npm:1.3.0"
|
||||
checksum: aad203588d967cd2dc3859226a4349992fec45f443b74a6b8e55f714c895fa25ee147c2e906b604bc48f93c48cd75526ec487a254ca142426d61ba29b7101d14
|
||||
"@pybricks/images@npm:^1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@pybricks/images@npm:1.4.0"
|
||||
checksum: 644be26497cb648bebab6be5f7cc5dae28fbe210f1cb5435316d10411a9a4a016abc37fe6fb52c2dd06c2e45bcdb5c38db0a6fbb31690ee4ea6bfdacbc67c25c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2976,7 +2976,7 @@ __metadata:
|
||||
"@pmmmwh/react-refresh-webpack-plugin": ^0.5.11
|
||||
"@pybricks/firmware": 7.22.0
|
||||
"@pybricks/ide-docs": 2.20.0
|
||||
"@pybricks/images": ^1.3.0
|
||||
"@pybricks/images": ^1.4.0
|
||||
"@pybricks/jedi": 1.17.0
|
||||
"@pybricks/mpy-cross-v5": ^2.0.0
|
||||
"@pybricks/mpy-cross-v6": ^2.0.0
|
||||
|
||||
Reference in New Issue
Block a user