omron-fins
Advanced tools
Comparing version 0.5.0-beta.3 to 0.5.0-beta.4
@@ -9,3 +9,3 @@ const dgram = require('dgram'); | ||
const FinsAddressUtil = require('./FinsAddressUtil'); | ||
const {dec2bcd, bcd2dec, boolsToBytes, wordsToBytes, mergeData, getKeyName, isInt } = require('./FinsDataUtils'); | ||
const {dec2bcd, bcd2dec, boolsToBytes, wordsToBytes, dwordsToBytes, mergeData, getKeyName, isInt } = require('./FinsDataUtils'); | ||
@@ -92,2 +92,12 @@ const MEMORY_AREA_READ = _getResponseCommandCode(...constants.CommandCodes.MEMORY_AREA_READ); | ||
try { | ||
self.options.maxEventListeners = parseInt(self.options.maxEventListeners || 30); | ||
if(isNaN(self.options.maxEventListeners) || self.options.maxEventListeners <= 0) { | ||
self.options.maxEventListeners = 30; | ||
} | ||
} catch (error) { | ||
self.options.maxEventListeners = 30; | ||
} | ||
this.setMaxListeners(self.options.maxEventListeners); | ||
switch (self.protocol) { | ||
@@ -124,3 +134,3 @@ case 'udp': | ||
self._socket_handler_error = socket_error.bind(self); | ||
self.processReply = _processReply.bind(self); | ||
socket_initialised.call(self); | ||
@@ -317,2 +327,4 @@ }; | ||
dataBytesToWrite = boolsToBytes(data); | ||
} else if (memoryAddress.elementLength === 4) { | ||
dataBytesToWrite = dwordsToBytes(data); | ||
} else { | ||
@@ -322,3 +334,2 @@ dataBytesToWrite = wordsToBytes(data); | ||
const packet = mergeData(headerBytes, command.command, addressData, regsToWrite, dataBytesToWrite); | ||
const buffer = Buffer.from(packet); | ||
@@ -734,3 +745,3 @@ const request = { | ||
if(!cmd) { | ||
_sendError(`commandCode '${commandCode}' not recognised`, callback, { tag: tag }); | ||
_sendError(self, `commandCode '${commandCode}' not recognised`, callback, { tag: tag }); | ||
return null; | ||
@@ -745,3 +756,3 @@ } | ||
if(!providedParam && expectedParam.required) { | ||
_sendError(`Parameter ${index+1} Missing. Expected '${expectedParam.name}'`, callback, { tag: tag }); | ||
_sendError(self, `Parameter ${index+1} Missing. Expected '${expectedParam.name}'`, callback, { tag: tag }); | ||
} | ||
@@ -751,3 +762,3 @@ if(expectedParam.type == null || expectedParam.type == "*" || expectedParam.type == "Any") { | ||
} else if(typeof providedParam !== expectedParam.type) { | ||
_sendError(`Parameter ${index+1} '${expectedParam.name}' incorrect type. Expected type of '${expectedParam.type}'`, callback, { tag: tag }); | ||
_sendError(self, `Parameter ${index+1} '${expectedParam.name}' incorrect type. Expected type of '${expectedParam.type}'`, callback, { tag: tag }); | ||
} | ||
@@ -780,3 +791,3 @@ } | ||
} else { | ||
_sendError(`command not recognised`, callback, { tag: tag }); | ||
_sendError(self, `command not recognised`, callback, { tag: tag }); | ||
return null; | ||
@@ -911,4 +922,4 @@ } | ||
function process(buffer) { | ||
const response = _processReply(buffer, rinfo, self.sequenceManager); | ||
if (response) { | ||
const response = self.processReply(buffer, rinfo); | ||
if (typeof response === "object") { | ||
self.sequenceManager.done(response.sid); //1st, cancel the timeout | ||
@@ -926,2 +937,4 @@ var seq = self.sequenceManager.get(response.sid); //now get the sequence | ||
} | ||
} else if(response === -1){ | ||
//error already sent | ||
} else { | ||
@@ -1034,16 +1047,16 @@ throw new Error("Unable to process the PLC reply"); | ||
function _initialProcessing(buf, sequenceManager, fnName, expectedCmdCode ) { | ||
function _initialProcessing(buf, /** @type {SequenceManager} */sequenceManager, fnName, expectedCmdCode ) { | ||
const sid = buf[9]; | ||
const responseCommandCode = _getResponseCommandCode(buf[10], buf[11]); | ||
const seq = sequenceManager.get(sid); | ||
const seq = sequenceManager && sequenceManager.get(sid); | ||
if(!seq || sid > sequenceManager.maxSID || sid < sequenceManager.minSID) { | ||
throw new Error(`Unexpected SID '${sid}' received`) | ||
throw new Error(`Unexpected SID '${sid}' received`); | ||
} | ||
expectedCmdCode = expectedCmdCode || constants.Commands[responseCommandCode].commandCode | ||
if (responseCommandCode !== expectedCmdCode) { | ||
throw new Error(`Unexpected command code response. Expected '${expectedCmdCode}' received '${responseCommandCode}'`) | ||
throw new Error(`Unexpected command code response. Expected '${expectedCmdCode}' received '${responseCommandCode}'`); | ||
} | ||
fnName = fnName || constants.Commands[responseCommandCode].name; | ||
if (seq.request.command.name !== fnName) { | ||
throw new Error(`Unexpected function type response. Expected '${fnName}' received '${seq.request.command.name}'`) | ||
throw new Error(`Unexpected function type response. Expected '${fnName}' received '${seq.request.command.name}'`); | ||
} | ||
@@ -1242,2 +1255,9 @@ return { | ||
/** | ||
* Process data for Memory Read Area | ||
* @param {Buffer} buf Data returned from PLC | ||
* @param {object} rinfo Remote Host Info | ||
* @param {SequenceManager} sequenceManager | ||
* @returns | ||
*/ | ||
function _processMemoryAreaRead(buf, rinfo, sequenceManager) { | ||
@@ -1247,20 +1267,21 @@ const fnName = "read"; | ||
const {sid, seq, command} = _initialProcessing(buf, sequenceManager, fnName, cmdCode); | ||
let WDs; | ||
let wdValues = false; | ||
let bits; | ||
let bitValues = false; | ||
const bufData = (buf.slice(14, buf.length)); | ||
let plcAddress; | ||
plcAddress = seq.request && seq.request.address; | ||
bitValues = plcAddress && plcAddress.isBitAddress == true; | ||
wdValues = plcAddress && plcAddress.isBitAddress == false; | ||
const plcAddress = seq.request && seq.request.address; | ||
const bitValues = plcAddress && plcAddress.isBitAddress == true; | ||
const dataElementLength = plcAddress && plcAddress.elementLength; | ||
let values; | ||
if (bitValues) { | ||
bits = []; | ||
bits.push(...bufData); | ||
} else if (wdValues) { | ||
WDs = []; | ||
for (var i = 0; i < bufData.length; i += 2) { | ||
WDs.push(bufData.readInt16BE(i)); | ||
values = []; | ||
values.push(...bufData); | ||
} else if (dataElementLength === 4) { | ||
values = []; | ||
for (let i = 0; i < bufData.length; i += 4) { | ||
values.push(bufData.readInt32BE(i)); | ||
} | ||
} else { | ||
values = []; | ||
for (let i = 0; i < bufData.length; i += 2) { | ||
values.push(bufData.readInt16BE(i)); | ||
} | ||
} | ||
@@ -1273,3 +1294,3 @@ | ||
commandDescription: "read", | ||
values: WDs ? WDs : bits, | ||
values: values, | ||
buffer: bufData, | ||
@@ -1279,5 +1300,12 @@ }; | ||
/** | ||
* Process data for Multiple Memory Read Area | ||
* @param {Buffer} buf Data returned from PLC | ||
* @param {object} rinfo Remote Host Info | ||
* @param {SequenceManager} sequenceManager | ||
* @returns | ||
*/ | ||
function _processMultipleMemoryAreaRead(buf, rinfo, sequenceManager) { | ||
const fnName = "read-multiple"; | ||
const cmdCode = "0104" | ||
const fnName = 'read-multiple'; | ||
const cmdCode = '0104' | ||
const {sid, seq, command} = _initialProcessing(buf, sequenceManager, fnName, cmdCode); | ||
@@ -1287,2 +1315,3 @@ const data = []; | ||
const memoryAddressList = [...seq.request.address]; | ||
for (var i = 0; i < bufData.length;) { | ||
@@ -1292,3 +1321,3 @@ const plcAddress = memoryAddressList.shift(); | ||
if (!plcAddress || plcAddress.memoryAreaCode !== memAreaCode) { | ||
throw new Error("unexpected memory address in response"); | ||
throw new Error(`Unexpected memory address in response. Expected '${plcAddress.memoryAreaCode}', Received ${memAreaCode}`); | ||
} | ||
@@ -1298,4 +1327,6 @@ if (plcAddress.isBitAddress) { | ||
i++; // move to the next memory area | ||
} | ||
else { | ||
} else if (plcAddress.elementLength === 4) { | ||
data.push(bufData.readInt32BE(i)); | ||
i = i + 4; // move to the next memory area | ||
} else { | ||
data.push(bufData.readInt16BE(i)); | ||
@@ -1314,50 +1345,62 @@ i = i + 2; // move to the next memory area | ||
function _processReply(buf, rinfo, sequenceManager) { | ||
function _processReply(buf, rinfo) { | ||
const self = this; | ||
let processResult; | ||
const responseCommandCode = _getResponseCommandCode(buf[10], buf[11]); | ||
const processEndCode = _processEndCode(buf[12], buf[13]); | ||
const sid = buf[9]; | ||
const seq = self.sequenceManager.get(sid); | ||
const callback = seq && seq.request && seq.request.callback; | ||
let processResult; | ||
switch (responseCommandCode) { | ||
case CPU_UNIT_STATUS_READ: | ||
processResult = _processStatusRead(buf, rinfo, sequenceManager); | ||
break; | ||
case CPU_UNIT_DATA_READ: | ||
processResult = _processCpuUnitDataRead(buf, rinfo, sequenceManager); | ||
break; | ||
case MEMORY_AREA_READ: | ||
processResult = _processMemoryAreaRead(buf, rinfo, sequenceManager); | ||
break; | ||
case CLOCK_READ: | ||
processResult = _processClockRead(buf, rinfo, sequenceManager); | ||
break; | ||
case MEMORY_AREA_READ_MULTI: | ||
processResult = _processMultipleMemoryAreaRead(buf, rinfo, sequenceManager); | ||
break; | ||
case MEMORY_AREA_WRITE: | ||
case MEMORY_AREA_FILL: | ||
case MEMORY_AREA_TRANSFER: | ||
case STOP: | ||
case RUN: | ||
case CLOCK_WRITE: | ||
processResult = _processDefault(buf, rinfo, sequenceManager); | ||
break; | ||
default: //MEMORY_AREA_WRITE MEMORY_AREA_FILL MEMORY_AREA_TRANSFER | ||
throw new Error(`Unrecognised response code '${responseCommandCode}'`); | ||
try { | ||
switch (responseCommandCode) { | ||
case CPU_UNIT_STATUS_READ: | ||
processResult = _processStatusRead(buf, rinfo, self.sequenceManager); | ||
break; | ||
case CPU_UNIT_DATA_READ: | ||
processResult = _processCpuUnitDataRead(buf, rinfo, self.sequenceManager); | ||
break; | ||
case MEMORY_AREA_READ: | ||
processResult = _processMemoryAreaRead(buf, rinfo, self.sequenceManager); | ||
break; | ||
case CLOCK_READ: | ||
processResult = _processClockRead(buf, rinfo, self.sequenceManager); | ||
break; | ||
case MEMORY_AREA_READ_MULTI: | ||
processResult = _processMultipleMemoryAreaRead(buf, rinfo, self.sequenceManager); | ||
break; | ||
case MEMORY_AREA_WRITE: | ||
case MEMORY_AREA_FILL: | ||
case MEMORY_AREA_TRANSFER: | ||
case STOP: | ||
case RUN: | ||
case CLOCK_WRITE: | ||
processResult = _processDefault(buf, rinfo, self.sequenceManager); | ||
break; | ||
default: | ||
throw new Error(`Unrecognised response code '${responseCommandCode}'`); | ||
} | ||
processResult.endCode = processEndCode.endCode; | ||
processResult.endCodeDescription = processEndCode.endCodeDescription; | ||
processResult.MRES = processEndCode.MRES; | ||
processResult.SRES = processEndCode.SRES; | ||
processResult.NetworkRelayError = processEndCode.NetworkRelayError; | ||
processResult.NonFatalCPUUnitErr = processEndCode.NonFatalCPUUnitErr; | ||
processResult.FatalCPUUnitErr = processEndCode.FatalCPUUnitErr; | ||
return processResult; | ||
} catch (error) { | ||
_sendError(self, error, callback, seq); | ||
return -1; | ||
} | ||
processResult.endCode = processEndCode.endCode; | ||
processResult.endCodeDescription = processEndCode.endCodeDescription; | ||
processResult.MRES = processEndCode.MRES; | ||
processResult.SRES = processEndCode.SRES; | ||
processResult.NetworkRelayError = processEndCode.NetworkRelayError; | ||
processResult.NonFatalCPUUnitErr = processEndCode.NonFatalCPUUnitErr; | ||
processResult.FatalCPUUnitErr = processEndCode.FatalCPUUnitErr; | ||
return processResult; | ||
} | ||
function _sendError(self, message, callback, seq) { | ||
const addrErr = Error(message); | ||
function _sendError(self, error, callback, seq) { | ||
const err = typeof error == "object" && error.message ? error : new Error(error); | ||
if (callback) { | ||
callback(addrErr, seq); | ||
callback(err, seq); | ||
} else if (self) { | ||
self.emit('error', err, seq); | ||
} else { | ||
self.emit('error', addrErr, seq); | ||
throw err | ||
} | ||
@@ -1364,0 +1407,0 @@ } |
@@ -61,3 +61,6 @@ const constants = require('./FinsConstants'); | ||
offsetWD = isInt(offsetWD, 0); | ||
if (decodedMemoryAddress.isBitAddress && decodedMemoryAddress.MemoryArea != "C" && decodedMemoryAddress.MemoryArea != "T") { | ||
if (decodedMemoryAddress.isBitAddress) { | ||
if(decodedMemoryAddress.MemoryArea === "C" || decodedMemoryAddress.MemoryArea === "T") { | ||
return `${decodedMemoryAddress.MemoryArea}${parseInt(decodedMemoryAddress.Address) + offsetWD}.x`; | ||
} | ||
offsetBit = isInt(offsetBit, 0); | ||
@@ -70,3 +73,3 @@ return `${decodedMemoryAddress.MemoryArea}${parseInt(decodedMemoryAddress.Address) + offsetWD}.${decodedMemoryAddress.Bit + offsetBit}`; | ||
function stringToAddress(addressString) { | ||
let re = /([A-Z]*)([0-9]*)\.?([0-9]*)/;//normal address Dxxx Cxxx | ||
let re = /([A-Z]*)([0-9]*)\.?([0-9|x|X]*)/;//normal address CIOnnn CIOnnn.0 Dnnn Cnnn Cnnn Tnnn Cnnn.x Tnnn.x | ||
if (addressString.includes('_')) { | ||
@@ -85,9 +88,19 @@ re = /(.+)_([0-9]*)\.?([0-9]*)/; //handle Ex_ basically E1_ is same as E + 1 up to 15 then E16_=0x60 ~ 0x68 | ||
let _isBit = false; | ||
let _elementLength = 2; | ||
let _bytes = []; | ||
let _memAreaCode; | ||
if(_area == 'T' || _area == 'C') { | ||
_isBit = true; | ||
} | ||
if (_bit && _bit.length) { | ||
if(_bit === 'x' || _bit === 'X') { | ||
_bit = ''; | ||
if(_area == 'T' || _area == 'C') { | ||
_isBit = true; | ||
_elementLength = 1; | ||
} else { | ||
throw new Error(`'${addressString}' is not a valid FINS address. '.x' is only valid for accessing completion bit of C and T addresses`); | ||
} | ||
} else if (_bit && _bit.length) { | ||
_bit = parseInt(_bit); | ||
if(isNaN(_bit)) { | ||
throw new Error(`'${addressString}' is not a valid FINS bit address`); | ||
} | ||
_elementLength = 1; | ||
_isBit = true; | ||
@@ -97,2 +110,5 @@ } else { | ||
} | ||
if(_area == 'IR') { | ||
_elementLength = 4; | ||
} | ||
const decodedMemory = { | ||
@@ -110,3 +126,2 @@ get MemoryArea() { | ||
return _isBit; | ||
//return typeof this.Bit == 'number'; | ||
}, | ||
@@ -119,2 +134,5 @@ get memoryAreaCode() { | ||
}, | ||
get elementLength() { | ||
return _elementLength; | ||
}, | ||
toString: function(){ | ||
@@ -121,0 +139,0 @@ return addressToString(this, 0, 0) |
@@ -203,4 +203,2 @@ | ||
case "C": | ||
case "CNT": | ||
case "CNTR": | ||
return memoryAddress+ 0x8000; | ||
@@ -240,5 +238,4 @@ default: | ||
"EM" : 0x98,//Extended Memories | ||
"TIM" : 0x89,//TIM PV | ||
"CNT" : 0x89,//CNT PV | ||
"CNTR": 0x89,//CNT PV | ||
"T" : 0x89,//TIM PV | ||
"C" : 0x89,//CNT PV | ||
"CIO" : 0xB0,//CIO | ||
@@ -260,5 +257,7 @@ "W" : 0xB1,//Work Area | ||
case "C": | ||
case "CNT": | ||
case "CNTR": | ||
return memoryAddress + 0x8000; | ||
case "IR": | ||
return memoryAddress + 0x0100; | ||
case "DR": | ||
return memoryAddress + 0x0200; | ||
default: | ||
@@ -286,5 +285,5 @@ return memoryAddress; | ||
case "C": | ||
case "CNT": | ||
case "CNTR": | ||
return memoryAddress + 0x0800; | ||
case "A": | ||
return memoryAddress + 0x0B00; | ||
default: | ||
@@ -306,5 +305,4 @@ return memoryAddress; | ||
"EM" : 0x98,//Extended Memories | ||
'TIM' : 0x81,//TIM PV | ||
'CNT' : 0x81,//CNT PV | ||
'CNTR': 0x81,//CNT PV | ||
'T' : 0x81,//TIM PV | ||
'C' : 0x81,//CNT PV | ||
'CIO' : 0x80,//CIO | ||
@@ -323,5 +321,7 @@ 'A' : 0x80,//Auxiliary Bit | ||
case "C": | ||
case "CNT": | ||
case "CNTR": | ||
return memoryAddress + 0x0800; | ||
case "A": | ||
return memoryAddress + 0x0B00; | ||
case "DR": | ||
return memoryAddress + 0x0003; | ||
default: | ||
@@ -328,0 +328,0 @@ return memoryAddress; |
@@ -55,2 +55,17 @@ const allowableTrueValues = { | ||
function _dwordsToBytes (data) { | ||
/** @type {Buffer}*/let buf; | ||
if (data != null) { | ||
let words = data; | ||
if (Array.isArray(words) == false) { | ||
words = [words]; | ||
} | ||
buf = Buffer.alloc(words.length * 4); | ||
for (let i = 0; i < words.length; i++) { | ||
buf.writeUInt32BE(words[i]); | ||
} | ||
} | ||
return buf && buf.toJSON().data; | ||
} | ||
/** | ||
@@ -103,2 +118,3 @@ * Merge variable numbers and arrays of numbers into a flat array | ||
wordsToBytes: _wordsToBytes, | ||
dwordsToBytes: _dwordsToBytes, | ||
mergeData: _mergeData, | ||
@@ -105,0 +121,0 @@ mergeArrays: _mergeArrays, |
{ | ||
"name": "omron-fins", | ||
"description": "Node.js implementation of the Omron FINS protocol", | ||
"version": "0.5.0-beta.3", | ||
"version": "0.5.0-beta.4", | ||
"main": "lib/index.js", | ||
@@ -6,0 +6,0 @@ "author": { |
130724
2621