EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  2025  <2026 Index 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  2025  <2026
<== Date ==> <== Thread ==>

Subject: Re: [Ext]Re: Modbus linked read/write question
From: Jesse Hopkins via Tech-talk <tech-talk at aps.anl.gov>
To: Mark Rivers <rivers at cars.uchicago.edu>, EPICS Tech-Talk <tech-talk at aps.anl.gov>
Date: Fri, 23 Jan 2026 19:29:37 +0000
Hi Mark,

That seems to have done the trick, thanks! I don't think it's caused an infinite loop, but I guess I'm not sure how to check.

All the best.

- Jesse

----
Jesse Hopkins, PhD (he/him)
Director, BioCAT
Sector 18, Advanced Photon Source
Research Associate Professor, Illinois Tech

From: Mark Rivers <rivers at cars.uchicago.edu>
Sent: Friday, January 23, 2026 11:52 AM
To: EPICS Tech-Talk <tech-talk at aps.anl.gov>; Jesse Hopkins <jhopkins1 at illinoistech.edu>
Subject: [Ext]Re: Modbus linked read/write question
 
Hi Jesse,

With many asyn drivers you can make output records match the corresponding readback records by using this line in the output record database file:

info(asyn:READBACK, "1")


However, that won't work in your case, because there are separate asyn drivers for the Modbus input and output records.  

I believe you can do it by adding a third record:

record(bo, "SyncOutput" {
    field(DOL, "BiRecord CP MS")
    field(OMSL, "closed_loop")
    field(OUT, "BoRecord PP NMS")
}

This record will process whenever your BiRecord has a new value.  It will write that new value into the output record.  The output record will process, which is inefficient, but it should not result in an infinite loop because the input won't change again.  It would be nice to be able to use NPP on the output link, but I think that won't work because it will not do callbacks on the new value, so OPI displays won't update.

Mark




From: Tech-talk <tech-talk-bounces at aps.anl.gov> on behalf of Jesse Hopkins via Tech-talk <tech-talk at aps.anl.gov>
Sent: Friday, January 23, 2026 11:35 AM
To: EPICS Tech-Talk <tech-talk at aps.anl.gov>
Subject: Modbus linked read/write question
 
Hi folks,

I'm working on developing basic device support for a Huber 8-fold attenuator over modbus. The device modbus interface has a single holding register with read/write access where each of the first 8 bits corresponds to the position of each attenuator, either in (1) or out (0). I was able to use (read: copy) the Koyo1 example in the modbus documentation with a couple of tweaks and get a set of binary inputs (using the modbus bi_word.template) and binary outputs (using the modbus bo_word.template) that work as expected, and it was quite quick (so thanks!).

The wrinkle is that this device can also be controlled through other means, both via a browser-based web interface and via a TCP/telnet style interface. If I use the web interface to change an attenuator position, the binary inputs update appropriately, however the binary outputs do not. More concretely, suppose that attenuator 1 is out. The binary input and output for this attenuator both have the expected value: 0. If I use the web interface to put it in, the binary input position reads as expected, 1, but the binary output still has a value of 0.

My question is whether that's a simple way to update the output position when the input position changes, to ensure that the outputs stay synced with the actual attenuator position if someone controls the device through these other interfaces. Note that I don't need to write to the device in this case, I just want to update the state of the EPICS record to reflect the new device state. 

The other possibility is that I just don't tell anyone else about the other ways to control the device and hope they only use the EPICS control.

In case it's useful, I've included my st.cmd and substitutions files as text at the end of this message.

All the best.

- Jesse

----
Jesse Hopkins, PhD (he/him)
Director, BioCAT
Sector 18, Advanced Photon Source
Research Associate Professor, Illinois Tech

st.cmd:
#!../../bin/linux-x86_64/huber_atten

#- SPDX-FileCopyrightText: 2003 Argonne National Laboratory
#-
#- SPDX-License-Identifier: EPICS

#- You may have to change huber_atten to something else
#- everywhere it appears in this file

< envPaths

## Register all support components
dbLoadDatabase "../../dbd/huber_atten.dbd"
huber_atten_registerRecordDeviceDriver pdbbase


# Use the following commands for TCP/IP
#drvAsynIPPortConfigure(const char *portName,
#                       const char *hostInfo,
#                       unsigned int priority,
#                       int noAutoConnect,
#                       int noProcessEos);
drvAsynIPPortConfigure("Huber1","164.54.204.27:502",0,0,0)
asynSetOption("Huber1",0, "disconnectOnReadTimeout", "Y")

#modbusInterposeConfig(const char *portName,
#                      modbusLinkType linkType,
#                      int timeoutMsec,
#                      int writeDelayMsec)
modbusInterposeConfig("Huber1",0,5000,0)


# Word access at Modbus address 0
# Access 1 words as inputs.  
# Modbus standard functions 3 (Read Multiple), 4 (Read One), 6 (Write One), and 16 (Write Multiple). 
# default data type unsigned integer.
# drvModbusAsynConfigure("portName", 
#           "tcpPortName", 
#           slaveAddress, 
#           modbusFunction, 
#           modbusStartAddress, 
#           modbusLength, 
#           dataType, 
#           pollMsec, 
#           "plcType")

drvModbusAsynConfigure("H1_Yn_In_Word", "Huber1", 0, 3, 0, 01, "UINT16",  100, "Huber")
drvModbusAsynConfigure("H1_Yn_Out_Word", "Huber1", 0, 6, 0, 01, "UINT16",  100, "Huber")

dbLoadTemplate("Huber1.substitutions")

iocInit

date


Huber1.substitutions:
# asyn record for the underlying asyn octet port
file "$(ASYN)/db/asynRecord.db" { pattern
{P,           R,       PORT,      ADDR,   IMAX,    OMAX}
{18ID:HUBER1:    OctetAsyn,    Huber1,     0,      80,      80}
}

# These are the Yn inputs done with word access Y0-Y7
file "$(MODBUS)/db/bi_word.template" { pattern
{P,           R,         PORT,              OFFSET,    MASK,     ZNAM,   ONAM,  ZSV,       OSV,    SCAN}
{18ID:HUBER1:,    Y0InW,     H1_Yn_In_Word,     0,        0x0001,    Out,    In,  NO_ALARM,  MAJOR,  "I/O Intr"}
{18ID:HUBER1:,    Y1InW,     H1_Yn_In_Word,     0,        0x0002,    Out,    In,  NO_ALARM,  MAJOR,  "I/O Intr"}
{18ID:HUBER1:,    Y2InW,     H1_Yn_In_Word,     0,        0x0004,    Out,    In,  NO_ALARM,  MAJOR,  "I/O Intr"}
{18ID:HUBER1:,    Y3InW,     H1_Yn_In_Word,     0,        0x0008,    Out,    In,  NO_ALARM,  MAJOR,  "I/O Intr"}
{18ID:HUBER1:,    Y4InW,     H1_Yn_In_Word,     0,        0x0010,    Out,    In,  NO_ALARM,  MAJOR,  "I/O Intr"}
{18ID:HUBER1:,    Y5InW,     H1_Yn_In_Word,     0,        0x0020,    Out,    In,  NO_ALARM,  MAJOR,  "I/O Intr"}
{18ID:HUBER1:,    Y6InW,     H1_Yn_In_Word,     0,        0x0040,    Out,    In,  NO_ALARM,  MAJOR,  "I/O Intr"}
{18ID:HUBER1:,    Y7InW,     H1_Yn_In_Word,     0,        0x0080,    Out,    In,  NO_ALARM,  MAJOR,  "I/O Intr"}
}
file "$(MODBUS)/db/mbbiDirect.template" { pattern
{P,           R,         PORT,               OFFSET,   MASK, SCAN}
{18ID:HUBER1:,    YnInWL,     H1_Yn_In_Word,      0,        0xFFFF, "I/O Intr"}
}
file "$(MODBUS)/db/intarray_in.template" { pattern
{P,           R,          PORT,              NELM,   SCAN}
{18ID:HUBER1:,    YnInWArray, H1_Yn_In_Word,     8,     "I/O Intr"}
}
file "$(MODBUS)/db/asynRecord.template" { pattern
{P,           R,         PORT,             ADDR,     TMOD,  IFACE}
{18ID:HUBER1:,    YnInWAsyn, H1_Yn_In_Word,    0,        Read,  asynInt32}
}
file "$(MODBUS)/db/statistics.template" { pattern
{P,           R,         PORT,          SCAN}
{18ID:HUBER1:,    YnInW,     H1_Yn_In_Word, "10 second"}
}
file "$(MODBUS)/db/poll_delay.template" { pattern
{P,           R,               PORT}
{18ID:HUBER1:,    YnInWPollDelay, H1_Yn_In_Word}
}


# These are the Yn outputs done with word access.  Y0-Y7 
file "$(MODBUS)/db/bo_word.template" { pattern
{P,           R,          PORT,               OFFSET,   MASK,      ZNAM,   ONAM}
{18ID:HUBER1:,    Y0OutW,     H1_Yn_Out_Word,     0,        0x0001,    Out,    In}
{18ID:HUBER1:,    Y1OutW,     H1_Yn_Out_Word,     0,        0x0002,    Out,    In}
{18ID:HUBER1:,    Y2OutW,     H1_Yn_Out_Word,     0,        0x0004,    Out,    In}
{18ID:HUBER1:,    Y3OutW,     H1_Yn_Out_Word,     0,        0x0008,    Out,    In}
{18ID:HUBER1:,    Y4OutW,     H1_Yn_Out_Word,     0,        0x0010,    Out,    In}
{18ID:HUBER1:,    Y5OutW,     H1_Yn_Out_Word,     0,        0x0020,    Out,    In}
{18ID:HUBER1:,    Y6OutW,     H1_Yn_Out_Word,     0,        0x0040,    Out,    In}
{18ID:HUBER1:,    Y7OutW,     H1_Yn_Out_Word,     0,        0x0080,    Out,    In}
}
file "$(MODBUS)/db/mbboDirect.template" { pattern
{P,           R,          PORT,              OFFSET,    MASK}
{18ID:HUBER1:,    YnOutWL,     H1_Yn_Out_Word,     0,         0xFFFF}
}
file "$(MODBUS)/db/asynRecord.template" { pattern
{P,           R,          PORT,              ADDR,     TMOD,  IFACE}
{18ID:HUBER1:,    YnOutWAsyn, H1_Yn_Out_Word,    0,        Read,  asynUInt32Digital}
}
file "$(MODBUS)/db/statistics.template" { pattern
{P,           R,          PORT,            SCAN}
{18ID:HUBER1:,    YnOutW,     H1_Yn_Out_Word,  "10 second"}
}

Replies:
Re: [Ext]Re: Modbus linked read/write question Jesse Hopkins via Tech-talk
Re: [Ext]Re: Modbus linked read/write question Mark Rivers via Tech-talk
References:
Modbus linked read/write question Jesse Hopkins via Tech-talk
Re: Modbus linked read/write question Mark Rivers via Tech-talk

Navigate by Date:
Prev: Re: Modbus linked read/write question Mark Rivers via Tech-talk
Next: epicsThreadOpts undeclared identifier windows build error Peterson, Kevin M. via Tech-talk
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  2025  <2026
Navigate by Thread:
Prev: Re: Modbus linked read/write question Mark Rivers via Tech-talk
Next: Re: [Ext]Re: Modbus linked read/write question Jesse Hopkins via Tech-talk
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  2025  <2026
ANJ, 19 Mar 2026 · Home · News · About · Talk · Base · Modules · Extensions ·
· Distributions · Download · Documents · Links · Licensing ·