/*---------------------------------------------------------------------------
linadriv.c

Driver for the Lock IN Amplifier SIGNAL RECOVERY Model 7265

Markus Zolliker, Oct 2006
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/time.h>
#include <math.h>
#include <tcl.h>
#include <fortify.h>
#include <sics.h>
#include <splitter.h>
#include <obpar.h>
#include <devexec.h>
#include <nserver.h>
#include <interrupt.h>
#include <emon.h>
#include <evcontroller.h>
#include <evcontroller.i>
#include <servlog.h>
#include <sicsvar.h>
#include <evdriver.i>
#include <rs232controller.h>
#include "fsm.h"
#include "ease.h"
#include "initializer.h"

typedef struct {
  EaseDriv d;
  float x, y;
} Lina;

static ParClass linaClass = { "LINA", sizeof(Lina) };

/*----------------------------------------------------------------------------*/
int LinaHandler(void *object) {
  int iret, l;
  EaseBase *eab = EaseBaseCast(object);
  char *corr;
  
  if (eab->state < EASE_idle) goto quit;
  if (availableNetRS232(eab->ser) || availableRS232(eab->ser)) {
    eab->msg[0] = '\0';
    l = sizeof(eab->ans);
    iret = readRS232TillTerm(eab->ser, eab->ans, &l);
    if (eab->state != EASE_expect && eab->state != EASE_lost) {
      if (iret == 1) {
        ParPrintf(eab, eError, "unexpected answer: %s", eab->ans);
      }
      goto quit;
    }
    if (iret == 1) {
      ParPrintf(eab, -2, "ans: %s", eab->ans);
      if (eab->state == EASE_lost) {
        goto quit;
      } else if (strncmp(eab->cmd,"ID",2) == 0) {
        if (strcmp(eab->ans, eab->version) == 0) {
          /* we are still connected with the same device */
        } else if (*eab->version == '\0') {
          strncat(eab->version, eab->ans, sizeof(eab->version)-1);
        } else { /* version (and therefore device) changed */
          eab->errCode = EASE_DEV_CHANGED;
          eab->state = EASE_idle;
          goto error;
        }
        eab->state = EASE_idle;
        goto quit;
      } else {
        eab->tmo = 120;
      }
    }
    if (iret != 1) {
      eab->errCode = iret;
      eab->state = EASE_idle;
      goto error;
    }
    eab->state = EASE_read;
  } else if (eab->state == EASE_expect) {
    if (time(NULL) > eab->cmdtime + eab->tmo) {
      eab->state = EASE_lost;
    }
  } else if (eab->state == EASE_lost) {
/*
    if (time(NULL) > eab->cmdtime) {
      EaseWrite(eab, "RS");
      eab->state = EASE_lost;
    }
*/
  }
  goto quit;
error:
  /* EaseWriteError(eab); */
quit:
  return EaseHandler(eab);
}
/*----------------------------------------------------------------------------*/
static void LinaParDef(void *object) {
  Lina *drv = ParCast(&linaClass, object);
  EaseBase *eab = object;

  ParName(""); ParTail("units");
  ParFloat(&drv->x, PAR_NAN);
  
  ParName("x"); ParTail("");
  ParFloat(&drv->x, PAR_NAN);
  
  ParName("y"); ParTail("");
  ParFloat(&drv->y, PAR_NAN);

  EaseBasePar(drv);
  EaseSendPar(drv);
/*
  EaseDrivPar(drv, "%.5g", "K");
*/
  ParStdDef();
  EaseMsgPar(drv);
}
/*----------------------------------------------------------------------------*/
static long LinaRead(long pc, void *object) {
  Lina *drv = ParCast(&linaClass, object);
  EaseBase *eab = object;
  char *p;
  
  switch (pc) { default: /* FSM BEGIN *******************************/
    EaseWrite(eab, "XY.");
  return __LINE__; case __LINE__: /**********************************/
    p = strchr(eab->ans, ',');
    if (p) {
      *p='\0';
      p++;
      drv->x = atof(eab->ans);
      drv->y = atof(p);
    }
    ParLog(drv);
  fsm_quit: return 0; } /* FSM END *********************************/
}
/*----------------------------------------------------------------------------*/
static long LinaStart(long pc, void *object) {
  Lina *drv = ParCast(&linaClass, object);
  EaseBase *eab = object;
  
  switch (pc) { default: /* FSM BEGIN *******************************/
    EaseWrite(eab, "ID");
  return __LINE__; case __LINE__: /**********************************/
    if (0 != strncmp(eab->version, "7265", 4)) {
      snprintf(eab->msg, sizeof eab->msg, "unknown lock in amplifier version: %s",
               eab->version);
      ParPrintf(drv, eError, "ERROR: %s", eab->msg);
      EaseStop(eab);
      goto quit;
    }
    ParPrintf(drv, eStatus, "connected to %s", eab->version);
    FsmCall(LinaRead);
  return __LINE__; case __LINE__: /**********************************/
    
  quit:
  return 0; } /* FSM END ********************************************/
}
/*----------------------------------------------------------------------------*/
static long LinaSet(long pc, void *object) {
  Lina *drv = ParCast(&linaClass, object);
  EaseBase *eab = object;
  char cmd[32];
  int upd;
  
  switch (pc) { default: /* FSM BEGIN *******************************/
  /*
    snprintf(cmd, sizeof cmd, "SETP %.5g;SETP?", drv->d.targetValue);
    EaseWrite(eab, cmd);
    */
  quit:
  return 0; } /* FSM END ********************************************/
}
/*----------------------------------------------------------------------------*/
static int LinaInit(SConnection *con, int argc, char *argv[], int dynamic) {
  /* args:
       MakeObject objectname lina <rs232>
       MakeObject objectname lina <host> <port>
   */
  Lina *drv;
  
  drv = EaseMakeDriv(con, &linaClass, argc, argv, dynamic, 7,
                    LinaParDef, LinaHandler, LinaStart, NULL, LinaRead,
                    LinaSet);
  if (drv == NULL) return 0;
/*
  setRS232ReplyTerminator(drv->d.b.ser,"\n");
  setRS232SendTerminator(drv->d.b.ser,"\n");
*/
  return 1;
}
/*----------------------------------------------------------------------------*/
void LinaStartup(void) {
  ParMakeClass(&linaClass, EaseDrivClass());
  MakeDriver("LINA", LinaInit, 0, "Lock in amplifier SIGNAL RECOVERY Model 7265");
}
