Working tree changes 2024-07-21 00:00
This commit is contained in:
parent
093ad46b68
commit
4e5250fc06
@ -34,7 +34,7 @@
|
||||
for (let i = 0; i < packets.length; i++) {
|
||||
sendProgress = Math.round(((i + 1) / packets.length) * 100);
|
||||
// console.log(Utils.bufToHex(packets[i].toBytes()))
|
||||
await $printerClient.sendPacket(packets[i]);
|
||||
await $printerClient.sendPacketWaitResponse(packets[i]);
|
||||
|
||||
// await Utils.sleep(100);
|
||||
// console.log(Utils.bufToHex(packets[i].toBytes()))
|
||||
|
@ -194,6 +194,7 @@
|
||||
"@mmote/niimbluelib@file:../niimbluelib":
|
||||
version "0.0.1"
|
||||
dependencies:
|
||||
async-mutex "^0.5.0"
|
||||
typescript-event-target "^1.1.1"
|
||||
|
||||
"@popperjs/core@^2.11.8", "@popperjs/core@^2.9.2":
|
||||
@ -408,6 +409,13 @@ aria-query@^5.3.0:
|
||||
dependencies:
|
||||
dequal "^2.0.3"
|
||||
|
||||
async-mutex@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.5.0.tgz#353c69a0b9e75250971a64ac203b0ebfddd75482"
|
||||
integrity sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
@ -1281,7 +1289,7 @@ tr46@~0.0.3:
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
|
||||
|
||||
tslib@^2.6.3:
|
||||
tslib@^2.4.0, tslib@^2.6.3:
|
||||
version "2.6.3"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0"
|
||||
integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==
|
||||
|
@ -23,6 +23,7 @@
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"async-mutex": "^0.5.0",
|
||||
"typescript-event-target": "^1.1.1"
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,15 @@
|
||||
import { Mutex } from "async-mutex";
|
||||
import { ConnectionInfo, NiimbotAbstractClient } from ".";
|
||||
import { NiimbotPacket, PacketParser, ResponseCommandId } from "../packets";
|
||||
import { Utils } from "../utils";
|
||||
import { ConnectEvent, DisconnectEvent, PacketParsedEvent, PacketReceivedEvent, RawPacketReceivedEvent, RawPacketSentEvent } from "./events";
|
||||
import {
|
||||
ConnectEvent,
|
||||
DisconnectEvent,
|
||||
PacketParsedEvent,
|
||||
PacketReceivedEvent,
|
||||
RawPacketReceivedEvent,
|
||||
RawPacketSentEvent,
|
||||
} from "./events";
|
||||
|
||||
class BleConfiguration {
|
||||
public static readonly SERVICE: string = "e7810a71-73ae-499d-8c15-faa9aef0c3f2";
|
||||
@ -16,6 +24,7 @@ class BleConfiguration {
|
||||
export class NiimbotBluetoothClient extends NiimbotAbstractClient {
|
||||
private gattServer?: BluetoothRemoteGATTServer = undefined;
|
||||
private channel?: BluetoothRemoteGATTCharacteristic = undefined;
|
||||
private mutex: Mutex = new Mutex();
|
||||
|
||||
public async connect(): Promise<ConnectionInfo> {
|
||||
this.disconnect();
|
||||
@ -51,7 +60,6 @@ export class NiimbotBluetoothClient extends NiimbotAbstractClient {
|
||||
this.dispatchTypedEvent("rawpacketreceived", new RawPacketReceivedEvent(target.value!));
|
||||
this.dispatchTypedEvent("packetreceived", new PacketReceivedEvent(packet));
|
||||
|
||||
|
||||
if (!(packet.getCommand() in ResponseCommandId)) {
|
||||
console.warn(`Unknown response command: 0x${Utils.numberToHex(packet.getCommand())}`);
|
||||
} else {
|
||||
@ -87,33 +95,52 @@ export class NiimbotBluetoothClient extends NiimbotAbstractClient {
|
||||
* If packet.responsePacketCommandId is defined, it will wait for packet with this command id.
|
||||
*/
|
||||
public async sendPacketWaitResponse(packet: NiimbotPacket, timeoutMs?: number): Promise<NiimbotPacket> {
|
||||
await this.sendPacket(packet);
|
||||
// what if response received at this point?
|
||||
return new Promise((resolve) => {
|
||||
let timeout: NodeJS.Timeout | undefined = undefined;
|
||||
return this.mutex.runExclusive(async () => {
|
||||
await this.sendPacket(packet, true);
|
||||
|
||||
const listener = (evt: PacketReceivedEvent) => {
|
||||
if (packet.getValidResponseIds().length === 0 || packet.getValidResponseIds().includes(evt.packet.getCommand())) {
|
||||
clearTimeout(timeout);
|
||||
this.removeEventListener("packetreceived", listener)
|
||||
resolve(evt.packet);
|
||||
}
|
||||
};
|
||||
if (packet.isNoResponse()) {
|
||||
return new NiimbotPacket(-1, []); // or undefined is better?
|
||||
}
|
||||
|
||||
timeout = setTimeout(() => {
|
||||
this.removeEventListener("packetreceived", listener)
|
||||
throw new Error("Timeout waiting response");
|
||||
}, timeoutMs ?? 1000);
|
||||
// what if response received at this point?
|
||||
|
||||
this.addEventListener("packetreceived", listener)
|
||||
return new Promise((resolve) => {
|
||||
let timeout: NodeJS.Timeout | undefined = undefined;
|
||||
|
||||
const listener = (evt: PacketReceivedEvent) => {
|
||||
if (
|
||||
packet.getValidResponseIds().length === 0 ||
|
||||
packet.getValidResponseIds().includes(evt.packet.getCommand())
|
||||
) {
|
||||
clearTimeout(timeout);
|
||||
this.removeEventListener("packetreceived", listener);
|
||||
resolve(evt.packet);
|
||||
}
|
||||
};
|
||||
|
||||
timeout = setTimeout(() => {
|
||||
this.removeEventListener("packetreceived", listener);
|
||||
throw new Error("Timeout waiting response");
|
||||
}, timeoutMs ?? 1000);
|
||||
|
||||
this.addEventListener("packetreceived", listener);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public async sendRaw(data: Uint8Array) {
|
||||
if (this.channel === undefined) {
|
||||
throw new Error("Channel is closed");
|
||||
public async sendRaw(data: Uint8Array, force?: boolean) {
|
||||
const send = async () => {
|
||||
if (this.channel === undefined) {
|
||||
throw new Error("Channel is closed");
|
||||
}
|
||||
await this.channel.writeValueWithoutResponse(data);
|
||||
this.dispatchTypedEvent("rawpacketsent", new RawPacketSentEvent(data));
|
||||
};
|
||||
|
||||
if (force) {
|
||||
return send();
|
||||
} else {
|
||||
await this.mutex.runExclusive(send);
|
||||
}
|
||||
await this.channel.writeValueWithoutResponse(data);
|
||||
this.dispatchTypedEvent("rawpacketsent", new RawPacketSentEvent(data));
|
||||
}
|
||||
}
|
||||
|
@ -16,11 +16,16 @@ export abstract class NiimbotAbstractClient extends TypedEventTarget<ClientEvent
|
||||
*/
|
||||
public abstract sendPacketWaitResponse(packet: NiimbotPacket, timeoutMs?: number): Promise<NiimbotPacket>;
|
||||
|
||||
/** Send raw data tp printer port */
|
||||
public abstract sendRaw(data: Uint8Array): Promise<void>;
|
||||
/**
|
||||
* Send raw bytes to the printer port.
|
||||
*
|
||||
* @param data Bytes to send.
|
||||
* @param force Ignore mutex lock. You should avoid using it.
|
||||
*/
|
||||
public abstract sendRaw(data: Uint8Array, force?: boolean): Promise<void>;
|
||||
|
||||
public async sendPacket(packet: NiimbotPacket) {
|
||||
await this.sendRaw(packet.toBytes());
|
||||
public async sendPacket(packet: NiimbotPacket, force?: boolean) {
|
||||
await this.sendRaw(packet.toBytes(), force);
|
||||
}
|
||||
|
||||
public async sendPacketWaitResponseDecoded(packet: NiimbotPacket, timeoutMs?: number): Promise<ParsedPacket> {
|
||||
|
@ -130,13 +130,11 @@ export class NiimbotSerialClient extends NiimbotAbstractClient {
|
||||
return p;
|
||||
}
|
||||
|
||||
public async sendRaw(data: Uint8Array) {
|
||||
public async sendRaw(data: Uint8Array, force?: boolean) {
|
||||
if (this.writer === undefined) {
|
||||
throw new Error("Port is not writable");
|
||||
}
|
||||
|
||||
await this.writer.write(data);
|
||||
|
||||
// this.writer.releaseLock();
|
||||
|
||||
this.dispatchTypedEvent("rawpacketsent", new RawPacketSentEvent(data));
|
||||
|
@ -9,10 +9,22 @@ export class NiimbotPacket {
|
||||
private data: Uint8Array;
|
||||
private validResponseIds: ResponseCommandId[];
|
||||
|
||||
/** There can be no response after this request. */
|
||||
private noResponse: boolean;
|
||||
|
||||
constructor(commandId: number, data: Uint8Array | number[], validResponseIds: ResponseCommandId[] = []) {
|
||||
this.commandId = commandId;
|
||||
this.data = data instanceof Uint8Array ? data : new Uint8Array(data);
|
||||
this.validResponseIds = validResponseIds;
|
||||
this.noResponse = false;
|
||||
}
|
||||
|
||||
public setNoResponse(): void {
|
||||
this.noResponse = true;
|
||||
}
|
||||
|
||||
public isNoResponse(): boolean {
|
||||
return this.noResponse;
|
||||
}
|
||||
|
||||
public getValidResponseIds(): ResponseCommandId[] {
|
||||
|
@ -188,13 +188,15 @@ export class PacketGenerator {
|
||||
|
||||
// https://github.com/ayufan/niimprint-web/blob/main/cmds.js#L215
|
||||
public static printEmptySpace(pos: number, repeats: number): NiimbotPacket {
|
||||
return new NiimbotPacket(RequestCommandId.PrintEmptyRow, [...Utils.u16ToBytes(pos), repeats]);
|
||||
const packet = new NiimbotPacket(RequestCommandId.PrintEmptyRow, [...Utils.u16ToBytes(pos), repeats]);
|
||||
packet.setNoResponse();
|
||||
return packet;
|
||||
}
|
||||
|
||||
public static printBitmapRow(pos: number, repeats: number, data: Uint8Array): NiimbotPacket {
|
||||
const blackPixelCount: number = Utils.countSetBits(data);
|
||||
|
||||
return new NiimbotPacket(RequestCommandId.PrintBitmapRow, [
|
||||
const packet = new NiimbotPacket(RequestCommandId.PrintBitmapRow, [
|
||||
...Utils.u16ToBytes(pos),
|
||||
// Black pixel count. Not sure what role it plays in printing.
|
||||
// There is two formats of this part
|
||||
@ -205,6 +207,8 @@ export class PacketGenerator {
|
||||
repeats,
|
||||
...data,
|
||||
]);
|
||||
packet.setNoResponse();
|
||||
return packet;
|
||||
}
|
||||
|
||||
/** Printer powers off if black pixel count > 6 */
|
||||
@ -216,13 +220,16 @@ export class PacketGenerator {
|
||||
throw new Error(`Black pixel count > 6 (${blackPixelCount})`);
|
||||
}
|
||||
|
||||
return new NiimbotPacket(RequestCommandId.PrintBitmapRowIndexed, [
|
||||
const packet = new NiimbotPacket(RequestCommandId.PrintBitmapRowIndexed, [
|
||||
...Utils.u16ToBytes(pos),
|
||||
0,
|
||||
...Utils.u16ToBytes(blackPixelCount),
|
||||
repeats,
|
||||
...indexes,
|
||||
]);
|
||||
|
||||
packet.setNoResponse();
|
||||
return packet;
|
||||
}
|
||||
|
||||
public static printClear(): NiimbotPacket {
|
||||
|
@ -19,6 +19,18 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz#f066abfcd1cbe66267cdbbf0de010d8a41b41597"
|
||||
integrity sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==
|
||||
|
||||
async-mutex@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.5.0.tgz#353c69a0b9e75250971a64ac203b0ebfddd75482"
|
||||
integrity sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
|
||||
tslib@^2.4.0:
|
||||
version "2.6.3"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0"
|
||||
integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==
|
||||
|
||||
typescript-event-target@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/typescript-event-target/-/typescript-event-target-1.1.1.tgz#20a6d491b77d2e37dc432c5394ab74c0d7065539"
|
||||
|
Reference in New Issue
Block a user