import { type } from "./common"; import { z } from "zod"; import _ from "lodash"; import { Err, Ok, type Result } from "ts-results-es"; import { isUint8Array } from "util/types"; const PKG_SIGN_ADDR = 0x00 const PKG_SIGN_DATA = 0xFF const PKG_SIGN_READ = 0x0F const PKG_SIGN_WRITE = 0xF0 export namespace UDPSendProtocol { const CMDLOC_BURST_TYPE = 5 const CMDLOC_TASK_ID = 3 const CMDLOC_READ_WRITE_TYPE = 0 const CmdPackageOptionsSchema = z.object({ burstType: z.enum(["Fixed", "Extend"]), taskID: z.number().nonnegative().lt(4), readWriteType: z.enum(["r", "w"]) }) export type CmdPackageOptions = z.infer export function isCmdPackageOptions(obj: any): obj is CmdPackageOptions { return CmdPackageOptionsSchema.safeParse(obj).success } export class CmdPackage { private ID: number = PKG_SIGN_ADDR private commandType: number = 0 private burstLength: number = 0 private _reserved: number = 0 private address: number = 0 constructor(array: Uint8Array) constructor(options: CmdPackageOptions) constructor(arg: any) { if (isCmdPackageOptions(arg)) { this.setCommandType(arg) } else if (isUint8Array(arg)) { this.ID = arg[0] this.commandType = arg[1] this.burstLength = arg[2] this._reserved = arg[3] this.address = type.bytesToNumber(arg.slice(4)) } else { throw new Err("Wrong Type") } } setCommandType(options: CmdPackageOptions) { const validOptions = CmdPackageOptionsSchema.parse(options) this.commandType = ( ((validOptions.burstType === "Fixed") ? 1 << CMDLOC_BURST_TYPE : 0) | (validOptions.taskID << CMDLOC_TASK_ID) | ((validOptions.readWriteType === "r") ? 1 << CMDLOC_READ_WRITE_TYPE : 0) ) } setBurstLength(len: number): Result { if (!type.UInt8.safeParse(len).success) { return new Err("Not 8Bits Unsigned Integer") } this.burstLength = len return new Ok(null) } setAddress(addr: number): Result { if (!type.UInt32.safeParse(addr).success) { return new Err("Not 32Bits Unsigned Integer") } this.address = addr return new Ok(null) } options(): CmdPackageOptions { return { burstType: type.numberMatch(this.commandType, CMDLOC_BURST_TYPE, "Extend", "Fixed"), taskID: (this.commandType >> CMDLOC_TASK_ID) & 0b0011, readWriteType: type.numberMatch(this.commandType, CMDLOC_READ_WRITE_TYPE, "w", "r") } } toUint8Array(): Uint8Array { var array = new Uint8Array(8) array[0] = this.ID array[1] = this.commandType array[2] = this.burstLength array[3] = this._reserved // Already check address length at the begining of set address let addressBytes = type.numberToBytes(this.address, 4).unwrap() array.set(addressBytes, 4) return array } } export function isCmdPackage(obj: any): obj is CmdPackage { return obj instanceof CmdPackage } export class DataPackage { private ID: number = PKG_SIGN_DATA private _reserved: number = 0 private body: Uint8Array constructor(body: Uint8Array) { this.body = body } toUint8Array(): Uint8Array { var array = new Uint8Array(4 + this.body.length) array[0] = this.ID array.fill(this._reserved, 1, 4) array.set(this.body, 4) return array } } export function isDataPackage(obj: any): obj is DataPackage { return obj instanceof DataPackage } } export namespace UDPReceiveProcotol { export class ReadPackage { private ID: number = PKG_SIGN_READ private taskID: number = 0 private resp: number = 0 private _reserved: number = 0 body: Uint8Array constructor(array: Uint8Array) { if (array.length < 5) { throw new Err("Not Long Enough") } this.ID = array[0] this.taskID = array[1] this.resp = array[2] this._reserved = array[3] this.body = new Uint8Array(array.slice(4)) } toUint8Array(): Uint8Array { let array = new Uint8Array(4 + this.body.length) array[0] = this.ID array[1] = this.taskID array[2] = this.resp array[3] = this._reserved array.set(this.body, 4) return array } } export function isReadPackage(obj: any): obj is ReadPackage { return obj instanceof ReadPackage } export class WritePackage { private ID: number = PKG_SIGN_WRITE private taskID: number = 0 private resp: number = 0 private _reserved: number = 0 constructor(array: Uint8Array) { if (array.length < 4) { throw new Err("Not Long Enough") } this.ID = array[0] this.taskID = array[1] this.resp = array[2] this._reserved = array[3] } toUint8Array(): Uint8Array { return new Uint8Array([ this.ID, this.taskID, this.resp, this._reserved ]) } } export function isWritePackage(obj: any): obj is WritePackage { return obj instanceof WritePackage } }