Hi Torsten,
- I am missing the name of the parameter here:
field(OUT,"@asynMask($(PORT), 0, 0x8000 )SomeName")
The Modbus driver defaults to parameter name MODBUS_DATA, which is parameter number 0. That is documented here:
https://epics-modules.github.io/modbus/device_support.html
So it is fine to omit the parameter name if it is MODBUS_DATA.
- In that sense, I am missing these fields in the record definition:
info(asyn:INITIAL_READBACK,"1”)
info(asyn:READBACK,"1”)
asyn:INITIAL_READBACK only applies to stringout and waveform records. That is documented here:
https://epics-modules.github.io/asyn/asynDriver.html#generic-device-support-for-epics-records
asyn:READBACK only enables setting the values of output record from driver interrupt callbacks, it does not control the initial read of the record value during iocInit. That is documented here:
https://epics-modules.github.io/asyn/asynDriver.html#generic-device-support-for-epics-records
So the behavior that Dale is observing is not the expected behavior.
Dale, can you add a longout record that talks to that same register, and uses mask=0xFFFF? I want to see if it reads back the actual state of that register at iocInit.
Thanks,
Mark
-----Original Message-----
From: Torsten Bögershausen <torsten.bogershausen at ess.eu>
Sent: Friday, April 14, 2023 2:38 PM
To: Dale Cox <dale.cox at acu.edu>
Cc: Mark Rivers <rivers at cars.uchicago.edu>; tech-talk at aps.anl.gov
Subject: Re: modbus ioc start
Hm,
I think I have lost track about the connection between records and asyn parameters.
I am missing the name of the parameter here:
> > record(bo,"$(P)$(R)-TC1_enable") {
> > field(DTYP,"asynUInt32Digital")
> > field(OUT,"@asynMask($(PORT), 0, 0x8000 )")
> field(OUT,"@asynMask($(PORT), 0, 0x8000 )SomeName")
> > field(ZNAM,"Disabled")
> > field(ONAM,"Enabled")
> > }
(Or isn’t that used in modbus ? I am confused)
The other question:
If I understand it rigth, you define output records.
And when the IOC starts, they should get their values from the device, whatever is the actual value here, should be reflected in the record.
In that sense, I am missing these fields in the record definition:
info(asyn:INITIAL_READBACK,"1”)
info(asyn:READBACK,"1”)
Or do I miss something ?
/Torsten
> On 14 Apr 2023, at 20:57, Dale Cox <dale.cox at acu.edu> wrote:
>
> Torsten,
>
> Here it is:
>
> epics> asynReport 10 Z8TC1_Config
> Z8TC1_Config multiDevice:Yes canBlock:Yes autoConnect:Yes
> enabled:Yes connected:Yes numberConnects 1
> nDevices 4 nQueued 0 blocked:No
> asynManagerLock:No synchronousLock:No
> exceptionActive:No exceptionUsers 0 exceptionNotifys 0
> traceMask:0x1 traceIOMask:0x0 traceInfoMask:0x1
> interposeInterfaceList
> asynOctet pinterface 0x7f2974234460 drvPvt 0x555800dc6c50
> interfaceList
> asynCommon pinterface 0x7f2974234d10 drvPvt 0x555800dc5170
> asynDrvUser pinterface 0x7f2974234aa0 drvPvt 0x555800dc5170
> asynOctet pinterface 0x7f2974234be0 drvPvt 0x555800dc5170
> asynUInt32Digital pinterface 0x7f2974234c60 drvPvt 0x555800dc5170
> asynInt32 pinterface 0x7f2974234ce0 drvPvt 0x555800dc5170
> asynInt64 pinterface 0x7f2974234ca0 drvPvt 0x555800dc5170
> asynFloat64 pinterface 0x7f2974234c40 drvPvt 0x555800dc5170
> asynInt32Array pinterface 0x7f2974234b80 drvPvt 0x555800dc5170
> addr 0 autoConnect Yes enabled Yes connected Yes exceptionActive No
> exceptionActive No exceptionUsers 0 exceptionNotifys 0
> blocked No
> traceMask:0x1 traceIOMask:0x0 traceInfoMask:0x1
> addr 1 autoConnect Yes enabled Yes connected Yes exceptionActive No
> exceptionActive No exceptionUsers 0 exceptionNotifys 0
> blocked No
> traceMask:0x1 traceIOMask:0x0 traceInfoMask:0x1
> addr 2 autoConnect Yes enabled Yes connected Yes exceptionActive No
> exceptionActive No exceptionUsers 0 exceptionNotifys 0
> blocked No
> traceMask:0x1 traceIOMask:0x0 traceInfoMask:0x1
> addr 3 autoConnect Yes enabled Yes connected Yes exceptionActive No
> exceptionActive No exceptionUsers 0 exceptionNotifys 0
> blocked No
> traceMask:0x1 traceIOMask:0x0 traceInfoMask:0x1 modbus port:
> Z8TC1_Config
> initialized: true
> asynOctet server: SenecaBus
> modbusSlave: 5
> modbusFunction: 6
> modbusStartAddress: 065
> modbusLength: 04
> absoluteAddressing: false
> dataType: 4 (UINT16)
> plcType: SenecaZ
> I/O errors: 0
> Read OK: 1
> Write OK: 0
> pollDelay: 0.400000
> Time for last I/O 21 msec
> Max. I/O time: 21 msec
> Time per hist. bin: 1 msec
> Port: Z8TC1_Config
> Timestamp: <undefined>
> Input EOS[0]:
> Output EOS[0]:
> Parameter list 0
> Number of parameters is: 12
> Parameter 0 type=asynInt32, name=MODBUS_DATA, value is undefined
> Parameter 1 type=asynInt32, name=MODBUS_READ, value is undefined
> Parameter 2 type=asynUInt32Digital, name=ENABLE_HISTOGRAM, value is
> undefined Parameter 3 type=asynInt32, name=READ_HISTOGRAM, value is
> undefined Parameter 4 type=asynInt32, name=HISTOGRAM_BIN_TIME, value
> is undefined Parameter 5 type=asynInt32Array,
> name=HISTOGRAM_TIME_AXIS, value is undefined Parameter 6
> type=asynFloat64, name=POLL_DELAY, value is undefined Parameter 7
> type=asynInt32, name=READ_OK, value=1, status=0 Parameter 8
> type=asynInt32, name=WRITE_OK, value=0, status=0 Parameter 9
> type=asynInt32, name=IO_ERRORS, value=0, status=0 Parameter 10
> type=asynInt32, name=LAST_IO_TIME, value=21, status=0 Parameter 11
> type=asynInt32, name=MAX_IO_TIME, value=21, status=0
>
> On Fri, Apr 14, 2023 at 1:46 PM Torsten Bögershausen <torsten.bogershausen at ess.eu> wrote:
> I have the slight feeling, but this is a shot into the blue, that the
> driver is doing the right thing.
> And may be the record is initialized to early ?
>
> What does
> asynReport 10 Z8TC1_Config
> give you ?
>
> Do you see the right values in the asynparameters ?
>
>
>
> > On 14 Apr 2023, at 15:43, Dale Cox via Tech-talk <tech-talk at aps.anl.gov> wrote:
> >
> > Thanks for the reply Mark.
> >
> > (1) Yes I thought this was the case. Whenever I enable some asyn trace lines in the IOC, I can see the initial modbus request. It looks like this:
> >
> > ...
> > drvModbusAsynConfigure("Z8TC1_Config", "SenecaBus", 5, 6, 53, 4,
> > "UINT16", 400, "SenecaZ")
> > 2023/04/14 08:32:01.482 SenecaBus asynManager::queueLockPort locking
> > port
> > 2023/04/14 08:32:01.482 SenecaBus asynManager::queueLockPort created
> > queueLockPortPvt=0x55ec3aba5df0
> > 2023/04/14 08:32:01.482 SenecaBus asynManager::queueLockPort created
> > queueLockPortPvt=0x55ec3aba5df0, event=0x55ec3aba5e10,
> > mutex=0x55ec3aba5eb0
> > 2023/04/14 08:32:01.482 SenecaBus asynManager::queueLockPort taking
> > mutex 0x55ec3aba5eb0
> > 2023/04/14 08:32:01.482 SenecaBus asynManager::queueLockPort
> > queueing request
> > 2023/04/14 08:32:01.482 SenecaBus addr -1 queueRequest priority 0
> > not lockHolder
> > 2023/04/14 08:32:01.482 SenecaBus schedule queueRequest timeout in
> > 2.000000 seconds
> > 2023/04/14 08:32:01.482 SenecaBus asynManager::queueLockPort waiting
> > for event
> > 2023/04/14 08:32:01.482 asynManager::portThread port=SenecaBus
> > callback
> > 2023/04/14 08:32:01.482 SenecaBus asynManager::queueLockPortCallback
> > signaling begin event
> > 2023/04/14 08:32:01.482 SenecaBus asynManager::queueLockPortCallback
> > waiting for mutex from queueUnlockPort
> > 2023/04/14 08:32:01.482 SenecaBus asynManager::queueLockPort got
> > event from callback
> > 2023/04/14 08:32:01.482 SenecaBus flush
> > 2023/04/14 08:32:01.482 /dev/ttyUSB0 flush
> > 2023/04/14 08:32:01.487 /dev/ttyUSB0 write.
> > 2023/04/14 08:32:01.487 /dev/ttyUSB0 write 8
> >
> > 05 03 00 35 00 04 55 83
> > 2023/04/14 08:32:01.487 wrote 8 to /dev/ttyUSB0, return asynSuccess
> > 2023/04/14 08:32:01.487 asynOctetSyncIO wrote:
> >
> > 05 03 00 35 00 04
> > 2023/04/14 08:32:01.487 /dev/ttyUSB0 read.
> > 2023/04/14 08:32:01.495 /dev/ttyUSB0 read 13
> >
> > 05 03 08 d0 11 d2 00 d2 00 d2 11 3b 1c
> > 2023/04/14 08:32:01.495 /dev/ttyUSB0 read 13, return 0
> > 2023/04/14 08:32:01.495 SenecaBus read 13 bytes eom=0
> >
> > 05 03 08 d0 11 d2 00 d2 00 d2 11 3b 1c
> > 2023/04/14 08:32:01.495 asynOctetSyncIO read:
> >
> > 03 08 d0 11 d2 00 d2 00 d2 11
> > 2023/04/14 08:32:01.495 SenecaBus queueUnlockPort
> > 2023/04/14 08:32:01.495 SenecaBus asynManager::queueUnlockPort
> > waiting for event
> > 2023/04/14 08:32:01.495 SenecaBus queueUnlockPort unlock mutex 0x55ec3aba5eb0 complete.
> > ...
> >
> > So I'm getting the requested registers back on that port, and you can see their values there. d0 11 is 1101000000010001 in binary, so when I look at the 15th bit, it should return back a 1. when I do a caget on that PV, I get a
0 (I get 0's for all of the records associated with these registers).
> >
> > Is it supposed to say "asynSuccess" at the end of the highlighted section? I get a "return 0".
> >
> >
> > Thanks for helping me troubleshoot.
> >
> > Dale
> >
> >
> > On Thu, Apr 13, 2023 at 4:38 PM Mark Rivers <rivers at cars.uchicago.edu> wrote:
> > Hi Dale,
> >
> >
> >
> > • My issue is that the PV values aren't being updated when the IOC starts -- meaning that after the IOC start, the bo and mbbo values stored in that register don't match what was returned via the initial modbus request.
> >
> >
> > I am not sure I completely understand what you are saying. Here is what should happen:
> >
> >
> >
> > • Because this port you created uses function code 6 (write single register) and because you have a non-zero poll time, the driver will do one initial read of that register using function code 3.
> > • EPICS device support for the bo records does a read operation from the port during init_record. If this read returns asynSuccess (which it should) then the value of the bo record is set to the value read from the driver.
This is the “bumpless reboot” concept.
> > • You have not set PINI=YES in these records, so the value from the record will not be written back to the device during iocInit. However, the record value should still match the device, because of steps 1 and 2 above.
> >
> >
> > If I understand correctly you are saying that the bo record does have the correct value read from the device during steps 1-2. But now the device has a different value from that in the record? I don’t understand that, since it
seems like there must have been a write to the device to change the value?
> >
> >
> >
> > Mark
> >
> >
> >
> >
> >
> > From: Tech-talk <tech-talk-bounces at aps.anl.gov> On Behalf Of Dale
> > Cox via Tech-talk
> > Sent: Thursday, April 13, 2023 8:29 AM
> > To: tech-talk at aps.anl.gov
> > Subject: modbus ioc start
> >
> >
> >
> > Good Morning,
> >
> >
> >
> > I have an IOC that is currently reading registers via modbus rtu over rs485. There are a set of registers that store multiple configuration options in a single register. I set up the port using this line:
> >
> >
> >
> > > drvModbusAsynConfigure("Z8TC1_Config", "SenecaBus", 5, 6, 53, 4,
> > > "UINT16", 100, "SenecaZ")
> >
> >
> >
> > I've enabled the debugging lines on this IOC. When the IOC starts, I can see that the correct registers are being retrieved when the port is created. I can also write config changes to those registers at their assigned PV's with
no issues that I have found. My issue is that the PV values aren't being updated when the IOC starts -- meaning that after the IOC start, the bo and mbbo values stored in that register don't match what was returned via the initial modbus request.
> >
> >
> >
> > Here are a couple of the DB entries that I'm using:
> >
> >
> >
> > record(bo,"$(P)$(R)-TC1_enable") {
> > field(DTYP,"asynUInt32Digital")
> > field(OUT,"@asynMask($(PORT), 0, 0x8000 )")
> > field(ZNAM,"Disabled")
> > field(ONAM,"Enabled")
> > }
> >
> > record(bo,"$(P)$(R)-TC2_enable") {
> > field(DTYP,"asynUInt32Digital")
> > field(OUT,"@asynMask($(PORT), 0, 0x4000 )")
> > field(ZNAM,"Disabled")
> > field(ONAM,"Enabled")
> > }
> >
> > record(bo,"$(P)$(R)-TC1-2_units") {
> > field(DTYP,"asynUInt32Digital")
> > field(OUT,"@asynMask($(PORT), 0, 0x2000 )")
> > field(ZNAM,"tempDegC")
> > field(ONAM,"mV")
> > }
> >
> >
> >
> > Any help is appreciated.
> >
> >
> >
> > Dale
> >
> >
> >
> > --
> >
> > Dale Cox
> >
> > Instrumentation and Electrical Engineer
> >
> > ACU NEXT Lab
> >
>