Working tree changes 2024-07-26 00:00
All checks were successful
Test project build / Build (push) Successful in 1m3s
All checks were successful
Test project build / Build (push) Successful in 1m3s
This commit is contained in:
parent
a33dc79fa1
commit
16324d5f5f
@ -33,5 +33,6 @@
|
||||
"tslib": "^2.6.3",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.3.1"
|
||||
}
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
||||
}
|
||||
|
@ -61,14 +61,9 @@ 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 {
|
||||
const data = PacketParser.parse(packet);
|
||||
if (data !== undefined) {
|
||||
this.dispatchTypedEvent("packetparsed", new PacketParsedEvent(data));
|
||||
}
|
||||
}*/
|
||||
if (!(packet.command in ResponseCommandId)) {
|
||||
console.warn(`Unknown response command: 0x${Utils.numberToHex(packet.command)}`);
|
||||
}
|
||||
});
|
||||
|
||||
await channel.startNotifications();
|
||||
@ -76,11 +71,8 @@ export class NiimbotBluetoothClient extends NiimbotAbstractClient {
|
||||
this.gattServer = gattServer;
|
||||
this.channel = channel;
|
||||
|
||||
let connectResult = ConnectResult.Connected;
|
||||
|
||||
try {
|
||||
connectResult = await this.abstraction.connectResult();
|
||||
console.log({connectResult: ConnectResult[connectResult]});
|
||||
await this.initialNegotiate();
|
||||
await this.fetchPrinterConfig();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
@ -88,7 +80,7 @@ export class NiimbotBluetoothClient extends NiimbotAbstractClient {
|
||||
|
||||
const result: ConnectionInfo = {
|
||||
deviceName: device.name,
|
||||
result: connectResult
|
||||
result: this.printerConfig.connectResult ?? ConnectResult.FirmwareErrors
|
||||
};
|
||||
|
||||
this.dispatchTypedEvent("connect", new ConnectEvent(result));
|
||||
@ -116,7 +108,7 @@ export class NiimbotBluetoothClient extends NiimbotAbstractClient {
|
||||
return this.mutex.runExclusive(async () => {
|
||||
await this.sendPacket(packet, true);
|
||||
|
||||
if (packet.isOneWay()) {
|
||||
if (packet.oneWay) {
|
||||
return new NiimbotPacket(-1, []); // or undefined is better?
|
||||
}
|
||||
|
||||
@ -127,8 +119,8 @@ export class NiimbotBluetoothClient extends NiimbotAbstractClient {
|
||||
|
||||
const listener = (evt: PacketReceivedEvent) => {
|
||||
if (
|
||||
packet.getValidResponseIds().length === 0 ||
|
||||
packet.getValidResponseIds().includes(evt.packet.getCommand())
|
||||
packet.validResponseIds.length === 0 ||
|
||||
packet.validResponseIds.includes(evt.packet.command)
|
||||
) {
|
||||
clearTimeout(timeout);
|
||||
this.removeEventListener("packetreceived", listener);
|
||||
@ -139,7 +131,7 @@ export class NiimbotBluetoothClient extends NiimbotAbstractClient {
|
||||
timeout = setTimeout(() => {
|
||||
this.removeEventListener("packetreceived", listener);
|
||||
throw new Error(
|
||||
`Timeout waiting response (waited for ${Utils.bufToHex(packet.getValidResponseIds(), ", ")})`
|
||||
`Timeout waiting response (waited for ${Utils.bufToHex(packet.validResponseIds, ", ")})`
|
||||
);
|
||||
}, timeoutMs ?? 1000);
|
||||
|
||||
|
@ -5,10 +5,12 @@ import { Abstraction } from "../packets/abstraction";
|
||||
|
||||
export type ConnectionInfo = {
|
||||
deviceName?: string;
|
||||
result: ConnectResult
|
||||
result: ConnectResult;
|
||||
};
|
||||
|
||||
export interface PrinterConfig {
|
||||
connectResult?: ConnectResult;
|
||||
protocolVersion?: number;
|
||||
model?: PrinterModelId;
|
||||
serial?: string;
|
||||
mac?: string;
|
||||
@ -52,8 +54,21 @@ export abstract class NiimbotAbstractClient extends TypedEventTarget<ClientEvent
|
||||
await this.sendRaw(packet.toBytes(), force);
|
||||
}
|
||||
|
||||
/** Send "connect" packet and fetch the protocol version */
|
||||
protected async initialNegotiate(): Promise<void> {
|
||||
const cfg = this.printerConfig;
|
||||
cfg.connectResult = await this.abstraction.connectResult();
|
||||
cfg.protocolVersion = 0;
|
||||
|
||||
if (cfg.connectResult === ConnectResult.ConnectedNew) {
|
||||
cfg.protocolVersion = 1;
|
||||
} else if (cfg.connectResult === ConnectResult.ConnectedV3) {
|
||||
const statusData = await this.abstraction.getPrinterStatusData();
|
||||
cfg.protocolVersion = statusData.protocolVersion;
|
||||
}
|
||||
}
|
||||
|
||||
public async fetchPrinterConfig(): Promise<PrinterConfig> {
|
||||
this.printerConfig = {};
|
||||
// console.log(await this.abstraction.getPrinterStatusData());
|
||||
this.printerConfig.model = await this.abstraction.getPrinterModel();
|
||||
this.printerConfig.serial = await this.abstraction.getPrinterSerialNumber();
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ConnectionInfo, NiimbotAbstractClient } from ".";
|
||||
import { NiimbotPacket } from "../packets";
|
||||
import { ConnectResult, NiimbotPacket } from "../packets";
|
||||
import { Utils } from "../utils";
|
||||
import { ConnectEvent, DisconnectEvent, RawPacketSentEvent } from "./events";
|
||||
|
||||
@ -28,8 +28,16 @@ export class NiimbotSerialClient extends NiimbotAbstractClient {
|
||||
this.writer = _port.writable.getWriter();
|
||||
const info = _port.getInfo();
|
||||
|
||||
try {
|
||||
await this.initialNegotiate();
|
||||
await this.fetchPrinterConfig();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
const result: ConnectionInfo = {
|
||||
deviceName: `Serial (VID:${info.usbVendorId?.toString(16)} PID:${info.usbProductId?.toString(16)})`,
|
||||
result: this.printerConfig.connectResult ?? ConnectResult.FirmwareErrors
|
||||
};
|
||||
|
||||
this.dispatchTypedEvent("connect", new ConnectEvent(result));
|
||||
|
@ -87,25 +87,25 @@ export class Abstraction {
|
||||
public async getPrintStatus(): Promise<PrintStatus> {
|
||||
const packet = await this.send(PacketGenerator.printStatus());
|
||||
|
||||
if (packet.getCommand() === ResponseCommandId.In_PrintError) {
|
||||
Validators.u8ArrayLengthEquals(packet.getData(), 1);
|
||||
if (packet.command === ResponseCommandId.In_PrintError) {
|
||||
Validators.u8ArrayLengthEquals(packet.data, 1);
|
||||
throw new PrintError(
|
||||
`Print error (${ResponseCommandId[packet.getCommand()]} packet received)`,
|
||||
packet.getData()[0]
|
||||
`Print error (${ResponseCommandId[packet.command]} packet received)`,
|
||||
packet.data[0]
|
||||
);
|
||||
}
|
||||
|
||||
Validators.u8ArrayLengthAtLeast(packet.getData(), 4); // can be 8, 10, but ignore it for now
|
||||
Validators.u8ArrayLengthAtLeast(packet.data, 4); // can be 8, 10, but ignore it for now
|
||||
|
||||
const r = new SequentialDataReader(packet.getData());
|
||||
const r = new SequentialDataReader(packet.data);
|
||||
const page = r.readI16();
|
||||
const pagePrintProgress = r.readI8();
|
||||
const pageFeedProgress = r.readI8();
|
||||
|
||||
if (packet.getData().length === 10) {
|
||||
if (packet.dataLength === 10) {
|
||||
r.skip(2);
|
||||
const error = r.readI8();
|
||||
throw new PrintError(`Print error (${ResponseCommandId[packet.getCommand()]} packet flag)`, error);
|
||||
throw new PrintError(`Print error (${ResponseCommandId[packet.command]} packet flag)`, error);
|
||||
}
|
||||
|
||||
return { page, pagePrintProgress, pageFeedProgress };
|
||||
@ -113,8 +113,8 @@ export class Abstraction {
|
||||
|
||||
public async connectResult(): Promise<ConnectResult> {
|
||||
const packet = await this.send(PacketGenerator.connect());
|
||||
Validators.u8ArrayLengthEquals(packet.getData(), 1);
|
||||
return packet.getData()[0] as ConnectResult;
|
||||
Validators.u8ArrayLengthAtLeast(packet.data, 1);
|
||||
return packet.data[0] as ConnectResult;
|
||||
}
|
||||
|
||||
public async getPrinterStatusData(): Promise<PrinterStatusData> {
|
||||
@ -122,10 +122,10 @@ export class Abstraction {
|
||||
const packet = await this.send(PacketGenerator.getPrinterStatusData());
|
||||
let supportColor = 0;
|
||||
|
||||
if (packet.getData().length > 12) {
|
||||
supportColor = packet.getData()[10];
|
||||
if (packet.dataLength > 12) {
|
||||
supportColor = packet.data[10];
|
||||
|
||||
let n = packet.getData()[11] * 100 + packet.getData()[12];
|
||||
let n = packet.data[11] * 100 + packet.data[12];
|
||||
if (n >= 204 && n < 300) {
|
||||
protocolVersion = 3;
|
||||
}
|
||||
@ -142,9 +142,9 @@ export class Abstraction {
|
||||
|
||||
public async getPrinterModel(): Promise<PrinterModelId> {
|
||||
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.PrinterModelId));
|
||||
Validators.u8ArrayLengthEquals(packet.getData(), 2);
|
||||
Validators.u8ArrayLengthEquals(packet.data, 2);
|
||||
|
||||
const id = Utils.bytesToI16(packet.getData());
|
||||
const id = Utils.bytesToI16(packet.data);
|
||||
|
||||
if (id in PrinterModelId) {
|
||||
return id as PrinterModelId;
|
||||
@ -166,11 +166,11 @@ export class Abstraction {
|
||||
consumablesType: LabelType.Invalid,
|
||||
};
|
||||
|
||||
if (packet.getData().length === 1) {
|
||||
if (packet.dataLength === 1) {
|
||||
return info;
|
||||
}
|
||||
|
||||
const r = new SequentialDataReader(packet.getData());
|
||||
const r = new SequentialDataReader(packet.data);
|
||||
info.tagPresent = true;
|
||||
info.uuid = Utils.bufToHex(r.readBytes(8), "");
|
||||
info.barCode = r.readVString();
|
||||
@ -194,8 +194,8 @@ export class Abstraction {
|
||||
};
|
||||
|
||||
// originally expected packet length is bound to model id, but we make it more robust and simple
|
||||
const len = packet.getData().length;
|
||||
const r = new SequentialDataReader(packet.getData());
|
||||
const len = packet.dataLength;
|
||||
const r = new SequentialDataReader(packet.data);
|
||||
|
||||
if (len === 10) {
|
||||
// d110
|
||||
@ -235,38 +235,38 @@ export class Abstraction {
|
||||
|
||||
public async getBatteryChargeLevel(): Promise<BatteryChargeLevel> {
|
||||
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.BatteryChargeLevel));
|
||||
Validators.u8ArrayLengthEquals(packet.getData(), 1);
|
||||
return packet.getData()[0] as BatteryChargeLevel;
|
||||
Validators.u8ArrayLengthEquals(packet.data, 1);
|
||||
return packet.data[0] as BatteryChargeLevel;
|
||||
}
|
||||
|
||||
public async getAutoShutDownTime(): Promise<AutoShutdownTime> {
|
||||
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.AutoShutdownTime));
|
||||
Validators.u8ArrayLengthEquals(packet.getData(), 1);
|
||||
return packet.getData()[0] as AutoShutdownTime;
|
||||
Validators.u8ArrayLengthEquals(packet.data, 1);
|
||||
return packet.data[0] as AutoShutdownTime;
|
||||
}
|
||||
|
||||
public async getLabelType(): Promise<LabelType> {
|
||||
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.LabelType));
|
||||
Validators.u8ArrayLengthEquals(packet.getData(), 1);
|
||||
return packet.getData()[0] as LabelType;
|
||||
Validators.u8ArrayLengthEquals(packet.data, 1);
|
||||
return packet.data[0] as LabelType;
|
||||
}
|
||||
|
||||
public async getPrinterSerialNumber(): Promise<string> {
|
||||
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.SerialNumber));
|
||||
Validators.u8ArrayLengthAtLeast(packet.getData(), 1);
|
||||
return Utils.u8ArrayToString(packet.getData());
|
||||
Validators.u8ArrayLengthAtLeast(packet.data, 1);
|
||||
return Utils.u8ArrayToString(packet.data);
|
||||
}
|
||||
|
||||
public async getPrinterBluetoothMacAddress(): Promise<string> {
|
||||
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.BluetoothAddress));
|
||||
Validators.u8ArrayLengthAtLeast(packet.getData(), 1);
|
||||
return Utils.bufToHex(packet.getData().reverse(), ":");
|
||||
Validators.u8ArrayLengthAtLeast(packet.data, 1);
|
||||
return Utils.bufToHex(packet.data.reverse(), ":");
|
||||
}
|
||||
|
||||
public async isSoundEnabled(soundType: SoundSettingsItemType): Promise<boolean> {
|
||||
const packet = await this.send(PacketGenerator.getSoundSettings(soundType));
|
||||
Validators.u8ArrayLengthEquals(packet.getData(), 3);
|
||||
const value = !!packet.getData()[2];
|
||||
Validators.u8ArrayLengthEquals(packet.data, 3);
|
||||
const value = !!packet.data[2];
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ export enum RequestCommandId {
|
||||
PrintEmptyRow = 0x84, // -124
|
||||
PrintEnd = 0xf3,
|
||||
PrinterInfo = 0x40, // See PrinterInfoType
|
||||
PrinterConfig = 0xaf,
|
||||
PrinterStatusData = 0xa5,
|
||||
PrintQuantity = 0x15,
|
||||
PrintStart = 0x01,
|
||||
@ -27,7 +28,7 @@ export enum RequestCommandId {
|
||||
SetPageSize = 0x13, // 2, 4 or 6 bytes
|
||||
SoundSettings = 0x58,
|
||||
Unknown1 = 0x0b, // some info request (niimbot app), 01 long 02 short
|
||||
WriteRFID = 0x70,
|
||||
WriteRFID = 0x70, // same as GetVolumeLevel???
|
||||
}
|
||||
|
||||
export enum ResponseCommandId {
|
||||
@ -42,6 +43,7 @@ export enum ResponseCommandId {
|
||||
In_PrintClear = 0x30,
|
||||
In_PrintEmptyRows = 0xd3,
|
||||
In_PrintEnd = 0xf4,
|
||||
In_PrinterConfig = 0xbf,
|
||||
In_PrinterInfoAutoShutDownTime = 0x47,
|
||||
In_PrinterInfoBluetoothAddress = 0x4d,
|
||||
In_PrinterInfoDensity = 0x41,
|
||||
@ -65,7 +67,6 @@ export enum ResponseCommandId {
|
||||
In_SetPageSize = 0x14,
|
||||
In_SoundSettings = 0x68,
|
||||
In_Unknown1 = 0xe4,
|
||||
In_Unknown2 = 0xc2,
|
||||
}
|
||||
|
||||
export enum PrinterInfoType {
|
||||
|
@ -5,45 +5,60 @@ export class NiimbotPacket {
|
||||
public static readonly HEAD = new Uint8Array([0x55, 0x55]);
|
||||
public static readonly TAIL = new Uint8Array([0xaa, 0xaa]);
|
||||
|
||||
private commandId: RequestCommandId;
|
||||
private data: Uint8Array;
|
||||
private validResponseIds: ResponseCommandId[];
|
||||
private _command: RequestCommandId;
|
||||
private _data: Uint8Array;
|
||||
private _validResponseIds: ResponseCommandId[];
|
||||
|
||||
/** There can be no response after this request. */
|
||||
private oneWay: boolean;
|
||||
private _oneWay: 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.oneWay = false;
|
||||
constructor(command: number, data: Uint8Array | number[], validResponseIds: ResponseCommandId[] = []) {
|
||||
this._command = command;
|
||||
this._data = data instanceof Uint8Array ? data : new Uint8Array(data);
|
||||
this._validResponseIds = validResponseIds;
|
||||
this._oneWay = false;
|
||||
}
|
||||
|
||||
public setNoResponse(): void {
|
||||
this.oneWay = true;
|
||||
/** Data length (header, command, dataLen, checksum, tail are excluded). */
|
||||
public get dataLength(): number {
|
||||
return this._data.length;
|
||||
}
|
||||
public get length(): number {
|
||||
return (
|
||||
NiimbotPacket.HEAD.length + // head
|
||||
1 + // cmd
|
||||
1 + // dataLength
|
||||
this.dataLength +
|
||||
1 + // checksum
|
||||
NiimbotPacket.TAIL.length
|
||||
);
|
||||
}
|
||||
|
||||
public isOneWay(): boolean {
|
||||
return this.oneWay;
|
||||
public set oneWay(value: boolean) {
|
||||
this._oneWay = value;
|
||||
}
|
||||
|
||||
public getValidResponseIds(): ResponseCommandId[] {
|
||||
return this.validResponseIds;
|
||||
public get oneWay(): boolean {
|
||||
return this._oneWay;
|
||||
}
|
||||
|
||||
public getCommand(): number {
|
||||
return this.commandId;
|
||||
public get validResponseIds(): ResponseCommandId[] {
|
||||
return this._validResponseIds;
|
||||
}
|
||||
|
||||
public getData(): Uint8Array {
|
||||
return this.data;
|
||||
public get command(): number {
|
||||
return this._command;
|
||||
}
|
||||
|
||||
public checksum(): number {
|
||||
public get data(): Uint8Array {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
public get checksum(): number {
|
||||
let checksum = 0;
|
||||
checksum ^= this.commandId;
|
||||
checksum ^= this.data.length;
|
||||
this.data.forEach((i: number) => (checksum ^= i));
|
||||
checksum ^= this._command;
|
||||
checksum ^= this._data.length;
|
||||
this._data.forEach((i: number) => (checksum ^= i));
|
||||
return checksum;
|
||||
}
|
||||
|
||||
@ -53,7 +68,7 @@ export class NiimbotPacket {
|
||||
NiimbotPacket.HEAD.length + // head
|
||||
1 + // cmd
|
||||
1 + // dataLength
|
||||
this.data.length +
|
||||
this._data.length +
|
||||
1 + // checksum
|
||||
NiimbotPacket.TAIL.length
|
||||
);
|
||||
@ -65,21 +80,21 @@ export class NiimbotPacket {
|
||||
arr.set(NiimbotPacket.HEAD, pos);
|
||||
pos += NiimbotPacket.HEAD.length;
|
||||
|
||||
arr[pos] = this.commandId;
|
||||
arr[pos] = this._command;
|
||||
pos += 1;
|
||||
|
||||
arr[pos] = this.data.length;
|
||||
arr[pos] = this._data.length;
|
||||
pos += 1;
|
||||
|
||||
arr.set(this.data, pos);
|
||||
pos += this.data.length;
|
||||
arr.set(this._data, pos);
|
||||
pos += this._data.length;
|
||||
|
||||
arr[pos] = this.checksum();
|
||||
arr[pos] = this.checksum;
|
||||
pos += 1;
|
||||
|
||||
arr.set(NiimbotPacket.TAIL, pos);
|
||||
|
||||
if(this.commandId === RequestCommandId.Connect) {
|
||||
if (this._command === RequestCommandId.Connect) {
|
||||
// const newArr = new Uint8Array(arr.length + 1);
|
||||
// newArr[0] = 3;
|
||||
// newArr.set(arr, 1);
|
||||
@ -119,7 +134,7 @@ export class NiimbotPacket {
|
||||
const checksum: number = buf.getUint8(4 + dataLen);
|
||||
const packet = new NiimbotPacket(cmd, data);
|
||||
|
||||
if (packet.checksum() !== checksum) {
|
||||
if (packet.checksum !== checksum) {
|
||||
throw new Error("Invalid packet checksum");
|
||||
}
|
||||
|
||||
|
@ -229,7 +229,7 @@ export class PacketGenerator {
|
||||
// https://github.com/ayufan/niimprint-web/blob/main/cmds.js#L215
|
||||
public static printEmptySpace(pos: number, repeats: number): NiimbotPacket {
|
||||
const packet = new NiimbotPacket(RequestCommandId.PrintEmptyRow, [...Utils.u16ToBytes(pos), repeats]);
|
||||
packet.setNoResponse();
|
||||
packet.oneWay = true;
|
||||
return packet;
|
||||
}
|
||||
|
||||
@ -247,7 +247,7 @@ export class PacketGenerator {
|
||||
repeats,
|
||||
...data,
|
||||
]);
|
||||
packet.setNoResponse();
|
||||
packet.oneWay = true;
|
||||
return packet;
|
||||
}
|
||||
|
||||
@ -268,7 +268,7 @@ export class PacketGenerator {
|
||||
...indexes,
|
||||
]);
|
||||
|
||||
packet.setNoResponse();
|
||||
packet.oneWay = true;
|
||||
return packet;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user