202 lines
5.1 KiB
TypeScript
202 lines
5.1 KiB
TypeScript
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<typeof CmdPackageOptionsSchema>
|
|
|
|
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<null, "Not 8Bits Unsigned Integer"> {
|
|
if (!type.UInt8.safeParse(len).success) {
|
|
return new Err("Not 8Bits Unsigned Integer")
|
|
}
|
|
this.burstLength = len
|
|
return new Ok(null)
|
|
}
|
|
|
|
setAddress(addr: number): Result<null, "Not 32Bits Unsigned Integer"> {
|
|
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
|
|
}
|
|
|
|
}
|