@ralphwetzel/node-red-ds2482-mcu
Version:
DS2482 I2C 1-Wire Master controller for Node-RED w/ MCU support
254 lines (206 loc) • 10.3 kB
JavaScript
/*
node-red-DS2482-mcu by @ralphwetzel
https://github.com/ralphwetzel/node-red-DS2482-mcu
License: MIT
*/
import {Buffer} from "buffer";
import {CRC16} from "crc";
class ds2408 {
paths = {
"power": [this.power_get],
"disable_test_mode": [undefined, this.disable_test_mode],
"strobe": [this.strobe_get, this.strobe_set],
"por": [this.por_get, this.por_set],
"sensed/all": [this.state_get],
"pio/all": [this.pio_get, this.pio_set],
"latch/all": [this.latch_get, this.latch_reset],
}
constructor () {
for (let i=0;i<8;i++) {
this.paths["sensed/ch" + i] = [ds2408.prototype["state_get" + i]];
this.paths["pio/ch" + i] = [ds2408.prototype["pio_get" + i], ds2408.prototype["pio_set" + i]];
this.paths["latch/ch" + i] = [ds2408.prototype["latch_get" + i]];
}
}
#cmds = Object.freeze({
READ_PIO: 0xF0,
CHANNEL_ACCESS_READ: 0xF5,
CHANNEL_ACCESS_WRITE: 0x5A,
WRITE_REGISTER: 0xCC,
RESET_LATCHES: 0xC3,
})
#channels = Object.freeze({
CH0: (1 << 0),
CH1: (1 << 1),
CH2: (1 << 2),
CH3: (1 << 3),
CH4: (1 << 4),
CH5: (1 << 5),
CH6: (1 << 6),
CH7: (1 << 7),
})
#bits = Object.freeze({
PLS: (1 << 0),
CT: (1 << 1),
ROS: (1 << 2),
PORL: (1 << 3),
VCCP: (1 << 7)
})
#registers = Object.freeze({
LOGIC_STATE: 0x88,
OUTPUT_LATCH_STATE: 0x89,
ACTIVITY_LATCH_STATE: 0x8A,
SELECTION_MASK: 0x8B,
POLATITY: 0x8C,
CONTROL_STATUS: 0x8D
})
#register_read(bridge, id, target) {
if (target) {
if (target < 0x88) { return 0; }
if (target > 0x8d) { return 0xFF; }
}
let cmd = Buffer.from([this.#cmds.READ_PIO, 0x88, 0]);
// { poly: 0x8005, init: 0x0000, res: 0x44C2, refIn: true, refOut: true, xorOut: 0xFFFF, name: "CRC-16/MAXIM" },
let crc16 = new CRC16(0x8005, 0, true, true, 0xFFFF);
let checksum;
let crc;
let regs;
let count = 5
do {
// initialisation
crc16.reset();
crc16.checksum(cmd.buffer);
bridge.matchROM(id);
trace("writing: " + cmd.toString("hex") + "\n");
// debugger;
bridge.writeData(cmd);
regs = bridge.readData(10); // registers until 0x8f, then crc16
trace("#register_read: " + JSON.stringify(regs) + "\n");
checksum = regs.readUInt16LE(8); // crc16 in 2 last bytes
let cbuf = Buffer.from(regs.buffer, 0, 8);
crc = crc16.checksum(cbuf);
trace("crc: " + crc.toString(16) + " | checksum: " + checksum.toString(16) + "\n");
count--;
} while (true == false) // (checksum != crc && count > -1)
if (target) {
return regs.readUInt8(target - 0x88);
}
return regs;
}
#register_write(bridge, id, data, target, invert) {
if (!data) return;
if (target < 0x8B || target > 0x8D) return;
data = invert ? (data ^ 0xFF) : data;
bridge.matchROM(id);
bridge.writeData([this.#cmds.WRITE_REGISTER, target, 0, (data & 0xFF)]);
bridge._resetWire();
}
#bit_get(value, bit) {
return ((value >> bit) % 2);
}
#bit_set(value, bit, status) {
return status ? (value | 1<<bit) : (value & ~(1<<bit));
}
#register_bit_get(bridge, id, register, bit, invert) {
let reg = this.#register_read(bridge, id, register);
reg = invert ? (reg ^ 0xFF) : reg
return this.#bit_get(reg, bit);
}
#register_bit_set(bridge, id, register, bit, state, invert) {
invert = invert ? 1 : 0;
state = state ? 1-invert : 0+invert;
let reg = this.#register_read(bridge, id, register);
reg = this.#bit_set(reg, bit, state);
do {
this.#register_write(bridge, id, register);
let check = this.#register_read(bridge, id, register);
} while (check != reg)
}
power_get(bridge, id) {
return this.#register_bit_get(bridge, id, this.#registers.CONTROL_STATUS, this.#bits.VCCP);
}
por_get(bridge, id) {
return this.#register_bit_get(bridge, id, this.#registers.CONTROL_STATUS, this.#bits.PORL);
}
por_set(bridge, id, data) {
data = data ? 1 : 0;
this.#register_bit_set(bridge, id, this.#registers.CONTROL_STATUS, this.#bits.PORL, state);
}
strobe_get(bridge, id) {
return this.#register_bit_get(bridge, id, this.#registers.CONTROL_STATUS, this.#bits.ROS);
}
strobe_set(bridge, id, data) {
return this.#register_bit_set(bridge, id, this.#registers.CONTROL_STATUS)
}
disable_test_mode(bridge, id) {
// magic command...
bridge.matchROM(id);
bridge.writeData([0x96, id, 0x3C]);
bridge._resetWire();
}
latch_reset(bridge, id) {
bridge.matchROM(id);
let count = 5;
do {
bridge.writeData(this.#cmds.RESET_LATCHES);
let res = bridge.readData(1);
count--;
} while (res != 0xAA & count > -1);
}
#pio_set_channel(bridge, id, channel, data) {
// to be sure!
this.disable_test_mode();
let reg;
if (channel) {
reg = this.#register_read(bridge, id, this.#registers.OUTPUT_LATCH_STATE);
reg = this.#bit_set(reg, channel, (data ? 1 : 0));
} else {
reg = data;
}
// reg = (reg ^ 0xFF) & 0xFF ; // invert bits & limit to byte
reg = reg & 0xFF;
bridge.writeData([this.#cmds.CHANNEL_ACCESS_WRITE, reg, (~reg & 0xFF)]);
let res = bridge.readData(1);
return (res == 0xAA);
}
// 0x88, inverted
state_get(bridge, id) { return this.#register_read(bridge, id, this.#registers.LOGIC_STATE); }
state_get0(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.LOGIC_STATE, this.#channels.CH0); }
state_get1(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.LOGIC_STATE, this.#channels.CH1); }
state_get2(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.LOGIC_STATE, this.#channels.CH2); }
state_get3(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.LOGIC_STATE, this.#channels.CH3); }
state_get4(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.LOGIC_STATE, this.#channels.CH4); }
state_get5(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.LOGIC_STATE, this.#channels.CH5); }
state_get6(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.LOGIC_STATE, this.#channels.CH6); }
state_get7(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.LOGIC_STATE, this.#channels.CH7); }
// 0x89, inverted
pio_get(bridge, id) { return this.#register_read(bridge, id, this.#registers.OUTPUT_LATCH_STATE); }
pio_get0(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.OUTPUT_LATCH_STATE, this.#channels.CH0); }
pio_get1(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.OUTPUT_LATCH_STATE, this.#channels.CH1); }
pio_get2(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.OUTPUT_LATCH_STATE, this.#channels.CH2); }
pio_get3(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.OUTPUT_LATCH_STATE, this.#channels.CH3); }
pio_get4(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.OUTPUT_LATCH_STATE, this.#channels.CH4); }
pio_get5(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.OUTPUT_LATCH_STATE, this.#channels.CH5); }
pio_get6(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.OUTPUT_LATCH_STATE, this.#channels.CH6); }
pio_get7(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.OUTPUT_LATCH_STATE, this.#channels.CH7); }
pio_set(bridge, id, data) { return this.#pio_set_channel(bridge, id, data); }
pio_set0(bridge, id, data) { return this.#pio_set_channel(bridge, id, this.#channels.CH0, data); }
pio_set1(bridge, id, data) { return this.#pio_set_channel(bridge, id, this.#channels.CH1, data); }
pio_set2(bridge, id, data) { return this.#pio_set_channel(bridge, id, this.#channels.CH2, data); }
pio_set3(bridge, id, data) { return this.#pio_set_channel(bridge, id, this.#channels.CH3, data); }
pio_set4(bridge, id, data) { return this.#pio_set_channel(bridge, id, this.#channels.CH4, data); }
pio_set5(bridge, id, data) { return this.#pio_set_channel(bridge, id, this.#channels.CH5, data); }
pio_set6(bridge, id, data) { return this.#pio_set_channel(bridge, id, this.#channels.CH6, data); }
pio_set7(bridge, id, data) { return this.#pio_set_channel(bridge, id, this.#channels.CH7, data); }
// 0x8a
latch_get(bridge, id) { return this.#register_read(bridge, id, this.#registers.ACTIVITY_LATCH_STATE); }
latch_get0(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.ACTIVITY_LATCH_STATE, this.#channels.CH0); }
latch_get1(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.ACTIVITY_LATCH_STATE, this.#channels.CH1); }
latch_get2(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.ACTIVITY_LATCH_STATE, this.#channels.CH2); }
latch_get3(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.ACTIVITY_LATCH_STATE, this.#channels.CH3); }
latch_get4(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.ACTIVITY_LATCH_STATE, this.#channels.CH4); }
latch_get5(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.ACTIVITY_LATCH_STATE, this.#channels.CH5); }
latch_get6(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.ACTIVITY_LATCH_STATE, this.#channels.CH6); }
latch_get7(bridge, id) { return this.#register_bit_get(bridge, id, this.#registers.ACTIVITY_LATCH_STATE, this.#channels.CH7); }
}
export { ds2408 as default}