Hi Toby,
What you are seeing reflects a design decision in the Modbus driver. These are the relevant comments in the code:
/* Process callbacks to device support. */
/* See if there are any asynUInt32Digital callbacks registered to be called
* when data changes. These callbacks only happen if the value has changed */
...
/* See if there are any asynInt32 callbacks registered to be called.
* These are called even if the data has not changed, because we could be doing
* ADC averaging */
So for asynUInt32 it only does the callbacks if the value has changed. For asynInt32 it always does the callbacks, even if the value has not changed. The reasoning is that the asynInt32 support can be used for ADCs which may use the asynInt32Average device support which does averaging, and so needs a callback for every value.
I understand that this is not a very good design. What we would like is to have the behavior configurable per parameter or even per record. But the asyn interfaces do not currently have a way to communicate that to the driver.
I think you can use the MDEL field of the ai record to prevent it from sending monitors when the difference from the previous value is less than MDEL. But you cannot prevent the record from processing on each callback.
One option would be to put this check in the device support callback routine. The driver would always call device support, but device support could decide whether to process the record or not. The question is what record field would we use? We should not use MDEL, because some users may be counting on the record to process on each callback but only send monitors if the delta is greater than or equal to MDEL.
This issue arises in the opposite sense for drivers written using asynPortDriver callbacks. It never does callbacks if the value has not changed, but there are cases (like ADC averaging) where one does want a callback on every value.
Mark
________________________________
From: Tech-talk <tech-talk-bounces at aps.anl.gov> on behalf of Tobin R Weber via Tech-talk <tech-talk at aps.anl.gov>
Sent: Monday, October 12, 2020 2:04 PM
To: tech-talk at aps.anl.gov
Subject: Modbus port driver processing record with new value call back without a new value
Hello Ladies and Gentleman,
I have been reading 16-bit holding registers using modbus (function code 3) from an acromag device (XT-1541) and a DirectLogic DL 205 Modular PLC. Using the "ai" record, and "asynInt32" for the "DTYP" field, I am able to correctly read the 16-bit values. However, the "SCAN" field is set to "I/O Intr", and the record processes every time the modbus port driver is polled (every 100 msec, in my case) regardless of the status of the value (i.e., even if the value has not changed). I see an identical issue with the "longin" record. I have tried many different things, and it appears using the "asynUInt32Digital" for the "DTYP" field with the "longin" record fixes the problem. Unfortunately, this device support is not available for the "ai" record with modbus.
My question: Is this the specified behavior? I'm sure I'm doing something wrong, but I have no idea what at this point. Below is one simple example of the issue:
Here is the st.cmd file:
st.cmd: Modbus TPC/IP communication with a Acromag XT-1541.
---------------------------------------------------------------------------------------------------------
drvAsynIPPortConfigure("AcromagHVPS","10.10.10.176:502<http://10.10.10.176:502/>",0,0,1)
modbusInterposeConfig("AcromagHVPS", 0, 1000, 0)
drvModbusAsynConfigure("HVPSRead", "AcromagHVPS",0,3,0,9,1,100,"AcromagHVPS")
dbLoadRecords "db/test.db"
cd "${TOP}/iocBoot/${IOC}"
iocInit
asynSetTraceIOMask "HVPSRead",1,4
asynSetTraceMask "HVPSRead",1,0x000b
---------------------------------------------------------------------------------------------------------
Here is the record that is scanned every 100 msec, despite the value not changing:
test.db: "ai" record to read modbus data.
---------------------------------------------------------------------------------------------------------
record(ai, "HVPSBOReadRecord") {
field(SCAN, "I/O Intr")
field(DTYP, "asynInt32")
field(INP, "@asynMask(HVPSRead, 1, -16, 1000)MODBUS_DATA ")
field(FLNK, "iocHeartbeat")
}
---------------------------------------------------------------------------------------------------------
epics shell: Shows that the modbus data read properly, but the "HVPSBOReadRecord" record is continually processed with a callback, despite it's value not changing. And I have verified that this record is actually being processed with FLNK's to other records as well as by setting the "TPRO" field.
---------------------------------------------------------------------------------------------------------
2020/09/10 16:03:21.561 HVPSBOReadRecord devAsynInt32::interruptCallbackInput new value=12750
2020/09/10 16:03:21.561 HVPSBOReadRecord devAsynInt32::getCallbackValue from ringBuffer value=12750
2020/09/10 16:03:21.662 HVPSBOReadRecord devAsynInt32::interruptCallbackInput new value=12750
2020/09/10 16:03:21.662 HVPSBOReadRecord devAsynInt32::getCallbackValue from ringBuffer value=12750
2020/09/10 16:03:21.764 HVPSBOReadRecord devAsynInt32::interruptCallbackInput new value=12750
2020/09/10 16:03:21.764 HVPSBOReadRecord devAsynInt32::getCallbackValue from ringBuffer value=12750
epics> 2020/09/10 16:03:21.865 HVPSBOReadRecord devAsynInt32::interruptCallbackInput new value=12750
2020/09/10 16:03:21.865 HVPSBOReadRecord devAsynInt32::getCallbackValue from ringBuffer value=12750
2020/09/10 16:03:21.966 HVPSBOReadRecord devAsynInt32::interruptCallbackInput new value=12750
2020/09/10 16:03:21.967 HVPSBOReadRecord devAsynInt32::getCallbackValue from ringBuffer value=12750
...
---------------------------------------------------------------------------------------------------------
Conversely, if I use this record, the record is only processed when the input data changes:
test.db: "longin" record to read modbus data.
---------------------------------------------------------------------------------------------------------
record(longin, "HVPSBOReadRecord") {
field(SCAN, "I/O Intr")
field(DTYP, "asynUInt32Digital")
field(INP, "@asynMask(HVPSRead, 1, 0xFFFF, 5000)MODBUS_DATA ")
field(FLNK, "iocHeartbeat")
}
---------------------------------------------------------------------------------------------------------
epics shell: Shows that the modbus read data properly, and not processing the "HVPSBOReadRecord" record continuously with a callback. I also verified that this record is only processed when the value changes via the .TPRO field, and FLNK's to other records.
---------------------------------------------------------------------------------------------------------
2020/09/10 16:01:35.160 HVPSBOReadRecord devAsynUInt32Digital::interruptCallbackInput new value=12750
2020/09/10 16:01:35.160 HVPSBOReadRecord devAsynInt32::getCallbackValue from ringBuffer value=12750
epics>
---------------------------------------------------------------------------------------------------------
I'm using:
EPICS: 3.15.6
Asyn: R4-32
Modbus: >= 2-10-2
However I have since tried EPICS base-3.15.7, modbus 3-0, and asyn R4-38.
Thanks very much for any help.
Toby
--
Tobin Weber
University of Washington
Department of Aeronautics and Astronautics
Research Scientist
Lab: 206-543-2108
- References:
- Modbus port driver processing record with new value call back without a new value Tobin R Weber via Tech-talk
- Navigate by Date:
- Prev:
Modbus port driver processing record with new value call back without a new value Tobin R Weber via Tech-talk
- Next:
How can I use pvapy or p4p to monitor multiple PVS 秦天 via Tech-talk <tech-talk at aps.anl.go
- 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
- Navigate by Thread:
- Prev:
Modbus port driver processing record with new value call back without a new value Tobin R Weber via Tech-talk
- Next:
How can I use pvapy or p4p to monitor multiple PVS 秦天 via Tech-talk <tech-talk at aps.anl.go
- 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
|