Skip to content

Commit b3bc2bf

Browse files
Fill out BT profile. Demo connect/disconnect.
Name filter something of a cludge
1 parent c72fb12 commit b3bc2bf

File tree

4 files changed

+104
-23
lines changed

4 files changed

+104
-23
lines changed

lib/bluetooth-profile.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,40 @@ export const profile = {
1111
id: "e95d0753-251d-470a-a062-fa1922dfa9a8",
1212
characteristics: {
1313
data: { id: "e95dca4b-251d-470a-a062-fa1922dfa9a8" },
14+
period: { id: "e95dfb24-251d-470a-a062-fa1922dfa9a8" },
1415
},
1516
},
1617
deviceInformation: {
1718
id: "0000180a-0000-1000-8000-00805f9b34fb",
1819
characteristics: {
1920
modelNumber: { id: "00002a24-0000-1000-8000-00805f9b34fb" },
21+
serialNumber: { id: "00002a25-0000-1000-8000-00805f9b34fb" },
22+
firmwareRevision: { id: "00002a26-0000-1000-8000-00805f9b34fb" },
23+
hardwareRevision: { id: "00002a27-0000-1000-8000-00805f9b34fb" },
24+
manufacturer: { id: "00002a29-0000-1000-8000-00805f9b34fb" },
25+
},
26+
},
27+
dfuControl: {
28+
id: "e95d93b0-251d-470a-a062-fa1922dfa9a8",
29+
characteristics: {
30+
control: { id: "e95d93b1-251d-470a-a062-fa1922dfa9a8" },
2031
},
2132
},
2233
led: {
2334
id: "e95dd91d-251d-470a-a062-fa1922dfa9a8",
2435
characteristics: {
2536
matrixState: { id: "e95d7b77-251d-470a-a062-fa1922dfa9a8" },
37+
text: { id: "e95d93ee-251d-470a-a062-fa1922dfa9a8" },
38+
scrollingDelay: { id: "e95d0d2d-251d-470a-a062-fa1922dfa9a8" },
2639
},
2740
},
28-
io: {
41+
ioPin: {
2942
id: "e95d127b-251d-470a-a062-fa1922dfa9a8",
3043
characteristics: {
31-
data: { id: "e95d8d00-251d-470a-a062-fa1922dfa9a8" },
44+
pinData: { id: "e95d8d00-251d-470a-a062-fa1922dfa9a8" },
45+
pinAdConfiguration: { id: "e95d5899-251d-470a-a062-fa1922dfa9a8" },
46+
pinIoConfiguration: { id: "e95db9fe-251d-470a-a062-fa1922dfa9a8" },
47+
pwmControl: { id: "e95dd822-251d-470a-a062-fa1922dfa9a8" },
3248
},
3349
},
3450
button: {
@@ -38,4 +54,29 @@ export const profile = {
3854
b: { id: "e95dda91-251d-470a-a062-fa1922dfa9a8" },
3955
},
4056
},
57+
event: {
58+
id: "e95d93af-251d-470a-a062-fa1922dfa9a8",
59+
characteristics: {
60+
microBitRequirements: { id: "e95db84c-251d-470a-a062-fa1922dfa9a8" },
61+
microBitEvent: { id: "e95d9775-251d-470a-a062-fa1922dfa9a8" },
62+
clientRequirements: { id: "e95d23c4-251d-470a-a062-fa1922dfa9a8" },
63+
clientEvent: { id: "e95d5404-251d-470a-a062-fa1922dfa9a8" },
64+
},
65+
},
66+
magnetometer: {
67+
id: "e95df2d8-251d-470a-a062-fa1922dfa9a8",
68+
characteristics: {
69+
data: { id: "e95dfb11-251d-470a-a062-fa1922dfa9a8" },
70+
period: { id: "e95d386c-251d-470a-a062-fa1922dfa9a8" },
71+
bearing: { id: "e95d9715-251d-470a-a062-fa1922dfa9a8" },
72+
calibration: { id: "e95db358-251d-470a-a062-fa1922dfa9a8" },
73+
},
74+
},
75+
temperature: {
76+
id: "e95d6100-251d-470a-a062-fa1922dfa9a8",
77+
characteristics: {
78+
data: { id: "e95d9250-251d-470a-a062-fa1922dfa9a8" },
79+
period: { id: "e95d1b25-251d-470a-a062-fa1922dfa9a8" },
80+
},
81+
},
4182
};

lib/bluetooth.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export class MicrobitWebBluetoothConnection
9191
* A progress callback. Called with undefined when the process is complete or has failed.
9292
*/
9393
progress: (percentage: number | undefined) => void;
94-
},
94+
}
9595
): Promise<void> {
9696
throw new Error("Unsupported");
9797
}
@@ -157,21 +157,23 @@ export class MicrobitWebBluetoothConnection
157157

158158
private async connectInternal(options: ConnectOptions): Promise<void> {
159159
if (!this.connection) {
160-
const device = await this.chooseDevice();
160+
const device = await this.chooseDevice(options);
161161
if (!device) {
162162
return;
163163
}
164164
this.connection = await createBluetoothDeviceWrapper(
165165
device,
166-
this.logging,
166+
this.logging
167167
);
168168
}
169169
// TODO: timeout unification?
170170
this.connection?.connect();
171171
this.setStatus(ConnectionStatus.CONNECTED);
172172
}
173173

174-
private async chooseDevice(): Promise<BluetoothDevice | undefined> {
174+
private async chooseDevice(
175+
options: ConnectOptions
176+
): Promise<BluetoothDevice | undefined> {
175177
if (this.device) {
176178
return this.device;
177179
}
@@ -181,20 +183,28 @@ export class MicrobitWebBluetoothConnection
181183
// TODO: give control over this to the caller
182184
const result = await Promise.race([
183185
navigator.bluetooth.requestDevice({
184-
// TODO: this is limiting
185-
filters: [{ namePrefix: `BBC micro:bit [${name}]` }],
186+
filters: [
187+
{
188+
namePrefix: options.name
189+
? `BBC micro:bit [${options.name}]`
190+
: "BBC micro:bit",
191+
},
192+
],
186193
optionalServices: [
187-
// TODO: include everything or perhaps parameterise?
188-
profile.uart.id,
189194
profile.accelerometer.id,
195+
profile.button.id,
190196
profile.deviceInformation.id,
197+
profile.dfuControl.id,
198+
profile.event.id,
199+
profile.ioPin.id,
191200
profile.led.id,
192-
profile.io.id,
193-
profile.button.id,
201+
profile.magnetometer.id,
202+
profile.temperature.id,
203+
profile.uart.id,
194204
],
195205
}),
196206
new Promise<"timeout">((resolve) =>
197-
setTimeout(() => resolve("timeout"), requestDeviceTimeoutDuration),
207+
setTimeout(() => resolve("timeout"), requestDeviceTimeoutDuration)
198208
),
199209
]);
200210
if (result === "timeout") {

lib/device.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ export interface FlashDataSource {
111111

112112
export interface ConnectOptions {
113113
serial?: boolean;
114+
// Name filter used for Web Bluetooth
115+
name?: string;
114116
}
115117

116118
export type BoardVersion = "V1" | "V2";
@@ -216,7 +218,7 @@ export interface DeviceConnection
216218
* The partial parameter reports the flash type currently in progress.
217219
*/
218220
progress: (percentage: number | undefined, partial: boolean) => void;
219-
},
221+
}
220222
): Promise<void>;
221223

222224
/**

src/demo.ts

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,19 @@
66
import "./demo.css";
77
import { MicrobitWebUSBConnection } from "../lib/webusb";
88
import { HexFlashDataSource } from "../lib/hex-flash-data-source";
9-
import { ConnectionStatus } from "../lib/device";
9+
import { ConnectionStatus, DeviceConnection } from "../lib/device";
10+
import { MicrobitWebBluetoothConnection } from "../lib/bluetooth";
1011

1112
document.querySelector<HTMLDivElement>("#app")!.innerHTML = `
12-
<section id="webusb">
13-
<h2>WebUSB</h2>
13+
<section id="flash">
14+
<h2>Connect and flash</h2>
15+
<label><div>Name</div>
16+
<input id="name" type="text">
17+
</label>
18+
<select class="transport">
19+
<option value="usb">WebUSB</option>
20+
<option value="bluetooth">Web Bluetooth</option>
21+
</select>
1422
<button class="connect">Connect</button>
1523
<button class="disconnect">Disconnect</button>
1624
<p class="status"></p>
@@ -19,18 +27,38 @@ document.querySelector<HTMLDivElement>("#app")!.innerHTML = `
1927
</section>
2028
`;
2129

22-
const connect = document.querySelector("#webusb > .connect")!;
23-
const disconnect = document.querySelector("#webusb > .disconnect")!;
24-
const flash = document.querySelector("#webusb > .flash")!;
30+
const transport = document.querySelector(
31+
"#flash > .transport"
32+
)! as HTMLSelectElement;
33+
const connect = document.querySelector("#flash > .connect")!;
34+
const disconnect = document.querySelector("#flash > .disconnect")!;
35+
const flash = document.querySelector("#flash > .flash")!;
2536
const fileInput = document.querySelector(
26-
"#webusb input[type=file]",
37+
"#flash input[type=file]"
2738
)! as HTMLInputElement;
28-
const statusParagraph = document.querySelector("#webusb > .status")!;
29-
const connection = new MicrobitWebUSBConnection();
39+
const statusParagraph = document.querySelector("#flash > .status")!;
40+
41+
const usb = new MicrobitWebUSBConnection();
42+
const bluetooth = new MicrobitWebBluetoothConnection();
43+
let connection: DeviceConnection = usb;
44+
3045
const initialisePromise = connection.initialize();
3146
const displayStatus = (status: ConnectionStatus) => {
3247
statusParagraph.textContent = status.toString();
3348
};
49+
transport.addEventListener("change", (e) => {
50+
switch (transport.value) {
51+
case "bluetooth": {
52+
connection = bluetooth;
53+
break;
54+
}
55+
case "usb": {
56+
connection = usb;
57+
break;
58+
}
59+
}
60+
});
61+
3462
connection.addEventListener("status", (event) => {
3563
displayStatus(event.status);
3664
});

0 commit comments

Comments
 (0)