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  <20102011  2012  2013  2014  2015  2016  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  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: RE: Analog output device support design
From: "Mark Rivers" <[email protected]>
To: "Ralph Lange" <[email protected]>, "EPICS tech-talk" <[email protected]>
Date: Wed, 28 Jul 2010 11:38:18 -0500
I generally agree with Ralph that if you are just supporting the ao
record with your DAC that asyn may be overkill.

On the other hand, my asyn driver for the Industry Pack dac128V is only
161 lines of code total (the source is appended).  It uses the
asynPortDriver C++ base class.  I think it may be a challenge to write
device support for your new DAC in only 161 lines of code.

Moreover, the advantage of this driver is that by implementing the
standard asynInt32 and asynFloat64 interfaces this driver can be called
from code other than just the ao record device support.  In particular
it can be, and is, called from the fast device support for the EPID
(fast feedback) record.  This means that I can drive the DAC at kHz
rates to close a feedback loop without having the overhead of processing
an ao record at those rates.

Mark

corvette:dac128V/dac128VApp/src>more drvDac128V.cpp 

/* drvDac128V.cpp
 * Driver for Systran DAC-128V using asynPortDriver base class
*/

#include <asynPortDriver.h>
#include <drvIpac.h>
#include <iocsh.h>
#include <epicsExport.h>

#define SYSTRAN_ID 0x45
#define SYSTRAN_DAC128V 0x69
#define MAX_CHANNELS 8

static const char *driverName = "DAC128V";

/** This is the class definition for the DAC128V class
  */
class DAC128V : public asynPortDriver {
public:
    DAC128V(const char *portName, int carrier, int slot);

    /* These are the methods that we override from asynPortDriver */
    virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32
value);
    virtual asynStatus readInt32(asynUser *pasynUser, epicsInt32
*value);
    virtual asynStatus getBounds(asynUser *pasynUser, epicsInt32 *low,
epicsInt32 *high);
    virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64
value);
    virtual asynStatus readFloat64(asynUser *pasynUser, epicsFloat64
*value);
    virtual void report(FILE *fp, int details);

protected:
    int DAC128V_Data;       /**< (asynInt32, asynFloat64,    r/w) DAC
output value in device units */
    #define FIRST_DAC_PARAM DAC128V_Data
    #define LAST_DAC_PARAM DAC128V_Data
    
private:
    int lastChan;
    int maxValue;
    volatile unsigned short* regs;    
};


#define DAC128VDataString  "DATA"

#define NUM_PARAMS (&LAST_DAC_PARAM - &FIRST_DAC_PARAM + 1)

DAC128V::DAC128V(const char *portName, int carrier, int slot)
    : asynPortDriver(portName, MAX_CHANNELS, NUM_PARAMS, 
          asynInt32Mask | asynFloat64Mask | asynDrvUserMask,
          asynInt32Mask | asynFloat64Mask, 
          ASYN_MULTIDEVICE, 1, /* ASYN_CANBLOCK=0, ASYN_MULTIDEVICE=1,
autoConnect=1 */
          0, 0)  /* Default priority and stack size */
{
    static const char *functionName = "DAC128V";

    createParam(DAC128VDataString, asynParamInt32, &DAC128V_Data);
    
    if (ipmValidate(carrier, slot, SYSTRAN_ID, SYSTRAN_DAC128V) != 0) {
       asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
            "%s:%s: module not found in carrier %d slot %d\n",
            driverName, functionName, carrier, slot);
    } else {
        this->regs = (unsigned short *) ipmBaseAddr(carrier, slot,
ipac_addrIO);
    }

    /* lastChan and maxValue could be set by looking at "model" in the
future
     * if models with more channels or more bits are available */
    this->lastChan = 7;
    this->maxValue = 4095;
}

asynStatus DAC128V::writeInt32(asynUser *pasynUser, epicsInt32 value)
{
    int channel;
    static const char *functionName = "writeInt32";

    this->getAddress(pasynUser, &channel);
    if(value<0 || value>this->maxValue || channel<0 ||
channel>this->lastChan)
        return(asynError);
    this->regs[channel] = value;
    asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, 
              "%s:%s, port %s, wrote %d to channel %d\n",
              driverName, functionName, this->portName, value, channel);
    return(asynSuccess);
}

asynStatus DAC128V::getBounds(asynUser *pasynUser, epicsInt32 *low,
epicsInt32 *high)
{
    *low = 0;
    *high = this->maxValue;
    return(asynSuccess);
}

asynStatus DAC128V::writeFloat64(asynUser *pasynUser, epicsFloat64
value)
{
   return(this->writeInt32(pasynUser, (epicsInt32) value));
}

asynStatus DAC128V::readInt32(asynUser *pasynUser, epicsInt32 *value)
{
    int channel;
    static const char *functionName = "readInt32";

    this->getAddress(pasynUser, &channel);
    if(channel<0 || channel>this->lastChan) return(asynError);
    *value=this->regs[channel];
    asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, 
              "%s:%s, port %s, read %d from channel %d\n",
              driverName, functionName, this->portName, *value,
channel);
    return(asynSuccess);
}

asynStatus DAC128V::readFloat64(asynUser *pasynUser, epicsFloat64
*value)
{
    epicsInt32 ivalue;
    asynStatus status;

    status = this->readInt32(pasynUser, &ivalue);
    *value = (epicsFloat64)ivalue;
    return(status);
}

/* Report  parameters */
void DAC128V::report(FILE *fp, int details)
{
    asynPortDriver::report(fp, details);
    fprintf(fp, "  Port: %s, address %p\n", this->portName, this->regs);
    if (details >= 1) {
        fprintf(fp, "  lastChan=%d, maxValue=%d\n", 
                this->lastChan, this->maxValue);
    }
}

/** Configuration command, called directly or from iocsh */
extern "C" int initDAC128V(const char *portName, int carrier, int slot)
{
    DAC128V *pDAC128V = new DAC128V(portName, carrier, slot);
    pDAC128V = NULL;  /* This is just to avoid compiler warnings */
    return(asynSuccess);
}


static const iocshArg initArg0 = { "Port name",iocshArgString};
static const iocshArg initArg1 = { "Carrier",iocshArgInt};
static const iocshArg initArg2 = { "Slot",iocshArgInt};
static const iocshArg * const initArgs[3] = {&initArg0,
                                             &initArg1,
                                             &initArg2};
static const iocshFuncDef initFuncDef = {"initDAC128V",3,initArgs};
static void initCallFunc(const iocshArgBuf *args)
{
    initDAC128V(args[0].sval, args[1].ival, args[2].ival);
}

void drvDac128VRegister(void)
{
    iocshRegister(&initFuncDef,initCallFunc);
}

extern "C" {
epicsExportRegistrar(drvDac128VRegister);
}

-----Original Message-----
From: [email protected]
[mailto:[email protected]] On Behalf Of Ralph Lange
Sent: Wednesday, July 28, 2010 10:09 AM
To: EPICS tech-talk
Subject: Re: Analog output device support design


  Hmm...

The original question was about support for an D/A converter.

A D/A converter will hardly ever need support for anything else but an 
ao record.
As a VME based memory-mapped device, it typically does not need 
asynchronous support, and does not implement I/O Intr scanning.
It uses a fixed bit width, which is unlikely to change.

While Asyn is a very generic and powerful framework, in this case it 
does not provide much added value, while requiring a lot of reading and 
understanding of mechanisms and interfaces that are not applicable.

So I would repeat my suggestion of taking an existing Device Support 
module for another VME D/A card, and change the bits where your hardware

is different.
Only having Device Support is perfectly appropriate in this case, as 
there is no "bus" type connection (such as GPIB, serial etc.) that would

justify separating the driver for that bus from the driver for the 
device you are talking to.

Device Support for a VME based D/A converters is usually very simple, 
and with a simple "steal-and-adapt" approach you should be up and 
running in a very short time.

For supporting A/D converters, Mark's arguments are many and strong: 
clearly a case for Asyn.
(But I would save that for a moment when you are more experienced and 
more adventurous, and using Asyn has strong advantages.)

Just my 2 cents...
Ralph


On 26.07.2010 22:42, Mark Rivers wrote:
> I'd second Erics suggestion about writing an asyn driver, rather than
writing device support.  The standard asyn device support already takes
care of the complexities of handling I/O Intr scanning, etc.  For an ai
device it has support for averaging, i.e. your driver is calling back
with new values at 1 kHz, but the device support can average all the
readings between record processing at the standard periodic scan rates.
>
> By writing an asyn driver you free the developer to use whatever
records they chose; perhaps the standard ai record, but they could also
use the mca record to put the callback values into a time-series array,
or use the epid record to do fast feedback at the 1kHz callback rate
from your driver, etc.  That support is already written.
>
> Mark
>
>
> ________________________________
>
> From: [email protected] on behalf of Eric Norum
> Sent: Mon 7/26/2010 6:15 PM
> To: Angus Gratton
> Cc: EPICS tech-talk
> Subject: Re: Analog output device support design
>
>
>
> On Jul 26, 2010, at 4:00 PM, Angus Gratton wrote:
> ......
>> Yes, I understand. I've been working from the well documented minimal
>> example given in this presentation:
>>
>>
http://www.aps.anl.gov/epics/meetings/2009-07/talks/em_WritingEPICSDrive
rs.ppt
> That's a good set of instructions.
> If you need asynchronous device support I would suggest that you look
through the ASYN support module documentation.
> In fact I'd go so far as to recommend ASYN for VME register-based
synchronous access as well.  The 'devEpics' support provides a good way
to decouple your I/O support from particular record types.  The synApps
package contains the ASYN support module and lots of good drivers (e.g.
ip330) for existing VME hardware.   One of these might be a good place
to start modifying to match your hardware.
>
>> Outside of there, I've downloaded a few device support sources and
>> looked at them but to be honest it's hard to tell what is legacy and
>> what is a good example - lots of the sources haven't been touched in
>> many years, some of them do things like combine device support&  the
>> driver into the same source, which I understand is no longer
>> recommended. Which is why I thought I'd ask to be sure, because I'm
not
>> yet experienced enough to tell the difference between a good example
and
>> a bad one.
>>
>> Regards,
>>
>> Angus
>>
> --
> Eric Norum
> [email protected]
>


Replies:
RE: Analog output device support design Angus Gratton
References:
Analog output device support design Angus Gratton
Re: Analog output device support design Ralph Lange
Re: Analog output device support design Angus Gratton
Re: Analog output device support design Eric Norum
RE: Analog output device support design Mark Rivers
Re: Analog output device support design Ralph Lange

Navigate by Date:
Prev: Re: HTML Device Driver Pete Jemian
Next: RE: Developing of record / driver / device support? Asyn? Mark Rivers
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: Analog output device support design Ralph Lange
Next: RE: Analog output device support design Angus Gratton
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 02 Sep 2010 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·