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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
export const ADDR = {
CTRL: 0xdb96,
OVEN: 0xaa55,
};
export const FUNC = {
// used by oven
O_CONNECT: 0x01,
O_TEMPS: 0x02,
O_READ: 0x03,
O_ACK_WRITE: 0x06,
// used by CTRL
C_PWM_HEAT: 0x08,
C_PWM_COOL: 0x0d,
C_STARTSTOP: 0x10,
C_REQ_READ: 0x11,
C_WRITE: 0x20,
C_ACK_CONNECT: 0xf1,
C_ACK_READ: 0xf2,
};
export const ARG = {
// for STARSTOP, REQUEST_READ
STARTSTOP_START: 0x11,
STARTSTOP_STOP: 0x22,
REQUEST_READ: 0x11,
// for CONNECT / ACK_CONNECT
CONNECT_CONNECTING: 0x0100,
CONNECT_CONNECTED: 0x0200,
// for *_PWM
PWM_ON: 0x44,
PWM_OFF: 0x88,
};
const lookup = (tbl, val) => Object.keys(tbl).find(key => tbl[key] === val);
export class Message {
constructor(buffer) {
this.buf = buffer;
this.view = new DataView(this.buf);
this.data = new DataView(this.buf, 4, this.buf.byteLength - 6);
}
get16(i) { return this.data.getUint16(i, false); }
set16(i, v) { this.data.setUint16(i, v, false); }
get address() { return this.view.getUint16(0, false); }
set address(val) { this.view.setUint16(0, val, false); }
get func() { return this.view.getUint8(2); }
set func(val) { this.view.setUint8(2, val)}
get data_len() { return this.view.getUint8(3); }
set data_len(val) { this.view.setUint8(3, val); }
get length() { return this.buf.byteLength; }
get checksum() { return this.view.getUint16(this.buf.byteLength-2, false); }
set checksum(val) { this.view.setUint16(this.buf.byteLength-2, val, false); }
calculateSum() {
let sum = 0;
for (let i = 0; i < this.length - 2; i++) {
sum += this.view.getUint8(i);
}
return sum & 0xffff;
}
getDataArray() {
return new Uint8Array(this.buf, 4, this.buf.byteLength - 6);
}
toString() {
const address = lookup(ADDR, this.address) ?? "????";
const func = lookup(FUNC, this.func) ?? "?_??";
const data = this.getDataArray();
return `to ${address}: ${func.substr(2)} [${data}]`;
}
static from8(addr, func, data) {
const len = 2 + 2 + data.length + 2;
const msg = new Message(new ArrayBuffer(len));
msg.address = addr;
msg.func = func;
msg.data_len = data.length;
for (let i = 0; i < data.length; i++) {
msg.data.setUint8(i, data[i]);
}
msg.checksum = msg.calculateSum();
return msg;
}
static from16(addr, func, data) {
const len = 2 + 2 + 2*data.length + 2;
const msg = new Message(new ArrayBuffer(len));
msg.address = addr;
msg.func = func;
msg.data_len = 2*data.length;
for (let i = 0; i < data.length; i++) {
msg.data.setUint16(2*i, data[i], false);
}
msg.checksum = msg.calculateSum();
return msg;
}
static empty(addr, func, data_len) {
const len = 2 + 2 + 2*data_len + 2;
const msg = new Message(new ArrayBuffer(len));
msg.address = addr;
msg.func = func;
msg.data_len = data_len;
return msg;
}
static tryParse(buffer) {
if (buffer.length < 4 + 2) return;
const data_len = buffer[3];
if (buffer.length < 4 + data_len + 2) return;
const msg = new Message(buffer.slice(0, 4 + data_len + 2).buffer);
if (msg.calculateSum() !== msg.checksum) {
throw new Error(`checksum mismatch: expected ${hex(msg.checksum)} but calculated ${hex(msg.calculateSum())}`);
}
return msg;
};
}
|