Skip to content

Commit

Permalink
Added Server example and API section to README.
Browse files Browse the repository at this point in the history
  • Loading branch information
TooTallNate committed Jan 3, 2011
1 parent 7239888 commit 69c94de
Showing 1 changed file with 130 additions and 15 deletions.
145 changes: 130 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,151 @@ RS-485 serial support should be possible with [node-serialport]. I haven't
had a chance to look into it yet.


A MODBUS Request
----------------
A MODBUS Master (Client)
------------------------

You will need to know which _function code_ (defined in the MODBUS specification)
you are invoking on the MODBUS slave. In this example, we'll request to read
from the current values of the first 50 __Input Registers__ on the slave:
You will need to know which _Function Code_ (defined in the MODBUS specification)
you are invoking on the remote MODBUS slave. In this example, we'll request to
read from the current values of the first 50 __Input Registers__ on the slave:

var net = require('net');
var ModbusRequestStack = require('modbus-stack').ModbusRequestStack;
// 'RIR' contains the "Function Code" that we are going to invoke on the remote device
var RIR = require('modbus-stack').FUNCTION_CODES.READ_INPUT_REGISTERS;

// IP and port of the MODBUS slave, default port is 502.
var conn = net.createConnection(502, '10.0.1.50');
// IP and port of the MODBUS slave, default port is 502
var client = require('modbus-stack/client').createClient(502, '10.0.1.50');

var req = new ModbusRequestStack(conn);
req.request(0x04, // Function Code: 4
0, // Start at address 0
50); // Read 50 contiguous registers from 0
// 'req' is an instance of the low-level `ModbusRequestStack` class
var req = client.request(RIR, // Function Code: 4
0, // Start at address 0
50); // Read 50 contiguous registers from 0

// 'response' is emitted after the entire contents of the response has been received.
req.on('response', function(registers) {
// An Array of length 50 filled with Numbers of the current registers.
console.log(registers);
client.end();
});

More to come...

A MODBUS Slave (Server)
-----------------------

`node-modbus-stack` makes it dead simple to create a compliant MODBUS Slave (or Server)
written in pure JavaScript. Here's an example of a server that would respond to the
request above:

var FC = require('modbus-stack').FUNCTION_CODES;

// 'handlers' is an Object with keys containing the "Function Codes" that your MODBUS
// server will handle. Anything function code requested without a handler defined here
// will have the Server transparently respond with Exception Code 1 ("Illegal Function")
var handlers = {};

// Define a handler for "Read Input Registers". We'll just respond with the register
// number requested. In a real-world situation, you'd probably look up these values from
// a database, etc.
handlers[FC.READ_INPUT_REGISTERS] = function(request, response) {
var start = request.startAddress;
var length = request.quantity;

var resp = new Array(length);
for (var i=0; i<length; i++) {
resp[i] = start + i;
}
response.writeResponse(resp);
}

require('modbus-stack/server').createServer(handlers).listen(502);

A "catch-all" function can be passed to `createServer()` instead of a "handlers" object, if you'd
rather have a single callback invoked for _all_ MODBUS requests. Just be sure to call
`writeException()` manually for any "Function Codes" your server isn't going to handle.


API
---

`require('modbus-stack')`

* `FUNCTION_CODES` - _Object_<br>
Contains the defined "Function Codes" as programmer-friendly names that translate into the defined code number.<br>
__Usage:__ `FUNCTION_CODES.READ_COILS → 1`

* `EXCEPTION_CODES` - _Object_<br>
Same as `FUNCTION_CODES`, contains the defined "Exception Codes".<br>
__Usage:__ `EXCEPTION_CODES.ILLEGAL_FUNCTION → 1`

* `ModbusRequestStack` - _Function_<br>
A `StreamStack` subclass that handles the client-side (Master) of the MODBUS protocol.<br>
__Usage:__ `var req = new ModbusRequestStack(stream)`

* `ModbusRequestStack#request(functionCode[, param1, param2, ...], cb)` - _Function_<br>
Writes a MODBUS request to the underlying `Stream` (usually a `net.Stream`). `response` will be
emitted after the slave responds to the request. The first arg is the "Function Code" to request.
Anything after that are parameters specific to each function code. `cb` is an optional callback
to attach to the `response` and `error` events. The function should have the
signature: `function(err, response) {}`.<br>
__Usage:__ `req.request(FC.READ_COILS, 0, 50)`

* `"response" - function(response)` - _Event_<br>
The "response" event is fired after the remote MODBUS slave responds to the `request` previously
sent.

* `"error" - function(error)` - _Event_<br>
The "error" event is fired if the remote MODBUS slave responds with an Exception Code instead of
a successful response code, or if a Function Code is requested in which `node-modbus-stack` hasn't
implemented the proper Function Code parsing logic in `client.js`.

* `ModbusResponseStack` - _Function_<br>
A `StreamStack` implementation to handle the server-side (Slave) of the MODBUS protocol.<br>
__Usage:__ `var res = new ModbusResponseStack(stream)`

* `ModbusResponseStack#writeResponse(param1[, param2, param3, ...])` - _Function_<br>
Writes out the MODBUS response after receiving a `request` event. The parameters given are
dependant on the MODBUS "Function Code" that was requested.<br>
__Usage:__ `res.writeResponse(array) // After receiving a "Read Input Registers" request`

* `ModbusResponseStack#writeException(exceptionCode)` - _Function_<br>
Writes out a MODBUS exception response after receiving a `request` event. `exceptionCode`
should be the desired exception code to respond with. See `EXCEPTION_CODES`.
__Usage:__ `res.writeException(EXCEPTION_CODES.ILLEGAL_FUNCTION)`

* `"request" - function(request)` - _Event_<br>
The "request" event is fired once a remote MODBUS master sends a Function Code request.
`request` is an Object containing interesting properties about the request, like `functionCode`
and any other parameters that go with the desired Function Code.

* `"error" - function(error)` - _Event_<br>
The "error" event is fired if a Function Code is requested in which `node-modbus-stack` hasn't
implemented the proper Function Code parsing logic in `server.js`.

`require('modbus-stack/client')`

* `createClient(port[, host])` - _Client_<br>
Creates and return a new `Client` instance, which is the preferred method of conventional
MODBUS master communication over TCP. The default MODBUS port is __502__.<br>
__Usage:__ `var client = modbusClient.createClient(502, 'example.com')`

* `Client#request(functionCode[, param1, param2, ...], cb)` - _ModbusRequestStack_<br>
Makes a MODBUS request to the remote MODBUS slave. Same as `ModusRequestStack#request()`.<br>
__Usage:__ `var req = client.request(FC.READ_COILS, 0, 10)`

* `Client#end()` - _Function_<br>
Sends a FIN to the remote slave device, closing the TCP connection.
__Usage:__ `client.end()`

`require('modbus-stack/server')`

* `createServer(handlers | callback)` - _Server_<br>
Creates and returns a new `Server` instance, which is used to make MODBUS compliant servers
easily. `handlers` should be an Object containing keys and callbacks of the Function Codes your
server is implementing, or a "catch-all" `callback` function can be passed to invoke for
_every_ MODBUS request, regardless of the Function Code.<br>
__Usage:__ `var server = modbusServer.createServer(handlers)`


[StreamStack]: http://github.com/TooTallNate/node-stream-stack
[node-serialport]: https://github.com/voodootikigod/node-serialport
[ModbusWiki]: http://en.wikipedia.org/wiki/Modbus
[Modbus]: http://www.modbus.org
[Node]: http://nodejs.org

0 comments on commit 69c94de

Please sign in to comment.