From ce3ea84923dfb9732a7ffdf81b44e6f90e548eeb Mon Sep 17 00:00:00 2001
From: Erik von Reis <evonreis@caltech.edu>
Date: Fri, 5 Jun 2020 10:22:46 -0700
Subject: [PATCH] put awgapi.h and awgapi.c back in

---
 src/gds/CMakeLists.txt |    2 +
 src/gds/awgapi.c       | 2888 ++++++++++++++++++++++++++++++++++++++++
 src/gds/awgapi.h       |  441 ++++++
 3 files changed, 3331 insertions(+)
 create mode 100644 src/gds/awgapi.c
 create mode 100644 src/gds/awgapi.h

diff --git a/src/gds/CMakeLists.txt b/src/gds/CMakeLists.txt
index 90f25c5b1..2911183dd 100644
--- a/src/gds/CMakeLists.txt
+++ b/src/gds/CMakeLists.txt
@@ -11,6 +11,7 @@ endif (${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
 
 
 SET (GDS_SRC
+        awgapi.c
         awgfunc.c
         awg.c
         awg_server.c
@@ -53,6 +54,7 @@ SET (GDS_CC_SRC
         )
 
 SET (GDS_HDR
+        awgapi.h
         awgfunc.h
         awg.h
         awg_server.h
diff --git a/src/gds/awgapi.c b/src/gds/awgapi.c
new file mode 100644
index 000000000..1f21a2c47
--- /dev/null
+++ b/src/gds/awgapi.c
@@ -0,0 +1,2888 @@
+static char *versionId = "Version $Id$" ;
+/* -*- mode: c; c-basic-offset: 3; -*- */
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* Module Name: awgapi							*/
+/*                                                         		*/
+/* Module Description: implements functions for controlling the AWG	*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+
+#ifndef __EXTENSIONS__
+#define __EXTENSIONS__
+#endif
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE
+#endif
+
+/* Header File List: */
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+
+#ifdef OS_VXWORKS
+#include <vxWorks.h>
+#include <semLib.h>
+#include <taskLib.h>
+#include <inetLib.h>
+#include <hostLib.h>
+#include <sysLib.h>
+#include <timers.h>
+
+#else
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#include "dtt/gdsutil.h"
+#include "dtt/awgapi.h"
+#include "dtt/rawgapi.h"
+#include "dtt/awgfunc.h"
+#include "dtt/gdschannel.h"
+#include "dtt/ds340.h"
+#ifndef _NO_TESTPOINTS
+#include "dtt/testpointinfo.h"
+#endif
+#include "dtt/targets.h"
+#include "dtt/rmorg.h"
+#if defined (_CONFIG_DYNAMIC)
+#include "dtt/confinfo.h" 
+#endif
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* Defines: Describes the local AWG capabilities			*/
+/*          _AWG_LOCAL		local AWG is present			*/
+/*          _AWG_LOCAL_SLOT	slot # of local AWG			*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+#if (TARGET == TARGET_H1_GDS_AWG1) ||  (TARGET == TARGET_H1_GDS_AWG1+10) 
+#define _AWG_LOCAL
+#define _AWG_LOCAL_SLOT		AWG_ID(0,0)
+
+#elif (TARGET == TARGET_H2_GDS_AWG1) || (TARGET == TARGET_H2_GDS_AWG1+10)
+#define _AWG_LOCAL
+#define _AWG_LOCAL_SLOT		AWG_ID(1,0)
+
+#elif (TARGET == TARGET_L1_GDS_AWG1) || (TARGET == TARGET_L1_GDS_AWG1+10)
+#define _AWG_LOCAL
+#define _AWG_LOCAL_SLOT		AWG_ID(0,0)
+
+#elif (TARGET == TARGET_M_GDS_UNIX || TARGET == TARGET_L_GDS_UNIX || TARGET == TARGET_H_GDS_UNIX)
+#define _AWG_LOCAL
+#define _AWG_LOCAL_SLOT		AWG_ID(0,0)
+#endif
+
+#ifdef _AWG_LOCAL
+#include "awg.h"
+#endif
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* Constants: _NETID		  net protocol used for rpc		*/
+/* 	      _MAX_IFO		  maximum number of ifo's		*/
+/*            _MAX_AWG_PER_IFO	  maximum number of awg's / ifo		*/
+/*            _SHOWBUF_SIZE	  maximum size of show reply		*/
+/*            MAX_SLOT_NAME	  maximum length of channel name	*/
+/*            MAX_SLOT_LIST	  maximum number of cached channel names*/
+/*            PRM_PATH		  parameter file path			*/
+/*            PRM_FILE		  parameter file name			*/
+/*            PRM_SECTION	  section heading for awg		*/
+/*            PRM_SECTION2	  section heading for cobox		*/
+/*            PRM_ENTRY1	  parameter file host entry		*/
+/*            PRM_ENTRY2	  parameter file rpc prog.num. entry	*/
+/*            PRM_ENTRY3	  parameter file rpc vers.num. entry	*/
+/*            PRM_ENTRY4	  parameter file cobox port # entry	*/
+/*            _HELP_TEXT	  help text for cmd line interface	*/
+/*            								*/
+/*----------------------------------------------------------------------*/
+#define _NETID			"tcp"
+#define _MAX_IFO		256
+#define _MAX_AWG_PER_IFO	5
+#define MAX_SLOT_NAME 		256
+#define MAX_SLOT_LIST 		16
+#define _SHOWBUF_SIZE		(256 * 1024)
+#if !defined (_AWG_LIB) && !defined (_CONFIG_DYNAMIC)
+#define PRM_FILE		gdsPathFile ("/param", "awg.par")
+#define PRM_SECTION		"awg"
+#define PRM_SECTION2		"dsg"
+#define PRM_ENTRY1		"hostname"
+#define PRM_ENTRY2		"prognum"
+#define PRM_ENTRY3		"progver"
+#define PRM_ENTRY4		"port"
+#endif
+#define _HELP_TEXT \
+	"Arbitrary waveform generator commands:\n" \
+	"  help: shows this help text\n" \
+	"  channels : display all excitation channels\n" \
+	"  show 'node'.'awg': show awg usage\n" \
+	"  new 'channel': reserve an awg slot\n" \
+	"  free 'slot' : frees the awg slot\n" \
+	"  set/add 'slot' 'waveform': sets/adds a waveform\n" \
+	"  gain 'slot' 'value' 'tRamp': sets the overall gain of a slot\n" \
+	"  stop 'slot': stops wavforms of an awg slot\n" \
+	"  ramp 'tRamp': sets the general phase in/out time\n" \
+	"  clear 'node'.'awg' : reset an awg\n" \
+	"  stat 'node'.'awg' : get statistics data\n" \
+	"Parameters:\n" \
+	"   node: interferometer number, starting at zero\n" \
+	"   awg: awg number, stating at zero\n" \
+	"   channel: full channel name, e.g. H1:LSC-TEST_IN\n" \
+	"   slot: slot number returned by new or original channel name\n" \
+	"   tRamp: ramp time; default is 1\n" \
+	"   waveform 1: 'func' freq ampl ofs phase ratio\n" \
+	"   waveform 2: impulse freq ampl duration delay\n" \
+	"   waveform 3: const ampl\n" \
+	"   waveform 4: 'noise' freq1 freq2 ampl ofs\n" \
+	"   waveform 5: sweep freq1 freq2 ampl1 ampl2 time 'sweeptype' 'updn'\n" \
+	"   waveform 6: arb freq scale 'trigger' rate point1 point2 point3 ...\n" \
+	"   waveform 7: stream scaling\n" \
+	"   func: sine, square, ramp or triangle\n" \
+	"   noise: normal or uniform\n" \
+	"   sweeptype: linear or log\n" \
+	"   updn: + (up), - (down) or blank for bidirectional\n" \
+	"   trigger: c (continous) r (random) w (wait) t (trig) \n"
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* Types:   awgHost_t		host addresses type            		*/
+/*          slotentry		channel name cache for slots		*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+#if defined (_AWG_LIB) || defined (_CONFIG_DYNAMIC)
+   struct awgHost_t {
+      int		valid;
+      char		hostname[100];
+      unsigned long	prognum;
+      unsigned long	progver;
+   };
+   typedef struct awgHost_t awgHost_t;
+#endif
+
+   struct slotentry {
+      char name[MAX_SLOT_NAME];
+      int slot;
+   };
+   typedef struct slotentry slotentry;
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* Globals: awg_init		whether clients were already init.	*/
+/*          awg_clnt		rpc client handles		 	*/
+/*          ds340addr		network address of DS340		*/
+/*          ds340port		network port of DS340  			*/
+/*          awgHost		host addresses            		*/
+/*          slotlist		channel name cache for slot numbers	*/
+/*          slotinit		slot initialized	       		*/
+/*          ramptime		general phase in/out time in sec	*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   static int		awg_init = 0;
+   static CLIENT*	awg_clnt[_MAX_IFO][_MAX_AWG_PER_IFO];
+   static char		ds340addr[NUM_DS340][256] = {{0}};
+   static int		ds340port[NUM_DS340] = {0};
+#if defined (_AWG_LIB) || defined (_CONFIG_DYNAMIC)
+   static awgHost_t	awgHost[_MAX_IFO][_MAX_AWG_PER_IFO] = {{{0}}};
+#endif
+   static slotentry 	slotlist[MAX_SLOT_LIST];
+   static int 		slotinit = 1;
+   static double 	ramptime = 0.0;
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* Forward declarations: 						*/
+/*	initAWGclient		init of rpc client			*/
+/*      								*/
+/*----------------------------------------------------------------------*/
+   static int initAWGclient (void);
+#if defined (_CONFIG_DYNAMIC) && !defined (_AWG_LIB)
+   static int ds340SetHostAddress (int ds340, const char* hostname, 
+                     int port);
+   static int awgSetHostAddress (int ifo, int awg, const char* hostname, 
+                     unsigned long prognum, unsigned long progver);
+#endif
+   static void initSlot (void);
+   static int updateSlot (int slot, const char* name);
+   static int freeSlot (int slot);
+   static const char* readSlot (const char* p, int* slot);
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* Internal Procedure Name: awgCheckInterface				*/
+/*                                                         		*/
+/* Procedure Description: check if AWG interface exists			*/
+/*                                                         		*/
+/* Procedure Arguments: node, awg #					*/
+/*                                                         		*/
+/* Procedure Returns: 1 if exists, 0 otherwise				*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   static int awgCheckInterface (int node, int j)
+   {
+      if ((node < 0) || (node >= _MAX_IFO) ||
+         ((j < 0) || (j >= _MAX_AWG_PER_IFO))) {
+         return 0;
+      }
+   #ifdef _AWG_LOCAL
+      if (AWG_ID (node, j) == _AWG_LOCAL_SLOT) {
+         return 1;
+      }
+   #endif
+      return (awg_clnt[node][j] != NULL);
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgSetChannel				*/
+/*                                                         		*/
+/* Procedure Description: reserves an awg slot to a channel		*/
+/*                                                         		*/
+/* Procedure Arguments: channel name					*/
+/*                                                         		*/
+/* Procedure Returns: slot number if successful, <0 if failed		*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int awgSetChannel (const char* name)
+   {
+      static int	lastawgnum = 0; /* stores the last awg num */
+      int		status;	/* status flag */
+      int 		ret;	/* return value */
+      int		node;	/* node ID */
+      int		j;	/* index */
+      gdsChnInfo_t	chn;	/* channel info */
+      int		chntype;/* channel type */
+      int		arg1 = 0;/* first argument for new channel */
+      int		arg2 = 0;/* second argument for new channel */
+      int		id;	/* channel id */
+   #ifndef _NO_TESTPOINTS
+      testpoint_t	tp;	/* test point id */
+   #endif
+   
+      /* test whether awg interface is initialized */
+      if (awg_init == 0) {
+         status = awg_client();
+         if (status < 0) {
+            return status - 10;
+         }
+      }
+   
+      /* get channel information */
+      if (gdsChannelInfo (name, &chn) < 0) {
+         return -1;
+      }
+   #ifdef _NO_TESTPOINTS
+      if (chn.rmOffset < 0) {
+         chntype = AWG_DS340_CHANNEL;
+         node = chn.rmId;
+         id = chn.chNum;
+         arg1 = arg2 = 0;
+      }
+      else {
+         chntype = AWG_MEM_CHANNEL;
+         node = chn.rmId;
+         id = chn.rmOffset;
+         arg1 = chn.rmBlockSize;
+         arg2 = chn.dataRate / NUMBER_OF_EPOCHS;
+      }
+   #else
+      chntype = 0;
+      if (tpIsValid (&chn, &node, &tp)) {
+         id = tp;
+      }
+      else {
+         /* not a valid excitation channel */
+         return -1;
+      }
+   
+      /* determine channel type */
+      if (chntype == 0) {
+         arg1 = arg2 = 0;
+         switch (TP_ID_TO_INTERFACE (tp))
+         {
+            /* LSC test point channel */
+            case TP_LSC_EX_INTERFACE:
+               {
+                  chntype = AWG_LSC_TESTPOINT;
+                  break;
+               }
+            /* ASC test point channel */
+            case TP_ASC_EX_INTERFACE:
+               {
+                  chntype = AWG_ASC_TESTPOINT;
+                  break;
+               }
+            /* DAC channel */
+            case TP_DAC_INTERFACE:
+               {
+                  chntype = AWG_DAC_CHANNEL;
+                  arg1 = AWG_DAC_DELAY;
+                  break;
+               }
+            /* DS340 channel */
+            case TP_DS340_INTERFACE:
+               {
+                  chntype = AWG_DS340_CHANNEL;
+                  break;
+               }
+            /* not an excitation test point/channel */
+            default : 
+               {
+                  return -2;
+               }
+         }
+      }
+   #endif
+   
+      /* treat DS340 separately */
+      if (chntype == AWG_DS340_CHANNEL) {
+         char		buf[512];
+         id -= TP_ID_DS340_OFS;
+         /* printf ("test %i - %s - %i\n", id,
+                ds340addr[id], ds340port[id]);*/
+         if ((id >= 0) && (id < NUM_DS340) &&
+            (connectCoboxDS340 (id, ds340addr[id], ds340port[id]) >= 0)) {
+            sprintf (buf, "found DSG @ cobox %s/port%i\n", 
+                    ds340addr[id], ds340port[id]);
+            gdsDebug (buf);
+            return AWG_ID (_MAX_IFO, 0) + id;
+         }
+         else {
+            sprintf (buf, "no DSG @ cobox %s/port%i\n", 
+                    ds340addr[id], ds340port[id]);
+            gdsDebug (buf);
+            return -7;
+         }
+      }
+   
+      /* we have a valid awg output type! Now check node id */
+      if ((node < 0) || (node >= _MAX_IFO)) {
+         return -3;
+      }
+   
+      /* cycle through awg number */
+      for (j = lastawgnum + 1; j <= lastawgnum + _MAX_AWG_PER_IFO; j++) {
+         if (awgCheckInterface (node, j % _MAX_AWG_PER_IFO)) {
+            break;
+         }
+      }
+      j %= _MAX_AWG_PER_IFO;
+      lastawgnum = j;
+   
+      /* test validity of awg */
+      if (!awgCheckInterface (node,j)) {
+         return -4;
+      }
+   
+      /* test for local awg */
+   #ifdef _AWG_LOCAL
+      if (AWG_ID (node, j) == _AWG_LOCAL_SLOT) {
+         ret = getIndexAWG (chntype, id, arg1, arg2);
+      }
+      else {
+      #endif
+      
+      /* ask awg for free slot */
+         if (awgnewchannel_1 (chntype, id, arg1, arg2, &ret, 
+            awg_clnt[node][j]) != RPC_SUCCESS) {
+            return -5;
+         }
+      #ifdef _AWG_LOCAL
+      }
+   #endif
+   
+      /* was a free slot available */
+      if (ret < 0) {
+         return -6;
+      }
+   
+      /* return slot number */
+      return AWG_ID (node, j) + ret;
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgRemoveChannel				*/
+/*                                                         		*/
+/* Procedure Description: removes a channel/slot from an awg 		*/
+/*                                                         		*/
+/* Procedure Arguments: slot						*/
+/*                                                         		*/
+/* Procedure Returns: 0 if successful, <0 when failed			*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int awgRemoveChannel (int slot)
+   {
+      int		status;	/* status flag */
+      int 		ret;	/* return value */
+      int		i;	/* index */
+      int		j;	/* index */
+      int		sl; 	/* slot within awg */
+   
+      /* test whether awg interface is initialized */
+      if (awg_init == 0) {
+         status = awg_client();
+         if (status < 0) {
+            return status - 10;
+         }
+      }
+   
+      /* use slot number to determine awg */
+      i = slot / _AWG_IFO_OFS - 1;
+      j = (slot % _AWG_IFO_OFS) / _AWG_NUM_OFS;
+      sl = (slot % _AWG_IFO_OFS) % _AWG_NUM_OFS;
+   
+      /* treat DS340 separately */
+      if ((i == _MAX_IFO) && (sl >= 0) && (sl < NUM_DS340)) {
+         return resetDS340 (sl);
+      }
+   
+      /* test parameters */
+      if (!awgCheckInterface (i,j) || (sl < 0)) {
+         return -1;
+      }
+   
+      /* test for local awg */
+   #ifdef _AWG_LOCAL
+      if (AWG_ID (i, j) == _AWG_LOCAL_SLOT) {
+         return releaseIndexAWG (sl);
+      }
+   #endif
+   
+      /* clear channel on remote AWG */
+      if (awgremovechannel_1 (sl, &ret, awg_clnt[i][j]) != 
+         RPC_SUCCESS) {
+         return -2;
+      }
+   
+      /* return error code */
+      if (ret >= 0) {
+         return 0;
+      }
+      else {
+         return ret - 2;
+      }
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* Internal Procedure Name: isExcitationChannel				*/
+/*                                                         		*/
+/* Procedure Description: returns true if a valid excitation channel	*/
+/*                                                         		*/
+/* Procedure Arguments: channel info					*/
+/*                                                         		*/
+/* Procedure Returns: true if excitation channel			*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int isExcitationChannel (const gdsChnInfo_t* info)
+   {
+      int		node;
+      testpoint_t	tp;
+
+      if (!tpIsValid (info, &node, &tp)) {
+         return 0;
+      }
+
+      if ((node < 0) || (node >= _MAX_IFO)) {
+         return 0;
+      }
+      switch (tpType (info)) {
+         case tpInvalid:
+         case tpLSC:
+         case tpASC:
+            return 0;
+         default:
+            return 1;
+      }
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgGetChannelNames				*/
+/*                                                         		*/
+/* Procedure Description: get all valid channel names	 		*/
+/*                                                         		*/
+/* Procedure Arguments: names, length					*/
+/*                                                         		*/
+/* Procedure Returns: length if successful, <0 when failed		*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int awgGetChannelNames (char* names, int len, int info)
+   {
+      int		status;	/* status flag */
+      int		size;	/* size of channel list */
+      char*		chn;	/* channel list */
+   
+      /* test whether awg interface is initialized */
+      if (awg_init == 0) {
+         status = awg_client();
+         if (status < 0) {
+            return status - 10;
+         }
+      }
+
+      /* allocate channel list */
+      chn = gdsChannelNames (-1, isExcitationChannel, info);
+      size = strlen (chn);
+      if (names == NULL) {
+         free (chn);
+         return size;
+      }
+      else {
+         if (size > len - 1) size = len - 1;
+         strncpy (names, chn, size);
+         names[size] = 0;
+         free (chn);
+         return size;
+      }
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgAddWaveform				*/
+/*                                                         		*/
+/* Procedure Description: adds waveforms to an awg slot			*/
+/*                                                         		*/
+/* Procedure Arguments: slot, list of components			*/
+/*                                                         		*/
+/* Procedure Returns: 0 if successful, <0 when failed			*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int awgAddWaveform (int slot, AWG_Component* comp, int numComp)
+   {
+      int		status;	/* status flag */
+      int 		ret;	/* return value */
+      int		i;	/* index */
+      int		j;	/* index */
+      int		sl; 	/* slot within awg */
+      int		k;	/* index */
+      int		l;	/* index */
+      awgcomponent_list_r wforms;	/* awg components */
+   
+      /* test whether awg interface is initialized */
+      if (awg_init == 0) {
+         status = awg_client();
+         if (status < 0) {
+            return status - 10;
+         }
+      }
+   
+      /* anything to do? */
+      if (numComp <= 0) {
+         return 0;
+      }
+   
+      /* use slot number to determine awg */
+      i = slot / _AWG_IFO_OFS - 1;
+      j = (slot % _AWG_IFO_OFS) / _AWG_NUM_OFS;
+      sl = (slot % _AWG_IFO_OFS) % _AWG_NUM_OFS;
+   
+      /* treat DS340 separately */
+      if ((i == _MAX_IFO) && (sl >= 0) && (sl < NUM_DS340) &&
+         isDS340Alive (sl)) {
+         DS340_ConfigBlock	conf;	/* configuration block */
+      
+         /* get configuration */;
+         getDS340 (sl, &conf);
+         conf.toggles &= DS340_INVT | DS340_SYNC | DS340_TERM;
+      
+         /* set waveform */
+         if (comp->wtype == awgSine) {
+            conf.func = ds340_sin;
+         } 
+         else if (comp->wtype == awgSquare) {
+            conf.func = ds340_square;
+         }
+         else if (comp->wtype == awgRamp) {
+            conf.func = ds340_ramp;
+         }
+         else if (comp->wtype == awgTriangle) {
+            conf.func = ds340_triangle;
+         } 
+         else if (comp->wtype == awgNoiseN) {
+            conf.func = ds340_noise;
+         }
+         else if (comp->wtype == awgArb) {
+            conf.func = ds340_arb;
+            conf.toggles |= DS340_TSRC;
+         }
+         else {
+            return -3;
+         }
+      
+         if ((comp->ramptime[0] < 1E-9) && (comp->ramptime[1] < 1E-9)) {
+             /* periodic, noise or abritrary waveform */
+            if (comp->wtype == awgNoiseN) {
+               conf.ampl = comp->par[0];
+               conf.offs = comp->par[3];
+            }
+            else if (comp->wtype == awgArb) {
+               conf.fsmp = comp->par[1];
+               conf.ampl = comp->par[0];
+               conf.offs = comp->par[3];
+            }
+            else {
+               conf.freq = comp->par[1];
+               conf.ampl = comp->par[0];
+               conf.offs = comp->par[3];
+            }
+         }
+         /* no test for sweep */
+         else if ((comp->ramptime[0] == 0) && (comp->ramptime[1] != 0) &&
+                 (comp->restart > 0) && (comp->duration > 0) &&
+                 (conf.func != ds340_noise)) {
+            /* sweep waveform */
+            conf.toggles |= DS340_SWEN | DS340_STRS;
+            if (SWEEP_OUT_TYPE (comp->ramptype) == AWG_PHASING_LOG) {
+               conf.toggles |= DS340_STYP;
+            } 
+            else if (SWEEP_OUT_TYPE (comp->ramptype) != 
+                    AWG_PHASING_LINEAR) {
+               return -3;
+            }
+            if ((numComp > 1) && 
+               (comp[1].start == comp[0].start + comp[0].duration) &&
+               (comp[0].par[1] == comp[1].ramppar[1]) &&
+               (comp[1].par[1] == comp[0].ramppar[1])) {
+               conf.toggles |= DS340_SDIR;
+            }
+            conf.func = ds340_sin;
+            conf.stfr = comp[0].par[1];
+            conf.spfr = comp[0].ramppar[1];
+            conf.ampl = comp[0].par[0];
+            conf.srat = 1.0/(double)comp[0].restart;
+            if ((conf.toggles & DS340_STYP) != 0) {
+               conf.srat *= 2;
+            }
+         }
+         else {
+            return -3;
+         }
+      	 /* set waveform */
+         setDS340 (sl, &conf);
+         if (uploadDS340Block (sl) < 0) {
+            return -2;
+         } 
+         else {
+            return 0;
+         }
+      }
+   
+      /* test parameters */
+      if (!awgCheckInterface (i, j) || (sl < 0)) {
+         return -1;
+      }
+   
+      /* test for local awg */
+   #ifdef _AWG_LOCAL
+      if (AWG_ID (i, j) == _AWG_LOCAL_SLOT) {
+         return addWaveformAWG (sl, comp, numComp);
+      }
+   #endif
+   
+      /* allocate memory */
+      wforms.awgcomponent_list_r_len = numComp;
+      wforms.awgcomponent_list_r_val = 
+         calloc (numComp, sizeof (awgcomponent_r));
+      if (wforms.awgcomponent_list_r_val == NULL) {
+         return -2;
+      }
+   
+      /* copy components */
+      for (k = 0; k < numComp; k++) {
+         wforms.awgcomponent_list_r_val[k].wtype = comp[k].wtype;
+         for (l = 0; l < 4; l++) {
+            wforms.awgcomponent_list_r_val[k].par[l] = comp[k].par[l];
+         }
+         wforms.awgcomponent_list_r_val[k].start = comp[k].start;
+         wforms.awgcomponent_list_r_val[k].duration = comp[k].duration;
+         wforms.awgcomponent_list_r_val[k].restart = comp[k].restart;
+         for (l = 0; l < 2; l++) {
+            wforms.awgcomponent_list_r_val[k].ramptime[l] = 
+               comp[k].ramptime[l];
+         }
+         wforms.awgcomponent_list_r_val[k].ramptype = comp[k].ramptype;
+         for (l = 0; l < 4; l++) {
+            wforms.awgcomponent_list_r_val[k].ramppar[l] = 
+               comp[k].ramppar[l];
+         }
+      }
+   
+      /* add waveforms */
+      if (awgaddwaveform_1 (sl, &wforms, &ret, awg_clnt[i][j]) != 
+         RPC_SUCCESS) {
+         free (wforms.awgcomponent_list_r_val);
+         return -2;
+      }
+      free (wforms.awgcomponent_list_r_val);
+   
+      /* return error code */
+      if (ret >= 0) {
+         return 0;
+      }
+      else {
+         return ret - 2;
+      }
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgSetWaveform				*/
+/*                                                         		*/
+/* Procedure Description: set arbitrary waveform of an awg slot		*/
+/*                                                         		*/
+/* Procedure Arguments: slot, data array, length			*/
+/*                                                         		*/
+/* Procedure Returns: 0 if successful, <0 when failed			*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int awgSetWaveform (int slot, float y[], int len)
+   {
+      int		status;	/* status flag */
+      int 		ret;	/* return value */
+      int		i;	/* index */
+      int		j;	/* index */
+      int		sl; 	/* slot within awg */
+      awgwaveform_r	wform;	/* awg components */
+   
+      /* test whether awg interface is initialized */
+      if (awg_init == 0) {
+         status = awg_client();
+         if (status < 0) {
+            return status - 10;
+         }
+      }
+   
+      /* anything to do? */
+      if (len < 0) {
+         return 0;
+      }
+   
+      /* use slot number to determine awg */
+      i = slot / _AWG_IFO_OFS - 1;
+      j = (slot % _AWG_IFO_OFS) / _AWG_NUM_OFS;
+      sl = (slot % _AWG_IFO_OFS) % _AWG_NUM_OFS;
+   
+      /* treat DS340 separately */
+      if ((i == _MAX_IFO) && (sl >= 0) && (sl < NUM_DS340) &&
+         isDS340Alive (sl)) {
+         return sendWaveDS340 (sl, y, len);
+      }
+   
+      /* test parameters */
+      if (!awgCheckInterface (i, j) || (sl < 0)) {
+         return -1;
+      }
+   
+      /* test for local awg */
+   #ifdef _AWG_LOCAL
+      if (AWG_ID (i, j) == _AWG_LOCAL_SLOT) {
+         return setWaveformAWG (sl, y, len);
+      }
+   #endif
+   
+      /* set waveforms */
+      wform.awgwaveform_r_len = len;
+      wform.awgwaveform_r_val = y;
+      if (awgsetwaveform_1 (sl, wform, &ret, awg_clnt[i][j]) != 
+         RPC_SUCCESS) {
+         return -2;
+      }
+   
+      /* return error code */
+      return ret;
+   }
+
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgSendWaveform				*/
+/*                                                         		*/
+/* Procedure Description: send stream to an awg slot			*/
+/*                                                         		*/
+/* Procedure Arguments: slot, time, epoch, data array, length		*/
+/*                                                         		*/
+/* Procedure Returns: 0 if successful, <0 when failed			*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int awgSendWaveform (int slot, taisec_t time, int epoch,
+                     float y[], int len)
+   {
+      int		status;	/* status flag */
+      int 		ret;	/* return value */
+      int		i;	/* index */
+      int		j;	/* index */
+      int		sl; 	/* slot within awg */
+      awgwaveform_r	wform;	/* awg components */
+   
+      /* test whether awg interface is initialized */
+      if (awg_init == 0) {
+         status = awg_client();
+         if (status < 0) {
+            return -5;
+         }
+      }
+   
+      /* anything to do? */
+      if (len <= 0) {
+         return -2;
+      }
+   
+      /* use slot number to determine awg */
+      i = slot / _AWG_IFO_OFS - 1;
+      j = (slot % _AWG_IFO_OFS) / _AWG_NUM_OFS;
+      sl = (slot % _AWG_IFO_OFS) % _AWG_NUM_OFS;
+   
+      /* test parameters: DS340not supported */
+      if (!awgCheckInterface (i, j) || (sl < 0)) {
+         return -1;
+      }
+   
+      /* test for local awg */
+   #ifdef _AWG_LOCAL
+      if (AWG_ID (i, j) == _AWG_LOCAL_SLOT) {
+         return sendWaveformAWG (sl, time, epoch, y, len);
+      }
+   #endif
+   
+      /* set waveforms */
+      wform.awgwaveform_r_len = len;
+      wform.awgwaveform_r_val = y;
+      if (awgsendwaveform_1 (sl, time, epoch, wform, 
+         &ret, awg_clnt[i][j]) != RPC_SUCCESS) {
+         return -5;
+      }
+   
+      /* return error code */
+      return ret;
+   }
+
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgStopWaveform				*/
+/*                                                         		*/
+/* Procedure Description: clears waveforms from an awg slot		*/
+/*                                                         		*/
+/* Procedure Arguments: slot						*/
+/*                                                         		*/
+/* Procedure Returns: 0 if successful, <0 when failed			*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int awgStopWaveform (int slot, int terminate, tainsec_t time)
+   {
+      int		status;	/* status flag */
+      int 		ret;	/* return value */
+      int		i;	/* index */
+      int		j;	/* index */
+      int		sl; 	/* slot within awg */
+   
+      /* test whether awg interface is initialized */
+      if (awg_init == 0) {
+         status = awg_client();
+         if (status < 0) {
+            return status - 10;
+         }
+      }
+   
+      /* use slot number to determine awg */
+      i = slot / _AWG_IFO_OFS - 1;
+      j = (slot % _AWG_IFO_OFS) / _AWG_NUM_OFS;
+      sl = (slot % _AWG_IFO_OFS) % _AWG_NUM_OFS;
+   
+      /* treat DS340 separately */
+      if ((i == _MAX_IFO) && (sl >= 0) && (sl < NUM_DS340) &&
+         isDS340Alive (sl)) {
+         return awgClearWaveforms (slot);
+      }
+   
+      /* test parameters */
+      if (!awgCheckInterface (i, j) || (sl < 0)) {
+         return -1;
+      }
+   
+      /* test for local AWG */
+   #ifdef _AWG_LOCAL
+      if (AWG_ID (i, j) == _AWG_LOCAL_SLOT) {
+         return stopWaveformAWG (sl, terminate, time);
+      }
+   #endif
+   
+      /* clear waveforms on remote AWG */
+      if (awgstopwaveform_1 (sl, terminate, time, &ret, 
+         awg_clnt[i][j]) != RPC_SUCCESS) {
+         return -2;
+      }
+   
+      /* return error code */
+      if (ret >= 0) {
+         return 0;
+      }
+      else {
+         return ret - 2;
+      }
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgClearWaveforms				*/
+/*                                                         		*/
+/* Procedure Description: clears waveforms from an awg slot		*/
+/*                                                         		*/
+/* Procedure Arguments: slot						*/
+/*                                                         		*/
+/* Procedure Returns: 0 if successful, <0 when failed			*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int awgClearWaveforms (int slot)
+   {
+      int		status;	/* status flag */
+      int 		ret;	/* return value */
+      int		i;	/* index */
+      int		j;	/* index */
+      int		sl; 	/* slot within awg */
+   
+      /* test whether awg interface is initialized */
+      if (awg_init == 0) {
+         status = awg_client();
+         if (status < 0) {
+            return status - 10;
+         }
+      }
+   
+      /* use slot number to determine awg */
+      i = slot / _AWG_IFO_OFS - 1;
+      j = (slot % _AWG_IFO_OFS) / _AWG_NUM_OFS;
+      sl = (slot % _AWG_IFO_OFS) % _AWG_NUM_OFS;
+   
+      /* treat DS340 separately */
+      if ((i == _MAX_IFO) && (sl >= 0) && (sl < NUM_DS340) &&
+         isDS340Alive (sl)) {
+         DS340_ConfigBlock	conf;
+         getDS340 (sl, &conf);
+         conf.ampl = 0;
+         conf.offs = 0;
+         setDS340 (sl, &conf);
+         if (uploadDS340Wave (sl) < 0) {
+            return -2;
+         } 
+         else {
+            return 0;
+         }
+      }
+   
+      /* test parameters */
+      if (!awgCheckInterface (i, j) || (sl < 0)) {
+         return -1;
+      }
+   
+      /* test for local AWG */
+   #ifdef _AWG_LOCAL
+      if (AWG_ID (i, j) == _AWG_LOCAL_SLOT) {
+         return resetAWG (sl);
+      }
+   #endif
+   
+      /* clear waveforms on remote AWG */
+      if (awgclearwaveforms_1 (sl, &ret, awg_clnt[i][j]) != 
+         RPC_SUCCESS) {
+         return -2;
+      }
+   
+      /* return error code */
+      if (ret >= 0) {
+         return 0;
+      }
+      else {
+         return ret - 2;
+      }
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgQueryWaveforms				*/
+/*                                                         		*/
+/* Procedure Description: queries an arbitrary waveform generator	*/
+/*                                                         		*/
+/* Procedure Arguments: slot id, pointer to result array, max length	*/
+/*                                                         		*/
+/* Procedure Returns: length of wave form list if successful, 		*/
+/*		      <0 when failed					*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int awgQueryWaveforms (int slot, AWG_Component* comp, int maxComp)
+   {
+      int		status;	/* status flag */
+      awgquerywaveforms_r 	ret;	/* return value */
+      int		i;	/* index */
+      int		j;	/* index */
+      int		sl; 	/* slot within awg */
+   
+      /* test whether awg interface is initialized */
+      if (awg_init == 0) {
+         status = awg_client();
+         if (status < 0) {
+            return status - 10;
+         }
+      }
+   
+      /* use slot number to determine awg */
+      i = slot / _AWG_IFO_OFS - 1;
+      j = (slot % _AWG_IFO_OFS) / _AWG_NUM_OFS;
+      sl = (slot % _AWG_IFO_OFS) % _AWG_NUM_OFS;
+   
+      /* treat DS340 separately */
+      if ((i == _MAX_IFO) && (sl >= 0) && (sl < NUM_DS340) &&
+         isDS340Alive (sl)) {
+         DS340_ConfigBlock	conf;	/* DS340 configuration */
+         AWG_WaveType 		wtype;	/* wave type */
+      
+         if (downloadDS340Block (sl) < 0) {
+            return -2;
+         }
+         getDS340 (sl, &conf);
+      	 /* determine waveform */
+         if (conf.func == ds340_sin) {
+            wtype = awgSine;
+         }
+         else if (conf.func == ds340_square) {
+            wtype = awgSquare;
+         }
+         else if (conf.func == ds340_ramp) {
+            wtype = awgSquare;
+         }
+         else if (conf.func == ds340_triangle) {
+            wtype = awgSquare;
+         }
+         else if (conf.func == ds340_noise) {
+            wtype = awgNoiseN;
+         }
+         else {
+            return -3;
+         }
+      
+      	 /* test for sweep */
+         if ((conf.toggles & DS340_SWEN) != 0) {
+            int		cnum;		/* number fo components */
+            int		flag;		/* AWG component flag */
+         
+            /* test sweep directions */
+            if ((conf.toggles & DS340_SDIR) == 0) {
+               if (maxComp < 1) {
+                  return 1;
+               }
+               flag = 0;
+            }
+            else {
+               if (maxComp < 2) {
+                  return 2;
+               }
+               flag = AWG_SWEEP_CYCLE;
+            }
+            /* test sweep type */
+            if ((conf.toggles & DS340_STYP) != 0) {
+               flag |= AWG_SWEEP_LOG;
+            }
+            if (conf.srat < 1E-6) {
+               return -3;
+            }
+            /* calculate sweep parameters */
+            if (awgSweepComponents (TAInow(), _ONESEC/conf.srat, conf.stfr,
+               conf.spfr, conf.ampl, conf.ampl, flag, comp, &cnum) < 0) {
+               return -3;
+            }
+            else {
+               return cnum;
+            }
+         }
+         /* periodic or noise */
+         else {
+            if (maxComp < 1) {
+               return 1;
+            }
+            memset (comp, 0, sizeof (AWG_Component));
+            comp->start = TAInow();
+            comp->duration = -1;
+            comp->restart = -1;
+         
+            /* noise first */
+            if (wtype == awgNoiseU) {
+               comp->wtype = wtype;
+               comp->par[0] = conf.ampl;
+               comp->par[1] = 0;
+               comp->par[2] = 10E6;
+               comp->par[3] = conf.offs;
+               return 1;
+            }
+            /* periodic */
+            if (awgPeriodicComponent (wtype, conf.freq, conf.ampl, 0, 
+               conf.offs, comp) < 0) {
+               return -3;
+            }
+            else {
+               return 1;
+            }
+         }
+      } 
+      /* only non DS340 channels */
+   
+      /* test parameters */
+      if (!awgCheckInterface (i, j) || (sl < 0)) {
+         return -1;
+      }
+   
+      /* test for local awg */
+   #ifdef _AWG_LOCAL
+      if (AWG_ID (i, j) == _AWG_LOCAL_SLOT) {
+         return queryWaveformAWG (sl, comp, maxComp);
+      }
+   #endif
+   
+      /* query awg */
+      memset (&ret, 0, sizeof (awgquerywaveforms_r));
+      if ((awgquerywaveforms_1 (sl, maxComp, &ret, awg_clnt[i][j]) != 
+         RPC_SUCCESS) || (ret.status < 0)) {
+         return -2;
+      }
+   
+      /* copy result */
+      for (i = 0; (i < maxComp) && 
+          (i < ret.wforms.awgcomponent_list_r_len); i++) {
+         comp[i].wtype = 
+            ret.wforms.awgcomponent_list_r_val[i].wtype;
+         for (j = 0; j < 4; j++) {
+            comp[i].par[j] = 
+               ret.wforms.awgcomponent_list_r_val[i].par[j];
+         }
+         comp[i].start = 
+            ret.wforms.awgcomponent_list_r_val[i].start;
+         comp[i].duration = 
+            ret.wforms.awgcomponent_list_r_val[i].duration;
+         comp[i].restart = 
+            ret.wforms.awgcomponent_list_r_val[i].restart;
+         for (j = 0; j < 2; j++) {
+            comp[i].ramptime[j] = 
+               ret.wforms.awgcomponent_list_r_val[i].ramptime[j];
+         }
+         comp[i].ramptype = 
+            ret.wforms.awgcomponent_list_r_val[i].ramptype;
+         for (j = 0; j < 4; j++) {
+            comp[i].ramppar[j] = 
+               ret.wforms.awgcomponent_list_r_val[i].ramppar[j];
+         }
+      }
+      /* free memory of return array */
+      xdr_free ((xdrproc_t)xdr_awgquerywaveforms_r, (char*) &ret);
+   
+      /* return length of returned waveform list */
+      return ret.wforms.awgcomponent_list_r_len;
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgSetGain					*/
+/*                                                         		*/
+/* Procedure Description: set the gain of an AWG slot			*/
+/*                                                         		*/
+/* Procedure Arguments: slot, gain, ramp time				*/
+/*                                                         		*/
+/* Procedure Returns: 0 if successful, <0 when failed			*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int awgSetGain (int slot, double gain, tainsec_t time)
+   {
+      int		status;	/* status flag */
+      int 		ret;	/* return value */
+      int		i;	/* index */
+      int		j;	/* index */
+      int		sl; 	/* slot within awg */
+   
+      /* test whether awg interface is initialized */
+      if (awg_init == 0) {
+         status = awg_client();
+         if (status < 0) {
+            return -5;
+         }
+      }
+   
+      /* use slot number to determine awg */
+      i = slot / _AWG_IFO_OFS - 1;
+      j = (slot % _AWG_IFO_OFS) / _AWG_NUM_OFS;
+      sl = (slot % _AWG_IFO_OFS) % _AWG_NUM_OFS;
+   
+      /* test parameters: DS340not supported */
+      if (!awgCheckInterface (i, j) || (sl < 0)) {
+         return -1;
+      }
+   
+      /* test for local awg */
+   #ifdef _AWG_LOCAL
+      if (AWG_ID (i, j) == _AWG_LOCAL_SLOT) {
+         return setGainAWG (sl, gain, time);
+      }
+   #endif
+   
+      /* set waveforms */
+      if (awgsetgain_1 (sl, gain, time, &ret, 
+         awg_clnt[i][j]) != RPC_SUCCESS) {
+         return -5;
+      }
+   
+      /* return error code */
+      return ret;
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgSetFilter				*/
+/*                                                         		*/
+/* Procedure Description: set a filter					*/
+/*                                                         		*/
+/* Procedure Arguments: slot, coeff, len				*/
+/*                                                         		*/
+/* Procedure Returns: 0 if successful, <0 when failed			*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int awgSetFilter (int slot, double y[], int len)
+   {
+      int		status;	/* status flag */
+      int 		ret;	/* return value */
+      int		i;	/* index */
+      int		j;	/* index */
+      int		sl; 	/* slot within awg */
+      awgfilter_r	coeff;	/* awg components */
+   
+      /* test whether awg interface is initialized */
+      if (awg_init == 0) {
+         status = awg_client();
+         if (status < 0) {
+            return -5;
+         }
+      }
+   
+      /* anything to do? */
+      if ((len < 0) || !y) {
+         return -2;
+      }
+   
+      /* use slot number to determine awg */
+      i = slot / _AWG_IFO_OFS - 1;
+      j = (slot % _AWG_IFO_OFS) / _AWG_NUM_OFS;
+      sl = (slot % _AWG_IFO_OFS) % _AWG_NUM_OFS;
+   
+      /* test parameters: DS340not supported */
+      if (!awgCheckInterface (i, j) || (sl < 0)) {
+         return -1;
+      }
+   
+      /* test for local awg */
+   #ifdef _AWG_LOCAL
+      if (AWG_ID (i, j) == _AWG_LOCAL_SLOT) {
+         return setFilterAWG (sl, y, len);
+      }
+   #endif
+   
+      /* set waveforms */
+      coeff.awgfilter_r_len = len;
+      coeff.awgfilter_r_val = y;
+      if (awgsetfilter_1 (sl, coeff, &ret, 
+         awg_clnt[i][j]) != RPC_SUCCESS) {
+         return -5;
+      }
+   
+      /* return error code */
+      return ret;
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgReset					*/
+/*                                                         		*/
+/* Procedure Description: resets arbitrary waveform generators		*/
+/*                                                         		*/
+/* Procedure Arguments: awg id						*/
+/*                                                         		*/
+/* Procedure Returns: 0 if successful, <0 when failed			*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int awgReset (int id)
+   {
+      int		status;	/* status flag */
+      int 		ret;	/* return value */
+      int		i;	/* index */
+      int		j;	/* index */
+   
+      /* test whether awg interface is initialized */
+      if (awg_init == 0) {
+         status = awg_client();
+         if (status < 0) {
+            return status;
+         }
+      }
+   
+      ret = 0;
+      if (id == -1) {
+         /* reset all awg's */
+         for (i = 0; i < _MAX_IFO; i++) {
+            for (j = 0; j < _MAX_AWG_PER_IFO; j++) {
+               if (awgCheckInterface (i, j)) {
+                  /* test for local AWG */
+               #ifdef _AWG_LOCAL
+                  if (AWG_ID (i, j) == _AWG_LOCAL_SLOT) {
+                     ret = releaseIndexAWG (-1);
+                  }
+                  else {
+                  #endif
+                  /* reset on remote AWG */
+                     if ((awgreset_1 (&status, awg_clnt[i][j]) !=
+                        RPC_SUCCESS) || (status != 0)) {
+                        ret = -1;
+                     }
+                  #ifdef _AWG_LOCAL
+                  }
+               	#endif
+               }
+            }
+         }
+      	 /* reset all DS340's */
+         resetDS340 (-1);
+      }
+      else if (id < 0) {
+         /* reset all awg's of an ifo */
+         i = (-id) / _AWG_IFO_OFS - 1;
+      	 /* treat DS340 separately */
+         if (i == _MAX_IFO) {
+            resetDS340 (-1);
+         }
+         else if ((i >= 0) && (i < _MAX_IFO)) {
+            for (j = 0; j < _MAX_AWG_PER_IFO; j++) {
+               if (awgCheckInterface (i, j)) {
+                  /* test for local AWG */
+               #ifdef _AWG_LOCAL
+                  if (AWG_ID (i, j) == _AWG_LOCAL_SLOT) {
+                     ret = releaseIndexAWG (-1);
+                  }
+                  else {
+                  #endif
+                  /* reset on remote AWG */
+                     if ((awgreset_1 (&status, awg_clnt[i][j]) !=
+                        RPC_SUCCESS) || (status != 0)) {
+                        ret = -1;
+                     }
+                  #ifdef _AWG_LOCAL
+                  }
+               	#endif
+               }
+            }
+         }
+      }
+      else {
+         /* reset one specific ifo */
+         i = id / _AWG_IFO_OFS - 1;
+         j = (id % _AWG_IFO_OFS) / _AWG_NUM_OFS;
+      	 /* treat DS340 separately */
+         if (i == _MAX_IFO) {
+            resetDS340 (j);
+         }
+         /* do awg's */
+         else if (awgCheckInterface (i, j)) {
+            /* test for local AWG */
+         #ifdef _AWG_LOCAL
+            if (AWG_ID (i, j) == _AWG_LOCAL_SLOT) {
+               ret = releaseIndexAWG (-1);
+            }
+            else {
+            #endif
+            /* reset on remote AWG */
+               if ((awgreset_1 (&status, awg_clnt[i][j]) !=
+                  RPC_SUCCESS) || (status != 0)) {
+                  ret = -1;
+               }
+            #ifdef _AWG_LOCAL
+            }
+         #endif
+         }
+      }
+   
+      return ret;
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgStatistics				*/
+/*                                                         		*/
+/* Procedure Description: obtains statistics data from an AWG		*/
+/*                                                         		*/
+/* Procedure Arguments: awg id, pointer to stat. data			*/
+/*                                                         		*/
+/* Procedure Returns: 0 if successful, <0 when failed			*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int awgStatistics (int slot, awgStat_t* stat)
+   {
+      int		status;	/* status flag */
+      awgstat_r 	ret;	/* return value */
+      int		i;	/* index */
+      int		j;	/* index */
+      int		sl; 	/* slot within awg */
+   
+      /* test whether awg interface is initialized */
+      if (awg_init == 0) {
+         status = awg_client();
+         if (status < 0) {
+            return status - 10;
+         }
+      }
+   
+      /* use slot number to determine awg */
+      i = slot / _AWG_IFO_OFS - 1;
+      j = (slot % _AWG_IFO_OFS) / _AWG_NUM_OFS;
+      sl = (slot % _AWG_IFO_OFS) % _AWG_NUM_OFS;
+      if (!awgCheckInterface (i, j) || (sl < 0)) {
+         return -1;
+      }
+   
+      /* test for local awg */
+   #ifdef _AWG_LOCAL
+      if (AWG_ID (i, j) == _AWG_LOCAL_SLOT) {
+         return getStatisticsAWG (stat);
+      }
+   #endif
+   
+      /* query awg */
+      memset (&ret, 0, sizeof (awgstat_r));
+      if ((awgstatistics_1 (stat == NULL, &ret, 
+         awg_clnt[i][j]) != RPC_SUCCESS) || (ret.status < 0)) {
+         return -2;
+      }
+   
+      /* copy result; do it the dumb way */
+      if (stat != NULL) {
+         memcpy (stat, &ret, sizeof (awgStat_t));
+      }
+      /* free memory of return array */
+      xdr_free ((xdrproc_t)xdr_awgstat_r, (char*) &ret);
+   
+      /* return */
+      return 0;
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgShow					*/
+/*                                                         		*/
+/* Procedure Description: returns config. string of AWG			*/
+/*                                                         		*/
+/* Procedure Arguments: awg id						*/
+/*                                                         		*/
+/* Procedure Returns: string if successful, NULL when failed		*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   char* awgShow (int id)
+   {
+      int		status;	/* status flag */
+      awgshow_r 	ret;	/* return value */
+      int		i;	/* index */
+      int		j;	/* index */
+      int		sl; 	/* slot within awg */
+      char*		p;	/* show buffer */
+   
+      /* test whether awg interface is initialized */
+      if (awg_init == 0) {
+         status = awg_client();
+         if (status < 0) {
+            return NULL;
+         }
+      }
+   
+      /* use slot number to determine awg */
+      i = abs(id) / _AWG_IFO_OFS - 1;
+      j = (abs(id) % _AWG_IFO_OFS) / _AWG_NUM_OFS;
+      sl = (abs(id) % _AWG_IFO_OFS) % _AWG_NUM_OFS;
+   
+      /* treat DS340 separately */
+      if (i == _MAX_IFO) {
+         /* alloc memory */
+         p = malloc (_SHOWBUF_SIZE);
+         if (p == NULL) {
+            return NULL;
+         }
+         strcpy (p, "Only connected DSG channels are shown\n");
+         j = strlen (p);
+      	 /* query ds340 */
+         for (i = 0; i < NUM_DS340; i++) {
+            if ((isDS340Alive (i)) && 
+               (strlen (p) + 100 < _SHOWBUF_SIZE)) {
+               sprintf (strend (p), 
+                       "\n=== Digital signal generator %i @ %s/%i===\n", 
+                       i, ds340addr[i], ds340port[i]);
+               downloadDS340Block (i);
+               showDS340Block (i, strend (p), _SHOWBUF_SIZE-strlen(p)-1);
+            }
+         }
+         if (strlen (p) == j) {
+            strcpy (p, "No DSG channels connected\n");
+         }
+         /* return */
+         if (strlen (p) < _SHOWBUF_SIZE - 1) {
+            p = realloc (p, strlen (p) + 1);
+         }
+         return p;
+      }
+   
+      /* test parameters */
+      if (!awgCheckInterface (i, j) || (sl < 0)) {
+         return NULL;
+      }
+   
+      /* test for local awg */
+   #ifdef _AWG_LOCAL
+      if (AWG_ID (i, j) == _AWG_LOCAL_SLOT) {
+         p = malloc (_SHOWBUF_SIZE);
+         if (p == NULL) {
+            return NULL;
+         }
+         if (id < 0) {
+            if (showAWG (sl, p, _SHOWBUF_SIZE) < 0) {
+               free (p);
+               return NULL;
+            }
+         }
+         else {
+            if (showAllAWGs (p, _SHOWBUF_SIZE) == NULL) {
+               free (p);
+               return NULL;
+            }
+         }
+         if (strlen (p) < _SHOWBUF_SIZE - 1) {
+            p = realloc (p, strlen (p) + 1);
+         }
+         return p;
+      }
+   #endif
+   
+      /* query awg */
+      memset (&ret, 0, sizeof (awgshow_r));
+      if (id < 0) {
+         if ((awgshowslot_1 (sl, &ret, awg_clnt[i][j]) != RPC_SUCCESS) || 
+            (ret.status < 0)) {
+            xdr_free ((xdrproc_t)xdr_awgshow_r, (char*) &ret);
+            return NULL;
+         }
+      }
+      else {
+         if ((awgshow_1 (&ret, awg_clnt[i][j]) != RPC_SUCCESS) || 
+            (ret.status < 0)) {
+            xdr_free ((xdrproc_t)xdr_awgshow_r, (char*) &ret);
+            return NULL;
+         }
+      }
+   
+      /* return */
+      return ret.res;
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awg_client					*/
+/*                                                         		*/
+/* Procedure Description: installs awg client interface			*/
+/*                                                         		*/
+/* Procedure Arguments: void						*/
+/*                                                         		*/
+/* Procedure Returns: # of AWGs if successful, <0 if failed		*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/           
+   int awg_client (void)
+   {
+      int		i;		/* index */
+      int		j;		/* index */
+      int		awgnum;		/* number of AWGs */
+   #if defined (_CONFIG_DYNAMIC)
+      const char* const* cinfo;		/* configuration info */
+      confinfo_t	crec;		/* conf. info record */
+   #endif
+   
+      /* test whether awg interface is initialized */
+      if (awg_init != 0) {
+         awgnum = 0;
+         for (i = 0; i < _MAX_IFO; i++) {
+            for (j = 0; j < _MAX_AWG_PER_IFO; j++) {
+               if (awg_clnt[i][j] != NULL) {
+                  awgnum++;
+               }
+            }
+         }
+         for (i = 0; i < NUM_DS340; i++) {
+            if ((strlen (ds340addr[i]) > 0) &&
+               (ds340port[i] > 0)) {
+               awgnum++;
+            }
+         }
+         return awgnum;
+      }
+      else {
+         /* dynamic configuration */
+      #if defined (_CONFIG_DYNAMIC)
+         for (cinfo = getConfInfo (0, 0); *cinfo != NULL; cinfo++) {
+            if ((parseConfInfo (*cinfo, &crec) == 0) &&
+               (gds_strcasecmp (crec.interface, 
+                                CONFIG_SERVICE_AWG) == 0)) {
+               if ((crec.ifo >= 0) && (crec.ifo < _MAX_IFO) &&
+                  (crec.num >= 0) && (crec.num < _MAX_AWG_PER_IFO) &&
+                  (crec.port_prognum > 0) && (crec.progver > 0)) {
+                  awgSetHostAddress (crec.ifo, crec.num, crec.host, 
+                                    crec.port_prognum, crec.progver);
+               }
+               else if ((crec.ifo == -1) &&
+                       (crec.num >= 0) && (crec.num < NUM_DS340) &&
+                       (crec.port_prognum > 0) && (crec.progver == -1)) {
+                  ds340SetHostAddress (crec.num, crec.host, 
+                                      crec.port_prognum);
+               }
+            }
+         }
+      #endif
+      
+         /* init clients */
+         return initAWGclient();
+      }
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awg_cleanup					*/
+/*                                                         		*/
+/* Procedure Description: terminates awg client interface		*/
+/*                                                         		*/
+/* Procedure Arguments: void						*/
+/*                                                         		*/
+/* Procedure Returns: void						*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/ 
+   void awg_cleanup (void)
+   {
+      int		i;		/* index */
+      int		j;		/* index */
+   
+      if (awg_init == 0) {
+         return;
+      }
+   
+      for (i = 0; i < _MAX_IFO; i++) {
+         for (j = 0; j < _MAX_AWG_PER_IFO; j++) {
+            if (awg_clnt[i][j] != NULL) {
+               clnt_destroy (awg_clnt[i][j]);
+               awg_clnt[i][j] = NULL;
+            }
+         }
+      
+      }
+   
+      awg_init = 0;
+   }
+
+
+#if defined (_AWG_LIB) || defined (_CONFIG_DYNAMIC)
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* Internal Procedure Name: awgSetHostAddress				*/
+/*                                                         		*/
+/* Procedure Description: sets the host adddr of the excitation engine	*/
+/*                                                         		*/
+/* Procedure Arguments: ifo id, awg id, hostname, prog #, ver #		*/
+/*                                                         		*/
+/* Procedure Returns: 0 if successful					*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   int awgSetHostAddress (int ifo, int awg, const char* hostname, 
+                     unsigned long prognum, unsigned long progver)
+   {   
+      if ((awg_init > 0) || (ifo < 0) || (ifo >= _MAX_IFO) ||
+         (awg < 0) || (awg >= _MAX_AWG_PER_IFO)) {
+         return -1;
+      }
+      /* set node parameters */
+      awgHost[ifo][awg].valid = 1;
+      strncpy (awgHost[ifo][awg].hostname, hostname, 
+              sizeof (awgHost[ifo][awg].hostname));
+      awgHost[ifo][awg].hostname[sizeof (awgHost[ifo][awg].hostname)-1] = 0;
+      awgHost[ifo][awg].prognum = (prognum > 0) ? 
+                           prognum : RPC_PROGNUM_AWG;
+      awgHost[ifo][awg].progver = (progver > 0) ? 
+                           progver : RPC_PROGVER_AWG;
+      return 0;
+   }
+
+
+   int ds340SetHostAddress (int ds340, const char* hostname, int port)
+   {
+      if ((awg_init > 0) || (ds340 < 0) || (ds340 >= NUM_DS340)) {
+         return -1;
+      }
+      strncpy (ds340addr[ds340], hostname, 100);
+      ds340addr[ds340][99] = 0;
+      ds340port[ds340] = port;
+      return 0;
+   }
+#endif
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* Internal Procedure Name: initAWGclient				*/
+/*                                                         		*/
+/* Procedure Description: init. the AWG interface			*/
+/*                                                         		*/
+/* Procedure Arguments: void						*/
+/*                                                         		*/
+/* Procedure Returns: # of AWGs if successful, <0 when failed		*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   static int initAWGclient (void) 
+   {
+      int		i;		/* index */
+      int		j;		/* index */
+      char		prms[80];	/* section heading */
+      struct in_addr 	addr;		/* host address */
+      char 		remotehost[PARAM_ENTRY_LEN];/* remote hostname */
+      char		hostname[30];	/* ip name */
+      unsigned long	prognum;	/* rpc prog. num. */
+      unsigned long	progver;	/* rpc prog. ver. */
+      struct timeval	timeout;	/* timeout for establishing conn. */
+      int		awgnum;		/* number of AWGs */
+   #if !defined (_AWG_LIB) && !defined (_CONFIG_DYNAMIC)
+      FILE*		fd;		/* file descriptor */
+      int		port;		/* cobox port number */
+   #endif
+   
+      /* initialize rpc for VxWorks */
+   #ifdef OS_VXWORKS
+      rpcTaskInit ();
+   #endif
+   
+      /* initialze awg number */
+      awgnum = 0;
+      /* create client handles */
+      for (i = 0; i < _MAX_IFO; i++) {
+      #if !defined (_AWG_LIB) && !defined (_CONFIG_DYNAMIC)
+      	 /* check whether file exists */ 
+         fd = fopen (PRM_FILE, "r");
+         if (fd == NULL) {
+            /* if file doesn't exist, set all handles to NULL */
+            for (j = 0; j < _MAX_AWG_PER_IFO; j++) {
+               awg_clnt[i][j] = NULL;
+            }
+            continue;
+         }
+         fclose (fd);
+      #endif
+      	 /* if file exists, read in parameters */
+         for (j = 0; j < _MAX_AWG_PER_IFO; j++) {
+            awg_clnt[i][j] = NULL;
+         #if !defined (_AWG_LIB) && !defined (_CONFIG_DYNAMIC)
+            /* construct section heading */
+            sprintf (prms, "%s%i-%s%i", SITE_PREFIX, i + 1, PRM_SECTION, j);
+            /* get remote host from parameter file */
+            strcpy (remotehost, "");
+            loadStringParam (PRM_FILE, prms, PRM_ENTRY1, remotehost);
+            if (strcmp (remotehost, "") == 0) {
+               continue;
+            }
+            /* get rpc parameters from parameter file */
+            prognum = RPC_PROGNUM_AWG;
+            if (loadNumParam (PRM_FILE, prms, PRM_ENTRY2, &prognum) < 0) {
+               continue;
+            }
+            progver = RPC_PROGVER_AWG;
+            if (loadNumParam (PRM_FILE, prms, PRM_ENTRY3, &progver) < 0) {
+               continue;
+            }
+         #else
+            if (!awgHost[i][j].valid) {
+               continue;
+            }
+            strncpy (remotehost, awgHost[i][j].hostname, 
+                    sizeof (remotehost));
+            remotehost[sizeof(remotehost)-1] = 0;
+            prognum = awgHost[i][j].prognum;
+            progver = awgHost[i][j].progver;
+         #endif
+         
+            /* check validity of host name */
+            if (rpcGetHostaddress (remotehost, &addr) != 0) {
+               continue;
+            }
+         
+            /* create an rpc client handle */
+         #ifdef OS_VXWORKS
+            inet_ntoa_b (addr, hostname);
+         #else
+            strncpy (hostname, inet_ntoa (addr), sizeof (hostname));
+            hostname[sizeof(hostname)-1] = 0;
+         #endif
+            timeout.tv_sec = RPC_PROBE_WAIT;
+            timeout.tv_usec = 0;
+         #ifndef OS_VXWORKS
+            rpcProbe (hostname, prognum, progver, _NETID, &timeout, 
+                     &awg_clnt[i][j]);
+         #endif
+            if (awg_clnt[i][j] != NULL) {
+               awgnum++;
+               sprintf (prms, "rpc client for awg %i.%i created", 
+                       i, j);
+               gdsDebug (prms);
+            }
+            else {
+               sprintf (prms, "rpc client for awg %i.%i failed", 
+                       i, j);
+               gdsError (GDS_ERR_PROG, prms);
+            }
+         }
+      }
+   
+      /* initialize cobox */
+   #if !defined (_AWG_LIB) && !defined (_CONFIG_DYNAMIC)
+      memset (ds340addr, 0, sizeof (ds340addr));
+      memset (ds340port, 0, sizeof (ds340port));
+      /* check whether file exists */ 
+      fd = fopen (PRM_FILE, "r");
+      if (fd != NULL) {
+         fclose (fd);
+      
+         for (i = 0; i < NUM_DS340; i++) {
+            /* if file exists, read in parameters */
+            /* construct section heading */
+            sprintf (prms, "%s-%s%i", SITE_PREFIX, PRM_SECTION2, i);
+            /* get remote host from parameter file */
+            strcpy (remotehost, "");
+            loadStringParam (PRM_FILE, prms, PRM_ENTRY1, remotehost);
+            if (strcmp (remotehost, "") == 0) {
+               continue;
+            }
+            /* get serial port number from parameter file */
+            port = 0;
+            if (loadIntParam (PRM_FILE, prms, PRM_ENTRY4, &port) < 0) {
+               continue;
+            }
+            if (port <= 0) {
+               continue;
+            }
+            strncpy (ds340addr[i], remotehost, 100);
+            ds340addr[i][99] = 0;
+            ds340port[i] = port;
+            /* printf ("%i:host = %s; port = %i\n", i, ds340addr[i],
+                   ds340port[i]);*/
+            awgnum++;
+         }
+      }
+   #else
+      for (i = 0; i < NUM_DS340; i++) {
+         if (strlen (ds340addr[i]) > 0) {
+            /* printf ("%i:host = %s; port = %i\n", i, ds340addr[i],
+                   ds340port[i]);*/
+            awgnum++;
+         }
+      }
+   #endif
+   
+      /* initialization successful */
+      awg_init = 1;
+      return awgnum;
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* Internal Procedure Name: cmdreply					*/
+/*                                                         		*/
+/* Procedure Description: command reply					*/
+/*                                                         		*/
+/* Procedure Arguments: string						*/
+/*                                                         		*/
+/* Procedure Returns: newly allocated char*				*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/   
+   static char* cmdreply (const char* m)
+   {
+      if (m == 0) {
+         return 0;
+      }
+      else {
+         char* p = (char*) malloc (strlen (m) + 1);
+         if (p != 0) {
+            strcpy (p, m);
+         }
+         return p;
+      }
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgWaveformCmd				*/
+/*                                                         		*/
+/* Procedure Description: returns awg components from string command	*/
+/*                                                         		*/
+/* Procedure Arguments: command string, awg component array (return, 	*/
+/*    max 2 elements), number of elements returned, error message,	*/
+/*    pointer to point array (return for arb awg), length of poin array	*/
+/*    boolean for DS340							*/
+/*                                                         		*/
+/* Procedure Returns: 0 if successful; <0 on error			*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/           
+   int awgWaveformCmd (const char* cmd, AWG_Component comp[], int* cnum,
+                     char** errmsg, float** points, int* num, int isDS340)
+   {
+      static tainsec_t oldTimeStamp = 0;
+      tainsec_t timeStamp;
+      const char*	p;	/* cursor into command string */
+   
+      if (errmsg != NULL) {
+         *errmsg = NULL;
+      }
+      if (points != NULL) {
+         *points = NULL;
+      }
+   
+      /* check parameters */
+      if ((cmd == 0) || (comp == 0) || (cnum == 0) || 
+         (num == 0) || (points == 0)) {
+         if (errmsg != 0)  {
+            *errmsg = cmdreply ("error: invalid arguments");
+         }
+         return -1;
+      }
+      *num = 0;
+      *cnum = 1;
+   
+      /* skip blanks */
+      p = cmd;
+      while ((*p == ' ') || (*p == '\t')) {
+         p++;
+      }
+      /* time stamp */
+      timeStamp = TAInow();
+      if (timeStamp - oldTimeStamp < _EPOCH / 10) {
+         timeStamp = oldTimeStamp;
+      }
+      else {
+         oldTimeStamp = timeStamp;
+      }
+      timeStamp += 4 * _EPOCH;
+   
+      /* determine waveform */
+      if (strlen (p) == 0) {
+         /* no waveform means clear */
+         return 0;
+      }
+      /* sine */
+      else if (gds_strncasecmp (p, "sine", 4) == 0) {
+         double 		f, a, o, q;
+         if ((sscanf (p + 4, "%lf%lf%lf%lf", &f, &a, &o, &q) != 4) ||
+            (awgPeriodicComponentEx (awgSine, timeStamp, 
+            f, a, q, o, comp) < 0)) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            return -2;
+         }
+      }
+      
+      /* square */
+      else if (gds_strncasecmp (p, "square", 6) == 0) {
+         double 		f, a, o, q, r;
+         int			num;
+         num = sscanf (p + 6, "%lf%lf%lf%lf%lf", &f, &a, &o, &q, &r);
+         if (num == 4) {
+            if (awgPeriodicComponentEx (awgSquare, timeStamp,
+               f, a, q, o, comp) < 0) {
+               if (errmsg != NULL) {
+                  *errmsg = cmdreply ("error: invalid arguments");
+               }
+               return -3;
+            }
+         }
+         else if (num == 5) {
+            if (awgSquareWaveComponentEx (timeStamp, 
+               f, a, q, o, r, comp) < 0) {
+               if (errmsg != NULL) {
+                  *errmsg = cmdreply ("error: invalid arguments");
+               }
+               return -3;
+            }
+            *cnum = 2;
+         }
+         else {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            return -3;
+         }
+      }
+      
+      /* ramp */
+      else if (gds_strncasecmp (p, "ramp", 4) == 0) {
+         double 		f, a, o, q;
+         if ((sscanf (p + 4, "%lf%lf%lf%lf", &f, &a, &o, &q) != 4) ||
+            (awgPeriodicComponentEx (awgRamp, timeStamp,
+            f, a, q, o, comp) < 0)) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            return -4;
+         }
+      }
+      
+      /* triangle */
+      else if (gds_strncasecmp (p, "triangle", 8) == 0) {
+         double 		f, a, o, q;
+         if ((sscanf (p + 8, "%lf%lf%lf%lf", &f, &a, &o, &q) != 4) ||
+            (awgPeriodicComponentEx (awgTriangle, timeStamp,
+            f, a, q, o, comp) < 0)) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            return -5;
+         }
+      }
+      
+      /* impulse */
+      else if (gds_strncasecmp (p, "impulse", 7) == 0) {
+         double 		f, a, du, de;
+         if ((sscanf (p + 7, "%lf%lf%lf%lf", &f, &a, &du, &de) != 4) ||
+            (awgPeriodicComponentEx (awgImpulse, timeStamp,
+            f, a, du, de, comp) < 0)) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            return -6;
+         }
+      }
+      
+      /* constant offset */
+      else if (gds_strncasecmp (p, "const", 5) == 0) {
+         double 		a;
+         if ((sscanf (p + 5, "%lf", &a) != 1) ||
+            (awgConstantComponentEx (timeStamp, a, comp) < 0)) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            return -7;
+         }
+      }
+      
+      /* normally distributed noise */
+      else if (gds_strncasecmp (p, "normal", 6) == 0) {
+         double 		f1, f2, a, o;
+         if ((sscanf (p + 6, "%lf%lf%lf%lf", &f1, &f2, &a, &o) != 4) ||
+            (awgNoiseComponentEx (awgNoiseN, timeStamp,
+            f1, f2, a, o, comp) < 0)) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            return -8;
+         }
+      }
+      
+      /* uniformly distributed noise */
+      else if (gds_strncasecmp (p, "uniform", 7) == 0) {
+         double 		f1, f2, a, o;
+         if ((sscanf (p + 7, "%lf%lf%lf%lf", &f1, &f2, &a, &o) != 4) ||
+            (awgNoiseComponentEx (awgNoiseU, timeStamp,
+            f1, f2, a, o, comp) < 0)) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            return -9;
+         }
+      }
+      
+      /* frequency/amplitude sweep */
+      else if (gds_strncasecmp (p, "sweep", 5) == 0) {
+         double		f1, f2, a1, a2, dt, ft;
+         char		stype[256];
+         char		dir = 0;
+         int		sFlag = 0;
+      
+         /* scan sweep parameters */
+         if (sscanf (p + 5, "%lf%lf%lf%lf%lf %s %c", &f1, &f2, &a1, 
+            &a2, &dt, stype, &dir) < 6) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            return -10;
+         }
+         if (gds_strncasecmp (stype, "log", 3) == 0) {
+            sFlag |= AWG_SWEEP_LOG;
+         }
+         f1 = fabs (f1); f2 = fabs (f2);
+         a1 = fabs (a1); a2 = fabs (a2);
+         dt = fabs (dt);
+         ft = (f1 < f2) ? f1 : f2;
+         if (ft < 1E-6) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            return -11;
+         }
+         if (dir == '-') {
+            ft = f1; f1 = f2; f2 = ft;
+            ft = a1; a1 = a2; a2 = ft;
+         }
+         else if (dir != '+') {
+            sFlag |= AWG_SWEEP_CYCLE;
+            dt *= 2;
+         }
+         /* calculate sweep parameters */
+         if (awgSweepComponents (timeStamp, 
+            dt * (double) _ONESEC, f1, f2, 
+            a1, a2, sFlag, comp, cnum) < 0) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            return -12;
+         }
+      }
+      
+      /* arbitrary waveform */
+      else if (gds_strncasecmp (p, "arb", 3) == 0) {
+         /* scan arb waveform parameter */
+         double		f;	/* sampling frequency */
+         double		scale;	/* scaling factor */
+         char		trig;	/* trigger type */
+         double		trigval;/* trigger value */
+         double		rate;	/* trigger interval */
+         float		point;	/* data point */
+         char*		tok;	/* token */
+         char*		lasts;	/* temp */
+         int		len = 0;/* array length */
+         float*		y;	/* data array */
+         float		max;	/* max of data array */
+         char*		cmdcopy;/* copy of command string */
+      
+         cmdcopy = cmdreply (p + 3);
+         if (cmdcopy == 0) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: not enough memory");
+            }
+            return -13;
+         }
+      
+         /* read sampling frequency */
+         if (((tok = strtok_r (cmdcopy, " ", &lasts)) == NULL) ||
+            (sscanf (tok, "%lf", &f) != 1) || (f <= 0)) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            free (cmdcopy);
+            return -14;
+         }
+         /* read scaling factor */
+         if (((tok = strtok_r (NULL, " ", &lasts)) == NULL) ||
+            (sscanf (tok, "%lf", &scale) != 1)) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            free (cmdcopy);
+            return -15;
+         }
+         /* read trigger type */
+         if (((tok = strtok_r (NULL, " ", &lasts)) == NULL) ||
+            (sscanf (tok, "%c", &trig) != 1) ||
+            ((tolower (trig) != 'c') && (tolower (trig) != 'w') && 
+            (tolower (trig) != 't') && (tolower (trig) != 'r'))) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            free (cmdcopy);
+            return -16;
+         }
+         if (tolower (trig) == 't') {
+            trigval = 3;
+         }
+         else if (tolower (trig) == 'w') {
+            trigval = 2;
+         }
+         else if (tolower (trig) == 'r') {
+            trigval = 1;
+         }
+         else {
+            trigval = 0;
+         }
+         /* read interval value */
+         if (((tok = strtok_r (NULL, " ", &lasts)) == NULL) ||
+            (sscanf (tok, "%lf", &rate) != 1) || (rate < 0)) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            free (cmdcopy);
+            return -17;
+         }
+      
+         y = malloc (10000 * sizeof (float));
+         if (y == NULL) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: not enough memory");
+            }
+            free (cmdcopy);
+            return -18;
+         }
+         max = 0;
+         while (((tok = strtok_r (NULL, " ", &lasts)) != NULL) &&
+               (sscanf (tok, "%f", &point) == 1)) {
+            y [len++] = point;
+            if (fabs (point) > max) {
+               max = fabs (point);
+            }
+            if (len % 10000 == 0) {
+               y = realloc (y, (len + 10000) * sizeof (float));
+               if (y == NULL) {
+                  if (errmsg != NULL) {
+                     *errmsg = cmdreply ("error: not enough memory");
+                  }
+                  free (cmdcopy);
+                  return -19;
+               } 
+            }
+         }
+         /* only DS340 needs amplitude separately */
+         if (!isDS340) {
+            max = 1;
+         }
+         if (awgPeriodicComponentEx (awgArb, timeStamp,
+            f, scale, rate, trigval, 
+            comp) < 0) {
+            free (y);
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: unable to download waveform");
+            }
+            free (cmdcopy);
+            return -20;
+         }
+         *points = y;
+         *num = len;
+         free (cmdcopy);
+      }
+      
+      /* waveform stream */
+      else if (gds_strncasecmp (p, "stream", 6) == 0) {
+         double 		a;
+         if ((sscanf (p + 6, "%lf", &a) != 1) ||
+            (awgStreamComponentEx (timeStamp, a, comp) < 0)) {
+            if (errmsg != NULL) {
+               *errmsg = cmdreply ("error: invalid arguments");
+            }
+            return -7;
+         }
+      }
+      
+      /* unrecognized waveform */
+      else {
+         if (errmsg != NULL) {
+            *errmsg = cmdreply ("error: unrecognized waveform");
+         }
+         return -21;
+      }
+   
+      /* check waveform components */
+      if (!awgIsValidComponent (comp) ||
+         ((*cnum == 2) && !awgIsValidComponent (comp + 1))) {
+         if (errmsg != NULL) {
+            *errmsg = cmdreply ("error: invalid arguments");
+         }
+         if (*points != 0) {
+            free (*points);
+         }
+         return -22;
+      }
+   
+      return 0;
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* Internal Procedure Name: awgSetPhaseIn				*/
+/*                                                         		*/
+/* Procedure Description: returns awg components from string command	*/
+/*                                                         		*/
+/* Procedure Arguments: awg component array, number of elements		*/
+/*                                                         		*/
+/* Procedure Returns: 0 if successful; <0 on error			*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/           
+   int awgSetPhaseIn (AWG_Component comp[], int cnum)
+   {
+      int			i;		/* index */
+      if (ramptime <= 0) {
+         return 0;
+      }
+      for (i = 0; i < cnum; ++i) {
+         /* makes sure we have a useful waveform */
+         if ((comp[i].wtype != awgSine) &&
+            (comp[i].wtype != awgSquare) &&
+            (comp[i].wtype != awgRamp) &&
+            (comp[i].wtype != awgTriangle) &&
+            (comp[i].wtype != awgConst) &&
+            (comp[i].wtype != awgImpulse) &&
+            (comp[i].wtype != awgNoiseN) &&
+            (comp[i].wtype != awgNoiseU)) {
+            continue;
+         }
+      	 /* don't if waveform is restarted */
+         if (comp[i].restart > 0) {
+            continue;
+         }
+      	 /* don't if ramp is already set */
+         if (comp[i].ramptype) {
+            continue;
+         }
+      	 /* OK */
+         comp[i].ramppar[0] = 0; /* amplitude */
+         comp[i].ramppar[1] = 0; /* frequency */
+         comp[i].ramppar[2] = 0; /* phase */
+         comp[i].ramppar[3] = 0; /* offset */
+         comp[i].ramptype = RAMP_TYPE (AWG_PHASING_LINEAR, 
+                                      AWG_PHASING_STEP, AWG_PHASING_STEP);
+         comp[i].ramptime[0] = (tainsec_t)(1E9*ramptime);
+         comp[i].ramptime[1] = 0;
+      }
+      return 0;
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* Internal Procedure Name: ___Slot					*/
+/*                                                         		*/
+/* Procedure Description: slot cache					*/
+/*                                                         		*/
+/* Procedure Arguments: -						*/
+/*                                                         		*/
+/* Procedure Returns: - 						*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/           
+   static void initSlot (void)
+   {
+      memset (slotlist, 0, sizeof (slotlist));
+      slotinit = 0;
+   }
+
+   static int updateSlot (int slot, const char* name)
+   {
+      int i;
+   
+      if (slotinit) initSlot();
+      /* already exists? */
+      for (i = 0; i < MAX_SLOT_LIST; ++i) {
+         if (slotlist[i].slot == slot) {
+            strncpy (slotlist[i].name, name, MAX_SLOT_NAME);
+            slotlist[i].name[MAX_SLOT_NAME-1] = 0;
+            return 0;
+         }
+      }
+      /* put it into new slot */
+      for (i = 0; i < MAX_SLOT_LIST; ++i) {
+         if (slotlist[i].slot) {
+            continue;
+         }
+         slotlist[i].slot = slot;
+         strncpy (slotlist[i].name, name, MAX_SLOT_NAME);
+         slotlist[i].name[MAX_SLOT_NAME-1] = 0;
+         return 0;
+      }
+      return -1;
+   }
+
+   static int freeSlot (int slot)
+   {
+      int i;
+   
+      if (slotinit) initSlot();
+      for (i = 0; i < MAX_SLOT_LIST; ++i) {
+         if (slotlist[i].slot == slot) {
+            slotlist[i].slot = 0;
+            return 0;
+         }
+      }
+      return -1;
+   }
+
+   static const char* readSlot (const char* p, int* slot)
+   {
+      int i;
+      int num;
+   
+      while (isspace (*p)) ++p;
+      /* number */
+      if (isdigit (*p)) {
+         if (sscanf (p, "%i%n", slot, &num) != 1) {
+            *slot = -1;
+            return NULL;
+         }
+         return p + num;
+      }
+      /* name */
+      else {
+         for (num = 0; p[num] && !isspace (p[num]); ++num) ;
+         for (i = 0; i < MAX_SLOT_LIST; ++i) {
+            if (gds_strncasecmp (p, slotlist[i].name, num) == 0) {
+               *slot = slotlist[i].slot;
+               return p + num;
+            }
+         }
+         *slot = -1;
+         return NULL;
+      }
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgFree					*/
+/*                                                         		*/
+/* Procedure Description: Free allocated memory 			*/
+/*                                                         		*/
+/* Procedure Arguments: pointer to be freed    				*/
+/*                                                         		*/
+/* Procedure Returns: void      					*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+   void
+   awgFree(void* p) {
+      free(p);
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgCommand					*/
+/*                                                         		*/
+/* Procedure Description: command line interface			*/
+/*                                                         		*/
+/* Procedure Arguments: command string					*/
+/*                                                         		*/
+/* Procedure Returns: reply string					*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+
+   char* awgCommand (const char* cmd)
+   {
+      char*		p;
+      int		i;	/* node number */
+      int		j;	/* awg number */
+      int		sl;	/* slot number */
+      char		buf[100]; /* buffer */
+      float		id; /* node.awg number */
+
+      /* help */
+      if (gds_strncasecmp (cmd, "help", 4) == 0) {
+         return cmdreply (_HELP_TEXT);
+      }
+      /* show */
+      else if (gds_strncasecmp (cmd, "show", 4) == 0) {
+         p = (char*)(cmd + 4);
+         while (isspace (*p)) ++p;
+         if (isdigit (*p) || (*p == '+') || (*p == '-') || (*p == '.')) {
+            if (sscanf (cmd + 4, "%f", &id) != 1) {
+               return cmdreply ("error: arguments for show are 'node'.'awg'/'slot'");
+            }
+            else {
+               if (id < _AWG_IFO_OFS) {
+                  i = (int) id;
+                  j = (int) (10 * (id - i));
+                  sl = -1;
+               }
+               else {
+                  i = (int)id / _AWG_IFO_OFS - 1;
+                  j = ((int)id % _AWG_IFO_OFS) / _AWG_NUM_OFS;
+                  sl = ((int)id % _AWG_IFO_OFS) % _AWG_NUM_OFS;
+               }	
+               if (i == _MAX_IFO) {
+                  return awgShow (AWG_ID (i,j));
+               }
+               if (!awgCheckInterface (i, j)) {
+                  sprintf (buf, "error: node %i/awg %i not available", i, j);
+                  return cmdreply (buf);
+               }
+               return awgShow (sl < 0 ? AWG_ID (i,j) : -(int)id);
+            }
+         }
+         else {
+            p = (char*) readSlot (cmd + 4, &sl);
+            if (p == NULL) {
+               sprintf (buf, "error: illegal slot name");
+               return cmdreply (buf);
+            }
+            return awgShow (-sl);
+         }
+      }
+      /* channels */
+      else if (gds_strncasecmp (cmd, "channel", 6) == 0) {
+         i = awgGetChannelNames (NULL, 0, 1);
+         if (i < 0) {
+            return cmdreply ("error: channel information not available");
+         }
+         else if (i == 0) {
+            return cmdreply ("no channels available");
+         }
+         p = malloc (i + 10);
+         if (p == NULL) {
+            return NULL;
+         }
+         if (awgGetChannelNames (p, i + 9, 1) < 0) {
+            return cmdreply ("error: channel information not available");
+         }
+         else {
+            return p;
+         }
+      }
+      /* new */
+      else if (gds_strncasecmp (cmd, "new", 3) == 0) {
+         /* remove blanks */
+         p = (char*) (cmd + 3);
+         while (*p == ' ') {
+            p++;
+         }
+         if (strchr (p, ' ') != NULL) {
+            *strchr (p, ' ') = 0;
+         }
+         sl = awgSetChannel (p);
+         if (sl < 0) {
+            return cmdreply ("error: no slot available or invalid channel name");
+         }
+         updateSlot (sl, p);
+         sprintf (buf, "slot %i", sl);
+         return cmdreply (buf);
+      }
+      /* free */
+      else if (gds_strncasecmp (cmd, "free", 4) == 0) {
+         if (readSlot (cmd + 4, &sl) == NULL) {
+         /*if (sscanf (cmd + 4, "%i", &sl) != 1) {*/
+            return cmdreply ("error: invalid slot number/name");
+         }
+         freeSlot (sl);
+         if (awgRemoveChannel (sl) < 0) {
+            return cmdreply ("error: slot not available or invalid");
+         }
+         sprintf (buf, "slot %i freed", sl);
+         return cmdreply (buf);
+      }
+      /* set & add */
+      else if ((gds_strncasecmp (cmd, "set", 3) == 0) ||
+              (gds_strncasecmp (cmd, "add", 3) == 0)) {
+         AWG_Component		comp[20];/* awg components */
+         int			cnum;	/* number of comp entries */
+         int			cnew;	/* temp. component # */
+         char*			errmsg;	/* error message */
+         float*			y;	/* awg point array */
+         int			len;	/* number of awg points */
+         char*			cmdcopy;/* copy of command string */
+         char*			lasts;	/* temp for strtok_r */
+      
+         memset (comp, 0, 20 * sizeof (AWG_Component));
+         for (cnum = 0; cnum < 20; cnum++) {
+            comp[cnum].start = TAInow();
+            comp[cnum].duration = -1;
+            comp[cnum].restart = -1;
+         }
+         /* scan slot number */
+         p = (char*) readSlot (cmd + 3, &sl);
+         if (p == NULL) {
+            return cmdreply ("error: invalid slot number/name");
+         }
+      
+         /* loop over waveforms */
+         cnum = 0;
+         cmdcopy = cmdreply (p);
+         if (cmdcopy == NULL) {
+            return cmdreply ("error: unable to set waveform");
+         }
+         p = strtok_r (cmdcopy, ",;", &lasts);
+         while ((p != NULL) && (cnum < 19)) {
+           /* skip blanks */
+            while (*p == ' ') {
+               p++;
+            }
+            /* determine waveform component */
+            y = NULL;
+            if (awgWaveformCmd (p, comp + cnum, &cnew, &errmsg, &y, 
+               &len, (sl / _AWG_IFO_OFS - 1) == _MAX_IFO) < 0) {
+               free (cmdcopy);
+               return errmsg;
+            }
+            cnum += cnew;
+            if (y != NULL) {
+               if ((len <= 0) || (awgSetWaveform (sl, y, len) < 0)) {
+                  free (y);
+                  free (cmdcopy);
+                  return cmdreply ("error: unable to download waveform");
+               }
+               free (y);
+            }
+            p = strtok_r (NULL, ",;", &lasts);
+         }
+         free (cmdcopy);
+      
+         /* set phase in */
+         if (awgSetPhaseIn (comp, cnum) < 0) {
+            return cmdreply ("error: illegal phase in");
+         }
+      
+         /* check if anything set */
+         if (gds_strncasecmp (cmd, "set", 3) == 0) {
+            /* stop waveforms first */
+            if (ramptime > 0) {
+               if (awgStopWaveform (sl, 2, (tainsec_t)(1E9*ramptime)) < 0) {
+                  return cmdreply ("error: unable to stop waveform");
+               }
+            }
+            else {
+               if (awgClearWaveforms (sl)) {
+                  return cmdreply ("error: unable to clear waveform");
+               }
+            }
+            if (cnum <= 0) {
+               return cmdreply ("waveform cleared");
+            }
+         }
+      	 /* now add new waveform */
+         if (cnum > 0) {
+            if (awgAddWaveform (sl, comp, cnum) < 0) {
+               return cmdreply ("error: slot not available or invalid");
+            }
+         }
+         sprintf (buf, "slot %i enabled", sl);
+         return cmdreply (buf);
+      }
+      /* gain */
+      else if (gds_strncasecmp (cmd, "gain", 4) == 0) {
+         int		n;
+         double		gain;
+         double		tramp;
+      
+         p = (char*)readSlot (cmd + 4, &sl);
+         if (p == NULL) {
+            return cmdreply ("error: invalid slot number/name");
+         }
+         if (sscanf (p, "%lf%n", &gain, &n) != 1) {
+            return cmdreply ("error: arguments for gain are 'value' 'time'");
+         }
+         p += n;
+         tramp = 1.0;
+         if (sscanf (p, "%lf", &tramp) != 1) tramp = 1.0;
+         if (awgSetGain (sl, gain, (tainsec_t)(1E9 * tramp)) < 0) {
+            return cmdreply ("error: unable to set gain");
+         }
+         sprintf (buf, "gain in slot %i is %f (ramp = %f sec)", 
+                 sl, gain, tramp);
+         return cmdreply (buf);
+      }
+      /* stop */
+      else if (gds_strncasecmp (cmd, "stop", 4) == 0) {
+         p = (char*)readSlot (cmd + 4, &sl);
+         if (p == NULL) {
+            return cmdreply ("error: invalid slot number/name");
+         }
+         if (ramptime > 0) {
+            if (awgStopWaveform (sl, 2, (tainsec_t)(1E9*ramptime)) < 0) {
+               return cmdreply ("error: unable to stop waveform");
+            }
+         }
+         else {
+            if (awgStopWaveform (sl, 0, 0)) {
+               return cmdreply ("error: unable to stop waveform");
+            }
+         }
+         sprintf (buf, "slot %i stopped", sl);
+         return cmdreply (buf);
+      }
+      /* ramp */
+      else if (gds_strncasecmp (cmd, "ramp", 4) == 0) {
+         if (sscanf (cmd + 4, "%lf", &ramptime) != 1) ramptime = 0.0;
+         sprintf (buf, "phase in/out time %f sec", ramptime);
+         return cmdreply (buf);
+      }
+      /* clear */
+      else if (gds_strncasecmp (cmd, "clear", 5) == 0) {
+         if (sscanf (cmd + 5, "%f", &id) != 1) {
+            return cmdreply ("error: arguments for clear are 'node'.'awg'");
+         }
+         else {
+            i = (int) id;
+            j = (int) (10 * (id - i));
+            if (id < 0) {
+               if (awgReset (-1) < 0) {
+                  return cmdreply ("error: reset failed");
+               }
+               return cmdreply ("reset succeeded");
+            }
+            else if ((i == _MAX_IFO) && !isDS340Alive (j)) {
+               sprintf (buf, "DS340(%i) not available", j);
+               return cmdreply (buf);
+            }
+            else if (!awgCheckInterface (i, j)) {
+               sprintf (buf, "error: node %i/awg %i not available", i, j);
+               return cmdreply (buf);
+            }
+            if (awgReset (AWG_ID (i,j)) < 0) {
+               return cmdreply ("error: reset failed");
+            }
+            return cmdreply ("reset succeeded");
+         }
+      }
+      /* filter */
+      else if (gds_strncasecmp (cmd, "filter", 6) == 0) {
+         int			n;	/* number of conv chars */
+         int			max;	/* max coeff */
+         double*		ba;	/* ba array */
+         int			len;	/* length of ba array */
+         char*			ret;	/* return string */
+      
+         /* scan slot number */
+         p = (char*) readSlot (cmd + 6, &sl);
+         if (p == NULL) {
+         /*if (sscanf (cmd + 6, "%i%n", &sl, &n) != 1) {*/
+            return cmdreply ("error: invalid slot number/name");
+         }
+         /*p = (char*)cmd + 6 + n;*/
+      	 /* get coeffcients */
+         max = strlen (p) / 2 + 10;
+         ba = calloc (max, sizeof (double));
+         for (len = 0; len < max; ++len) {
+            while (isspace ((int)*p)) ++p;
+            if (!*p) {
+               break;
+            }
+            if (!isdigit ((int)*p) && (*p != '-') && (*p != '+') && (*p != '.')) {
+               len = -1;
+               break;
+            }
+            sscanf (p, "%lf%n", ba +len, &n);
+            p += n;
+         }
+         if (awgSetFilter (sl, ba, len) < 0) {
+            ret = cmdreply ("error: filter failed");
+         }
+         else if (len == 0) {
+            ret = cmdreply ("filter reset");
+         }
+         else {
+            ret = cmdreply ("filter set");
+         }
+         free (ba);
+         return ret;
+      }
+      /* stat */
+      else if (gds_strncasecmp (cmd, "stat", 4) == 0) {
+         if (sscanf (cmd + 4, "%f", &id) != 1) {
+            return cmdreply ("error: arguments for stat are 'node'.'awg'");
+         }
+         else {
+            awgStat_t		stat;
+            char		zero;
+            i = (int) id;
+            j = (int) (10 * (id - i));
+            if (!awgCheckInterface (i, j)) {
+               sprintf (buf, "error: node %i/awg %i not available", i, j);
+               return cmdreply (buf);
+            }
+            if (sscanf (cmd + 4, "%*f %c", &zero) == 1) {
+               awgStatistics (AWG_ID (i,j), NULL);
+               return cmdreply ("statistics reset");
+            }
+            else if (awgStatistics (AWG_ID (i,j), &stat) < 0) {
+               return cmdreply ("error: no statistics available");
+            } 
+            else {
+               p = malloc (16 * 100);
+               sprintf 
+                  (p, 
+                  "Staistics of node %i/awg %i (time in ms/heartbeat)\n"
+                  "%10.0f : number of waveform processing cycles\n"
+                  "%10.3f : average time to process waveforms\n"
+                  "%10.3f : standard deviation of processing waveforms\n"
+                  "%10.3f : maximum time needed to process waveforms\n"
+                  "%10.0f : number of reflective memory writes\n"
+                  "%10.3f : average time to write to reflective memory\n"
+                  "%10.3f : standard deviation of writing to reflective memory\n"
+                  "%10.3f : maximum time needed to write to reflective memory\n"
+                  "%10.3f : spare time after writing to reflective memory\n"
+                  "%10.0f : number of late writes to reflective memory\n"
+                  "%10.0f : number of writes to the DAC\n"
+                  "%10.3f : average time to write to the DAC\n"
+                  "%10.3f : standard deviation of writing to the DAC\n"
+                  "%10.3f : maximum time needed to write to the DAC\n"
+                  "%10.0f : number of missed writes to the DAC\n",
+                  i, j, stat.pwNum, stat.pwMean/1E6, stat.pwStddev/1E6,
+                  stat.pwMax/1E6, stat.rmNum, stat.rmMean/1E6, 
+                  stat.rmStddev/1E6, stat.rmMax/1E6, stat.rmCrit/1E6, 
+                  stat.rmNumCrit, stat.dcNum, stat.dcMean/1E6, 
+                  stat.dcStddev/1E6, stat.dcMax/1E6, stat.dcNumCrit);
+               return p;
+            }
+         }
+      }
+      else {
+         return cmdreply ("error: unrecognized command\n"
+                         "use help for further information");
+      }
+   }
+
+
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* External Procedure Name: awgcmdline					*/
+/*                                                         		*/
+/* Procedure Description: command line interface			*/
+/*                                                         		*/
+/* Procedure Arguments: command string					*/
+/*                                                         		*/
+/* Procedure Returns: reply string					*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/           
+   int awgcmdline (const char* cmd)
+   {
+      char* 		p;
+      int		ret;
+   
+      p = awgCommand (cmd);
+      if (p) {
+         printf ("%s\n", p);
+      }
+      else {
+         printf ("failed\n");
+      }
+      ret = (strncmp (p, "error:", 6) == 0) ? -1 : 0;
+      free (p);
+      return ret;
+   }
diff --git a/src/gds/awgapi.h b/src/gds/awgapi.h
new file mode 100644
index 000000000..1d93f9dce
--- /dev/null
+++ b/src/gds/awgapi.h
@@ -0,0 +1,441 @@
+/* Version: $Id$ */
+/*----------------------------------------------------------------------*/
+/*                                                         		*/
+/* Module Name: awgapi							*/
+/*                                                         		*/
+/* Module Description: 	API to the arbitrary waveform generator		*/
+/*									*/
+/*                                                         		*/
+/* Module Arguments: none				   		*/
+/*                                                         		*/
+/* Revision History:					   		*/
+/* Rel   Date     Programmer  	Comments				*/
+/* 0.1	 30June98 D. Sigg    	First release		   		*/
+/*                                                         		*/
+/* Documentation References:						*/
+/*	Man Pages: awgapi.html						*/
+/*	References: none						*/
+/*                                                         		*/
+/* Author Information:							*/
+/* Name          Telephone       Fax             e-mail 		*/
+/* Daniel Sigg   (509) 372-8336  (509) 372-2178  sigg_d@ligo.mit.edu	*/
+/*                                                         		*/
+/* Code Compilation and Runtime Specifications:				*/
+/*	Code Compiled on: Ultra-Enterprise, Solaris 5.6			*/
+/*	Compiler Used: sun workshop C 4.2				*/
+/*	Runtime environment: sparc/solaris				*/
+/*                                                         		*/
+/* Code Standards Conformance:						*/
+/*	Code Conforms to: LIGO standards.	OK			*/
+/*			  Lint.			TBD			*/
+/*			  ANSI			TBD			*/
+/*			  POSIX			TBD			*/
+/*									*/
+/* Known Bugs, Limitations, Caveats:					*/
+/*								 	*/
+/*									*/
+/*                                                         		*/
+/*                      -------------------                             */
+/*                                                         		*/
+/*                             LIGO					*/
+/*                                                         		*/
+/*        THE LASER INTERFEROMETER GRAVITATIONAL WAVE OBSERVATORY.	*/
+/*                                                         		*/
+/*                     (C) The LIGO Project, 1996.			*/
+/*                                                         		*/
+/*                                                         		*/
+/* California Institute of Technology			   		*/
+/* LIGO Project MS 51-33				   		*/
+/* Pasadena CA 91125					   		*/
+/*                                                         		*/
+/* Massachusetts Institute of Technology		   		*/
+/* LIGO Project MS 20B-145				   		*/
+/* Cambridge MA 01239					   		*/
+/*                                                         		*/
+/* LIGO Hanford Observatory				   		*/
+/* P.O. Box 1970 S9-02					   		*/
+/* Richland WA 99352					   		*/
+/*                                                         		*/
+/* LIGO Livingston Observatory		   				*/
+/* 19100 LIGO Lane Rd.					   		*/
+/* Livingston, LA 70754					   		*/
+/*                                                         		*/
+/*----------------------------------------------------------------------*/
+
+#ifndef _GDS_AWGAPI_H
+#define _GDS_AWGAPI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Header File List: */
+#ifndef _TAINSEC_T
+#define _TAINSEC_T
+#include <inttypes.h>
+   typedef int64_t tainsec_t;
+   typedef unsigned long taisec_t;
+#endif
+#include "awgtype.h"
+
+
+/** @name Arbitrary Waveform Generator Remote API
+    This API provides routines to remotely access the arbitrary 
+    waveform generators.
+
+    @memo Control interface for arbitrary waveform generators
+    @author Written June 1998 by Daniel Sigg
+    @see Arbitrary Waveform Generator
+    @version 0.1
+************************************************************************/
+
+/*@{*/
+
+#if 0
+/** Compiler flag for a compiling a stand-alone dynamic link library.
+
+    @author DS, June 98
+    @see Test point API
+************************************************************************/
+#define _AWG_LIB
+
+/** Compiler flag for a enabling dynamic configuration. When enabled
+    the host address and interface information of arbitrary waveform 
+    generators is queried from the network rather than read in through 
+    a file.
+
+    @author DS, June 98
+    @see Test point API
+************************************************************************/
+#undef _CONFIG_DYNAMIC
+#endif
+
+/** Installs an awg client interface. This function might be called 
+    prior of using the awg interface. If not, the first call to any of 
+    the functions in this API will call it. There is no penalty of not
+    calling awg_client explicitly. The function returns the number of
+    AWGs which can be reached through this interface.
+
+    @param void
+    @return number of AWGs if successful, <0 otherwise
+    @author DS, June 98
+************************************************************************/
+   int awg_client (void);
+
+/** Terminates an awg client interface.
+
+    @param void
+    @return void
+    @author DS, June 98
+************************************************************************/
+   void awg_cleanup (void);
+
+#ifdef _AWG_LIB
+/** Sets the excitation engine host address. This function is only 
+    available when compiling with the _AWG_LIB flag. It disables
+    the default parameter file and set the host address and rpc program
+    and version number directly. If a program number of zero is
+    specified, the default will be used. If a program version of 
+    zero is specified, the default will be used. This function must
+    be called before any other function (including awg_client).
+
+    @param ifo interferometer id (4K - 0, 2K - 1)
+    @param awg excitation engine id
+    @param hostname host name of excitation engine
+    @param prognum rpc program number
+    @param progver rpc program version
+    @return 0 if successful, <0 otherwise
+    @author DS, June 98
+************************************************************************/
+   int awgSetHostAddress (int ifo, int awg, const char* hostname, 
+                     unsigned long prognum, unsigned long progver);
+
+/** Sets the DS340 host address. This function is only 
+    available when compiling with the _AWG_LIB flag. It will disable
+    the default parameter file and set the host address and port 
+    number of the cobox directly. This function must
+    be called before any other function (including awg_client).
+
+    @param ds340 ds340 id
+    @param hostname host name of cobox controlling the DS340
+    @param port port number of the cobox
+    @return 0 if successful, <0 otherwise
+    @author DS, June 98
+************************************************************************/
+   int ds340SetHostAddress (int ds340, const char* hostname, int port);
+#endif
+
+/** Relate a channel name with a free slot in an excitation engine.
+
+    @param name channel name
+    @return slot number if successful, <0 if not
+    @author DS, June 98
+************************************************************************/
+   int awgSetChannel (const char* name);
+
+
+/** Remove a channel name from an excitation engine.
+
+    @param slot slot number
+    @return 0 if successful, <0 if not
+    @author DS, June 98
+************************************************************************/
+   int awgRemoveChannel (int slot);
+
+
+/** Ask for all valid channel names. The function needs a buffer
+    which is long enough to hold all excitation channel names
+    (space separated list). The function will return the number
+    of characters written into the names buffer. If the names buffer
+    is NULL, the function will simply return the necessary length 
+    for the result (not including the terminating 0).
+ 
+
+    @param names list of channel names (return)
+    @param len length of names buffer
+    @param info 0 - names only, 1 - names and rates
+    @return number of characters if successful, <0 if not
+    @author DS, June 98
+************************************************************************/
+   int awgGetChannelNames (char* names, int len, int info);
+
+
+/** Add a waveform to an arbitrary waveform generator slot.
+
+    @param slot slot number
+    @param comp list of waveform components to be added
+    @param numComp number of components in the list
+    @return 0 if successful, <0 if not
+    @author DS, June 98
+************************************************************************/
+   int awgAddWaveform (int slot, AWG_Component* comp, int numComp);
+
+
+/** Download an arbitrary waveform to an arbitrary waveform generator 
+    slot. This function will not automatically switch on the output.
+    This requires that a component with awgArb is also added to the
+    slot. The specified frequency will be interpreted as the sampling
+    frequency.
+
+    @param slot slot number
+    @param y data points
+    @param len length of data array
+    @return 0 if successful, <0 if not
+    @author DS, June 98
+************************************************************************/
+   int awgSetWaveform (int slot, float y[], int len);
+
+
+/** Send a waveform to an arbitrary waveform generator. This routine
+    is used by the stream interface to transfer data to the front-end.
+    The return codes are as following
+    \begin{verbatim}
+     0    Data accepted
+     1    Data accepted, but there is currently not enough buffer space
+          to accept another block of data with the same length
+     2    The data block duplicates a time that was sent previously
+     3    The data block is not contiguous with the previous block
+    -1    This awg slot is not currently set up for stream data
+    -2    Invalid data block or size
+    -3    The timestamp of the data block is already past
+    -4    The timestamp of the data block is too far in the future
+    \end{verbatim}
+
+    @param slot slot number
+    @param time Start time of waveform in GPS sec
+    @param epoch Epoch of waveform
+    @param y data points
+    @param len length of data array
+    @return 0 if successful, <0 if not
+    @author DS, June 98
+************************************************************************/
+   int awgSendWaveform (int slot, taisec_t time, int epoch,
+                     float y[], int len);
+
+
+/** Stops a waveform in an arbitrary waveform generator slot. A waveform
+    can be stopped in several different ways:
+
+    \begin{verbatim}
+    0 reset
+    1 freeze
+    2 phase-out
+    \end{verbatim}
+
+    Reset will immediately stop any waveforms and reset the slot.
+    Freeze will continue to output the waveform in its current state
+    forever. Phase-out takes an additional argument which specifes 
+    a ramp down time.
+
+    There are several restrictions: (1) freeze will only work with
+    swept sine-like excitation signals, and (2) phase-out will only
+    ramp down the signal, if it is of inifinite duration.
+
+    @param slot slot number
+    @param terminate termination flag
+    @param time ramp down time
+    @param slot slot number
+    @return 0 if successful, <0 if not
+    @author DS, June 98
+************************************************************************/
+   int awgStopWaveform (int slot, int terminate, tainsec_t time);
+
+
+/** Set the overall gain of an arbitrary waveform generator slot.
+    The time argument is used to specify the ramp time. The gain is
+    ramped linearly from the old value to the new one. A negative 
+    ramp time indicates to use the previously specified one.
+
+    @param slot slot number
+    @param gain overall gain of waveforms
+    @param time ramp time
+    @return 0 if successful, <0 if not
+    @author DS, June 98
+************************************************************************/
+   int awgSetGain (int slot, double gain, tainsec_t time);
+
+
+/** Set an IIR filter in the arbitrary waveform generator. The specified
+    filter coefficients must be second order sections.
+
+    @param slot slot number
+    @param y filter data array (gain, b1, b2, a1, a2, etc.)
+    @param len length of data array
+    @return 0 if successful, <0 if not
+    @author DS, June 98
+************************************************************************/
+   int awgSetFilter (int slot, double y[], int len);
+
+
+/** Clear all waveforms from an arbitrary waveform generator slot.
+
+    @param slot slot number
+    @return 0 if successful, <0 if not
+    @author DS, June 98
+************************************************************************/
+   int awgClearWaveforms (int slot);
+
+
+/** Returns the waveforms of an arbitrary waveform generator.
+
+    @param slot slot number
+    @param comp pointer to a list of awg components to store the result
+    @param maxComp size of the result components array
+    @return 0 if successful, <0 if not
+    @author DS, June 98
+************************************************************************/
+   int awgQueryWaveforms (int slot, AWG_Component* comp, int maxComp);
+
+
+/** Reset all slots of an arbitrary waveform generator to zero. If the 
+    'id' is -1 all arbitrary waveform generators are reset. Use the 
+    macro AWG_ID to obtain the id for a specific AWG or for all AWG's
+    of a interferometer.
+
+    @param id identification of an arbitrary waveform generator
+    @return 0 if successful, <0 if not
+    @author DS, June 98
+************************************************************************/
+   int awgReset (int id);
+
+
+/** Obtains run-time statistics of an arbitrary waveform generator. Use 
+    the macro AWG_ID to obtain the id for a specific AWG of an 
+    interferometer.
+
+    @param id identification of an arbitrary waveform generator
+    @param stat statistics result
+    @return 0 if successful, <0 if not
+    @author DS, June 98
+************************************************************************/
+   int awgStatistics (int id, awgStat_t* stat);
+
+
+#if 0
+/** Returns the identification number of an arbitrary waveform generator.
+    The interferometer number has to be either 1 (4K), 2 (2K) or -1 
+    (both). If an interferometer has more than one awg, they are numbered
+    starting with 0. A -1 stands for all awg's belonging to a specific 
+    interferometer.
+
+    @param ifo interferometer number; 1 or 2
+    @param awgnum awg number; 0 and up
+    @return identification of an arbitrary waveform generator
+    @author DS, June 98
+************************************************************************/
+#define AWG_ID(ifo,awgnum)
+#endif
+
+/** Returns a string describing the current AWG configuration. The
+    caller is responsible to free the returned string!
+
+    @param id identification of an arbitrary waveform generator
+    @return configuration string if successful, NULL if not
+    @author DS, June 98
+************************************************************************/
+   char* awgShow (int id);
+
+/** ASCII command for an arbitrary waveform generator. This function 
+    interprets the specified waveform string and returns the 
+    corresponding awg components and awg points (arbitary waveforms
+    only). On error the function returns a negative value and an
+    error message if a string pointer is specified. The caller is 
+    responsible to free the memory returned by points or errmsg.
+    (In no case both are returned!) For arbitrary waveforms the caller 
+    should also specify if the waveforms are meant for a DS340.
+
+    @param cmd waveform description
+    @param comp awg components (return, maximum 2)
+    @param cnum number of awg components (return)
+    @param errmsg error message (return)
+    @param points waveform array (return)
+    @param num number of points in the waveform array
+    @param isDS340 true if stand-alone AWG
+    @return 0 if successful, <0 if not
+    @see T990013 for allowed waveforms
+    @author DS, June 98
+************************************************************************/
+   int awgWaveformCmd (const char* cmd, AWG_Component comp[], int* cnum,
+                     char** errmsg, float** points, int* num, 
+                     int isDS340);
+
+/** ASCII interface to the arbitrary waveform generators.
+
+    The function returns a string which was allocated with malloc. The
+    caller is reponsible to free this string if no longer needed.
+
+    @param cmd command string
+    @return reply string
+    @author DS, June 98
+************************************************************************/
+   char* awgCommand (const char* cmd);
+
+/** ASCII interface to the arbitrary waveform generators.
+
+    The function calls awgCommand and writes the return to stdout.
+
+    @param cmd command string
+    @return 0 if successful, <0 on error
+    @author DS, June 98
+************************************************************************/
+   int awgcmdline (const char* cmd);
+
+
+#define _AWG_IFO_OFS		1000
+#define _AWG_NUM_OFS		100
+
+#define AWG_ID(ifo,awgnum) \
+	(((ifo) == -1 ? -1 : (_AWG_IFO_OFS * (ifo + 1) + \
+	 ((awgnum) == -1 ? (-2 * _AWG_IFO_OFS * (ifo + 1)) : \
+	                   (_AWG_NUM_OFS * (awgnum))))))
+
+
+
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_GDS_AWGAPI_H */
-- 
GitLab