Skip to content

Commit

Permalink
Only start serial when a listener is added (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
microbit-robert authored Jul 18, 2024
1 parent 55b09c4 commit 4594d86
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 8 deletions.
1 change: 0 additions & 1 deletion lib/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ export type FlashDataSource = (
) => Promise<string | Uint8Array>;

export interface ConnectOptions {
serial?: boolean;
// Name filter used for Web Bluetooth
name?: string;
}
Expand Down
59 changes: 52 additions & 7 deletions lib/usb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ import {
} from "./device.js";
import { TypedEventTarget } from "./events.js";

interface InternalConnectOptions extends ConnectOptions {
serial?: boolean;
}

// Temporary workaround for ChromeOS 105 bug.
// See https://bugs.chromium.org/p/chromium/issues/detail?id=1363712&q=usb&can=2
export const isChromeOS105 = (): boolean => {
Expand Down Expand Up @@ -120,7 +124,9 @@ export class MicrobitWebUSBConnection
setTimeout(() => {
if (this.status === ConnectionStatus.CONNECTED) {
this.unloading = false;
this.startSerialInternal();
if (this.addedListeners.serialdata) {
this.startSerialInternal();
}
}
}, assumePageIsStayingOpenDelay);
},
Expand All @@ -130,11 +136,26 @@ export class MicrobitWebUSBConnection

private logging: Logging;

private _addEventListener = this.addEventListener;
private _removeEventListener = this.removeEventListener;

private addedListeners = {
serialdata: false,
};

constructor(
options: MicrobitWebUSBConnectionOptions = { logging: new NullLogging() },
) {
super();
this.logging = options.logging;
this.addEventListener = (type, ...args) => {
this._addEventListener(type, ...args);
this.startNotifications(type);
};
this.removeEventListener = (type, ...args) => {
this.stopNotifications(type);
this._removeEventListener(type, ...args);
};
}

private log(v: any) {
Expand Down Expand Up @@ -256,10 +277,12 @@ export class MicrobitWebUSBConnection
} else {
// This might not strictly be "reinstating". We should make this
// behaviour configurable when pulling out a library.
this.log("Reinstating serial after flash");
if (this.connection.daplink) {
await this.connection.daplink.connect();
await this.startSerialInternal();
if (this.addedListeners.serialdata) {
this.log("Reinstating serial after flash");
if (this.connection.daplink) {
await this.connection.daplink.connect();
await this.startSerialInternal();
}
}
}
}
Expand Down Expand Up @@ -387,13 +410,15 @@ export class MicrobitWebUSBConnection
this.setStatus(ConnectionStatus.NO_AUTHORIZED_DEVICE);
}

private async connectInternal(options: ConnectOptions): Promise<void> {
private async connectInternal(
options: InternalConnectOptions,
): Promise<void> {
if (!this.connection) {
const device = await this.chooseDevice();
this.connection = new DAPWrapper(device, this.logging);
}
await withTimeout(this.connection.reconnectAsync(), 10_000);
if (options.serial === undefined || options.serial) {
if (this.addedListeners.serialdata && options.serial !== false) {
this.startSerialInternal();
}
this.setStatus(ConnectionStatus.CONNECTED);
Expand All @@ -410,6 +435,26 @@ export class MicrobitWebUSBConnection
this.dispatchTypedEvent("afterrequestdevice", new AfterRequestDevice());
return this.device;
}

private async startNotifications(type: string) {
switch (type as keyof DeviceConnectionEventMap) {
case "serialdata": {
this.startSerialInternal();
this.addedListeners.serialdata = true;
break;
}
}
}

private async stopNotifications(type: string) {
switch (type as keyof DeviceConnectionEventMap) {
case "serialdata": {
this.stopSerialInternal();
this.addedListeners.serialdata = false;
break;
}
}
}
}

const genericErrorSuggestingReconnect = (e: any) =>
Expand Down
31 changes: 31 additions & 0 deletions src/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ConnectionStatus,
ConnectionStatusEvent,
DeviceConnection,
SerialDataEvent,
} from "../lib/device";
import { MicrobitWebBluetoothConnection } from "../lib/bluetooth";
import { AccelerometerDataEvent } from "../lib/accelerometer";
Expand All @@ -30,6 +31,10 @@ document.querySelector<HTMLDivElement>("#app")!.innerHTML = `
<p class="status"></p>
<label><div>File to flash</div><input type="file"/></label>
<button class="flash">Flash</button>
<div class="serial-controls">
<button class="serial-listen">Listen to serial</button>
<button class="serial-stop">Stop serial data</button>
</div>
<div class="acc-data-controls">
<button class="acc-data-get">Get accelerometer data</button>
<button class="acc-data-listen">Listen to accelerometer data</button>
Expand Down Expand Up @@ -73,6 +78,12 @@ const accPeriodInput = document.querySelector(
const accPeriodSet = document.querySelector(
"#flash > .acc-period-controls > .acc-period-set",
)!;
const serialListen = document.querySelector(
"#flash > .serial-controls > .serial-listen",
)!;
const serialStop = document.querySelector(
"#flash > .serial-controls > .serial-stop",
)!;

const displayStatus = (status: ConnectionStatus) => {
statusParagraph.textContent = status.toString();
Expand Down Expand Up @@ -212,3 +223,23 @@ accPeriodSet.addEventListener("click", async () => {
);
}
});

let data = "";
const serialDataListener = (event: SerialDataEvent) => {
for (const char of event.data) {
if (char === "\n") {
console.log(data);
data = "";
} else {
data += char;
}
}
};

serialListen.addEventListener("click", async () => {
connection.addEventListener("serialdata", serialDataListener);
});

serialStop.addEventListener("click", async () => {
connection.removeEventListener("serialdata", serialDataListener);
});

0 comments on commit 4594d86

Please sign in to comment.