DNP3 Slave Driver

The ESF DNP3 Slave Driver implements a DNP3 slave integrated with ESF Driver and Wires/Asset models.

Features

  • The driver manages a local cache whose entries represent DNP3 data points.
  • Support for a subset of DNP3 object types.
  • Support for spontaneous messages.
  • Supports assigning group/variation to be used for static/event data for each point.
  • Support for assigning deadbands to data points in configuration.
  • Supports changing analog/binary output status points using commands.
  • TCP and SSL support
  • UDP support (starting from 2.1.0)

Driver cache

The drive cache can be represented as a key -> value map.

The keys are are (data point index, resource type) pairs, where resource type represents the data point type (binary input, analog input etc)
The values are are information object representations.

The most straightforward way for populating the cache is to define Assets whose channels represent the entries.
More precisely, entries are created by calling the Driver.prepareRead() and/or Driver.registerChannelListener() Java APIs. If the entries are defined through the Web UI by creating Assets, ESF will take care of calling the APIs above.

  • Current cache entry values can be retrieved using READ operations/channels.
  • Cache entry values can be updated using READ_WRITE operations/channels.
  • Cache update events can be notified to applications by registering channel listeners. In terms of Assets, this corresponds to enabling the listen channel parameter.

Driver cache size

The driver allows to define at most 65536 data points per resource type.
The number of data points for each type can be configured using the following global configuration parameters:

  • Binary input count
  • Double bit binary input count
  • Analog input count
  • Counter count
  • Binary output status count
  • Analog output status count

Input cache entries

The entries that represent input data can be retrieved and/or updated locally using all the interfaces that leverage ESF Driver APIs, for example by performing a read or write on an Asset channel.

After the value of an input entry is updated by a framework component, its value will be visible to DNP3 masters.
Updating an input entry value can optionally also trigger sending an unsolicited message to the client.

Output status cache entries

Binary/Analog output status entry values can be retrieved and/or updated locally in the same way as input entries.

Output status entries can also be modified by the DNP3 master through commands. When a command is received, the new value will be written in the cache and retained indefinitely until another command for the same entry is received.

The driver can emit events to framework components just after a command is received. Events can be received on a Wire Graph by ticking the listen flag in Wire Asset configuration or by using the Driver.registerChannelListener() Java APIs.

Commands only cause modifications of the output status data point values. Any side effects of the command need to be managed by external components in an appropriate way for the specific application.

Uninitialized entries

All cache entries are created in an uninitialized state until a value is written to them either by an ESF component or by the DNP3 master.

The behavior of an uninitialized entry is the following:

  • If the value is read by a framework component, an error will be generated reporting that the entry value has not been set yet.

  • If the data point is sent to a DNP3 master, it will report a default value and the offline, restart flags.

Entry lifecycle

As previously said, entries are created by calling the Driver.prepareRead() and/or Driver.registerChannelListener() Java APIs, which is done automatically by the framework if the user creates Asset channels using the web UI.

Every entry is reference counted, calls to Driver.prepareRead() or Driver.registerChannelListener() related to the same (index, resource type) entry key will increase the reference count and calls to PreparedRead.close() and Driver.unregisterChannelListener() will decrease it.

When the reference count reaches 0, the entry will be deleted.

In term of Assets, all channels referring to the same (index, resource type) will refer to the same entry and increase the reference count. If and when all channels referring to the same (index, resource type) are deleted the entry will be removed.

Asset channel configuration contains other parameters besides (index, resource type), (for example static/event group variation). If multiple channels referencing the same entry are defined, it is important that the other parameters are set to same value. If this requirement is not respected, the driver will use one of the provided values for each parameter, which one is undefined.

Cache persistence

Cache entries reside in device RAM only and are not persisted in any way. An ESF restart or gateway reboot will cause all entries to return to the uninitialized state.

UDP Support

Knows issues/limitations

Version 2.1.0 is affected by OpenDNP3 issue https://github.com/dnp3/opendnp3/issues/405.
This can cause connection problems and log flooding if the drivers receives UDP communication related ICMP errors.
Until the issue is fixed upstream, a possible workaround is to filter ICMP error messages using firewall.
This can be done adding the following iptables rules on the gateway, for example by adding them in /etc/sysconfig/iptables:

-A INPUT -p icmp -m icmp --icmp-type port-unreachable -j DROP
-A INPUT -p icmp -m icmp --icmp-type host-unreachable -j DROP

While this should prevent the issue, these rules will cause parsing failures in ESF 6.2.0 and earlier Firewall Service. This will cause the Firewall Web UI to stop working. This will be fixed in ESF 7.0.0.

In order to restore Firewall Web UI operation, the rules above can be removed from /etc/sysconfig/iptables and restart the gateway, this will also remove the workaround.

If possible, similar rules should be instead added to the peer so that it does not send back ICMP errors to the gateway.

Using UDP on Docker will not work if the UDP port is exposed using the -p docker run argument due to port/address translation.

#### Configuration parameter changes

The following global configuration parameters have been changed/added in 2.1.0:

  • The Transport type parameter has been added with the following options

    • TCP (the default)
    • UDP
      Select UDP to enable UDP communication.
  • The Master address parameter must be set to the master hostname/IP address. This parameter is mandatory for UDP communication, it is otherwise ignored.

  • The Master port parameter must be set to the UDP port used by the master. The driver will send packets to this UDP ports and expects this to be used as source port by the master. This parameter is mandatory for UDP communication, it is otherwise ignored.

Channel configuration parameters

Currently the channel configuration is composed of the following parameters:

  • Resource Type: The resource type addressed by the channel, usually a data point type.

  • Index: The index of the data point. The value of this parameter must be less than the cache size for the corresponding data point type set in global driver configuration.

  • Event class: Can be used to assign a per channel event class. If set to DEFAULT, the default event class for the channel data point type from global configuration will be used.

  • Static Variation: Can be used to assign the static variation to be used for the channel. If set to DEFAULT, the default static variation for the channel data point type from global configuration will be used.
    The static variation must be compatible with the data point type.

  • Event Variation: Can be used to assign the event variation to be used for the channel. If set to DEFAULT, the default event variation for the channel data point type from global configuration will be used.
    The event variation must be compatible with the data point type.

  • Deadband: Can be used to assign a numeric deadband to the channel. If not set, deadbanding for the channel will be disabled.

Supported types

The driver currently supports the following data point types:

  • Binary input:

    Supported static variations:

    GroupVariation
    11
    12

    Supported event variations:

    GroupVariation
    21
    22
    23
  • Double bit binary input

    Supported static variations:

    GroupVariation
    32

    Supported event variations:

    GroupVariation
    41
    42
    43
  • Analog input

    Supported static variations:

    GroupVariation
    301
    302
    303
    304
    305
    306

    Supported event variations:

    GroupVariation
    321
    322
    323
    324
    325
    326
    327
    328
  • Counter

    Supported static variations:

    GroupVariation
    201
    202
    205
    206

    Supported event variations:

    GroupVariation
    221
    222
    225
    226
  • Binary output status

    Supported static variations:

    GroupVariation
    102

    Supported event variations:

    GroupVariation
    111
    112
  • Analog output status

    Supported static variations:

    GroupVariation
    401
    402
    403
    404

    Supported event variations:

    GroupVariation
    421
    422
    423
    424
    425
    426
    427
    428

Mapping DNP3 types and Driver/Wires types

The Driver, Wires and Asset models support the following types, that refer to the corresponding Java types.

  • BOOLEAN
  • BYTE_ARRAY
  • DOUBLE
  • INTEGER
  • LONG
  • FLOAT
  • STRING

These types are used in interactions between the Driver and the other ESF components, like the Wire Graph.

  • The numeric types allow to encode the "main" value of the information objects.

  • The STRING type allows to produce a Json representation of the information objects, containing all of its fields (e.g. value, timestamp, quality bits, etc).
    The current version of the driver only supports this type for reads from the cache and events sent to the framework, currently it is not possible to use it for updating a cache entry.

    This driver uses the same JSON format as DNP3 master driver, please refer to master driver documentation for more details.

  • The BYTE_ARRAY type is not currently supported by the Driver.

The applicable types for each information object type are described below:

Binary inputs
  • BOOLEAN: Encodes the data point value

  • STRING: JSON representation

Double bit binary input
  • INTEGER, LONG, DOUBLE, FLOAT: Encode the current data point value in the following way (available for reads and writes):

    Numeric valueState
    0INTERMEDIATE
    1DETERMINED_OFF
    2DETERMINED_ON
    otherINDETERMINATE
  • STRING: JSON representation (available for reads)

Analog input
  • INTEGER, LONG, DOUBLE, FLOAT: Encode the data point value (available for reads and writes).

  • STRING: JSON representation (available for reads).

Counter
  • INTEGER, LONG, DOUBLE, FLOAT: Encode the data point value (available for reads and writes).

  • STRING: JSON representation (available for reads).

Binary output status
  • BOOLEAN: Encodes the data point value (available for reads and writes).

  • STRING: JSON representation (available for reads).

Analog output status
  • INTEGER, LONG, DOUBLE, FLOAT: Encode the data point value (available for reads and writes).

  • STRING: JSON representation (available for reads).

Command handling

The driver allows to update the Binary output status and Analog output points by the DNP3 master through commands.

The reception of a command causes the generation of an event reporting the received value. Events can be received by framework components using the ChannelListener APIs and can be emitted by WireAsset components if the listen flag is selected in channel configuration.

The updated value is also stored in the corresponding cache entry and can be retrieved by framework components using reads.

Binary output status

Binary output status value can be set using CROB commands, all command fields except the control code are currently ignored. The control code that sets the data point in the on and off state is defined by the following global configuration parameters:

  • Binary output status on control code
  • Binary output status off control code

Analog output status

Analog output status values can be set using the following commands:

  • 32 bit analog output block command (Group 41 Variation 1).
  • 16 bit analog output block command (Group 41 Variation 2).
  • 32 bit floating point output block command (Group 41 Variation 3).
  • 64 bit floating point output block command (Group 41 Variation 4).

Clock synchronization

The driver supports the clock synchronization command that can be used to adjust the timestamps contained in time-tagged information objects.

Timestamps in time-tagged information objects are obtained from server clock.

Server clock behavior is the following:

  • It is initialized from system time when the driver starts.
  • It is based on a monotonic clock provided by the java.lang.System.nanoTime() Java function.
    • A clock synchronization command does not affect device system time but only server time.
  • If no clock sync is received for a time interval equal to Expected clock sync interval seconds global configuration parameter value, the driver will se the need time IIN flag.

Note about floating point values
The driver currently does not support denormal floating point values, it is recommended to avoid using such values if possible. Denormal floating point values received from the framework will be clamped to 0 by the driver.