FPGA_WebLab/server/udpProtocol.ts

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
}
}