/*--------------------------------------------------------------------------
			     D I L L U D R I V

     This file contains the implementation of a driver for the Oxford 
     Instruments dillution cryostat using the CC0-510/AVSI temperature
     controller.

  
      Mark Koennecke, October 1997

       Copyright: see copyright.h
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <assert.h>
#include <fortify.h>
#include <conman.h>
#include <servlog.h>
#include <fortify.h>

#include "evdriver.h" 
#include "hardsup/dillutil.h"
#include "hardsup/el734_def.h"
#include "hardsup/el734fix.h"
#include "dilludriv.h"      
      
/*-----------------------------------------------------------------------*/
  typedef struct {
                   pDILLU pData;
                   char *pHost;
                   int iPort;
                   int iChannel;
                   int iLastError;
                   char *pTranslationFile;
                  } DILLUDriv, *pDILLUDriv;
/*----------------------------------------------------------------------------*/
  static int GetDILLUPos(pEVDriver  self, float *fPos)
  {
     pDILLUDriv pMe = NULL;
     int iRet;
     
     assert(self);
     pMe = (pDILLUDriv)self->pPrivate;
     assert(pMe);
   
     iRet = DILLU_Read(&pMe->pData,fPos);     
     if(iRet != 1 )
     {
       pMe->iLastError = iRet;
       return 0;
     }
     if( (*fPos < 0) || (*fPos > 1000) )
     {
       *fPos = -999.;
       return 0;
     }
     return 1;
  } 
/*----------------------------------------------------------------------------*/
  static int DILLURun(pEVDriver self, float fVal)
  {
     pDILLUDriv pMe = NULL;
     int iRet;
     
     assert(self);
     pMe = (pDILLUDriv )self->pPrivate;
     assert(pMe);

     iRet  = DILLU_Set(&pMe->pData,fVal);
     if(iRet != 1)
     {
       pMe->iLastError = iRet;
       return 0;
     }
     return 1;
 }
/*--------------------------------------------------------------------------*/
  static int DILLUError(pEVDriver self, int *iCode, char *error, int iErrLen)
  {
     pDILLUDriv pMe = NULL;
     
     assert(self);
     pMe = (pDILLUDriv)self->pPrivate;
     assert(pMe);

     *iCode = pMe->iLastError;
     DILLU_Error2Text(&pMe->pData,pMe->iLastError,error,iErrLen);    
    
    return 1;
  }
/*--------------------------------------------------------------------------*/
  static int DILLUSend(pEVDriver self, char *pCommand, char *pReply, int iLen)
  {
     pDILLUDriv pMe = NULL;
     int iRet;
     
     assert(self);
     pMe = (pDILLUDriv )self->pPrivate;
     assert(pMe);

     iRet  = DILLU_Send(&pMe->pData,pCommand, pReply,iLen);
     if(iRet != 1)
     {
       pMe->iLastError = iRet;
       return 0;
     }
     return 1;

  }  
/*--------------------------------------------------------------------------*/
  static int DILLUInit(pEVDriver self)
  {
     pDILLUDriv pMe = NULL;
     int iRet;
     
     assert(self);
     pMe = (pDILLUDriv )self->pPrivate;
     assert(pMe);

     pMe->pData = NULL;
     iRet = DILLU_Open(&pMe->pData, pMe->pHost, pMe->iPort, pMe->iChannel,
                       0,pMe->pTranslationFile);
     if(iRet != 1)
     {
         pMe->iLastError = iRet;
         return 0;
     }
     DILLU_Config(&pMe->pData, 1000);
     return 1;
  }  
/*--------------------------------------------------------------------------*/
  static int DILLUClose(pEVDriver self)
  {
     pDILLUDriv pMe = NULL;
     int iRet;
     
     assert(self);
     pMe = (pDILLUDriv )self->pPrivate;
     assert(pMe);

     DILLU_Close(&pMe->pData);
     return 1;
  }  
/*---------------------------------------------------------------------------*/
  static int DILLUFix(pEVDriver self, int iError)
  {
     pDILLUDriv pMe = NULL;
     int iRet;
     
     assert(self);
     pMe = (pDILLUDriv )self->pPrivate;
     assert(pMe);

        switch(iError)
        {
            /* network errors */
            case EL734__BAD_FLUSH:
            case EL734__BAD_RECV:
            case EL734__BAD_RECV_NET:
            case EL734__BAD_RECV_UNKN:
            case EL734__BAD_RECVLEN:
            case EL734__BAD_RECV1:
            case EL734__BAD_RECV1_PIPE:
            case EL734__BAD_RNG:
            case EL734__BAD_SEND:
            case EL734__BAD_SEND_PIPE:
            case EL734__BAD_SEND_NET:
            case EL734__BAD_SEND_UNKN:
            case EL734__BAD_SENDLEN:
                      DILLUClose(self);
                      iRet = DILLUInit(self);
                      if(iRet)
                      {
                        return DEVREDO;
                      }                 
                      else
                      {
                        return DEVFAULT;
                      }                 
                      break;
            /* handable protocoll errors */
            case EL734__BAD_TMO:
                      return DEVREDO;
                      break;
            case DILLU__NODILLFILE:
            case DILLU__ERRORTABLE:
            case DILLU__READONLY:
            case DILLU__OUTOFRANGE:
            case DILLU__BADMALLOC:          
            case DILLU__FILENOTFOUND:
                      return DEVFAULT;
            case DILLU__BADREAD:
            case DILLU__SILLYANSWER:
                       return DEVREDO;                                        
            default:
                      return DEVFAULT;
                      break;                       
        }
        return DEVFAULT;
  }
     
/*--------------------------------------------------------------------------*/
  static int DILLUHalt(pEVDriver *self)
  {
     assert(self);
     
     return 1;
  }
/*------------------------------------------------------------------------*/
  void KillDILLU(void *pData)
  {
     pDILLUDriv pMe = NULL;
     
     pMe = (pDILLUDriv)pData;
     assert(pMe);
     
     if(pMe->pHost)
     {
        free(pMe->pHost);
     }
     if(pMe->pTranslationFile)
     {
       free(pMe->pTranslationFile);
     }
     free(pMe);
  }  
/*------------------------------------------------------------------------*/
  pEVDriver CreateDILLUDriv(int argc, char *argv[])
  {
     pEVDriver pNew = NULL;
     pDILLUDriv pSim = NULL;
     
     /* check for arguments */
     if(argc < 3)
     {
       return NULL;
     }
     
     pNew = CreateEVDriver(argc,argv);
     pSim = (pDILLUDriv)malloc(sizeof(DILLUDriv));
     memset(pSim,0,sizeof(DILLUDriv));
     if(!pNew || !pSim)
     {
       return NULL;
     }
     pNew->pPrivate = pSim;
     pNew->KillPrivate = KillDILLU;
     
     /* initalise pDILLUDriver */
     pSim->iLastError = 0;
     pSim->pHost = strdup(argv[0]);
     pSim->iPort = atoi(argv[1]);
     pSim->iChannel = atoi(argv[2]);
     pSim->pTranslationFile = strdup(argv[3]);
     
     
     /* initialise function pointers */
     pNew->SetValue = DILLURun;
     pNew->GetValue = GetDILLUPos;
     pNew->Send     = DILLUSend;
     pNew->GetError = DILLUError;
     pNew->TryFixIt = DILLUFix;
     pNew->Init     = DILLUInit;
     pNew->Close    = DILLUClose;
     
     return pNew; 
  }	
  
