/*-------------------------------------------------------------------------- N H Q 2 0 0 D R I V This file contains the implementation of a driver for the NHQ 200 Voltage controller. Mark Koennecke, Juli 1997 Mark Lesha, January 2006 (based on ITC4 code) Douglas Clowes, December 2006 (based on LAKESHORE340 code) Copyright: Labor fuer Neutronenstreuung Paul Scherrer Institut CH-5423 Villigen-PSI The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. ----------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include typedef struct __EVDriver *pEVDriver; #include /* Do we need these ? #include #include */ #include #include #include "hardsup/nhq200util.h" #include "hardsup/el734_def.h" #include "hardsup/el734fix.h" #define SHITTYVALUE -777 /*------------------------- The Driver ------------------------------------*/ pEVDriver CreateNHQ200Driver(int argc, char *argv[]); int ConfigNHQ200(pEVDriver self); /*-----------------------------------------------------------------------*/ typedef struct { pNHQ200 pData; char *pHost; int iPort; int iChannel; int iControl; /* NHQ200 control */ float fDiv; float fMult; int iRead; /* NHQ200 sensor */ int iTmo; int iLastError; } NHQ200Driv, *pNHQ200Driv; /*----------------------------------------------------------------------------*/ static int GetNHQ200Pos(pEVDriver self, float *fPos) { pNHQ200Driv pMe = NULL; int iRet; assert(self); pMe = (pNHQ200Driv)self->pPrivate; assert(pMe); iRet = NHQ200_Read(&pMe->pData,fPos); if(iRet <= 0 ) { pMe->iLastError = iRet; return 0; } if( (*fPos < 0) || (*fPos > 10000) ) { *fPos = -999.; pMe->iLastError = SHITTYVALUE; return 0; } return 1; } /*----------------------------------------------------------------------------*/ static int NHQ200Run(pEVDriver self, float fVal) { pNHQ200Driv pMe = NULL; int iRet; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); iRet = NHQ200_Set(&pMe->pData,fVal); if(iRet != 1) { pMe->iLastError = iRet; return 0; } return 1; } /*--------------------------------------------------------------------------*/ static int NHQ200Error(pEVDriver self, int *iCode, char *error, int iErrLen) { pNHQ200Driv pMe = NULL; assert(self); pMe = (pNHQ200Driv)self->pPrivate; assert(pMe); *iCode = pMe->iLastError; if(pMe->iLastError == SHITTYVALUE) { strncpy(error,"Invalid voltage returned from NHQ200, check unit",iErrLen); } else { NHQ200_ErrorTxt(&pMe->pData,pMe->iLastError,error,iErrLen); } return 1; } /*--------------------------------------------------------------------------*/ static int NHQ200Send(pEVDriver self, char *pCommand, char *pReply, int iLen) { pNHQ200Driv pMe = NULL; int iRet; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); iRet = NHQ200_Send(&pMe->pData,pCommand, pReply,iLen); if(iRet <= 0) { pMe->iLastError = iRet; return 0; } return 1; } /*--------------------------------------------------------------------------*/ static int NHQ200Init(pEVDriver self) { pNHQ200Driv pMe = NULL; int iRet; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); pMe->pData = NULL; iRet = NHQ200_Open(&pMe->pData, pMe->pHost, pMe->iRead, pMe->iControl,0); if(iRet != 1) { if(iRet == NHQ200__NONHQ200) { return -1; } else { pMe->iLastError = iRet; return 0; } } return 1; } /*--------------------------------------------------------------------------*/ static int NHQ200Close(pEVDriver self) { pNHQ200Driv pMe = NULL; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); NHQ200_Close(&pMe->pData); return 1; } /*---------------------------------------------------------------------------*/ static int NHQ200Fix(pEVDriver self, int iError) { pNHQ200Driv pMe = NULL; int iRet; assert(self); pMe = (pNHQ200Driv )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: NHQ200Close(self); iRet = NHQ200Init(self); if(iRet) { return DEVREDO; } else { return DEVFAULT; } break; /* handable protocoll errors */ case EL734__BAD_TMO: return DEVREDO; break; case -501: /* Bad_COM */ return DEVREDO; case -504: /* Badly formatted */ return DEVREDO; default: return DEVFAULT; break; } return DEVFAULT; } /*--------------------------------------------------------------------------*/ #if 0 static int NHQ200Halt(pEVDriver *self) { assert(self); return 1; } #endif /*------------------------------------------------------------------------*/ void KillNHQ200(void *pData) { pNHQ200Driv pMe = NULL; pMe = (pNHQ200Driv)pData; assert(pMe); if(pMe->pHost) { free(pMe->pHost); } free(pMe); } /*------------------------------------------------------------------------*/ pEVDriver CreateNHQ200Driver(int argc, char *argv[]) { pEVDriver pNew = NULL; pNHQ200Driv pSim = NULL; /* check for arguments */ if(argc < 3) { return NULL; } pNew = CreateEVDriver(argc,argv); if(!pNew) return NULL; pSim = (pNHQ200Driv)malloc(sizeof(NHQ200Driv)); if(!pSim) return NULL; memset(pSim,0,sizeof(NHQ200Driv)); pNew->pPrivate = pSim; pNew->KillPrivate = KillNHQ200; /* initalise pNHQ200Driver */ pSim->iControl = atoi(argv[2]); pSim->iRead = atoi(argv[1]); pSim->iLastError = 0; pSim->iTmo = 10; /* The NHQ200 doesn't require divisors or multipliers and they are always forced to 1.0 */ pSim->fDiv = 1.0; pSim->fMult = 1.0; pSim->pHost = strdup(argv[0]); pSim->iPort = 0; pSim->iChannel = 0; /* initialise function pointers */ pNew->SetValue = NHQ200Run; pNew->GetValue = GetNHQ200Pos; pNew->Send = NHQ200Send; pNew->GetError = NHQ200Error; pNew->TryFixIt = NHQ200Fix; pNew->Init = NHQ200Init; pNew->Close = NHQ200Close; return pNew; } /*--------------------------------------------------------------------------*/ int ConfigNHQ200(pEVDriver self) { pNHQ200Driv pMe = NULL; int iRet; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); iRet = NHQ200_Config(&pMe->pData, pMe->iTmo, pMe->iRead, pMe->iControl,pMe->fDiv,pMe->fMult); if(iRet < 0) { pMe->iLastError = iRet; return 0; } return 1; } /*-------------------------------------------------------------------------*/ int SetSensorNHQ200(pEVDriver self, int iSensor) { pNHQ200Driv pMe = NULL; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); /* The NHQ200 incorporates two voltage supplies so allow iSensor=1 to 2 */ if( (iSensor < 1) || (iSensor > 2) ) { return 0; } pMe->iRead = iSensor; pMe->pData->iRead = iSensor; return 1; } /*-------------------------------------------------------------------------*/ int SetControlNHQ200(pEVDriver self, int iSensor) { pNHQ200Driv pMe = NULL; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); /* The NHQ200 incorporates two voltage supplies so allow iSensor=1 to 2 */ if( (iSensor < 1) || (iSensor > 2) ) { return 0; } pMe->iControl = iSensor; pMe->pData->iControl = iSensor; return 1; } /*-------------------------------------------------------------------------*/ int SetTMONHQ200(pEVDriver self, int iSensor) { pNHQ200Driv pMe = NULL; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); if(iSensor < 10) { return 0; } pMe->iTmo = iSensor; return 1; } /*-------------------------------------------------------------------------*/ int GetControlNHQ200(pEVDriver self) { pNHQ200Driv pMe = NULL; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); return pMe->iControl; } /*-------------------------------------------------------------------------*/ int GetSensorNHQ200(pEVDriver self) { pNHQ200Driv pMe = NULL; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); return pMe->iRead; } /*-------------------------------------------------------------------------*/ int GetTMONHQ200(pEVDriver self) { pNHQ200Driv pMe = NULL; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); return pMe->iTmo; } /*-------------------------------------------------------------------------*/ float GetDivisorNHQ200(pEVDriver self) { pNHQ200Driv pMe = NULL; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); return pMe->fDiv; /* but forced to 1.0 for NHQ200, not used */ } /*--------------------------------------------------------------------------*/ int SetDivisorNHQ200(pEVDriver self, float fDiv) { pNHQ200Driv pMe = NULL; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); /* The NHQ200 doesn't need divisor, force to 1.0 */ pMe->fDiv = 1.0; /* fDiv */; return 1; } /*-------------------------------------------------------------------------*/ float GetMultNHQ200(pEVDriver self) { pNHQ200Driv pMe = NULL; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); return pMe->fMult; /* but forced to 1.0 for NHQ200, not used */ } /*--------------------------------------------------------------------------*/ int SetMultNHQ200(pEVDriver self, float fDiv) { pNHQ200Driv pMe = NULL; assert(self); pMe = (pNHQ200Driv )self->pPrivate; assert(pMe); /* The NHQ200 doesn't need multiplier, force to 1.0 */ pMe->fMult = 1.0; /* fDiv */; return 1; }