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  <20152016  2017  2018  2019  2020  2021  2022  2023  2024  Index 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  <20152016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: RE: Read record field in asynDriver
From: Mark Rivers <[email protected]>
To: Ralph Lange <[email protected]>, EPICS Tech-Talk <[email protected]>
Date: Fri, 20 Feb 2015 15:22:19 +0000
> But the per-address call happens at the first processing of a record using the address, 
> not at initialization time. (Lazy initialization, if that was intended.)

It was intended, because asynManager is never told the maximum number of addresses that will be used.  It is just told ASYN_MULTIDEVICE and then discovers what addresses are actually in use as they are referenced.  This was intended for GPIB, for example, where only a certain number of addresses will be used.

asynPortDriver does require specifying the maximum number of addresses in the constructor, because it allocates fixed length tables in the constructor.

I'm glad you found a solution that works for you (and doesn't require any changes in asyn!).

Mark


________________________________________
From: [email protected] [[email protected]] on behalf of Ralph Lange [[email protected]]
Sent: Friday, February 20, 2015 9:13 AM
To: EPICS Tech-Talk
Subject: Re: Read record field in asynDriver

Hi Mark,

On 20/02/2015 15:50, Mark Rivers wrote:
>> The driver's connect() is only called once for the port, right?!
> No, that is not true.  It is called once per address.  I just added a printf in asynPortDriver::connect to print a message each time it is called with the address for which it was called.  This is the output for an ASYN_MULTIDEVICE driver in areaDetector:
>
> asynPortDriver::connect entry, port=ROISTAT1, addr=0
> asynPortDriver::connect entry, port=ROISTAT1, addr=1
> asynPortDriver::connect entry, port=ROISTAT1, addr=2
> asynPortDriver::connect entry, port=ROISTAT1, addr=3
> asynPortDriver::connect entry, port=ROISTAT1, addr=4
> asynPortDriver::connect entry, port=ROISTAT1, addr=5
> asynPortDriver::connect entry, port=ROISTAT1, addr=6
> asynPortDriver::connect entry, port=ROISTAT1, addr=7

That's correct.
But the per-address call happens at the first processing of a record
using the address, not at initialization time. (Lazy initialization, if
that was intended.)
In our case, this is happening too late - we need to do all the
by-address initialization calls before the first record processes.

>> During per-record-instance initialization, the port driver must call the
>> low level card driver with one configuration call per channel, using
>> board number, channel number, and range (record's EGUL, EGUF) as parameters.
> What if the user wants to change the range of that ADC after iocInit?  So they want to change the range of the ADC and also change EGUL and EGUF to match?  Then you want to have a record that pushes those new values down to the driver.  It seems to me that EGUL and EGUF are just another case of a driver parameter.  You might also want to change some gain, filtering, etc. for the driver.  Each of those configurable items should have a record that pushes the configuration to the driver.  If you really don't want the user changing them then set them with PINI=YES and hide the records from the user?  Or if you really don't want records, then have a driver configuration command per channel?

I completely agree for driver parameters that you want to (and are able
to) change at run time.

But: these updates will come separately, and later - there's a good
chance that the record will start sampling a channel before our driver
has the data it needs to configure it. (Note that the CP links in your
original example further delays pushing the parameter as the CA thread
that is running the pusher record is of lower priority than any periodic
scan.)

For our application, using the info items and an initHook routine seems
the most simple and appropriate solution.

Thanks for your comments!
~Ralph


> ________________________________________
> From: [email protected] [[email protected]] on behalf of Ralph Lange [[email protected]]
> Sent: Thursday, February 19, 2015 8:26 AM
> To: EPICS Tech-Talk
> Subject: Re: Read record field in asynDriver
>
> Hi Mark,
>
> We are facing a similar issue:
>
> Our ASYN port driver for a DAQ board is modelling the board and its
> channels as a multi device, with port=board and addr=channel.
>
> During per-record-instance initialization, the port driver must call the
> low level card driver with one configuration call per channel, using
> board number, channel number, and range (record's EGUL, EGUF) as parameters.
>
> What would be your approach for that?
>
> Your intermediate record hack does not work nicely (in addition to being
> somewhat ugly), as the parameter values would come in too late and
> separately, and the addr=channel number is not contained in a field of
> the "main" record.
>
> The driver's connect() is only called once for the port, right?!
> Couldn't that be complemented with a routine that is called once per
> addr for multi devices, and gets the addr and maybe a pointer to the
> parameter field of the link that it is being called for? (We'd be happy
> to cram the necessary low level config params into the link config, and
> have the driver pull it out.)
> Alternatively, probably cleaner and more flexible, you could allow a
> special info field for asyn driver configuration options to be added to
> the record, and pass a a pointer to its string value when calling the
> driver for each addr.
>
> What do you think?
>
> Thanks for your help,
> ~Ralph
>
>
> On 02/02/2015 23:36, Mark Rivers wrote:
>> There is no direct communicaton possible between the NELM field of the waveform record and the asyn driver.  However, it is easy to do using an intermediate longout record, for example:
>>
>> record(longout,"$(P)$(R)NELM1") {
>>       field(DOL,  "$(P)$(R)Waveform1.NELM CP MS")
>>       field(OMSL, "closed_loop")
>>       field(DTYP, "asynInt32")
>>       field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))WAVEFORM_NELM1")
>> }
>>
>> record(longout,"$(P)$(R)NELM2") {
>>       field(DOL,  "$(P)$(R)Waveform2.NELM CP MS")
>>       field(OMSL, "closed_loop")
>>       field(DTYP, "asynInt32")
>>       field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))WAVEFORM_NELM2")
>> }
>>
>> These longout records  will process whenever the NELM fields change, including once at iocInit.
>>
>> They will send the NELM field of the appropriate waveform record to you driver.  You just need to treat the writes with 2 different pasynUser->reason values differently.  If it is the one corresponding to WAVEFORM_NELM1 do one thing, and do something different if it is for WAVEFORM_NELM2.
>>
>> Mark



References:
Read record field in asynDriver Vikram Bhagat
RE: Read record field in asynDriver Mark Rivers
Re: Read record field in asynDriver Ralph Lange
RE: Read record field in asynDriver Mark Rivers
Re: Read record field in asynDriver Ralph Lange

Navigate by Date:
Prev: Re: RRM offline? J. Lewis Muir
Next: Re: RRM offline? Andrew Johnson
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  <20152016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: Read record field in asynDriver Ralph Lange
Next: Strawberry Perl Make still broken? J. Lewis Muir
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  <20152016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 16 Dec 2015 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·