/*************************************************************************\
* Copyright (c) 2009 Yokogawa Corporation of America
* Copyright (c) 2013 High Energy Accelerator Reseach Organization (KEK)
* This file is distributed subject to a Software License Agreement found
* in the file LICENSE that is included with this distribution.
\*************************************************************************/

#include    <stdlib.h>
#include    <stdio.h>
#include    <string.h>
#include    <unistd.h>
#include    <devCommonGpib.h>
#include    <errlog.h>
#include    <menuFtype.h>

#define DEVICE       SL1000

#define tcat(x,y,z) x ## y ## z
#define cat(x,y,z) tcat(x,y,z)

#define DSET_AI         cat(devAi,      DEVICE, Gpib)
#define DSET_AO         cat(devAo,      DEVICE, Gpib)
#define DSET_LO         cat(devLo,      DEVICE, Gpib)
#define DSET_BI         cat(devBi,      DEVICE, Gpib)
#define DSET_BO         cat(devBo,      DEVICE, Gpib)
#define DSET_MBBO       cat(devMbbo,    DEVICE, Gpib)
#define DSET_MBBI       cat(devMbbi,    DEVICE, Gpib)
#define DSET_SI         cat(devSi,      DEVICE, Gpib)
#define DSET_SO         cat(devSo,      DEVICE, Gpib)
#define DSET_WF         cat(devWf,      DEVICE, Gpib)
#define DSET_LI         cat(devLongin,  DEVICE, Gpib)
#define NAME(device)    "dev" #device "Gpib"

#define SL1000_DISP_WAVE_LEN     2002 /* length of display-waveform is fixed to 2002 by the hardware */
#define SL1000_RAW_WAVE_LEN   5000000 /* length of raw-waveform */

#include    <devGpib.h>

#define TIMEWINDOW      2.00        /* 2 second delay before reconnect */
#define TIMEOUT         12.0        /* 12 second limit for I/O operation */

/**************************************************************************
String arrays for EFAST operations
***************************************************************************/

static char     *(timeRefCmd[])    = {":TRIG:POS 0",
                                      ":TRIG:POS 10",
                                      ":TRIG:POS 20",
                                      ":TRIG:POS 30",
                                      ":TRIG:POS 40",
                                      ":TRIG:POS 50",
                                      ":TRIG:POS 60",
                                      ":TRIG:POS 70",
                                      ":TRIG:POS 80",
                                      ":TRIG:POS 90",
                                      ":TRIG:POS 100",
                                      NULL};

static char     *(trigSourceCmd[]) = {":TRIG:SIMP:SOUR EXT",
                                      ":TRIG:SIMP:SOUR LINE",
                                      ":TRIG:SIMP:SOUR 1",
                                      ":TRIG:SIMP:SOUR 2",
                                      ":TRIG:SIMP:SOUR 3",
                                      ":TRIG:SIMP:SOUR 4",
                                      ":TRIG:SIMP:SOUR 5",
                                      ":TRIG:SIMP:SOUR 6",
                                      ":TRIG:SIMP:SOUR 7",
                                      ":TRIG:SIMP:SOUR 8",
                                      ":TRIG:SIMP:SOUR 9",
                                      ":TRIG:SIMP:SOUR 10",
                                      ":TRIG:SIMP:SOUR 11",
                                      ":TRIG:SIMP:SOUR 12",
                                      ":TRIG:SIMP:SOUR 13",
                                      ":TRIG:SIMP:SOUR 14",
                                      NULL};

static char     *(trigSourceTable[]) = {"EXT"   ,
                                        "LINE"  ,
                                        "1"     ,
                                        "2"     ,
                                        "3"     ,
                                        "4"     ,
                                        "5"     ,
                                        "6"     ,
                                        "7"     ,
                                        "8"     ,
                                        "9"     ,
                                        "10"    ,
                                        "11"    ,
                                        "12"    ,
                                        "13"    ,
                                        "14"    ,
                                        NULL};

static char     *(trigSlopeCmd[])  = {":TRIG:SLOP FALL",
                                      ":TRIG:SLOP RISE",
                                      NULL};

static char     *(trigSlopeTable[])  = {"FALL" ,
                                        "RISE" ,
                                        NULL};

static char     *(acqModeCmd[]) = {":TRIG:MMOD NORM",
                                   ":TRIG:MMOD SING",
                                    NULL};

static char     *(acqModeTable[])  = {"NORM" ,
                                      "SING" ,
                                       NULL};

static char     *(frontPanelLockCmd[])  = {":SYST:KEYL 0",
                                           ":SYST:KEYL 1",
                                           NULL};

static char     *(frontPanelLockTable[])  = {"0" ,
                                             "1"  ,
                                             NULL};

/**************************************************************************
declarations of convert routines
**************************************************************************/
static int convertWave();
static int convertDispWaveAll();
static int convertDispWave();
static int convertTimeAxis();
static int writeStringWf();
static int readSetupData();
static int writeSetupData();
static int aoSmplRate();
static int aoTimeSpan();
static int miTrigStat();
static int boInit();
static int biAcqStat();
static int aiCurrentTrigNo();
static int aiMaxHistoryNo();
static int boResetTrigNo();
static int aoDispWaveHistNo();
static int aoWaveHistNo();
static int aoDispWaveTrigNo();
static int aiDispWaveTrigNoAbs();
static int aiDispWaveTrigNo();
static int aiWaveTrigNo();
static int aoWaveTrigNoAbs();
static int aiWaveTrigNoAbs();
static int aiOldTrigNo();
static int aiDispWaveTrigNoDiff();
static int boDispWaveTrigNoDiffHold();
static int boReleaseSrq();
static int boSrqEnable();
static int biSrqEnable();
static int moTrigSource();
static int moSelectChannel();
static int moSelectModule();
static int moWaveChan();
static int boEnableChannel();
static int biEnableChannel();
static int moVdiv();
static int miVdiv();
static int aiVdiv();
static int moCoupling();
static int miCoupling();
static int moProbe();
static int miProbe();
static int siModuleName();
static int aiChanNum();
static int biChEnable();
static int miTrigPos();
static int aiTrigPos();
static int miSmplRateA();
static int miSmplRateB();
static int liRecLen();
static int moWaveLen();
static int aoWaveLen();
static int aoWavePos();
static int soSetupName();
static int boSaveSetup();
static int boRecallSetup();
static int aiWaveLen();
static int aiDispWaveLen();
static int aiCurrentVal();

/**************************************************************************
Static data support
**************************************************************************/
typedef struct
{
    void *pvtAddr;
    int AcqStat;
    int ChNum;
    int ModNum;
    int TargetCh;
    int TargetMod;
    char ChEnable[16];
    int SrqEnable;
    int RecLen;
    int DispWaveLen;
    int DispWaveNelm;
    int DispWaveNord;
    int WaveCh;
    int WaveLen;
    int WavePos;
    int WaveNelm;
    int WaveNord;
    int ParamChangedFlag;
    int HistMax;
    int DispWaveTrigNoDiffHold;
    short *DispWaveBuf;
    double SmplRate;
    double CurrentTrigNo;
    double DispWaveTrigNo;
    double DispWaveTrigNoAbs;
    double DispWaveTrigNoOld;
    double DispWaveTrigNoDiff;
    double DispWaveHisNo;
    double WaveTrigNo;
    double WaveTrigNoAbs;
    double WaveHisNo;
    double Gain[16];
    double Offset[16];
    char SetupDataName[40];
} STATIC_VAL;

#define MAX_UNIT_SUPORTED_NUM   (16)
static STATIC_VAL  _static_value[MAX_UNIT_SUPORTED_NUM];

#define BYTE_ORDER_LSB (0)
#define BYTE_ORDER_MSB (1)
static int _byte_order;     /* 0:LSB  1:MSB */

static void init_sval()
{
  int int_one;

  /* fill by zero */
  memset((unsigned char *)_static_value, 0, sizeof(_static_value));

  /* check byte order (endian) of this computer */
  int_one = 1;
  if((*(char *)&int_one) == 1)
  {
    _byte_order = BYTE_ORDER_LSB;
  }
  else
  {
    _byte_order = BYTE_ORDER_MSB;
  }
}

static STATIC_VAL *get_sval(struct gpibDpvt *pdpvt)
{
  asynUser *pasynUser = pdpvt->pasynUser;
  STATIC_VAL *psval = _static_value;
  int i;

  for(i=0; i<MAX_UNIT_SUPORTED_NUM; i++, psval++)
  {
    if(psval->pvtAddr == pdpvt->asynCommonPvt)
    {
      return(psval);
    }
    if(psval->pvtAddr == NULL)
    {
      psval->pvtAddr = pdpvt->asynCommonPvt;
      return(psval);
    }
  }
  asynPrint(pasynUser, ASYN_TRACE_FLOW, "SL1000 device support error:  Number of units exceed limit! (max=%d)\n", MAX_UNIT_SUPORTED_NUM);
  return(&_static_value[MAX_UNIT_SUPORTED_NUM-1]);
}

/**************************************************************************
Array of gpibCmd
**************************************************************************/

#define TIME_AXIS_CMD(mode)  {&DSET_WF, GPIBREAD, IB_Q_LOW, ":ACQ:TIME?;:TIM:SRAT?;:TRIG:POS?", "%lf", 0, 1000000, convertTimeAxis, mode , 0, NULL, NULL, NULL}
#define DISP_DATA_CMD(ch)  {&DSET_WF, GPIBCVTIO, IB_Q_LOW, "", "%lf", 0, 20000, convertDispWave, ch , 0, NULL, NULL, NULL}
#define CH_ENABLE_CMD(ch)  {&DSET_BI,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,10,biChEnable,ch,0,NULL,NULL,NULL}
#define CURRENT_VAL_CMD(ch)  {&DSET_AI,GPIBCVTIO,IB_Q_LOW, ":MON:ASEN:CHAN%d?","%f",0,40,aiCurrentVal,ch,0,NULL,NULL,NULL}
#define RAW_DATA_CMD(ch)   {&DSET_WF, GPIBCVTIO, IB_Q_LOW, ":ACQ:TIME?;:TIM:SRAT?;:WAV:TRAC %d; GAIN?; OFFS?;:CONT:TRIG:LAC?;:WAV:HMAX?", "%lf", 0, SL1000_RAW_WAVE_LEN, convertWave, ch , 0, NULL, NULL, NULL}

static struct gpibCmd gpibCmds[] =
{
/* 000: init GPIB Parameters */
    {&DSET_BO,GPIBCMD,IB_Q_HIGH,"*CLS;:COMM:HEAD 0;:COMM:VERB 0;:STOP;:ACQ:MMOD TRIG;:TRIG:MMOD NORM;:MON:VERB 1;*SRE 8;:STAT:FILT1 FALL;:STAT:EESE 1;:DAT:BYT %s",NULL,0,200,boInit,0,0,NULL,NULL,0},
/* 001: reset scope : BO  */
    {&DSET_BO,GPIBCMD,IB_Q_HIGH,"*RST",NULL,0,0,NULL,0,0,NULL,NULL,0},
/* 002: get number of channels : AI */
    {&DSET_AI,GPIBCVTIO,IB_Q_LOW,NULL,NULL,0,50,aiChanNum,0,0,NULL,NULL,NULL},
/* 003: get max history number : AI */
    {&DSET_AI,GPIBREAD,IB_Q_LOW,":WAV:HMAX?","%lf",0,20,aiMaxHistoryNo,0,0,NULL,NULL,NULL},
/* 004: read acquire status BI */
    {&DSET_BI,GPIBREAD,IB_Q_HIGH,":STAT:COND?","%d",0,20,biAcqStat,0,0,NULL,NULL,NULL},
/* 005: Trigger Status */
    {&DSET_MBBI,GPIBREAD,IB_Q_HIGH,":STAT:COND?","%d",0,50,miTrigStat,0,0,NULL,NULL,NULL},
/* 006: read last trigger number : AI */
    {&DSET_AI,GPIBREAD,IB_Q_LOW,":CONT:TRIG:LAC?","%lf",0,50,aiCurrentTrigNo,0,0,NULL,NULL,NULL},
/* 007: Front panel lock control : BO */
    {&DSET_BO,GPIBEFASTO,IB_Q_HIGH,NULL,NULL,0,0,NULL,0,0,frontPanelLockCmd,NULL,0},
/* 008: Front panel lock status BI */
    {&DSET_BI,GPIBEFASTI,IB_Q_HIGH,":SYST:KEYL?",NULL,0,50,NULL,0,0,frontPanelLockTable,NULL,NULL},
/* 009: */
    FILL,
/* 010: set acquire stop after : BO */
    {&DSET_BO,GPIBEFASTO,IB_Q_HIGH,NULL,NULL,0,0,NULL,0,0,acqModeCmd,NULL,0},
/* 011: read acquire stop after status BI */
    {&DSET_BI,GPIBEFASTI,IB_Q_HIGH,"TRIG:MMOD?",NULL,0,50,NULL,0,0,acqModeTable,NULL,NULL},
/* 012: read recLen : LI */
    {&DSET_LI,GPIBREAD,IB_Q_LOW,":ACQ:TIME?;:TIM:SRAT?","%lf",0,50,liRecLen,0,0,NULL,NULL,NULL},
/* 013: dummy */
    {&DSET_AI,GPIBCVTIO,IB_Q_LOW,NULL,NULL,0,50,NULL,0,0,NULL,NULL,0},
/* 014: set time span : AO */
    {&DSET_AO,GPIBWRITE,IB_Q_LOW,NULL,NULL,0,50,aoTimeSpan,0,0,NULL,NULL,0},
/* 015: set horizontal scale : AO */
    {&DSET_AO,GPIBWRITE,IB_Q_LOW,NULL,NULL,0,50,aoSmplRate,0,0,NULL,NULL,0},
/* 016: read horizontal scale : AI */
    {&DSET_AI,GPIBREAD,IB_Q_LOW,":TIM:SRAT?","%lf",0,50,NULL,0,0,NULL,NULL,NULL},
/* 017: read smplRate A : MBBI */
    {&DSET_MBBI,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,50,miSmplRateA,0,0,NULL,NULL,NULL},
/* 018: read smplRate B : MBBI */
    {&DSET_MBBI,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,50,miSmplRateB,0,0,NULL,NULL,NULL},
/* 019: */
    FILL,
/* 020: set display reference : MBBO */
    {&DSET_MBBO,GPIBEFASTO,IB_Q_HIGH,NULL,NULL,0,0,NULL,0,0,timeRefCmd,NULL,0},
/* 021: read trig pos  : MBBI          */
    {&DSET_MBBI,GPIBREAD,IB_Q_LOW,":TRIG:POS?","%lf",0,50,miTrigPos,0,0,NULL,NULL,NULL},
/* 022: read display reference : AI */
    {&DSET_AI,GPIBREAD,IB_Q_LOW,":TRIG:POS?","%lf",0,20,aiTrigPos,0,0,NULL,NULL,NULL},
/* 023: set delay : AO */
    {&DSET_AO,GPIBWRITE,IB_Q_LOW,NULL,":TRIG:DEL %e",0,50,NULL,0,0,NULL,NULL,0},
/* 024: read delay : AI */
    {&DSET_AI,GPIBREAD,IB_Q_LOW,":TRIG:DEL?","%lf",0,50,NULL,0,0,NULL,NULL,NULL},
/* 025: set holdoff : AO */
    {&DSET_AO,GPIBWRITE,IB_Q_HIGH,NULL,":TRIG:HOLD:TIME %e",0,50,NULL,0,0,NULL,NULL,0},
/* 026: read holdoff : AI */
    {&DSET_AI,GPIBREAD,IB_Q_HIGH,":TRIG:HOLD:TIME?","%lf",0,40,NULL,0,0,NULL,NULL,NULL},
/* 027: set trigger source : MBBO */
    {&DSET_MBBO,GPIBWRITE,IB_Q_HIGH,NULL,NULL,0,30,moTrigSource,0,0,trigSourceCmd,NULL,0},
/* 028: read trigger source mode : MBBI */
    {&DSET_MBBI,GPIBEFASTI,IB_Q_HIGH,":TRIG:SIMP:SOUR?",NULL,0,50,NULL,0,0,trigSourceTable,NULL,NULL},
/* 029: set trigger slope : MBBO */
    {&DSET_MBBO,GPIBEFASTO,IB_Q_HIGH,NULL,NULL,0,0,NULL,0,0,trigSlopeCmd,NULL,0},
/* 030: read trigger slope : MBBI */
    {&DSET_MBBI,GPIBEFASTI,IB_Q_HIGH,":TRIG:SLOP?",NULL,0,50,NULL,0,0,trigSlopeTable,NULL,NULL},
/* 031: set trigger level : AO */
    {&DSET_AO,GPIBWRITE,IB_Q_LOW,NULL,":TRIG:LEV %e",0,30,NULL,0,0,NULL,NULL,0},
/* 032: read trigger level : AI */
    {&DSET_AI,GPIBREAD,IB_Q_HIGH,":TRIG:LEV?","%lf",0,40,NULL,0,0,NULL,NULL,NULL},
/* 033~139: */
    FILL,FILL,FILL,FILL,FILL,FILL,FILL,
/* 040: select Active Channel : MBBO */
    {&DSET_MBBO,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,30,moSelectChannel,0,0,NULL,NULL,NULL},
/* 041: enable channel : BO */
    {&DSET_BO,GPIBWRITE,IB_Q_HIGH,"CHAN%d:DISP %d",NULL,0,40,boEnableChannel,0,0,NULL,NULL,0},
/* 042: read channel enable : BI  */
    {&DSET_BI,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,40,biEnableChannel,0,0,NULL,NULL,NULL},
/* 043: set vertical scale : MBBO */
    {&DSET_MBBO,GPIBWRITE,IB_Q_HIGH,":STOP;CHAN%d:VDIV %s",NULL,0,30,moVdiv,0,0,NULL,NULL,0},
/* 044: read vertical range : MBBI */
    {&DSET_MBBI,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,50,miVdiv,0,0,NULL,NULL,NULL},
/* 045: read vertical range : AI */
    {&DSET_AI,GPIBCVTIO,IB_Q_LOW,NULL,NULL,0,50,aiVdiv,0,0,NULL,NULL,NULL},
/* 046: set coulping : MBBO */
    {&DSET_MBBO,GPIBWRITE,IB_Q_HIGH,":STOP;CHAN%d:COUP %s",NULL,0,30,moCoupling,0,0,NULL,NULL,0},
/* 047: read coupling : MBBI */
    {&DSET_MBBI,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,50,miCoupling,0,0,NULL,NULL,NULL},
/* 048: set probe : MBBO */
    {&DSET_MBBO,GPIBWRITE,IB_Q_HIGH,":STOP;CHAN%d:PROB %s",NULL,0,30,moProbe,0,0,NULL,NULL,0},
/* 049: read probe: MBBI */
    {&DSET_MBBI,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,50,miProbe,0,0,NULL,NULL,NULL},
/* 050: read module name: SI */
    {&DSET_SI,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,100,siModuleName,0,0,NULL,NULL,NULL},
/* 051~066: ch<x> enable : BI  */
    CH_ENABLE_CMD(1),CH_ENABLE_CMD(2),CH_ENABLE_CMD(3),CH_ENABLE_CMD(4),
    CH_ENABLE_CMD(5),CH_ENABLE_CMD(6),CH_ENABLE_CMD(7),CH_ENABLE_CMD(8),
    CH_ENABLE_CMD(9),CH_ENABLE_CMD(10),CH_ENABLE_CMD(11),CH_ENABLE_CMD(12),
    CH_ENABLE_CMD(13),CH_ENABLE_CMD(14),CH_ENABLE_CMD(15),CH_ENABLE_CMD(16),
/* 067~069: */
    FILL,FILL,FILL,
/* 070: start acquisition : BO */
    {&DSET_BO,GPIBWRITE,IB_Q_HIGH,NULL,":STAR",0,20,NULL,0,0,NULL,NULL,0},
/* 071: stop acquisition : BO */
    {&DSET_BO,GPIBWRITE,IB_Q_HIGH,NULL,":STOP",0,20,NULL,0,0,NULL,NULL,0},
/* 072: manual trigger : BO */
    {&DSET_BO,GPIBWRITE,IB_Q_HIGH,NULL,":MTR",0,20,NULL,0,0,NULL,NULL,0},
/* 073: reset trig No. : BO */
    {&DSET_BO,GPIBWRITE,IB_Q_LOW,NULL,NULL,0,50,boResetTrigNo,0,0,NULL,NULL,0},
/* 074~079: */
    FILL,FILL,FILL,FILL,FILL,FILL,
/* 080: update current value : BO */
    {&DSET_BO,GPIBWRITE,IB_Q_HIGH,NULL,":MON:UPD:EXEC",0,20,NULL,0,0,NULL,NULL,0},
/* 081~096: read current value chan1 : AI */
    CURRENT_VAL_CMD(1),CURRENT_VAL_CMD(2),CURRENT_VAL_CMD(3),CURRENT_VAL_CMD(4),
    CURRENT_VAL_CMD(5),CURRENT_VAL_CMD(6),CURRENT_VAL_CMD(7),CURRENT_VAL_CMD(8),
    CURRENT_VAL_CMD(9),CURRENT_VAL_CMD(10),CURRENT_VAL_CMD(11),CURRENT_VAL_CMD(12),
    CURRENT_VAL_CMD(13),CURRENT_VAL_CMD(14),CURRENT_VAL_CMD(15),CURRENT_VAL_CMD(16),
/* 097~099: */
    FILL,FILL,FILL,
/* 100: set relative trigger no : AO */
    {&DSET_AO,GPIBCVTIO,IB_Q_LOW,"dummy","%lf",0,0,aoDispWaveHistNo,0,0,NULL,NULL,NULL},
/* 101: length of waveform data : MBBO */
    {&DSET_MBBO,GPIBCVTIO,IB_Q_LOW,"dummy","%d",0,0,moWaveLen,0,0,NULL,NULL,NULL},
/* 102: get length for DispWave : AI */
    {&DSET_AI,GPIBCVTIO,IB_Q_LOW,NULL,NULL,0,50,aiDispWaveLen,0,0,NULL,NULL,NULL},
/* 103: */
    FILL,
/* 104: hold trigger no. diff no : BO */
    {&DSET_BO,GPIBCVTIO,IB_Q_LOW,NULL,NULL,0,0,boDispWaveTrigNoDiffHold,0,0,NULL,NULL,NULL},
/* 105: get access trigger no : AI */
    {&DSET_AI,GPIBCVTIO,IB_Q_LOW,"dummy","%lf",0,0,aiDispWaveTrigNo,0,0,NULL,NULL,NULL},
/* 106: get trigger no diff: AI */
    {&DSET_AI,GPIBCVTIO,IB_Q_LOW,"dummy","%lf",0,0,aiDispWaveTrigNoDiff,0,0,NULL,NULL,NULL},
/* 107: get old trigger no : AI */
    {&DSET_AI,GPIBCVTIO,IB_Q_LOW,"dummy","%lf",0,0,aiOldTrigNo,0,0,NULL,NULL,NULL},
/* 108: set absolute trigger no : AO */
    {&DSET_AO,GPIBCVTIO,IB_Q_LOW,"dummy","%lf",0,0,aoDispWaveTrigNo,0,0,NULL,NULL,NULL},
/* 109: get absolute trigger no : AI */
    {&DSET_AI,GPIBCVTIO,IB_Q_LOW,"dummy","%lf",0,0,aiDispWaveTrigNoAbs,0,0,NULL,NULL,NULL},
/* 110: X axis in time units for dispWave */
    TIME_AXIS_CMD(1),
/* 111~126: get dispWave : WF */
    DISP_DATA_CMD(1),DISP_DATA_CMD(2),DISP_DATA_CMD(3),DISP_DATA_CMD(4),
    DISP_DATA_CMD(5),DISP_DATA_CMD(6),DISP_DATA_CMD(7),DISP_DATA_CMD(8),
    DISP_DATA_CMD(9),DISP_DATA_CMD(10),DISP_DATA_CMD(11),DISP_DATA_CMD(12),
    DISP_DATA_CMD(13),DISP_DATA_CMD(14),DISP_DATA_CMD(15),DISP_DATA_CMD(16),
/* 127: get dispWave of all channels : WF */
    {&DSET_WF,GPIBCVTIO,IB_Q_LOW,":ACQ:TIME?;:TIM:SRAT?;:WAV:TRAC 1; GAIN?; OFFS?;:WAV:TRAC 2; GAIN?; OFFS?;:WAV:TRAC 3; GAIN?; OFFS?;:WAV:TRAC 4; GAIN?; OFFS?;:WAV:TRAC 5; GAIN?; OFFS?;:WAV:TRAC 6; GAIN?; OFFS?;:WAV:TRAC 7; GAIN?; OFFS?;:WAV:TRAC 8; GAIN?; OFFS?;:WAV:TRAC 9; GAIN?; OFFS?;:WAV:TRAC 10; GAIN?; OFFS?;:WAV:TRAC 11; GAIN?; OFFS?;:WAV:TRAC 12; GAIN?; OFFS?;:WAV:TRAC 13; GAIN?; OFFS?;:WAV:TRAC 14; GAIN?; OFFS?;:WAV:TRAC 15; GAIN?; OFFS?;:WAV:TRAC 16; GAIN?; OFFS?;:CONT:TRIG:LAC?;:WAV:HMAX?", "%lf", 0, SL1000_RAW_WAVE_LEN, convertDispWaveAll, 0 , 0, NULL, NULL, NULL},
/* 128~129: */
    FILL,FILL,
/* 130: select Channel Number for Waveform : MBBO */
    {&DSET_MBBO,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,30,moWaveChan,0,0,NULL,NULL,NULL},
/* 131: set relative trigger no for Wf: AO */
    {&DSET_AO,GPIBCVTIO,IB_Q_LOW,"dummy","%lf",0,0,aoWaveHistNo,0,0,NULL,NULL,NULL},
/* 132: set length for Wave: AO */
    {&DSET_AO,GPIBCVTIO,IB_Q_LOW,"dummy","%lf",0,0,aoWaveLen,0,0,NULL,NULL,NULL},
/* 133: get length for Wave : AI */
    {&DSET_AI,GPIBCVTIO,IB_Q_LOW,NULL,NULL,0,50,aiWaveLen,0,0,NULL,NULL,NULL},
/* 134: set position for Wave: AO */
    {&DSET_AO,GPIBCVTIO,IB_Q_LOW,"dummy","%lf",0,0,aoWavePos,0,0,NULL,NULL,NULL},
/* 135: get access trigger no for Wf: AI */
    {&DSET_AI,GPIBCVTIO,IB_Q_LOW,"dummy","%lf",0,0,aiWaveTrigNo,0,0,NULL,NULL,NULL},
/* 136: X axis in time units for raw wave */
    TIME_AXIS_CMD(0),
/* 137: get wave : WF */
    {&DSET_WF, GPIBCVTIO, IB_Q_LOW, ":ACQ:TIME?;:TIM:SRAT?;:WAV:TRAC %d; GAIN?; OFFS?;:CONT:TRIG:LAC?;:WAV:HMAX?", "%lf", 0, SL1000_RAW_WAVE_LEN, convertWave, 0 , 0, NULL, NULL, NULL},
/* 138: set absolute trigger no for Wf: AO */
    {&DSET_AO,GPIBCVTIO,IB_Q_LOW,"dummy","%lf",0,0,aoWaveTrigNoAbs,0,0,NULL,NULL,NULL},
/* 139: get absolute trigger no for Wf: AI */
    {&DSET_AI,GPIBCVTIO,IB_Q_LOW,"dummy","%lf",0,0,aiWaveTrigNoAbs,0,0,NULL,NULL,NULL},
/* 140: read enable SRQ: BO  */
    {&DSET_BO,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,10,boSrqEnable,0,0,NULL,NULL,NULL},
/* 141: read enable SRQ: BI  */
    {&DSET_BI,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,10,biSrqEnable,0,0,NULL,NULL,NULL},
/* 142: release SRQ : BO */
    {&DSET_BO,GPIBWRITE,IB_Q_HIGH,NULL,NULL,0,20,boReleaseSrq,0,0,NULL,NULL,NULL},
/* 143: SRQ Hnadler */
    { &DSET_LI,GPIBSRQHANDLER,IB_Q_HIGH,NULL,NULL,0,0,NULL,0,0,NULL,NULL,NULL},
/* 144~149: */
    FILL,FILL,FILL,FILL,FILL,FILL,
/* 150: setup name : SO */
    {&DSET_SO,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,40,soSetupName,0,0,NULL,NULL,0},
/* 151: save setup : BO */
    {&DSET_BO,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,80,boRecallSetup,0,0,NULL,NULL,NULL},
/* 152: save setup : BO */
    {&DSET_BO,GPIBWRITE,IB_Q_HIGH,NULL,NULL,0,80,boSaveSetup,0,0,NULL,NULL,NULL},
/* 153: read setup : WF */
    {&DSET_WF,GPIBREAD,IB_Q_LOW,"CONT:SGET?","%lf",0,2000000,readSetupData,0,0,NULL,NULL,NULL},
/* 154: write setup : WF */
    {&DSET_WF,GPIBWRITE,IB_Q_LOW,NULL,NULL,0,2000000,writeSetupData,0,0,NULL,NULL,0},
/* 155: write a long response string */
    {&DSET_WF,GPIBWRITE,IB_Q_HIGH,NULL,NULL,0,258,writeStringWf,256,0,NULL,NULL,0},
/* 156: read a long response string */
    {&DSET_WF,GPIBREAD,IB_Q_HIGH,"",NULL,0,258,readSetupData,256,0,NULL,NULL,NULL},
/* 157: string output only : SO */
    {&DSET_SO,GPIBWRITE,IB_Q_HIGH,NULL,"%s",0,41,NULL,0,0,NULL,NULL,0},
/* 158: read GPIB device response : SI  */
    {&DSET_SI,GPIBREAD,IB_Q_HIGH,"","%s",0,100,NULL,0,0,NULL,NULL,NULL},
/* 159: select Active Module : MBBO */
    {&DSET_MBBO,GPIBCVTIO,IB_Q_HIGH,NULL,NULL,0,30,moSelectModule,0,0,NULL,NULL,NULL},
/* 160-175 : get rawWave : WF */
    RAW_DATA_CMD(1), RAW_DATA_CMD(2), RAW_DATA_CMD(3), RAW_DATA_CMD(4),
    RAW_DATA_CMD(5), RAW_DATA_CMD(6), RAW_DATA_CMD(7), RAW_DATA_CMD(8),
    RAW_DATA_CMD(9), RAW_DATA_CMD(10), RAW_DATA_CMD(11), RAW_DATA_CMD(12),
    RAW_DATA_CMD(13), RAW_DATA_CMD(14), RAW_DATA_CMD(15), RAW_DATA_CMD(16),
};

/* The following is the number of elements in the command array above.  */
#define NUMPARAMS       sizeof(gpibCmds)/sizeof(struct gpibCmd)


/*****************************************************************************
 *
 * Structure containing the user's functions and operating parameters needed
 * by the gpib library functions.
 *
 *****************************************************************************/

static long init_ai(int parm)
{
  if (parm == 0)
  {
    devSupParms.name = NAME(SL1000);     /* device support module type name */
    devSupParms.gpibCmds = gpibCmds;     /* GPIB command array */
    devSupParms.numparams = NUMPARAMS;   /* number of supported parameters */
    devSupParms.timeout = TIMEOUT;       /* I/O time limit (msec) */
    devSupParms.timeWindow = TIMEWINDOW; /* # of milliseconds to skip after a device times out */
    devSupParms.respond2Writes = -1;     /* set pos if the device responds to writes */
    init_sval();                         /* initialize static data */
  }
  return(0);
}

/****************************************************************************
 *
 * Custom convert routines for SL1000
 *
 ***************************************************************************/

static int
convertWave(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct waveformRecord *pwf= (struct waveformRecord *)pdpvt->precord;
  asynUser *pasynUser = pdpvt->pasynUser;
  gpibCmd *pgpibCmd = gpibCmdGet(pdpvt);
  asynOctet *pasynOctet = pdpvt->pasynOctet;
  void *asynOctetPvt = pdpvt->asynOctetPvt;
  STATIC_VAL *psval = get_sval(pdpvt);
  signed char *pMsg;
  signed short *pShort;
  float *pFArray;
  double yMult, yOff;
  double dsrat, dspan;
  double lac, aac;
  int i, length, pos, width;
  int iday, ihour, imin, isec, imsec, iusec;
  int ch, nelm, hmax;
  size_t ntrans;
  char cmd[128];
  char stmp[10];

  /* Use channel if specified by P1. Otherwise use channel given by
   * psval->WaveCh which is specified by gpibCmds[130] */
  ch = P1 ? P1 : psval->WaveCh;

  if (!psval->ChEnable[ch-1]) {
     // skip disabled channel
     pwf->nord = 0;
     return 0;
  }

  if(psval->WaveNelm < pwf->nelm)
  {
    psval->WaveNelm = pwf->nelm;
  }
  nelm = psval->WaveNelm;

  sprintf(cmd, pgpibCmd->cmd, ch);
  if(pasynOctet->write(asynOctetPvt,pasynUser,cmd,
                           strlen(cmd),&ntrans) != asynSuccess) {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                                              "convertWaveform write failed");
    return -1;
  }
  if(pdevSupportGpib->readArbitraryBlockProgramData(pdpvt) <= 0) {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                          "convertWaveform readArbitraryBlockProgramData failed");
    return -1;
  }
  /* Confirm wf record is expecting floats */
  if(pwf->ftvl != menuFtypeFLOAT) {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                  "%s.FTVL must be FLOAT\n", pwf->name);
    return -1;
  }

  if(sscanf(pdpvt->msg, "%d,%d,%d,%d,%d,%d;%lg;%lg;%lg;%lf;%d",
      &iday, &ihour, &imin, &isec, &imsec, &iusec, &dsrat,
      &yMult, &yOff, &lac, &hmax) != 11) {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                           "convertWaveform sscanf failed\n");
    return -1;
  }
  dspan = 1e-6*((double)iusec+0.005) +
          1e-3*(double)imsec +
          (double)isec +
          60.0*(double)imin +
          3600.0*(double)ihour +
          86400.0*(double)iday;
  length = (int)(dspan*dsrat);

  if((psval->WavePos > 0) && (psval->WavePos < length))
  {
    pos = psval->WavePos;
  }
  else
  {
    pos = 0;
  }

  if((psval->WaveLen > 0) && (psval->WaveLen < (length - pos)))
  {
    length = psval->WaveLen;
  }
  else
  {
    length = length - pos;
  }

  if(nelm < length)
  {
    length = nelm;
  }
  else
  {
    nelm = length;
  }

  if((psval->WaveTrigNoAbs > 0) &&
     (psval->WaveTrigNoAbs > (lac - (double)psval->HistMax)) &&
     (psval->WaveTrigNoAbs <= lac))
  {
          psval->WaveTrigNo = psval->WaveTrigNoAbs;
  }
  else
  {
    psval->WaveTrigNo = lac + psval->WaveHisNo;
    if(psval->WaveTrigNo < 1)
    {
      psval->WaveTrigNo = 1;
    }
    psval->WaveTrigNoAbs = 0;
  }
  aac = psval->WaveTrigNo;

  if((aac < 1) || (aac < lac-hmax))
  {
    pwf->nord = 0;
    return 0;
  }

  sprintf(cmd, ":DAT:RAW? %d,%.0lf,%d,%d", ch, aac, pos, length);

  if (pasynOctet->write(asynOctetPvt,pasynUser,cmd,
                           strlen(cmd),&ntrans) != asynSuccess)
  {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                                              "convertWaveform write failed");
    return -1;
  }
  if (pdevSupportGpib->readArbitraryBlockProgramData(pdpvt) <= 0) {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                          "convertWaveform readArbitraryBlockProgramData failed");
    return -1;
  }
  if (sscanf(pdpvt->msg, "#%1d", &width) != 1) {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                                               "convertWaveform sscanf failed");
    return -1;
  }

  pMsg = (signed char*)strchr(pdpvt->msg, '#') + 2;
  strncpy(stmp, (char *)pMsg, width);
  pMsg = pMsg + width;
  stmp[width] = '\0';
  sscanf(stmp, "%d", &length);
  length/=sizeof(short);
  length=length-length%2;

  /* initialize short pointer and float pointer */
  pShort= (short *)pMsg;
  pFArray = (float *)pwf->bptr;

  /* Fill in waveform */
  for(i=0; i<length; i++, pShort++, pFArray++)
  {
    short stmp = *pShort;
    *pFArray = (float)((stmp - yOff) * yMult);
  }

  psval->WaveNord = nelm;
  pwf->nord = nelm;
  pwf->hopr = (32767.0 - yOff) * yMult;
  pwf->lopr = (-32767.0 - yOff) *  yMult;

  return 0;
}

static int
convertDispWaveAll(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct waveformRecord *pwf= (struct waveformRecord *)pdpvt->precord;
  asynUser *pasynUser = pdpvt->pasynUser;
  gpibCmd *pgpibCmd = gpibCmdGet(pdpvt);
  asynOctet *pasynOctet = pdpvt->pasynOctet;
  void *asynOctetPvt = pdpvt->asynOctetPvt;
  STATIC_VAL *psval = get_sval(pdpvt);
  signed char *pMsg;
  double dsrat;
  /* double dspan; */
  double lac, aac;
  int length,  width;
  int iday, ihour, imin, isec, imsec, iusec;
  /* int nelm; */
  size_t ntrans;
  char cmd[1024];
  char stmp[10];

  /* nelm = SL1000_DISP_WAVE_LEN*16; */

  if(psval->ParamChangedFlag == 1)
  {
    strcpy(cmd, pgpibCmd->cmd);
    if(pasynOctet->write(asynOctetPvt,pasynUser,cmd,
                           strlen(cmd),&ntrans) != asynSuccess) {
      epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                                              "convertDispWaveAll write failed(1)");
      return -1;
    }
    if(pdevSupportGpib->readArbitraryBlockProgramData(pdpvt) <= 0) {
          epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                            "convertDispWaveAll readArbitraryBlockProgramData failed(1)");
      return -1;
    }
    if (sscanf(pdpvt->msg, "%d,%d,%d,%d,%d,%d;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lg;%lf;%d",
                    &iday, &ihour, &imin, &isec, &imsec, &iusec,
                    &dsrat,
                    &psval->Gain[0], &psval->Offset[0],
                    &psval->Gain[1], &psval->Offset[1],
                    &psval->Gain[2], &psval->Offset[2],
                    &psval->Gain[3], &psval->Offset[3],
                    &psval->Gain[4], &psval->Offset[4],
                    &psval->Gain[5], &psval->Offset[5],
                    &psval->Gain[6], &psval->Offset[6],
                    &psval->Gain[7], &psval->Offset[7],
                    &psval->Gain[8], &psval->Offset[8],
                    &psval->Gain[9], &psval->Offset[9],
                    &psval->Gain[10], &psval->Offset[10],
                    &psval->Gain[11], &psval->Offset[11],
                    &psval->Gain[12], &psval->Offset[12],
                    &psval->Gain[13], &psval->Offset[13],
                    &psval->Gain[14], &psval->Offset[14],
                    &psval->Gain[15], &psval->Offset[15],
                    &lac,
                   &psval->HistMax) != 41) {
      epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                             "convertDispWaveAll sscanf failed(1)\n");
      return -1;
    }
    /*
    dspan = 1e-6*((double)iusec+0.005) +
      1e-3*(double)imsec +
      (double)isec +
      60.0*(double)imin +
      3600.0*(double)ihour +
      86400.0*(double)iday;
    */
    psval->ParamChangedFlag = 0;
  }

  aac = psval->DispWaveTrigNo;
  if(aac < 1)
  {
    pwf->nord = 0;
    return 0;
  }

  sprintf(cmd, ":DAT:DISP:SCAN 1001;:DAT:DISP:SEND? ALL,%.0lf", aac);

  if(pasynOctet->write(asynOctetPvt,pasynUser,cmd,
                           strlen(cmd),&ntrans) != asynSuccess)
  {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                                              "convertDispWaveAll write failed(2)");
    return -1;
  }
  if(pdevSupportGpib->readArbitraryBlockProgramData(pdpvt) <= 0) {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                          "convertDispWaveAll readArbitraryBlockProgramData failed(2)");
    return -1;
  }
  if (sscanf(pdpvt->msg, "#%1d", &width) != 1) {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                                                     "convertDispWaveAll sscanf failed(2)");
    return -1;
  }
  pMsg = (signed char *)strchr(pdpvt->msg, '#') + 2;
  strncpy(stmp, (char *)pMsg, width);
  pMsg = pMsg + width;
  stmp[width] = '\0';
  sscanf(stmp, "%d", &length);
  memcpy(pwf->bptr, pMsg, length);
  psval->DispWaveBuf = (short *)pwf->bptr;

  return 0;
}

static int
convertDispWave(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct waveformRecord *pwf= (struct waveformRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);
  int i, j, nelm, length;
  int ch = P1-1;
  signed short *pShort;
  float *pFArray;
  double yMult, yOff;

  /* get nelm */
  if(psval->DispWaveNelm < pwf->nelm)
  {
    psval->DispWaveNelm = pwf->nelm;
  }
  nelm = psval->DispWaveNelm;

  /* initialize short pointer */
  length = SL1000_DISP_WAVE_LEN;
  for(i=0,j=0; i<ch; i++)
  {
    if(psval->ChEnable[i])
    {
      j += length;
    }
  }
  pShort= &psval->DispWaveBuf[j];


  /* initialize float pointer */
  pFArray = (float *)pwf->bptr;

  /* get convert parameter */
  yMult = psval->Gain[ch];
  yOff  = psval->Offset[ch];

  /* Fill in waveform */
  if(nelm < length)     /* compress */
  {
    for(i=0, j=0; i<nelm; i+=2)
    {
      int firstFlag = 1;
      int maxminFlag = 0;
      short stmpMax =  32767;
      short stmpMin = -32768;
      for(; ((j*nelm)<=((i+1)*length))&&(j<length); j++, pShort++)
      {
        short stmp = *pShort;
        if(firstFlag)
        {
          firstFlag = 0;
          stmpMax = stmpMin = stmp;
        }
        else
        {
          if(stmp > stmpMax)
          {
            maxminFlag = 1;
            stmpMax = stmp;
          }
          else if(stmp < stmpMin)
          {
            maxminFlag = 0;
            stmpMin = stmp;
          }
        }
      }
      if(maxminFlag)
      {
        pFArray[i] = (float)((stmpMin - yOff) * yMult);
        pFArray[i+1] = (float)((stmpMax - yOff) * yMult);
      }
      else
      {
        pFArray[i] = (float)((stmpMax - yOff) * yMult);
        pFArray[i+1] = (float)((stmpMin - yOff) * yMult);
      }
    }
  }
  else if(nelm > length)    /* interpolate */
  {
    for(i=0, j=0; j<length; j++, pShort++)
    {
      short stmp = *pShort;
      float ftmp = (float)((stmp - yOff) * yMult);
      for(; i*length<(j+1)*nelm; i++)
      {
        pFArray[i] = ftmp;
      }
    }
  }
  else              /* raw */
  {
    for(i=0; i<length; i++, pShort++, pFArray++)
    {
      short stmp = *pShort;
      *pFArray = (float)((stmp - yOff) * yMult);
    }
  }

  psval->DispWaveNord = nelm;

  pwf->nord = nelm;
  pwf->hopr = (32767.0 - yOff) * yMult;
  pwf->lopr = (-32767.0 - yOff) *  yMult;

  return 0;
}

static int
convertTimeAxis(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct waveformRecord *pwf= (struct waveformRecord *)pdpvt->precord;
  asynUser *pasynUser = pdpvt->pasynUser;
  STATIC_VAL *psval = get_sval(pdpvt);
  float *pFTime;
  double xIncr, xZero;
  double dsrat, dtrigpos, dspan;
  int j, length, pos, fullLen, ptOff;
  int iday, ihour, imin, isec, imsec, iusec;
  int nelm;

  sscanf(pdpvt->msg, "%d,%d,%d,%d,%d,%d;%lg;%lg",
          &iday, &ihour, &imin, &isec, &imsec, &iusec, &dsrat, &dtrigpos);
  dspan = 1e-6*((double)iusec) +
          1e-3*(double)imsec +
          (double)isec +
          60.0*(double)imin +
          3600.0*(double)ihour +
          86400.0*(double)iday;
  fullLen = length = (int)(dspan*dsrat);
  pos = 0;

  if(P1==0)  /* raw data */
  {
    if(psval->WaveNelm < pwf->nelm)
    {
      psval->WaveNelm = pwf->nelm;
    }
    nelm = psval->WaveNelm;
    if((psval->WavePos > 0) && (psval->WavePos < length))
    {
      pos = psval->WavePos;
    }

    if((psval->WaveLen > 0) && (psval->WaveLen < (length - pos)))
    {
      length = psval->WaveLen;
    }
    else
    {
       length = length - pos;
    }

    if(nelm < length)
    {
      length = nelm;
    }
    else
    {
      nelm = length;
    }

    xIncr = 1.0/dsrat;
    ptOff = (int)((double)fullLen * dtrigpos / 100.0) - pos;
    pFTime = (float *)pwf->bptr; 
    xZero = 0.0;
    for(j=0; ((j<length) && (j<nelm)); j++)
    {
      pFTime[j] = (((j-ptOff) * xIncr) + xZero) * 1.0e6; 
    }
  }
  else       /* Software P-P commpress/interpolate data */
  {
    if(psval->DispWaveNelm < pwf->nelm)
    {
      psval->DispWaveNelm = pwf->nelm;
    }
    nelm = psval->DispWaveNelm;

    if((psval->DispWaveLen != 0) && ((psval->DispWaveLen < nelm)))
    {
      nelm = psval->DispWaveLen;
    }

    ptOff = (int)((double)nelm * dtrigpos / 100.0);
    pFTime = (float *)pwf->bptr;
    for(j=0; j<nelm; j++)
    {
      pFTime[j] = (dspan * (double)(j-ptOff) / (double)nelm) * 1.0e6;
    }
  }

  asynPrint(pasynUser, ASYN_TRACE_FLOW, "\nTotal count = %d\n ", j);
  pwf->nord = j;

  return 0;
}

static int
aiCurrentVal(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aiRecord *pai= (struct aiRecord *)pdpvt->precord;
  asynUser *pasynUser = pdpvt->pasynUser;
  gpibCmd *pgpibCmd = gpibCmdGet(pdpvt);
  asynOctet *pasynOctet = pdpvt->pasynOctet;
  void *asynOctetPvt = pdpvt->asynOctetPvt;
  STATIC_VAL *psval = get_sval(pdpvt);
  char cmd[128];
  size_t ntrans;
  double ftmp;

  if(P1 > psval->ChNum)
  {
    pai->val = 0.0;
    return 0;
  }

  sprintf(cmd, pgpibCmd->cmd, P1);
  if(pasynOctet->write(asynOctetPvt,pasynUser,cmd,strlen(cmd),&ntrans)!=asynSuccess)
  {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                                                        "aiCurrentVal write failed");
    return -1;

  }
  if(pasynOctet->read(asynOctetPvt,pdpvt->pasynUser,cmd,sizeof(cmd)-1,&ntrans,NULL) != asynSuccess)
  {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                                                        "aiCurrentVal read failed");
    return -1;
  }

  ftmp = strtod(cmd+9, NULL);

  switch(cmd[20])
  {
    case 'u':   ftmp /= 1.0e-6;     break;
    case 'm':   ftmp /= 1000.0;     break;
    case 'k':   ftmp *= 1000.0;     break;
    case 'M':   ftmp *= 1.0e6;      break;
  }
  pai->val = ftmp;

  return 0;
}


static int
boInit(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  gpibCmd *pgpibCmd = gpibCmdGet(pdpvt);

  if(_byte_order == BYTE_ORDER_LSB)
  {
    sprintf(pdpvt->msg, pgpibCmd->cmd, "LSBF");
  }
  else   /* if(_byte_order == BYTE_ORDER_MSB) */
  {
    sprintf(pdpvt->msg, pgpibCmd->cmd, "MSBF");
  }
  return 0;
}


static int
readSetupData(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct waveformRecord *pwf= (struct waveformRecord *)pdpvt->precord;
  int ncopy;

  if(pdpvt->msgInputLen <= pwf->nelm) {
    ncopy = pdpvt->msgInputLen;
  }
  else {
    ncopy = pwf->nelm;
    errlogPrintf("%s readSetupData() truncating %d bytes to %u byte .NELM\n",
                                    pwf->name, pdpvt->msgInputLen, pwf->nelm);
  }
  memcpy(pwf->bptr,&pdpvt->msg[0],ncopy);
  pwf->nord=ncopy;
  return(0);
}

static int
writeSetupData(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct waveformRecord *pwf= (struct waveformRecord *)pdpvt->precord;

  strncpy(&pdpvt->msg[0],":CONT:SSET ",11);
  memcpy(&pdpvt->msg[10],pwf->bptr,pwf->nord);
  return(pwf->nord+10);
}

static int
writeStringWf(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct waveformRecord *pwf= (struct waveformRecord *)pdpvt->precord;
  int nelm;

  nelm = (pwf->nord < P1)?pwf->nord:P1;
  memcpy(&pdpvt->msg[0],pwf->bptr,nelm);
  return(nelm);
}

static int
aoSmplRate(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aoRecord *pao= (struct aoRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  if(psval->AcqStat)
  {
    sprintf(pdpvt->msg, ":STOP;:TIM:SRAT %e;:STAR", pao->oval);
  }
  else
  {
    sprintf(pdpvt->msg, ":TIM:SRAT %e", pao->oval);
  }
  psval->ParamChangedFlag = 1;

  return(strlen(pdpvt->msg));
}

static void
getTimeSpanSettingCmd(double second, char *buf, int acqStat)
{
  int day, hour, min, sec, msec, usec;

  second = second + 0.5e-6;    /* round by 1usec */

  sec = (int)second;
  usec = (int)(1000000.0 * (second - (double)sec));

  day  = sec  / (60 * 60 * 24);       sec  %= (60 * 60 * 24);
  hour = sec  / (60 * 60);            sec  %= (60 * 60);
  min  = sec  / (60);                 sec  %= 60;
  msec = usec / 1000;                 usec %= 1000;

  if(acqStat)
  {
    sprintf(buf, ":STOP;:ACQ:TIME %d,%d,%d,%d,%d,%d;:STAR", day, hour, min, sec, msec, usec);
  }
  else
  {
    sprintf(buf, ":ACQ:TIME %d,%d,%d,%d,%d,%d", day, hour, min, sec, msec, usec);
  }
}

static int
aoTimeSpan(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aoRecord *pao= (struct aoRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  getTimeSpanSettingCmd(pao->oval, pdpvt->msg, psval->AcqStat);
  psval->ParamChangedFlag = 1;

  return(strlen(pdpvt->msg));
}

static int
aiCurrentTrigNo(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aiRecord *pai= (struct aiRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  double lac;

  sscanf(pdpvt->msg, "%lf", &lac);

  pai->val = lac;
  psval->CurrentTrigNo = lac;

  if((psval->DispWaveTrigNoAbs > 0) &&
     (psval->DispWaveTrigNoAbs > (lac - (double)psval->HistMax)) &&
     (psval->DispWaveTrigNoAbs <= lac))
  {
    psval->DispWaveTrigNo = psval->DispWaveTrigNoAbs;
  }
  else
  {
    psval->DispWaveTrigNo = psval->CurrentTrigNo + psval->DispWaveHisNo;
    if(psval->DispWaveTrigNo < 1)
    {
      psval->DispWaveTrigNo = 1;
    }
    psval->DispWaveTrigNoAbs = 0;
  }

  return 0;
}


static int
aiMaxHistoryNo(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aiRecord *pai= (struct aiRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  int maxHis;

  sscanf(pdpvt->msg, "%d", &maxHis);

  if(maxHis > 0)
  {
    pai->val = maxHis;
  }
  else
  {
    pai->val = 5000;
  }

  psval->HistMax = (int)(pai->val+0.5);

  return 0;
}

static int
boResetTrigNo(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  STATIC_VAL *psval = get_sval(pdpvt);

  if(psval->AcqStat)
  {
    sprintf(pdpvt->msg, ":STOP;:HIST:CLE;:STAR");
  }
  else
  {
    sprintf(pdpvt->msg, ":HIST:CLE");
  }

  return(strlen(pdpvt->msg));
}

static int
aoDispWaveHistNo(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aoRecord *pao= (struct aoRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  psval->DispWaveHisNo = pao->val;

  if((psval->DispWaveTrigNoAbs > 0) &&
     (psval->DispWaveTrigNoAbs > (psval->CurrentTrigNo - (double)psval->HistMax)) &&
     (psval->DispWaveTrigNoAbs <= psval->CurrentTrigNo))
  {
    psval->DispWaveTrigNo = psval->DispWaveTrigNoAbs;
  }
  else
  {
    psval->DispWaveTrigNo = psval->CurrentTrigNo + psval->DispWaveHisNo;
    if(psval->DispWaveTrigNo < 1)
    {
      psval->DispWaveTrigNo = 1;
    }
    psval->DispWaveTrigNoAbs = 0;
  }

  return 0;
}

static int
aoWaveHistNo(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aoRecord *pao= (struct aoRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  psval->WaveHisNo = pao->val;
  return 0;
}

static int
aoDispWaveTrigNo(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aoRecord *pao= (struct aoRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  if(psval->DispWaveTrigNoAbs == pao->val)
  {
    return 0;
  }

  psval->DispWaveTrigNoAbs = pao->val;

  if((psval->DispWaveTrigNoAbs > 0) &&
     (psval->DispWaveTrigNoAbs > (psval->CurrentTrigNo - (double)psval->HistMax)) &&
     (psval->DispWaveTrigNoAbs <= psval->CurrentTrigNo))
  {
    psval->DispWaveTrigNo = psval->DispWaveTrigNoAbs;
  }
  else
  {
    psval->DispWaveTrigNo = psval->CurrentTrigNo + psval->DispWaveHisNo;
    if(psval->DispWaveTrigNo < 1)
    {
      psval->DispWaveTrigNo = 1;
    }
    psval->DispWaveTrigNoAbs = 0;
  }

  return 0;
}

static int
aiDispWaveTrigNoAbs(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aiRecord *pai= (struct aiRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  pai->val = psval->DispWaveTrigNoAbs;
  return 0;
}

static int
aiDispWaveTrigNo(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aiRecord *pai= (struct aiRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  pai->val = psval->DispWaveTrigNo;
  return 0;
}

static int
aiWaveTrigNo(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aiRecord *pai= (struct aiRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  pai->val = psval->WaveTrigNo;
  return 0;
}

static int
aoWaveTrigNoAbs(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aoRecord *pao= (struct aoRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  if(psval->WaveTrigNoAbs == pao->val)
  {
    return 0;
  }
  psval->WaveTrigNoAbs = pao->val;
  return 0;
}
static int
aiWaveTrigNoAbs(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aiRecord *pai= (struct aiRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  pai->val = psval->WaveTrigNoAbs;
  return 0;
}


static int
aiOldTrigNo(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aiRecord *pai= (struct aiRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  if(psval->DispWaveTrigNoOld > 0)
  {
    psval->DispWaveTrigNoDiff = psval->CurrentTrigNo - psval->DispWaveTrigNoOld;
  }
  else
  {
    psval->DispWaveTrigNoDiff = 1;
  }
  pai->val = psval->DispWaveTrigNoOld = psval->CurrentTrigNo;
  return 0;
}

static int
aiDispWaveTrigNoDiff(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aiRecord *pai= (struct aiRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  if(psval->DispWaveTrigNoDiff < 0)
  {
    pai->val = 0;
  }
  else
  {
    if(psval->DispWaveTrigNoDiffHold)
    {
      if(pai->val < psval->DispWaveTrigNoDiff)
      {
        pai->val = psval->DispWaveTrigNoDiff;
      }
    }
    else
    {
      pai->val = psval->DispWaveTrigNoDiff;
    }
  }
  return 0;
}

static int
boDispWaveTrigNoDiffHold(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct boRecord *pbo= (struct boRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  psval->DispWaveTrigNoDiffHold = pbo->val;
  return 0;
}

static int
miTrigStat(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbbiRecord *pmbbi= (struct mbbiRecord *)pdpvt->precord;

  int conditionRegister = atoi(pdpvt->msg);

  if(conditionRegister & (1<<1))        /* bit1 indicate REC */
  {
    pmbbi->val = 3;
  }
  else if(conditionRegister & (1<<0))   /* bit0 indicate CAP */
  {
    if(conditionRegister & (1<<2))      /* bit2 indicate Awaiting trig */
    {
      pmbbi->val = 1;
    }
    else
    {
      pmbbi->val = 2;
    }
  }
  else
  {
    pmbbi->val = 0;
  }
  pmbbi->rval = pmbbi->val;

  return 0;
}

static int
biAcqStat(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct biRecord *pbi= (struct biRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  int conditionRegister = atoi(pdpvt->msg);

  if(conditionRegister & (1<<12))       /* bit12 indicate RUNNING */
    pbi->val = 1;
  else
    pbi->val = 0;
  pbi->rval = pbi->val;

  psval->AcqStat = pbi->val;

  return 0;
}

static int
boReleaseSrq(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  STATIC_VAL *psval = get_sval(pdpvt);

  if(psval->SrqEnable)
  {
    sprintf(pdpvt->msg, ":STAT:EESR?");
    return(strlen(pdpvt->msg));
  }
  else
  {
    return 0;
  }
}

static int
boSrqEnable(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct boRecord *pbo= (struct boRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  psval->SrqEnable = pbo->val;

  return 0;
}

static int
biSrqEnable(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct biRecord *pbi= (struct biRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  pbi->rval = pbi->val = psval->SrqEnable;
  
  return 0;
}

static int
queryChCmd(struct gpibDpvt *pdpvt, const char *cmd, char *res, int sizeof_res)
{
  asynUser  *pasynUser    = pdpvt->pasynUser;
  asynOctet *pasynOctet   = pdpvt->pasynOctet;
  void      *asynOctetPvt = pdpvt->asynOctetPvt;
  STATIC_VAL *psval = get_sval(pdpvt);
  size_t ntrans;
  char buf[80];

  sprintf(buf, cmd, psval->TargetCh+1);

  if(pasynOctet->write(asynOctetPvt,pasynUser,buf,strlen(buf),&ntrans)!=asynSuccess)
  {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,"write failed");
    return -1;

  }
  if(pasynOctet->read(asynOctetPvt,pdpvt->pasynUser,res,sizeof_res-1,&ntrans,NULL)!=asynSuccess)
  {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,"read failed");
    return -1;
  }
  strtok(res, "\r\n");
  return 0;
}


static int
boEnableChannel(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct boRecord *pbo= (struct boRecord *)pdpvt->precord;
  gpibCmd *pgpibCmd = gpibCmdGet(pdpvt);
  STATIC_VAL *psval = get_sval(pdpvt);

  sprintf(pdpvt->msg, pgpibCmd->cmd, psval->TargetCh+1, pbo->val);
  return 0;
}

static int
biEnableChannel(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct biRecord *pbi= (struct biRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);
  char res[40];

  if(queryChCmd(pdpvt, ":CHAN%d:DISP?", res, sizeof(res)))
  {
    return -1;
  }
  pbi->rval = atoi(res);
  psval->ChEnable[psval->TargetCh] = (char)pbi->rval;
  return 0;
}

static char *(vdivTable[]) = {
    "1.000E-03",
    "2.000E-03",
    "5.000E-03",
    "10.000E-03",
    "20.000E-03",
    "50.000E-03",
    "100.000E-03",
    "200.000E-03",
    "500.000E-03",
    "1.000E+00",
    "2.000E+00",
    "5.000E+00",
    "10.000E+00",
    "20.000E+00",
    "50.000E+00",
    "100.000E+00",
/*
    "200.000E+00",
    "500.000E+00",
    "1.000E+03",
    "2.000E+03",
    "5.000E+03",
    "10.000E+03",
    "20.000E+03",
    "50.000E+03",
*/
    NULL
};

static int
moVdiv(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbboRecord *pmo= (struct mbboRecord *)pdpvt->precord;
  gpibCmd *pgpibCmd = gpibCmdGet(pdpvt);
  STATIC_VAL *psval = get_sval(pdpvt);

  sprintf(pdpvt->msg, pgpibCmd->cmd, psval->TargetCh+1, vdivTable[pmo->val]);
  psval->ParamChangedFlag = 1;
  return 0;
}

static int
miVdiv(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbbiRecord *pmi= (struct mbbiRecord *)pdpvt->precord;
  char res[40];
  int i;

  if(queryChCmd(pdpvt, ":CHAN%d:VDIV?", res, sizeof(res)))
  {
    return -1;
  }
  for(i=0; vdivTable[i] != NULL; i++)
  {
    if(strcmp(vdivTable[i], res)==0)
    {
      if(i>15)
      {
        i = 15;
      }
      pmi->val = pmi->rval = i;
      return 0;
    }
  }
  return -1;
}

static int
aiVdiv(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aiRecord *pai= (struct aiRecord *)pdpvt->precord;
  char res[40];

  if(queryChCmd(pdpvt, ":CHAN%d:VDIV?", res, sizeof(res)))
  {
    return -1;
  }
  pai->val = strtod(res, NULL);
  return 0;
}

static char *(couplingTable[]) = {
    "DC",
    "AC",
    "GND",
    NULL
};

static int
moCoupling(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbboRecord *pmo= (struct mbboRecord *)pdpvt->precord;
  gpibCmd *pgpibCmd = gpibCmdGet(pdpvt);
  STATIC_VAL *psval = get_sval(pdpvt);

  sprintf(pdpvt->msg, pgpibCmd->cmd, psval->TargetCh+1, couplingTable[pmo->val]);
  return 0;
}

static int
miCoupling(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbbiRecord *pmi= (struct mbbiRecord *)pdpvt->precord;
  char res[40];
  int i;

  if(queryChCmd(pdpvt, ":CHAN%d:COUP?", res, sizeof(res)))
  {
    return -1;
  }
  for(i=0; couplingTable[i] != NULL; i++)
  {
    if(strcmp(couplingTable[i], res)==0)
    {
      pmi->val = pmi->rval = i;
      return 0;
    }
  }
  return -1;
}


static char *(probeTable[]) = {
    "1",
    "10",
    "100",
    "1000",
    NULL
};

static int
moProbe(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbboRecord *pmo= (struct mbboRecord *)pdpvt->precord;
  gpibCmd *pgpibCmd = gpibCmdGet(pdpvt);
  STATIC_VAL *psval = get_sval(pdpvt);

  sprintf(pdpvt->msg, pgpibCmd->cmd, psval->TargetCh+1, probeTable[pmo->val]);
  psval->ParamChangedFlag = 1;
  return 0;
}

static int
miProbe(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbbiRecord *pmi= (struct mbbiRecord *)pdpvt->precord;
  char res[40];
  int i;

  if(queryChCmd(pdpvt, ":CHAN%d:PROB?", res, sizeof(res)))
  {
    return -1;
  }
  for(i=0; probeTable[i] != NULL; i++)
  {
    if(strcmp(probeTable[i], res)==0)
    {
      pmi->val = pmi->rval = i;
      return 0;
    }
  }
  return -1;
}

static int
siModuleName(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct stringinRecord *psi= (struct stringinRecord *)pdpvt->precord;
  char res[40];

  if(queryChCmd(pdpvt, ":CHAN%d:MODU?", res, sizeof(res)))
  {
    return -1;
  }
  strncpy(psi->val, &res[1], 39);
  return 0;
}

static int
moSelectChannel(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbboRecord *pmo= (struct mbboRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  /* Remove unnecessary items. (Only as for the first of the beginning.) */
  if((psval->ChNum < 16) && (pmo->ffvl != 0))
  {
    switch(psval->ChNum)
    {
      case  0: pmo->zrvl = 0; pmo->zrst[0] = 0;
      case  1: pmo->onvl = 0; pmo->onst[0] = 0;
      case  2: pmo->twvl = 0; pmo->twst[0] = 0;
      case  3: pmo->thvl = 0; pmo->thst[0] = 0;
      case  4: pmo->frvl = 0; pmo->frst[0] = 0;
      case  5: pmo->fvvl = 0; pmo->fvst[0] = 0;
      case  6: pmo->sxvl = 0; pmo->sxst[0] = 0;
      case  7: pmo->svvl = 0; pmo->svst[0] = 0;
      case  8: pmo->eivl = 0; pmo->eist[0] = 0;
      case  9: pmo->nivl = 0; pmo->nist[0] = 0;
      case 10: pmo->tevl = 0; pmo->test[0] = 0;
      case 11: pmo->elvl = 0; pmo->elst[0] = 0;
      case 12: pmo->tvvl = 0; pmo->tvst[0] = 0;
      case 13: pmo->ttvl = 0; pmo->ttst[0] = 0;
      case 14: pmo->ftvl = 0; pmo->ftst[0] = 0;
      case 15: pmo->ffvl = 0; pmo->ffst[0] = 0;
    }
  }
  if(pmo->val >= psval->ChNum)
  {
    pmo->val = psval->ChNum - 1;
  }
  psval->TargetCh = pmo->val;
  return 0;
}

static int
moSelectModule(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbboRecord *pmo= (struct mbboRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  /* Remove unnecessary items. (Only as for the first of the beginning.) */
  if((psval->ModNum < 8) && (pmo->svvl != 0))
  {
    switch(psval->ModNum)
    {
      case  0: pmo->zrvl = 0; pmo->zrst[0] = 0;
      case  1: pmo->onvl = 0; pmo->onst[0] = 0;
      case  2: pmo->twvl = 0; pmo->twst[0] = 0;
      case  3: pmo->thvl = 0; pmo->thst[0] = 0;
      case  4: pmo->frvl = 0; pmo->frst[0] = 0;
      case  5: pmo->fvvl = 0; pmo->fvst[0] = 0;
      case  6: pmo->sxvl = 0; pmo->sxst[0] = 0;
      case  7: pmo->svvl = 0; pmo->svst[0] = 0;
    }
  }
  if(pmo->val >= psval->ModNum)
  {
    pmo->val = psval->ModNum - 1;
  }
  psval->TargetMod = pmo->val;
  return 0;
}

static int
moWaveChan(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbboRecord *pmo= (struct mbboRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  /* Remove unnecessary items. (Only as for the first of the beginning.) */
  if((psval->ChNum < 16) && (pmo->ffvl != 0))
  {
    switch(psval->ChNum)
    {
      case  0: pmo->zrvl = 0; pmo->zrst[0] = 0;
      case  1: pmo->onvl = 0; pmo->onst[0] = 0;
      case  2: pmo->twvl = 0; pmo->twst[0] = 0;
      case  3: pmo->thvl = 0; pmo->thst[0] = 0;
      case  4: pmo->frvl = 0; pmo->frst[0] = 0;
      case  5: pmo->fvvl = 0; pmo->fvst[0] = 0;
      case  6: pmo->sxvl = 0; pmo->sxst[0] = 0;
      case  7: pmo->svvl = 0; pmo->svst[0] = 0;
      case  8: pmo->eivl = 0; pmo->eist[0] = 0;
      case  9: pmo->nivl = 0; pmo->nist[0] = 0;
      case 10: pmo->tevl = 0; pmo->test[0] = 0;
      case 11: pmo->elvl = 0; pmo->elst[0] = 0;
      case 12: pmo->tvvl = 0; pmo->tvst[0] = 0;
      case 13: pmo->ttvl = 0; pmo->ttst[0] = 0;
      case 14: pmo->ftvl = 0; pmo->ftst[0] = 0;
      case 15: pmo->ffvl = 0; pmo->ffst[0] = 0;
    }
  }
  if(pmo->val >= psval->ChNum)
  {
    pmo->val = psval->ChNum - 1;
  }
  psval->WaveCh = pmo->val + 1;
  return 0;
}

static int
aiChanNum(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aiRecord *pai= (struct aiRecord *)pdpvt->precord;
  char res[256];
  asynUser  *pasynUser    = pdpvt->pasynUser;
  asynOctet *pasynOctet   = pdpvt->pasynOctet;
  void      *asynOctetPvt = pdpvt->asynOctetPvt;
  STATIC_VAL *psval = get_sval(pdpvt);
  size_t ntrans;
  int i;
  const char *cmd = ":CHAN1:DISP?;:CHAN2:DISP?;:CHAN3:DISP?;:CHAN4:DISP?;:CHAN5:DISP?;:CHAN6:DISP?;:CHAN7:DISP?;:CHAN8:DISP?;:CHAN9:DISP?;:CHAN10:DISP?;:CHAN11:DISP?;:CHAN12:DISP?;:CHAN13:DISP?;:CHAN14:DISP?;:CHAN15:DISP?;:CHAN16:DISP?";

  if(pasynOctet->write(asynOctetPvt,pasynUser,cmd,strlen(cmd),&ntrans)!=asynSuccess)
  {
    epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,"write failed");
    return -1;

  }
  if(pasynOctet->read(asynOctetPvt,pdpvt->pasynUser,res,sizeof(res)-1,&ntrans,NULL)!=asynSuccess)
  {
    psval->ChNum = 0;
    return 0;
  }
  strtok(res, "\r\n");
  psval->ChNum = (strlen(res) + 1) / 2;
  psval->ModNum = psval->ChNum / 2;
  pai->val = psval->ChNum;

  for(i=0; i<psval->ChNum; i++)
  {
    psval->ChEnable[i] = (char)atoi(&res[i*2]);
  }
  return 0;
}

static int
biChEnable(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct biRecord *pbi= (struct biRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  pbi->rval = psval->ChEnable[P1-1];

  return 0;
}

static int
moTrigSource(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbboRecord *pmo= (struct mbboRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  /* Remove unnecessary items. (Only as for the first of the beginning.) */
  if((psval->ChNum < 14) && (pmo->ffvl != 0))
  {
    switch(psval->ChNum)
    {
      case  0: pmo->twvl = 0; pmo->twst[0] = 0;
      case  1: pmo->thvl = 0; pmo->thst[0] = 0;
      case  2: pmo->frvl = 0; pmo->frst[0] = 0;
      case  3: pmo->fvvl = 0; pmo->fvst[0] = 0;
      case  4: pmo->sxvl = 0; pmo->sxst[0] = 0;
      case  5: pmo->svvl = 0; pmo->svst[0] = 0;
      case  6: pmo->eivl = 0; pmo->eist[0] = 0;
      case  7: pmo->nivl = 0; pmo->nist[0] = 0;
      case  8: pmo->tevl = 0; pmo->test[0] = 0;
      case  9: pmo->elvl = 0; pmo->elst[0] = 0;
      case 10: pmo->tvvl = 0; pmo->tvst[0] = 0;
      case 11: pmo->ttvl = 0; pmo->ttst[0] = 0;
      case 12: pmo->ftvl = 0; pmo->ftst[0] = 0;
      default: pmo->ffvl = 0; pmo->ffst[0] = 0;
    }
  }

  if(pmo->val >= psval->ChNum + 2)
  {
    pmo->val = psval->ChNum + 1;
  }

  sprintf(pdpvt->msg, "%s", P3[pmo->val]);

  return(strlen(pdpvt->msg));
}


static int
miTrigPos(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbbiRecord *pmi= (struct mbbiRecord *)pdpvt->precord;
  double dpos;
  STATIC_VAL *psval = get_sval(pdpvt);

  sscanf(pdpvt->msg, "%lf", &dpos);
  pmi->val = pmi->rval = ((int)(dpos/10.0 + 0.5));
  psval->ParamChangedFlag = 1;

  return 0;
}

static int
aiTrigPos(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aiRecord *pai= (struct aiRecord *)pdpvt->precord;
  double dpos;

  sscanf(pdpvt->msg, "%lf", &dpos);
  pai->rval = pai->val = (double)((int)(dpos + 0.5));

  return 0;
}



static int
miSmplRateB(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbbiRecord *pmi= (struct mbbiRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);
  double dsrat = psval->SmplRate;

  if(dsrat<1.0e3*0.9999999)       { pmi->val = 2; pmi->rval = 0; }
  else if(dsrat<1.0e6*0.9999999)  { pmi->val = 1; pmi->rval = 3; }
  else                            { pmi->val = 0; pmi->rval = 6; }

  return 0;
}

static int
miSmplRateA(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbbiRecord *pmi= (struct mbbiRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);
  double dsrat = psval->SmplRate;

  while(dsrat>=1000*0.9999999)
  {
    dsrat /= 1000;
  }
  if(dsrat<=1.0)         { pmi->val = 0; pmi->rval = 1; }
  else if(dsrat<=2.0)    { pmi->val = 1; pmi->rval = 2; }
  else if(dsrat<=5.0)    { pmi->val = 2; pmi->rval = 5; }
  else if(dsrat<=10.0)   { pmi->val = 3; pmi->rval = 10; }
  else if(dsrat<=20.0)   { pmi->val = 4; pmi->rval = 20; }
  else if(dsrat<=50.0)   { pmi->val = 5; pmi->rval = 50; }
  else if(dsrat<=100.0)  { pmi->val = 6; pmi->rval = 100; }
  else if(dsrat<=200.0)  { pmi->val = 7; pmi->rval = 200; }
  else                   { pmi->val = 8; pmi->rval = 500; }

  return 0;
}

static int
liRecLen(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct longinRecord *pmi= (struct longinRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);
  int iday, ihour, imin, isec, imsec, iusec, length;
  double dsrat, dspan;

  sscanf(pdpvt->msg, "%d,%d,%d,%d,%d,%d;%lg", &iday, &ihour, &imin, &isec, &imsec, &iusec, &dsrat);
  dspan = 1e-6*((double)iusec) +
              1e-3*(double)imsec +
              (double)isec +
              60.0*(double)imin +
              3600.0*(double)ihour +
              86400.0*(double)iday;
  length = (int)(dspan*dsrat+0.1);

  psval->RecLen = length;

  if(dsrat<=5.0)           dsrat = 5.0;
  else if(dsrat<=10.0)     dsrat = 10.0;
  else if(dsrat<=20.0)     dsrat = 20.0;
  else if(dsrat<=50.0)     dsrat = 50.0;
  else if(dsrat<=100.0)    dsrat = 100.0;
  else if(dsrat<=200.0)    dsrat = 200.0;
  else if(dsrat<=500.0)    dsrat = 500.0;
  else if(dsrat<=1.0e3)    dsrat = 1.0e3;
  else if(dsrat<=2.0e3)    dsrat = 2.0e3;
  else if(dsrat<=5.0e3)    dsrat = 5.0e3;
  else if(dsrat<=10.0e3)   dsrat = 10.0e3;
  else if(dsrat<=20.0e3)   dsrat = 20.0e3;
  else if(dsrat<=50.0e3)   dsrat = 50.0e3;
  else if(dsrat<=100.0e3)  dsrat = 100.0e3;
  else if(dsrat<=200.0e3)  dsrat = 200.0e3;
  else if(dsrat<=500.0e3)  dsrat = 500.0e3;
  else if(dsrat<=1.0e6)    dsrat = 1.0e6;
  else if(dsrat<=2.0e6)    dsrat = 2.0e6;
  else if(dsrat<=5.0e6)    dsrat = 5.0e6;
  else if(dsrat<=10.0e6)   dsrat = 10.0e6;
  else if(dsrat<=20.0e6)   dsrat = 20.0e6;
  else if(dsrat<=50.0e6)   dsrat = 50.0e6;
  else                     dsrat = 100.0e6;
  psval->SmplRate = dsrat;

  pmi->val = length;

  return 0;
}

static int
moWaveLen(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct mbboRecord *pmo= (struct mbboRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  psval->DispWaveLen = pmo->rval;
  return 0;
}

static int
aoWaveLen(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aoRecord *pao= (struct aoRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  psval->WaveLen = pao->val;
  return 0;
}

static int
aiWaveLen(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aiRecord *pai= (struct aiRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  pai->val = psval->WaveNord;
  return 0;
}

static int
aiDispWaveLen(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aiRecord *pai= (struct aiRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  pai->val = psval->DispWaveNord;
  return 0;
}



static int
aoWavePos(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct aoRecord *pao= (struct aoRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  psval->WavePos = pao->val;
  return 0;
}


static int
soSetupName(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  struct stringoutRecord *pso= (struct stringoutRecord *)pdpvt->precord;
  STATIC_VAL *psval = get_sval(pdpvt);

  strncpy(psval->SetupDataName, pso->val, 40);
  psval->SetupDataName[39] = '\0';

  return 0;
}


static int
boSaveSetup(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  asynUser *pasynUser = pdpvt->pasynUser;
  void *asynOctetPvt = pdpvt->asynOctetPvt;
  asynOctet *pasynOctet = pdpvt->pasynOctet;
  STATIC_VAL *psval = get_sval(pdpvt);
  size_t ntrans;
  char cmd[256];

  if((strlen(psval->SetupDataName) < 40) && (strlen(psval->SetupDataName) != 0))
  {
    /* check same file already exist */
    sprintf(cmd, ":FILE:IO:READ:NAME \"%s.SET\";:FILE:IO:READ:OPEN?", psval->SetupDataName);
    if(pasynOctet->write(asynOctetPvt,pasynUser,cmd,strlen(cmd),&ntrans)!=asynSuccess)
    {
      return -1;
    }
    if(pasynOctet->read(asynOctetPvt,pdpvt->pasynUser,cmd,sizeof(cmd)-1,&ntrans,NULL) != asynSuccess)
    {
      return -1;
    }
    /* if exist, remove it */
    if(atoi(cmd) > 0)
    {
      sprintf(cmd, ":FILE:IO:READ:CLOS;:FILE:DEL \"%s.SET\"", psval->SetupDataName);
      if(pasynOctet->write(asynOctetPvt,pasynUser,cmd,strlen(cmd),&ntrans)!=asynSuccess)
      {
        return -1;
      }
    }
    /* save setup */
    sprintf(pdpvt->msg, ":FILE:SAVE:ANAM OFF;:FILE:SAVE:NAME \"%s\";:FILE:SAVE:SET:EXEC", psval->SetupDataName);
    return(strlen(pdpvt->msg));
  }
  else
  {
    return 0;
  }
}

static int
boRecallSetup(struct gpibDpvt *pdpvt, int P1, int P2, char **P3)
{
  asynUser *pasynUser = pdpvt->pasynUser;
  void *asynOctetPvt = pdpvt->asynOctetPvt;
  asynOctet *pasynOctet = pdpvt->pasynOctet;
  STATIC_VAL *psval = get_sval(pdpvt);
  size_t ntrans;
  char cmd[256];


  if((strlen(psval->SetupDataName) < 40) && (strlen(psval->SetupDataName) != 0))
  {
    sprintf(cmd, ":COMM:OPSE 64;:FILE:LOAD:SET \"%s\";*OPC?", psval->SetupDataName);
  }
  else
  {
    return -1;
  }

  if(pasynOctet->write(asynOctetPvt,pasynUser,cmd,strlen(cmd),&ntrans) != asynSuccess)
  {
    return -1;
  }
  sleep(4);  /* wait for recall proc finished */
  if(pasynOctet->read(asynOctetPvt,pdpvt->pasynUser,cmd,sizeof(cmd)-1,&ntrans,NULL) != asynSuccess)
  {
    return -1;
  }
  return 0;
}
