Skip to content

Commit 029a350

Browse files
authored
Merge branch 'master' into ev3-no-version-cmd
2 parents a70010e + 0d0e366 commit 029a350

8 files changed

Lines changed: 48 additions & 77 deletions

File tree

src/firmware/actions.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
// Copyright (c) 2020-2025 The Pybricks Authors
2+
// Copyright (c) 2020-2026 The Pybricks Authors
33

44
import { FirmwareReaderError, HubType } from '@pybricks/firmware';
55
import { createAction } from '../actions';
@@ -139,15 +139,6 @@ export const didStart = createAction(() => ({
139139
type: 'flashFirmware.action.didStart',
140140
}));
141141

142-
/**
143-
* Action that indicates current firmware flashing progress.
144-
* @param value The current progress (0 to 1).
145-
*/
146-
export const didProgress = createAction((value: number) => {
147-
// assert(value >= 0 && value <= 1, 'value out of range');
148-
return { type: 'flashFirmware.action.didProgress', value };
149-
});
150-
151142
/** Action that indicates that flashing firmware completed successfully. */
152143
export const didFinish = createAction(() => ({
153144
type: 'flashFirmware.action.didFinish',
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2025-2026 The Pybricks Authors
3+
4+
import { Intent } from '@blueprintjs/core';
5+
import { Error } from '@blueprintjs/icons';
6+
import React from 'react';
7+
import type { CreateToast } from '../../toasterTypes';
8+
import { useI18n } from './i18n';
9+
10+
const UnsupportedDfuHub: React.FunctionComponent = () => {
11+
const i18n = useI18n();
12+
return (
13+
<>
14+
<p>{i18n.translate('unsupportedDfuHub.message')}</p>
15+
</>
16+
);
17+
};
18+
19+
export const unsupportedDfuHub: CreateToast = (onAction) => ({
20+
message: <UnsupportedDfuHub />,
21+
icon: <Error />,
22+
intent: Intent.DANGER,
23+
onDismiss: () => onAction('dismiss'),
24+
});

src/firmware/alerts/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
// Copyright (c) 2022-2025 The Pybricks Authors
2+
// Copyright (c) 2022-2026 The Pybricks Authors
33

44
import { dfuError } from './DfuError';
55
import { flashProgress } from './FlashProgress';
@@ -8,6 +8,7 @@ import { noDfuInterface } from './NoDfuInterface';
88
import { noWebHid } from './NoWebHid';
99
import { noWebUsb } from './NoWebUsb';
1010
import { releaseButton } from './ReleaseButton';
11+
import { unsupportedDfuHub } from './UnsupportedDfuHub';
1112

1213
export default {
1314
dfuError,
@@ -17,4 +18,5 @@ export default {
1718
noWebHid,
1819
noWebUsb,
1920
releaseButton,
21+
unsupportedDfuHub,
2022
};

src/firmware/alerts/translations/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
"installUsbDriverButton": "Install USB Driver",
2323
"configureUdevRulesButton": "Configure udev rules"
2424
},
25+
"unsupportedDfuHub": {
26+
"message": "This hub has different internal electronics and requires a different firmware. Pybricks does not support this yet. We are working on it!"
27+
},
2528
"noDfuInterface": {
2629
"message": "This is very unusual. The USB device did not contain the expected interface."
2730
},

src/firmware/reducers.test.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
// SPDX-License-Identifier: MIT
2-
// Copyright (c) 2021-2025 The Pybricks Authors
2+
// Copyright (c) 2021-2026 The Pybricks Authors
33

44
import { AnyAction } from 'redux';
55
import {
66
FailToFinishReasonType,
77
didFailToFinish,
88
didFinish,
9-
didProgress,
109
didStart,
1110
} from './actions';
1211
import reducers from './reducers';
@@ -26,7 +25,6 @@ test('initial state', () => {
2625
"isFirmwareFlashEV3InProgress": false,
2726
"isFirmwareFlashUsbDfuInProgress": false,
2827
"isFirmwareRestoreOfficialDfuInProgress": false,
29-
"progress": null,
3028
"restoreOfficialDialog": {
3129
"isOpen": false,
3230
},
@@ -44,8 +42,3 @@ test('flashing', () => {
4442
).flashing,
4543
).toBe(false);
4644
});
47-
48-
test('progress', () => {
49-
expect(reducers({ progress: 1 } as State, didStart()).progress).toBe(null);
50-
expect(reducers({ progress: null } as State, didProgress(1)).progress).toBe(1);
51-
});

src/firmware/reducers.ts

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
// SPDX-License-Identifier: MIT
2-
// Copyright (c) 2021-2025 The Pybricks Authors
2+
// Copyright (c) 2021-2026 The Pybricks Authors
33

44
import { Reducer, combineReducers } from 'redux';
55
import {
66
didFailToFinish,
77
didFinish,
8-
didProgress,
98
didStart,
109
firmwareDidFailToFlashUsbDfu,
1110
firmwareDidFailToRestoreOfficialDfu,
@@ -33,18 +32,6 @@ const flashing: Reducer<boolean> = (state = false, action) => {
3332
return state;
3433
};
3534

36-
const progress: Reducer<number | null> = (state = null, action) => {
37-
if (didStart.matches(action)) {
38-
return null;
39-
}
40-
41-
if (didProgress.matches(action)) {
42-
return action.value;
43-
}
44-
45-
return state;
46-
};
47-
4835
const isFirmwareFlashUsbDfuInProgress: Reducer<boolean> = (state = false, action) => {
4936
if (firmwareFlashUsbDfu.matches(action)) {
5037
return true;
@@ -100,7 +87,6 @@ export default combineReducers({
10087
installPybricksDialog,
10188
restoreOfficialDialog,
10289
flashing,
103-
progress,
10490
isFirmwareFlashUsbDfuInProgress,
10591
isFirmwareRestoreOfficialDfuInProgress,
10692
isFirmwareFlashEV3InProgress,

src/firmware/sagas.test.ts

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
// Copyright (c) 2021-2024 The Pybricks Authors
2+
// Copyright (c) 2021-2026 The Pybricks Authors
33

44
import {
55
FirmwareMetadata,
@@ -43,7 +43,6 @@ import {
4343
MetadataProblem,
4444
didFailToFinish,
4545
didFinish,
46-
didProgress,
4746
didStart,
4847
flashFirmware as flashFirmwareAction,
4948
} from './actions';
@@ -175,9 +174,6 @@ describe('flashFirmware', () => {
175174

176175
saga.put(didRequest(id));
177176

178-
action = await saga.take();
179-
expect(action).toEqual(didProgress(offset / totalFirmwareSize));
180-
181177
action = await saga.take();
182178
expect(action).toEqual(
183179
alertsShowAlert(
@@ -213,9 +209,6 @@ describe('flashFirmware', () => {
213209

214210
saga.put(programResponse(0x33, totalFirmwareSize));
215211

216-
action = await saga.take();
217-
expect(action).toEqual(didProgress(1));
218-
219212
action = await saga.take();
220213
expect(action).toEqual(
221214
alertsShowAlert(
@@ -341,9 +334,6 @@ describe('flashFirmware', () => {
341334

342335
saga.put(didRequest(id));
343336

344-
action = await saga.take();
345-
expect(action).toEqual(didProgress(offset / totalFirmwareSize));
346-
347337
action = await saga.take();
348338
expect(action).toEqual(
349339
alertsShowAlert(
@@ -379,9 +369,6 @@ describe('flashFirmware', () => {
379369

380370
saga.put(programResponse(0xe0, totalFirmwareSize));
381371

382-
action = await saga.take();
383-
expect(action).toEqual(didProgress(1));
384-
385372
action = await saga.take();
386373
expect(action).toEqual(
387374
alertsShowAlert(
@@ -1306,9 +1293,6 @@ describe('flashFirmware', () => {
13061293

13071294
saga.put(didRequest(id));
13081295

1309-
action = await saga.take();
1310-
expect(action).toEqual(didProgress(offset / totalFirmwareSize));
1311-
13121296
action = await saga.take();
13131297
expect(action).toEqual(
13141298
alertsShowAlert(
@@ -1482,9 +1466,6 @@ describe('flashFirmware', () => {
14821466

14831467
saga.put(didRequest(id));
14841468

1485-
action = await saga.take();
1486-
expect(action).toEqual(didProgress(offset / totalFirmwareSize));
1487-
14881469
action = await saga.take();
14891470
expect(action).toEqual(
14901471
alertsShowAlert(
@@ -1664,9 +1645,6 @@ describe('flashFirmware', () => {
16641645

16651646
saga.put(didRequest(id));
16661647

1667-
action = await saga.take();
1668-
expect(action).toEqual(didProgress(offset / totalFirmwareSize));
1669-
16701648
action = await saga.take();
16711649
expect(action).toEqual(
16721650
alertsShowAlert(
@@ -1702,9 +1680,6 @@ describe('flashFirmware', () => {
17021680

17031681
saga.put(programResponse(0xf3, totalFirmwareSize));
17041682

1705-
action = await saga.take();
1706-
expect(action).toEqual(didProgress(1));
1707-
17081683
action = await saga.take();
17091684
expect(action).toEqual(
17101685
alertsShowAlert(
@@ -2230,9 +2205,6 @@ describe('flashFirmware', () => {
22302205

22312206
saga.put(didRequest(id));
22322207

2233-
action = await saga.take();
2234-
expect(action).toEqual(didProgress(offset / totalFirmwareSize));
2235-
22362208
action = await saga.take();
22372209
expect(action).toEqual(
22382210
alertsShowAlert(
@@ -2267,9 +2239,6 @@ describe('flashFirmware', () => {
22672239

22682240
saga.put(programResponse(0x27, totalFirmwareSize));
22692241

2270-
action = await saga.take();
2271-
expect(action).toEqual(didProgress(1));
2272-
22732242
action = await saga.take();
22742243
expect(action).toEqual(
22752244
alertsShowAlert(

src/firmware/sagas.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ import {
7575
MetadataProblem,
7676
didFailToFinish,
7777
didFinish,
78-
didProgress,
7978
didStart,
8079
firmwareDidFailToFlashEV3,
8180
firmwareDidFailToFlashUsbDfu,
@@ -531,8 +530,6 @@ function* handleFlashFirmware(action: ReturnType<typeof flashFirmware>): Generat
531530
);
532531
yield* waitForDidRequest(programAction.id);
533532

534-
yield* put(didProgress(offset / firmware.length));
535-
536533
yield* put(
537534
alertsShowAlert(
538535
'firmware',
@@ -617,8 +614,6 @@ function* handleFlashFirmware(action: ReturnType<typeof flashFirmware>): Generat
617614
yield* disconnectAndCancel();
618615
}
619616

620-
yield* put(didProgress(1));
621-
622617
yield* put(
623618
alertsShowAlert(
624619
'firmware',
@@ -754,6 +749,15 @@ function* handleFlashUsbDfu(action: ReturnType<typeof firmwareFlashUsbDfu>): Gen
754749
return;
755750
}
756751

752+
if (
753+
device.productId === LegoUsbProductId.SpikePrimeBootloader &&
754+
device.deviceVersionMajor !== 1
755+
) {
756+
yield* put(alertsShowAlert('firmware', 'unsupportedDfuHub'));
757+
yield* put(firmwareDidFailToFlashUsbDfu());
758+
return;
759+
}
760+
757761
const dfu = new WebDFU(
758762
device,
759763
// forceInterfacesName is needed to get the flash layout map
@@ -1033,6 +1037,7 @@ function* handleRestoreOfficialDfu(
10331037
}
10341038
}
10351039

1040+
const firmwareEv3ProgressToastId = 'firmware.ev3.progress';
10361041
const getNextEV3MessageId = createCountFunc();
10371042

10381043
function* handleFlashEV3(action: ReturnType<typeof firmwareFlashEV3>): Generator {
@@ -1230,6 +1235,7 @@ function* handleFlashEV3(action: ReturnType<typeof firmwareFlashEV3>): Generator
12301235
error: eraseError,
12311236
}),
12321237
);
1238+
yield* put(alertsHideAlert(firmwareEv3ProgressToastId));
12331239
// FIXME: should have a better error reason
12341240
yield* put(didFailToFinish(FailToFinishReasonType.Unknown, eraseError));
12351241
yield* put(firmwareDidFailToFlashEV3());
@@ -1247,6 +1253,7 @@ function* handleFlashEV3(action: ReturnType<typeof firmwareFlashEV3>): Generator
12471253
error: sendError,
12481254
}),
12491255
);
1256+
yield* put(alertsHideAlert(firmwareEv3ProgressToastId));
12501257
// FIXME: should have a better error reason
12511258
yield* put(didFailToFinish(FailToFinishReasonType.Unknown, sendError));
12521259
yield* put(firmwareDidFailToFlashEV3());
@@ -1255,10 +1262,6 @@ function* handleFlashEV3(action: ReturnType<typeof firmwareFlashEV3>): Generator
12551262
}
12561263
}
12571264

1258-
yield* put(
1259-
didProgress((i + sectorData.byteLength) / action.firmware.byteLength),
1260-
);
1261-
12621265
yield* put(
12631266
alertsShowAlert(
12641267
'firmware',
@@ -1267,7 +1270,7 @@ function* handleFlashEV3(action: ReturnType<typeof firmwareFlashEV3>): Generator
12671270
action: 'flash',
12681271
progress: (i + sectorData.byteLength) / action.firmware.byteLength,
12691272
},
1270-
firmwareBleProgressToastId,
1273+
firmwareEv3ProgressToastId,
12711274
true,
12721275
),
12731276
);
@@ -1281,7 +1284,7 @@ function* handleFlashEV3(action: ReturnType<typeof firmwareFlashEV3>): Generator
12811284
action: 'flash',
12821285
progress: 1,
12831286
},
1284-
firmwareBleProgressToastId,
1287+
firmwareEv3ProgressToastId,
12851288
true,
12861289
),
12871290
);

0 commit comments

Comments
 (0)