diff --git a/lib/slave.js b/lib/slave.js deleted file mode 100644 index e517d5d..0000000 --- a/lib/slave.js +++ /dev/null @@ -1,406 +0,0 @@ -'use strict'; -const common = require(__dirname + '/common.js'); -const Modbus = require('./jsmodbus'); - -// expected -// let options = { -// config: { -// round: 1, -// tcp: { -// port: 502 -// } -// }, -// objects: { -// } -// coils: { -// config: ... -// changed: true, -// addressHigh: 0, -// addressLow: 0, -// values: [], -// mapping: {} -// }, -// inputRegs: ..., -// disInputs: ..., -// holdingRegs: ... -// }; - -function Slave(options, adapter) { - let objects = options.objects; - let device = options.devices[Object.keys(options.devices)[0]]; - let delayStart = true; - let modbusServer; - - function getListOfClients(clients) { - let list = []; - for(let c in clients) { - if (clients.hasOwnProperty(c)) { - let address = clients[c].address().address; - if (address) list.push(address); - } - } - return list.join(','); - } - - this.write = (id, state) => { - if (!objects[id] || !objects[id].native) { - adapter.log.error('Can not set state ' + id + ': unknown object'); - return; - } - - if (objects[id].native.float === undefined) { - objects[id].native.float = - objects[id].native.type === 'floatle' || objects[id].native.type === 'floatbe' || objects[id].native.type === 'floatsw' || - objects[id].native.type === 'doublele' || objects[id].native.type === 'doublebe' || objects[id].native.type === 'floatsb'; - } - let val; - let buffer; - let b; - - let t = typeof state.val; - let type = objects[id].native.regType; - let regs = device[type]; - if (!regs) { - adapter.log.error('Invalid type ' + type); - return; - } - regs.changed = true; - - if (type === 'disInputs' || type === 'coils') { - if (t === 'boolean' || t === 'number') { - regs.values[objects[id].native.address - regs.addressLow] = state.val ? 1 : 0; - } else { - regs.values[objects[id].native.address - regs.addressLow] = parseInt(state.val, 10) ? 1 : 0; - } - } else if (type === 'inputRegs' || type === 'holdingRegs') { - if (objects[id].native.type !== 'string') { - if (t === 'boolean') { - val = state.val ? 1 : 0; - } else if (t === 'number') { - val = state.val; - } else { - val = parseFloat(state.val); - } - val = (val - objects[id].native.offset) / objects[id].native.factor; - if (!objects[id].native.float) val = Math.round(val); - } else { - val = state.val; - } - buffer = common.writeValue(objects[id].native.type, val, objects[id].native.len); - for (b = 0; b < buffer.length; b++) { - regs.values[(objects[id].native.address - regs.addressLow) * 2 + b] = buffer[b]; - } - } else { - adapter.log.error('Unknown state "' + id + '" type: ' + objects[id].native.regType); - } - }; - - this.start = () => { - if (!delayStart && !modbusServer) { - modbusServer = Modbus('server', 'tcp')({ - options: { - log: adapter.log, - tcp: { - port: parseInt(options.config.tcp.port, 10) || 502, - hostname: options.config.tcp.bind || '127.0.0.1', - } - }, - responseDelay: 100, - coils: new Buffer((device.coils.addressHigh >> 3) + ((device.coils.addressHigh - 1) % 8 ? 1 : 0)), - discrete: new Buffer((device.disInputs.addressHigh >> 3) + ((device.disInputs.addressHigh - 1) % 8 ? 1 : 0)), - input: new Buffer(device.inputRegs.addressHigh * 2), - holding: new Buffer(device.holdingRegs.addressHigh * 2) - }); - - modbusServer.on('readCoilsRequest', function (start, quantity) { - let regs = device.coils; - if (regs.changed || (regs.lastStart > start || regs.lastEnd < start + quantity)) { - regs.lastStart = start; - regs.lastEnd = start + quantity; - regs.changed = false; - let resp = new Array(Math.ceil(quantity / 16) * 2); - let i = 0; - let data = this.getCoils(); - let j; - for (j = 0; j < resp.length && start + j < data.byteLength; j++) { - resp[j] = data.readUInt8(start + j); - } - for (; j < resp.length; j++) { - resp[j] = 0; - } - - while (i < quantity && i + start < regs.addressHigh) { - if (regs.values[i + start - regs.addressLow]) { - resp[Math.floor(i / 8)] |= 1 << (i % 8); - } else { - resp[Math.floor(i / 8)] &= ~(1 << (i % 8)); - } - i++; - } - let len = data.length; - for (i = 0; i < resp.length; i++) { - if (start + i >= len) break; - data.writeUInt8(resp[i], start + i); - } - } - }); - - modbusServer.on('readDiscreteInputsRequest', function (start, quantity) { - let regs = device.disInputs; - if (regs.changed || (regs.lastStart > start || regs.lastEnd < start + quantity)) { - regs.lastStart = start; - regs.lastEnd = start + quantity; - regs.changed = false; - let resp = new Array(Math.ceil(quantity / 16) * 2); - let i = 0; - let data = this.getDiscrete(); - let j; - for (j = 0; j < resp.length && start + j < data.byteLength; j++) { - resp[j] = data.readUInt8(start + j); - } - for (; j < resp.length; j++) { - resp[j] = 0; - } - while (i < quantity && i + start < regs.addressHigh) { - if (regs.values[i + start - regs.addressLow]) { - resp[Math.floor(i / 8)] |= 1 << (i % 8); - } else { - resp[Math.floor(i / 8)] &= ~(1 << (i % 8)); - } - i++; - } - let len = data.length; - for (i = 0; i < resp.length; i++) { - if (start + i >= len) break; - data.writeUInt8(resp[i], start + i); - } - } - }); - - modbusServer.on('readInputRegistersRequest', function (start, quantity) { - let regs = device.inputRegs; - if (regs.changed || (regs.lastStart > start || regs.lastEnd < start + quantity)) { - regs.lastStart = start; - regs.lastEnd = start + quantity; - regs.changed = false; - let data = this.getInput(); - const end = start + quantity * 2; - const low = regs.addressLow * 2; - const high = regs.addressHigh * 2; - for (let i = start; i < end; i++) { - if (i >= data.length) break; - if (i >= low && i < high) { - data.writeUInt8(regs.values[i - low], i); - } else { - data.writeUInt8(0, i); - } - } - } - }); - - modbusServer.on('readHoldingRegistersRequest', function (start, quantity) { - let regs = device.holdingRegs; - if (regs.changed || (regs.lastStart > start || regs.lastEnd < start + quantity)) { - regs.lastStart = start; - regs.lastEnd = start + quantity; - regs.changed = false; - let data = this.getHolding(); - const end = start + quantity * 2; - const low = regs.addressLow * 2; - const high = regs.addressHigh * 2; - for (let i = start; i < end; i++) { - if (i >= data.length) break; - if (i >= low && i < high) { - data.writeUInt8(regs.values[i - low], i); - } else { - data.writeUInt8(0, i); - } - } - } - }); - - modbusServer.on('postWriteSingleCoilRequest', function (start, value) { - let regs = device.coils; - let a = start - regs.addressLow; - - if (a >= 0 && regs.mapping[a]) { - adapter.setState(regs.mapping[a], value, true, function (err) { - // analyse if the state could be set (because of permissions) - if (err) adapter.log.error('Can not set state: ' + err); - }); - regs.values[a] = value; - } - }); - - const mPow2 = [ - 0x01, - 0x02, - 0x04, - 0x08, - 0x10, - 0x20, - 0x40, - 0x80 - ]; - - modbusServer.on('postWriteMultipleCoilsRequest', function (start, length /* , byteLength*/) { - let regs = device.coils; - let i = 0; - let data = this.getCoils(); - if (start < regs.addressLow) { - start = regs.addressLow; - } - - while (i < length && i + start < regs.addressHigh) { - let a = i + start - regs.addressLow; - if (a >= 0 && regs.mapping[a]) { - let value = data.readUInt8((i + start) >> 3); - value = value & mPow2[(i + start) % 8]; - adapter.setState(regs.mapping[a], !!value, true, function (err) { - // analyse if the state could be set (because of permissions) - if (err) adapter.log.error('Can not set state: ' + err); - }); - regs.values[a] = !!value; - } - i++; - } - }); - - modbusServer.on('postWriteSingleRegisterRequest', function (start, value) { - let regs = device.holdingRegs; - start = start >> 1; - let a = start - regs.addressLow; - - if (a >= 0 && regs.mapping[a]) { - let native = options.objects[regs.mapping[a]].native; - let buf = new Buffer(2); - buf.writeUInt16BE(value); - let val = common.extractValue(native.type, native.len, buf, 0); - - if (native.type !== 'string') { - val = (val - native.offset) / native.factor; - val = Math.round(val * options.config.round) / options.config.round; - } - - adapter.setState(regs.mapping[a], val, true, function (err) { - // analyse if the state could be set (because of permissions) - if (err) adapter.log.error('Can not set state: ' + err); - }); - - regs.values[a] = buf[0]; - regs.values[a + 1] = buf[1]; - } - }); - - modbusServer.on('postWriteMultipleRegistersRequest', function (start, length /* , byteLength*/) { - let regs = device.holdingRegs; - let data = this.getHolding(); - let i = 0; - start = start >> 1; - - if (start < regs.addressLow) { - start = regs.addressLow; - } - - while (i < length && i + start < regs.addressHigh) { - let a = i + start - regs.addressLow; - if (a >= 0 && regs.mapping[a]) { - let native = options.objects[regs.mapping[a]].native; - - let val = common.extractValue(native.type, native.len, data, i + start); - if (native.type !== 'string') { - val = val * native.factor + native.offset; - val = Math.round(val * options.config.round) / options.config.round; - } - adapter.setState(regs.mapping[a], val, true, function (err) { - // analyse if the state could be set (because of permissions) - if (err) adapter.log.error('Can not set state: ' + err); - }); - for (let k = 0; k < native.len * 2; k++) { - regs.values[a * 2 + k] = data.readUInt8(start * 2 + k); - } - i += native.len; - } else { - i++; - } - } - }); - - modbusServer.on('connection', client => { - let list = getListOfClients(modbusServer.getClients()); - adapter.log.debug('+ Clients connected: ' + list); - adapter.setState('info.connection', list, true); - }).on('close', client => { - let list = getListOfClients(modbusServer.getClients()); - adapter.log.debug('- Client connected: ' + list); - adapter.setState('info.connection', list, true); - }).on('error', err => { - let list = getListOfClients(modbusServer.getClients()); - adapter.log.info('- Clients connected: ' + list); - adapter.setState('info.connection', list, true); - adapter.log.warn('Error on connection: ' + JSON.stringify(err)); - }); - } - }; - - this.close = () => { - if (modbusServer) { - try { - modbusServer.close(); - } catch (e) { - - } - modbusServer = null; - } - }; - - this._initValues = (states, regs) => { - // build ready arrays - for (let i = 0; regs.fullIds.length > i; i++) { - let id = regs.fullIds[i]; - if (states[id] && states[id].val !== undefined) { - this.write(id, states[id]); - } else { - adapter.setState(id, 0, true, err => { - // analyse if the state could be set (because of permissions) - if (err) adapter.log.error('Can not set state ' + id + ': ' + err); - }); - } - } - // fill with 0 empty values - for (let i = 0; i < regs.values.length; i++) { - if (regs.values[i] === undefined || regs.values[i] === null) { - regs.values[i] = 0; - } else if (typeof regs.values[i] === 'boolean') { - regs.values[i] = regs.values[i] ? 1 : 0; - } else if (typeof regs.values[i] !== 'number') { - regs.values[i] = parseInt(regs.values[i], 10) ? 1 : 0; - } - } - }; - - this.initValues = callback => { - // read all states - adapter.getStates('*', (err, states) => { - this._initValues(states, device.disInputs); - this._initValues(states, device.coils); - this._initValues(states, device.inputRegs); - this._initValues(states, device.holdingRegs); - callback(); - }); - }; - - (function _constructor() { - adapter.setState('info.connection', 0, true); - - this.initValues(() => { - delayStart = false; - adapter.log.debug('Slave ready to start'); - this.start(); - }); - }.bind(this))(); - - return this; -} - -module.exports = Slave; \ No newline at end of file