Skip to content

Commit a18f007

Browse files
More integrated approach to native BLE
1 parent e936baf commit a18f007

13 files changed

+444
-271
lines changed

src/components/ConnectionFlowDialogs.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,7 @@ const ConnectionDialogs = () => {
108108
message: "radio-bridge",
109109
});
110110
}
111-
await actions.connectAndFlashMicrobitViaWebUSB(
112-
progressCallback,
113-
onFlashSuccess
114-
);
111+
await actions.connectAndFlash(progressCallback, onFlashSuccess);
115112
};
116113
return (
117114
<SelectMicrobitUsbDialog
@@ -142,9 +139,9 @@ const ConnectionDialogs = () => {
142139
/>
143140
);
144141
}
145-
case ConnectionFlowStep.EnterBluetoothPattern: {
142+
case ConnectionFlowStep.BluetoothPattern: {
146143
const handleConnectNativeBluetooth = async () => {
147-
await actions.connectAndFlashMicrobitViaBluetooth(progressCallback);
144+
await actions.connectAndFlash(progressCallback, () => {});
148145
};
149146
const onNextClick =
150147
stage.flowType === ConnectionFlowType.ConnectNativeBluetooth
@@ -163,7 +160,7 @@ const ConnectionDialogs = () => {
163160
/>
164161
);
165162
}
166-
case ConnectionFlowStep.ConnectBluetoothTutorial: {
163+
case ConnectionFlowStep.WebBluetoothPreConnectTutorial: {
167164
const handleConnectBluetooth = () => {
168165
logging.event({
169166
type: "connect-user",
@@ -192,7 +189,7 @@ const ConnectionDialogs = () => {
192189
/>
193190
);
194191
}
195-
case ConnectionFlowStep.ConnectingBluetooth: {
192+
case ConnectionFlowStep.BluetoothConnect: {
196193
return (
197194
<LoadingDialog isOpen={isOpen} headingId="connect-bluetooth-heading" />
198195
);

src/components/DownloadChooseMicrobitDialog.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import twoMicrobitsImage from "../images/stylised-two-microbits-black.svg";
2222
import ConnectContainerDialog, {
2323
ConnectContainerDialogProps,
2424
} from "./ConnectContainerDialog";
25-
import { DownloadState, MicrobitToFlash } from "../model";
25+
import { DownloadState, SameOrDifferentChoice } from "../model";
2626

2727
export interface DownloadChooseMicrobitDialogProps
2828
extends Omit<ConnectContainerDialogProps, "children" | "headingId"> {
@@ -31,7 +31,9 @@ export interface DownloadChooseMicrobitDialogProps
3131
stage: DownloadState;
3232
}
3333

34-
type MicrobitOption = MicrobitToFlash.Same | MicrobitToFlash.Different;
34+
type MicrobitOption =
35+
| SameOrDifferentChoice.Same
36+
| SameOrDifferentChoice.Different;
3537

3638
const DownloadChooseMicrobitDialog = ({
3739
onSameMicrobitClick,
@@ -40,9 +42,9 @@ const DownloadChooseMicrobitDialog = ({
4042
...props
4143
}: DownloadChooseMicrobitDialogProps) => {
4244
const defaultValue =
43-
stage.microbitToFlash === MicrobitToFlash.Default
44-
? MicrobitToFlash.Same
45-
: stage.microbitToFlash;
45+
stage.microbitChoice === SameOrDifferentChoice.Default
46+
? SameOrDifferentChoice.Same
47+
: stage.microbitChoice;
4648
const [selected, setSelected] = useState<MicrobitOption>(defaultValue);
4749
const handleOptionChange = useCallback(
4850
(opt: MicrobitOption) => setSelected(opt),
@@ -56,19 +58,19 @@ const DownloadChooseMicrobitDialog = ({
5658
const group = getRootProps();
5759
const radioCardOptions: Omit<RadioCardProps, "isSelected">[] = [
5860
{
59-
id: MicrobitToFlash.Same,
61+
id: SameOrDifferentChoice.Same,
6062
imgSrc: microbitImage,
6163
},
6264
{
63-
id: MicrobitToFlash.Different,
65+
id: SameOrDifferentChoice.Different,
6466
imgSrc: twoMicrobitsImage,
6567
},
6668
];
6769
return (
6870
<ConnectContainerDialog
6971
{...props}
7072
onNextClick={
71-
selected === MicrobitToFlash.Same
73+
selected === SameOrDifferentChoice.Same
7274
? onSameMicrobitClick
7375
: onDifferentMicrobitClick
7476
}

src/components/DownloadDialogs.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import ConnectRadioDataCollectionMicrobitDialog from "./ConnectRadioDataCollecti
1313
import DownloadChooseMicrobitDialog from "./DownloadChooseMicrobitDialog";
1414
import DownloadHelpDialog from "./DownloadHelpDialog";
1515
import DownloadProgressDialog from "./DownloadProgressDialog";
16+
import EnterBluetoothPatternDialog from "./EnterBluetoothPatternDialog";
1617
import IncompatibleEditorDevice from "./IncompatibleEditorDevice";
1718
import ManualFlashingDialog from "./ManualFlashingDialog";
1819
import SelectMicrobitUsbDialog from "./SelectMicrobitUsbDialog";
@@ -85,7 +86,7 @@ const DownloadDialogs = () => {
8586
samples: getTotalNumSamples(actions),
8687
},
8788
});
88-
await downloadActions.connectAndFlashMicrobit(stage);
89+
await downloadActions.connectAndFlash(stage);
8990
};
9091

9192
return (
@@ -98,6 +99,25 @@ const DownloadDialogs = () => {
9899
/>
99100
);
100101
}
102+
case DownloadStep.BluetoothPattern: {
103+
// This is only used for native bluetooth.
104+
const handleConnectNativeBluetooth = async () => {
105+
// TODO: progress needs to account for searching stage
106+
await downloadActions.connectAndFlash(stage);
107+
};
108+
return (
109+
<EnterBluetoothPatternDialog
110+
isOpen
111+
onClose={downloadActions.close}
112+
onBackClick={downloadActions.getOnBack}
113+
onNextClick={handleConnectNativeBluetooth}
114+
microbitName={stage.bluetoothMicrobitName}
115+
onChangeMicrobitName={(name: string) => {
116+
downloadActions.onChangeMicrobitName(name);
117+
}}
118+
/>
119+
);
120+
}
101121
case DownloadStep.FlashingInProgress:
102122
return (
103123
<DownloadProgressDialog

src/connect-actions.ts

Lines changed: 37 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*
44
* SPDX-License-Identifier: MIT
55
*/
6+
import { Capacitor } from "@capacitor/core";
67
import {
78
AccelerometerDataEvent,
89
BoardVersion,
@@ -20,6 +21,11 @@ import { ConnectionType } from "./connection-stage-hooks";
2021
import { MicrobitCapacitorBluetoothConnection } from "./device/capacitor-ble";
2122
import { HexType, getFlashDataSource } from "./device/get-hex-file";
2223
import { Logging } from "./logging/logging";
24+
import {
25+
isWebUSBConnection,
26+
MicrobitConnection,
27+
MicrobitFlashConnection,
28+
} from "./device/connection-utils";
2329

2430
export enum ConnectResult {
2531
Success = "Success",
@@ -48,7 +54,6 @@ export type StatusListener = (e: {
4854
}) => void;
4955

5056
export interface ConnectionAndFlashOptions {
51-
temporaryUsbConnection: MicrobitWebUSBConnection;
5257
callbackIfDeviceIsSame?: () => Promise<void>;
5358
}
5459

@@ -77,60 +82,53 @@ export class ConnectActions {
7782
usb.status !== DeviceConnectionStatus.NOT_SUPPORTED;
7883
}
7984

80-
requestUSBConnection = async (
85+
getDefaultFlashConnection(): MicrobitFlashConnection {
86+
return Capacitor.isNativePlatform()
87+
? (this.bluetooth as MicrobitCapacitorBluetoothConnection)
88+
: this.usb;
89+
}
90+
91+
connect = async (
92+
connection: MicrobitConnection,
8193
options?: ConnectionAndFlashOptions
82-
): Promise<
83-
| {
84-
result: ConnectResult.Success;
85-
deviceId: number;
86-
usb: MicrobitWebUSBConnection;
87-
}
88-
| {
89-
result: ConnectAndFlashFailResult;
90-
deviceId?: number;
91-
usb?: MicrobitWebUSBConnection;
92-
}
93-
> => {
94-
const usb = options?.temporaryUsbConnection ?? this.usb;
94+
): Promise<ConnectResult> => {
9595
try {
96-
await usb.connect();
97-
// Save remote micro:bit device id is stored for passing it to bridge micro:bit
98-
const deviceId = usb.getDeviceId();
99-
if (
100-
options?.temporaryUsbConnection &&
101-
options?.callbackIfDeviceIsSame &&
102-
deviceId === this.usb.getDeviceId()
103-
) {
104-
await options?.callbackIfDeviceIsSame();
105-
}
106-
if (!deviceId) {
107-
return { result: ConnectResult.Failed };
96+
await connection.connect();
97+
98+
if (isWebUSBConnection(connection)) {
99+
// Save remote micro:bit device id is stored for passing it to bridge micro:bit
100+
const deviceId = connection.getDeviceId();
101+
if (
102+
options?.callbackIfDeviceIsSame &&
103+
this.usb !== connection &&
104+
deviceId === this.usb.getDeviceId()
105+
) {
106+
await options.callbackIfDeviceIsSame();
107+
}
108+
if (!deviceId) {
109+
return ConnectResult.Failed;
110+
}
108111
}
109-
return { result: ConnectResult.Success, deviceId, usb };
112+
return ConnectResult.Success;
110113
} catch (e) {
111114
this.logging.error(
112115
`USB request device failed/cancelled: ${JSON.stringify(e)}`
113116
);
114-
return { result: this.handleConnectAndFlashError(e) };
117+
return this.handleConnectAndFlashError(e);
115118
}
116119
};
117120

118-
flashMicrobitWebUSB = async (
121+
flash = async (
122+
connection: MicrobitFlashConnection,
119123
hex: string | HexType,
120-
progress: (progress: number) => void,
121-
temporaryUsbConnection?: MicrobitWebUSBConnection
124+
progress: (progress: number) => void
122125
): Promise<ConnectResult> => {
123126
const data = Object.values(HexType).includes(hex as HexType)
124127
? getFlashDataSource(hex as HexType)
125128
: createUniversalHexFlashDataSource(hex);
126129

127-
const usb = temporaryUsbConnection ?? this.usb;
128-
if (!usb) {
129-
return ConnectResult.Failed;
130-
}
131-
132130
try {
133-
await usb.flash(data, {
131+
await connection.flash(data, {
134132
partial: true,
135133
// If we could improve the re-rendering due to progress further we can remove this and accept the
136134
// default which updates 4x as often.
@@ -140,24 +138,7 @@ export class ConnectActions {
140138
return ConnectResult.Success;
141139
} catch (e) {
142140
this.logging.error(`USB flashing failed: ${JSON.stringify(e)}`);
143-
return ConnectResult.Failed;
144-
}
145-
};
146-
147-
flashMicrobitBluetooth = async (hex: string | HexType, name: string) => {
148-
const data = Object.values(HexType).includes(hex as HexType)
149-
? getFlashDataSource(hex as HexType)
150-
: createUniversalHexFlashDataSource(hex);
151-
152-
const bluetooth = this.bluetooth as MicrobitCapacitorBluetoothConnection;
153-
try {
154-
this.logging.log("Starting bluetooth flashing");
155-
bluetooth.setNameFilter(name);
156-
await bluetooth.flash(data);
157-
return ConnectResult.Success;
158-
} catch (e) {
159-
this.logging.error(e);
160-
return ConnectResult.Failed;
141+
return this.handleConnectAndFlashError(e);
161142
}
162143
};
163144

src/connect-status-hooks.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ export enum ConnectionStatus {
2222
* Represents the initial connection status.
2323
*/
2424
NotConnected = "NotConnected",
25+
/**
26+
* Skip all listener connection updates until an explicit transition.
27+
*/
28+
Preparing = "Preparing",
2529
/**
2630
* Connecting occurs for the initial connection.
2731
*/

0 commit comments

Comments
 (0)