This repository has been archived on 2024-09-16. You can view files and clone it, but cannot push or open issues or pull requests.

305 lines
8.4 KiB
TypeScript
Raw Normal View History

2024-07-22 00:00:01 +03:00
import {
2024-07-23 00:00:01 +03:00
AutoShutdownTime,
BatteryChargeLevel,
2024-07-25 00:00:01 +03:00
ConnectResult,
2024-07-23 00:00:01 +03:00
HeartbeatType,
2024-07-22 00:00:01 +03:00
LabelType,
NiimbotPacket,
PacketGenerator,
PrinterInfoType,
2024-07-31 01:00:02 +03:00
PrintOptions,
2024-07-22 00:00:01 +03:00
ResponseCommandId,
SoundSettingsItemType,
SoundSettingsType,
2024-07-31 01:00:02 +03:00
EncodedImage,
NiimbotAbstractClient,
Utils,
Validators,
ProtocolVersion,
} from "..";
2024-07-23 00:00:01 +03:00
import { SequentialDataReader } from "./data_reader";
2024-07-22 00:00:01 +03:00
export class PrintError extends Error {
public readonly reasonId: number;
constructor(message: string, reasonId: number) {
super(message);
this.reasonId = reasonId;
}
}
export interface PrintStatus {
/** 0 n */
page: number;
/** 0 100 */
pagePrintProgress: number;
/** 0 100 */
pageFeedProgress: number;
}
export interface RfidInfo {
tagPresent: boolean;
uuid: string;
barCode: string;
serialNumber: string;
allPaper: number;
usedPaper: number;
consumablesType: LabelType;
}
/** closingState inverted on some printers */
export interface HeartbeatData {
paperState: number;
rfidReadState: number;
2024-07-25 00:00:01 +03:00
lidClosed: boolean;
powerLevel: BatteryChargeLevel;
2024-07-22 00:00:01 +03:00
}
2024-07-23 00:00:01 +03:00
export interface SoundSettings {
category: SoundSettingsType;
item: SoundSettingsItemType;
value: boolean;
}
2024-07-25 00:00:01 +03:00
export interface PrinterStatusData {
supportColor: number;
protocolVersion: number;
}
2024-07-23 00:00:01 +03:00
/** Not sure for name. */
2024-07-22 00:00:01 +03:00
export class Abstraction {
2024-07-31 01:00:02 +03:00
private readonly DEFAULT_TIMEOUT: number = 1_000;
2024-07-22 00:00:01 +03:00
private client: NiimbotAbstractClient;
2024-07-31 01:00:02 +03:00
private timeout: number = this.DEFAULT_TIMEOUT;
2024-07-22 00:00:01 +03:00
constructor(client: NiimbotAbstractClient) {
this.client = client;
}
public getTimeout(): number {
return this.timeout;
}
public setTimeout(value: number) {
this.timeout = value;
}
2024-07-31 01:00:02 +03:00
public setDefaultTimeout() {
this.timeout = this.DEFAULT_TIMEOUT;
}
2024-07-23 00:00:01 +03:00
/** Send packet and wait for response */
2024-07-22 00:00:01 +03:00
private async send(packet: NiimbotPacket): Promise<NiimbotPacket> {
return this.client.sendPacketWaitResponse(packet, this.timeout);
}
public async getPrintStatus(): Promise<PrintStatus> {
const packet = await this.send(PacketGenerator.printStatus());
2024-07-26 00:00:02 +03:00
if (packet.command === ResponseCommandId.In_PrintError) {
Validators.u8ArrayLengthEquals(packet.data, 1);
2024-07-28 00:00:01 +03:00
throw new PrintError(`Print error (${ResponseCommandId[packet.command]} packet received)`, packet.data[0]);
2024-07-22 00:00:01 +03:00
}
2024-07-26 00:00:02 +03:00
Validators.u8ArrayLengthAtLeast(packet.data, 4); // can be 8, 10, but ignore it for now
2024-07-22 00:00:01 +03:00
2024-07-26 00:00:02 +03:00
const r = new SequentialDataReader(packet.data);
2024-07-22 00:00:01 +03:00
const page = r.readI16();
const pagePrintProgress = r.readI8();
const pageFeedProgress = r.readI8();
2024-07-26 00:00:02 +03:00
if (packet.dataLength === 10) {
2024-07-22 00:00:01 +03:00
r.skip(2);
const error = r.readI8();
2024-07-28 00:00:01 +03:00
if (error !== 0) {
throw new PrintError(`Print error (${ResponseCommandId[packet.command]} packet flag)`, error);
}
2024-07-22 00:00:01 +03:00
}
return { page, pagePrintProgress, pageFeedProgress };
}
2024-07-25 00:00:01 +03:00
public async connectResult(): Promise<ConnectResult> {
const packet = await this.send(PacketGenerator.connect());
2024-07-26 00:00:02 +03:00
Validators.u8ArrayLengthAtLeast(packet.data, 1);
return packet.data[0] as ConnectResult;
2024-07-25 00:00:01 +03:00
}
public async getPrinterStatusData(): Promise<PrinterStatusData> {
let protocolVersion = 0;
const packet = await this.send(PacketGenerator.getPrinterStatusData());
let supportColor = 0;
2024-07-28 00:00:01 +03:00
if (packet.dataLength > 12) {
supportColor = packet.data[10];
2024-07-25 00:00:01 +03:00
2024-08-01 01:00:02 +03:00
const n = packet.data[11] * 100 + packet.data[12];
2024-07-28 00:00:01 +03:00
if (n >= 204 && n < 300) {
protocolVersion = 3;
2024-07-25 00:00:01 +03:00
}
2024-07-28 00:00:01 +03:00
if (n >= 301) {
protocolVersion = 4;
}
}
2024-07-25 00:00:01 +03:00
return {
supportColor,
2024-07-28 00:00:01 +03:00
protocolVersion,
};
2024-07-25 00:00:01 +03:00
}
2024-08-01 01:00:02 +03:00
public async getPrinterModel(): Promise<number> {
2024-07-22 00:00:01 +03:00
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.PrinterModelId));
2024-07-26 00:00:02 +03:00
Validators.u8ArrayLengthEquals(packet.data, 2);
2024-08-01 01:00:02 +03:00
return Utils.bytesToI16(packet.data);
2024-07-22 00:00:01 +03:00
}
/** Read paper nfc tag info */
public async rfidInfo(): Promise<RfidInfo> {
const packet = await this.send(PacketGenerator.rfidInfo());
const info: RfidInfo = {
tagPresent: false,
uuid: "",
barCode: "",
serialNumber: "",
allPaper: -1,
usedPaper: -1,
consumablesType: LabelType.Invalid,
};
2024-07-26 00:00:02 +03:00
if (packet.dataLength === 1) {
2024-07-22 00:00:01 +03:00
return info;
}
2024-07-26 00:00:02 +03:00
const r = new SequentialDataReader(packet.data);
2024-07-22 00:00:01 +03:00
info.tagPresent = true;
info.uuid = Utils.bufToHex(r.readBytes(8), "");
info.barCode = r.readVString();
info.serialNumber = r.readVString();
info.allPaper = r.readI16();
info.usedPaper = r.readI16();
info.consumablesType = r.readI8() as LabelType;
r.end();
return info;
}
public async heartbeat(): Promise<HeartbeatData> {
2024-07-29 00:00:01 +03:00
const packet = await this.send(PacketGenerator.heartbeat(HeartbeatType.Advanced1));
2024-07-22 00:00:01 +03:00
const info: HeartbeatData = {
paperState: -1,
rfidReadState: -1,
2024-07-25 00:00:01 +03:00
lidClosed: false,
powerLevel: BatteryChargeLevel.Charge0,
2024-07-22 00:00:01 +03:00
};
2024-07-23 00:00:01 +03:00
// originally expected packet length is bound to model id, but we make it more robust and simple
2024-07-26 00:00:02 +03:00
const len = packet.dataLength;
const r = new SequentialDataReader(packet.data);
2024-07-22 00:00:01 +03:00
2024-07-23 00:00:01 +03:00
if (len === 10) {
2024-07-22 00:00:01 +03:00
// d110
r.skip(8);
2024-07-25 00:00:01 +03:00
info.lidClosed = r.readBool();
2024-07-22 00:00:01 +03:00
info.powerLevel = r.readI8();
2024-07-23 00:00:01 +03:00
} else if (len === 20) {
2024-07-22 00:00:01 +03:00
r.skip(18);
info.paperState = r.readI8();
info.rfidReadState = r.readI8();
2024-07-23 00:00:01 +03:00
} else if (len === 19) {
2024-07-22 00:00:01 +03:00
r.skip(15);
2024-07-25 00:00:01 +03:00
info.lidClosed = r.readBool();
2024-07-22 00:00:01 +03:00
info.powerLevel = r.readI8();
info.paperState = r.readI8();
info.rfidReadState = r.readI8();
2024-07-23 00:00:01 +03:00
} else if (len === 13) {
2024-07-22 00:00:01 +03:00
// b1
r.skip(9);
2024-07-25 00:00:01 +03:00
info.lidClosed = r.readBool();
2024-07-22 00:00:01 +03:00
info.powerLevel = r.readI8();
info.paperState = r.readI8();
info.rfidReadState = r.readI8();
} else {
throw new Error("Invalid heartbeat length");
}
r.end();
2024-08-01 01:00:02 +03:00
const model: number | undefined = this.client.getPrinterInfo().model_id;
2024-07-25 00:00:01 +03:00
2024-08-01 01:00:02 +03:00
if (model !== undefined && ![512, 514, 513, 2304, 1792, 3584, 5120, 2560, 3840, 4352, 272].includes(model)) {
2024-07-25 00:00:01 +03:00
info.lidClosed = !info.lidClosed;
}
2024-07-22 00:00:01 +03:00
return info;
}
2024-07-23 00:00:01 +03:00
public async getBatteryChargeLevel(): Promise<BatteryChargeLevel> {
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.BatteryChargeLevel));
2024-07-26 00:00:02 +03:00
Validators.u8ArrayLengthEquals(packet.data, 1);
return packet.data[0] as BatteryChargeLevel;
2024-07-23 00:00:01 +03:00
}
public async getAutoShutDownTime(): Promise<AutoShutdownTime> {
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.AutoShutdownTime));
2024-07-26 00:00:02 +03:00
Validators.u8ArrayLengthEquals(packet.data, 1);
return packet.data[0] as AutoShutdownTime;
2024-07-23 00:00:01 +03:00
}
2024-07-28 00:00:01 +03:00
public async setAutoShutDownTime(time: AutoShutdownTime): Promise<void> {
await this.send(PacketGenerator.setAutoShutDownTime(time));
}
2024-07-23 00:00:01 +03:00
public async getLabelType(): Promise<LabelType> {
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.LabelType));
2024-07-26 00:00:02 +03:00
Validators.u8ArrayLengthEquals(packet.data, 1);
return packet.data[0] as LabelType;
2024-07-23 00:00:01 +03:00
}
public async getPrinterSerialNumber(): Promise<string> {
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.SerialNumber));
2024-07-26 00:00:02 +03:00
Validators.u8ArrayLengthAtLeast(packet.data, 1);
return Utils.u8ArrayToString(packet.data);
2024-07-23 00:00:01 +03:00
}
public async getPrinterBluetoothMacAddress(): Promise<string> {
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.BluetoothAddress));
2024-07-26 00:00:02 +03:00
Validators.u8ArrayLengthAtLeast(packet.data, 1);
return Utils.bufToHex(packet.data.reverse(), ":");
2024-07-23 00:00:01 +03:00
}
public async isSoundEnabled(soundType: SoundSettingsItemType): Promise<boolean> {
const packet = await this.send(PacketGenerator.getSoundSettings(soundType));
2024-07-26 00:00:02 +03:00
Validators.u8ArrayLengthEquals(packet.data, 3);
const value = !!packet.data[2];
2024-07-23 00:00:01 +03:00
return value;
}
public async setSoundEnabled(soundType: SoundSettingsItemType, value: boolean): Promise<void> {
await this.send(PacketGenerator.setSoundSettings(soundType, value));
}
2024-07-31 01:00:02 +03:00
2024-08-01 01:00:02 +03:00
public async print(
protoVersion: ProtocolVersion,
image: EncodedImage,
options?: PrintOptions,
timeout?: number
): Promise<void> {
2024-07-31 01:00:02 +03:00
this.setTimeout(timeout ?? 10_000);
const packets: NiimbotPacket[] = PacketGenerator.generatePrintSequence(protoVersion, image, options);
try {
for (const element of packets) {
await this.send(element);
}
} finally {
this.setDefaultTimeout();
}
}
public async printEnd(): Promise<void> {
await this.send(PacketGenerator.printEnd());
}
2024-07-22 00:00:01 +03:00
}