Skip to content

Modbus Device Service Component

The Modbus Device Service component provides communication and control with devices supporting the Modbus protocol. Modbus supports communication using either RS485 serial or Ethernet connections. These are referred to as RTU and TCP/IP respectively.

Using the device service with Modbus RTU differs subtly from using it for Modbus TCP connections, we will cover the differences on this page.

Key Features

The Modbus Device Service supports the following key features:

  • Read. Data can be read from each primary table using the appropriate function code:
Primary Table Modbus Function
Coils 1
Discrete Inputs 2
Holding Registers 3
Input Registers 4
  • Write. Data can be written to each writable primary table using the appropriate function code:
Primary Table Modbus Function
Coils (Single Coil) 5
Holding Registers (Single Register) 6
Coils (Multiple Coils) 15
Holding Registers (Multiple Registers) 16
  • Support for Modbus RTU connection types
  • Support for Modbus TCP/IP connection types
  • Batch read operation. Read multiple values in a single Modbus call from each primary table, using the function codes seen in the first table above
  • Batch write operation. Write multiple values in a single Modbus call to each writable primary table, using the function codes seen in the second table above

Modbus Device Service Configuration

Note

Since there are no driver-specific configuration options for Modbus, please refer to Device Service Component Configuration for all the relevant core components that will need populated in order to run the Modbus Device Service.

A template of the Modbus Device Service configuration file is provided:

{
  "Library": "libxrt-modbus-device-service.so",
  "Factory": "xrt_modbus_device_service_factory",
  "Name": "modbus",
  "TelemetryTopic": "xrt/devices/modbus/telemetry",
  "RequestTopic": "xrt/devices/modbus/request",
  "ReplyTopic": "xrt/devices/modbus/reply",
  "StateDir": "./deployment/state",
  "ProfileDir": "./deployment/profiles",
  "Scheduler": "sched",
  "Logger": "logger",
  "ThreadPool": "pool",
  "Bus": "bus"
}

Modbus Device Profile

Details on general profile usage can be found on the Device Profiles page.

The following sections will cover how device resources are mapped to Modbus properties.

Required Profile Attributes

Ensure that the following profile attributes are defined in the device profile:

Attribute Description Valid Values
primaryTable Identifies the primary table. The primary table must be one of the following:
  • HOLDING_REGISTERS
  • INPUT_REGISTERS
  • COILS
  • DISCRETE_INPUT
startingAddress The address at which to start reading/writing in the Modbus device's representation of memory Any Int16 value

Once we run a command, device-modbus will know its value type and register type, startingAddress, and register length. This allows it to read or write a value using the Modbus protocol.

Other Profile Attributes

The other (optional) attributes used in a Modbus device resource are described in the following table:

Attribute Description Valid Values
rawtype Defines the binary data read from the Modbus device and uses a value descriptor data type to identify the data type that the user wants to receive Valid string values are as follows:
  • INT16
  • UINT16
isByteSwap Defines whether to swap the byte on reading little-endian data to transform to big-endian format.

The Modbus Device Service uses big-endian format.

If the Modbus device uses little-endian format, set this attribute to true to correctly convert the data.
true, false
isWordSwap Defines whether to use 16-bit segments, also known as words, to re-order the byte sequence with big-endian or little-endian formats

To re-order the byte sequence, set this attribute to true
true, false
boolIndex Retrieves the bool value from the specified bit of a register The default is 0

For HOLDING_REGISTER and INPUT_REGISTERS, the valid range is 0 to 15, inclusive

For COILS and DISCRETE_INPUT, the value is 0
stringEncoding The supported string encoding Valid values are UTF8 or ASCII

Default is UTF8
stringRegisterSize Defines the capacity of the device resource for the string data Valid range is from 1 to 123 , inclusive

Default is 1

For example, to store the "Hello World" string in ASCII encoding, we need 96 bits (12 characters multiplied by 8 bits), so the required stringRegisterSize would be 6 (96 bits divided by 16 bits)

For the read command, the Modbus device reads the data types from the specified startingAddress for the length specified in the stringRegisterSize and parses the binary data to a sting with the encoding specified in stringEncoding

For the write command, the Modbus device checks that the parameter is a valid string in the specified encoding, converts the string to data bytes and writes it back to the register

Data Types

When the device receives a request, it returns a value with a Modbus type. The following table lists the supported Modbus data types, their equivalent XRT data types, the supported read / write abilities, and how many 16-bit registers are used to store the data:

Modbus Data Type XRT Data Type Read/Write Ability Number of 16-bit Registers Used
Bit Boolean RW 1
String String RW Dependant on string encoding
Signed 8-bit Int Int8 RW 1
Unsigned 8-bit Int UInt8 RW 1
Signed 16-bit Int Int16 RW 1
Unsigned 16-bit Int UInt16 RW 1
Signed 32-bit Int Int32 RW 2
Unsigned 32-bit Int UInt32 RW 2
32-bit Float Float32 RW 2
Signed 64-bit Int Int64 RW 4
Unsigned 64-bit Int UInt64 RW 4
64-bit Double Float64 RW 4

Example Device Resources

The following section provides examples of some device resources mapped to Modbus properties.

  • The extract from a device profile shown below reads the 'Current' property, whose unsigned 16-bit int value is found at address 9 of the holding table registers.
Location Description
Primary Table Holding Registers
Starting Address 9
Property Current
Modbus Data Type Unsigned 16-bit Int
XRT Data Type UInt16
Read/Write Access RW
{
  "name": "Current",
  "description": "Average current of all phases",
  "attributes": {
    "primaryTable": "HOLDING_REGISTERS",
    "startingAddress": 9
  },
  "properties": {
    "valueType": "UInt16",
    "readWrite": "RW"
  }
}
  • The extract from a device profile shown below reads the 'Energy' property, whose 32-bit float value is found at address 4001 of the holding registers.
Location Description
Primary Table Holding Registers
Starting Address 4001
Property Energy
Modbus Data Type 32-bit Float
XRT Data Type Float 32
Read/Write Access RW
{
  "name": "Energy",
  "description": "System Total True Energy",
  "attributes": {
    "primaryTable": "HOLDING_REGISTERS",
    "startingAddress": 4001
  },
  "properties": {
    "valueType": "Float32",
    "readWrite": "RW"
  }
}
  • The extract from a device profile shown below reads the 'IsRunning' property, whose boolean value is found at address 1 of the coils.
Location Description
Primary Table Coils
Starting Address 1
boolIndex 0
Property IsRunning
Modbus Data Type Bit value
XRT Data Type Bool
Read/Write Access RW
{
  "name": "IsRunning",
  "description": "Boolean value indicating whether system is running.",
  "attributes": {
    "primaryTable": "COILS",
    "startingAddress": 1,
    "boolIndex": 0
  },
  "properties": {
    "valueType": "Bool",
    "readWrite": "RW"
  }
}
  • The extract from a device profile shown below reads the 'FanSpeedAvg' property, whose 16-bit signed int value is found at address 1000 of the holding registers. This example utilises scaling via the raw type identified. In this case, the value stored in the register will be multiplied by 0.01 to obtain the float 32 value.

    For example, a read value of 2250 would become 22.50. See the Device Profiles page for more information on scaling factors in XRT.

Location Description
Primary Table Holding Registers
Starting Address 1000
Raw Type INT16
Scaling Factor 0.01
Property FanSpeedAvg
Modbus Data Type 32-bit Float
XRT Data Type Float 32
Read/Write Access RW
{
  "name": "FanSpeedAvg",
  "description": "Average fan speed for the system.",
  "attributes": {
    "primaryTable": "HOLDING_REGISTERS",
    "startingAddress": 1000,
    "rawType": "INT16"
  },
  "properties": {
    "valueType": "Float32",
    "readWrite": "RW",
    "scale": 0.01
  }
}

Device Commands

See the Device Profiles page for details on how to define device commands for grouping device resources for fewer requests

Modbus Device Provisioning

The following sections will explain how devices can be statically configured for both Modbus-TCP and Modbus-RTU device services.

Note

For information on dynamic device additions, removals and updates please see the MQTT API Guide.

Modbus Protocol Properties

The available Modbus protocol properties are described in the following table:

Protocol Property Description Valid Values
UnitID The station identifier Values up to 247
Address For Modbus TCP/IP, the IP address or host name

For Modbus RTU, the path to the serial device
When using TCP, a valid IP address

When using RTU, a valid serial address
Port Used for Modbus TCP/IP only

The TCP port of the Modbus device
Any valid port number
BaudRate Used for Modbus RTU only

The baud rate for a serial device

The provided baud rate must match for devices using the same address
Unsigned integer
DataBits Used for Modbus RTU only

The number of bits of data
Valid values are as follows:
  • 5
  • 6
  • 7
  • 8
StopBits Used for Modbus RTU only

The number of stop bits
Valid values are as follows:
  • 1
  • 2
Parity Used for Modbus RTU only

The parity value

Specify N for no parity

Specify E for even parity

Specify O for odd parity
Valid values are as follows:
  • N
  • E
  • O

Modbus-TCP Device Provisioning Example

To provision a Modbus-TCP device, the modbus-tcp protocol must be used along with the relevant protocol properties provided in the table above.

An example of a Modbus-TCP device provision within the devices.json file is provided below:

{
  "modbus-sim": {
    "profileName": "modbus-sim-profile",
    "protocols": {
      "modbus-tcp": {
        "Address": "127.0.0.1",
        "Port": 502,
        "UnitID": 1
      }
    },
    "name": "modbus-sim"
  }
}

Modbus-RTU Device Provisioning Example

To provision a Modbus-RTU device, the modbus-rtu protocol must be used along with some protocol properties:

An example of a Modbus-RTU device is provided below:

{
  "modbus-sim": {
    "profileName": "modbus-sim-profile",
    "protocols": {
      "modbus-rtu": {
        "Address": "/tmp/slave",
        "UnitID": 1,
        "BaudRate": 9600,
        "DataBits": 8,
        "StopBits": 1,
        "Parity": "N"
      }
    },
    "name": "modbus-sim"
  }
}

Modbus Device Service Interaction

For information on how to dynamically execute reads, writes, setting up schedules, and much more, please refer to the MQTT API Guide.

For interactive examples of the Modbus-TCP and Modbus-RTU Device Services refer to the Modbus-TCP XRT Example and Modbus-RTU XRT Example projects. Follow the instructions in that example to demonstrate many features of XRT with the device service running against a Modbus simulator.

Run the Modbus Device Service

Find details on how to run the Modbus Device Service on the Run Device Services page.

Back to top