Skip to content

Commit

Permalink
Update (#401)
Browse files Browse the repository at this point in the history
* link TCP port with existing socket

* add linkTelnet

* add linkTcpRTUBuffered

* worker api

* worker api fixes

* readme
  • Loading branch information
yarosdev authored Apr 5, 2021
1 parent 9d42e84 commit ac2200f
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 15 deletions.
72 changes: 72 additions & 0 deletions worker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#### What can I do with this module ?

This class makes it easy to grab some data from device.
Also, it handles typecast to int32, uint32, float etc.
Type 'double' is not supported by nodejs...

#### Examples

###### Setup client and worker
```` javascript
const client = new ModbusRTU()

client.connect..........

client.setWorkerOptions({
maxConcurrentRequests: 10, // it will send 10 requests or less at a time if any
debug: true
})
````
###### Read some data
``` javascript
// Read 4 values starting from 10009 register.
// Under the hood it will read 8 registers due to int32 type
const response = await client.send({
unit: 1,
fc: 3,
address: 10009,
quantity: 4,
type: 'int32',
});
````
###### Write some data
``` javascript
// Write 2 values to address: 10009 and 10011
const response = await client.send({
unit: 1,
fc: 16,
address: 10009,
value: [10999, 10888],
type: 'int32',
});
````
###### Poll some data
``` javascript
// It will build all READ requests for you in optimal way
const response = await client.poll({
unit: 1,
map: [
{ fc: 3, address: [10011, 10013, 10018], type: "int32" },
{ fc: 3, address: 10003, type: "int32" },
{ fc: 3, address: 10005, type: "int32" },
{ fc: 3, address: 10007, type: "int32" },
{ fc: 3, address: 10009, type: "int32" },
{ fc: 2, address: [1,2,3]},
{ fc: 1, address: [1,2,3]},
{ fc: 1, address: 4},
{ fc: 1, address: 5},
{ fc: 1, address: 6},
{ fc: 3, address: [10001]}, // default type is int16
{ fc: 3, address: [10020, 10023, 10026], type: "float"},
{ fc: 3, address: [10030, 10034], type: "double"}
],
onProgress: (progress, data) => {
console.log(
progress, // Poll progress from 0...1 where 1 means 100%
data, // Data from the current request
);
},
maxChunkSize: 32, // max registers per request
skipErrors: false, // if false it will stop poll and return PARTIAL result
})
```
40 changes: 25 additions & 15 deletions worker/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@ function getByteLength(type) {
return 2;
case "int32":
case "uint32":
return 4;
case "float":
return 6;
case "double":
return 8;
return 4;
default:
throw new Error("Unsupported type");
}
Expand Down Expand Up @@ -96,8 +93,6 @@ Worker.prototype.bufferize = function(data, type) {
buffer.writeUInt32BE(data[i], i * byteLength);
} else if(type === "float") {
buffer.writeFloatBE(data[i], i * byteLength);
} else if(type === "double") {
buffer.writeDoubleBE(data[i], i * byteLength);
}
}

Expand All @@ -119,8 +114,6 @@ Worker.prototype.unbufferize = function(buffer, type) {
data.push(buffer.readUInt32BE(i * byteLength));
} else if(type === "float") {
data.push(buffer.readFloatBE(i * byteLength));
} else if(type === "double") {
data.push(buffer.readDoubleBE(i * byteLength));
}
}

Expand All @@ -141,14 +134,25 @@ Worker.prototype.send = function({ fc, unit, address, value, quantity, arg, type

arg = arg || quantity || value;

if(fc === 1 || fc === 2) {
arg = arg || 1;
}

if(fc === 3 || fc === 4) {
type = type || "int16";
arg = arg * getByteLength(type) / 2;
arg = (arg || 1) * getByteLength(type) / 2;
}

if(fc === 6 || fc === 16) {
type = type || "int16";
arg = this.bufferize(arg, type);
if(fc === 6 && arg.length > 2) {
fc = 16;
}
}

if(fc === 5 && arg instanceof Array && arg.length > 1) {
fc = 15;
}

const id = this.nextId();
Expand Down Expand Up @@ -189,7 +193,7 @@ Worker.prototype.run = function() {

if(typeof request.checkBeforeQueuing === "function") {
if(request.checkBeforeQueuing() === false) {
return this.process();
return this.process(); // Skip current request and go on
}
}

Expand Down Expand Up @@ -228,7 +232,9 @@ Worker.prototype.run = function() {
.catch((error) => {
this._running.delete(request.id);

this.emit("failed", { request, error });
error.request = request;

this.emit("failed", error);

request.reject(error);

Expand All @@ -245,7 +251,7 @@ Worker.prototype._poll_send = function(result, { i, fc, unit, address, arg, item
this.log("scheduled push", "poll #" + result.id, "req #" + i, "#" + id, fc, length, type);

const resolve = function(response) {
const data = items.map((address, index) => [fc, address, response[index]]);
const data = items.map((address, index) => ({ address, value: response[index] }));
result._req += 1;
result.done += 1;
result.data = [...result.data, ...data];
Expand Down Expand Up @@ -275,10 +281,15 @@ Worker.prototype.poll = function({ unit, map, onProgress, maxChunkSize, skipErro
skipErrors = Boolean(skipErrors);
defaultType = defaultType || "int16";

if(unit < 1 || unit > 250 || isNaN(unit) || unit === undefined) {
throw new Error("invalid unit");
}

this.log("poll", `unit=${unit}`, "map size=" + Object.keys(map).length, `maxChunkSize=${maxChunkSize}`, `skipErrors=${skipErrors}`);

const result = {
id: this.nextId(),
unit,
total: 0,
done: 0,
data: [],
Expand Down Expand Up @@ -360,15 +371,14 @@ Worker.prototype.poll = function({ unit, map, onProgress, maxChunkSize, skipErro

result.total = requests.length;

return new Promise(((resolve, reject) => {

return new Promise(((resolve) => {
const check = function() {
if(result._req === result.total) {
result.dt = Date.now() - result.dt;
resolve(result);
} else if(result.error && skipErrors !== true) {
result.dt = Date.now() - result.dt;
reject(result);
resolve(result);
}
};

Expand Down

0 comments on commit ac2200f

Please sign in to comment.