Skip to content

Commit ef39410

Browse files
Initial work on full flashing speed (#397)
Almost all the impact is from the connection library option but the other tweaks make it easier to rule things out. We're still spending seconds of full flashing time updating the UI only so there's more that can be done here. To reproduce the original issue flash a Python hex before either the data collection or the MakeCode hexes.
1 parent f40354a commit ef39410

File tree

9 files changed

+100
-102
lines changed

9 files changed

+100
-102
lines changed

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"@emotion/react": "^11.11.4",
6161
"@emotion/styled": "^11.11.5",
6262
"@microbit/makecode-embed": "^0.0.0-alpha.7",
63-
"@microbit/microbit-connection": "^0.0.0-alpha.21",
63+
"@microbit/microbit-connection": "^0.0.0-alpha.25",
6464
"@microbit/ml-header-generator": "^0.4.3",
6565
"@tensorflow/tfjs": "^4.20.0",
6666
"@types/w3c-web-serial": "^1.0.6",

src/components/ConnectionFlowDialogs.tsx

Lines changed: 36 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { useDisclosure } from "@chakra-ui/react";
2-
import { useCallback, useEffect, useState } from "react";
1+
import { useCallback, useState } from "react";
32
import { bluetoothUniversalHex } from "../connection-stage-actions";
43
import {
54
ConnectionFlowStep,
65
ConnectionFlowType,
76
ConnectionStage,
87
useConnectionStage,
98
} from "../connection-stage-hooks";
9+
import { useLogging } from "../logging/logging-hooks";
1010
import BrokenFirmwareDialog from "./BrokenFirmwareDialog";
1111
import ConnectBatteryDialog from "./ConnectBatteryDialog";
1212
import ConnectCableDialog, {
@@ -23,29 +23,19 @@ import TryAgainDialog from "./TryAgainDialog";
2323
import UnsupportedMicrobitDialog from "./UnsupportedMicrobitDialog";
2424
import WebUsbBluetoothUnsupportedDialog from "./WebUsbBluetoothUnsupportedDialog";
2525
import WhatYouWillNeedDialog from "./WhatYouWillNeedDialog";
26-
import { useLogging } from "../logging/logging-hooks";
2726

2827
const ConnectionDialogs = () => {
2928
const { stage, actions } = useConnectionStage();
3029
const logging = useLogging();
3130
const [flashProgress, setFlashProgress] = useState<number>(0);
32-
const { isOpen, onClose: onCloseDialog, onOpen } = useDisclosure();
3331
const [microbitName, setMicrobitName] = useState<string | undefined>(
3432
stage.bluetoothMicrobitName
3533
);
3634
const onClose = useCallback(() => {
3735
actions.setFlowStep(ConnectionFlowStep.None);
38-
onCloseDialog();
39-
}, [actions, onCloseDialog]);
36+
}, [actions]);
4037

41-
useEffect(() => {
42-
if (stage.flowStep !== ConnectionFlowStep.None && !isOpen) {
43-
onOpen();
44-
}
45-
if (stage.flowStep === ConnectionFlowStep.None && isOpen) {
46-
onClose();
47-
}
48-
}, [isOpen, onClose, onOpen, stage]);
38+
const isOpen = stage.flowStep !== ConnectionFlowStep.None;
4939

5040
const progressCallback = useCallback(
5141
(progress: number) => {
@@ -57,51 +47,8 @@ const ConnectionDialogs = () => {
5747
[actions, stage.flowStep]
5848
);
5949

60-
const onChangeMicrobitName = useCallback(
61-
(name: string) => {
62-
actions.onChangeMicrobitName(name);
63-
setMicrobitName(name);
64-
},
65-
[actions]
66-
);
67-
68-
const onFlashSuccess = useCallback((newStage: ConnectionStage) => {
69-
// Inferring microbit name saves the user from entering the pattern
70-
// for bluetooth connection flow
71-
if (newStage.bluetoothMicrobitName) {
72-
setMicrobitName(newStage.bluetoothMicrobitName);
73-
}
74-
}, []);
75-
76-
const connectAndFlash = useCallback(async () => {
77-
if (stage.flowType === ConnectionFlowType.ConnectRadioBridge) {
78-
logging.event({
79-
type: "connect-user",
80-
message: "radio-bridge",
81-
});
82-
}
83-
await actions.connectAndflashMicrobit(progressCallback, onFlashSuccess);
84-
}, [actions, logging, onFlashSuccess, progressCallback, stage.flowType]);
85-
86-
const onSkip = useCallback(
87-
() => actions.setFlowStep(ConnectionFlowStep.ConnectBattery),
88-
[actions]
89-
);
90-
const onInstructManualFlashing = useCallback(
91-
() => actions.setFlowStep(ConnectionFlowStep.ManualFlashingTutorial),
92-
[actions]
93-
);
94-
9550
const dialogCommonProps = { isOpen, onClose };
9651

97-
const handleConnectBluetooth = useCallback(() => {
98-
logging.event({
99-
type: "connect-user",
100-
message: "bluetooth",
101-
});
102-
void actions.connectBluetooth();
103-
}, [actions, logging]);
104-
10552
switch (stage.flowStep) {
10653
case ConnectionFlowStep.ReconnectFailedTwice:
10754
case ConnectionFlowStep.Start: {
@@ -134,12 +81,29 @@ const ConnectionDialogs = () => {
13481
onBackClick={actions.onBackClick}
13582
onNextClick={actions.onNextClick}
13683
config={config}
137-
onSkip={onSkip}
84+
onSkip={() => actions.setFlowStep(ConnectionFlowStep.ConnectBattery)}
13885
onSwitch={actions.switchFlowType}
13986
/>
14087
);
14188
}
14289
case ConnectionFlowStep.WebUsbFlashingTutorial: {
90+
const connectAndFlash = async () => {
91+
const onFlashSuccess = (newStage: ConnectionStage) => {
92+
// Inferring microbit name saves the user from entering the pattern
93+
// for bluetooth connection flow
94+
if (newStage.bluetoothMicrobitName) {
95+
setMicrobitName(newStage.bluetoothMicrobitName);
96+
}
97+
};
98+
99+
if (stage.flowType === ConnectionFlowType.ConnectRadioBridge) {
100+
logging.event({
101+
type: "connect-user",
102+
message: "radio-bridge",
103+
});
104+
}
105+
await actions.connectAndflashMicrobit(progressCallback, onFlashSuccess);
106+
};
143107
return (
144108
<SelectMicrobitUsbDialog
145109
{...dialogCommonProps}
@@ -175,11 +139,21 @@ const ConnectionDialogs = () => {
175139
onBackClick={actions.onBackClick}
176140
onNextClick={actions.onNextClick}
177141
microbitName={microbitName}
178-
onChangeMicrobitName={onChangeMicrobitName}
142+
onChangeMicrobitName={(name: string) => {
143+
actions.onChangeMicrobitName(name);
144+
setMicrobitName(name);
145+
}}
179146
/>
180147
);
181148
}
182149
case ConnectionFlowStep.ConnectBluetoothTutorial: {
150+
const handleConnectBluetooth = () => {
151+
logging.event({
152+
type: "connect-user",
153+
message: "bluetooth",
154+
});
155+
void actions.connectBluetooth();
156+
};
183157
return (
184158
<SelectMicrobitBluetoothDialog
185159
{...dialogCommonProps}
@@ -227,7 +201,9 @@ const ConnectionDialogs = () => {
227201
return (
228202
<BrokenFirmwareDialog
229203
{...dialogCommonProps}
230-
onSkip={onInstructManualFlashing}
204+
onSkip={() =>
205+
actions.setFlowStep(ConnectionFlowStep.ManualFlashingTutorial)
206+
}
231207
onTryAgain={actions.onTryAgain}
232208
/>
233209
);

src/components/DownloadDialogs.tsx

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,24 @@
1-
import { useCallback } from "react";
1+
import { useDownloadActions } from "../hooks/download-hooks";
2+
import { useLogging } from "../logging/logging-hooks";
3+
import { DownloadStep } from "../model";
4+
import { useStore } from "../store";
5+
import { getTotalNumSamples } from "../utils/gestures";
26
import ConnectCableDialog from "./ConnectCableDialog";
3-
import DownloadProgressDialog from "./DownloadProgressDialog";
7+
import ConnectRadioDataCollectionMicrobitDialog from "./ConnectRadioDataCollectionMicrobitDialog";
48
import DownloadChooseMicrobitDialog from "./DownloadChooseMicrobitDialog";
59
import DownloadHelpDialog from "./DownloadHelpDialog";
10+
import DownloadProgressDialog from "./DownloadProgressDialog";
11+
import IncompatibleEditorDevice from "./IncompatibleEditorDevice";
612
import ManualFlashingDialog from "./ManualFlashingDialog";
713
import SelectMicrobitUsbDialog from "./SelectMicrobitUsbDialog";
8-
import { DownloadStep as DownloadStep } from "../model";
9-
import { useDownloadActions } from "../hooks/download-hooks";
10-
import { useStore } from "../store";
1114
import UnplugRadioLinkMicrobitDialog from "./UnplugRadioLinkMicrobitDialog";
12-
import ConnectRadioDataCollectionMicrobitDialog from "./ConnectRadioDataCollectionMicrobitDialog";
13-
import IncompatibleEditorDevice from "./IncompatibleEditorDevice";
14-
import { useLogging } from "../logging/logging-hooks";
15-
import { getTotalNumSamples } from "../utils/gestures";
1615

1716
const DownloadDialogs = () => {
1817
const actions = useDownloadActions();
1918
const stage = useStore((s) => s.download);
19+
const flashingProgress = useStore((s) => s.downloadFlashingProgress);
2020
const gestures = useStore((s) => s.gestures);
2121
const logging = useLogging();
22-
const handleDownloadProject = useCallback(async () => {
23-
logging.event({
24-
type: "hex-download",
25-
detail: {
26-
actions: gestures.length,
27-
samples: getTotalNumSamples(gestures),
28-
},
29-
});
30-
await actions.connectAndFlashMicrobit(stage);
31-
}, [actions, gestures, logging, stage]);
3222

3323
switch (stage.step) {
3424
case DownloadStep.Help:
@@ -81,7 +71,18 @@ const DownloadDialogs = () => {
8171
onNextClick={actions.getOnNext()}
8272
/>
8373
);
84-
case DownloadStep.WebUsbFlashingTutorial:
74+
case DownloadStep.WebUsbFlashingTutorial: {
75+
const handleDownloadProject = async () => {
76+
logging.event({
77+
type: "hex-download",
78+
detail: {
79+
actions: gestures.length,
80+
samples: getTotalNumSamples(gestures),
81+
},
82+
});
83+
await actions.connectAndFlashMicrobit(stage);
84+
};
85+
8586
return (
8687
<SelectMicrobitUsbDialog
8788
isOpen
@@ -90,12 +91,13 @@ const DownloadDialogs = () => {
9091
onNextClick={handleDownloadProject}
9192
/>
9293
);
94+
}
9395
case DownloadStep.FlashingInProgress:
9496
return (
9597
<DownloadProgressDialog
9698
isOpen
9799
headingId="downloading-header"
98-
progress={stage.flashProgress * 100}
100+
progress={flashingProgress * 100}
99101
/>
100102
);
101103
case DownloadStep.ManualFlashingTutorial:

src/components/DownloadProgressDialog.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ export const getHeadingId = (flowType: ConnectionFlowType) => {
2929
}
3030
};
3131

32+
const noop = () => {};
33+
3234
const DownloadProgressDialog = ({
3335
isOpen,
3436
headingId,
@@ -39,7 +41,7 @@ const DownloadProgressDialog = ({
3941
closeOnOverlayClick={false}
4042
motionPreset="none"
4143
isOpen={isOpen}
42-
onClose={() => {}}
44+
onClose={noop}
4345
size="3xl"
4446
isCentered
4547
>

src/connect-actions.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,10 @@ export class ConnectActions {
122122
try {
123123
await usb.flash(data, {
124124
partial: true,
125-
progress: (v: number | undefined) => progress(v ?? 100),
125+
// If we could improve the re-rendering due to progress further we can remove this and accept the
126+
// default which updates 4x as often.
127+
minimumProgressIncrement: 0.01,
128+
progress: (v: number | undefined) => progress(v ?? 1),
126129
});
127130
return ConnectResult.Success;
128131
} catch (e) {

src/hooks/download-hooks.tsx

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { useSettings, useStore } from "../store";
2323
import { downloadHex } from "../utils/fs-util";
2424

2525
export class DownloadProjectActions {
26+
private flashingProgressCallback: (value: number) => void;
2627
constructor(
2728
private state: DownloadState,
2829
private setState: (stage: DownloadState) => void,
@@ -31,8 +32,16 @@ export class DownloadProjectActions {
3132
private connectActions: ConnectActions,
3233
private connectionStage: ConnectionStage,
3334
private connectionStageActions: ConnectionStageActions,
34-
private connectionStatus: ConnectionStatus
35-
) {}
35+
private connectionStatus: ConnectionStatus,
36+
flashingProgressCallback: (value: number) => void
37+
) {
38+
this.flashingProgressCallback = (value: number) => {
39+
if (state.step !== DownloadStep.FlashingInProgress) {
40+
setState({ ...state, step: DownloadStep.FlashingInProgress });
41+
}
42+
flashingProgressCallback(value);
43+
};
44+
}
3645

3746
clearMakeCodeUsbDevice = () => {
3847
this.setState({ ...this.state, usbDevice: undefined });
@@ -196,14 +205,6 @@ export class DownloadProjectActions {
196205
}
197206
};
198207

199-
private flashingProgressCallback = (progress: number) => {
200-
this.setState({
201-
...this.state,
202-
step: DownloadStep.FlashingInProgress,
203-
flashProgress: progress,
204-
});
205-
};
206-
207208
getOnNext = () => {
208209
const nextStep = this.getNextStep();
209210
return nextStep ? () => this.setStep(nextStep) : undefined;
@@ -270,6 +271,9 @@ export class DownloadProjectActions {
270271

271272
export const useDownloadActions = (): DownloadProjectActions => {
272273
const stage = useStore((s) => s.download);
274+
const setDownloadFlashingProgress = useStore(
275+
(s) => s.setDownloadFlashingProgress
276+
);
273277
const setStage = useStore((s) => s.setDownload);
274278
const [settings, setSettings] = useSettings();
275279
const connectActions = useConnectActions();
@@ -288,13 +292,15 @@ export const useDownloadActions = (): DownloadProjectActions => {
288292
connectActions,
289293
connectionStage,
290294
connectionStageActions,
291-
connectionStatus
295+
connectionStatus,
296+
setDownloadFlashingProgress
292297
),
293298
[
294299
connectActions,
295300
connectionStage,
296301
connectionStageActions,
297302
connectionStatus,
303+
setDownloadFlashingProgress,
298304
setSettings,
299305
setStage,
300306
settings,

src/model.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ export enum MicrobitToFlash {
130130
export interface DownloadState {
131131
step: DownloadStep;
132132
microbitToFlash: MicrobitToFlash;
133-
flashProgress: number;
134133
hex?: HexData;
135134
// The micro:bit used to flash the hex. We remember your choice for easy code
136135
// iteration for as long as the editor is open.

0 commit comments

Comments
 (0)