diff --git a/README.md b/README.md index 4c44797..6c47ff2 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ yarn add @mmote/niimbluelib --exact ### Usage example ```js -import { Utils, RequestCommandId, ResponseCommandId, NiimbotBluetoothClient, ImageEncoder } from "@mmote/niimbluelib"; +import { Utils, RequestCommandId, ResponseCommandId, NiimbotBluetoothClient, ImageEncoder, PrintTaskVersion } from "@mmote/niimbluelib"; const client = new NiimbotBluetoothClient(); @@ -77,10 +77,12 @@ ctx.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1); const image = ImageEncoder.encodeCanvas(canvas, props.printDirection); -await client.abstraction.print(client.getPrintTaskVersion(), image, { quantity }); +const taskVersion = client.getPrintTaskVersion() ?? PrintTaskVersion.V3; + +await client.abstraction.print(taskVersion, image, { quantity }); try { - await client.abstraction.waitUntilPrintFinished(quantity); + await client.abstraction.waitUntilPrintFinished(taskVersion, quantity); } catch (e) { console.error(e); } @@ -95,4 +97,4 @@ Eslint not included. Install it with: ``` npm install --no-save --no-package-lock eslint@9.x globals @eslint/js typescript-eslint -``` \ No newline at end of file +``` diff --git a/src/packets/abstraction.ts b/src/packets/abstraction.ts index bea5925..b02d293 100644 --- a/src/packets/abstraction.ts +++ b/src/packets/abstraction.ts @@ -10,7 +10,7 @@ import { SoundSettingsItemType, SoundSettingsType, } from "."; -import { NiimbotAbstractClient, PrintProgressEvent } from "../client"; +import { NiimbotAbstractClient, PacketReceivedEvent, PrintProgressEvent } from "../client"; import { EncodedImage } from "../image_encoder"; import { PrintTaskVersion } from "../print_task_versions"; import { PrinterModel } from "../printer_models"; @@ -73,6 +73,7 @@ export class Abstraction { private client: NiimbotAbstractClient; private timeout: number = this.DEFAULT_TIMEOUT; private statusPollTimer: NodeJS.Timeout | undefined; + private statusTimeoutTimer: NodeJS.Timeout | undefined; constructor(client: NiimbotAbstractClient) { this.client = client; @@ -102,7 +103,8 @@ export class Abstraction { Validators.u8ArrayLengthEquals(packet.data, 1); const errorName = PrinterErrorCode[packet.data[0]] ?? "unknown"; throw new PrintError( - `Print error (${ResponseCommandId[packet.command]} packet received, code is ${packet.data[0]} - ${errorName})`, packet.data[0] + `Print error (${ResponseCommandId[packet.command]} packet received, code is ${packet.data[0]} - ${errorName})`, + packet.data[0] ); } @@ -357,6 +359,40 @@ export class Abstraction { } } + public async waitUntilPrintFinishedV1(pagesToPrint: number, timeoutMs: number = 5_000): Promise<void> { + return new Promise<void>((resolve, reject) => { + const listener = (evt: PacketReceivedEvent) => { + if (evt.packet.command === ResponseCommandId.In_PrinterPageIndex) { + Validators.u8ArrayLengthEquals(evt.packet.data, 2); + const page = Utils.bytesToI16(evt.packet.data); + + this.client.dispatchTypedEvent("printprogress", new PrintProgressEvent(page, pagesToPrint, 100, 100)); + + clearTimeout(this.statusTimeoutTimer); + this.statusTimeoutTimer = setTimeout(() => { + this.client.removeEventListener("packetreceived", listener); + reject(new Error("Timeout waiting print status")); + }, timeoutMs); + + if (page === pagesToPrint) { + clearTimeout(this.statusTimeoutTimer); + this.client.removeEventListener("packetreceived", listener); + resolve(); + } + } + }; + + clearTimeout(this.statusTimeoutTimer); + this.statusTimeoutTimer = setTimeout(() => { + this.client.removeEventListener("packetreceived", listener); + reject(new Error("Timeout waiting print status")); + }, timeoutMs); + + this.client.dispatchTypedEvent("printprogress", new PrintProgressEvent(1, pagesToPrint, 0, 0)); + this.client.addEventListener("packetreceived", listener); + }); + } + /** * Poll printer every {@link pollIntervalMs} and resolve when printer pages equals {@link pagesToPrint}, pagePrintProgress=100, pageFeedProgress=100. * @@ -365,8 +401,10 @@ export class Abstraction { * @param pagesToPrint Total pages to print. * @param pollIntervalMs Poll interval in milliseconds. */ - public async waitUntilPrintFinished(pagesToPrint: number, pollIntervalMs: number = 300): Promise<void> { - return new Promise((resolve, reject) => { + public async waitUntilPrintFinishedV2(pagesToPrint: number, pollIntervalMs: number = 300): Promise<void> { + return new Promise<void>((resolve, reject) => { + this.client.dispatchTypedEvent("printprogress", new PrintProgressEvent(1, pagesToPrint, 0, 0)); + this.statusPollTimer = setInterval(() => { this.getPrintStatus() .then((status: PrintStatus) => { @@ -388,6 +426,23 @@ export class Abstraction { }); } + /** + * printprogress event is firing during this process. + * + * @param pagesToPrint Total pages to print. + */ + public async waitUntilPrintFinished( + taskVersion: PrintTaskVersion, + pagesToPrint: number, + options?: { pollIntervalMs?: number; timeoutMs?: number } + ): Promise<void> { + if (taskVersion === PrintTaskVersion.V1) { + return this.waitUntilPrintFinishedV1(pagesToPrint, options?.timeoutMs); + } + + return this.waitUntilPrintFinishedV2(pagesToPrint, options?.pollIntervalMs); + } + public async printEnd(): Promise<void> { await this.send(PacketGenerator.printEnd()); }