EPICS device support

modbus implements the following standard asyn interfaces:

  • asynUInt32Digital

  • asynInt32

  • asynInt32Array

  • asynInt64

  • asynFloat64

  • asynFloat64Array

  • asynOctet

  • asynCommon

  • asynDrvUser

Because it implements these standard interfaces, EPICS device support is done entirely with the generic EPICS device support provided with asyn itself. There is no special device support provided as part of modbus.

It is necessary to use asyn R4-8 or later, because some minor enhancements were made to asyn to support the features required by modbus.

The following tables document the asyn interfaces used by the EPICS device support.

The drvUser parameter is used by the driver to determine what command is being sent from device support. The default is MODBUS_DATA, which is thus optional in the link specification in device support. If no drvUser field is specified, or if MODBUS_DATA is specified, then the Modbus data type for records using the asynInt32, asynInt64, and asynFloat64 interfaces is the default data type specified in the drvModbusAsynConfigure command. Records can override the default Modbus data type by specifying datatype-specific drvUser field, e.g. BCD_SIGNED, INT16, FLOAT32_LE, etc.

The offset parameter is used to specify the location of the data for a record relative to the starting Modbus address for that driver. This offset is specified in bits for drivers using Modbus functions 1, 2, 5, and 15 that control discrete inputs or coils. For example, if the Modbus function is 2 and the Modbus starting address is 04000, then offset=2 refers to address 04002. For a Koyo PLC the X inputs are at this Modbus starting address for Modbus function 2, so offset=2 is input X2.

If absolute addressing is being used then the offset parameter is an absolute 16-bit Modbus address, and is not relative to the starting Modbus address, which is -1.

The offset is specified in words for drivers using Modbus functions 3, 4, 6 and 16 that address input registers or holding registers. For example, if the Modbus function is set to 6 and the Modbus address is 040600 then offset=2 refers to address 040602. For a Koyo PLC the C control relays are accessed as 16-bit words at this Modbus starting address for Modbus function 6. offset=2 will thus write to the third 16 bit-word, which is coils C40-C57.

For 32-bit or 64-bit data types (INT32_LE, INT32_BE, FLOAT32_LE, FLOAT32_BE) the offset specifies the location of the first 16-bit register, and the second register is at offset+1, etc.

For string data types (STRING_HIGH, STRING_LOW, STRING_HIGH_LOW, STRING_LOW_HIGH, ZSTRING_HIGH, ZSTRING_LOW, ZSTRING_HIGH_LOW, ZSTRING_LOW_HIGH) the offset specifies the location of the first 16-bit register, and the second register is at offset+1, etc.

asynUInt32Digital

asynUInt32Digital device support is selected with

field(DTYP,"asynUInt32Digital")
field(INP,"@asynMask(portName,offset,mask,timeout)drvUser")

Modbus function

Offset type

Data type

drvUser

Records supported

Description

1, 2

Bit

Single bit

MODBUS_DATA

bi, mbbi, mbbiDirect, longin

value = (Modbus data & mask), (normally mask=1)

3, 4, 23

16-bit word

16-bit word

MODBUS_DATA

bi, mbbi, mbbiDirect, longin

value = (Modbus data & mask), (mask selects bits of interest)

5

Bit

Single bit

MODBUS_DATA

bo, mbbo, mbboDirect, longout

Modbus write (value & mask), (normally mask=1)

6, 16

16-bit word

16-bit word

MODBUS_DATA

bo, mbbo, mbboDirect, longout

If mask==0 or mask==0xFFFF does Modbus write (value). Else does read/modify/write:Sets bits that are set in value and set in mask. Clears bits that are clear in value and set in mask.

Any

NA

NA

ENABLE_HISTOGRAM

bi, mbbi, mbbiDirect, longin

Returns 0/1 if I/O time histogramming is disabled/enabled in driver.

Any

NA

NA

ENABLE_HISTOGRAM

bo, mbbo, mbboDirect, longout

If value = 0/1 then disable/enable I/O time histogramming in driver.

asynInt32

asynInt32 device support is selected with

field(DTYP,"asynInt32")
field(INP,"@asyn(portName,offset,timeout)drvUser")

or

field(INP,"@asynMask(portName,offset,nbits,timeout)drvUser")

The asynMask syntax is used for analog I/O devices, in order to specify the number of bits in the device. This is required for Modbus because the driver only knows that it is returning a 16-bit register, but not the actual number of bits in the device, and hence cannot return meaningful data with asynInt32->getBounds().

nbits>0 for a unipolar device. For example, nbits=12 means unipolar 12-bit device, with a range of 0 to 4095. nbits<0 for a bipolar device. For example, nbits=-12 means bipolar 12-bit device, with a range of -2048 to 2047)

Note: when writing 32-bit or 64-bit values function code 16 should be used if the device supports it. The write will then be “atomic”. If function code 6 is used then the data will be written in multiple messages, and there will be an short time period in which the device has incorrect data.

Modbus function

Offset type

Data type

drvUser

Records supported

Description

1, 2

Bit

Single bit

MODBUS_DATA

ai, bi, mbbi, longin

value = (epicsUInt32)Modbus data

3, 4, 23

16-bit words

16, 32, or 64-bit word

MODBUS_DATA (or datatype-specific value)

ai, mbbi, longin

value = (epicsInt32)Modbus data

5

Bit

Single bit

MODBUS_DATA

ao, bo, mbbo, longout

Modbus write value

6, 16, 23

16-bit words

16, 32, or 64-bit word

MODBUS_DATA (or datatype-specific value)

ao, mbbo, longout

Modbus write value

Any

NA

NA

MODBUS_READ

ao, bo, longout

Writing to a Modbus input driver with this drvUser value will force the poller thread to run once immediately, regardless of the value of POLL_DELAY.

Any

NA

NA

READ_OK

ai, longin

Returns number of successful read operations on this asyn port

Any

NA

NA

WRITE_OK

ai, longin

Returns number of successful write operations on this asyn port

Any

NA

NA

IO_ERRORS

ai, longin

Returns number of I/O errors on this asyn port

Any

NA

NA

LAST_IO_TIME

ai, longin

Returns number of milliseconds for last I/O operation

Any

NA

NA

MAX_IO_TIME

ai, longin

Returns maximum number of milliseconds for I/O operations

Any

NA

NA

HISTOGRAM_BIN_TIME

ao, longout

Sets the time per bin in msec in the statistics histogram

asynInt64

asynInt64 device support is selected with

field(DTYP,"asynInt64")
field(INP,"@asyn(portName,offset,timeout)drvUser")

Note: when writing 32-bit or 64-bit values function code 16 should be used if the device supports it. The write will then be “atomic”. If function code 6 is used then the data will be written in multiple messages, and there will be an short time period in which the device has incorrect data.

Modbus function

Offset type

Data type

drvUser

Records supported

Description

1, 2

Bit

Single bit

MODBUS_DATA

ai, longin, int64in

value = (epicsUInt64)Modbus data

3, 4, 23

16-bit words

16, 32, or 64-bit word

MODBUS_DATA (or datatype-specific value)

ai, longin, int64in

value = (epicsInt64)Modbus data

5

Bit

Single bit

MODBUS_DATA

ao, longout, int64out

Modbus write value

6, 16, 23

16-bit words

16, 32, or 64-bit word

MODBUS_DATA (or datatype-specific value)

ao, longout, int64out

Modbus write value

asynFloat64

asynFloat64 device support is selected with

field(DTYP,"asynFloat64")
field(INP,"@asyn(portName,offset,timeout)drvUser")

Note: when writing 32-bit or 64-bit values function code 16 should be used if the device supports it. The write will then be “atomic”. If function code 6 is used then the data will be written in multiple messages, and there will be an short time period in which the device has incorrect data.

Modbus function

Offset type

Data type

drvUser

Records supported

Description

1, 2

Bit

Single bit

MODBUS_DATA

ai

value = (epicsFloat64)Modbus data

3, 4, 23

16-bit words

16, 32, or 64-bit word

MODBUS_DATA (or datatype-specific value)

ai

value = (epicsFloat64)Modbus data

5

Bit

Single bit

MODBUS_DATA

ao

Modbus write (epicsUInt16)value

6, 16, 23

16-bit word

16-bit word

MODBUS_DATA (or datatype-specific value)

ao

Modbus write value

Any

NA

NA

POLL_DELAY

ai, ao

Read or write the delay time in seconds between polls for the read poller thread. If <=0 then the poller thread does not run periodically, it only runs when it is woken up by an epicsEvent signal, which happens when the driver has an asynInt32 write with the MODBUS_READ drvUser string.

asynInt32Array

asynInt32Array device support is selected with

field(DTYP,"asynInt32ArrayIn")
field(INP,"@asyn(portName,offset,timeout)drvUser")

or

field(DTYP,"asynInt32ArrayOut")
field(INP,"@asyn(portName,offset,timeout)drvUser")

asynInt32Array device support is used to read or write arrays of up to 2000 coil values or up to 125 16-bit registers. It is also used to read the histogram array of I/O times when histogramming is enabled.

Modbus function

Offset type

Data type

drvUser

Records supported

Description

1, 2

Bit

Array of bits

MODBUS_DATA

waveform (input)

value = (epicsInt32)Modbus data[]

3, 4, 23

16-bit word

Array of 16, 32 or 64-bit words

MODBUS_DATA (or datatype-specific value)

waveform (input)

value = (epicsInt32)Modbus data[]

15

Bit

Array of bits

MODBUS_DATA

waveform (output)

Modbus write (epicsUInt16)value[]

16, 23

16-bit word

Array of 16, 32, or 64-bit words

MODBUS_DATA (or datatype-specific value)

waveform (output)

Modbus write value[]

Any

32-bit word

NA

READ_HISTOGRAM

waveform (input)

Returns a histogram array of the I/O times in milliseconds since histogramming was last enabled.

Any

32-bit word

NA

HISTOGRAM_TIME_AXIS

waveform (input)

Returns the time axis of the histogram data. Each element is HISTOGRAM_BIN_TIME msec.

asynFloat64Array

asynFloat64Array device support is selected with

field(DTYP,"asynFloat64ArrayIn")
field(INP,"@asyn(portName,offset,timeout)drvUser")

or

field(DTYP,"asynFloat64ArrayOut")
field(INP,"@asyn(portName,offset,timeout)drvUser")

asynFloat64Array device support is used to read or write arrays of up to 2000 coil values or up to 125 16-bit registers.

Modbus function

Offset type

Data type

drvUser

Records supported

Description

1, 2

Bit

Array of bits

MODBUS_DATA

waveform (input)

value = (epicsFloat64)Modbus data[]

3, 4, 23

16-bit word

Array of 16, 32 or 64-bit words

MODBUS_DATA (or datatype-specific value)

waveform (input)

value = (epicsFloat64)Modbus data[]

15

Bit

Array of bits

MODBUS_DATA

waveform (output)

Modbus write (epicsUInt16)value[]

16, 23

16-bit word

Array of 16, 32, or 64-bit words

MODBUS_DATA (or datatype-specific value)

waveform (output)

Modbus write value[]

Any

32-bit word

NA

READ_HISTOGRAM

waveform (input)

Returns a histogram array of the I/O times in milliseconds since histogramming was last enabled.

Any

32-bit word

NA

HISTOGRAM_TIME_AXIS

waveform (input)

Returns the time axis of the histogram data. Each element is HISTOGRAM_BIN_TIME msec.

asynOctet

asynOctet device support is selected with

field(DTYP,"asynOctetRead")
field(INP,"@asyn(portName,offset,timeout)drvUser[=number_of_characters]")

or

field(DTYP,"asynOctetWrite")
field(INP,"@asyn(portName,offset,timeout)drvUser[=number_of_characters]")

asynOctet device support is used to read or write strings of up to 250 characters.

Note: The 0 terminating byte at the end of the string in a waveform record or stringout record is only written to the Modbus device if one of the ZSTRING_* drvUser types is used.

Note: On input the number of characters read from the Modbus device will be the lesser of:

  • The number of characters in the record minus the terminating 0 byte (39 for stringin, NELM-1 for waveform) or

  • The number of characters specified after drvUser (minus the terminating 0 byte) or

  • The number of characters contained in the registers defined modbusLength argument to drvModbusAsynConfigure (modbusLength or modbusLength*2 depending on whether the drvUser field specifies 1 or 2 characters per register.

The string will be truncated if any of the characters read from Modbus is a 0 byte, but there is no guarantee that the last character in the string is followed by a 0 byte in the Modbus registers. Generally either number_of_characters or NELM in the waveform record should be used to define the correct length for the string.

Modbus function

Offset type

Data type

drvUser

Records supported

Description

3, 4, 23

16-bit word

String of characters

STRING_HIGH, STRING_LOW, STRING_HIGH_LOW, or STRING_LOW_HIGH</br> ZSTRING_HIGH, ZSTRING_LOW, ZSTRING_HIGH_LOW, or ZSTRING_LOW_HIGH

waveform (input) or stringin

value = Modbus data[]

16, 23

16-bit word

String of characters

STRING_HIGH, STRING_LOW, STRING_HIGH_LOW, or STRING_LOW_HIGH</br> ZSTRING_HIGH, ZSTRING_LOW, ZSTRING_HIGH_LOW, or ZSTRING_LOW_HIGH

waveform (output) or stringout

Modbus write value[]

Template files

modbus provides example template files in the modbusApp/Db directory. These include the following.

Files

Description

Macro arguments

bi_bit.template

asynUInt32Digital support for bi record with discrete inputs or coils. Mask=1.

P, R, PORT, OFFSET, ZNAM, ONAM, ZSV, OSV, SCAN

bo_bit.template

asynUInt32Digital support for bo record with coil outputs. Mask=1.

P, R, PORT, OFFSET, ZNAM, ONAM

bi_word.template

asynUInt32Digital support for bi record with register inputs.

P, R, PORT, OFFSET, MASK, ZNAM, ONAM, ZSV, OSV, SCAN

bo_word.template

asynUInt32Digital support for bo record with register outputs.

P, R, PORT, OFFSET, MASK, ZNAM, ONAM

mbbiDirect.template

asynUInt32Digital support for mbbiDirect record with register inputs.

P, R, PORT, OFFSET, MASK, SCAN

mbboDirect.template

asynUInt32Digital support for mbboDirect record with register outputs.

P, R, PORT, OFFSET, MASK

longin.template

asynUInt32Digital support for longin record with register inputs. Mask=0xFFFF.

P, R, PORT, OFFSET, SCAN

longout.template

asynUInt32Digital support for longout record with register outputs. Mask=0xFFFF.

P, R, PORT, OFFSET

longinInt32.template

asynInt32 support for longin record with register inputs.

P, R, PORT, OFFSET, SCAN, DATA_TYPE

longoutInt32.template

asynInt32 support for longout record with register outputs.

P, R, PORT, OFFSET, DATA_TYPE

ai.template

asynInt32 support for ai record with LINEAR conversion

P, R, PORT, OFFSET, BITS, EGUL, EGUF, PREC, SCAN

ao.template

asynInt32 support for ao record with LINEAR conversion

P, R, PORT, OFFSET, BITS, EGUL, EGUF, PREC

ai_average.template

asynInt32Average support for ai record with LINEAR conversion. This support gets callbacks each time the poll thread reads the analog input, and averages readings until the record is processed.

P, R, PORT, OFFSET, BITS, EGUL, EGUF, PREC, SCAN

intarray_in.template

asynInt32Array support for waveform record with discrete, coil, or register inputs.

P, R, PORT, OFFSET, NELM, SCAN

intarray_out.template

asynInt32Array support for waveform record with discrete, coil, or register outputs.

P, R, PORT, OFFSET, NELM

int64in.template

asynInt64 support for int64in record with register inputs.

P, R, PORT, OFFSET, SCAN, DATA_TYPE

int64out.template

asynInt64 support for int64out record with register outputs.

P, R, PORT, OFFSET, DATA_TYPE

aiFloat64.template

asynFloat64 support for ai record

P, R, PORT, OFFSET, LOPR, HOPR, PREC, SCAN, DATA_TYPE

aoFloat64.template

asynFloat64 support for ao record

P, R, PORT, OFFSET, LOPR, HOPR, PREC, DATA_TYPE

stringin.template

asynOctet support for stringin record

P, R, PORT, OFFSET, DATA_TYPE, SCAN

stringout.template

asynOctet support for stringout record

P, R, PORT, OFFSET, DATA_TYPE, INITIAL_READBACK

stringWaveformIn.template

asynOctet input support for waveform record

P, R, PORT, OFFSET, DATA_TYPE, NELM, SCAN

stringWaveformOut.template

asynOctet output support for waveform record

P, R, PORT, OFFSET, DATA_TYPE, NELM, INITIAL_READBACK

asynRecord.template

Support for asyn record. Useful for controlling trace printing, and for debugging.

P, R, PORT, ADDR, TMOD, IFACE

poll_delay.template

Support for ao record to control the delay time for the poller thread.

P, R, PORT

poll_trigger.template

Support for bo record to trigger running the poller thread.

P, R, PORT

statistics.template

Support for bo, longin and waveform records to read I/O statistics for the port.

P, R, PORT, SCAN

The following table explains the macro parameters used in the preceding table.

Macro

Description

P

Prefix for record name. Complete record name is $(P)$(R).

R

Record name. Complete record name is $(P)$(R).

PORT

Port name for modbus asyn port.

OFFSET

Offset for Modbus data relative to start address for this port.

MASK

Bit mask used to select data for this record.

ZNAM

String for 0 value for bi/bo records.

ONAM

String for 1 value for bi/bo records.

ZSV

0 severity for bi/bo records.

OSV

1 severity for bi/bo records.

BITS

Number of bits for analog I/O devices. >0=unipolar, <0=bipolar.

DATA_TYPE

drvUser field specifying the Modbus data type. If this field is blank or is MODBUS_DATA then the default datatype specified in the drvModbusAsynConfigure command is used. Other allowed values are listed in the table above (UINT16, INT16SM, BCD_SIGNED, etc.)

EGUL

Engineering value for lower limit of analog device.

EGUF

Engineering value for upper limit of analog device.

LOPR

Lower display limit of analog device.

HOPR

Upper display limit of analog device.

PREC

Number of digits of precision for ai/ao records.

NELM

Number of elements in waveform records.

ADDR

Address for asyn record, same as OFFSET above.

TMOD

Transfer mode for asyn record.

IFACE

asyn interface for asyn record.

SCAN

Scan rate for record (e.g. “1 second”, “I/O Intr”, etc.).

INITIAL_READBACK

Controls whether an initial readback from the device is done for the stringout or string waveform output records.