/*-------------------------------------------------------------------------
  This is the implementation file for a driver for the Risoe A1931a 
  temperature controller. This driver controls the device through a GPIB 
  interface.
  
  copyright: see file COPYRIGHT

   Mark Koennecke, February 2003
 -------------------------------------------------------------------------*/
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <assert.h>
#include <unistd.h>
#include <fortify.h>
#include <sics.h>
#include <obpar.h>
#include <evcontroller.h>
#include <evcontroller.i>
#include <evdriver.i>  
#include <gpibcontroller.h>
#include "A1931.h"

/*========================== private data structure ====================*/
typedef struct {
  int sensor;   /* the control sensor */
  pGPIB gpib;   /* the GPIB interface to use in order to talk to the thing*/
  int gpibAddress; /* address on bus */
  int devID;    /* deviceID of the controller on the GPIB */
  char errorBuffer[132]; /* a buffer for error messages from the thing*/
  char commandLine[132]; /* buffer to keep the offending command line */
  int errorCode; /* error indicator */
}A1931, *pA1931;
/*============================ defines ================================*/
#define COMMERROR -300
#define A1931ERROR -301
#define FILEERROR   -302
/*====================================================================*/
static char *A1931comm(pEVDriver pData, char *command){
  char buffer[256], *pPtr;
  int status;
  pA1931 self = NULL;
  Tcl_DString reply;

  self = (pA1931)pData->pPrivate;
  assert(self);
  
  /*
    send 
  */
  strncpy(buffer,command,250);
  strcat(buffer,"\n");
  status = GPIBsend(self->gpib,self->devID,buffer,(int)strlen(buffer));
  if(status < 0){
    self->errorCode = COMMERROR;
    GPIBerrorDescription(self->gpib,status,self->errorBuffer,131);
    return NULL;
  }

  /*
    read until > is found
  */
  Tcl_DStringInit(&reply);
  while(1){
    pPtr = GPIBreadTillTerm(self->gpib,self->devID,10);
    if(strstr(pPtr,"GPIB READ ERROR")  != NULL){
      free(pPtr);
      self->errorCode = COMMERROR;
      Tcl_DStringFree(&reply);
      return NULL;
    } else {
      Tcl_DStringAppend(&reply,pPtr,-1);
      if(strchr(pPtr,'>') != NULL){
	/*
	  finished
	*/
	free(pPtr);
	break;
      }
      free(pPtr);
    }
  }
  pPtr = NULL;
  pPtr = strdup(Tcl_DStringValue(&reply));
  Tcl_DStringFree(&reply);
  if(pPtr[0] == '#'){
    /*
      error
    */
    self->errorCode = A1931ERROR;
    strncpy(self->errorBuffer,pPtr,131);
    free(pPtr);
    return NULL;
  }
  return pPtr;
}
/*--------------------------------------------------------------------*/
static int A1931command(pEVDriver pData, char *command, char *replyBuffer,
		 int replyBufferLen){
  pA1931 self = NULL;
  char *pReply = NULL;

  self = (pA1931)pData->pPrivate;
  assert(self);

  pReply = A1931comm(pData,command);
  if(pReply != NULL){
    strncpy(replyBuffer,pReply,replyBufferLen);
    free(pReply);
    return 1;
  } else {
    strncpy(replyBuffer,self->errorBuffer,replyBufferLen);
    return 0;
  }
}
/*====================================================================*/
static int A1931Init(pEVDriver pData){
  pA1931 self = NULL;

  self = (pA1931)pData->pPrivate;
  assert(self);

  self->devID = GPIBattach(self->gpib,0,self->gpibAddress,0,13,0,0); 
  if(self->devID < 0){
    return 0;
  }
  return 1;
}
/*====================================================================*/
static int A1931Close(pEVDriver pData){
 pA1931 self = NULL;

  self = (pA1931)pData->pPrivate;
  assert(self);

  GPIBdetach(self->gpib,self->devID);
  self->devID = 0;
  return 1;
}
/*===================================================================*/
static int A1931Get(pEVDriver pData,float *fPos){
  pA1931 self = NULL;
  char buffer[132], command[50];
  int status;

  self = (pA1931)pData->pPrivate;
  assert(self);

  sprintf(command,"?TEMP%1.1d",self->sensor);
  status = A1931command(pData,command,buffer,131);
  if(!status){
    return 0;
  }
  sscanf(buffer,"%f",fPos);
  return 1;
}
/*=====================================================================*/
static int A1931Set(pEVDriver pData, float fNew){
  pA1931 self = NULL;
  char buffer[132], command[50];
  int status;

  self = (pA1931)pData->pPrivate;
  assert(self);

  sprintf(command,"SET%1.1d=%f",self->sensor,fNew);
  status = A1931command(pData,command,buffer,131);
  if(!status){
    return 0;
  }
  return 1;
}
/*====================================================================*/
static int A1931error(pEVDriver pData, int *iCode, char *errBuff, int bufLen){
  pA1931 self = NULL;
  char pError[256];

  self = (pA1931)pData->pPrivate;
  assert(self);

  *iCode = self->errorCode;
  sprintf(pError,"ERROR: %s",self->errorBuffer);
  strncpy(errBuff,pError,bufLen);
  return 1;
}
/*====================================================================*/
static int A1931fix(pEVDriver pData, int iCode){
  pA1931 self = NULL;
  char pError[256];

  self = (pA1931)pData->pPrivate;
  assert(self);

  if(iCode == COMMERROR){
    GPIBclear(self->gpib,self->devID);
    return DEVREDO;
  } 
  return DEVFAULT;
}
/*=====================================================================*/
pEVDriver CreateA1931Driver(int argc, char *argv[]){
  pEVDriver self = NULL;
  pA1931 priv = NULL;

  if(argc < 2){
    return NULL;
  }

  /*
    allocate space 
  */
  self = CreateEVDriver(argc,argv);
  priv = (pA1931)malloc(sizeof(A1931));
  if(self == NULL || priv == NULL){
    return NULL;
  }
  memset(priv,0,sizeof(A1931));
  self->pPrivate = priv;
  self->KillPrivate = free;

  /*
    initialize
  */
  priv->gpib = (pGPIB)FindCommandData(pServ->pSics,argv[0],"GPIB");
  if(!priv->gpib){
    DeleteEVDriver(self);
    return NULL;
  }
  priv->sensor = 1;
  priv->gpibAddress = atoi(argv[1]);

  /*
    initialize function pointers
  */
  self->Send =  A1931command;
  self->Init = A1931Init;
  self->Close = A1931Close;
  self->GetValue = A1931Get;
  self->SetValue = A1931Set;
  self->GetError = A1931error;
  self->TryFixIt = A1931fix;

  return self;
}
/*=======================================================================*/
static int downloadFile(pA1931 self, FILE *fd){
  char buffer[132], *pPtr;
  int status;

  while(1){
    if(fgets(buffer,130,fd) == NULL){
      self->errorCode = FILEERROR;
      strcpy(self->errorBuffer,"Failed to read from file");
      return 0;
    }
    if(strstr(buffer,"$END") != NULL){
      break;
    }
    status = GPIBsend(self->gpib,self->devID,buffer,(int)strlen(buffer));
    if(status < 0){
      self->errorCode = COMMERROR;
      GPIBerrorDescription(self->gpib,status,self->errorBuffer,131);
      return 0;
    }
    pPtr = GPIBreadTillTerm(self->gpib,self->devID,10);
    if(pPtr[0] == '#'){
      self->errorCode = A1931ERROR;
      strncpy(self->errorBuffer,pPtr,131);
      strncpy(self->commandLine,buffer,131);
      free(pPtr);
      return 0;
    }
    free(pPtr);
    usleep(50);
  }
  return 1;
}
/*=======================================================================*/
int A1931Action(SConnection *pCon, SicsInterp *pSics, void *pData,
		int argc, char *argv[]){
  pEVControl pEV = NULL;
  pA1931 self = NULL;
  char buffer[256];
  char error[132];
  FILE *fd = NULL;
  int status, iCode;

  pEV = (pEVControl)pData;
  assert(pEV);
  self = (pA1931)pEV->pDriv->pPrivate;
  assert(self);

  if(argc > 1){
    strtolower(argv[1]);
    if(strcmp(argv[1],"sensor") == 0){
      if(argc > 2){
	/* set case */
	if(!SCMatchRights(pCon,usUser)){
	  return 0;
	}
	self->sensor = atoi(argv[2]);
	SCSendOK(pCon);
	return 1;
      } else {
	/* get case */
	sprintf(buffer,"%s.sensor = %d",argv[0],self->sensor);
	SCWrite(pCon,buffer,eValue);
	return 1;
      }
    }else if(strcmp(argv[1],"list") == 0){
      sprintf(buffer,"%s.sensor = %d",argv[0],self->sensor);
      SCWrite(pCon,buffer,eValue);
      return EVControlWrapper(pCon,pSics,pData,argc,argv);
    } else if(strcmp(argv[1],"file") == 0){
      if(!SCMatchRights(pCon,usUser)){
	return 0;
      }
      if(argc < 3){
	SCWrite(pCon,"ERROR: need filename argument",eError);
	return 0;
      }
      fd = fopen(argv[2],"r");
      if(fd == NULL){
	sprintf(buffer,"ERROR: failed to open %s", argv[2]);
	SCWrite(pCon,buffer,eError);
	return 0;
      }
      status = downloadFile(self,fd);
      fclose(fd);
      if(!status){
	A1931error(pEV->pDriv,&iCode,error,131);
	sprintf(buffer,"%s while transfering file", error);
	SCWrite(pCon,buffer,eError);
	sprintf(buffer,"Offending command: %s",self->commandLine);
	SCWrite(pCon,buffer,eError);
	return 0;
      }
      SCSendOK(pCon);
      return 1;
    }
  } 
  return EVControlWrapper(pCon,pSics,pData,argc,argv);
}
