Modbus Client

The Modbus TCP client is an Ethernet implementation of the widely supported, widely used Modbus protocol. The Modbus client is designed in Lua and utilizes the Barracuda App Server socket API. The Modbus client enables business logic, implemented in the Lua scripting language, to communicate with Modbus TCP servers. The Modbus client can also be used for bridging Modbus with protocols such as HTTP, WebSockets, SMQ, MQTT, etc.

Conversion between Modbus and Lua types

Modbus supports bit values and 16 bit words. Bit values are converted to/from Lua boolean values. Word values are converted to/from Lua numbers. Lua can store both integer and floating point values in the number type.

The Modbus client supports additional types that enable the conversion of types to and from the Modbus 16 bit word value. The following additional types are supported: dword (4 bytes), float (4 bytes), double (8 bytes) and string (raw data). The length parameter is automatically adjusted to/from the Modbus word value. For example, requesting the Modbus client to read 4 'double' values from the server makes the Modbus client send a request for reading 4*8 word values. Writing a 5 byte string value (raw data) sends 3 word values, where the last byte in the last word is zero padded. Note that a Lua string may contain any value and is often used for storing and working with binary data.

Error handling

All functions return a value on success and nil,error on failure. The error code can be any of the socket error codes or one of the Modbus exception codes (number 0x01 to 0x0B).

When in asynchronous transaction mode, all functions return the Modbus transaction number if the Modbus socket write operation succeeds. Any Modbus response exception code will be sent to the asynchronous transaction callback function -- i.e., on error, the callback will receive the arguments: nil,error.

Any type of error will force a disconnect on the TCP connection; thus if any error occurs, a new connection must be established.

Modes of operation

The Modbus client can operate in the three socket modes provided by the Barracuda App Server socket API: blocking, asynchronous, and cosocket mode. In addition, the Modbus client can operate in asynchronous transaction mode.

The default socket blocking mode is useful for Modbus operations performed in an LSP page, where a connection may be opened, a request sent, and where the LSP page waits in blocking mode for the Modbus response. Modbus code, not operating in the context of an LSP page, should preferably operate in cosocket mode or asynchronous transaction mode. When in cosocket mode, it is important to understand the limitations that apply to method socket:read(), which is used by the Modbus stack for receiving Modbus response data.

Asynchronous transaction mode:

The asynchronous transaction mode enables pipelining of Modbus requests and enables multiple requests to be issued without having to wait for the Modbus response.

The Modbus client creates its own cosocket when operating in transaction mode (config option async). When operating in transaction mode, the cosocket waits for TCP messages sent from the Modbus server, parses the response independently from any sent messages, and dispatches the parsed response to the asynchronous transaction callback function provided when the request was initiated.

The Modbus methods do not return the result when operating in transaction mode. Instead, the methods return the Modbus transaction number. The same transaction number is passed into the asynchronous transaction callback function when the server sends the response message.

The callback function receives four arguments, where you are required to use at least two. The following two functions illustrate the data passed into the callback and how the data may be used:

function callback(data, err, transaction, mb) -- if all arguments are used function callback(data, err) -- Minimum set of arguments

Callback function's arguments:

The following example shows how to open a Modbus server connection, send one asynchronous message, and how to close the connection. The purpose with the two assert calls is to further explain the callback function's arguments.

local mb -- The Modbus instance
local transaction -- last sent transaction number

local function mycallback(data, err, _transaction, _mb)
   assert(transaction == _transaction) -- integrity check
   assert(mb == _mb) -- Integrity check
   if data then
      -- data is a table with boolean values
   else
      trace("Failed, error code:", err)
   end
   mb:close() -- Close connection
end

local mbmodule=require"modbus.client"
mb,err = mbmodule.connect("localhost", {async=true})
if mb then
   transaction = mb:rcoil(0, 5, mycallback) -- Initiate request
end

API for Creating a Modbus Client

function connect(addr, opt)

Creates and connects a Modbus client instance:
mb, err=require"mobdbus.client".connect(addr,op)

Modbus Object Methods

method mb:rcoil(addr, len [, onresp])

Read coil(s) (function code 1)

Returns table | nil,err - method 'rcoil' returns a Lua table with boolean (true/false) values on success and nil,err on error.

method mb:wcoil(addr, val[, onresp])

Write single coil (function code 5) or write multiple coils (function code 15)

Returns boolean | nil,err - method 'wcoil' returns true on success and nil,err on error.

method mb:discrete(addr, len[, onresp])

Read discrete input (function code 2)

Returns table | nil,err - method 'discrete' returns a Lua table with boolean (true/false) values on success and nil,err on error.

method mb:rholding(addr, len[, vtype][, onresp])

Read holding register(s) (function code 3)

Returns table | nil,err - method 'rholding' returns a Lua table with values on success and nil,err on error.

method mb:wholding(addr, val[, vtype][, onresp])

Write single register (function code 6) or write multiple registers (function code 16)

Returns boolean | nil,err - method 'wholding' returns true on success and nil,err on error.

method mb:register(addr, len[, vtype][, onresp])

Read input register(s) (function code 4)

Returns table | nil,err - method 'register ' returns a Lua table with values on success and nil,err on error.

method mb:readwrite(raddr, rlen, waddr, wval[, vtype][, onresp])

Read/write multiple registers (function code 23). This function code performs a combination of one read operation and one write operation in a single Modbus transaction.

Returns table | nil,err - method 'readwrite' returns a Lua table with values on success and nil,err on error.

method mb:connected()

Returns true if the client is connected to a Modbus server, otherwise false is returned.

method mb:close()

Closes the socket connection. This function also terminates the cosocket if the Modbus client is operating in asynchronous mode. The optional onclose callback will not be called when this method is called.