Modbus commands within node.js - node.js

I'm new here and try to build my webaplication with node.js to read and write modbus data from a door operator.
So far I have successfully used modbus-serial package to send and receive data with function code 3 and 16.
var ModbusRTU = require("modbus-serial");
var client = new ModbusRTU();
client.connectRTUBuffered("/dev/ttyUSB0", { baudRate : 9600, dataBits : 8, stopBits : 1, parity : "none", });
client.setID(2);
socket.on('op_mode', function (data, err) {
if (err){
console.log(err);
} else {
console.log('op_mode : ' + data);
client.writeRegisters(20, [data, 0]); //data is a number between 1 and 6
}
});
This represents the equivalent of typing "2 16 0 20 0 2 4 0 2 0 0" into Realterm on Windows.
With "2 3 0 20 0 2" I'm able to read data with Realterm. An the equivalent in node.js is:
client.readHoldingRegisters(20, 2, function(err, data) {
if (err){
console.log(err);
} else {
console.log('Reg 20: ' + data.data[0]);
}
});
Now I need to send the command "2 100 252 249 0 0" with node.js which I don't know how to do as the function code 100 is not present. The same command in Realterm is working fine.
For me it would also be ok to use the SerialPort package but need some help to get the code right to receive an answer from my operator.
Thanks in advance.
Additional information from 08.02.2021
Message information from documentation:
Slave address Byte 0 = 2
Function code Byte 1 = 100
Byte 2 = 252
Byte 3 = 249
Byte 4 = 0
Byte 5 = 0
Modbus16 CRC must be added. Response has the same structure.

Related

Fltk channel receiver misses some messages

I create an fltk window with a button. When clicked, the button spawns a thread with 10 iterations inside. Each iteration sends a message to the channel. With println!() everything works fine, but if I delete it - the channel starts skipping some messages.
[dependencies]
fltk = { version="1.2.23", features=["fltk-bundled"] }
fltk-evented = "0.1"
use fltk::{prelude::*, *};
use std::{cell::RefCell, rc::Rc, thread};
fn main() {
//create channel
let (mainSender, mainReceiver) = app::channel::<i32>();
//create application, window, button
let mainApp = app::App::default();
let mut win = window::Window::default().with_size(500, 500);
let mut btn = button::Button::new(20, 20, 100, 40, "START");
win.end();
win.show();
let mainSenderClone = mainSender.clone();
btn.handle(move |thisBtn, evt| match evt {
//btn event handler
enums::Event::Push => {
//click event
thread::spawn(move || {
//create thread
let mut cnt = 0; //10 iterations
while (cnt < 10) {
mainSenderClone.send(cnt);
//println!("sent_from_thread: {}",cnt); - uncommenting this fixes the situation
cnt += 1;
}
});
true //event handled
}
_ => false, //ignore other events
});
//start listening
while mainApp.wait() {
if let Some(msg) = mainReceiver.recv() {
println!("RECEIVED: {}", msg);
}
}
}
The output (without println!() in the thread):
RECEIVED: 1
RECEIVED: 3
RECEIVED: 5
RECEIVED: 7
RECEIVED: 9
With println!():
sent_from_thread: 0
RECEIVED: 0
sent_from_thread: 1
RECEIVED: 1
sent_from_thread: 2
RECEIVED: 2
sent_from_thread: 3
RECEIVED: 3
sent_from_thread: 4
RECEIVED: 4
sent_from_thread: 5
RECEIVED: 5
sent_from_thread: 6
RECEIVED: 6
sent_from_thread: 7
RECEIVED: 7
sent_from_thread: 8
RECEIVED: 8
sent_from_thread: 9
RECEIVED: 9
So, after few days of learning magic, I decided to do "cargo update + build" and then everything started working properly.
I still don't quite understand what was that and how did the previous downloaded dependencies get corrupted, but.. yeah, updating fixed it
Another question, I still dont get why sometimes the channel receives all the 10 messages immediately, and sometimes 0123 [1-2 seconds pause] 456789. But I think I will eventually find it out
Thanks to everyone who took my code and tested it, especially #denys-séguret, #joe-jingyu

Why fs.readfile benchmark times are very different from crypto.pbkdf2?

I'm trying to understand how Nodejs uses libuv threadpool. Turns out there are some modules that uses this threadpool like fs and crypto so I tried this :
const crypto = require("crypto")
const start = Date.now()
for (let i = 0; i < 5; i++) {
crypto.pbkdf2('a', 'b', 100000, 512, 'sha512', () => {
console.log(`${i + 1}: ${Date.now() - start}`)
})
}
the results were :
1: 1178
2: 1249
3: 1337
4: 1344
5: 2278
And that was expected. The default threadpool size is 4, so 4 hashes will finish almost at the same time and the fifth will wait.
But when I do the same thing with fs.readfile() :
const start = Date.now()
const fs = require('fs')
for (let i = 0; i < 5; i++) {
fs.readFile('./test.txt', () => {
console.log(`${i + 1} : ${Date.now() - start}`)
})
}
I get this:
1 : 7
2 : 20
3 : 20
4 : 20
5 : 21
There is always one that finishes first and the others finish around the same time. I tried reading the file just twice, the same thing happens one will finish first the second after. I also tried reading it 10 times, same thing. Why is this happening
Edit:
test.txt is just 5 bytes
I'm using a quad-core laptop running windows 10

NodeJs tcp socket receive chunk

const net = require('net')
const sockets = []
server.on('connection', sock => {
log("tcp_server", "info", `Connected at ${sock.remoteAddress}:${sock.remotePort}`)
sockets.push(sock);
// Write the data back to all the connected, the client will receive it as data from the server
sockets.forEach((sock, index, array) => {
})
sock.on('data', data => {
})
// Add a 'close' event handler to this instance of socket
sock.on('close', data => {
}) // end sock.on
})
server.listen(conf.port, conf.serverHost, () => {
const address = server.address()
const port = address.port
const family = address.family
const ipaddr = address.address
log("tcp_server", "info", 'Server is listening at port ' + port)
log("tcp_server", "info", 'Server ip :' + ipaddr)
log("tcp_server", "info", 'Server is IP4/IP6 : ' + family)
})
this is my socket tcp server
and i faced problem with receive chunk data in c# its easy to receive every chunk if i know the size of it
and i can control how much byte i want to receive every time
now in NodeJs i can get the buffer length by get first 5 byte
and then get the size of the message
var size = (buff[1] << 24) | (buff[2] << 16) | (buff[3] << 8) | buff[4];
i tried this simple code for get the chunk data and process it
first i define a Buffer in top
var mybuffer = Buffer.alloc(30);
var length = 0;
sock.on('data', data => {
data.copy(mybuffer, length , 0, data.length); //copy buffer to mybuffer
length += data.length;
//now check if my length is 5 or greater i can determine the buffer size i sent
size = (buff[1] << 24) | (buff[2] << 16) | (buff[3] << 8) | buff[4];
//now need to continue receive until i reach (size - length) = total bytes i sent
})
this what i tried for receive all the chunk but still need more work
any idea how to receive all data depend on size i sent on first 5 bytes of every message
I found this code easysocket! similar to what i want i just made simple edit to the code and its work like charm

Best practice for seperating Node TCP stream into packets?

I'm using Node's TCP client for a real-time backend for my game, which communicates in a fixed-length protocol. For example,
0x00 - Connection Request
int32 Identifier
4 bytes long
0x01 - Position Update
int32 positionx
int32 positiony
8 bytes long
Of course, Node works like this
socket.on("data", (data) => {
// Arbitary buffer of bytes
})
I only want to process packets one at a time once they've been recieved in full, but what's the best way to A: continue adding to a buffer until the full packet is recieved and B: make sure not to include the data of a second packet in the first one
This is how I solved it!
function readData(data, socket) {
console.log("Read chunk of data " + data.length + " bytes long")
while (data.length > 0) {
if (expectsNewPacket) {
packetBuffer = new Buffer(0)
currentPacketInfo = getPacketInformationFromHeader(data)
data = currentPacketInfo.slicedData
console.log("New packet: ident " + currentPacketInfo.ident + ", length: " + currentPacketInfo.length)
expectedLengthRemaining = currentPacketInfo.length
expectsNewPacket = false
}
// If the data is more than the rest of the packet, just concat the rest of the packet and remove it from our block
if (data.length >= expectedLengthRemaining) {
packetBuffer = Buffer.concat([packetBuffer, data.slice(0, expectedLengthRemaining)])
data = data.slice(expectedLengthRemaining)
processPacket(packetBuffer, socket)
expectsNewPacket = true
} else {
// Or if the data length is less than what we need, just add all that we can and we'll add more later
packetBuffer = Buffer.concat([packetBuffer, data.slice(0, data.length)])
data = data.slice(data.length)
}
}
}

Architecture of code using node js

I am having problems with my code architecture and am looking for advice. I am sending multiple read request to a server via udp and printing the read response out. An example of how the request and response look are below. I am getting the response back as one large hex string starting at 0008.. I need a way for the code to know how many addresses were sent to be read and what data size was requested and take that into account on printing out the data. Since the data size can change, I can not just split the string up using a definite value. I am not looking for actual code but rather just some ideas on how one could tackle this.
Request
00 06 - Opcode
00 00 - Block #
02 - Count
34 97 00 20 - Address 1
04 00 - Data Size 1 (bytes)
30 97 00 20 - Address 2
01 00 - Data Size 2 (bytes)
Response- 00080001e60300009
00 08 - Opcode
00 01 - Block #
e6 03 00 00 - Data 1
09 - Data 2
What I am printing right now- e603000009
How I want it printed - Address 1 = e6030000
Address 2 = 09 ...
Address 3 = 00 00
etc.
(it would know what it is a new data by the data size that was requested and the # of addresses that were requested)
Part of code where I am sending a read request and emitting it to html
app.post('/output3', function(req, res){
res.sendFile(__dirname + '/upload3.html');
//Define the host and port values of UDP
var HOST= '192.168.0.136';
var PORT= 69;
var io = require('socket.io')(http);
//Mulitple parameters
//setInterval will send message constantly.
var client= dgram.createSocket('udp4');
var counter = 0;
//array for addresses
var address=[];
//array for size
var size=[];
//iterate through all addresses and convert to little endian
for (var i=0; i<req.body.address.length; i++) {
var n= req.body.address[i];
var s = n.toString(16).match(/.{1,2}/g);
address[i]= s.reverse().join("").toString(16); // ==> "0x985c0020" (= 2556166176)
}
//iterate through all size and make hex strings and little endian
for (var i=0; i<req.body.size.length; i++) {
function pad(number, length) {
var my_string = '' + number;
while (my_string.length < length) {
my_string = '0' + my_string;
}
return my_string;
}
var n2= pad(req.body.size[i], 4);
var s2 = n2.toString(16).match(/.{1,2}/g);
size[i]= s2.reverse().join("").toString(16);
}
//empty string to add address and size together
var x='';
for (var i=0; i<req.body.address.length; i++) {
x += address[i]+size[i];
}
console.log(req.body.size);
var mrq= read(x);
//Open listener to recieve intial message and print in to webpage
io.on('connection', function(socket){
var mrq= read(x);
io.emit('mrq', mrq);
});
function read() {
// Memory Read Request is a 16-bit word with a value of 6
var message = '0006'
// Block number is a 16-bit word that we will always set to 0
message += '0000'
// Count is variable, and calculated by the size of the parameter list
message += '02'
for (var i=0; i < arguments.length; i++) {
message += arguments[i];
}
return message;
}
var message = new Buffer(mrq, 'hex');
counter++;
var loop= setInterval(function () {
//Sends packets to UDP and setInterval sends packets again for specific time
client.send(message, 0, message.length, PORT, HOST, function (err, bytes) {
if (err) throw err;
});
if (counter === 1000000000000000) {
clearInterval(loop);
}
}, 1/50);
//Open listener to recieve intial message and print in to webpage
io.on('connection', function(socket){
client.on('message', function( message, rinfo ){
//hex string
var temp = message.readUIntBE(0, 2);
//console.log(message.toString(16));
io.emit('temp', temp);
});
});
Showing your current code would help us answer this better.
but in general, the way would be to use a write stream and push your string out in chunks, rather than as a whole block.

Resources