import { fun } from "./common"; import { z } from "zod"; import _ from "lodash"; export namespace EquipmentPackage { const HEADER_LENGTH = 8 const BYTES_RETURN_ACK = 0b0001_0000 const BYTES_TRANSFORM_TYPE = 0b0000_1000 const BYTES_READ_WRITE_TYPE = 0b0000_0100 const HeaderOptionsSchema = z.object({ returnAck: z.boolean(), transformType: z.enum(["Fixed", "Extend"]), readWriteType: z.enum(["r", "w"]) }).partial() export type HeaderOptions = z.infer export function isHeaderOptions(obj: any): obj is HeaderOptions { return HeaderOptionsSchema.safeParse(obj).success } export class Header { private commandType: number = 0 private bytesLength: number = 0 private commmandID: number = 0 private _reserved: number = 0 private address: number = 0 constructor(options: HeaderOptions) { this.setCommandType(options) } setCommandType(options: HeaderOptions) { const validOptions = HeaderOptionsSchema.parse(options) this.commandType = (validOptions.returnAck === true ? BYTES_RETURN_ACK : 0) | (validOptions.transformType === "Extend" ? BYTES_TRANSFORM_TYPE : 0) | (validOptions.readWriteType === "w" ? BYTES_READ_WRITE_TYPE : 0) } setBytesLength(length: number) { this.bytesLength = length } setAddress(address: number) { this.address = address } getCommandType(): HeaderOptions { return { returnAck: ((this.commandType & BYTES_RETURN_ACK) === BYTES_RETURN_ACK ? true : false), transformType: ((this.commandType & BYTES_TRANSFORM_TYPE) === BYTES_TRANSFORM_TYPE ? "Extend" : "Fixed"), readWriteType: ((this.commandType & BYTES_READ_WRITE_TYPE) === BYTES_READ_WRITE_TYPE ? "w" : "r") } } incCommandID() { this.commmandID++ } clearCommandID() { this.commmandID = 0 } toUint8Array(): Uint8Array { var array = new Uint8Array(HEADER_LENGTH) array[0] = this.commandType array[1] = this.bytesLength array[2] = this.commmandID array[3] = this._reserved array[4] = this._reserved let addressBytes = fun.numberToBytes(this.address, 3) array[5] = addressBytes[0] array[6] = addressBytes[1] array[7] = addressBytes[2] return array } } export class Package { private header: Header private body: Uint8Array constructor(header: Header | HeaderOptions, body?: Uint8Array) { if (header instanceof Header) { this.header = header } else if (isHeaderOptions(header)) { this.header = new Header(header) } else { throw Error("Create EquipmentSocket Failure!") } this.body = (body === undefined) ? new Uint8Array(0) : _.cloneDeep(body) } toUint8Array(): Uint8Array { const header = this.header.toUint8Array() const bodyLength = this.body.length let total = new Uint8Array(header.length + bodyLength) total.set(header) if (bodyLength > 0) total.set(this.body, header.length) return total } } }