From 4594d86b15f0de631574a7fdab2b31e1cb87f6d9 Mon Sep 17 00:00:00 2001 From: Robert Knight <95928279+microbit-robert@users.noreply.github.com> Date: Thu, 18 Jul 2024 10:11:17 +0100 Subject: [PATCH] Only start serial when a listener is added (#8) --- lib/device.ts | 1 - lib/usb.ts | 59 +++++++++++++++++++++++++++++++++++++++++++++------ src/demo.ts | 31 +++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 8 deletions(-) diff --git a/lib/device.ts b/lib/device.ts index 7f3fdc0..05d4c81 100644 --- a/lib/device.ts +++ b/lib/device.ts @@ -98,7 +98,6 @@ export type FlashDataSource = ( ) => Promise; export interface ConnectOptions { - serial?: boolean; // Name filter used for Web Bluetooth name?: string; } diff --git a/lib/usb.ts b/lib/usb.ts index f4de936..31c2d6e 100644 --- a/lib/usb.ts +++ b/lib/usb.ts @@ -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 => { @@ -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); }, @@ -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) { @@ -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(); + } } } } @@ -387,13 +410,15 @@ export class MicrobitWebUSBConnection this.setStatus(ConnectionStatus.NO_AUTHORIZED_DEVICE); } - private async connectInternal(options: ConnectOptions): Promise { + private async connectInternal( + options: InternalConnectOptions, + ): Promise { 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); @@ -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) => diff --git a/src/demo.ts b/src/demo.ts index 1163b70..0f3b48e 100644 --- a/src/demo.ts +++ b/src/demo.ts @@ -11,6 +11,7 @@ import { ConnectionStatus, ConnectionStatusEvent, DeviceConnection, + SerialDataEvent, } from "../lib/device"; import { MicrobitWebBluetoothConnection } from "../lib/bluetooth"; import { AccelerometerDataEvent } from "../lib/accelerometer"; @@ -30,6 +31,10 @@ document.querySelector("#app")!.innerHTML = `

+
+ + +
@@ -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(); @@ -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); +});