Skip to content
Juanmabs22 edited this page Jun 19, 2019 · 3 revisions

Examples - server


ModbusTCP Server
// create an empty modbus client
var ModbusRTU = require("modbus-serial");
var vector = {
  getInputRegister: function(addr, unitID) { return addr; },
  getHoldingRegister: function(addr, unitID) { return addr + 8000; },
  getCoil: function(addr, unitID) { return (addr % 2) === 0; },
  setRegister: function(addr, value, unitID) { console.log('set register', addr, value, unitID); return; },
  setCoil: function(addr, value, unitID) { console.log('set coil', addr, value, unitID); return; }
};

// set the server to answer for modbus requests
console.log('ModbusTCP listening on modbus://0.0.0.0:502');
var serverTCP = new ModbusRTU.ServerTCP(vector, {host: '0.0.0.0'});

ModbusRTU Server - managing multiples functions at the same time

You need a way to have a mutex, semaphore or something to make your RTU only running at one time. You need a async queue.

Then, create a queue with only 1 worker, if there only one worker using the rtu none else will use it => Safethread! noCRCproblems!

const queue = require('async/queue');
let queueRTU = queue(this.runner.bind(this), 1);

then, create the function to handle the jobs on the worker:

async runner(thingToProcess) {
    [Here you will use the rtu]
}

To do it simple, the runner will receive a promise+action, so the runner will run the action and resolve the promise when ends, the runner won't know whats is doing, but we want only that the worker make only one thing at time:

async runner(magicPromise) {
    try{
        magicPromise.resolve(await magicPromise.action());
    } catch (error) {
        magicPromise.reject(error);
    }
    // callback(); // You won't use callback due the async enviroment
}

next, you will create the jobs to run the worker, I mean, the magicPromise:

    const runInSafeThread = (action) => {
        let resolve, reject;
        let magicPromise = new Promise((res, rej) => {
            resolve = res;
            reject = rej;
        });
        magicPromise.action= action;
        magicPromise.resolve = resolve;
        magicPromise.reject  = reject;

        queueRTU.push(magicPromise); // Here we send the magicPromise to be processed by the worker

        return magicPromise;
    };

Tha magicPromises combines a Promise with a function to send all together to the worker to the worker would be able to run the action and notify us when finish the action.

You have now the environment! Now you only have to send actions.

let result = await runInSafeThread (async () => await rtuClientIniciazated.readInputRegisters(14, 1));
console.log(result);

Check that we await 2 times:

  • the awaited readInputRegisters is to return the data read
  • the first await is to wait until the worker run the action send and get the result.

I recommend run only the modbus-serial functions inside runInSafeThread to ensure good performance.

⚠ If you still receiving CRC errors or timeout check all your functions has await.

Full code:

const queue = require('async/queue');
let queueRTU = queue(this.runner.bind(this), 1);

async runner(magicPromise) {
    try{
        magicPromise.resolve(await magicPromise.action());
    } catch (error) {
        magicPromise.reject(error);
    }
    // callback(); // You won't use callback due async enviroment
}


const runInSafeThread = (action) => {
    let resolve, reject;
    let magicPromise = new Promise((res, rej) => {
        resolve = res;
        reject = rej;
    });
    magicPromise.action= action;
    magicPromise.resolve = resolve;
    magicPromise.reject  = reject;

    queueRTU.push(magicPromise); // Here we send the magicPromise to be processed by the worker

    return magicPromise;
};

let result = await runInSafeThread(async () => await rtuClientIniciazated.readInputRegisters(14, 1));
console.log(result);