IOCINFRAApp/src/drvAsynKeithley648x.cpp
changeset 0 77d8eafe2a07
equal deleted inserted replaced
-1:000000000000 0:77d8eafe2a07
       
     1 /*
       
     2  Description
       
     3     This module provides support for a multiple device port driver. To
       
     4     initialize the driver, the method drvAsynKeithley6485() is called from the
       
     5     startup script with the following calling sequence.
       
     6 
       
     7         drvAsynKeithley6485(myport,ioport,ioaddr)
       
     8 
       
     9         Where:
       
    10             myport - Keithley6485 Asyn interface port driver name (i.e. "EP0" )
       
    11             ioport - Communication port driver name (i.e. "S0" )
       
    12             ioaddr - Communication port device addr
       
    13 
       
    14     The method dbior can be called from the IOC shell to display the current
       
    15     status of the driver.
       
    16 */
       
    17 
       
    18 
       
    19 /* System related include files */
       
    20 #include <math.h>
       
    21 #include <stdio.h>
       
    22 #include <stdlib.h>
       
    23 #include <string.h>
       
    24 
       
    25 
       
    26 /* EPICS system related include files */
       
    27 #include <iocsh.h>
       
    28 #include <epicsStdio.h>
       
    29 #include <cantProceed.h>
       
    30 #include <epicsString.h>
       
    31 #include <epicsExport.h>
       
    32 #include <errlog.h>
       
    33 
       
    34 /* EPICS synApps/Asyn related include files */
       
    35 #include <asynDriver.h>
       
    36 #include <asynDrvUser.h>
       
    37 #include <asynInt32.h>
       
    38 #include <asynFloat64.h>
       
    39 #include <asynOctet.h>
       
    40 #include <asynOctetSyncIO.h>
       
    41 #include <asynStandardInterfaces.h>
       
    42 
       
    43 /* Define symbolic constants */
       
    44 #define TIMEOUT         (5.0)
       
    45 #define BUFFER_SIZE     (100)
       
    46 
       
    47 
       
    48 typedef enum {Octet=1, Float64=2, Int32=3} Type;
       
    49 
       
    50 static const char *driver = "drvAsynKeithley648x";      /* String for asynPrint */
       
    51 
       
    52 
       
    53 /* Declare port driver structure */
       
    54 struct Port
       
    55 {
       
    56   int devtype; // 1:6485, 2:6487
       
    57   char* myport;
       
    58   char* ioport;
       
    59   int ioaddr;
       
    60 
       
    61   int init; // really needed??
       
    62 
       
    63   char model[BUFFER_SIZE+1], *serial, *dig_rev, *disp_rev, *brd_rev;
       
    64 
       
    65   struct
       
    66   {
       
    67     int ioErrors;
       
    68     int writeReads;
       
    69     int writeOnlys;
       
    70   } stats;
       
    71 
       
    72   struct
       
    73   {
       
    74     double reading;
       
    75     int timestamp;
       
    76     union 
       
    77     {
       
    78       int raw;
       
    79       struct 
       
    80       {
       
    81         unsigned int overflow             : 1;
       
    82         unsigned int filter_enabled       : 1;
       
    83         unsigned int math_enabled         : 1;
       
    84         unsigned int null_enabled         : 1;
       
    85         unsigned int limit_test           : 1;
       
    86         unsigned int limit_result         : 2;
       
    87         unsigned int overvoltage          : 1;
       
    88         unsigned int padding              : 1;
       
    89         unsigned int zero_check_enabled   : 1;
       
    90         unsigned int zero_correct_enabled : 1;
       
    91       } bits;
       
    92     } status;
       
    93     /* 
       
    94        Bits:
       
    95        0 (OFLO)   — Set to 1 if measurement performed while in over-range 
       
    96                     (overflowed reading).
       
    97        1 (Filter) — Set to 1 when measurement performed with the averaging 
       
    98                     filter enabled.
       
    99        2 (Math)   — Set to 1 when measurement performed with CALC1 enabled.
       
   100        3 (Null)   — Set to 1 if null for CALC2 is enabled.
       
   101        4 (Limits) — Set to 1 if a limit test (CALC2) is enabled.
       
   102        5 & 6 (Limit Results) — Provides limit test results:
       
   103                 Bit 6    Bit 5   
       
   104                   0        0      All limit tests passed
       
   105                   0        1      CALC2:LIM1 test failed
       
   106                   1        0      CALC2:LIM2 test failed
       
   107        7 (Overvoltage)  — Set to 1 if measurement performed with an 
       
   108                           overvoltage condition on the input.
       
   109        9 (Zero Check)   — Set to 1 when zero check is enabled.
       
   110       10 (Zero Correct) — Set to 1 when zero correct is enabled.
       
   111     */
       
   112     int eom;
       
   113   } data;
       
   114 
       
   115   /* Asyn info */
       
   116   asynUser *pasynUser;
       
   117   asynUser *pasynUserTrace;  /* asynUser for asynTrace on this port */
       
   118   asynStandardInterfaces asynStdInterfaces;
       
   119 };
       
   120 
       
   121 
       
   122 struct Command
       
   123 {
       
   124   const char *tag;
       
   125   int dev;
       
   126   int type;
       
   127   int id;
       
   128 };
       
   129 
       
   130 
       
   131 /* Declare command structure */
       
   132 struct GenCommand
       
   133 {
       
   134   asynStatus (*readFunc)(int which, Port *pport, void* data, Type Iface, 
       
   135                          size_t *length, int *eom);
       
   136   asynStatus (*writeFunc)(int which, Port *pport, void* data, Type Iface);
       
   137 };
       
   138 
       
   139 struct SimpleCommand
       
   140 {
       
   141   int type;
       
   142   const char *cmd_str;
       
   143 };
       
   144 
       
   145 /* Public interface forward references */
       
   146 int drvAsynKeithley648x(const char* myport,const char* ioport, int ioaddr);
       
   147 
       
   148 
       
   149 /* Forward references for asynCommon methods */
       
   150 static void report(void* ppvt,FILE* fp,int details);
       
   151 static asynStatus connect(void* ppvt,asynUser* pasynUser);
       
   152 static asynStatus disconnect(void* ppvt,asynUser* pasynUser);
       
   153 static asynCommon ifaceCommon = {report,connect,disconnect};
       
   154 
       
   155 /* Forward references for asynDrvUser methods */
       
   156 static asynStatus create(void* ppvt,asynUser* pasynUser,const char* drvInfo,
       
   157                          const char** pptypeName,size_t* psize);
       
   158 static asynStatus destroy(void* ppvt,asynUser* pasynUser);
       
   159 static asynStatus gettype(void* ppvt,asynUser* pasynUser,
       
   160                           const char** pptypeName,size_t* psize);
       
   161 static asynDrvUser ifaceDrvUser = {create,gettype,destroy};
       
   162 
       
   163 /* Forward references for asynFloat64 methods */
       
   164 static asynStatus readFloat64(void* ppvt,asynUser* pasynUser,
       
   165                               epicsFloat64* value);
       
   166 static asynStatus writeFloat64(void* ppvt,asynUser* pasynUser,
       
   167                                epicsFloat64 value);
       
   168 static asynFloat64 ifaceFloat64 = {writeFloat64, readFloat64};
       
   169 
       
   170 /* Forward references for asynInt32 methods */
       
   171 static asynStatus readInt32(void* ppvt,asynUser* pasynUser,epicsInt32* value);
       
   172 static asynStatus writeInt32(void* ppvt,asynUser* pasynUser,epicsInt32 value);
       
   173 static asynInt32 ifaceInt32 =  {writeInt32, readInt32};
       
   174 
       
   175 /* Forward references for asynOctet methods */
       
   176 static asynStatus flushOctet( void* ppvt, asynUser* pasynUser);
       
   177 static asynStatus writeOctet( void* ppvt, asynUser* pasynUser, const char *data,
       
   178                               size_t numchars, size_t* nbytes);
       
   179 static asynStatus readOctet( void* ppvt, asynUser* pasynUser, char* data,
       
   180                              size_t maxchars, size_t *nbytes, int *eom);
       
   181 static asynOctet ifaceOctet = { writeOctet, readOctet, flushOctet};
       
   182 
       
   183 
       
   184 /* Forward references for external asynOctet interface */
       
   185 static asynStatus writeOnly(Port* pport, const char* outBuf);
       
   186 static asynStatus writeRead(Port* pport, const char* outBuf, char* inpBuf,
       
   187                             int inputSize, int *eomReason);
       
   188 
       
   189 
       
   190 static asynStatus readDummy(int which, Port *pport, void *data, Type Iface, 
       
   191                             size_t *length, int *eom);
       
   192 static asynStatus writeDummy(int which, Port *pport, void* data, Type Iface);
       
   193 
       
   194 static asynStatus readSimpleData( int which, Port *pport, void *data, 
       
   195                                   Type Iface, size_t *length, int *eom);
       
   196 static asynStatus writeSimpleData( int which, Port *pport, void *data, 
       
   197                                    Type Iface);
       
   198 
       
   199 static asynStatus readCache(int which, Port *pport, void *data, 
       
   200                             Type Iface, size_t *length, int *eom);
       
   201 
       
   202 static asynStatus readSensorReading(int which, Port *pport, void* data, 
       
   203                                     Type Iface, size_t *length, int *eom);
       
   204 static asynStatus readRange(int which, Port *pport, void* data, 
       
   205                             Type Iface, size_t *length, int *eom);
       
   206 static asynStatus writeRange(int which, Port *pport, void* data, Type Iface);
       
   207 static asynStatus readRate(int which, Port *pport, void* data, 
       
   208                            Type Iface, size_t *length, int *eom);
       
   209 static asynStatus writeRate(int which, Port *pport, void* data, Type Iface);
       
   210 static asynStatus readVoltageSettings(int which, Port *pport, void* data, 
       
   211                                             Type Iface, size_t *length, int *eom);
       
   212 static asynStatus writeVoltageSettings(int which, Port *pport, void* data, 
       
   213                                               Type Iface);
       
   214 static asynStatus readCommon(int which, Port *pport, void* data, 
       
   215                              Type Iface, size_t *length, int *eom);
       
   216 static asynStatus writeCommon(int which, Port *pport, void* data, Type Iface);
       
   217 
       
   218 
       
   219 
       
   220 
       
   221 // General commands that need special attention go here
       
   222 enum { VOID_CMD, READ_CMD, RANGE_CMD, RANGE_AUTO_ULIMIT_CMD, 
       
   223        RANGE_AUTO_LLIMIT_CMD, RATE_CMD, DIGITAL_FILTER_CONTROL_CMD,
       
   224        VOLTAGE_RANGE_CMD, VOLTAGE_CURRENT_LIMIT_CMD,      GEN_CMD_NUMBER };
       
   225 static GenCommand genCommandTable[GEN_CMD_NUMBER] = 
       
   226   {
       
   227     { readDummy,           writeDummy},     // VOID
       
   228     { readSensorReading,   writeDummy},     // READ
       
   229     { readRange,           writeRange},     // RANGE
       
   230     { readRange,           writeRange},     // RANGE_AUTO_ULIMIT
       
   231     { readRange,           writeRange},     // RANGE_AUTO_LLIMIT
       
   232     { readRate,            writeRate},      // RATE
       
   233     { readCommon,          writeCommon},    // DIGITAL_FILTER_CONTROL
       
   234     { readVoltageSettings, writeVoltageSettings}, // VOLTAGE_RANGE_COMMAND
       
   235     { readVoltageSettings, writeVoltageSettings}, // VOLTAGE_CURRENT_LIMIT_COMMAND
       
   236   };
       
   237 
       
   238 // commands that are very simple-minded go here
       
   239 enum { RESET_CMD, RANGE_AUTO_CMD,
       
   240        ZERO_CHECK_CMD, ZERO_CORRECT_CMD, ZERO_CORRECT_ACQUIRE_CMD, 
       
   241        MEDIAN_FILTER_CMD, MEDIAN_FILTER_RANK_CMD, 
       
   242        DIGITAL_FILTER_CMD, DIGITAL_FILTER_COUNT_CMD, 
       
   243        VOLTAGE_CMD, VOLTAGE_STATE_CMD, VOLTAGE_10V_INTERLOCK_CMD, VOLTAGE_INTERLOCK_STATUS_CMD,
       
   244        SIMPLE_CMD_NUMBER};
       
   245 
       
   246 enum { SIMPLE_TRIGGER=0, SIMPLE_OCTET=Octet, SIMPLE_FLOAT64=Float64, 
       
   247        SIMPLE_INT32=Int32 };
       
   248 static SimpleCommand simpleCommandTable[SIMPLE_CMD_NUMBER] = 
       
   249   {
       
   250     { SIMPLE_TRIGGER, "*RST"},                // RESET DEVICE
       
   251 
       
   252     { SIMPLE_INT32,   ":RANGE:AUTO"},         // RANGE_AUTO
       
   253 
       
   254     { SIMPLE_INT32,   "SYST:ZCH"},            // ZERO CHECK
       
   255     { SIMPLE_INT32,   "SYST:ZCOR"},           // ZERO CORRECT
       
   256     { SIMPLE_TRIGGER, "SYST:ZCOR:ACQ"},       // ZERO CORRECT ACQUIRE
       
   257 
       
   258     { SIMPLE_INT32,   "MED"},                 // MEDIAN FILTER
       
   259     { SIMPLE_INT32,   "MED:RANK"},            // MEDIAN FILTER RANK
       
   260 
       
   261     { SIMPLE_INT32,   "AVER"},                // DIGITAL FILTER
       
   262     { SIMPLE_INT32,   "AVER:COUN"},           // DIGITAL FILTER COUNT
       
   263 
       
   264     { SIMPLE_FLOAT64, "SOUR:VOLT"},           // VOLTAGE
       
   265     { SIMPLE_INT32,   "SOUR:VOLT:STAT"},      // VOLTAGE STATE
       
   266     { SIMPLE_INT32,   "SOUR:VOLT:INT"},       // VOLTAGE 10V INTERLOCK
       
   267     { SIMPLE_INT32,   "SOUR:VOLT:INT:FAIL"},  // VOLTAGE INTERLOCK STATUS
       
   268 
       
   269     // { SIMPLE_INT32,   "AVER:"},      // 
       
   270     // { SIMPLE_INT32,   "AVER:"},      // 
       
   271   };
       
   272 
       
   273 
       
   274 enum { TIMESTAMP_CMD, STATUS_RAW_CMD, STATUS_OVERFLOW_CMD, STATUS_FILTER_CMD, 
       
   275        STATUS_MATH_CMD, STATUS_NULL_CMD, STATUS_LIMITS_CMD, 
       
   276        STATUS_OVERVOLTAGE_CMD, STATUS_ZERO_CHECK_CMD, STATUS_ZERO_CORRECT_CMD,
       
   277        MODEL_CMD, SERIAL_CMD, DIG_REV_CMD, DISP_REV_CMD, BRD_REV_CMD, 
       
   278        CACHE_CMD_NUMBER };
       
   279 
       
   280 #define COMMAND_NUMBER (GEN_CMD_NUMBER + SIMPLE_CMD_NUMBER + CACHE_CMD_NUMBER)
       
   281 
       
   282 enum { CMD_GEN, CMD_SIMPLE, CMD_CACHE };
       
   283 enum { DEV_ALL, DEV_6485, DEV_6487};
       
   284 static Command commandTable[ COMMAND_NUMBER ] = 
       
   285   {
       
   286     { "VOID",                     DEV_ALL,  CMD_GEN,    VOID_CMD                     },
       
   287     { "READ",                     DEV_ALL,  CMD_GEN,    READ_CMD                     },
       
   288     { "RANGE",                    DEV_ALL,  CMD_GEN,    RANGE_CMD                    },
       
   289     { "RANGE_AUTO_ULIMIT",        DEV_ALL,  CMD_GEN,    RANGE_AUTO_ULIMIT_CMD        },
       
   290     { "RANGE_AUTO_LLIMIT",        DEV_ALL,  CMD_GEN,    RANGE_AUTO_LLIMIT_CMD        },
       
   291     { "RATE",                     DEV_ALL,  CMD_GEN,    RATE_CMD                     },
       
   292     { "DIGITAL_FILTER_CONTROL",   DEV_ALL,  CMD_GEN,    DIGITAL_FILTER_CONTROL_CMD   },
       
   293     { "VOLTAGE_RANGE",            DEV_6487, CMD_GEN,    VOLTAGE_RANGE_CMD            },
       
   294     { "VOLTAGE_CURRENT_LIMIT",    DEV_6487, CMD_GEN,    VOLTAGE_CURRENT_LIMIT_CMD    },
       
   295     { "RESET",                    DEV_ALL,  CMD_SIMPLE, RESET_CMD                    },
       
   296     { "RANGE_AUTO",               DEV_ALL,  CMD_SIMPLE, RANGE_AUTO_CMD               },
       
   297     { "ZERO_CHECK",               DEV_ALL,  CMD_SIMPLE, ZERO_CHECK_CMD               },
       
   298     { "ZERO_CORRECT",             DEV_ALL,  CMD_SIMPLE, ZERO_CORRECT_CMD             },
       
   299     { "ZERO_CORRECT_ACQUIRE",     DEV_ALL,  CMD_SIMPLE, ZERO_CORRECT_ACQUIRE_CMD     },
       
   300     { "MEDIAN_FILTER",            DEV_ALL,  CMD_SIMPLE, MEDIAN_FILTER_CMD            },
       
   301     { "MEDIAN_FILTER_RANK",       DEV_ALL,  CMD_SIMPLE, MEDIAN_FILTER_RANK_CMD       },
       
   302     { "DIGITAL_FILTER",           DEV_ALL,  CMD_SIMPLE, DIGITAL_FILTER_CMD           },
       
   303     { "DIGITAL_FILTER_COUNT",     DEV_ALL,  CMD_SIMPLE, DIGITAL_FILTER_COUNT_CMD     },
       
   304     { "VOLTAGE",                  DEV_6487, CMD_SIMPLE, VOLTAGE_CMD                  },
       
   305     { "VOLTAGE_STATE",            DEV_6487, CMD_SIMPLE, VOLTAGE_STATE_CMD            },
       
   306     { "VOLTAGE_TENV_INTERLOCK",   DEV_6487, CMD_SIMPLE, VOLTAGE_10V_INTERLOCK_CMD    },
       
   307     { "VOLTAGE_INTERLOCK_STATUS", DEV_6487, CMD_SIMPLE, VOLTAGE_INTERLOCK_STATUS_CMD },
       
   308     { "MODEL",                    DEV_ALL,  CMD_CACHE,  MODEL_CMD                    },
       
   309     { "SERIAL",                   DEV_ALL,  CMD_CACHE,  SERIAL_CMD                   },
       
   310     { "DIG_REV",                  DEV_ALL,  CMD_CACHE,  DIG_REV_CMD                  },
       
   311     { "DISP_REV",                 DEV_ALL,  CMD_CACHE,  DISP_REV_CMD                 },
       
   312     { "BRD_REV",                  DEV_ALL,  CMD_CACHE,  BRD_REV_CMD                  },
       
   313     { "TIMESTAMP",                DEV_ALL,  CMD_CACHE,  TIMESTAMP_CMD                },
       
   314     { "STATUS_RAW",               DEV_ALL,  CMD_CACHE,  STATUS_RAW_CMD               },
       
   315     { "STATUS_OVERFLOW",          DEV_ALL,  CMD_CACHE,  STATUS_OVERFLOW_CMD          },
       
   316     { "STATUS_FILTER",            DEV_ALL,  CMD_CACHE,  STATUS_FILTER_CMD            },
       
   317     { "STATUS_MATH",              DEV_ALL,  CMD_CACHE,  STATUS_MATH_CMD              },
       
   318     { "STATUS_NULL",              DEV_ALL,  CMD_CACHE,  STATUS_NULL_CMD              },
       
   319     { "STATUS_LIMITS",            DEV_ALL,  CMD_CACHE,  STATUS_LIMITS_CMD            },
       
   320     { "STATUS_OVERVOLTAGE",       DEV_ALL,  CMD_CACHE,  STATUS_OVERVOLTAGE_CMD       },
       
   321     { "STATUS_ZERO_CHECK",        DEV_ALL,  CMD_CACHE,  STATUS_ZERO_CHECK_CMD        },
       
   322     { "STATUS_ZERO_CORRECT",      DEV_ALL,  CMD_CACHE,  STATUS_ZERO_CORRECT_CMD      },
       
   323   };
       
   324 
       
   325 
       
   326 
       
   327 /****************************************************************************
       
   328  * Define public interface methods
       
   329  ****************************************************************************/
       
   330 int drvAsynKeithley648x(const char *type, const char *myport,
       
   331                         const char *ioport, int ioaddr)
       
   332 {
       
   333   int status = asynSuccess;
       
   334   Port* pport;
       
   335   //  int i;
       
   336   asynStandardInterfaces *pInterfaces;
       
   337 
       
   338   char inpBuf[BUFFER_SIZE];
       
   339   int eomReason;
       
   340 
       
   341   pport = (Port*)callocMustSucceed(1,sizeof(Port),"drvAsynKeithley6485");
       
   342   pport->myport = epicsStrDup(myport);
       
   343   pport->ioport = epicsStrDup(ioport);
       
   344   pport->ioaddr = ioaddr;
       
   345 
       
   346   pport->devtype = DEV_ALL;
       
   347   if( !strcmp("6485", type))
       
   348     pport->devtype = DEV_6485;
       
   349   if( !strcmp("6487", type))
       
   350     pport->devtype = DEV_6487;
       
   351   if(pport->devtype == DEV_ALL) // DEV_ALL is not a real device
       
   352     {
       
   353       errlogPrintf("%s::drvAsynKeithley6485 type has to be "
       
   354                    "either \'6485\' or \'6487\'.\n", driver);
       
   355       return asynError;
       
   356     }
       
   357 
       
   358 
       
   359   status = pasynOctetSyncIO->connect(ioport,ioaddr,&pport->pasynUser,NULL);
       
   360   if (status != asynSuccess)
       
   361     {
       
   362       errlogPrintf("%s::drvAsynKeithley6485 port %s can't connect "
       
   363                    "to asynCommon on Octet server %s address %d.\n",
       
   364                    driver, myport, ioport, ioaddr);
       
   365       return asynError;
       
   366     }
       
   367 
       
   368   /* Create asynUser for asynTrace */
       
   369   pport->pasynUserTrace = pasynManager->createAsynUser(0, 0);
       
   370   pport->pasynUserTrace->userPvt = pport;
       
   371 
       
   372   status = pasynManager->registerPort(myport,ASYN_CANBLOCK,1,0,0);
       
   373   if( status != asynSuccess) 
       
   374     {
       
   375       errlogPrintf("%s::drvAsynKeithley6485 port %s can't register port\n",
       
   376                    driver, myport);
       
   377       return asynError;
       
   378     }
       
   379 
       
   380   pInterfaces = &pport->asynStdInterfaces;
       
   381     
       
   382   /* Initialize interface pointers */
       
   383   pInterfaces->common.pinterface    = (void *)&ifaceCommon;
       
   384   pInterfaces->drvUser.pinterface   = (void *)&ifaceDrvUser;
       
   385   pInterfaces->octet.pinterface     = (void *)&ifaceOctet;
       
   386   pInterfaces->int32.pinterface     = (void *)&ifaceInt32;
       
   387   pInterfaces->float64.pinterface   = (void *)&ifaceFloat64;
       
   388 
       
   389   status = pasynStandardInterfacesBase->initialize(myport, pInterfaces,
       
   390                                                    pport->pasynUserTrace, 
       
   391                                                    pport);
       
   392   if (status != asynSuccess) 
       
   393     {
       
   394       errlogPrintf("%s::drvAsynKeithley6485 port %s"
       
   395                    " can't register standard interfaces: %s\n",
       
   396                    driver, myport, pport->pasynUserTrace->errorMessage);
       
   397       return asynError;
       
   398     }
       
   399 
       
   400 #ifdef vxWorks
       
   401   /* Send a sacrificial clear status to vxworks device (i.e. VME)*/
       
   402   /* This fixes a problem with *IDN? call when starting from a cold boot */
       
   403   /* with the SBS IP-Octal hardware. */
       
   404   if( writeOnly(pport,"") )
       
   405     {
       
   406       errlogPrintf("%s::drvAsynKeithley6485 port %s failed to write\n",
       
   407                    driver, myport);
       
   408       return asynError;
       
   409     }
       
   410 #endif
       
   411 
       
   412   /* Reset device */
       
   413   if( writeOnly(pport,"*CLS") )
       
   414     {
       
   415       errlogPrintf("%s::drvAsynKeithley6485 port %s failed to clear\n",
       
   416                    driver, myport);
       
   417       return asynError;
       
   418     }
       
   419   
       
   420 
       
   421   /* Identification query */
       
   422   if( writeRead(pport,"*IDN?",inpBuf,sizeof(inpBuf),&eomReason) )
       
   423     {
       
   424       errlogPrintf("%s::drvAsynKeithley6485 port %s failed to "
       
   425                    "acquire identification\n", driver, myport);
       
   426       return asynError;
       
   427     }
       
   428   strcpy(pport->model,inpBuf);
       
   429   // char *model, *serial, *dig_rev, *disp_rev, *brd_rev;
       
   430   pport->serial = strchr( pport->model, ',');
       
   431   pport->serial = strchr( pport->serial + 1, ',');
       
   432   *(pport->serial) = '\0';
       
   433   pport->serial++;
       
   434   pport->dig_rev = strchr( pport->serial, ',');
       
   435   *(pport->dig_rev) = '\0';
       
   436   pport->dig_rev++;
       
   437   pport->disp_rev = strchr( pport->dig_rev, '/');
       
   438   *(pport->disp_rev) = '\0';
       
   439   pport->disp_rev++;
       
   440   pport->brd_rev = strchr( pport->disp_rev, '/');
       
   441   *(pport->brd_rev) = '\0';
       
   442   pport->brd_rev++;
       
   443   
       
   444   /* Complete initialization */
       
   445   pport->init=1;
       
   446 
       
   447   pport->data.reading = 0.0;
       
   448   pport->data.timestamp = 0;
       
   449   pport->data.status.raw = 0;
       
   450 
       
   451   return asynSuccess;
       
   452 }
       
   453 
       
   454 
       
   455 
       
   456 
       
   457 /****************************************************************************
       
   458  * Define private read and write parameter methods
       
   459  ****************************************************************************/
       
   460 
       
   461 static asynStatus readDummy(int which, Port *pport, void *data, Type Iface, 
       
   462                             size_t *length, int *eom)
       
   463 {
       
   464   return asynSuccess;
       
   465 }
       
   466 
       
   467 static asynStatus writeDummy(int which, Port *pport, void *data, Type Iface)
       
   468 {
       
   469   return asynSuccess;
       
   470 }
       
   471 
       
   472 ///
       
   473 
       
   474 static asynStatus readSimpleData( int which, Port *pport, void *data, 
       
   475                                   Type Iface, size_t *length, int *eom)
       
   476 {
       
   477   asynStatus status;
       
   478   char outBuf[BUFFER_SIZE];
       
   479   char inpBuf[BUFFER_SIZE];
       
   480 
       
   481   int len;
       
   482 
       
   483   // Trigger will automatically not work
       
   484   if( simpleCommandTable[which].type != Iface)
       
   485     return asynSuccess;
       
   486 
       
   487   sprintf( outBuf, "%s?", simpleCommandTable[which].cmd_str);
       
   488     
       
   489   status = writeRead( pport, outBuf, inpBuf, BUFFER_SIZE, &pport->data.eom);
       
   490   if( status != asynSuccess)
       
   491     return status;
       
   492 
       
   493   switch( Iface)
       
   494     {
       
   495     case Float64:
       
   496       *((epicsFloat64 *) data) = atof(inpBuf);
       
   497       break;
       
   498     case Int32:
       
   499       *((epicsInt32 *) data) = atoi(inpBuf);
       
   500       break;
       
   501     case Octet:
       
   502       len = strlen( inpBuf);
       
   503       if( len > 39)
       
   504         inpBuf[39] = '\0';
       
   505       strcpy( (char *) data, inpBuf);
       
   506       break;
       
   507     }
       
   508 
       
   509   return asynSuccess;
       
   510 }
       
   511 
       
   512 static asynStatus writeSimpleData( int which, Port *pport, void *data, 
       
   513                                     Type Iface)
       
   514 {
       
   515   char outBuf[BUFFER_SIZE];
       
   516   
       
   517   if( simpleCommandTable[which].type == SIMPLE_TRIGGER )
       
   518     sprintf( outBuf, "%s", simpleCommandTable[which].cmd_str);
       
   519   else
       
   520     {
       
   521       if( simpleCommandTable[which].type != Iface )
       
   522         return asynSuccess;
       
   523       
       
   524       switch( simpleCommandTable[which].type & Iface)
       
   525         {
       
   526         case Float64:
       
   527           sprintf( outBuf, "%s %g", simpleCommandTable[which].cmd_str, 
       
   528                    *((epicsFloat64*) data) );
       
   529           break;
       
   530         case Int32:
       
   531           sprintf( outBuf, "%s %d", simpleCommandTable[which].cmd_str, 
       
   532                    *((epicsInt32*) data) );
       
   533           break;
       
   534         case Octet:
       
   535           sprintf( outBuf, "%s %s", simpleCommandTable[which].cmd_str, 
       
   536                    ((char *) data) );
       
   537           break;
       
   538         }
       
   539     }
       
   540 
       
   541   return writeOnly( pport, outBuf);
       
   542 }
       
   543 
       
   544 ////
       
   545 
       
   546 static asynStatus readCache(int which, Port *pport, void *data, 
       
   547                             Type Iface, size_t *length, int *eom)
       
   548 {
       
   549   char *char_cache = NULL;
       
   550   int len;
       
   551 
       
   552   switch( Iface)
       
   553     {
       
   554     case Octet:
       
   555       switch(which)
       
   556         {
       
   557         case MODEL_CMD:
       
   558           char_cache = pport->model;
       
   559           break;
       
   560         case SERIAL_CMD:
       
   561           char_cache = pport->serial;
       
   562           break;
       
   563         case DIG_REV_CMD:
       
   564           char_cache = pport->dig_rev;
       
   565           break;
       
   566         case DISP_REV_CMD:
       
   567           char_cache = pport->disp_rev;
       
   568           break;
       
   569         case BRD_REV_CMD:
       
   570           char_cache = pport->brd_rev;
       
   571           break;
       
   572         }
       
   573       len = strlen(char_cache);
       
   574       if( len < 40)
       
   575         strcpy( (char *) data, char_cache);
       
   576       else // just in case string will overflow the EPICS string size of 40
       
   577         {
       
   578           len = 39;
       
   579           memcpy( (char *) data, char_cache, len);
       
   580           ((char *) data)[len] = '\0';
       
   581         }
       
   582       *length = len;
       
   583       *eom = 0;
       
   584       break;
       
   585     case Float64:
       
   586     //   switch( which)
       
   587     //     {
       
   588     //     }
       
   589       break;
       
   590     case Int32:
       
   591       switch( which)
       
   592         {
       
   593         case TIMESTAMP_CMD:
       
   594           *(epicsInt32*)data = pport->data.timestamp;
       
   595           break;  
       
   596         case STATUS_RAW_CMD:
       
   597           *(epicsInt32*) data = pport->data.status.raw;
       
   598           break;
       
   599         case STATUS_OVERFLOW_CMD:
       
   600           *(epicsInt32*) data = pport->data.status.bits.overflow;
       
   601           break;
       
   602         case STATUS_FILTER_CMD:
       
   603           *(epicsInt32*) data = pport->data.status.bits.filter_enabled;
       
   604           break;
       
   605         case STATUS_MATH_CMD:
       
   606           *(epicsInt32*) data = pport->data.status.bits.math_enabled;
       
   607           break;
       
   608         case STATUS_NULL_CMD:
       
   609           *(epicsInt32*) data = pport->data.status.bits.null_enabled;
       
   610           break;
       
   611         case STATUS_LIMITS_CMD:
       
   612           if( pport->data.status.bits.limit_test)
       
   613             *(epicsInt32*) data = pport->data.status.bits.limit_result;
       
   614           else
       
   615             *(epicsInt32*) data = 3;
       
   616           break;
       
   617         case STATUS_OVERVOLTAGE_CMD:
       
   618           *(epicsInt32*) data = pport->data.status.bits.overvoltage;
       
   619           break;
       
   620         case STATUS_ZERO_CHECK_CMD:
       
   621           *(epicsInt32*) data = pport->data.status.bits.zero_check_enabled;
       
   622           break;
       
   623         case STATUS_ZERO_CORRECT_CMD:
       
   624           *(epicsInt32*) data = pport->data.status.bits.zero_correct_enabled;
       
   625           break;
       
   626         }
       
   627       break;
       
   628     }
       
   629 
       
   630   return asynSuccess;
       
   631 }
       
   632 
       
   633 
       
   634 static asynStatus readSensorReading(int which, Port *pport, void *data, 
       
   635                                     Type Iface, size_t *length, int *eom)
       
   636 {
       
   637   asynStatus status;
       
   638   char inpBuf[BUFFER_SIZE];
       
   639 
       
   640   char *str, *token[3], *saveptr;
       
   641   int pass;
       
   642 
       
   643   status = writeRead( pport, "READ?", inpBuf, BUFFER_SIZE, &pport->data.eom);
       
   644   if( status != asynSuccess)
       
   645     return status;
       
   646 
       
   647   str = inpBuf;
       
   648   for( pass = 0; pass < 3; pass++, str = NULL)
       
   649     {
       
   650       token[pass] = epicsStrtok_r(str, ",", &saveptr);
       
   651       if (token == NULL)
       
   652         break;
       
   653     }
       
   654   if( pass != 3)
       
   655     return asynError;
       
   656 
       
   657   pport->data.reading = atof( token[0]);
       
   658   pport->data.timestamp = (int) atof( token[1]);
       
   659   pport->data.status.raw = (int) atof( token[2]);
       
   660 
       
   661   switch( Iface )
       
   662     {
       
   663     case Octet:
       
   664       // only print current value
       
   665       *length = sprintf( (char *) data, "%s", token[0]);
       
   666       *eom = pport->data.eom;
       
   667       break;
       
   668     case Float64:
       
   669       *(epicsFloat64*)data = pport->data.reading;
       
   670       break;
       
   671     case Int32:
       
   672       break;
       
   673     }
       
   674 
       
   675   return asynSuccess;
       
   676 }
       
   677 
       
   678 static asynStatus readRange(int which, Port *pport, void *data, 
       
   679                             Type Iface, size_t *length, int *eom)
       
   680 {
       
   681   asynStatus status;
       
   682   char inpBuf[BUFFER_SIZE];
       
   683 
       
   684   if( Iface == Octet)
       
   685     return asynSuccess;
       
   686 
       
   687   switch( which)
       
   688     {
       
   689     case RANGE_CMD:
       
   690       status = writeRead( pport, ":RANGE?", inpBuf, BUFFER_SIZE, 
       
   691                           &pport->data.eom);
       
   692       break;
       
   693     case RANGE_AUTO_ULIMIT_CMD:
       
   694       status = writeRead( pport, ":RANGE:AUTO:ULIM?", inpBuf, BUFFER_SIZE, 
       
   695                           &pport->data.eom);
       
   696       break;
       
   697     case RANGE_AUTO_LLIMIT_CMD:
       
   698       status = writeRead( pport, ":RANGE:AUTO:LLIM?", inpBuf, BUFFER_SIZE, 
       
   699                           &pport->data.eom);
       
   700       break;
       
   701     default:
       
   702       return asynError;
       
   703     }
       
   704   if( status != asynSuccess)
       
   705     return status;
       
   706 
       
   707   if( Iface == Float64)
       
   708     {
       
   709       double val;
       
   710 
       
   711       val = atof( inpBuf);
       
   712       if( val == 0.0)
       
   713         return asynError;
       
   714 
       
   715       *(epicsFloat64*) data = val;
       
   716     }
       
   717   else if( Iface == Int32)
       
   718     {
       
   719       char *p;
       
   720 
       
   721       p = strchr( inpBuf, 'E');
       
   722       if(p == NULL)
       
   723         return asynError;
       
   724       p++;
       
   725       *(epicsInt32*) data = 9 + atoi(p) ;
       
   726     }
       
   727 
       
   728   return asynSuccess;
       
   729 }
       
   730 
       
   731 
       
   732 static asynStatus writeRange( int which, Port *pport, void *data, Type Iface)
       
   733 {
       
   734   char outBuf[BUFFER_SIZE];
       
   735   int value;
       
   736 
       
   737   if( Iface != Int32)
       
   738     return asynSuccess;
       
   739 
       
   740   value = *((epicsInt32*) data);
       
   741   if( (value < 0) || (value > 7) )
       
   742     return asynError;
       
   743     
       
   744   switch( which)
       
   745     {
       
   746     case RANGE_CMD:
       
   747       sprintf( outBuf, ":RANGE 2.0e%d", -9 + value );
       
   748       break;
       
   749     case RANGE_AUTO_ULIMIT_CMD:
       
   750       sprintf( outBuf, ":RANGE:AUTO:ULIM 2.0e%d", -9 + value );
       
   751       break;
       
   752     case RANGE_AUTO_LLIMIT_CMD:
       
   753       sprintf( outBuf, ":RANGE:AUTO:LLIM 2.0e%d", -9 + value );
       
   754       break;
       
   755     default:
       
   756       return asynError;
       
   757     }
       
   758 
       
   759   return writeOnly( pport, outBuf);
       
   760 }
       
   761 
       
   762 
       
   763 static asynStatus readRate(int which, Port *pport, void *data, 
       
   764                            Type Iface, size_t *length, int *eom)
       
   765 {
       
   766   asynStatus status;
       
   767   char inpBuf[BUFFER_SIZE];
       
   768 
       
   769   double val;
       
   770   int rate;
       
   771 
       
   772   if( Iface != Int32)
       
   773     return asynSuccess;
       
   774 
       
   775   status = writeRead( pport, ":NPLC?", inpBuf, BUFFER_SIZE, &pport->data.eom);
       
   776   if( status != asynSuccess)
       
   777     return status;
       
   778 
       
   779   val = atof( inpBuf);
       
   780   if( val > 1.0)
       
   781     rate = 0; // SLOW
       
   782   else if( val > 0.1)
       
   783     rate = 1; // MEDIUM
       
   784   else
       
   785     rate = 2; // FAST
       
   786   
       
   787   *((epicsInt32*) data) = rate;
       
   788 
       
   789   return asynSuccess;
       
   790 }
       
   791 
       
   792 
       
   793 static asynStatus writeRate( int which, Port *pport, void *data, Type Iface)
       
   794 {
       
   795   char outBuf[BUFFER_SIZE];
       
   796   int rate;
       
   797   double val;
       
   798 
       
   799   if( Iface != Int32)
       
   800     return asynSuccess;
       
   801 
       
   802   rate = *((epicsInt32*) data);
       
   803   if( (rate < 0) || (rate > 2) )
       
   804     return asynError;
       
   805 
       
   806   switch( rate)
       
   807     {
       
   808     case 0:
       
   809       val = 6.0;
       
   810       break;
       
   811     case 1:
       
   812       val = 1.0;
       
   813       break;
       
   814     case 2:
       
   815       val = 0.1;
       
   816       break;
       
   817     default:
       
   818       val = 1.0;
       
   819       break;
       
   820     }
       
   821 
       
   822   sprintf( outBuf, ":NPLC %g", val );
       
   823   return writeOnly( pport, outBuf);
       
   824 }
       
   825 
       
   826 
       
   827 static asynStatus readVoltageSettings(int which, Port *pport, void *data, Type Iface, 
       
   828                                       size_t *length, int *eom)
       
   829 {
       
   830   asynStatus status;
       
   831   char inpBuf[BUFFER_SIZE];
       
   832 
       
   833   double val;
       
   834 
       
   835   if(( which != VOLTAGE_RANGE_CMD) && ( which != VOLTAGE_CURRENT_LIMIT_CMD))
       
   836     return asynError;
       
   837   if( Iface == Octet)
       
   838     return asynSuccess;
       
   839 
       
   840   if( which == VOLTAGE_RANGE_CMD)
       
   841     status = writeRead( pport, "SOUR:VOLT:RANGE?", inpBuf, BUFFER_SIZE, 
       
   842                         &pport->data.eom);
       
   843   else
       
   844     status = writeRead( pport, "SOUR:VOLT:ILIM?", inpBuf, BUFFER_SIZE, 
       
   845                         &pport->data.eom);
       
   846   if( status != asynSuccess)
       
   847     return status;
       
   848 
       
   849   val = atof( inpBuf);
       
   850   if( val == 0.0)
       
   851     return asynError;
       
   852 
       
   853   if( Iface == Float64)
       
   854     {
       
   855       *((epicsFloat64*) data) = val;
       
   856     }
       
   857   else if( Iface == Int32)
       
   858     {
       
   859       if( which == VOLTAGE_RANGE_CMD)
       
   860         {
       
   861           if( val == 10.0)
       
   862             *((epicsInt32*) data) = 0;
       
   863           else if( val == 50.0)
       
   864             *((epicsInt32*) data) = 1;
       
   865           else if( val == 500.0)
       
   866             *((epicsInt32*) data) = 2;
       
   867         }
       
   868       else
       
   869         {
       
   870           if( val == 2.5e-5)
       
   871             *((epicsInt32*) data) = 0;
       
   872           else if( val == 2.5e-4)
       
   873             *((epicsInt32*) data) = 1;
       
   874           else if( val == 2.5e-3)
       
   875             *((epicsInt32*) data) = 2;
       
   876           else if( val == 2.5e-2)
       
   877             *((epicsInt32*) data) = 3;
       
   878         }
       
   879     }
       
   880 
       
   881   return asynSuccess;
       
   882 }
       
   883 
       
   884 
       
   885 static asynStatus writeVoltageSettings( int which, Port *pport, void *data, Type Iface)
       
   886 {
       
   887   char outBuf[BUFFER_SIZE];
       
   888   int value;
       
   889 
       
   890   if(( which != VOLTAGE_RANGE_CMD) && ( which != VOLTAGE_CURRENT_LIMIT_CMD))
       
   891     return asynError;
       
   892   if( Iface != Int32)
       
   893     return asynSuccess;
       
   894 
       
   895   value = *((epicsInt32*) data);
       
   896   if( which == VOLTAGE_RANGE_CMD) 
       
   897     {
       
   898       if( (value < 0) || (value > 2) )
       
   899         return asynError;
       
   900 
       
   901       if( value == 0)
       
   902         value = 10;
       
   903       else if( value == 1)
       
   904         value = 50;
       
   905       else 
       
   906         value = 500;
       
   907    
       
   908       sprintf( outBuf, "SOUR:VOLT:RANGE %d", value );
       
   909     }
       
   910   else
       
   911     {
       
   912       if( (value < 0) || (value > 3) )
       
   913         return asynError;
       
   914 
       
   915       sprintf( outBuf, "SOUR:VOLT:ILIM 2.5e%d", value - 5 );
       
   916     }
       
   917 
       
   918   return writeOnly( pport, outBuf);
       
   919 }
       
   920 
       
   921 
       
   922 static asynStatus readCommon(int which, Port *pport, void *data, 
       
   923                              Type Iface, size_t *length, int *eom)
       
   924 {
       
   925   asynStatus status;
       
   926   char inpBuf[BUFFER_SIZE];
       
   927 
       
   928   int val = 0;
       
   929 
       
   930   if( Iface != Int32)
       
   931     return asynSuccess;
       
   932 
       
   933   switch(which)
       
   934     {
       
   935     case DIGITAL_FILTER_CONTROL_CMD:
       
   936       status = writeRead( pport, "AVER:TCON?", inpBuf, BUFFER_SIZE, 
       
   937                           &pport->data.eom);
       
   938 
       
   939       if( status != asynSuccess)
       
   940         return status;
       
   941       if( !strcmp( "MOV", inpBuf) )
       
   942         val = 0;
       
   943       else if( !strcmp( "REP", inpBuf) )
       
   944         val = 1;
       
   945       else
       
   946         return asynError;
       
   947       break;
       
   948     }
       
   949   
       
   950   *((epicsInt32*) data) = val;
       
   951 
       
   952   return asynSuccess;
       
   953 }
       
   954 
       
   955 
       
   956 static asynStatus writeCommon( int which, Port *pport, void *data, Type Iface)
       
   957 {
       
   958   char outBuf[BUFFER_SIZE];
       
   959   int val;
       
   960 
       
   961   if( Iface != Int32)
       
   962     return asynSuccess;
       
   963 
       
   964   val = *((epicsInt32*) data);
       
   965   switch( which)
       
   966     {
       
   967     case DIGITAL_FILTER_CONTROL_CMD:
       
   968       if( !val)
       
   969         sprintf( outBuf, "AVER:TCON MOV" );
       
   970       else if(val == 1)
       
   971         sprintf( outBuf, "AVER:TCON REP" );
       
   972       else
       
   973         return asynError;
       
   974       break;
       
   975     }
       
   976 
       
   977   return writeOnly( pport, outBuf);
       
   978 }
       
   979 
       
   980 
       
   981 /****************************************************************************
       
   982  * Define private interface asynCommon methods
       
   983  ****************************************************************************/
       
   984 static void report(void* ppvt,FILE* fp,int details)
       
   985 {
       
   986   //  int i;
       
   987   Port* pport = (Port*)ppvt;
       
   988 
       
   989   fprintf( fp, "Keithley648x port: %s\n", pport->myport);
       
   990   if( details)
       
   991     {
       
   992       fprintf( fp, "    server:     %s\n", pport->ioport);
       
   993       fprintf( fp, "    address:    %d\n", pport->ioaddr);
       
   994       fprintf( fp, "    ioErrors:   %d\n", pport->stats.ioErrors);
       
   995       fprintf( fp, "    writeReads: %d\n", pport->stats.writeReads);
       
   996       fprintf( fp, "    writeOnlys: %d\n", pport->stats.writeOnlys);
       
   997       fprintf( fp, "    support %s initialized\n",(pport->init)?"IS":"IS NOT");
       
   998     }
       
   999 
       
  1000 }
       
  1001 
       
  1002 static asynStatus connect(void* ppvt,asynUser* pasynUser)
       
  1003 {
       
  1004   pasynManager->exceptionConnect(pasynUser);
       
  1005   return asynSuccess;
       
  1006 }
       
  1007 
       
  1008 static asynStatus disconnect(void* ppvt,asynUser* pasynUser)
       
  1009 {
       
  1010   pasynManager->exceptionDisconnect(pasynUser);
       
  1011   return asynSuccess;
       
  1012 }
       
  1013 
       
  1014 
       
  1015 /****************************************************************************
       
  1016  * Define private interface asynDrvUser methods
       
  1017  ****************************************************************************/
       
  1018 static asynStatus create(void* ppvt, asynUser *pasynUser, const char *drvInfo, 
       
  1019                          const char **pptypeName, size_t *psize)
       
  1020 {
       
  1021   Port* pport=(Port*)ppvt;
       
  1022   
       
  1023   int i;
       
  1024   
       
  1025   for(i = 0; i < COMMAND_NUMBER; i++) 
       
  1026     if( !epicsStrCaseCmp( drvInfo, commandTable[i].tag) ) 
       
  1027       {
       
  1028         if( (commandTable[i].dev != DEV_ALL) && 
       
  1029             (commandTable[i].dev != pport->devtype) )
       
  1030           {
       
  1031             errlogPrintf("%s::create port %s failed as tag %s is for different "
       
  1032                          "device\n", driver, pport->myport, drvInfo);
       
  1033             pasynUser->reason = 0;
       
  1034             return asynError;
       
  1035           }
       
  1036         pasynUser->reason = i;
       
  1037         break;
       
  1038       }
       
  1039   if( i == COMMAND_NUMBER ) 
       
  1040     {
       
  1041       errlogPrintf("%s::create port %s failed to find tag %s\n",
       
  1042                    driver, pport->myport, drvInfo);
       
  1043       pasynUser->reason = 0;
       
  1044       return asynError;
       
  1045     }
       
  1046   
       
  1047   return asynSuccess;
       
  1048 }
       
  1049 
       
  1050 static asynStatus gettype(void* ppvt,asynUser* pasynUser,
       
  1051                           const char** pptypeName,size_t* psize)
       
  1052 {
       
  1053   if( pptypeName ) 
       
  1054     *pptypeName = NULL;
       
  1055   if( psize ) 
       
  1056     *psize = 0;
       
  1057 
       
  1058   return asynSuccess;
       
  1059 }
       
  1060 
       
  1061 static asynStatus destroy(void* ppvt,asynUser* pasynUser)
       
  1062 {
       
  1063   return asynSuccess;
       
  1064 }
       
  1065 
       
  1066 
       
  1067 /****************************************************************************
       
  1068  * Define private interface asynFloat64 methods
       
  1069  ****************************************************************************/
       
  1070 static asynStatus writeFloat64(void* ppvt,asynUser* pasynUser,
       
  1071                                epicsFloat64 value)
       
  1072 {
       
  1073   Port* pport=(Port*)ppvt;
       
  1074   int which = pasynUser->reason;
       
  1075 
       
  1076   int id;
       
  1077   id = commandTable[which].id;
       
  1078 
       
  1079   if( pport->init == 0) 
       
  1080     return asynError;
       
  1081 
       
  1082    switch( commandTable[which].type )
       
  1083     {
       
  1084     case CMD_GEN:
       
  1085       return genCommandTable[id].writeFunc(id, pport, &value, Float64);
       
  1086       break;
       
  1087     case CMD_SIMPLE:
       
  1088       return writeSimpleData( id, pport, &value, Float64);
       
  1089       break;
       
  1090     }
       
  1091 
       
  1092   return asynSuccess;
       
  1093 }
       
  1094 
       
  1095 static asynStatus readFloat64(void* ppvt,asynUser* pasynUser,
       
  1096                               epicsFloat64* value)
       
  1097 {
       
  1098   Port* pport=(Port*)ppvt;
       
  1099   int which = pasynUser->reason;
       
  1100 
       
  1101   int id;
       
  1102   id = commandTable[which].id;
       
  1103 
       
  1104   if( pport->init == 0) 
       
  1105     return asynError;
       
  1106 
       
  1107   switch( commandTable[which].type )
       
  1108     {
       
  1109     case CMD_GEN:
       
  1110       return genCommandTable[id].readFunc(id, pport, value, Float64, 
       
  1111                                           NULL, NULL);
       
  1112       break;
       
  1113     case CMD_SIMPLE:
       
  1114       return readSimpleData( id, pport, value, Float64, NULL, NULL);
       
  1115       break;
       
  1116     case CMD_CACHE:
       
  1117       return readCache(id, pport, value, Float64, NULL, NULL);
       
  1118       break;
       
  1119     }
       
  1120 
       
  1121   return asynSuccess;
       
  1122 }
       
  1123 
       
  1124 
       
  1125 /****************************************************************************
       
  1126  * Define private interface asynInt32 methods
       
  1127  ****************************************************************************/
       
  1128 static asynStatus writeInt32(void *ppvt, asynUser *pasynUser, epicsInt32 value)
       
  1129 {
       
  1130   Port* pport=(Port*)ppvt;
       
  1131   int which = pasynUser->reason;
       
  1132 
       
  1133   int id;
       
  1134   id = commandTable[which].id;
       
  1135 
       
  1136   if( pport->init == 0) 
       
  1137     return asynError;
       
  1138 
       
  1139   switch( commandTable[which].type )
       
  1140     {
       
  1141     case CMD_GEN:
       
  1142       return genCommandTable[id].writeFunc(id, pport, &value, Int32);
       
  1143       break;
       
  1144     case CMD_SIMPLE:
       
  1145       return writeSimpleData( id, pport, (void *) &value, Int32);
       
  1146       break;
       
  1147     }
       
  1148   
       
  1149   return asynSuccess;
       
  1150 }
       
  1151 
       
  1152 static asynStatus readInt32(void *ppvt, asynUser *pasynUser, epicsInt32 *value)
       
  1153 {
       
  1154   Port* pport=(Port*)ppvt;
       
  1155   int which = pasynUser->reason;
       
  1156 
       
  1157   int id;
       
  1158   id = commandTable[which].id;
       
  1159 
       
  1160   if( pport->init == 0) 
       
  1161     return asynError;
       
  1162 
       
  1163   switch( commandTable[which].type )
       
  1164     {
       
  1165     case CMD_GEN:
       
  1166       return genCommandTable[id].readFunc(id, pport, value, Int32, 
       
  1167                                           NULL, NULL);
       
  1168       break;
       
  1169     case CMD_SIMPLE:
       
  1170       return readSimpleData( id, pport, value, Int32, NULL, NULL);
       
  1171       break;
       
  1172     case CMD_CACHE:
       
  1173       return readCache(id, pport, value, Int32, NULL, NULL);
       
  1174       break;
       
  1175     }
       
  1176 
       
  1177   return asynSuccess;
       
  1178 }
       
  1179 
       
  1180 
       
  1181 /****************************************************************************
       
  1182  * Define private interface asynOctet methods
       
  1183  ****************************************************************************/
       
  1184 static asynStatus flushOctet(void *ppvt, asynUser* pasynUser)
       
  1185 {
       
  1186   return asynSuccess;
       
  1187 }
       
  1188 
       
  1189 static asynStatus writeOctet(void *ppvt, asynUser *pasynUser, const char *data,
       
  1190                              size_t numchars, size_t *nbytes)
       
  1191 {
       
  1192   Port* pport=(Port*)ppvt;
       
  1193   int which = pasynUser->reason;
       
  1194 
       
  1195   int id;
       
  1196   id = commandTable[which].id;
       
  1197 
       
  1198   if( pport->init == 0) 
       
  1199     return asynError;
       
  1200 
       
  1201   switch( commandTable[which].type )
       
  1202     {
       
  1203     case CMD_GEN:
       
  1204       *nbytes=strlen(data);
       
  1205       return genCommandTable[id].writeFunc(id, pport, (void *) data, Octet);
       
  1206       break;
       
  1207     case CMD_SIMPLE:
       
  1208       *nbytes=strlen(data);
       
  1209       return writeSimpleData( id, pport, &data, Octet);
       
  1210       break;
       
  1211     }
       
  1212   
       
  1213   return asynSuccess;
       
  1214 }
       
  1215 
       
  1216 static asynStatus readOctet(void* ppvt, asynUser* pasynUser, char* data,
       
  1217                             size_t maxchars,size_t* nbytes,int* eom)
       
  1218 {
       
  1219   Port* pport=(Port*)ppvt;
       
  1220   int which = pasynUser->reason;
       
  1221 
       
  1222   int id;
       
  1223   id = commandTable[which].id;
       
  1224 
       
  1225   if( pport->init == 0) 
       
  1226     return asynError;
       
  1227 
       
  1228   switch( commandTable[which].type )
       
  1229     {
       
  1230     case CMD_GEN:
       
  1231       return genCommandTable[id].readFunc(id, pport, (void *) data, Octet, 
       
  1232                                           nbytes, eom);
       
  1233       break;
       
  1234     case CMD_SIMPLE:
       
  1235       return readSimpleData( id, pport, data, Octet, nbytes, eom);
       
  1236       break;
       
  1237     case CMD_CACHE:
       
  1238       return readCache(id, pport, (void *) data, Octet, nbytes, eom);
       
  1239       break;
       
  1240     }
       
  1241 
       
  1242   return asynSuccess;
       
  1243 }
       
  1244 
       
  1245 
       
  1246 /****************************************************************************
       
  1247  * Define private Keithley648x external interface asynOctet methods
       
  1248  ****************************************************************************/
       
  1249 static asynStatus writeOnly(Port *pport, const char *outBuf)
       
  1250 {
       
  1251   asynStatus status;
       
  1252   size_t nActual, nRequested;
       
  1253 
       
  1254   nRequested=strlen(outBuf);
       
  1255   status = 
       
  1256     pasynOctetSyncIO->write(pport->pasynUser,outBuf,nRequested,TIMEOUT,&nActual);
       
  1257   if( nActual!=nRequested ) 
       
  1258     status = asynError;
       
  1259 
       
  1260   if( status!=asynSuccess )
       
  1261     {
       
  1262       pport->stats.ioErrors++;
       
  1263       asynPrint(pport->pasynUserTrace,ASYN_TRACE_ERROR, 
       
  1264                 "%s writeOnly: error %d wrote \"%s\"\n",
       
  1265                 pport->myport,status,outBuf);
       
  1266     }
       
  1267   else
       
  1268     pport->stats.writeOnlys++;
       
  1269 
       
  1270   asynPrint(pport->pasynUserTrace, ASYN_TRACEIO_FILTER,
       
  1271             "%s writeOnly: wrote \"%s\"\n",
       
  1272             pport->myport,outBuf);
       
  1273 
       
  1274   return status;
       
  1275 }
       
  1276 
       
  1277 static asynStatus writeRead(Port *pport, const char *outBuf, char *inpBuf,
       
  1278                             int inputSize, int *eomReason)
       
  1279 {
       
  1280   asynStatus status;
       
  1281   size_t nWrite, nRead, nWriteRequested;
       
  1282 
       
  1283   nWriteRequested=strlen(outBuf);
       
  1284   status = pasynOctetSyncIO->writeRead(pport->pasynUser,outBuf,
       
  1285                                        nWriteRequested,inpBuf,inputSize-1,
       
  1286                                        TIMEOUT,&nWrite,&nRead,eomReason);
       
  1287   if( nWrite!=nWriteRequested ) 
       
  1288     status = asynError;
       
  1289 
       
  1290   if( status!=asynSuccess )
       
  1291     {
       
  1292       pport->stats.ioErrors++;
       
  1293       asynPrint(pport->pasynUserTrace,ASYN_TRACE_ERROR,
       
  1294                 "%s writeRead: error %d wrote \"%s\"\n",
       
  1295                 pport->myport,status,outBuf);
       
  1296     }
       
  1297   else
       
  1298     {
       
  1299       inpBuf[nRead]='\0';
       
  1300       pport->stats.writeReads++;
       
  1301     }
       
  1302 
       
  1303   asynPrint(pport->pasynUserTrace,ASYN_TRACEIO_FILTER,
       
  1304             "%s writeRead: wrote \"%s\" read \"%s\"\n",
       
  1305             pport->myport,outBuf,inpBuf);
       
  1306   
       
  1307   return status;
       
  1308 }
       
  1309 
       
  1310 
       
  1311 /****************************************************************************
       
  1312  * Register public methods
       
  1313  ****************************************************************************/
       
  1314  
       
  1315 /* Initialization method definitions */
       
  1316 static const iocshArg arg0 = {"type",iocshArgString};
       
  1317 static const iocshArg arg1 = {"myport",iocshArgString};
       
  1318 static const iocshArg arg2 = {"ioport",iocshArgString};
       
  1319 static const iocshArg arg3 = {"ioaddr",iocshArgInt};
       
  1320 static const iocshArg* args[]= {&arg0,&arg1,&arg2,&arg3};
       
  1321 static const iocshFuncDef drvAsynKeithley648xFuncDef = 
       
  1322   {"drvAsynKeithley648x",4,args};
       
  1323 static void drvAsynKeithley648xCallFunc(const iocshArgBuf* args)
       
  1324 {
       
  1325   drvAsynKeithley648x(args[0].sval,args[1].sval,args[2].sval,args[3].ival);
       
  1326 }
       
  1327 
       
  1328 /* Registration method */
       
  1329 static void drvAsynKeithley648xRegister(void)
       
  1330 {
       
  1331   static int firstTime = 1;
       
  1332 
       
  1333   if( firstTime )
       
  1334     {
       
  1335       firstTime = 0;
       
  1336       iocshRegister( &drvAsynKeithley648xFuncDef,drvAsynKeithley648xCallFunc );
       
  1337     }
       
  1338 }
       
  1339 epicsExportRegistrar( drvAsynKeithley648xRegister );