diff options
Diffstat (limited to 'web/protocol.js')
| -rw-r--r-- | web/protocol.js | 138 |
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; + }; +} |
