modbus-serial
Advanced tools
Comparing version 8.0.10 to 8.0.11
@@ -86,2 +86,3 @@ "use strict"; | ||
cl.writeRegisters = _convert(cl.writeFC16); | ||
cl.reportServerID = _convert(cl.writeFC17); | ||
cl.readFileRecords = _convert(cl.writeFC20); | ||
@@ -88,0 +89,0 @@ cl.readDeviceIdentification = _convert(cl.writeFC43); |
70
index.js
@@ -21,2 +21,3 @@ "use strict"; | ||
require("./utils/buffer_bit")(); | ||
const { SerialPort } = require("serialport"); | ||
const crc16 = require("./utils/crc16"); | ||
@@ -207,2 +208,26 @@ const modbusSerialDebug = require("debug")("modbus-serial"); | ||
/** | ||
* Parse the data for a Modbus - | ||
* Report server ID (FC=17) | ||
* | ||
* @param {Buffer} data the data buffer to parse. | ||
* @param {Function} next the function to call next. | ||
*/ | ||
function _readFC17(data, next) { | ||
const length = parseInt(data.readUInt8(2)); | ||
const serverId = parseInt(data.readUInt8(3)); | ||
const running = data.readUInt8(4) === 0xFF; | ||
let additionalData; | ||
if (length > 2) { | ||
additionalData = Buffer.alloc(length - 2); | ||
// copy additional data | ||
data.copy(additionalData, 0, 5, data.length - 2); | ||
} else { | ||
additionalData = Buffer.alloc(0); | ||
} | ||
if (next) | ||
next(null, { serverId: serverId, running: running, additionalData: additionalData }); | ||
} | ||
/** | ||
* Parse the data fro Modbus - | ||
@@ -507,2 +532,5 @@ * Read File Records | ||
break; | ||
case 17: | ||
_readFC17(data, next); | ||
break; | ||
case 20: | ||
@@ -1012,2 +1040,39 @@ _readFC20(data, transaction.next); | ||
/** | ||
* Write a Modbus "Report Server ID" (FC=17) to serial port. | ||
* | ||
* @param {number} address the slave unit address. | ||
* @param {Function} next the function to call next. | ||
*/ | ||
writeFC17(address, da, l, next) { | ||
// check port is actually open before attempting write | ||
if (this.isOpen !== true) { | ||
if (next) next(new PortNotOpenError()); | ||
return; | ||
} | ||
const code = 17; | ||
// set state variables | ||
this._transactions[this._port._transactionIdWrite] = { | ||
nextAddress: address, | ||
nextCode: code, | ||
lengthUnknown: true, | ||
next: next | ||
}; | ||
const codeLength = 2; | ||
const buf = Buffer.alloc(codeLength + 2); // add 2 crc bytes | ||
buf.writeUInt8(address, 0); | ||
buf.writeUInt8(code, 1); | ||
// add crc bytes to buffer | ||
buf.writeUInt16LE(crc16(buf.slice(0, -2)), codeLength); | ||
// write buffer to serial port | ||
_writeBufferToPort.call(this, buf, this._port._transactionIdWrite); | ||
} | ||
/** | ||
* Write mODBUS "Read Device Identification" (FC=20) to serial port | ||
@@ -1100,2 +1165,7 @@ * @param {number} address the slave unit address. | ||
module.exports = ModbusRTU; | ||
module.exports.getPorts = function getPorts() { | ||
return SerialPort.list(); | ||
}; | ||
module.exports.TestPort = require("./ports/testport"); | ||
@@ -1102,0 +1172,0 @@ try { |
import { Socket } from 'net'; | ||
import { TestPort } from "./TestPort"; | ||
import { PortInfo } from '@serialport/bindings-cpp'; | ||
export class ModbusRTU { | ||
@@ -7,2 +9,4 @@ constructor(port?: any); | ||
static getPorts(): Promise<PortInfo[]> | ||
open(callback: Function): void; | ||
@@ -67,2 +71,3 @@ close(callback: Function): void; | ||
readDeviceIdentification(deviceIdCode: number, objectId: number): Promise<ReadDeviceIdentificationResult>; | ||
reportServerID(deviceIdCode: number): Promise<ReportServerIDResult>; | ||
@@ -106,2 +111,8 @@ isOpen: boolean; | ||
export interface ReportServerIDResult { | ||
serverId: number; | ||
running: boolean; | ||
additionalData: Buffer; | ||
} | ||
export interface SerialPortOptions { | ||
@@ -108,0 +119,0 @@ baudRate?: number; |
{ | ||
"name": "modbus-serial", | ||
"version": "8.0.10", | ||
"version": "8.0.11", | ||
"description": "A pure JavaScript implemetation of MODBUS-RTU (Serial and TCP) for NodeJS.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -10,5 +10,7 @@ "use strict"; | ||
const MIN_DATA_LENGTH = 6; | ||
const MIN_WRITE_DATA_LENGTH = 4; | ||
const MAX_BUFFER_LENGTH = 256; | ||
const CRC_LENGTH = 2; | ||
const READ_DEVICE_IDENTIFICATION_FUNCTION_CODE = 43; | ||
const REPORT_SERVER_ID_FUNCTION_CODE = 17; | ||
const LENGTH_UNKNOWN = "unknown"; | ||
@@ -126,2 +128,6 @@ const BITS_TO_NUM_OF_OBJECTS = 7; | ||
} | ||
} else if (functionCode === self._cmd && functionCode === REPORT_SERVER_ID_FUNCTION_CODE) { | ||
const contentLength = self._buffer[i + 2]; | ||
self._emitData(i, contentLength + 5); // length + serverID + status + contentLength + CRC | ||
return; | ||
} else { | ||
@@ -192,4 +198,4 @@ if (functionCode === self._cmd && i + expectedLength <= bufferLength) { | ||
write(data) { | ||
if(data.length < MIN_DATA_LENGTH) { | ||
modbusSerialDebug("expected length of data is to small - minimum is " + MIN_DATA_LENGTH); | ||
if(data.length < MIN_WRITE_DATA_LENGTH) { | ||
modbusSerialDebug("expected length of data is to small - minimum is " + MIN_WRITE_DATA_LENGTH); | ||
return; | ||
@@ -222,2 +228,6 @@ } | ||
break; | ||
case 17: | ||
// response is device specific | ||
this._length = LENGTH_UNKNOWN; | ||
break; | ||
case 43: | ||
@@ -224,0 +234,0 @@ // this function is super special |
@@ -182,2 +182,5 @@ "use strict"; | ||
break; | ||
case 17: | ||
handlers.reportServerID(requestBuffer, vector, unitID, cb); | ||
break; | ||
case 43: | ||
@@ -184,0 +187,0 @@ handlers.handleMEI(requestBuffer, vector, unitID, cb); |
@@ -955,2 +955,58 @@ /* eslint-disable no-var */ | ||
/** | ||
* Function to handle FC17 request. | ||
* | ||
* @param requestBuffer - request Buffer from client | ||
* @param vector - vector of functions for read and write | ||
* @param unitID - Id of the requesting unit | ||
* @param {function} callback - callback to be invoked passing {Buffer} response | ||
* @returns undefined | ||
* @private | ||
*/ | ||
function _handleReportServerID(requestBuffer, vector, unitID, callback) { | ||
if(!vector.reportServerID) { | ||
callback({ modbusErrorCode: 0x01 }); | ||
return; | ||
} | ||
// build answer | ||
const promiseOrValue = vector.reportServerID(unitID); | ||
_handlePromiseOrValue(promiseOrValue, function(err, value) { | ||
if(err) { | ||
callback(err); | ||
return; | ||
} | ||
if (!value) { | ||
callback({ modbusErrorCode: 0x01, msg: "Report Server ID not supported by device" }); | ||
return; | ||
} | ||
if (!value.id || !value.running) { | ||
callback({ modbusErrorCode: 0x04, msg: "Invalid content provided for Report Server ID: " + JSON.stringify(value) }); | ||
return; | ||
} | ||
const id = value.id; | ||
const running = value.running; | ||
const additionalData = value.additionalData; | ||
let contentLength = 2; // serverID + Running | ||
if (additionalData) { | ||
contentLength += additionalData.length; | ||
} | ||
const totalLength = 3 + contentLength + 2; // UnitID + FC + Byte-Count + Content-Length + CRC | ||
let i = 2; | ||
const responseBuffer = Buffer.alloc(totalLength); | ||
i = responseBuffer.writeUInt8(contentLength, i); | ||
i = responseBuffer.writeUInt8(id, i); | ||
if (running === true) { | ||
i = responseBuffer.writeUInt8(0xFF, i); | ||
} else { | ||
i += 1; | ||
} | ||
if (additionalData) { | ||
additionalData.copy(responseBuffer, i); | ||
} | ||
callback(null, responseBuffer); | ||
}); | ||
} | ||
/** | ||
* Function to handle FC43 request. | ||
@@ -1160,3 +1216,4 @@ * | ||
writeMultipleRegisters: _handleWriteMultipleRegisters, | ||
reportServerID: _handleReportServerID, | ||
handleMEI: _handleMEI | ||
}; |
@@ -26,9 +26,9 @@ import * as events from 'events'; | ||
getMultipleInputRegisters?: | ||
((addr: number, length: number, unitID: number, cb: FCallbackVal<number>) => void) | | ||
((addr: number, length: number, unitID: number) => Promise<number>) | | ||
((addr: number, length: number, unitID: number) => number); | ||
((addr: number, length: number, unitID: number, cb: FCallbackVal<number[]>) => void) | | ||
((addr: number, length: number, unitID: number) => Promise<number[]>) | | ||
((addr: number, length: number, unitID: number) => number[]); | ||
getMultipleHoldingRegisters?: | ||
((addr: number, length: number, unitID: number, cb: FCallbackVal<number>) => void) | | ||
((addr: number, length: number, unitID: number) => Promise<number>) | | ||
((addr: number, length: number, unitID: number) => number); | ||
((addr: number, length: number, unitID: number, cb: FCallbackVal<number[]>) => void) | | ||
((addr: number, length: number, unitID: number) => Promise<number[]>) | | ||
((addr: number, length: number, unitID: number) => number[]); | ||
setCoil?: | ||
@@ -42,2 +42,6 @@ ((addr: number, value: boolean, unitID: number, cb: FCallback) => void) | | ||
((addr: number, value: number, unitID: number) => void) | ||
setRegisterArray?: | ||
((addr: number, value: number[], unitID: number, cb: FCallback) => void) | | ||
((addr: number, value: number[], unitID: number) => Promise<void>) | | ||
((addr: number, value: number[], unitID: number) => void); | ||
} | ||
@@ -44,0 +48,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
382795
9881