aboutsummaryrefslogtreecommitdiffstats
path: root/web/protocol.js
diff options
context:
space:
mode:
Diffstat (limited to 'web/protocol.js')
-rw-r--r--web/protocol.js138
1 files changed, 138 insertions, 0 deletions
diff --git a/web/protocol.js b/web/protocol.js
new file mode 100644
index 0000000..9c93f8e
--- /dev/null
+++ b/web/protocol.js
@@ -0,0 +1,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;
+ };
+}