All files / static / packet_conv / lanes_info.js

100.00% Branches 15/15
100.00% Lines 107/107
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x6
x6
x7
x7
x6
x7
x7
x1
x9
x9
x6
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x3
x1
x3
x1
x3
x6
x6
x1
x3
x3
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x1
x15
x15
x15
x17
x17
x1
x27
x15
x17
x17
x1
x25
x15
x17
x17
x1
x23
x15
x19
x19
x1
x15
x25
x30
x30
x30
x30
x25
x1
x19
x15








































































































/**
 * @file Encoding/decoding functions for lanes-info packet
 *
 * @author aKuad
 */

import { typeof_detail } from "../util/typeof_detail.js";
import { LaneInfo } from "./LaneInfo.js";


/**
 * Packet type ID of lanes-info packet
 */
export const LANES_INFO_PACKET_TYPE_ID = 0x30;


/**
 * Create lanes-info packet
 *
 * @param {Array<LaneInfo>} lanes_info LaneInfo array to encode
 * @returns {Uint8Array} Encoded packet
 *
 * @throws {TypeError} If `lanes_info` is not `Array`
 * @throws {TypeError} If `lanes_info` has non `LaneInfo` elements
 */
export function packet_lanes_info_encode(lanes_info) {
  // Arguments type checking
  if(!(lanes_info instanceof Array)) {
    throw new TypeError(`lanes_info must be Array, but got ${typeof_detail(lanes_info)}`);
  }
  if(lanes_info.filter(e => !(e instanceof LaneInfo)).length !== 0) {
    throw new TypeError("Non LaneInfo elements detected");
  }

  const packet_body = lanes_info.flatMap(e => Array.from(e.to_bytes()));
  return Uint8Array.of(LANES_INFO_PACKET_TYPE_ID, ...packet_body);
}


/**
 * Unpack lanes-info packet
 *
 * Note: About raises, see reference of `is_lanes_info_packet`.
 *
 * @param {Uint8Array} raw_packet Encoded packet
 * @returns {Array<LaneInfo>} Decoded data - Lane ID, lane name, current volume
 */
export function packet_lanes_info_decode(raw_packet) {
  is_lanes_info_packet(raw_packet, true);

  const lanes_info = [];

  for(let i = 1; i < raw_packet.length; i += 5) {
    lanes_info.push(LaneInfo.from_bytes(raw_packet.slice(i, i + 5)));
  }

  return lanes_info;
}


/**
 * Verify the packet is lanes_info packet
 *
 * Note: It won't check lane_name field contain non-ascii or control-ascii characters
 *
 * @param {Uint8Array} raw_packet Packet to verify
 * @param {boolean} throw_on_invalid Toggle behavior when packet is invalid, true: raise exception, false: return false
 * @returns {boolean} It is an lanes_info: true, otherwise: false (if throw_on_invalid === true, error will be thrown)
 *
 * @throws {TypeError} If `raw_packet` is not `Uint8Array`
 * @throws {RangeError} If `raw_packet` is an empty array
 * @throws {RangeError} If `raw_packet` has not an lanes_info packet type ID
 * @throws {RangeError} If `raw_packet` is invalid length as lanes_info
 */
export function is_lanes_info_packet(raw_packet, throw_on_invalid = false) {
  try {
    // Arguments type checking
    if(!(raw_packet instanceof Uint8Array)) {
      throw new TypeError(`raw_packet must be Uint8Array, but got ${typeof_detail(raw_packet)}`);
    }

    // Packet content availability checking
    if(raw_packet.length === 0) {
      throw new RangeError("Empty array passed");
    }

    // Packet type ID checking
    if(raw_packet[0] !== LANES_INFO_PACKET_TYPE_ID) {
      throw new RangeError(`It has not an lanes_info packet type ID - should be ${LANES_INFO_PACKET_TYPE_ID}, but got ${raw_packet[0]}`);
    }

    // Packet length checking
    if(((raw_packet.length - 1) % 5) !== 0) {
      throw new RangeError("Invalid length bytes as lanes_info packet, may be broken");
    }

  } catch(e) {
    if(throw_on_invalid) {
      throw e;
    } else {
      return false;
    }
  }

  return true;
}