finish basic udp protocol
This commit is contained in:
		@@ -36,6 +36,13 @@ test("Test Number Processor Function", () => {
 | 
			
		||||
  expect(type.numberToBytes(0x12345678, 4).unwrap()).toEqual(new Uint8Array([0x78, 0x56, 0x34, 0x12]))
 | 
			
		||||
  expect(type.numberToBytes(0x12345678, 4, true).unwrap()).toEqual(new Uint8Array([0x12, 0x34, 0x56, 0x78]))
 | 
			
		||||
 | 
			
		||||
  // Convert Uint8Array to Number
 | 
			
		||||
  expect(type.bytesToNumber(new Uint8Array([0xFF]))).toBe(255)
 | 
			
		||||
  expect(type.bytesToNumber(new Uint8Array([0xAA, 0xAA]))).toEqual(0xAAAA)
 | 
			
		||||
  expect(type.bytesToNumber(new Uint8Array([0x78, 0x56, 0x34, 0x12]))).toEqual(0x12345678)
 | 
			
		||||
  expect(type.bytesToNumber(new Uint8Array([0x12, 0x34, 0x56, 0x78]), true)).toEqual(0x12345678)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  // Number Match 
 | 
			
		||||
  for (let i = 0; i < CYCLES; i++) {
 | 
			
		||||
    const num1 = _.random(CYCLES / 2, false)
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ export namespace type {
 | 
			
		||||
  export const Int16 = Integer.lt(Math.pow(2, 15)).gte(-Math.pow(2, 16))
 | 
			
		||||
  export const Int32 = Integer.lt(Math.pow(2, 31)).gte(-Math.pow(2, 32))
 | 
			
		||||
 | 
			
		||||
  export function numberToBytes(num: number, bytesLength: number, reverse: boolean = false)
 | 
			
		||||
  export function numberToBytes(num: number, bytesLength: number, isRightHigh: boolean = false)
 | 
			
		||||
    : Result<Uint8Array, ErrorType> {
 | 
			
		||||
    // Check Integer
 | 
			
		||||
    if (!Int32.safeParse(num).success && !UInt32.lte(32).safeParse(bytesLength).success) {
 | 
			
		||||
@@ -39,7 +39,7 @@ export namespace type {
 | 
			
		||||
 | 
			
		||||
    var array = new Uint8Array(bytesLength)
 | 
			
		||||
 | 
			
		||||
    if (reverse) {
 | 
			
		||||
    if (isRightHigh) {
 | 
			
		||||
      for (let i = 0; i < bytesLength; i++) {
 | 
			
		||||
        array[bytesLength - 1 - i] = ((num >> (i << 3)) & 0xFF)
 | 
			
		||||
      }
 | 
			
		||||
@@ -52,6 +52,21 @@ export namespace type {
 | 
			
		||||
    return new Ok(array)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  export function bytesToNumber(bytes: Uint8Array, isRightHigh: boolean = false): number {
 | 
			
		||||
    let num = 0
 | 
			
		||||
    const len = bytes.length
 | 
			
		||||
    if (isRightHigh) {
 | 
			
		||||
      for (let i = 0; i < len; i++) {
 | 
			
		||||
        num += bytes[len - 1 - i] << (i << 3)
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      for (let i = 0; i < len; i++) {
 | 
			
		||||
        num += bytes[i] << (i << 3)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return num
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  export function numberMatch(
 | 
			
		||||
    srcNum: number,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,15 @@
 | 
			
		||||
import { resolve } from "path";
 | 
			
		||||
import { type udp } from "bun";
 | 
			
		||||
import Tinypool from "tinypool";
 | 
			
		||||
import type { UDPReceiveProcotol, UDPSendProtocol } from "./udpProtocol";
 | 
			
		||||
 | 
			
		||||
type UDPDataType = {
 | 
			
		||||
  address: string,
 | 
			
		||||
  data: udp.Data,
 | 
			
		||||
  data: (
 | 
			
		||||
    UDPSendProtocol.CmdPackage |
 | 
			
		||||
    UDPSendProtocol.DataPackage |
 | 
			
		||||
    UDPReceiveProcotol.ReadPackage |
 | 
			
		||||
    UDPReceiveProcotol.WritePackage
 | 
			
		||||
  ),
 | 
			
		||||
  port: number,
 | 
			
		||||
  date?: string,
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,6 @@ import type { UDPDataType } from "./udp"
 | 
			
		||||
const udpClient = await Bun.udpSocket({})
 | 
			
		||||
 | 
			
		||||
export function send(data: UDPDataType): boolean {
 | 
			
		||||
  return udpClient.send(data.data, data.port, data.address)
 | 
			
		||||
  return udpClient.send(data.data.toUint8Array(), data.port, data.address)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,52 +1,86 @@
 | 
			
		||||
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";
 | 
			
		||||
 | 
			
		||||
export namespace SendProtocol {
 | 
			
		||||
  const CMD_BURST_TYPE = 0b1100_0000
 | 
			
		||||
  const CMD_TASK_ID = 0b0011_0000
 | 
			
		||||
  const CMD_READ_WRITE_TYPE = 0b0000_0001
 | 
			
		||||
const PKG_SIGN_ADDR = 0x00
 | 
			
		||||
const PKG_SIGN_DATA = 0xFF
 | 
			
		||||
const PKG_SIGN_READ = 0x0F
 | 
			
		||||
const PKG_SIGN_WRITE = 0xF0
 | 
			
		||||
 | 
			
		||||
  const AddrPackageOptionsSchema = z.object({
 | 
			
		||||
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 AddrPackageOptions = z.infer<typeof AddrPackageOptionsSchema>
 | 
			
		||||
  export type CmdPackageOptions = z.infer<typeof CmdPackageOptionsSchema>
 | 
			
		||||
 | 
			
		||||
  export function isAddrPackageOptions(obj: any): obj is AddrPackageOptions {
 | 
			
		||||
    return AddrPackageOptionsSchema.safeParse(obj).success
 | 
			
		||||
  export function isCmdPackageOptions(obj: any): obj is CmdPackageOptions {
 | 
			
		||||
    return CmdPackageOptionsSchema.safeParse(obj).success
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  export class AddrPackage {
 | 
			
		||||
    private ID: number = 0x00
 | 
			
		||||
  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(options: AddrPackageOptions) {
 | 
			
		||||
      this.setCommandType(options)
 | 
			
		||||
 | 
			
		||||
    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: AddrPackageOptions) {
 | 
			
		||||
      const validOptions = AddrPackageOptionsSchema.parse(options)
 | 
			
		||||
      this.commandType =
 | 
			
		||||
    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) {
 | 
			
		||||
    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) {
 | 
			
		||||
    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(): AddrPackageOptions {
 | 
			
		||||
    options(): CmdPackageOptions {
 | 
			
		||||
      return {
 | 
			
		||||
        burstType: type.numberMatch(this.commandType, CMD_BURST_TYPE, "Extend", "Fixed"),
 | 
			
		||||
        readWriteType: type.numberMatch(this.commandType, CMD_READ_WRITE_TYPE, "w", "r")
 | 
			
		||||
        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")
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -58,18 +92,16 @@ export namespace SendProtocol {
 | 
			
		||||
      array[2] = this.burstLength
 | 
			
		||||
      array[3] = this._reserved
 | 
			
		||||
 | 
			
		||||
      let addressBytes = type.numberToBytes(this.address, 4)
 | 
			
		||||
      array[4] = addressBytes[0]
 | 
			
		||||
      array[5] = addressBytes[1]
 | 
			
		||||
      array[6] = addressBytes[2]
 | 
			
		||||
      array[7] = addressBytes[3]
 | 
			
		||||
      // 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 class DataPackage {
 | 
			
		||||
    private ID: number = 0xFF
 | 
			
		||||
    private ID: number = PKG_SIGN_DATA
 | 
			
		||||
    private _reserved: number = 0
 | 
			
		||||
    private body: Uint8Array
 | 
			
		||||
 | 
			
		||||
@@ -90,4 +122,63 @@ export namespace SendProtocol {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export namespace ReceiveProcotol { }
 | 
			
		||||
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 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
 | 
			
		||||
      ])
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user