jsmodbus
Version:
Implementation for the Serial/TCP Modbus protocol.
161 lines (127 loc) • 4.42 kB
JavaScript
const ModbusRequestBody = require('./request-body.js')
/** Write Multiple Coils Request Body
* @extends ModbusRequestBody
*/
class WriteMultipleCoilsRequestBody extends ModbusRequestBody {
static fromBuffer (buffer) {
try {
const fc = buffer.readUInt8(0)
if (fc !== 0x0F) {
return null
}
const address = buffer.readUInt16BE(1)
const quantity = buffer.readUInt16BE(3)
const numberOfBytes = buffer.readUInt8(5)
const values = buffer.slice(6, 6 + numberOfBytes)
return new WriteMultipleCoilsRequestBody(address, values, quantity)
} catch (e) {
return null
}
}
/** Create a new Write Multiple Coils Request Body.
* @param {Number} address Write address.
* @param {Array|Buffer} values Values to be written. Either a Array of Boolean values or a Buffer.
* @param {Number} quantity In case of values being a Buffer, specify the number of coils that needs to be written.
* @throws {InvalidStartAddressException} When address is larger than 0xFFFF.
* @throws {InvalidArraySizeException}
* @throws {InvalidBufferSizeException}
*/
constructor (address, values, quantity) {
super(0x0F)
if (address > 0xFFFF) {
throw new Error('InvalidStartAddress')
}
if (Array.isArray(values) && values.length > 0x07b0 * 8) {
throw new Error('InvalidArraySize')
}
if (values instanceof Buffer && values.length > 0x07b0) {
throw new Error('InvalidBufferSize')
}
if (values instanceof Buffer && (values.length * 8) < quantity) {
throw new Error('InvalidBufferSize')
}
this._address = address
this._values = values
this._quantity = quantity || values.length
this._numberOfBytes = Math.ceil(this._quantity / 8)
if (this._values instanceof Buffer) {
this._valuesAsBuffer = this._values
this._byteCount = Math.ceil(this._quantity / 8) + 6
this._valuesAsArray = []
for (let i = 0; i < this._quantity; i += 1) {
const pos = i % 8
const curByteIdx = Math.floor(i / 8)
const curByte = this._values.readUInt8(curByteIdx)
this._valuesAsArray.push((curByte & Math.pow(2, pos)) > 0)
}
}
if (this._values instanceof Array) {
this._byteCount = Math.ceil(this._values.length / 8) + 6
this._valuesAsArray = this._values
const len = Math.min(1968, this._values.length)
let curByte = 0
let curByteIdx = 0
let cntr = 0
const bytes = Buffer.allocUnsafe(this._numberOfBytes)
for (let i = 0; i < len; i += 1) {
curByte += this._values[i] ? Math.pow(2, cntr) : 0
cntr = (cntr + 1) % 8
if (cntr === 0 || i === len - 1) {
bytes.writeUInt8(curByte, curByteIdx)
curByteIdx = curByteIdx + 1
curByte = 0
}
}
this._valuesAsBuffer = bytes
}
}
/** Address to be written to. */
get address () {
return this._address
}
/** Values */
get values () {
return this._values
}
get valuesAsArray () {
return this._valuesAsArray
}
get valuesAsBuffer () {
return this._valuesAsBuffer
}
/** Quantity of coils */
get quantity () {
return this._quantity
}
get byteCount () {
return this._byteCount
}
get numberOfBytes () {
return this._numberOfBytes
}
get name () {
return 'WriteMultipleCoils'
}
createPayload () {
if (this._values instanceof Buffer) {
const payload = Buffer.alloc(this._byteCount)
payload.writeUInt8(this._fc, 0) // function code
payload.writeUInt16BE(this._address, 1) // start address
payload.writeUInt16BE(this._quantity, 3) // quantity of coils
payload.writeUInt8(this._numberOfBytes, 5) // byte count
this._values.copy(payload, 6, 0, this._byteCount) // values
return payload
} else if (this._values instanceof Array) {
const len = Math.min(1968, this._values.length)
const payload = Buffer.alloc(6 + this._numberOfBytes)
const bytes = this._valuesAsBuffer
payload.writeUInt8(this._fc, 0) // function code
payload.writeUInt16BE(this._address, 1) // start address
payload.writeUInt16BE(len, 3) // quantity of coils
payload.writeUInt8(this._numberOfBytes, 5) // byte count
bytes.copy(payload, 6) // values
return payload
}
}
}
module.exports = WriteMultipleCoilsRequestBody