From 81359a740f33921f57a68fb1b418b6488a753132 Mon Sep 17 00:00:00 2001 From: Ferdi Franceschini Date: Tue, 9 May 2006 09:17:15 +1000 Subject: [PATCH] Added to repository. r986 | ffr | 2006-05-09 09:17:15 +1000 (Tue, 09 May 2006) | 2 lines --- site_ansto/Makefile | 103 ++++ site_ansto/anstohm.cpp | 447 ++++++++++++++ site_ansto/anstohm.h | 28 + site_ansto/hm_asim.cpp | 1038 +++++++++++++++++++++++++++++++++ site_ansto/hm_asim.h | 21 + site_ansto/hm_tango.h | 30 + site_ansto/itc4.c | 281 +++++++++ site_ansto/itc4.h | 43 ++ site_ansto/itc4.w | 74 +++ site_ansto/itc4driv.c | 478 +++++++++++++++ site_ansto/lakeshore340.c | 284 +++++++++ site_ansto/lakeshore340.h | 49 ++ site_ansto/lakeshore340driv.c | 489 ++++++++++++++++ site_ansto/lh45.c | 284 +++++++++ site_ansto/lh45.h | 49 ++ site_ansto/lh45driv.c | 489 ++++++++++++++++ site_ansto/make_gen_variables | 34 ++ site_ansto/motor_asim.c | 655 +++++++++++++++++++++ site_ansto/motor_asim.h | 17 + site_ansto/motor_dmc2280.c | 802 +++++++++++++++++++++++++ site_ansto/motor_dmc2280.h | 17 + site_ansto/motor_driver.h | 24 + site_ansto/refl2t.c | 403 +++++++++++++ site_ansto/refl2t.h | 49 ++ site_ansto/site_ansto.c | 238 ++++++++ site_ansto/site_dummy.c | 131 +++++ 26 files changed, 6557 insertions(+) create mode 100644 site_ansto/Makefile create mode 100644 site_ansto/anstohm.cpp create mode 100644 site_ansto/anstohm.h create mode 100644 site_ansto/hm_asim.cpp create mode 100644 site_ansto/hm_asim.h create mode 100644 site_ansto/hm_tango.h create mode 100644 site_ansto/itc4.c create mode 100644 site_ansto/itc4.h create mode 100644 site_ansto/itc4.w create mode 100644 site_ansto/itc4driv.c create mode 100644 site_ansto/lakeshore340.c create mode 100644 site_ansto/lakeshore340.h create mode 100644 site_ansto/lakeshore340driv.c create mode 100644 site_ansto/lh45.c create mode 100644 site_ansto/lh45.h create mode 100644 site_ansto/lh45driv.c create mode 100644 site_ansto/make_gen_variables create mode 100644 site_ansto/motor_asim.c create mode 100644 site_ansto/motor_asim.h create mode 100644 site_ansto/motor_dmc2280.c create mode 100644 site_ansto/motor_dmc2280.h create mode 100644 site_ansto/motor_driver.h create mode 100644 site_ansto/refl2t.c create mode 100644 site_ansto/refl2t.h create mode 100644 site_ansto/site_ansto.c create mode 100644 site_ansto/site_dummy.c diff --git a/site_ansto/Makefile b/site_ansto/Makefile new file mode 100644 index 00000000..cea936b3 --- /dev/null +++ b/site_ansto/Makefile @@ -0,0 +1,103 @@ +# vim: ft=make ts=4 sw=4 noet cindent +#--------------------------------------------------------------------------- +# Makefile for SICS +# machine-dependent part for Redhat Linux with AFS at PSI +# +# Mark Koennecke 1996-2001 +# Markus Zolliker, March 2003 +#========================================================================== + +include ../linux_def +# TODO Should use PSI ../make_gen instead of make_gen_variables +include make_gen_variables + +# PSI rules and variables +EXTRA=nintf.o +PSI_CLEAN_MATRIX = rm -f ../*.o; $(MAKE) -C ../matrix $(MFLAGS) clean +PSI_CFLAGS = -I./ -I$(HDFROOT)/include -DHDF5 \ + -fwritable-strings -DCYGNUS -DNONINTF -g $(DFORTIFY) +PSI_SLIBS = matrix/libmatrix.a +PSI_LIBS = -L$(HDFROOT)/lib $(NILIB)\ + -ltcl8.4 $(HDFROOT)/lib/libhdf5.a \ + -ldl -lz -lm -lc + +../%.o : ../%.c + cd ..; $(CC) -c $(PSI_CFLAGS) $*.c -o $*.o + +../matrix/libmatrix.a: + make -C ../matrix $(MFLAGS) libmatrix.a + +# ANSTO rules and variables +CC = gcc +CFLAGS = -g -Ihardsup -I.. -Wno-unused -Wno-comment -Wno-switch -Werror +HDFROOT=/usr/local + +SRC = ./../.. +SITENAME = _ansto +SITEDIR = site_ansto +SITELIB = libansto.a +SITEHARDSUP = hardsup/libhlib.a +HARDSUPDIR = $(SITEDIR)/hardsup +SUBLIBS = libansto.a hardsup/libhlib.a +VPATH = $(SRC) + TANGOROOT = /usr/local/lib/ + OMNIORBROOT = /usr/local/lib +COREDIR = $(SRC) + +.SUFFIXES: +.SUFFIXES: .c .o .f + +TANGOLIBS = \ + /usr/local/lib/libclient.a \ + /usr/local/lib/liblog4tango.a \ + /usr/local/lib/libtango.a \ + /usr/local/lib/libomniDynamic4.a \ + /usr/local/lib/libomniORB4.a \ + /usr/local/lib/libomnithread.a + +#OBJ= site_ansto.o batch.o buffer.o ruli.o protocol.o sinfox.o \ +# motor_asim.o motor_dmc2280.o motor_pdx.o \ +# itc4.o itc4driv.o \ +# hm_mrpd.o scan_mrpd.o + +OBJ= site_ansto.o \ + motor_asim.o motor_dmc2280.o\ + lh45.o lh45driv.o \ + lakeshore340.o lakeshore340driv.o \ + ../psi/tcpdocho.o ../psi/tcpdornier.o + +all: ../matrix/libmatrix.a $(COREOBJ:%=../%) libansto.a libhardsup + $(CC) -g -o SICServer $(COREOBJ:%=../%) $(SUBLIBS) $(PSI_SLIBS:%=../%) $(PSI_LIBS) + +libansto.a: $(OBJ) + rm -f libansto.a + ar cr libansto.a $(OBJ) + ranlib libansto.a + +libhardsup: + $(MAKE) -C hardsup/ + +anstohm.o : anstohm.cpp + $(CXX) -c anstohm.cpp $(CFLAGS) $(CXXFLAGS) -Wno-all + +hm_mrpd.o : hm_mrpd.cpp + $(CXX) -c hm_mrpd.cpp $(CFLAGS) $(CXXFLAGS) -Wno-all + +hm_asim.o : hm_asim.cpp + $(CXX) -c hm_asim.cpp $(CFLAGS) $(CXXFLAGS) -Wno-all + +clean: + $(PSI_CLEAN_MATRIX) + $(MAKE) -C hardsup clean + rm -f SICServer + rm -f *.a + rm -f *.o + +MZOBJ=fsm.o logger.o sugar.o pardef.o ease.o strobj.o oxinst.o \ + ipsdriv.o ilmdriv.o itcdriv.o ighdriv.o euro2kdriv.o modbus.o + +cflags: + @echo ${CFLAGS} + +deploy: all + cd instrument; ./make_sics_tar.tcl diff --git a/site_ansto/anstohm.cpp b/site_ansto/anstohm.cpp new file mode 100644 index 00000000..a0ff95ab --- /dev/null +++ b/site_ansto/anstohm.cpp @@ -0,0 +1,447 @@ +/*---------------------------------------------------------------------------- + + A N S T O H M + + A histogramming memory driver for the ANSTO histogrammer. This version + assumes the histogrammer is a TANGO device server and uses the TANGO + api to communicate with the histogrammer. It has to be compiled with + the C++ compiler and the SICServer has to be linked with C++. + + Andy Gotz, February 2004 + + Copyright: + + ANSTO + Lucas Heights + New South Wales + AUSTRALIA + + + 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 +extern "C" { +#include "fortify.h" +#include "sics.h" +#include "countdriv.h" +#include "counter.h" +#include "stringdict.h" +#include "HistMem.h" +#include "HistDriv.i" +#include "anstohm.h" +} +#include + +/* + +#define TESTVAL 128 + + define TESTVAL to set the simulated histogram to a fixed value for + testing +*/ + static int iSet = 0; + static HistInt iSetVal = 0; + static HistMode eHistMode; +/* + * histogrammer proxy and data globals + * + * NOTE: defining this as globals means ONLY one histogrammer can be + * interfaces from SICS. If we need more we need to manage multiple + * histogram devices e.g. by adding them to the pHistDriver structure + */ + + static char *hm_device = "localhost:30001/hifar/mrpd/hm#dbase=no"; + static Tango::DeviceProxy *hm_proxy=NULL; + static vector hm_data; + +/*--------------------------------------------------------------------------*/ + static int AnstoHMConfig(pHistDriver self, SConnection *pCon, + pStringDict pOption, SicsInterp *pSics) + { + int i, iLength = 1, status; + char pData[132]; + + if(eHistMode == eHTOF) + { + for(i = 0; i < self->data->rank; i++) + { + iLength *= self->data->iDim[i]; + } + iLength *= self->data->nTimeChan; + } + +/* + * set count mode + */ + if (hm_proxy != NULL) + { + try + { + string count_mode; + if (self->eCount == ePreset) + { + count_mode = "monitor"; + } + else + { + count_mode = "time"; + } + Tango::DeviceAttribute attr_write((const char*)"count_mode",count_mode); + hm_proxy->write_attribute(attr_write); + } + catch(Tango::DevFailed &exception) + { + SCWrite(pCon,"ERROR: Histogram Count Mode failed",eError); + SCWrite(pCon,"Tango error :",eError); + SCWrite(pCon,exception.errors[0].desc,eError); + return 0; + } + } + +/* + * send preset to histogrammer + */ + if (hm_proxy != NULL) + { + try + { +/* + * QUESTION: what are the time units of fCountPreset ? Might have to scale it + * should iExponent be taken into account here ? + */ + long preset = (long)self->fCountPreset; + Tango::DeviceAttribute attr_write((const char*)"preset",preset); + hm_proxy->write_attribute(attr_write); + } + catch(Tango::DevFailed &exception) + { + SCWrite(pCon,"ERROR: Histogram Preset failed",eError); + SCWrite(pCon,"Tango error :",eError); + SCWrite(pCon,exception.errors[0].desc,eError); + return 0; + } + } + + return 1; + } +/*-------------------------------------------------------------------------*/ + static int AnstoHMStart(pHistDriver self, SConnection *pCon) + { + if (hm_proxy != NULL) + { + try + { + hm_proxy->command_inout("Start"); + } + catch (Tango::DevFailed &exception) + { + SCWrite(pCon,"ERROR: TANGO Histogram Start failed",eError); + SCWrite(pCon,exception.errors[0].desc,eError); + return 0; + } + } + return 1; + } +/*-------------------------------------------------------------------------*/ + static int AnstoHMPause(pHistDriver self, SConnection *pCon) + { + if (hm_proxy != NULL) + { + try + { + hm_proxy->command_inout("Pause"); + } + catch (Tango::DevFailed &exception) + { + SCWrite(pCon,"ERROR: Histogram Pause failed",eError); + SCWrite(pCon,"Tango error :",eError); + SCWrite(pCon,exception.errors[0].desc,eError); + return 0; + } + } + return 1; + } +/*------------------------------------------------------------------------*/ + static int AnstoHMContinue(pHistDriver self, SConnection *pCon) + { + if (hm_proxy != NULL) + { + try + { + hm_proxy->command_inout("Continue"); + } + catch (Tango::DevFailed &exception) + { + SCWrite(pCon,"ERROR: Histogram Continue failed",eError); + SCWrite(pCon,"Tango error :",eError); + SCWrite(pCon,exception.errors[0].desc,eError); + return 0; + } + } + return 1; + } +/*-------------------------------------------------------------------------*/ + static int AnstoHMHalt(pHistDriver self) + { + if (hm_proxy != NULL) + { + try + { + hm_proxy->command_inout("Halt"); + } + catch (Tango::DevFailed &exception) + { +/* + SCWrite(pCon,"ERROR: Histogram Halt failed",eError); + SCWrite(pCon,exception.errors[0].desc,eError); + */ + return 0; + } + } + return 1; + } +/*-------------------------------------------------------------------------*/ + static int AnstoHMGetCountStatus(pHistDriver self, SConnection *pCon) + { + if (hm_proxy != NULL) + { + try + { + Tango::DevState state; + state = hm_proxy->state(); + switch (state) + { + case Tango::OFF : + return HWIdle; + case Tango::RUNNING : + return HWBusy; + case Tango::STANDBY : + return HWPause; + case Tango::FAULT : + return HWFault; + default : + return HWFault; + } + } + catch(Tango::DevFailed &exception) + { + SCWrite(pCon,"ERROR: Histogram state() failed",eError); + SCWrite(pCon,"Tango error :",eError); + SCWrite(pCon,exception.errors[0].desc,eError); + return 0; + } + } + } +/*-------------------------------------------------------------------------*/ + static int AnstoHMGetError(pHistDriver self, int *iCode, char *pError, int iLen) + { + return 0; + } +/*-------------------------------------------------------------------------*/ + static int AnstoHMTryAndFixIt(pHistDriver self, int iCode) + { + if (hm_proxy != NULL) + { + try + { + hm_proxy->command_inout("Reset"); + } + catch (Tango::DevFailed &exception) + { +/* + SCWrite(pCon,"ERROR: Histogram Reset failed",eError); + SCWrite(pCon,"Tango error :",eError); + SCWrite(pCon,exception.errors[0].desc,eError); +*/ + return 0; + } + } + return 1; + } +/*--------------------------------------------------------------------------*/ + static int AnstoHMGetData(pHistDriver self, SConnection *pCon) + { + try + { + Tango::DeviceAttribute attr_read = hm_proxy->read_attribute("data"); + +// return data in global hm_data variable + + attr_read >> hm_data; + } + catch(Tango::DevFailed &exception) + { + SCWrite(pCon,"ERROR: Histogram GetData failed",eError); + SCWrite(pCon,"Tango error :",eError); + SCWrite(pCon,exception.errors[0].desc,eError); + return 0; + } + return 1; + } +/*--------------------------------------------------------------------------*/ + static int AnstoHMGetHistogram(pHistDriver self, SConnection *pCon, + int i, int iStart, int iEnd, HistInt *lData) + { + int ii; + + if(i < 0) + { + SCWrite(pCon,"ERROR: histogram out of range",eError); + return 0; + } +#ifdef TESTVAL + for(ii = iStart; ii < iEnd; ii++) + { + lData[ii] = TESTVAL; + } +#else + AnstoHMGetData(self, pCon); + for(ii = iStart; ii < iEnd; ii++) + { + if (ii < hm_data.size()) lData[ii-iStart] = hm_data[ii]; + } +#endif + return 1; + } +/*------------------------------------------------------------------------*/ + static int AnstoHMSetHistogram(pHistDriver self, SConnection *pCon, + int i, int iStart, int iEnd, HistInt *lData) + { + iSet = 1; + iSetVal = lData[0]; + return 1; + } + +/*-------------------------------------------------------------------------*/ + static int AnstoHMPreset(pHistDriver self, SConnection *pCon, HistInt iVal) + { + iSet = 1; + iSetVal = iVal; + + return 1; + } +/*------------------------------------------------------------------------*/ + static int AnstoHMFreePrivate(pHistDriver self) + { + return 1; + } +/*------------------------------------------------------------------------*/ + static long AnstoHMGetMonitor(pHistDriver self, int i, SConnection *pCon) + { + long hm_monitor; + try + { + Tango::DeviceAttribute attr_read = hm_proxy->read_attribute("monitor"); + +// return data in global hm_data variable + + attr_read >> hm_monitor; + } + catch(Tango::DevFailed &exception) + { + SCWrite(pCon,"ERROR: Histogram GetData failed",eError); + SCWrite(pCon,"Tango error :",eError); + SCWrite(pCon,exception.errors[0].desc,eError); + return 0; + } + return hm_monitor; + } +/*------------------------------------------------------------------------*/ + static float AnstoHMGetTime(pHistDriver self, SConnection *pCon) + { + double hm_time; + try + { + Tango::DeviceAttribute attr_read = hm_proxy->read_attribute("time"); + +// return data in global hm_data variable + + attr_read >> hm_time; + } + catch(Tango::DevFailed &exception) + { + SCWrite(pCon,"ERROR: Histogram GetData failed",eError); + SCWrite(pCon,"Tango error :",eError); + SCWrite(pCon,exception.errors[0].desc,eError); + return 0; + } + return (float)hm_time; + + } +/*-------------------------------------------------------------------------*/ +pHistDriver CreateAnstoHM(pStringDict pOpt) +{ + pHistDriver pNew = NULL; + + /* create the general driver */ + pNew = CreateHistDriver(pOpt); + if(!pNew) + { + return NULL; + } + + /* not using private data currently */ + pNew->pPriv = NULL; + + /* configure all those functions */ + pNew->Configure = AnstoHMConfig; + pNew->Start = AnstoHMStart; + pNew->Halt = AnstoHMHalt; + pNew->GetCountStatus = AnstoHMGetCountStatus; + pNew->GetError = AnstoHMGetError; + pNew->TryAndFixIt = AnstoHMTryAndFixIt; + pNew->GetData = AnstoHMGetData; + pNew->GetHistogram = AnstoHMGetHistogram; + pNew->SetHistogram = AnstoHMSetHistogram; + pNew->GetMonitor = AnstoHMGetMonitor; + pNew->GetTime = AnstoHMGetTime; + pNew->Preset = AnstoHMPreset; + pNew->FreePrivate = AnstoHMFreePrivate; + pNew->Pause = AnstoHMPause; + pNew->Continue = AnstoHMContinue; + pNew->fCountPreset = 1; + StringDictAddPair(pOpt,"device",hm_device); + + try + { + hm_proxy = new Tango::DeviceProxy(hm_device); + } + catch(Tango::DevFailed &exception) + { + printf("ERROR: New Tango DeviceProxy failed\n"); +/* + SCWrite(pCon,"ERROR: New Tango DeviceProxy failed",eError); + SCWrite(pCon,"Tango error :",eError); + SCWrite(pCon,exception.errors[0].desc,eError); + */ + return 0; + } + hm_data.resize(10); + + return pNew; + } + diff --git a/site_ansto/anstohm.h b/site_ansto/anstohm.h new file mode 100644 index 00000000..c2bd546e --- /dev/null +++ b/site_ansto/anstohm.h @@ -0,0 +1,28 @@ + +#line 15 "histsim.w" + +/*-------------------------------------------------------------------------- + A N S T O H M + + The ANSTO histogramming memory driver include file + + Andy Gotz, February 2004 + + copyright: see implementation file. +---------------------------------------------------------------------------*/ +#ifndef SICSANSTOHM +#define SICSANSTOHM + +#line 5 "histsim.w" + +#ifdef __cplusplus +extern "C" { +#endif +pHistDriver CreateAnstoHM(pStringDict pOpt); +#ifdef __cplusplus +} +#endif + +#line 27 "histsim.w" + +#endif diff --git a/site_ansto/hm_asim.cpp b/site_ansto/hm_asim.cpp new file mode 100644 index 00000000..e74ff355 --- /dev/null +++ b/site_ansto/hm_asim.cpp @@ -0,0 +1,1038 @@ +/*---------------------------------------------------------------------------- + + H M _ A S I M + + A simulation histogramming memory driver for the ANSTO histogrammer. + It has to be compiled with the C++ compiler and the SICServer has to + be linked with C++. + + Paul Hathaway, September 2004 + + Copyright: see Copyright.txt +----------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +extern "C" { +#include "fortify.h" +#include "sics.h" +#include "countdriv.h" +#include "counter.h" +#include "stringdict.h" +#include "HistMem.h" +#include "HistDriv.i" +#include "hm_asim.h" +} +#include +#define TESTVAL 128 +/* + define TESTVAL to set the simulated histogram to a fixed value for + testing +*/ +#define HM_ASIM_IDLE 0 +#define HM_ASIM_BUSY 1 +#define HM_ASIM_PAUSE 2 +#define HM_ASIM_FAULT 3 + +#define HM_MODE_TIME 0 +#define HM_MODE_COUNT 1 + +/*-------------------------------------------------------------------------*/ +class AsimDetector +{ +public: + int iSet; + HistInt iSetVal; + + AsimDetector(char *deviceName) + { + if(0 hm_data; + HistMode eHistMode; + + vector hm_patch; + vector hm_ctr; + vector hm_tgt; + static const long zero = 0; + int iChannels; + int iCounters; + int iVetoCtr; + int iMonCtr; + long hm_monitor; + int hm_state; + int iCountMode; + long lPreset; + long lVetoThreshold; + long iDuration; + long iLastPollTime; + long iRunningTime; + float fFlux; +}; +/*---------------------------------------------------------------------------*/ +float AsimDetector::SimRandom(void) + { + float fVal; + fVal = ( (float) rand() / (float)RAND_MAX ) * 100.0; + return fVal; + } + +/*---------------------------------------------------------------------------*/ +int AsimDetector::UpdateRunningTime() +{ + time_t tD; + + time(&tD); /* This fn valid between Jan 1970 and Jan 2038 */ + if (HM_ASIM_BUSY == hm_state) + { + iRunningTime += ((long)tD - iLastPollTime); + } + iLastPollTime = (long)tD; + return 1; +} + +/*----------------------------------------------------------------------------*/ +int AsimDetector::UpdateCounters() +{ + float fraction; + switch (hm_state) + { + case HM_ASIM_BUSY: + UpdateRunningTime(); + fraction = (float)iRunningTime / (float)iDuration; + FillCounters(fraction); +// if (iRunningTime >= iDuration) +// { +// iRunningTime = iDuration; +// FillCounters(1.0); +// } +// else /* Counting. Calculate intermediate counts */ +// { +// fraction = (float)iRunningTime / (float)iDuration; +// FillCounters(fraction); +// } + + if(1==IsCountComplete()) + { + hm_state = HM_ASIM_IDLE; + } + break; + case HM_ASIM_PAUSE: + UpdateRunningTime(); + break; + case HM_ASIM_IDLE: + case HM_ASIM_FAULT: + default: break; + } + return 1; +} + +/*---------------------------------------------------------------------------*/ +int AsimDetector::IsCountComplete() +{ + switch(iCountMode) + { + case HM_MODE_TIME: + if (iRunningTime >= iDuration) return 1; else return 0; + break; + case HM_MODE_COUNT: + if (hm_monitor >= lPreset) return 1; else return 0; + break; + default: + hm_state = HM_ASIM_FAULT; return 0; + } +} + +/*--------------------------------------------------------------------------*/ +int AsimDetector::SetCounters(int numCounters) +{ + // todo: test validity of numCounters + hm_tgt.resize(numCounters); + hm_ctr.resize(numCounters); + for(int i=iCounters; iiChannels)||(destChn<0)) + { + return 0; + } + hm_patch[destChn] = srcCtr; + return 1; +} + +/*--------------------------------------------------------------------------*/ +void AsimDetector::PatchHistogram() +{ + for(int i=0;iiDuration) iDuration = 1; + for(int i=0; i(iCounters-1))||(iCtr<0)) + { + iMonCtr = 0; + return 0; + } + else + { + iMonCtr = iCtr; + return 1; + } +} + +/*-------------------------------------------------------------------------*/ +int AsimDetector::GetMonitor(HistInt *lData) +{ + hm_monitor = hm_ctr[iMonCtr]; + (*lData) = (HistInt) hm_monitor; + return 1; +} + +/*-------------------------------------------------------------------------*/ +int AsimDetector::SetVetoInput(int iCtr) +{ + if((iCtr>iChannels)||(iCtr<-1)) + { + iVetoCtr = -1; + return 0; + } + iVetoCtr = iCtr; + return 1; +} + +/*-------------------------------------------------------------------------*/ +int AsimDetector::SetVetoThreshold(HistInt lLevel) +{ + lVetoThreshold = (long) lLevel; + return 1; +} + +/*-------------------------------------------------------------------------*/ +int AsimDetector::GetVetoThreshold(HistInt *lLevel) +{ + *lLevel = (HistInt) lVetoThreshold; + return 1; +} + +/*-------------------------------------------------------------------------*/ +int AsimDetector::GetVeto(HistInt *lVeto) +{ + if(0pPriv); + + // Configure TOF Mode + if(pAsim->GetHistMode() == eHTOF) + { + for(i = 0; i < self->data->rank; i++) + { + iLength *= self->data->iDim[i]; + } + iLength *= self->data->nTimeChan; + } + + // Configure Counters + { + int numCtrs = 0; + float fVal; + int iRet = StringDictGetAsNumber(pOption,"counters",&fVal); + if(0SetCounters(numCtrs); + numCtrs = pAsim->GetCounters(); + sprintf(pBuffer,"STATUS:HM_ASIM: Register %d counters",numCtrs); + SCWrite(pCon,pBuffer,eStatus); + snprintf(pBuffer,10,"%-d",numCtrs); + if(0==StringDictUpdate(pOption,"counters",pBuffer)) + { + StringDictAddPair(pOption,"counters",pBuffer); + } + } + + // Configure Channels + { + int numChan = 0; + float fVal; + int iRet = StringDictGetAsNumber(pOption,"channels",&fVal); + if(0SetChannels(numChan); + numChan = pAsim->GetChannels(); + sprintf(pBuffer,"STATUS:HM_ASIM: Register %d channels",numChan); + SCWrite(pCon,pBuffer,eStatus); + snprintf(pBuffer,10,"%-d",numChan); + if(0==StringDictUpdate(pOption,"channels",pBuffer)) + { + StringDictAddPair(pOption,"channels",pBuffer); + } + } + + // Configure Count Mode + if (self->eCount == ePreset) + { + pAsim->SetCountMode(HM_MODE_COUNT); + } + else + { + pAsim->SetCountMode(HM_MODE_TIME); + } + + // Configure Preset + pAsim->SetPreset((long)(self->fCountPreset)); + + // Configure Channel to Counter patches + int numChn = pAsim->GetChannels(); + for(int ch=0; chSetPatch(ch,iCtr); + sprintf(pBuffer,"STATUS:HM_ASIM: Patch Channel %d to Counter %d",ch,iCtr); + } else { + pAsim->SetPatch(ch,-1); + sprintf(pBuffer,"STATUS:HM_ASIM: Disconnect Channel %d",ch); + } + SCWrite(pCon,pBuffer,eStatus); + } + + // Configure Monitor Input (always set, default 0) + { + int iMonCtr = 0; + float fVal; + int iRet = StringDictGetAsNumber(pOption,"monitor_input",&fVal); + if(0SetMonitorInput(iMonCtr); + sprintf(pBuffer,"STATUS:HM_ASIM: Monitor Input Counter %d",iMonCtr); + SCWrite(pCon,pBuffer,eStatus); + snprintf(pBuffer,10,"%-d",iMonCtr); + if(0==StringDictUpdate(pOption,"monitor_input",pBuffer)) + { + StringDictAddPair(pOption,"monitor_input",pBuffer); + } + } + + // Configure Veto Input (set to valid counter or disconnected(-1)) + { + int iVetoCtr; + float fVal; + int iRet = StringDictGetAsNumber(pOption,"veto_input",&fVal); + if(0SetVetoInput(iVetoCtr); + sprintf(pBuffer,"STATUS:HM_ASIM: Veto Input Counter %d",iVetoCtr); + } + else + { + iVetoCtr = -1; + pAsim->SetVetoInput(iVetoCtr); + sprintf(pBuffer,"STATUS:HM_ASIM: Veto Input Disconnected"); + } + SCWrite(pCon,pBuffer,eStatus); + snprintf(pBuffer,10,"%-d",iVetoCtr); + if(0==StringDictUpdate(pOption,"veto_input",pBuffer)) + { + StringDictAddPair(pOption,"veto_input",pBuffer); + } + } + + // Configure Veto Threshold (default 0) + { + HistInt lThreshold; + float fVal; + int iRet = StringDictGetAsNumber(pOption,"veto_threshold",&fVal); + if(0SetVetoThreshold(lThreshold); + pAsim->GetVetoThreshold(&lThreshold); + sprintf(pBuffer,"STATUS:HM_ASIM: Veto Threshold %d",lThreshold); + SCWrite(pCon,pBuffer,eStatus); + snprintf(pBuffer,10,"%-d",lThreshold); + if(0==StringDictUpdate(pOption,"veto_threshold",pBuffer)) + { + StringDictAddPair(pOption,"veto_threshold",pBuffer); + } + } + + // Configure Flux + { + float fVal; + int iRet = StringDictGetAsNumber(pOption,"flux",&fVal); + if(0SetFlux(fVal); + } + pAsim->GetFlux(&fVal); + sprintf(pBuffer,"STATUS:HM_ASIM: Flux set to %.1f cps",fVal); + SCWrite(pCon,pBuffer,eStatus); + snprintf(pBuffer,16,"%.1f",fVal); + if(0==StringDictUpdate(pOption,"flux",pBuffer)) + { + StringDictAddPair(pOption,"flux",pBuffer); + } + } + pAsim->Reset(); + + if(1==iSuccess) + { + sprintf(pBuffer,"STATUS:HM_ASIM: AsimConfig Successful"); + SCWrite(pCon,pBuffer,eStatus); + return OKOK; + } + else + { + sprintf(pBuffer,"ERROR:HM_ASIM: AsimConfig Failed"); + SCWrite(pCon,pBuffer,eError); + return HWFault; + } +} + +/*-------------------------------------------------------------------------*/ + static int AsimStart(pHistDriver self, SConnection *pCon) + { + AsimDetector *pAsim = NULL; + + pAsim = (AsimDetector *) (self->pPriv); + + // Configure Count Mode + if (self->eCount == ePreset) + pAsim->SetCountMode(HM_MODE_COUNT); + else + pAsim->SetCountMode(HM_MODE_TIME); + + pAsim->SetPreset((long)(self->fCountPreset)); + + if(1==pAsim->Start()) + { + SCWrite(pCon,"STATUS:HM_ASIM: Histogram Start Count",eStatus); + return OKOK; + } + else + { + SCWrite(pCon,"ERROR:HM_ASIM: Histogram Start Count Failed",eError); + return HWFault; + } + } +/*-------------------------------------------------------------------------*/ + static int AsimPause(pHistDriver self, SConnection *pCon) + { + AsimDetector *pAsim = NULL; + + pAsim = (AsimDetector *) (self->pPriv); + if(1==pAsim->Pause()) + { + SCWrite(pCon,"STATUS:HM_ASIM: Histogram Pause Count",eStatus); + return OKOK; + } + else + { + SCWrite(pCon,"ERROR:HM_ASIM: Histogram Pause Count Failed",eError); + return HWFault; + } + } +/*------------------------------------------------------------------------*/ +static int AsimContinue(pHistDriver self, SConnection *pCon) +{ + AsimDetector *pAsim = NULL; + int iState; + + pAsim = (AsimDetector *) (self->pPriv); + if(1==pAsim->Continue()) + { + SCWrite(pCon,"STATUS:HM_ASIM: Histogram Continue Count",eStatus); + return OKOK; + } + else + { + SCWrite(pCon,"ERROR:HM_ASIM: Histogram Continue Count Failed",eError); + return HWFault; + } +} +/*-------------------------------------------------------------------------*/ + static int AsimHalt(pHistDriver self) +{ + AsimDetector *pAsim = NULL; + pAsim = (AsimDetector *) (self->pPriv); + if(1==pAsim->Halt()) return OKOK; else return HWFault; +} + +/*-------------------------------------------------------------------------*/ + static int AsimGetCountStatus(pHistDriver self, SConnection *pCon) + { + int status; + int retCode; + char error[80]; + AsimDetector *pAsim = NULL; + + pAsim = (AsimDetector *) (self->pPriv); + pAsim->GetCountStatus(&status); + switch (status) + { + case HM_ASIM_IDLE: retCode = OKOK; break; + case HM_ASIM_BUSY: retCode = HWBusy; break; + case HM_ASIM_PAUSE: retCode = HWPause; break; + case HM_ASIM_FAULT: + default: retCode = HWFault; break; + } + return retCode; + } + +/*-------------------------------------------------------------------------*/ + static int AsimGetError(pHistDriver self, int *iCode, char *pError, int iLen) + { + AsimDetector *pAsim = NULL; + pAsim = (AsimDetector *) (self->pPriv); + *iCode = 0; + strncpy(pError,"ERROR:HM_ASIM: 0", iLen); + return OKOK; // QUESTION: Return 0 or OKOK; ? + } +/*-------------------------------------------------------------------------*/ +static int AsimTryAndFixIt(pHistDriver self, int iCode) +{ + int status; + AsimDetector *pAsim = NULL; + pAsim = (AsimDetector *) (self->pPriv); + pAsim->GetCountStatus(&status); + return AsimHalt(self); +} +/*--------------------------------------------------------------------------*/ +static int AsimGetData(pHistDriver self, SConnection *pCon) +{ + char error[80]; + AsimDetector *pAsim = NULL; + + pAsim = (AsimDetector *) (self->pPriv); + if (NULL!=pAsim) + { + if(0==pAsim->GetData()) + { + SCWrite(pCon,"ERROR:HM_ASIM: Histogram GetData failed",eError); + return HWFault; + } + return OKOK; + } + return HWFault; +} +/*--------------------------------------------------------------------------*/ +static int AsimGetHistogram(pHistDriver self, SConnection *pCon, + int i, int iStart, int iEnd, HistInt *lData) +{ + AsimDetector *pAsim = NULL; + + pAsim = (AsimDetector *) (self->pPriv); + + switch(AsimGetData(self,pCon)) + { + case OKOK: + if(1==pAsim->GetHistogram(iStart,iEnd,lData)) + { + return OKOK; + } + else return HWFault; + default: + return HWFault; + } + return HWFault; +} +/*------------------------------------------------------------------------*/ +static int AsimSetHistogram(pHistDriver self, SConnection *pCon, + int i, int iStart, int iEnd, HistInt *lData) +{ + AsimDetector *pAsim = NULL; + + pAsim = (AsimDetector *) (self->pPriv); + + pAsim->iSet = 1; + pAsim->iSetVal = lData[0]; + return OKOK; +} +/*-------------------------------------------------------------------------*/ +static int AsimPreset(pHistDriver self, SConnection *pCon, HistInt iVal) +{ + AsimDetector *pAsim = NULL; + + pAsim = (AsimDetector *) (self->pPriv); + pAsim->iSet = 1; + pAsim->iSetVal = iVal; + return OKOK; +} +/*------------------------------------------------------------------------*/ +static int AsimFreePrivate(pHistDriver self) +{ + AsimDetector *pAsim = NULL; + pAsim = (AsimDetector *) (self->pPriv); + delete pAsim; + return OKOK; +} +/*------------------------------------------------------------------------*/ +static long AsimGetMonitor(pHistDriver self, int i, SConnection *pCon) +{ + HistInt value; + AsimDetector *pAsim = NULL; + pAsim = (AsimDetector *) (self->pPriv); + pAsim->GetMonitor(&value); + return value; +} +/*------------------------------------------------------------------------*/ +static float AsimGetTime(pHistDriver self, SConnection *pCon) +{ + float value; + AsimDetector *pAsim = NULL; + pAsim = (AsimDetector *) (self->pPriv); + pAsim->GetRunningTime(&value); + return value; +} + +/*-------------------------------------------------------------------------*/ +pHistDriver CreateHmAsim(pStringDict pOpt) +{ + pHistDriver pNew = NULL; + AsimDetector *pAsim = NULL; + + /* create the general driver */ + pNew = CreateHistDriver(pOpt); + if(!pNew) + { + return NULL; + } + + pAsim = new AsimDetector("simulation"); + if(NULL==pAsim) + { + return NULL; + } + StringDictAddPair(pOpt,"device","hm_asim simulation"); + pAsim->SetCounters(16); + pAsim->SetChannels(10); + + /* if not using private data currently: pNew->pPriv = NULL; */ + pNew->pPriv = pAsim; + + /* configure all those functions */ + pNew->Configure = AsimConfig; + pNew->Start = AsimStart; + pNew->Halt = AsimHalt; + pNew->GetCountStatus = AsimGetCountStatus; + pNew->GetError = AsimGetError; + pNew->TryAndFixIt = AsimTryAndFixIt; + pNew->GetData = AsimGetData; + pNew->GetHistogram = AsimGetHistogram; + pNew->SetHistogram = AsimSetHistogram; + pNew->GetMonitor = AsimGetMonitor; + pNew->GetTime = AsimGetTime; + pNew->Preset = AsimPreset; + pNew->FreePrivate = AsimFreePrivate; + pNew->Pause = AsimPause; + pNew->Continue = AsimContinue; + pNew->fCountPreset = 1; + + return pNew; + } + diff --git a/site_ansto/hm_asim.h b/site_ansto/hm_asim.h new file mode 100644 index 00000000..e5797015 --- /dev/null +++ b/site_ansto/hm_asim.h @@ -0,0 +1,21 @@ +/*-------------------------------------------------------------------------- + H M _ A S I M + + The ANSTO simulated histogramming memory driver include file + + Paul Hathaway, September 2004 + + Copyright: see Copyright.txt +---------------------------------------------------------------------------*/ +#ifndef HM_ASIM +#define HM_ASIM + +#ifdef __cplusplus +extern "C" { +#endif +pHistDriver CreateHmAsim(pStringDict pOpt); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/site_ansto/hm_tango.h b/site_ansto/hm_tango.h new file mode 100644 index 00000000..d877b62a --- /dev/null +++ b/site_ansto/hm_tango.h @@ -0,0 +1,30 @@ + +#line 15 "histsim.w" + +/*-------------------------------------------------------------------------- + H M _ T A N G O + + Header file for the ANSTO histogramming memory driver interfacing + a TANGO server + + Based on anstohm.h (Andy Gotz, February 2004) + Modified: Paul Hathaway, July 2004 + + Copyright: see Copyright.txt +---------------------------------------------------------------------------*/ +#ifndef SICS_HM_TANGO +#define SICS_HM_TANGO + +#line 5 "histsim.w" + +#ifdef __cplusplus +extern "C" { +#endif +pHistDriver CreateHmTango(pStringDict pOpt); +#ifdef __cplusplus +} +#endif + +#line 27 "histsim.w" + +#endif diff --git a/site_ansto/itc4.c b/site_ansto/itc4.c new file mode 100644 index 00000000..ae983c12 --- /dev/null +++ b/site_ansto/itc4.c @@ -0,0 +1,281 @@ +/*--------------------------------------------------------------------------- + I T C 4 + + This is the implementation for a ITC4 object derived from an more general + environment controller. + + Mark Koennecke, August 1997 + + 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 +#include +#include +#include +#include +#include +#include "itc4.h" + +/*---------------------------------------------------------------------------*/ + int ITC4SetPar(pEVControl self, char *name, float fNew, SConnection *pCon) + { + int iRet; + + /* check authorsisation */ + if(!SCMatchRights(pCon,usUser)) + { + SCWrite(pCon,"ERROR: you are not authorised to change this parameter", + eError); + return 0; + } + + /* just catch those three names which we understand */ + if(strcmp(name,"sensor") == 0) + { + iRet = SetSensorITC4(self->pDriv,(int)fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigITC4(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: ITC4 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + else if(strcmp(name,"control") == 0) + { + iRet = SetControlITC4(self->pDriv,(int)fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigITC4(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: ITC4 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + else if(strcmp(name,"timeout") == 0) + { + iRet = SetTMOITC4(self->pDriv,(int)fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigITC4(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: ITC4 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + else if(strcmp(name,"divisor") == 0) + { + iRet = SetDivisorITC4(self->pDriv,fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigITC4(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: ITC4 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + else if(strcmp(name,"multiplicator") == 0) + { + iRet = SetMultITC4(self->pDriv,fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigITC4(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: ITC4 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + else + return EVCSetPar(self,name,fNew,pCon); + } +/*--------------------------------------------------------------------------*/ + int ITC4GetPar(pEVControl self, char *name, float *fNew) + { + int iRet; + float fDiv; + + /* just catch those two names which we understand */ + if(strcmp(name,"sensor") == 0) + { + iRet = GetSensorITC4(self->pDriv); + *fNew = (float)iRet; + return 1; + } + else if(strcmp(name,"control") == 0) + { + iRet = GetControlITC4(self->pDriv); + *fNew = (float)iRet; + return 1; + } + else if(strcmp(name,"timeout") == 0) + { + iRet = GetTMOITC4(self->pDriv); + *fNew = (float)iRet; + return 1; + } + else if(strcmp(name,"divisor") == 0) + { + fDiv = GetDivisorITC4(self->pDriv); + *fNew = fDiv; + return 1; + } + else if(strcmp(name,"multiplicator") == 0) + { + fDiv = GetMultITC4(self->pDriv); + *fNew = fDiv; + return 1; + } + else + return EVCGetPar(self,name,fNew); + } +/*---------------------------------------------------------------------------*/ + int ITCList(pEVControl self, SConnection *pCon) + { + char pBueffel[132]; + int iRet; + + iRet = EVCList(self,pCon); + sprintf(pBueffel,"%s.sensor = %d\n",self->pName, + GetSensorITC4(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + sprintf(pBueffel,"%s.control = %d\n",self->pName, + GetControlITC4(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + sprintf(pBueffel,"%s.timeout = %d\n",self->pName, + GetTMOITC4(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + sprintf(pBueffel,"%s.divisor = %f\n",self->pName, + GetDivisorITC4(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + sprintf(pBueffel,"%s.multiplicator = %f\n",self->pName, + GetMultITC4(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + return iRet; + } +/*-------------------------------------------------------------------------*/ + int ITC4Wrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) + { + pEVControl self = NULL; + char pBueffel[256]; + int iRet; + double fNum; + float fVal; + + self = (pEVControl)pData; + assert(self); + assert(pCon); + assert(pSics); + + if(argc < 2) + { + return EVControlWrapper(pCon,pSics,pData,argc,argv); + } + + strtolower(argv[1]); + if((strcmp(argv[1],"sensor") == 0) || (strcmp(argv[1],"control") == 0) || + (strcmp(argv[1],"timeout") == 0) || (strcmp(argv[1],"divisor") == 0) || + (strcmp(argv[1],"multiplicator") == 0) ) + { + if(argc > 2) /* set case */ + { + iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&fNum); + if(iRet != TCL_OK) + { + sprintf(pBueffel,"ERROR: expected number, got %s",argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + return ITC4SetPar(self,argv[1],(float)fNum,pCon); + } + else /* get case */ + { + iRet = ITC4GetPar(self,argv[1],&fVal); + sprintf(pBueffel,"%s.%s = %f\n",self->pName, + argv[1],fVal); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } + else if(strcmp(argv[1],"list") == 0) + { + return ITCList(self,pCon); + } + else + { + return EVControlWrapper(pCon,pSics,pData,argc,argv); + } + /* not reached */ + return 0; + } diff --git a/site_ansto/itc4.h b/site_ansto/itc4.h new file mode 100644 index 00000000..1068ef3d --- /dev/null +++ b/site_ansto/itc4.h @@ -0,0 +1,43 @@ + +/*------------------------------------------------------------------------- + ITC 4 + + Support for Oxford Instruments ITC4 Temperature controllers for SICS. + The meaning and working of the functions defined is as desribed for a + general environment controller. + + Mark Koennecke, Juli 1997 + + copyright: see implementation file. + +-----------------------------------------------------------------------------*/ +#ifndef SICSITC4 +#define SICSITC4 +/*------------------------- The Driver ------------------------------------*/ + + pEVDriver CreateITC4Driver(int argc, char *argv[]); + int ConfigITC4(pEVDriver self); + int SetSensorITC4(pEVDriver self, int iSensor); + int SetControlITC4(pEVDriver self, int iSensor); + int GetSensorITC4(pEVDriver self); + int GetControlITC4(pEVDriver self); + int SetDivisorITC4(pEVDriver self, float iSensor); + float GetDivisorITC4(pEVDriver self); + int SetMultITC4(pEVDriver self, float iSensor); + float GetMultITC4(pEVDriver self); + int SetTMOITC4(pEVDriver self, int iSensor); + int GetTMOITC4(pEVDriver self); + + +/*------------------------- The ITC4 object ------------------------------*/ + + int ITC4Wrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + int ITC4SetPar(pEVControl self, char *name, float fNew, + SConnection *pCon); + int ITC4GetPar(pEVControl self, char *name, float *fVal); + int ITCList(pEVControl self, SConnection *pCon); + + +#endif + diff --git a/site_ansto/itc4.w b/site_ansto/itc4.w new file mode 100644 index 00000000..98d83f9e --- /dev/null +++ b/site_ansto/itc4.w @@ -0,0 +1,74 @@ +\subsubsection{Oxford Instruments ITC4 Temperature Controllers} +SINQ makes heavy use of Oxford Instruments ITC4 temperature controllers. In +order to support them the following software components had to be defined in +addition to the basic environmet controller interfaces: +\begin{itemize} +\item ITC4driver, naturally. +\item A ITC4-controller object as derivation of environment controller. ITC4 +'s allow you to select a sensor which you read as your standard sensor and a +sensor which is used for automatic control. The ITC4 controller object adds +just that additional functionality to the statndard environment controller. +\end{itemize} +The additional data, the selection of sensors, will be kept in the driver. +This serves also an example for implementing inheritance without C++. + +The driver interface: +@d itcd @{ + pEVDriver CreateITC4Driver(int argc, char *argv[]); + int ConfigITC4(pEVDriver self); + int SetSensorITC4(pEVDriver self, int iSensor); + int SetControlITC4(pEVDriver self, int iSensor); + int GetSensorITC4(pEVDriver self); + int GetControlITC4(pEVDriver self); + int SetDivisorITC4(pEVDriver self, float iSensor); + float GetDivisorITC4(pEVDriver self); + int SetMultITC4(pEVDriver self, float iSensor); + float GetMultITC4(pEVDriver self); + int SetTMOITC4(pEVDriver self, int iSensor); + int GetTMOITC4(pEVDriver self); + +@} + +The ConfigITC4 is special. It has to be called to commit changes to the +driver read and control parameters. + +The ITC4 object interface: +@d itco @{ + int ITC4Wrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + int ITC4SetPar(pEVControl self, char *name, float fNew, + SConnection *pCon); + int ITC4GetPar(pEVControl self, char *name, float *fVal); + int ITCList(pEVControl self, SConnection *pCon); +@} + +The functions defined are: new parameter handling functions, with just +support for the two extra parameters added and a new Wrapper function for +SICS. The meaning of all these functions, their parameters and return values +are identical to those defined for an environment controller. Additionally, +the standard environment controller functions will work as described. The +functions described above are just needed to implement the extra parameters. + +@o itc4.h @{ +/*------------------------------------------------------------------------- + ITC 4 + + Support for Oxford Instruments ITC4 Temperature controllers for SICS. + The meaning and working of the functions defined is as desribed for a + general environment controller. + + Mark Koennecke, Juli 1997 + + copyright: see implementation file. + +-----------------------------------------------------------------------------*/ +#ifndef SICSITC4 +#define SICSITC4 +/*------------------------- The Driver ------------------------------------*/ +@ +/*------------------------- The ITC4 object ------------------------------*/ +@ + +#endif + +@} diff --git a/site_ansto/itc4driv.c b/site_ansto/itc4driv.c new file mode 100644 index 00000000..90e1d9ad --- /dev/null +++ b/site_ansto/itc4driv.c @@ -0,0 +1,478 @@ +/*-------------------------------------------------------------------------- + I T C 4 D R I V + + This file contains the implementation of a driver for the Oxford + Instruments ITC4 Temperature controller. + + + Mark Koennecke, Juli 1997 + + 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 "hardsup/itc4util.h" +#include "hardsup/el734_def.h" +#include "hardsup/el734fix.h" + +#define SHITTYVALUE -777 +/*------------------------- The Driver ------------------------------------*/ + + pEVDriver CreateITC4Driver(int argc, char *argv[]); + int ConfigITC4(pEVDriver self); + + +/*-----------------------------------------------------------------------*/ + typedef struct { + pITC4 pData; + char *pHost; + int iPort; + int iChannel; + int iControl; /* itc control */ + float fDiv; + float fMult; + int iRead; /* itc sensor */ + int iTmo; + int iLastError; + } ITC4Driv, *pITC4Driv; +/*----------------------------------------------------------------------------*/ + static int GetITC4Pos(pEVDriver self, float *fPos) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv)self->pPrivate; + assert(pMe); + + iRet = ITC4_Read(&pMe->pData,fPos); + if(iRet != 1 ) + { + pMe->iLastError = iRet; + return 0; + } + if( (*fPos < 0) || (*fPos > 10000) ) + { + *fPos = -999.; + pMe->iLastError = SHITTYVALUE; + return 0; + } + return 1; + } +/*----------------------------------------------------------------------------*/ + static int ITC4Run(pEVDriver self, float fVal) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + iRet = ITC4_Set(&pMe->pData,fVal); + if(iRet != 1) + { + pMe->iLastError = iRet; + return 0; + } + return 1; + } +/*--------------------------------------------------------------------------*/ + static int ITC4Error(pEVDriver self, int *iCode, char *error, int iErrLen) + { + pITC4Driv pMe = NULL; + + assert(self); + pMe = (pITC4Driv)self->pPrivate; + assert(pMe); + + *iCode = pMe->iLastError; + if(pMe->iLastError == SHITTYVALUE) + { + strncpy(error,"Invalid temperature returned form ITC4, check sensor",iErrLen); + } + else + { + ITC4_ErrorTxt(&pMe->pData,pMe->iLastError,error,iErrLen); + } + return 1; + } +/*--------------------------------------------------------------------------*/ + static int ITC4Send(pEVDriver self, char *pCommand, char *pReply, int iLen) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + iRet = ITC4_Send(&pMe->pData,pCommand, pReply,iLen); + if(iRet != 1) + { + pMe->iLastError = iRet; + return 0; + } + return 1; + + } +/*--------------------------------------------------------------------------*/ + static int ITC4Init(pEVDriver self) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + pMe->pData = NULL; + iRet = ITC4_Open(&pMe->pData, pMe->pHost, pMe->iRead, pMe->iControl,0); + if(iRet != 1) + { + if(iRet == ITC4__NOITC) + { + return -1; + } + else + { + pMe->iLastError = iRet; + return 0; + } + } + return 1; + } +/*--------------------------------------------------------------------------*/ + static int ITC4Close(pEVDriver self) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + ITC4_Close(&pMe->pData); + return 1; + } +/*---------------------------------------------------------------------------*/ + static int ITC4Fix(pEVDriver self, int iError) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )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: + ITC4Close(self); + iRet = ITC4Init(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; + } + +/*--------------------------------------------------------------------------*/ + static int ITC4Halt(pEVDriver *self) + { + assert(self); + + return 1; + } +/*------------------------------------------------------------------------*/ + void KillITC4(void *pData) + { + pITC4Driv pMe = NULL; + + pMe = (pITC4Driv)pData; + assert(pMe); + + if(pMe->pHost) + { + free(pMe->pHost); + } + free(pMe); + } +/*------------------------------------------------------------------------*/ + pEVDriver CreateITC4Driver(int argc, char *argv[]) + { + pEVDriver pNew = NULL; + pITC4Driv pSim = NULL; + + /* check for arguments */ + if(argc < 3) + { + return NULL; + } + + pNew = CreateEVDriver(argc,argv); + pSim = (pITC4Driv)malloc(sizeof(ITC4Driv)); + memset(pSim,0,sizeof(ITC4Driv)); + if(!pNew || !pSim) + { + return NULL; + } + pNew->pPrivate = pSim; + pNew->KillPrivate = KillITC4; + + /* initalise pITC4Driver */ + pSim->iControl = atoi(argv[2]); + pSim->iRead = atoi(argv[1]); + pSim->iLastError = 0; + pSim->iTmo = 10; + pSim->fDiv = 10.; + pSim->fMult = 10; + pSim->pHost = strdup(argv[0]); + pSim->iPort = 0; + pSim->iChannel = 0; + + + /* initialise function pointers */ + pNew->SetValue = ITC4Run; + pNew->GetValue = GetITC4Pos; + pNew->Send = ITC4Send; + pNew->GetError = ITC4Error; + pNew->TryFixIt = ITC4Fix; + pNew->Init = ITC4Init; + pNew->Close = ITC4Close; + + return pNew; + } +/*--------------------------------------------------------------------------*/ + int ConfigITC4(pEVDriver self) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + iRet = ITC4_Config(&pMe->pData, pMe->iTmo, pMe->iRead, + pMe->iControl,pMe->fDiv,pMe->fMult); + if(iRet < 0) + { + pMe->iLastError = iRet; + return 0; + } + return 1; + } +/*-------------------------------------------------------------------------*/ + int SetSensorITC4(pEVDriver self, int iSensor) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + if( (iSensor < 1) || (iSensor > 4) ) + { + return 0; + } + pMe->iRead = iSensor; + pMe->pData->iRead = iSensor; + return 1; + } +/*-------------------------------------------------------------------------*/ + int SetControlITC4(pEVDriver self, int iSensor) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + if( (iSensor < 1) || (iSensor > 4) ) + { + return 0; + } + pMe->iControl = iSensor; + pMe->pData->iControl = iSensor; + return 1; + } +/*-------------------------------------------------------------------------*/ + int SetTMOITC4(pEVDriver self, int iSensor) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + if(iSensor < 10) + { + return 0; + } + pMe->iTmo = iSensor; + return 1; + } +/*-------------------------------------------------------------------------*/ + int GetControlITC4(pEVDriver self) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + return pMe->iControl; + } +/*-------------------------------------------------------------------------*/ + int GetSensorITC4(pEVDriver self) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + return pMe->iRead; + } +/*-------------------------------------------------------------------------*/ + int GetTMOITC4(pEVDriver self) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + return pMe->iTmo; + } +/*-------------------------------------------------------------------------*/ + float GetDivisorITC4(pEVDriver self) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + return pMe->fDiv; + } +/*--------------------------------------------------------------------------*/ + int SetDivisorITC4(pEVDriver self, float fDiv) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + pMe->fDiv = fDiv; + return 1; + } +/*-------------------------------------------------------------------------*/ + float GetMultITC4(pEVDriver self) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + return pMe->fMult; + } +/*--------------------------------------------------------------------------*/ + int SetMultITC4(pEVDriver self, float fDiv) + { + pITC4Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pITC4Driv )self->pPrivate; + assert(pMe); + + pMe->fMult = fDiv; + return 1; + } + diff --git a/site_ansto/lakeshore340.c b/site_ansto/lakeshore340.c new file mode 100644 index 00000000..769d15c9 --- /dev/null +++ b/site_ansto/lakeshore340.c @@ -0,0 +1,284 @@ +/*--------------------------------------------------------------------------- + L A K E S H O R E 3 4 0 + + This is the implementation for a LAKESHORE340 object derived from a more general + environment controller. + + Mark Koennecke, August 1997 + Mark Lesha, January 2006 (based on ITC4 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 +#include +#include +#include +#include +#include +#include "lakeshore340.h" + +/*---------------------------------------------------------------------------*/ + int LAKESHORE340SetPar(pEVControl self, char *name, float fNew, SConnection *pCon) + { + int iRet; + + /* check authorisation */ + if(!SCMatchRights(pCon,usUser)) + { + SCWrite(pCon,"ERROR: you are not authorised to change this parameter", + eError); + return 0; + } + + /* just catch those three names which we understand */ + if(strcmp(name,"sensor") == 0) + { + iRet = SetSensorLAKESHORE340(self->pDriv,(int)fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigLAKESHORE340(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: LAKESHORE340 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + else if(strcmp(name,"control") == 0) + { + iRet = SetControlLAKESHORE340(self->pDriv,(int)fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigLAKESHORE340(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: LAKESHORE340 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + else if(strcmp(name,"timeout") == 0) + { + iRet = SetTMOLAKESHORE340(self->pDriv,(int)fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigLAKESHORE340(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: LAKESHORE340 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + /* Note divisors and multipliers will not be used with the LAKESHORE340 + but leave in for back compatibility */ + else if(strcmp(name,"divisor") == 0) + { + iRet = SetDivisorLAKESHORE340(self->pDriv,fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigLAKESHORE340(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: LAKESHORE340 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + else if(strcmp(name,"multiplicator") == 0) + { + iRet = SetMultLAKESHORE340(self->pDriv,fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigLAKESHORE340(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: LAKESHORE340 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + else + return EVCSetPar(self,name,fNew,pCon); + } +/*--------------------------------------------------------------------------*/ + int LAKESHORE340GetPar(pEVControl self, char *name, float *fNew) + { + int iRet; + float fDiv; + + /* just catch those two names which we understand */ + if(strcmp(name,"sensor") == 0) + { + iRet = GetSensorLAKESHORE340(self->pDriv); + *fNew = (float)iRet; + return 1; + } + else if(strcmp(name,"control") == 0) + { + iRet = GetControlLAKESHORE340(self->pDriv); + *fNew = (float)iRet; + return 1; + } + else if(strcmp(name,"timeout") == 0) + { + iRet = GetTMOLAKESHORE340(self->pDriv); + *fNew = (float)iRet; + return 1; + } + else if(strcmp(name,"divisor") == 0) + { + fDiv = GetDivisorLAKESHORE340(self->pDriv); + *fNew = fDiv; + return 1; + } + else if(strcmp(name,"multiplicator") == 0) + { + fDiv = GetMultLAKESHORE340(self->pDriv); + *fNew = fDiv; + return 1; + } + else + return EVCGetPar(self,name,fNew); + } +/*---------------------------------------------------------------------------*/ + int LAKESHORE340List(pEVControl self, SConnection *pCon) + { + char pBueffel[132]; + int iRet; + + iRet = EVCList(self,pCon); + sprintf(pBueffel,"%s.sensor = %d\n",self->pName, + GetSensorLAKESHORE340(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + sprintf(pBueffel,"%s.control = %d\n",self->pName, + GetControlLAKESHORE340(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + sprintf(pBueffel,"%s.timeout = %d\n",self->pName, + GetTMOLAKESHORE340(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + sprintf(pBueffel,"%s.divisor = %f\n",self->pName, + GetDivisorLAKESHORE340(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + sprintf(pBueffel,"%s.multiplicator = %f\n",self->pName, + GetMultLAKESHORE340(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + return iRet; + } +/*-------------------------------------------------------------------------*/ + int LAKESHORE340Wrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) + { + pEVControl self = NULL; + char pBueffel[256]; + int iRet; + double fNum; + float fVal; + + self = (pEVControl)pData; + assert(self); + assert(pCon); + assert(pSics); + + if(argc < 2) + { + return EVControlWrapper(pCon,pSics,pData,argc,argv); + } + + strtolower(argv[1]); + if((strcmp(argv[1],"sensor") == 0) || (strcmp(argv[1],"control") == 0) || + (strcmp(argv[1],"timeout") == 0) || (strcmp(argv[1],"divisor") == 0) || + (strcmp(argv[1],"multiplicator") == 0) ) + { + if(argc > 2) /* set case */ + { + iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&fNum); + if(iRet != TCL_OK) + { + sprintf(pBueffel,"ERROR: expected number, got %s",argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + return LAKESHORE340SetPar(self,argv[1],(float)fNum,pCon); + } + else /* get case */ + { + iRet = LAKESHORE340GetPar(self,argv[1],&fVal); + sprintf(pBueffel,"%s.%s = %f\n",self->pName, + argv[1],fVal); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } + else if(strcmp(argv[1],"list") == 0) + { + return LAKESHORE340List(self,pCon); + } + else + { + return EVControlWrapper(pCon,pSics,pData,argc,argv); + } + /* not reached */ + return 0; + } diff --git a/site_ansto/lakeshore340.h b/site_ansto/lakeshore340.h new file mode 100644 index 00000000..de11c68b --- /dev/null +++ b/site_ansto/lakeshore340.h @@ -0,0 +1,49 @@ + +/*------------------------------------------------------------------------- + LAKESHORE 340 + + Support for Lakeshore 340 Temperature controllers for SICS. + The meaning and working of the functions defined is as desribed for a + general environment controller. + + Mark Koennecke, Juli 1997 + Mark Lesha, January 2006 (based on ITC4 code) + + copyright: see implementation file. + +-----------------------------------------------------------------------------*/ +#ifndef SICSLAKESHORE340 +#define SICSLAKESHORE340 +/*------------------------- The Driver ------------------------------------*/ + + pEVDriver CreateLAKESHORE340Driver(int argc, char *argv[]); + int ConfigLAKESHORE340(pEVDriver self); + int SetSensorLAKESHORE340(pEVDriver self, int iSensor); + int SetControlLAKESHORE340(pEVDriver self, int iSensor); + int GetSensorLAKESHORE340(pEVDriver self); + int GetControlLAKESHORE340(pEVDriver self); + /* Divisors and multipliers should not be applicable to the LAKESHORE340 + since it uses floating point variables, but we leave the functions + in here anyway for the time being (setting will have no effect and + a value of 1.0 will always be returned. */ + int SetDivisorLAKESHORE340(pEVDriver self, float iSensor); + float GetDivisorLAKESHORE340(pEVDriver self); + int SetMultLAKESHORE340(pEVDriver self, float iSensor); + float GetMultLAKESHORE340(pEVDriver self); + /* Leave in time-out functionality */ + int SetTMOLAKESHORE340(pEVDriver self, int iSensor); + int GetTMOLAKESHORE340(pEVDriver self); + + +/*------------------------- The LAKESHORE340 object ------------------------------*/ + + int LAKESHORE340Wrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + int LAKESHORE340SetPar(pEVControl self, char *name, float fNew, + SConnection *pCon); + int LAKESHORE340GetPar(pEVControl self, char *name, float *fVal); + int LAKESHORE340List(pEVControl self, SConnection *pCon); + + +#endif + diff --git a/site_ansto/lakeshore340driv.c b/site_ansto/lakeshore340driv.c new file mode 100644 index 00000000..e831aeb7 --- /dev/null +++ b/site_ansto/lakeshore340driv.c @@ -0,0 +1,489 @@ +/*-------------------------------------------------------------------------- + L A K E S H O R E 3 4 0 D R I V + + This file contains the implementation of a driver for the + Lakeshore 340 Temperature controller. + + + Mark Koennecke, Juli 1997 + Mark Lesha, January 2006 (based on ITC4 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 "hardsup/lakeshore340util.h" +#include "hardsup/el734_def.h" +#include "hardsup/el734fix.h" + +#define SHITTYVALUE -777 +/*------------------------- The Driver ------------------------------------*/ + + pEVDriver CreateLAKESHORE340Driver(int argc, char *argv[]); + int ConfigLAKESHORE340(pEVDriver self); + + +/*-----------------------------------------------------------------------*/ + typedef struct { + pLAKESHORE340 pData; + char *pHost; + int iPort; + int iChannel; + int iControl; /* LAKESHORE340 control */ + float fDiv; + float fMult; + int iRead; /* LAKESHORE340 sensor */ + int iTmo; + int iLastError; + } LAKESHORE340Driv, *pLAKESHORE340Driv; +/*----------------------------------------------------------------------------*/ + static int GetLAKESHORE340Pos(pEVDriver self, float *fPos) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv)self->pPrivate; + assert(pMe); + + iRet = LAKESHORE340_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 LAKESHORE340Run(pEVDriver self, float fVal) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + iRet = LAKESHORE340_Set(&pMe->pData,fVal); + if(iRet != 1) + { + pMe->iLastError = iRet; + return 0; + } + return 1; + } +/*--------------------------------------------------------------------------*/ + static int LAKESHORE340Error(pEVDriver self, int *iCode, char *error, int iErrLen) + { + pLAKESHORE340Driv pMe = NULL; + + assert(self); + pMe = (pLAKESHORE340Driv)self->pPrivate; + assert(pMe); + + *iCode = pMe->iLastError; + if(pMe->iLastError == SHITTYVALUE) + { + strncpy(error,"Invalid temperature returned form LAKESHORE340, check sensor",iErrLen); + } + else + { + LAKESHORE340_ErrorTxt(&pMe->pData,pMe->iLastError,error,iErrLen); + } + return 1; + } +/*--------------------------------------------------------------------------*/ + static int LAKESHORE340Send(pEVDriver self, char *pCommand, char *pReply, int iLen) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + iRet = LAKESHORE340_Send(&pMe->pData,pCommand, pReply,iLen); + if(iRet <= 0) + { + pMe->iLastError = iRet; + return 0; + } + return 1; + + } +/*--------------------------------------------------------------------------*/ + static int LAKESHORE340Init(pEVDriver self) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + pMe->pData = NULL; + iRet = LAKESHORE340_Open(&pMe->pData, pMe->pHost, pMe->iRead, pMe->iControl,0); + if(iRet != 1) + { + if(iRet == LAKESHORE340__NOLAKESHORE340) + { + return -1; + } + else + { + pMe->iLastError = iRet; + return 0; + } + } + return 1; + } +/*--------------------------------------------------------------------------*/ + static int LAKESHORE340Close(pEVDriver self) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + LAKESHORE340_Close(&pMe->pData); + return 1; + } +/*---------------------------------------------------------------------------*/ + static int LAKESHORE340Fix(pEVDriver self, int iError) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )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: + LAKESHORE340Close(self); + iRet = LAKESHORE340Init(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; + } + +/*--------------------------------------------------------------------------*/ + static int LAKESHORE340Halt(pEVDriver *self) + { + assert(self); + + return 1; + } +/*------------------------------------------------------------------------*/ + void KillLAKESHORE340(void *pData) + { + pLAKESHORE340Driv pMe = NULL; + + pMe = (pLAKESHORE340Driv)pData; + assert(pMe); + + if(pMe->pHost) + { + free(pMe->pHost); + } + free(pMe); + } +/*------------------------------------------------------------------------*/ + pEVDriver CreateLAKESHORE340Driver(int argc, char *argv[]) + { + pEVDriver pNew = NULL; + pLAKESHORE340Driv pSim = NULL; + + /* check for arguments */ + if(argc < 3) + { + return NULL; + } + + pNew = CreateEVDriver(argc,argv); + pSim = (pLAKESHORE340Driv)malloc(sizeof(LAKESHORE340Driv)); + memset(pSim,0,sizeof(LAKESHORE340Driv)); + if(!pNew || !pSim) + { + return NULL; + } + pNew->pPrivate = pSim; + pNew->KillPrivate = KillLAKESHORE340; + + /* initalise pLAKESHORE340Driver */ + pSim->iControl = atoi(argv[2]); + pSim->iRead = atoi(argv[1]); + pSim->iLastError = 0; + pSim->iTmo = 10; + + /* The LAKESHORE340 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 = LAKESHORE340Run; + pNew->GetValue = GetLAKESHORE340Pos; + pNew->Send = LAKESHORE340Send; + pNew->GetError = LAKESHORE340Error; + pNew->TryFixIt = LAKESHORE340Fix; + pNew->Init = LAKESHORE340Init; + pNew->Close = LAKESHORE340Close; + + return pNew; + } +/*--------------------------------------------------------------------------*/ + int ConfigLAKESHORE340(pEVDriver self) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + iRet = LAKESHORE340_Config(&pMe->pData, pMe->iTmo, pMe->iRead, + pMe->iControl,pMe->fDiv,pMe->fMult); + if(iRet < 0) + { + pMe->iLastError = iRet; + return 0; + } + return 1; + } +/*-------------------------------------------------------------------------*/ + int SetSensorLAKESHORE340(pEVDriver self, int iSensor) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + /* The LAKESHORE340 allows bath temp, external temp and tank temp to be read + so allow iRead=1 to 4 for A,B,C,D respectively. */ + if( (iSensor < 1) || (iSensor > 4) ) + { + return 0; + } + pMe->iRead = iSensor; + pMe->pData->iRead = iSensor; + return 1; + } +/*-------------------------------------------------------------------------*/ + int SetControlLAKESHORE340(pEVDriver self, int iSensor) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + /* For the LAKESHORE340 allow selection of internal or external control + where iControl==1 to 4 for A,B,C,D respectively. */ + if( (iSensor < 1) || (iSensor > 4) ) + { + return 0; + } + pMe->iControl = iSensor; + pMe->pData->iControl = iSensor; + return 1; + } +/*-------------------------------------------------------------------------*/ + int SetTMOLAKESHORE340(pEVDriver self, int iSensor) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + if(iSensor < 10) + { + return 0; + } + pMe->iTmo = iSensor; + return 1; + } +/*-------------------------------------------------------------------------*/ + int GetControlLAKESHORE340(pEVDriver self) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + return pMe->iControl; + } +/*-------------------------------------------------------------------------*/ + int GetSensorLAKESHORE340(pEVDriver self) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + return pMe->iRead; + } +/*-------------------------------------------------------------------------*/ + int GetTMOLAKESHORE340(pEVDriver self) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + return pMe->iTmo; + } +/*-------------------------------------------------------------------------*/ + float GetDivisorLAKESHORE340(pEVDriver self) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + return pMe->fDiv; /* but forced to 1.0 for LAKESHORE340, not used */ + } +/*--------------------------------------------------------------------------*/ + int SetDivisorLAKESHORE340(pEVDriver self, float fDiv) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + /* The LAKESHORE340 doesn't need divisor, force to 1.0 */ + pMe->fDiv = 1.0; /* fDiv */; + return 1; + } +/*-------------------------------------------------------------------------*/ + float GetMultLAKESHORE340(pEVDriver self) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + return pMe->fMult; /* but forced to 1.0 for LAKESHORE340, not used */ + } +/*--------------------------------------------------------------------------*/ + int SetMultLAKESHORE340(pEVDriver self, float fDiv) + { + pLAKESHORE340Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLAKESHORE340Driv )self->pPrivate; + assert(pMe); + + /* The LAKESHORE340 doesn't need multiplier, force to 1.0 */ + pMe->fMult = 1.0; /* fDiv */; + return 1; + } + diff --git a/site_ansto/lh45.c b/site_ansto/lh45.c new file mode 100644 index 00000000..6f127fe0 --- /dev/null +++ b/site_ansto/lh45.c @@ -0,0 +1,284 @@ +/*--------------------------------------------------------------------------- + L H 4 5 + + This is the implementation for a LH45 object derived from an more general + environment controller. + + Mark Koennecke, August 1997 + Mark Lesha, January 2006 (based on ITC4 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 +#include +#include +#include +#include +#include +#include "lh45.h" + +/*---------------------------------------------------------------------------*/ + int LH45SetPar(pEVControl self, char *name, float fNew, SConnection *pCon) + { + int iRet; + + /* check authorsisation */ + if(!SCMatchRights(pCon,usUser)) + { + SCWrite(pCon,"ERROR: you are not authorised to change this parameter", + eError); + return 0; + } + + /* just catch those three names which we understand */ + if(strcmp(name,"sensor") == 0) + { + iRet = SetSensorLH45(self->pDriv,(int)fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigLH45(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: LH45 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + else if(strcmp(name,"control") == 0) + { + iRet = SetControlLH45(self->pDriv,(int)fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigLH45(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: LH45 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + else if(strcmp(name,"timeout") == 0) + { + iRet = SetTMOLH45(self->pDriv,(int)fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigLH45(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: LH45 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + /* Note divisors and multipliers will not be used with the LH45 + but leave in for back compatibility */ + else if(strcmp(name,"divisor") == 0) + { + iRet = SetDivisorLH45(self->pDriv,fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigLH45(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: LH45 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + else if(strcmp(name,"multiplicator") == 0) + { + iRet = SetMultLH45(self->pDriv,fNew); + if(!iRet) + { + SCWrite(pCon,"ERROR: value out of range",eError); + return 0; + } + iRet = ConfigLH45(self->pDriv); + if(iRet != 1) + { + SCWrite(pCon,"ERROR: LH45 configuration failed! ",eError); + SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + else + return EVCSetPar(self,name,fNew,pCon); + } +/*--------------------------------------------------------------------------*/ + int LH45GetPar(pEVControl self, char *name, float *fNew) + { + int iRet; + float fDiv; + + /* just catch those two names which we understand */ + if(strcmp(name,"sensor") == 0) + { + iRet = GetSensorLH45(self->pDriv); + *fNew = (float)iRet; + return 1; + } + else if(strcmp(name,"control") == 0) + { + iRet = GetControlLH45(self->pDriv); + *fNew = (float)iRet; + return 1; + } + else if(strcmp(name,"timeout") == 0) + { + iRet = GetTMOLH45(self->pDriv); + *fNew = (float)iRet; + return 1; + } + else if(strcmp(name,"divisor") == 0) + { + fDiv = GetDivisorLH45(self->pDriv); + *fNew = fDiv; + return 1; + } + else if(strcmp(name,"multiplicator") == 0) + { + fDiv = GetMultLH45(self->pDriv); + *fNew = fDiv; + return 1; + } + else + return EVCGetPar(self,name,fNew); + } +/*---------------------------------------------------------------------------*/ + int LH45List(pEVControl self, SConnection *pCon) + { + char pBueffel[132]; + int iRet; + + iRet = EVCList(self,pCon); + sprintf(pBueffel,"%s.sensor = %d\n",self->pName, + GetSensorLH45(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + sprintf(pBueffel,"%s.control = %d\n",self->pName, + GetControlLH45(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + sprintf(pBueffel,"%s.timeout = %d\n",self->pName, + GetTMOLH45(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + sprintf(pBueffel,"%s.divisor = %f\n",self->pName, + GetDivisorLH45(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + sprintf(pBueffel,"%s.multiplicator = %f\n",self->pName, + GetMultLH45(self->pDriv)); + SCWrite(pCon,pBueffel,eValue); + return iRet; + } +/*-------------------------------------------------------------------------*/ + int LH45Wrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) + { + pEVControl self = NULL; + char pBueffel[256]; + int iRet; + double fNum; + float fVal; + + self = (pEVControl)pData; + assert(self); + assert(pCon); + assert(pSics); + + if(argc < 2) + { + return EVControlWrapper(pCon,pSics,pData,argc,argv); + } + + strtolower(argv[1]); + if((strcmp(argv[1],"sensor") == 0) || (strcmp(argv[1],"control") == 0) || + (strcmp(argv[1],"timeout") == 0) || (strcmp(argv[1],"divisor") == 0) || + (strcmp(argv[1],"multiplicator") == 0) ) + { + if(argc > 2) /* set case */ + { + iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&fNum); + if(iRet != TCL_OK) + { + sprintf(pBueffel,"ERROR: expected number, got %s",argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + return LH45SetPar(self,argv[1],(float)fNum,pCon); + } + else /* get case */ + { + iRet = LH45GetPar(self,argv[1],&fVal); + sprintf(pBueffel,"%s.%s = %f\n",self->pName, + argv[1],fVal); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } + else if(strcmp(argv[1],"list") == 0) + { + return LH45List(self,pCon); + } + else + { + return EVControlWrapper(pCon,pSics,pData,argc,argv); + } + /* not reached */ + return 0; + } diff --git a/site_ansto/lh45.h b/site_ansto/lh45.h new file mode 100644 index 00000000..263560f5 --- /dev/null +++ b/site_ansto/lh45.h @@ -0,0 +1,49 @@ + +/*------------------------------------------------------------------------- + LH 45 + + Support for Julabo LH45 Temperature controllers for SICS. + The meaning and working of the functions defined is as desribed for a + general environment controller. + + Mark Koennecke, Juli 1997 + Mark Lesha, January 2006 (based on ITC4 code) + + copyright: see implementation file. + +-----------------------------------------------------------------------------*/ +#ifndef SICSLH45 +#define SICSLH45 +/*------------------------- The Driver ------------------------------------*/ + + pEVDriver CreateLH45Driver(int argc, char *argv[]); + int ConfigLH45(pEVDriver self); + int SetSensorLH45(pEVDriver self, int iSensor); + int SetControlLH45(pEVDriver self, int iSensor); + int GetSensorLH45(pEVDriver self); + int GetControlLH45(pEVDriver self); + /* Divisors and multipliers should not be applicable to the LH45 + since it uses floating point variables, but we leave the functions + in here anyway for the time being (setting will have no effect and + a value of 1.0 will always be returned. */ + int SetDivisorLH45(pEVDriver self, float iSensor); + float GetDivisorLH45(pEVDriver self); + int SetMultLH45(pEVDriver self, float iSensor); + float GetMultLH45(pEVDriver self); + /* Leave in time-out functionality */ + int SetTMOLH45(pEVDriver self, int iSensor); + int GetTMOLH45(pEVDriver self); + + +/*------------------------- The LH45 object ------------------------------*/ + + int LH45Wrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + int LH45SetPar(pEVControl self, char *name, float fNew, + SConnection *pCon); + int LH45GetPar(pEVControl self, char *name, float *fVal); + int LH45List(pEVControl self, SConnection *pCon); + + +#endif + diff --git a/site_ansto/lh45driv.c b/site_ansto/lh45driv.c new file mode 100644 index 00000000..7e84eef5 --- /dev/null +++ b/site_ansto/lh45driv.c @@ -0,0 +1,489 @@ +/*-------------------------------------------------------------------------- + L H 4 5 D R I V + + This file contains the implementation of a driver for the Julabo + LH45 Temperature controller. + + + Mark Koennecke, Juli 1997 + Mark Lesha, January 2006 (based on ITC4 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 "hardsup/lh45util.h" +#include "hardsup/el734_def.h" +#include "hardsup/el734fix.h" + +#define SHITTYVALUE -777 +/*------------------------- The Driver ------------------------------------*/ + + pEVDriver CreateLH45Driver(int argc, char *argv[]); + int ConfigLH45(pEVDriver self); + + +/*-----------------------------------------------------------------------*/ + typedef struct { + pLH45 pData; + char *pHost; + int iPort; + int iChannel; + int iControl; /* LH45 control */ + float fDiv; + float fMult; + int iRead; /* LH45 sensor */ + int iTmo; + int iLastError; + } LH45Driv, *pLH45Driv; +/*----------------------------------------------------------------------------*/ + static int GetLH45Pos(pEVDriver self, float *fPos) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv)self->pPrivate; + assert(pMe); + + iRet = LH45_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 LH45Run(pEVDriver self, float fVal) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + iRet = LH45_Set(&pMe->pData,fVal); + if(iRet != 1) + { + pMe->iLastError = iRet; + return 0; + } + return 1; + } +/*--------------------------------------------------------------------------*/ + static int LH45Error(pEVDriver self, int *iCode, char *error, int iErrLen) + { + pLH45Driv pMe = NULL; + + assert(self); + pMe = (pLH45Driv)self->pPrivate; + assert(pMe); + + *iCode = pMe->iLastError; + if(pMe->iLastError == SHITTYVALUE) + { + strncpy(error,"Invalid temperature returned form LH45, check sensor",iErrLen); + } + else + { + LH45_ErrorTxt(&pMe->pData,pMe->iLastError,error,iErrLen); + } + return 1; + } +/*--------------------------------------------------------------------------*/ + static int LH45Send(pEVDriver self, char *pCommand, char *pReply, int iLen) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + iRet = LH45_Send(&pMe->pData,pCommand, pReply,iLen); + if(iRet <= 0) + { + pMe->iLastError = iRet; + return 0; + } + return 1; + + } +/*--------------------------------------------------------------------------*/ + static int LH45Init(pEVDriver self) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + pMe->pData = NULL; + iRet = LH45_Open(&pMe->pData, pMe->pHost, pMe->iRead, pMe->iControl,0); + if(iRet != 1) + { + if(iRet == LH45__NOLH45) + { + return -1; + } + else + { + pMe->iLastError = iRet; + return 0; + } + } + return 1; + } +/*--------------------------------------------------------------------------*/ + static int LH45Close(pEVDriver self) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + LH45_Close(&pMe->pData); + return 1; + } +/*---------------------------------------------------------------------------*/ + static int LH45Fix(pEVDriver self, int iError) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )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: + LH45Close(self); + iRet = LH45Init(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; + } + +/*--------------------------------------------------------------------------*/ + static int LH45Halt(pEVDriver *self) + { + assert(self); + + return 1; + } +/*------------------------------------------------------------------------*/ + void KillLH45(void *pData) + { + pLH45Driv pMe = NULL; + + pMe = (pLH45Driv)pData; + assert(pMe); + + if(pMe->pHost) + { + free(pMe->pHost); + } + free(pMe); + } +/*------------------------------------------------------------------------*/ + pEVDriver CreateLH45Driver(int argc, char *argv[]) + { + pEVDriver pNew = NULL; + pLH45Driv pSim = NULL; + + /* check for arguments */ + if(argc < 3) + { + return NULL; + } + + pNew = CreateEVDriver(argc,argv); + pSim = (pLH45Driv)malloc(sizeof(LH45Driv)); + memset(pSim,0,sizeof(LH45Driv)); + if(!pNew || !pSim) + { + return NULL; + } + pNew->pPrivate = pSim; + pNew->KillPrivate = KillLH45; + + /* initalise pLH45Driver */ + pSim->iControl = atoi(argv[2]); + pSim->iRead = atoi(argv[1]); + pSim->iLastError = 0; + pSim->iTmo = 10; + + /* The LH45 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 = LH45Run; + pNew->GetValue = GetLH45Pos; + pNew->Send = LH45Send; + pNew->GetError = LH45Error; + pNew->TryFixIt = LH45Fix; + pNew->Init = LH45Init; + pNew->Close = LH45Close; + + return pNew; + } +/*--------------------------------------------------------------------------*/ + int ConfigLH45(pEVDriver self) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + iRet = LH45_Config(&pMe->pData, pMe->iTmo, pMe->iRead, + pMe->iControl,pMe->fDiv,pMe->fMult); + if(iRet < 0) + { + pMe->iLastError = iRet; + return 0; + } + return 1; + } +/*-------------------------------------------------------------------------*/ + int SetSensorLH45(pEVDriver self, int iSensor) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + /* The LH45 allows bath temp, external temp and tank temp to be read + so allow iRead=1 to 3 for each of these respectively */ + if( (iSensor < 1) || (iSensor > 3) ) + { + return 0; + } + pMe->iRead = iSensor; + pMe->pData->iRead = iSensor; + return 1; + } +/*-------------------------------------------------------------------------*/ + int SetControlLH45(pEVDriver self, int iSensor) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + /* For the LH45 allow selection of internal or external control + where iControl==1 or 2 respectively */ + if( (iSensor < 1) || (iSensor > 2) ) + { + return 0; + } + pMe->iControl = iSensor; + pMe->pData->iControl = iSensor; + return 1; + } +/*-------------------------------------------------------------------------*/ + int SetTMOLH45(pEVDriver self, int iSensor) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + if(iSensor < 10) + { + return 0; + } + pMe->iTmo = iSensor; + return 1; + } +/*-------------------------------------------------------------------------*/ + int GetControlLH45(pEVDriver self) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + return pMe->iControl; + } +/*-------------------------------------------------------------------------*/ + int GetSensorLH45(pEVDriver self) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + return pMe->iRead; + } +/*-------------------------------------------------------------------------*/ + int GetTMOLH45(pEVDriver self) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + return pMe->iTmo; + } +/*-------------------------------------------------------------------------*/ + float GetDivisorLH45(pEVDriver self) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + return pMe->fDiv; /* but forced to 1.0 for LH45, not used */ + } +/*--------------------------------------------------------------------------*/ + int SetDivisorLH45(pEVDriver self, float fDiv) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + /* The LH45 doesn't need divisor, force to 1.0 */ + pMe->fDiv = 1.0; /* fDiv */; + return 1; + } +/*-------------------------------------------------------------------------*/ + float GetMultLH45(pEVDriver self) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + return pMe->fMult; /* but forced to 1.0 for LH45, not used */ + } +/*--------------------------------------------------------------------------*/ + int SetMultLH45(pEVDriver self, float fDiv) + { + pLH45Driv pMe = NULL; + int iRet; + + assert(self); + pMe = (pLH45Driv )self->pPrivate; + assert(pMe); + + /* The LH45 doesn't need multiplier, force to 1.0 */ + pMe->fMult = 1.0; /* fDiv */; + return 1; + } + diff --git a/site_ansto/make_gen_variables b/site_ansto/make_gen_variables new file mode 100644 index 00000000..06e77d44 --- /dev/null +++ b/site_ansto/make_gen_variables @@ -0,0 +1,34 @@ +# vim: ft=make ts=4 sw=4 noet cindent +COBJ = Sclient.o network.o ifile.o intcli.o $(FORTIFYOBJ) +SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ + servlog.o sicvar.o nserver.o SICSmain.o motorlist.o\ + sicsexit.o costa.o task.o $(FORTIFYOBJ)\ + macro.o ofac.o obpar.o obdes.o drive.o status.o intserv.o \ + devexec.o mumo.o mumoconf.o selector.o selvar.o fupa.o lld.o \ + lld_blob.o strrepl.o lin2ang.o fomerge.o \ + script.o o2t.o alias.o napi.o napi5.o nxdata.o stringdict.o sdynar.o \ + histmem.o histdriv.o histsim.o interface.o callback.o \ + event.o emon.o evcontroller.o evdriver.o simev.o perfmon.o \ + danu.o nxdict.o varlog.o stptok.o nread.o trigd.o cell.o\ + scan.o fitcenter.o telnet.o token.o wwildcard.o hklmot.o\ + tclev.o hkl.o integrate.o optimise.o dynstring.o nxutil.o \ + mesure.o uubuffer.o commandlog.o udpquieck.o fourtable.o\ + rmtrail.o help.o nxupdate.o confvirtualmot.o vector.o\ + simchop.o choco.o chadapter.o trim.o scaldate.o tasub.o\ + hklscan.o xytable.o exebuf.o exeman.o ubfour.o ubcalc.o\ + circular.o maximize.o sicscron.o scanvar.o tasublib.o\ + d_sign.o d_mod.o tcldrivable.o stdscan.o diffscan.o \ + synchronize.o definealias.o oscillate.o tasdrive.o \ + hmcontrol.o userscan.o rs232controller.o lomax.o tasscanub.o \ + fourlib.o motreg.o motreglist.o anticollider.o nxdataset.o \ + s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) mcreader.o mccontrol.o\ + hmdata.o nxscript.o tclintimpl.o sicsdata.o mcstascounter.o \ + mcstashm.o initializer.o remob.o tclmotdriv.o protocol.o \ + sinfox.o sicslist.o cone.o $(EXTRA) + +MOTOROBJ = motor.o simdriv.o +COUNTEROBJ = countdriv.o simcter.o counter.o +VELOOBJ = velo.o velosim.o + +COREOBJ = $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) $(VELOOBJ) + diff --git a/site_ansto/motor_asim.c b/site_ansto/motor_asim.c new file mode 100644 index 00000000..9a159189 --- /dev/null +++ b/site_ansto/motor_asim.c @@ -0,0 +1,655 @@ +/*----------------------------------------------------------------------------- + + Based on SINQ code 1996-2003 by Mark Koennecke + + Modifications: Paul Hathaway April 2004 + SimRun failure rate independent of polling rate + Fault condition determined at initial drive command and reported + at appropriate time: + ASIM_NO_FAULT - run to destination, report no error (OKOK,HWIdle) + ASIM_HW_FAULT - no movement, report HWFault + ASIM_POS_FAULT - run to error position, report no error (OKOK,HWIdle) + ASIM_STALL_FAULT - run to stall position, report HWFault + + Copyright: See COPYRIGHT.txt + + Instrument definition file usage: + Motor motname ASIM lowerlimit upperlimit failpercent [speed] + +----------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include + +/* SICS kernel declarations */ +#include "sics.h" +#include "modriv.h" /* includes abstract motor defn */ +#include "fortify.h" +#include "conman.h" +#include "servlog.h" +#include "splitter.h" +#include "SCinter.h" + +/* #include "motor_driver.h" */ +/* Ansto-specific simulation driver */ +/* #include "sim_motor.h" */ +#include "motor_asim.h" + +/* ----------------------- Simulation -----------------------------------*/ +/* #ifndef SICS_ANSTO_MOTOR_ASIM */ +#define SICS_ANSTO_MOTOR_ASIM +#define MAX_LONG 2147483647 + +/* device internal status and error codes */ +/* BUSY - motor in motion toward target + * IDLE - movement complete, normal condition + * FAULT - no motion, motor awaiting reset + * CRASH - no motion, unable to recover + */ +#define ASIM_BUSY 1 +#define ASIM_IDLE 2 +#define ASIM_FAULT 3 +#define ASIM_CRASH 4 + + /* the first fields of ASIMDriv structure HAVE to be IDENTICAL to the + * abstract motor driver structure in modriv.h (motor_driver.h) + */ + + typedef struct ___MoDriv { + /* general motor driver interface fields. REQUIRED! */ + float fUpper; /* upper limit */ + float fLower; /* lower limit */ + char *name; + int (*GetPosition)(void *self,float *fPos); + int (*RunTo)(void *self, float fNewVal); + int (*GetStatus)(void *self); + void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen); + int (*TryAndFixIt)(void *self,int iError, float fNew); + int (*Halt)(void *self); + int (*GetDriverPar)(void *self, char *name, float *value); + int (*SetDriverPar)(void *self,SConnection *pCon, char *name, + float newValue); + void (*ListDriverPar)(void *self, char *motorName, SConnection *pCon); + void (*KillPrivate)(void *self); + + /* ASIM-specific fields */ + float fFailure; /* percent random failures */ + int iFaultType; /* used internally and for debugging */ + float fSpeed; + long iDuration; /* expected duration of move (secs) */ + long iTime; /* expected completion time (secs since 1969) */ + long iRunningTime; /* time (sec) running current move */ + long iLastPollTime; + float fPos; /* simulated current position */ + float fTarget; /* simulation target position including fault */ + float fDestination; /* requested final position */ + int iStatus; + } ASIMDriv; + +/* fault types */ +#define ASIM_NO_FAULT 0 +#define ASIM_HW_FAULT 1 +#define ASIM_POS_FAULT 2 +#define ASIM_STALL_FAULT 3 + +/* thresholds for determining relative proportion of fault types */ +/*static const float TH_HW_FAULT = 20.0; /* ie (20-0) % of faults */ +/*static const float TH_STALL_FAULT = 40.0; /* ie (40-20)% of faults */ +/*static const float TH_POS_FAULT = 100.0; /* ie remaining faults */ + +/*static const float MIN_SPEED = 0.0001; */ + +#define TH_HW_FAULT 20.0 +#define TH_STALL_FAULT 40.0 +#define TH_POS_FAULT 100.0 +#define MIN_SPEED 0.0001 + +/* void KillASIM(void *pData); */ +static void UpdateRunningTime(ASIMDriv *); +static void UpdatePosition(ASIMDriv *); +static float SimRandom(void); +static int SimHalt(void *); +static int RunComplete(ASIMDriv *); +static int SimGetPos(void *, float *); +static int SimRun(void *, float); +static void SimError(void *self, int *iCode, char *error, int iErrLen); +static int SimFix(void *self, int iError, float fNew); +static int SimHalt(void *self); +static int SimStat(void *self); + +/*-------------------------------------------------------------------------*/ + static float SimRandom(void) + { + float fVal; + fVal = ( (float) rand() / (float)RAND_MAX ) * 100.0; + return fVal; + } +/*---------------------------------------------------------------------------*/ + static void UpdateRunningTime(ASIMDriv *pDriv) + { + time_t tD; + + time(&tD); /* This fn valid between Jan 1970 and Jan 2038 */ + if (ASIM_BUSY == pDriv->iStatus) + { + pDriv->iRunningTime += ((long)tD - pDriv->iLastPollTime); + } + pDriv->iLastPollTime = (long)tD; + } +/*----------------------------------------------------------------------------*/ + static void UpdatePosition(ASIMDriv *pDriv) + { + float fDirn = 1.0; + UpdateRunningTime(pDriv); + switch (pDriv->iStatus) + { + case ASIM_BUSY: + if (pDriv->iRunningTime >= pDriv->iDuration) + { + switch (pDriv->iFaultType) + { + case ASIM_POS_FAULT: /* no break */ + case ASIM_NO_FAULT: + pDriv->fPos = pDriv->fTarget; + pDriv->iStatus = ASIM_IDLE; + break; + default : + pDriv->iFaultType = ASIM_HW_FAULT; /* no break */ + case ASIM_HW_FAULT: + pDriv->iStatus = ASIM_FAULT; + break; + case ASIM_STALL_FAULT: + pDriv->fPos = pDriv->fTarget; + pDriv->iStatus = ASIM_FAULT; + break; + } + } + else /* Running. Calculate intermediate position */ + { + switch (pDriv->iFaultType) + { + case ASIM_POS_FAULT: + case ASIM_NO_FAULT: + case ASIM_STALL_FAULT: + if (pDriv->fTarget < pDriv->fPos) { + fDirn = -1.0; + } else fDirn = 1.0; + pDriv->fPos = pDriv->fTarget - fDirn * pDriv->fSpeed * (pDriv->iDuration - pDriv->iRunningTime); + pDriv->iStatus = ASIM_BUSY; + break; + case ASIM_HW_FAULT: + pDriv->iStatus = ASIM_FAULT; + break; + default: break; /* error: unknown fault type */ + } + } + break; + case ASIM_FAULT: + case ASIM_IDLE: + case ASIM_CRASH: + default: break; + } + } +/*---------------------------------------------------------------------------*/ + static int RunComplete(ASIMDriv *pDriv) + { + UpdatePosition(pDriv); + if(ASIM_BUSY!=pDriv->iStatus) return 1; else return 0; + } +/*----------------------------------------------------------------------------*/ + static int SimGetPos(void *self, float *fPos) + { + int motCode = OKOK; + ASIMDriv *pDriv; + assert(self); + pDriv = (ASIMDriv *)self; + UpdatePosition(pDriv); + *fPos = pDriv->fPos; + switch (pDriv->iStatus) + { + case ASIM_IDLE: /* no break */ + case ASIM_BUSY: + motCode = OKOK; + break; + default: + case ASIM_CRASH: + case ASIM_FAULT: + motCode = HWFault; + break; + } + return motCode; + } +/*----------------------------------------------------------------------------*/ + static int SimRun(void *self, float fVal) + { + ASIMDriv *pDriv; + float fDiff; + float fFault; + int iSucceed; + float fDirection; + float fDelta; + float fDuration; + time_t tD; + + assert(self); + pDriv = (ASIMDriv *)self; + + switch (pDriv->iStatus) + { + case ASIM_IDLE: pDriv->iStatus = ASIM_BUSY; + case ASIM_BUSY: break; + default: pDriv->iStatus = ASIM_CRASH; + case ASIM_CRASH: + case ASIM_FAULT: return HWFault; + break; + } + + /* New run command */ + /* Determine desired distance and direction (fDiff >= 0.0)*/ + pDriv->fDestination = fVal; + fDiff = fVal - pDriv->fPos; + if(0.0 > fDiff) + { + fDiff = -fDiff; + fDirection = -1.0; + } + else + fDirection = 1.0; + + /* Determine whether fault will occur */ + if ((0.0 >= pDriv->fFailure)||(SimRandom() > pDriv->fFailure)) + iSucceed = 1; + else + iSucceed = 0; + + /* Determine delta from actual target by fault mode */ + if (0 == iSucceed) + { + fFault = SimRandom(); + if ((TH_HW_FAULT > fFault)||(HWFault==pDriv->iStatus)) + { /* fail as soon as possible */ + pDriv->iStatus = ASIM_FAULT; + pDriv->iFaultType = ASIM_HW_FAULT; + fDelta = -fDiff; + } + else + { + if (TH_STALL_FAULT > fFault) + { /* stall before 80% complete */ + pDriv->iFaultType = ASIM_STALL_FAULT; + fDelta = (-1.0) * fDiff * (0.2 + SimRandom()/125.0); + } + else + { /* position fault to +/- 10% */ + pDriv->iFaultType = ASIM_POS_FAULT; + fDelta = fDiff * SimRandom()/1000.0; + if (50.0 > SimRandom()) fDelta = -fDelta; + } + } + } + else /* no failure */ + { + pDriv->iFaultType = ASIM_NO_FAULT; + fDelta = 0.0; + } + + /* Calculate target and time using speed */ + if (pDriv->fSpeed >= MIN_SPEED) + { + fDiff = fDiff + fDelta; + fDuration = fDiff/(pDriv->fSpeed); + if (fDuration > MAX_LONG) + pDriv->iDuration = 2000000000; + else + pDriv->iDuration = (long)fDuration; + } + else + { + fDiff = 0.0; + pDriv->iDuration = 0; + } + pDriv->fTarget = pDriv->fPos + fDirection * fDiff; + pDriv->iRunningTime = 0; + pDriv->iLastPollTime = time(&tD); + pDriv->iTime = tD + pDriv->iDuration; + + if(ASIM_BUSY==pDriv->iStatus) + return OKOK; + else + return HWFault; + + } /* SimRun */ + +/*--------------------------------------------------------------------------*/ +/* iErrLen fixed to 131 in fn [reportAndFixError] of + * iCode reported to SimFix via [reportAndFixError] + */ + static void SimError(void *self, int *iCode, char *error, int iErrLen) + { + int motCode = HWFault; + ASIMDriv *pDriv; + + assert(self); + pDriv = (ASIMDriv *)self; + + switch (pDriv->iStatus) + { + case ASIM_IDLE: motCode = HWIdle; break; + case ASIM_BUSY: motCode = HWBusy; break; + case ASIM_CRASH: + case ASIM_FAULT: + default: motCode = HWFault; break; + } + + *iCode = pDriv->iFaultType; + + switch (pDriv->iFaultType) + { + case ASIM_POS_FAULT: + strncpy(error,"ERROR: ASIM Position Fault",iErrLen); + break; + case ASIM_NO_FAULT: + strncpy(error,"STATUS: ASIM No Fault",iErrLen); + break; + case ASIM_HW_FAULT: + strncpy(error,"ERROR: ASIM Motor Hardware Fault",iErrLen); + break; + case ASIM_STALL_FAULT: + strncpy(error,"ERROR: ASIM Motor Stall",iErrLen); + break; + default: /* error: unknown fault type */ + strncpy(error,"ERROR: Unknown fault type",iErrLen); + break; + } + assert(strlen(error)<131); + } /* SimError */ + +/*---------------------------------------------------------------------------*/ + static int SimFix(void *self, int iError, float fNew) + { + ASIMDriv *pDriv; + int iRet; + float fRand; + + assert(self); + pDriv = (ASIMDriv *)self; + + switch (pDriv->iStatus) + { + case ASIM_IDLE: + switch (pDriv->iFaultType) + { + case ASIM_POS_FAULT: return MOTOK; + case ASIM_NO_FAULT: return MOTOK; + case ASIM_HW_FAULT: return MOTFAIL; + case ASIM_STALL_FAULT: return MOTREDO; + default: return MOTFAIL; /* error: unknown fault type */ + } + break; + case ASIM_BUSY: return MOTOK; break; + case ASIM_CRASH: return MOTFAIL; break; + case ASIM_FAULT: + SimHalt(self); + if(TH_HW_FAULT >= SimRandom()) + { + pDriv->iStatus = ASIM_CRASH; + return MOTFAIL; + } + pDriv->iStatus = ASIM_IDLE; + pDriv->iFaultType = ASIM_NO_FAULT; + return MOTOK; + break; + default: + pDriv->iStatus = ASIM_CRASH; + pDriv->iFaultType = ASIM_HW_FAULT; + return MOTFAIL; + } +/* SICSLogWrite("Attempt fix for simulated motor",eHWError); */ + } /* SimFix */ + +/*--------------------------------------------------------------------------*/ + static int SimHalt(void *self) + { + int motCode = OKOK; + ASIMDriv *pDriv; + assert(self); + + pDriv = (ASIMDriv *)self; + UpdatePosition(pDriv); + pDriv->iTime = 0; + pDriv->iDuration = 0; + pDriv->fTarget = pDriv->fPos; + pDriv->fDestination = pDriv->fPos; + switch (pDriv->iStatus) + { + case ASIM_BUSY: pDriv->iStatus = ASIM_IDLE; + case ASIM_IDLE: motCode = OKOK; + break; + default: motCode = HWFault; + break; + } + return motCode; + } +/*--------------------------------------------------------------------------*/ + static int SimStat(void *self) + { + int motCode = HWIdle; + ASIMDriv *pDriv; + assert(self); + pDriv = (ASIMDriv *)self; + + UpdatePosition(pDriv); + switch (pDriv->iStatus) + { + case ASIM_BUSY: motCode = HWBusy; break; + case ASIM_IDLE: motCode = HWIdle; break; + default: motCode = HWFault; break; + } + return motCode; + } +/*-----------------------------------------------------------------------*/ +static int SimSetPar(void *self, SConnection *pCon, char *name, float newValue) +{ + int iSuccess = 0; + ASIMDriv *pDriv = (ASIMDriv *) self; + + assert(self); + assert(pCon); + + if(strcmp(name,"hardupperlim") == 0) + { + pDriv->fUpper = newValue; + iSuccess = 1; + } + if(strcmp(name,"hardlowerlim") == 0) + { + pDriv->fLower = newValue; + iSuccess = 1; + } + if(strcmp(name,"speed") == 0) + { + pDriv->fSpeed = newValue; + iSuccess = 1; + } + return iSuccess; +} + +/*-----------------------------------------------------------------------*/ +static int SimGetPar(void *self, char *name, float *value) +{ + int iSuccess = 0; + ASIMDriv *pDriv = (ASIMDriv *) self; + assert(self); + + if (0==strcmp("hardupperlim",name)) + { + *value = pDriv->fUpper; + iSuccess = 1; + } + if (0==strcmp("hardlowerlim",name)) + { + *value = pDriv->fLower; + iSuccess=1; + } + return iSuccess; +} + +/*-----------------------------------------------------------------------*/ +static void SimListPar(void *self, char *motorName, SConnection *pCon) +{ + ASIMDriv *pDriv = (ASIMDriv *) self; + char pBuffer[256]; + + assert(self); + assert(pCon); + + sprintf(pBuffer,"%s.%s = %f",motorName,"hardupperlim",pDriv->fUpper); + SCWrite(pCon,pBuffer,eValue); + sprintf(pBuffer,"%s.%s = %f",motorName,"hardlowerlim",pDriv->fLower); + SCWrite(pCon,pBuffer,eValue); +} + +/*---------------------------------------------------------------------------*/ + static void SimKill(void *pData) +{ + /* + the controller is owned by the controller object and will be + deleted when that object is removed + */ + return; +} + +/*--------------------------------------------------------------------------*/ +MotorDriver *CreateASIM(SConnection *pCon, int argc, char *argv[]) +{ + TokenList *pList = NULL; + TokenList *pCurrent; + ASIMDriv *pDriv = NULL; + time_t tD; + + assert(pCon); + + /* check number of arguments */ + if(argc < 3) + { + SCWrite(pCon,"Insufficient numbers of arguments for ASIM Motor",eError); + return NULL; + } + + /* split arguments */ + pList = SplitArguments(argc, argv); + if(!pList) + { + SCWrite(pCon,"Error parsing arguments in ASIM Motor",eError); + return NULL; + } + + /* allocate memory */ + pDriv = (ASIMDriv *)malloc(sizeof(ASIMDriv)); + if(!pDriv) + { + SCWrite(pCon,"Error allocating memory in ASIM Motor",eError); + DeleteTokenList(pList); + return NULL; + } + memset(pDriv,0,sizeof(ASIMDriv)); + + /* check and enter args, first lowerLimit */ + pCurrent = pList; + if(pCurrent->Type == eInt) + { + pDriv->fLower = (float)pCurrent->iVal; + } + else if(pCurrent->Type == eFloat) + { + pDriv->fLower = pCurrent->fVal; + } + else + { + SCWrite(pCon,"ERROR: Expect numerical 'lower limit' at argument 1 after Motor ASIM",eError); + free(pDriv); + DeleteTokenList(pList); + return NULL; + } + + /* then, upper limit */ + pCurrent = pCurrent->pNext; + if(pCurrent->Type == eInt) + { + pDriv->fUpper = (float)pCurrent->iVal; + } + else if(pCurrent->Type == eFloat) + { + pDriv->fUpper = pCurrent->fVal; + } + else + { + SCWrite(pCon,"ERROR: Expect numerical 'upper limit' at argument 2 after Motor ASIM",eError); + free(pDriv); + DeleteTokenList(pList); + return NULL; + } + + /* thirdly, failure rate */ + pCurrent = pCurrent->pNext; + if(pCurrent->Type == eInt) + { + pDriv->fFailure = (float)pCurrent->iVal; + } + else if(pCurrent->Type == eFloat) + { + pDriv->fFailure = pCurrent->fVal; + } + else + { + SCWrite(pCon,"ERROR: Expect numerical 'failure rate' at argument 3 after Motor ASIM",eError); + free(pDriv); + DeleteTokenList(pList); + return NULL; + } + + /* calculate current position, initialise func pters */ + pDriv->fPos = (pDriv->fUpper + pDriv->fLower)/2.0; + /* pDriv->name = strdup("SICS_ANSTO_MOTOR_ASIM"); */ + pDriv->name = malloc((1+strlen("SICS_ANSTO_MOTOR_ASIM"))*sizeof(char)); + strcpy(pDriv->name,"SICS_ANSTO_MOTOR_ASIM"); + + pDriv->GetPosition = SimGetPos; + pDriv->RunTo = SimRun; + pDriv->GetStatus = SimStat; + pDriv->GetError = SimError; + pDriv->TryAndFixIt = SimFix; + pDriv->Halt = SimHalt; + pDriv->SetDriverPar = SimSetPar; + pDriv->GetDriverPar = SimGetPar; + pDriv->ListDriverPar = SimListPar; + pDriv->KillPrivate = SimKill; + + /* set default parameters */ + pDriv->fSpeed = 0.01; + pDriv->iTime = time(&tD); + pDriv->iFaultType = ASIM_NO_FAULT; + pDriv->iDuration = 0; + pDriv->iRunningTime = 0; + pDriv->iLastPollTime = pDriv->iTime; + pDriv->fTarget = pDriv->fPos; + pDriv->fDestination = pDriv->fPos; + pDriv->iStatus = OKOK; + + srand( (unsigned)time( NULL ) ); + + /* check for optional speed paramter */ + pCurrent = pCurrent->pNext; + if(pCurrent) + { + if(pCurrent->Type == eFloat) + { + pDriv->fSpeed = pCurrent->fVal; + if(pDriv->fSpeed < 0.0) pDriv->fSpeed = 0.0 - pDriv->fSpeed; + } + } + DeleteTokenList(pList); + return (MotorDriver *)pDriv; +} diff --git a/site_ansto/motor_asim.h b/site_ansto/motor_asim.h new file mode 100644 index 00000000..b1c2319f --- /dev/null +++ b/site_ansto/motor_asim.h @@ -0,0 +1,17 @@ +/*-------------------------------------------------------------------------- + * motor_asim.h + + Header file for ANSTO Simulation Motor + Based on SINQ "modriv.h" for EL734 motor driver by Mark Koennecke 1996 + Modifications Paul Hathaway April 2004 + + Copyright: see implementation file +---------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif +MotorDriver *CreateASIM(SConnection *pCon, int argc, char *argv[]); +#ifdef __cplusplus +} +#endif diff --git a/site_ansto/motor_dmc2280.c b/site_ansto/motor_dmc2280.c new file mode 100644 index 00000000..99b569cf --- /dev/null +++ b/site_ansto/motor_dmc2280.c @@ -0,0 +1,802 @@ +/*------------------------------------------------------------------------ + Implements a SICS motor object with a MotorDriver interface. + The control and communications functions are implemented in a separate layer + in instrument/dmc2280.tcl + +Copyright: see file Copyright.txt + +Ferdi Franceschini November 2005 +-----------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* +#include "splint/splint_fortify.h" +#include "splint/splint_tclDecls.h" +#include "splint/splint_dynstring.h" +#include "splint/splint_SCinter.h" +*/ + +/*----------------------------------------------------------------------- + The motor driver structure. Please note that the first set of fields has + be identical with the fields of AbstractModriv in ../modriv.h + ------------------------------------------------------------------------*/ +typedef struct __MoDriv { + /* general motor driver interface + fields. _REQUIRED! + */ + float fUpper; /* upper limit */ + float fLower; /* lower limit */ + char *name; + int (*GetPosition)(void *self,float *fPos); + int (*RunTo)(void *self, float fNewVal); + int (*GetStatus)(void *self); + void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen); + int (*TryAndFixIt)(void *self,int iError, float fNew); + int (*Halt)(void *self); + int (*GetDriverPar)(void *self, char *name, + float *value); + int (*SetDriverPar)(void *self,SConnection *pCon, + char *name, float newValue); + void (*ListDriverPar)(void *self, char *motorName, + SConnection *pCon); + void (*KillPrivate)(void *self); + + + /* DMC-2280 specific fields */ + SConnection *pCon; + prs232 controller; + int iMotor; + int errorCode; + int oredMsr; + int lastValue; + int iConfig; + char units[256]; /* physical units for axis */ + float speed; /* physical units per second */ + float maxSpeed; /* physical units per second */ + float accel; /* physical units per second^2 */ + float maxAccel; /* physical units per second^2 */ + float decel; /* physical units per second^2 */ + float maxDecel; /* physical units per second^2 */ + char axisLabel; + char lastCmd[1024]; + float home; /* home position for axis, default=0 */ + int motorHome; /* motor home position in steps */ + int stepsPerX; /* steps per physical unit */ + int abs_endcoder; /* Flag = 1 if there is an abs enc */ + int absEncHome; /* Home position in counts for abs enc */ + int cntsPerX; /* absolute encoder counts per physical unit */ +} DMC2280Driv, *pDMC2280Driv; +/*------------------- error codes ----------------------------------*/ +#define BADADR -1 // Unknown host/port? +#define BADBSY -2 +#define BADCMD -3 +#define BADPAR -4 // Does SICS already check parameter types? +#define BADUNKNOWN -5 +#define BADSTP -6 +#define BADEMERG -7 +#define RVRSLIM -8 +#define FWDLIM -9 +#define RUNFAULT -10 +#define POSFAULT -11 +#define BADCUSHION -12 +#define ERRORLIM -13 +#define IMPOSSIBLE_LIM_SW -14 +#define BGFAIL -15 +/*--------------------------------------------------------------------*/ +#define STATUSMOVING 128 /* Motor is moving */ +#define STATUSERRORLIMIT 64 /* Number of errorss exceed limit */ +#define STATUSOFF 32 /* Motor off */ +#define STATUSFWDLIMIT 8 /* Forward limit switch active */ +#define STATUSRVRSLIMIT 4 /* Reverse limit switch active */ + +#define INIT_STR_SIZE 256 +#define STR_RESIZE_LENGTH 256 +#define CMDLEN 1024 +#define ERRLEN 256 +#define BUFFLEN 512 +#define FAILURE 0 +#define SUCCESS 1 +#define _REQUIRED 1 +#define _OPTIONAL 0 + +#define HOME "home" +#define HARDLOWERLIM "hardlowerlim" +#define HARDUPPERLIM "hardupperlim" +#define UNITS "units" +#define SPEED "speed" +#define MAXSPEED "maxSpeed" +#define ACCEL "accel" +#define MAXACCEL "maxAccel" +#define DECEL "decel" +#define MAXDECEL "maxDecel" + +static int DMC2280Receive(pDMC2280Driv self, /*@out@*/ char *reply); + +/* Return motor speed in steps/sec */ +static int motSpeed(pDMC2280Driv self, float speed) { + int motSpeed; + motSpeed = abs((int)(speed * self->stepsPerX + 0.5)); + return motSpeed; +} + +/* Return motor acceleration in steps/sec^2 */ +static int motAccel(pDMC2280Driv self, float accel) { + int motAccel; + motAccel = abs((int)(accel * self->stepsPerX + 0.5)); + return motAccel; +} + +/* Return motor deceleration in steps/sec^2 */ +static int motDecel(pDMC2280Driv self, float decel) { + int motDecel; + motDecel = abs((int)(decel * self->stepsPerX + 0.5)); + return motDecel; +} + +static int DMC2280ReadChar(pDMC2280Driv self, char *reply) { + int i, status, retries=20, dataLen=1; + for (i=0; icontroller, reply, &dataLen); + switch (status) { + case 1: + return SUCCESS; + case TIMEOUT: + self->errorCode = status; + continue; + default: + self->errorCode = status; + return FAILURE; + } + } + return FAILURE; +} +/*---------------------------------------------------------------------*/ +/* First character returned by controller is + '?' for an invalid command or + ':' or space for a valid command */ +static int DMC2280Send(pDMC2280Driv self, char *command) { + char cmdValid, pError[ERRLEN], reply[256]; + char *GetEMsg = "TC 1"; + int status; + + strncpy(self->lastCmd, command, CMDLEN); + status = writeRS232(self->controller, command, strlen(command)); + if (status != 1) { + self->errorCode = status; + return FAILURE; + } + + if (FAILURE == (status = DMC2280ReadChar(self, &cmdValid))) { + self->errorCode = status; + return FAILURE; + } else { + switch (cmdValid) { + case ':': + case ' ': + return SUCCESS; + case '?': + status = writeRS232(self->controller, GetEMsg, strlen(GetEMsg)); + if (status != 1) { + self->errorCode = status; + return FAILURE; + } + if (FAILURE == DMC2280Receive(self, reply)) + return HWFault; + snprintf(pError, ERRLEN, "DMC2280ERROR: Bad command '%s'", command); + SCWrite(self->pCon, reply, eError); + self->errorCode = BADCMD; + return FAILURE; + default: + self->errorCode = BADUNKNOWN; + return FAILURE; + } + } +} + +static int DMC2280Receive(pDMC2280Driv self, char *reply) { + int i, status, retries=20, dataLen=255; + for (i=0; icontroller, reply, &dataLen); + switch (status) { + case 1: + return dataLen; + case TIMEOUT: + self->errorCode = status; + continue; + /* TODO case INCOMPLETE: */ + default: + self->errorCode = status; + return FAILURE; + } + } + return FAILURE; +} +/*---------------------------------------------------------------------*/ +static int DMC2280GetPos(void *pData, float *fPos){ + pDMC2280Driv self = NULL; + char reply[1024]; + char cmd[CMDLEN]; + float absEncPos, motorPos; + + reply[0]='\0'; + self = (pDMC2280Driv)pData; + assert(self != NULL); + if (1 == self->abs_endcoder) { + snprintf(cmd, CMDLEN, "TP%c", self->axisLabel); + if (FAILURE == DMC2280Send(self, cmd)) + return HWFault; + if (FAILURE == DMC2280Receive(self, reply)) + return HWFault; + absEncPos =(float)atof(reply); + *fPos = (absEncPos - self->absEncHome)/self->cntsPerX + self->home; + } else { + snprintf(cmd, ERRLEN, "TD%c", self->axisLabel); + if (FAILURE == DMC2280Send(self, cmd)) + return HWFault; + if (FAILURE == DMC2280Receive(self, reply)) + return HWFault; + motorPos =(float)atof(reply); + *fPos = (motorPos - self->motorHome)/self->stepsPerX + self->home; + } + return OKOK; +} +/*----------------------------------------------------------------------*/ +static int DMC2280Run(void *pData,float fValue){ + pDMC2280Driv self = NULL; + char axis; + char cmd[CMDLEN], SH[CMDLEN], BG[CMDLEN], absPosCmd[CMDLEN]; + int absEncHome, stepsPerX, motorHome, cntsPerX, newAbsPosn; + float target; + + self = (pDMC2280Driv)pData; + assert(self != NULL); + axis=self->axisLabel; + motorHome = self->motorHome; + stepsPerX=self->stepsPerX; + snprintf(SH, CMDLEN, "SH%c", axis); + snprintf(BG, CMDLEN, "BG%c", axis); + target = fValue - self->home; + newAbsPosn = (int)(target * stepsPerX + motorHome + 0.5); + snprintf(absPosCmd, CMDLEN, "PA%c=%d",axis, newAbsPosn); + + if (1 == self->abs_endcoder) { + /* Ensure that the defined motor position matches actual position */ + absEncHome = self->absEncHome; + cntsPerX = self->cntsPerX; + snprintf(cmd, CMDLEN, "DP%c=(_TP%c - %d)*(%d/%d) + %d",axis,axis,absEncHome,stepsPerX,cntsPerX,motorHome); + if (FAILURE == DMC2280Send(self, cmd)) + return HWFault; + snprintf(cmd, CMDLEN, "%cQTARGET=%d", axis, (int) (target * cntsPerX + absEncHome + 0.5)); + if (FAILURE == DMC2280Send(self, cmd)) + return HWFault; + } + + if (FAILURE == DMC2280Send(self, absPosCmd)) + return HWFault; + if (FAILURE == DMC2280Send(self, SH)) + return HWFault; + if (FAILURE == DMC2280Send(self, BG)) + return HWFault; + return OKOK; +} + + +/*------------------------------------------------------------------------*/ +static int DMC2280Status(void *pData){ + pDMC2280Driv self = NULL; + char cmd[CMDLEN]; + int switches; + char switchesAscii[10], reply[256]; + int moving, fwd_limit_active, rvrs_limit_active, errorlimit; + int SERVO_LOOP_NOT_RUNNING = -1, servoLoopStatus; + int SHOULD_FIXPOS=1, should_fixpos; + + self = (pDMC2280Driv)pData; + assert(self != NULL); + /* Get status of switches + * see TS (Tell Switches) in Galil manc2xx */ + snprintf(cmd, CMDLEN, "TS%c", self->axisLabel); + if (FAILURE == DMC2280Send(self, cmd)) + return HWFault; + if (FAILURE == DMC2280Receive(self, switchesAscii)) + return HWFault; + sscanf(switchesAscii, "%d", &switches); + moving = (switches & STATUSMOVING)>0; + fwd_limit_active = !(switches & STATUSFWDLIMIT)>0; + rvrs_limit_active = !(switches & STATUSRVRSLIMIT)>0; + errorlimit = (switches & STATUSERRORLIMIT)>0; + + if (fwd_limit_active && rvrs_limit_active) { + self->errorCode = IMPOSSIBLE_LIM_SW; + return HWFault; + } + if (moving) { + self->errorCode = BADBSY; + return HWBusy; + } else { + /* If motor stopped check limits and error status */ + if (fwd_limit_active) { + self->errorCode = FWDLIM; + return HWFault; + } else if (rvrs_limit_active) { + self->errorCode = RVRSLIM; + return HWFault; + } else if (errorlimit) { + self->errorCode = ERRORLIM; + return HWFault; + } + if (self->abs_endcoder == 1) { + /* Make sure that the servo loop is closed by checking if + * the CLSLOOP thread is running on the controller.*/ + if (FAILURE == DMC2280Send(self, "MG _XQ1")) + return HWFault; + if (FAILURE == DMC2280Receive(self, reply)) + return HWFault; + sscanf(reply, "%d", &servoLoopStatus); + if (servoLoopStatus == SERVO_LOOP_NOT_RUNNING) { + /* Start subroutine on controller to close the servo loop */ + if (FAILURE == DMC2280Send(self, "XQ#CLSLOOP")) + return HWFault; + } + snprintf(cmd, CMDLEN, "MG %cSHLDFIX", self->axisLabel); + if (FAILURE == DMC2280Send(self, cmd)) + return HWFault; + if (FAILURE == DMC2280Receive(self, reply)) + return HWFault; + sscanf(reply, "%d", &should_fixpos); + if (should_fixpos == SHOULD_FIXPOS) { + snprintf(cmd, CMDLEN, "%cFIXPOS=1", self->axisLabel); + if (FAILURE == DMC2280Send(self, cmd)) + return HWFault; + self->errorCode=BADBSY; + return HWBusy; + } + } + return HWIdle; + } +} +/*----------------------------------------------------------------------*/ +static void DMC2280Error(void *pData, int *iCode, char *error, int errLen){ + pDMC2280Driv self = NULL; + self = (pDMC2280Driv)pData; + assert(self != NULL); + + *iCode = self->errorCode; + switch(*iCode){ + case BADADR: + strncpy(error,"Bad address",(size_t)errLen); + break; + case BADBSY: + strncpy(error,"Motor still busy",(size_t)errLen); + break; + case BADCMD: + snprintf(error, (size_t)errLen, "Bad command: '%s'", self->lastCmd); + break; + case BADPAR: + strncpy(error,"Bad parameter",(size_t)errLen); + break; + case BADUNKNOWN: + strncpy(error,"Unknown error condition",(size_t)errLen); + break; + case BADSTP: + strncpy(error,"Motor is stopped",(size_t)errLen); + break; + case BADEMERG: + strncpy(error,"Emergency stop is engaged",(size_t)errLen); + break; + case BGFAIL: + strncpy(error,"Begin not possible due to limit switch",(size_t)errLen); + break; + case RVRSLIM: + strncpy(error,"Crashed into reverse limit switch",(size_t)errLen); + break; + case FWDLIM: + strncpy(error,"Crashed into forward limit switch",(size_t)errLen); + break; + case RUNFAULT: + strncpy(error,"Run fault detected",(size_t)errLen); + break; + case POSFAULT: + strncpy(error,"Positioning fault detected",(size_t)errLen); + break; + case BADCUSHION: + strncpy(error,"Air cushion problem",(size_t)errLen); + break; + case ERRORLIM: + strncpy(error,"Axis error exceeds error limit",(size_t)errLen); + break; + case IMPOSSIBLE_LIM_SW: + strncpy(error,"Both limit switches seem active, maybe the polarity is set 'active low'. You should controller the controller with CN 1,-1,-1,0", (size_t)errLen); + break; + default: + /* FIXME What's the default */ + break; + } +} +/*----------------------------------------------------------------------*/ +static int DMC2280Fix(void *pData, int iCode,/*@unused@*/ float fValue){ + pDMC2280Driv self = NULL; + + self = (pDMC2280Driv)pData; + assert(self != NULL); + + switch(iCode){ + case BADADR: + case BADCMD: + //case TIMEOUT: + case BADPAR: + case BADBSY: + return MOTREDO; + case RUNFAULT: + case POSFAULT: + return MOTREDO; + case NOTCONNECTED: + initRS232(self->controller); + return MOTREDO; + } + return MOTFAIL; +} +/*----------------------------------------------------------------------*/ +/* Emergency Halt + * Uses maximum deceleration */ +static int DMC2280Halt(void *pData){ + pDMC2280Driv self = NULL; + char cmd[CMDLEN]; + + self = (pDMC2280Driv)pData; + assert(self != NULL); + /* Set maximum deceleration to stop motor */ + snprintf(cmd, CMDLEN, "DC%c", motDecel(self, self->maxDecel)); + if (FAILURE == DMC2280Send(self, cmd)) + return HWFault; + /* Stop motor */ + snprintf(cmd, CMDLEN, "ST%c", self->axisLabel); + if (FAILURE == DMC2280Send(self, cmd)) + return HWFault; + /* Restore deceleration */ + snprintf(cmd, CMDLEN, "DC%c", motDecel(self, self->decel)); + if (FAILURE == DMC2280Send(self, cmd)) + return HWFault; + + return 1; +} +/*--------------------------------------------------------------------*/ +static int DMC2280GetPar(void *pData, char *name, + float *fValue){ + pDMC2280Driv self = NULL; + + self = (pDMC2280Driv)pData; + + if(strcmp(name,HOME) == 0) { + *fValue = self->home; + return 1; + } + if(strcmp(name,HARDLOWERLIM) == 0) { + *fValue = self->fLower; + return 1; + } + if(strcmp(name,HARDUPPERLIM) == 0) { + *fValue = self->fUpper; + return 1; + } + if(strcmp(name,SPEED) == 0) { + *fValue = self->speed; + return 1; + } + if(strcmp(name,MAXSPEED) == 0) { + *fValue = self->maxSpeed; + return 1; + } + if(strcmp(name,ACCEL) == 0) { + *fValue = self->accel; + return 1; + } + if(strcmp(name,MAXACCEL) == 0) { + *fValue = self->maxAccel; + return 1; + } + if(strcmp(name,DECEL) == 0) { + *fValue = self->decel; + return 1; + } + if(strcmp(name,MAXDECEL) == 0) { + *fValue = self->maxDecel; + return 1; + } + return 0; +} +/*--------------------------------------------------------------------*/ +static int DMC2280SetPar(void *pData, SConnection *pCon, + char *name, float newValue){ + pDMC2280Driv self = NULL; + char pError[ERRLEN]; + char cmd[CMDLEN]; + + self = (pDMC2280Driv)pData; + + /* Set home */ + if(strcmp(name,HOME) == 0) { + if ( (self->fLower - newValue) > FLT_EPSILON) { + snprintf(pError, ERRLEN,"ERROR: %s must be greater than or equal to %f", HOME, self->fLower); + SCWrite(pCon, pError, eError); + return 1; + } + if ( (newValue - self->fUpper) > FLT_EPSILON) { + snprintf(pError, ERRLEN,"ERROR: %s must be less than or equal to %f", HOME, self->fUpper); + SCWrite(pCon, pError, eError); + return 1; + } + self->home = newValue; + return 1; + } + + /* Set upper limit, lower limit */ + if(strcmp(name,HARDLOWERLIM) == 0) { + self->fLower = newValue; + return 1; + } + if(strcmp(name,HARDUPPERLIM) == 0) { + self->fUpper = newValue; + return 1; + } + + /* Set speed */ + if(strcmp(name,SPEED) == 0) { + if ((0.0 - newValue) > FLT_EPSILON) { + snprintf(pError, ERRLEN,"ERROR: %s must be greater than or equal to %f", SPEED, 0.0); + SCWrite(pCon, pError, eError); + return 1; + } + if ((newValue - self->maxSpeed ) > FLT_EPSILON) { + snprintf(pError, ERRLEN,"ERROR: %s must be less than or equal to %f", SPEED, self->maxSpeed); + SCWrite(pCon, pError, eError); + return 1; + } + self->speed = newValue; + snprintf(cmd,CMDLEN,"SP%c=%d", self->axisLabel, motSpeed(self, self->speed)); + if (FAILURE == DMC2280Send(self, cmd)) + return 0; /* FIXME should signal a HWFault */ + return 1; + } + + /* Set Acceleration */ + if(strcmp(name,ACCEL) == 0) { + if ((0.0 - newValue) > FLT_EPSILON) { + snprintf(pError, ERRLEN,"ERROR: %s must be greater than or equal to %f", ACCEL, 0.0); + SCWrite(pCon, pError, eError); + return 1; + } + if ((newValue - self->maxAccel ) > FLT_EPSILON) { + snprintf(pError, ERRLEN,"ERROR: %s must be less than or equal to %f", ACCEL, self->maxAccel); + SCWrite(pCon, pError, eError); + return 1; + } + self->accel = newValue; + snprintf(cmd,CMDLEN,"AC%c=%d", self->axisLabel, motAccel(self, self->accel)); + if (FAILURE == DMC2280Send(self, cmd)) + return 0; /* FIXME should signal a HWFault */ + return 1; + } + + /* Set Deceleration */ + if(strcmp(name,DECEL) == 0) { + if ((0.0 - newValue) > FLT_EPSILON) { + snprintf(pError, ERRLEN,"ERROR: %s must be greater than or equal to %f", DECEL, 0.0); + SCWrite(pCon, pError, eError); + return 1; + } + if ((newValue - self->maxDecel ) > FLT_EPSILON) { + snprintf(pError, ERRLEN,"ERROR: %s must be less than or equal to %f", DECEL, self->maxDecel); + SCWrite(pCon, pError, eError); + return 1; + } + self->decel = newValue; + snprintf(cmd,CMDLEN,"DC%c=%d", self->axisLabel, motDecel(self, self->decel)); + if (FAILURE == DMC2280Send(self, cmd)) + return 0; /* FIXME should signal a HWFault */ + return 1; + } + + return 0; +} +/*--------------------------------------------------------------------*/ +static void DMC2280List(void *self, char *name, SConnection *pCon){ + char buffer[BUFFLEN]; + + snprintf(buffer, BUFFLEN, "%s.axis = %c\n", name, ((pDMC2280Driv)self)->axisLabel); + SCWrite(pCon, buffer, eStatus); + snprintf(buffer, BUFFLEN, "%s.home = %f\n", name, ((pDMC2280Driv)self)->home); + SCWrite(pCon, buffer, eStatus); + snprintf(buffer, BUFFLEN, "%s.units = %s\n", name, ((pDMC2280Driv)self)->units); + SCWrite(pCon, buffer, eStatus); + snprintf(buffer, BUFFLEN, "%s.speed = %f\n", name, ((pDMC2280Driv)self)->speed); + SCWrite(pCon, buffer, eStatus); + snprintf(buffer, BUFFLEN, "%s.maxSpeed = %f\n", name, ((pDMC2280Driv)self)->maxSpeed); + SCWrite(pCon, buffer, eStatus); + snprintf(buffer, BUFFLEN, "%s.accel = %f\n", name, ((pDMC2280Driv)self)->accel); + SCWrite(pCon, buffer, eStatus); + snprintf(buffer, BUFFLEN, "%s.maxAccel = %f\n", name, ((pDMC2280Driv)self)->maxAccel); + SCWrite(pCon, buffer, eStatus); + snprintf(buffer, BUFFLEN, "%s.decel = %f\n", name, ((pDMC2280Driv)self)->decel); + SCWrite(pCon, buffer, eStatus); + snprintf(buffer, BUFFLEN, "%s.maxDecel = %f\n", name, ((pDMC2280Driv)self)->maxDecel); + SCWrite(pCon, buffer, eStatus); + return; +} +/*---------------------------------------------------------------------*/ +static void KillDMC2280(void *pData){ + pDMC2280Driv self = NULL; + self = (pDMC2280Driv)pData; + assert(self != NULL); + free(self->name); + /*@-temptrans@*/ free(self); /*@+temptrans@*/ + return; +} +static prs232 DMC2280Connect(SConnection *pCon, char *buffer, int port) { + prs232 controller=NULL; + char pError[ERRLEN]; + int usecTimeout = 50000; /* 50msec timeout */ + + controller=createRS232(buffer,port); + if (controller==NULL) { + snprintf(pError, ERRLEN, + "ERROR: failed to create controller for %s at port %d", + controller->pHost, controller->iPort); + SCWrite(pCon,pError,eError); + return NULL; + } + if ( initRS232(controller) != 1) { + snprintf(pError, ERRLEN, + "ERROR: failed to connect to %s at port %d", + controller->pHost, controller->iPort); + SCWrite(pCon,pError,eError); + return NULL; + } + setRS232ReplyTerminator(controller,"&\r\n:"); + setRS232SendTerminator(controller,"\r\n"); + setRS232Timeout(controller, usecTimeout); + return controller; +} + +/* Get configuration parameter */ +static char *getParam(SConnection *pCon, Tcl_Interp *pTcl, char *params, char *parName, int mustHave ) { + char *pPtr=NULL, pError[ERRLEN]; + pPtr = Tcl_GetVar2(pTcl,params,parName,TCL_GLOBAL_ONLY); + if((mustHave == _REQUIRED) && !pPtr){ + snprintf(pError, ERRLEN,"ERROR: No '%s' parameter given for dmc2280 motor", parName); + SCWrite(pCon,pError, eError); + } + return pPtr; +} + +/*------------------------------------------------------------------*/ +/*@null@*/ MotorDriver *CreateDMC2280(SConnection *pCon, char *motor, char *params){ + /*@keep@*/ pDMC2280Driv pNew = NULL; + char *pPtr = NULL; + char buffer[132]; + char pError[ERRLEN]; + char cmd[CMDLEN]; + int port; + Tcl_Interp *interp; + + buffer[0]='\0'; + + interp = InterpGetTcl(pServ->pSics); + + /* + allocate and initialize data structure + */ + pNew = (pDMC2280Driv)malloc(sizeof(DMC2280Driv)); + if(!pNew){ + (void) SCWrite(pCon,"ERROR: no memory to allocate motor driver", + eError); + return NULL; + } + /* Get hostname and port from the list of named parameters */ + if ((pPtr=getParam(pCon, interp, params,"port",1)) == NULL) return NULL; + sscanf(pPtr,"%d",&port); + if ((pPtr=getParam(pCon, interp, params,"host",1)) == NULL) return NULL; + strncpy(buffer,pPtr, 131); + + /* Connect to the controller */ + memset(pNew,0,sizeof(DMC2280Driv)); + pNew->controller = DMC2280Connect(pCon, buffer,port); + if( pNew->controller == NULL ) { + snprintf(pError, ERRLEN, "\tError occurred when creating DMC2280 motor '%s'", motor); + SCWrite(pCon,pError,eError); + return NULL; + } + + /*FIXME Tell splint that there's no memory leak because pointers are being initialised here */ + /*@-mustfreeonly@*/ + pNew->name = (char *)malloc(sizeof(char)*(strlen(motor)+1)); + if (pNew->name == NULL) { + (void) SCWrite(pCon,"ERROR: no memory to allocate motor driver", + eError); + free(pNew); + return NULL; + } + strcpy(pNew->name, motor); + pNew->pCon = pCon; + pNew->home = 0.0; + pNew->fLower = 0.0;//(float)atof(argv[2]); + pNew->fUpper = 100.0;//(float)atof(argv[3]); + pNew->GetPosition = DMC2280GetPos; + pNew->RunTo = DMC2280Run; + pNew->GetStatus = DMC2280Status; + pNew->GetError = DMC2280Error; + pNew->TryAndFixIt = DMC2280Fix; + pNew->Halt = DMC2280Halt; + pNew->GetDriverPar = DMC2280GetPar; + pNew->SetDriverPar = DMC2280SetPar; + pNew->ListDriverPar = DMC2280List; + pNew->KillPrivate = KillDMC2280; + if ((pPtr=getParam(pCon, interp, params,UNITS,_REQUIRED)) == NULL) + return NULL; + sscanf(pPtr,"%s",pNew->units); + if ((pPtr=getParam(pCon, interp, params,MAXSPEED,_REQUIRED)) == NULL) + return NULL; + sscanf(pPtr,"%f",&(pNew->speed)); + pNew->maxSpeed = pNew->speed; + if ((pPtr=getParam(pCon, interp, params,MAXACCEL,_REQUIRED)) == NULL) + return NULL; + sscanf(pPtr,"%f",&(pNew->accel)); + pNew->maxAccel = pNew->accel; + if ((pPtr=getParam(pCon, interp, params,MAXDECEL,_REQUIRED)) == NULL) + return NULL; + sscanf(pPtr,"%f",&(pNew->decel)); + pNew->maxDecel = pNew->decel; + if ((pPtr=getParam(pCon, interp, params,"axis",_REQUIRED)) == NULL) + return NULL; + sscanf(pPtr,"%c",&(pNew->axisLabel)); + if ((pPtr=getParam(pCon, interp, params,"stepsPerX",_REQUIRED)) == NULL) + return NULL; + sscanf(pPtr,"%d",&(pNew->stepsPerX)); + if ((pPtr=getParam(pCon, interp, params,"motorHome",_OPTIONAL)) == NULL) + pNew->motorHome=0; + else + sscanf(pPtr,"%d",&(pNew->motorHome)); + if ((pPtr=getParam(pCon, interp, params,"absEnc",_OPTIONAL)) == NULL) + pNew->abs_endcoder=0; + else { + sscanf(pPtr,"%d",&(pNew->abs_endcoder)); + if ((pPtr=getParam(pCon, interp, params,"absEncHome",_REQUIRED)) == NULL) + pNew->absEncHome=0; + else + sscanf(pPtr,"%d",&(pNew->absEncHome)); + if ((pPtr=getParam(pCon, interp, params,"cntsPerX",_REQUIRED)) == NULL) + pNew->cntsPerX=1; + else + sscanf(pPtr,"%d",&(pNew->cntsPerX)); + } + /*@+mustfreeonly@*/ + + /* Set speed */ + snprintf(cmd,CMDLEN,"SP%c=%d", pNew->axisLabel, motSpeed(pNew, pNew->speed)); + if (FAILURE == DMC2280Send(pNew, cmd)) + exit(EXIT_FAILURE); + /* Set acceleration */ + snprintf(cmd,CMDLEN,"AC%c=%d", pNew->axisLabel, motAccel(pNew, pNew->accel)); + if (FAILURE == DMC2280Send(pNew, cmd)) + exit(EXIT_FAILURE); + /* Set deceleration */ + snprintf(cmd,CMDLEN,"DC%c=%d", pNew->axisLabel, motDecel(pNew, pNew->decel)); + if (FAILURE == DMC2280Send(pNew, cmd)) + exit(EXIT_FAILURE); + /* TODO Initialise current position and target to get a sensible initial list output */ + return (MotorDriver *)pNew; +} + + + + + diff --git a/site_ansto/motor_dmc2280.h b/site_ansto/motor_dmc2280.h new file mode 100644 index 00000000..d4286fa0 --- /dev/null +++ b/site_ansto/motor_dmc2280.h @@ -0,0 +1,17 @@ +/*-------------------------------------------------------------------------- + * dmc2280.h + + The Galil motion controller driver include file + + Nick Hauser, March 2004 + + copyright: see implementation file. +---------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif +MotorDriver *CreateDMC2280(SConnection *pCon, int argc, char *argv[]); +#ifdef __cplusplus +} +#endif diff --git a/site_ansto/motor_driver.h b/site_ansto/motor_driver.h new file mode 100644 index 00000000..50483b11 --- /dev/null +++ b/site_ansto/motor_driver.h @@ -0,0 +1,24 @@ +/*-------------------------------------------------------------------------- +----------------------------------------------------------------------------*/ + +#define MOTREDO -1 +#define MOTFAIL 0 +#define MOTOK 1 + + typedef struct __AbstractMoDriv { + /* general motor driver interface fields. REQUIRED! */ + float fUpper; /* upper limit */ + float fLower; /* lower limit */ + char *name; + int (*GetPosition)(void *self, float *fPos); + int (*RunTo)(void *self,float fNewVal); + int (*GetStatus)(void *self); + void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen); + int (*TryAndFixIt)(void *self, int iError,float fNew); + int (*Halt)(void *self); + int (*GetDriverPar)(void *self, char *name, float *value); + int (*SetDriverPar)(void *self,SConnection *pCon, char *name, + float newValue); + void (*ListDriverPar)(void *self, char *motorName, SConnection *pCon); + void (*KillPrivate)(void *self); + } MotorDriver; diff --git a/site_ansto/refl2t.c b/site_ansto/refl2t.c new file mode 100644 index 00000000..12b20c22 --- /dev/null +++ b/site_ansto/refl2t.c @@ -0,0 +1,403 @@ +/*--------------------------------------------------------------------------- + REFL2T.c + +Paul Hathaway, Nick Hauser, Mark Koennecke, February 2004 +---------------------------------------------------------------------------*/ +#include +#include +#include +#include "fortify.h" +#include +#include "sics.h" +#include "motor.h" +#include "obpar.h" + +#define DEBUG 1 + +#define MAXMOT 3 +#define MAXPAR 13 + +#define PI 3.14157 + +#include "refl2t.h" + + +/* detector height movement */ +#define MOTCOZ 0 +/* detector movement along main axis */ +#define MOTCOY 1 +/* whole sample table height movement */ +#define MOTSOZ 2 + + +/*====================================================================== + The core of it all: The calculation of the settings for the various + motors. +========================================================================*/ + static int CalculateREFL(pRefl2T self, SConnection *pCon, float fNew) + { + float fDetPos, HeightOffset, DetLength; + int iRet; + +/* assume: solid sample, horizontal beam, surface at height zero */ +/* read vals of motor coy */ + iRet = MotorGetSoftPosition(self->aEngine[MOTCOY],pCon,&fDetPos); + if(iRet != 1) + { + return iRet; + } + + HeightOffset = ObVal(self->aParameter,PARDHO); + DetLength = ObVal(self->aParameter,PARDDD) + fDetPos; + +/* calculate det height above beam axis */ +/* add detector offset height */ + + fNew = DetLength * tan((double)(fNew * PI / 180.0)) + HeightOffset ; + self->fTarget = fNew; + return 1; + +/* Replacement code using MotEntry structure + self->toStart[MOTCOZ].pMot = self->aEngine[MOTCOZ]; + strcpy(self->toStart[MOTCOZ].pName,self->aEngine[MOTCOZ]->name); + self->toStart[MOTCOZ].fTarget = DetLength * tan((double)(fNew * PI / 180.0)) + HeightOffset; + */ + } + +/*======================================================================== + Definition of interface functions. +=========================================================================*/ + static long R2TSetValue(void *pData, SConnection *pCon, float fNew) + { + int i, iRet; + pIDrivable pDriv = NULL; + pRefl2T self = (pRefl2T) pData; + + assert(self); + + /* calculation */ + iRet = CalculateREFL(self,pCon,fNew); + if(iRet != 1) + { + return iRet; + } + + /* start them all */ + /* for(i = 0; i < self->iStart; i++) + {*/ + pDriv = self->aEngine[MOTCOZ].pMot->pDescriptor->GetInterface( + self->aEngine[MOTCOZ].pMot,DRIVEID); /* DRIVEID ??? */ + if(pDriv != NULL) + { + iRet = pDriv->SetValue(self->tEngine[MOTCOZ].pMot,pCon, + self->fTarget); /* works for one motor MOTCOZ */ + if(iRet != OKOK) + { + return iRet; + } + } + /* } */ + return OKOK; + } + + +/*-------------------------------------------------------------------------*/ + static int R2THalt(void *pData) + { + int i, iRet; + pIDrivable pDriv = NULL; + pRefl2T self = (pRefl2T) pData; + + assert(self); + + /* stop them all */ + /*for(i = 0; i < self->iStart; i++) + {*/ + pDriv = self->aEngine[MOTCOZ].pMot->pDescriptor->GetInterface( + self->aEngine[MOTCOZ].pMot,DRIVEID); + if(pDriv != NULL) + { + iRet = pDriv->Halt(self->aEngine[MOTCOZ].pMot); + } + /* } */ + return OKOK; + } +/*-----------------------------------------------------------------------*/ + static int R2TCheck(void *pData, float fNew, char *error, int iErrLen) + { + int i, iRet; + pIDrivable pDriv = NULL; + pRefl2T self = (pRefl2T) pData; + SConnection *pDumCon = NULL; + +/* Define code for this function */ + assert(self); + pDumCon = SCCreateDummyConnection(pServ->pSics); + assert(pDumCon); + + /* calculation */ + iRet = CalculateREFL(self,pDumCon,fNew); + SCDeleteConnection(pDumCon); + if(iRet != 1) + { + return iRet; + } + + /* check them all */ +/* for(i = 0; i < self->iStart; i++) + {*/ + pDriv = self->aEngine[MOTCOZ].pMot->pDescriptor->GetInterface( + self->aEngine[MOTCOZ].pMot,DRIVEID); + if(pDriv != NULL) + { + iRet = pDriv->CheckLimits(self->aEngine[MOTCOZ].pMot, + self->aEngine[MOTCOZ].fTarget, + error,iErrLen); + if(iRet != 1) + { + return iRet; + } + } + /* } */ + return 1; + } + + static float R2TGetValue(void *pData, SConnection *pCon) + { + + pRefl2T self = (pRefl2T) pData; + + assert(self); + + return fResult; + } + + static void *R2TGetInterface(void *pData, int iID) + { + pRefl2T self = (pRefl2T) pData; + + assert(self); + if(iID == DRIVEID) + { + return self->pDriv; + } + return NULL; + } + + + static void Refl2TKill(void *pData) + { + pRefl2T self = (pRefl2T) pData; + + if(self == NULL) + return; + + if(self->pDes) + DeleteDescriptor(self->pDes); + + if(self->pDriv) + free(self->pDriv); + + if(self->aParameter) + ObParDelete(self->aParameter); + + free(self); + } +/*-------------------------------------------------------------------------- + Initialization: All is done from the Factory function. This takes an Tcl + array as parameter which is supposed to hold the names of all motors. + This must fail if one of the motors cannot be accessed. +--------------------------------------------------------------------------*/ + int Refl2TFactory(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) + { + pRefl2T pNew; + int i, iRet; + char pBueffel[512]; + char *pMot = NULL; + + if(argc < 1) + { + SCWrite(pCon, + "ERROR: Insufficient number of arguments to Refl2tFactory", + eError); + return 0; + } + + /* allocate space ..............*/ + pNew = (pRefl2T)malloc(sizeof(Refl2T)); + if(!pNew) + { + SCWrite(pCon,"ERROR: out of memory in Refl2TFactory",eError); + return 0; + } + memset(pNew,0,sizeof(Refl2T)); + pNew->pDes = CreateDescriptor("Refl2T"); + pNew->aParameter = ObParCreate(MAXPAR); + pNew->pDriv = CreateDrivableInterface(); + if( (!pNew->pDes) || (!pNew->aParameter) || (!pNew->pDriv) ) + { + SCWrite(pCon,"ERROR: out of memory in Refl2TFactory",eError); + Refl2TKill(pNew); + return 0; + } + + /* find the motors*/ + pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"coz",TCL_GLOBAL_ONLY); + if(!pMot) + { + SCWrite(pCon,"ERROR: no value for coz motr found",eError); + Refl2TKill(pNew); + return 0; + } + pNew->aMot[MOTCOZ] = FindMotor(pSics,pMot); + if(!pNew->aEngine[MOTCOZ]) + { + sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot); + SCWrite(pCon,pBueffel,eError); + Refl2TKill(pNew); + return 0; + } + + pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"coy",TCL_GLOBAL_ONLY); + if(!pMot) + { + SCWrite(pCon,"ERROR: no value for coy motor found",eError); + Refl2TKill(pNew); + return 0; + } + pNew->aEngine[MOTCOY] = FindMotor(pSics,pMot); + if(!pNew->aEngine[MOTCOY]) + { + sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot); + SCWrite(pCon,pBueffel,eError); + Refl2TKill(pNew); + return 0; + } + + pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"soz",TCL_GLOBAL_ONLY); + if(!pMot) + { + SCWrite(pCon,"ERROR: no value for coz motor found",eError); + Refl2TKill(pNew); + return 0; + } + pNew->aEngine[MOTSOZ] = FindMotor(pSics,pMot); + if(!pNew->aEngine[MOTSOZ]) + { + sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot); + SCWrite(pCon,pBueffel,eError); + Refl2TKill(pNew); + return 0; + } + + /* initialize parameters */ + ObParInit(pNew->aParameter,PARDDD,"detectord",1400.,usMugger); + ObParInit(pNew->aParameter,PARDHO,"heightoffset",50.,usMugger); + ObParInit(pNew->aParameter,PARDSO,"stageoffset",50.,usMugger); + + /* initialize interfaces */ + pNew->pDes->GetInterface = R2TGetInterface; + pNew->pDes->SaveStatus = R2TSave; + pNew->pDriv->Halt = R2THalt; + pNew->pDriv->CheckLimits = R2TCheck; + pNew->pDriv->SetValue = R2TSetValue; + pNew->pDriv->CheckStatus = R2TStatus; + pNew->pDriv->GetValue = R2TGetValue; + + /* install commands */ + iRet = AddCommand(pSics,argv[1], + Refl2TAction,Refl2TKill,pNew); + if(!iRet) + { + sprintf(pBueffel,"ERROR: duplicate command %s NOT created", + argv[1]); + SCWrite(pCon,pBueffel,eError); + Refl2TKill(pNew); + return 0; + } + return 1; + } + +/*----------------------------------------------------------------------*/ + int Refl2TAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) + { + pRefl2T self = (pRefl2T)pData; + char pBueffel[256]; + float fVal; + double dVal; + ObPar *pPar = NULL; + int iRet; + + assert(self); + + if(argc > 1) + { + strtolower(argv[1]); + /* deal with list */ + if(strcmp(argv[1],"list") == 0) + { + R2TList(self,pCon,argv[0]); + return 1; + } + /* otherwise it should be a parameter command */ + if(argc >= 3) + { + iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&dVal); + if(iRet != TCL_OK) + { + sprintf(pBueffel,"ERROR: failed to convert %s to number", + argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + iRet = ObParSet(self->aParameter,argv[0],argv[1],(float)dVal,pCon); + if(iRet) + { + SCSendOK(pCon); + } + return iRet; + } + else /* argc = 2 */ + { + pPar = ObParFind(self->aParameter,argv[1]); + if(!pPar) + { + sprintf(pBueffel,"ERROR: parameter %s NOT found",argv[1]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + sprintf(pBueffel,"%s.%s = %f",argv[0],pPar->name, pPar->fVal); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } + else + { + fVal = self->pDriv->GetValue(self,pCon); + sprintf(pBueffel," %s = %f", argv[0], fVal); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } + + static void R2TList(pRefl2T self, SConnection *pCon, char *name) + { + char pBueffel[132]; + Tcl_DString tString; + + assert(pCon); + assert(self); + + Tcl_DStringInit(&tString); + sprintf(pBueffel, + "%s.detectord %f \n", name, ObVal(self->aParameter,PARDDD)); + Tcl_DStringInit(&tString); + sprintf(pBueffel, + "%s.heightoffset %f \n", name, ObVal(self->aParameter,PARDHO)); + Tcl_DStringInit(&tString); + sprintf(pBueffel, + "%s.sampleoffset %f \n", name, ObVal(self->aParameter,PARDSO)); + } + diff --git a/site_ansto/refl2t.h b/site_ansto/refl2t.h new file mode 100644 index 00000000..9fb8e63a --- /dev/null +++ b/site_ansto/refl2t.h @@ -0,0 +1,49 @@ +/*********************************************************** +* Simple virtual 2 theta driver for the RRR Reflectometer * +* * +* Paul Hathaway, Nick Hauser, Mark Koennecke. 4 Feb 2004. * +************************************************************/ + +#define MAXMOT = 3; + +/* aMot is the array of motors that includes the + 1. sample stage height motor + 2. detector x motor + 3. detector z motor +*/ + + typedef struct __REFL2T { + pObjectDescriptor pDes; + pIDrivable pDriv; + pMotor aEngine[MAXMOT]; + /* MotEntry toStart[]; */ + ObPar *aParameter; + float fTarget; + }Refl2T; + +#ifndef REFL2T +#define REFL2T + + typedef struct __REFL2T *pRefl2T; + + int Refl2TFactory(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + int Refl2TAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +#endif + +/* distance sample to detector */ +#define PARDDD = 0; +/* distance offset for height of detector */ +#define PARDHO = 1; +/* distance offset for sample height */ +#define PARDSO = 2; + + typedef struct { + pMotor pMot; + char pName[80]; + float fTarget; + int iLast; + }MotEntry, *pMotEntry; + diff --git a/site_ansto/site_ansto.c b/site_ansto/site_ansto.c new file mode 100644 index 00000000..a4eb58ae --- /dev/null +++ b/site_ansto/site_ansto.c @@ -0,0 +1,238 @@ +/*------------------------------------------------------------------------ + File: anstoSite.c + + This is the site specific interface to SICS for ANSTO. This file implements + the interface defined in ../site.h + + Copyright: see file Copyright.txt + + Template: Mark Koennecke, June 2003 + Nick Hauser, Paul Hathaway, May 2004 + -----------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include + +/* site-specific driver header files */ +#include "motor_asim.h" +#include "itc4.h" +/* Added code for new LH45 and Lakeshore 340 drivers */ +#include "lh45.h" +#include "lakeshore340.h" +/* + from tcpdornier.c +*/ +extern int VelSelTcpFactory(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); +extern pCodri MakeTcpDoChoDriver(char *tclArray, SConnection *pCon); + + +void SiteInit(void) { + +#define INIT(F) { void F(void); F(); } +/* insert here initialization routines ... */ + +} + +static pSite /*@null@*/ siteANSTO = NULL; + +/*----------------------------------------------------------------------*/ +static void AddCommands(SicsInterp *pInter) +{ +// int iRet; +// SConnection *pDummyConn; + (void) AddCommand(pInter,"MakeTCPSelector",VelSelTcpFactory,NULL,NULL); + /* + * Initialisation: Force execution here or use config script + */ +// pDummyConn = SCCreateDummyConnection(pInter); +// iRet = InterpExecute(pInter,pDummyConn,"config outcode warning"); +// iRet = InterpExecute(pInter,pDummyConn,"InstallSinfox"); +// iRet = InterpExecute(pInter,pDummyConn,"InstallProtocolHandler"); +// SCDeleteConnection(pDummyConn); +} +/*---------------------------------------------------------------------*/ +static void RemoveCommands(SicsInterp *pSics){ +// RemoveCommand(pInter,"InstallProtocolHandler"0); +// RemoveCommand(pInter,"InstallSinfox"); +} +/*-------------------------------------------------------------------*/ +/*@null@*/ static pMotor CreateMotorAnsto(SConnection *pCon, int argc, char *argv[]) +{ + MotorDriver *pDriver = NULL; + pMotor pNew = NULL; + Tcl_Interp *pTcl = NULL; + char pBueffel[132]; + + /* create the motor */ + strtolower(argv[1]); + if(strcmp(argv[1],"dmc2280") == 0) { + pDriver = (MotorDriver *)CreateDMC2280(pCon,argv[0],argv[2]); + if(!pDriver){ + return NULL; + } + pNew = MotorInit("DMC2280",argv[0],pDriver); + if(!pNew) { + sprintf(pBueffel,"ERROR:SITE: Failure to create motor %s",argv[1]); + SCWrite(pCon,pBueffel,eError); + return NULL; + } + } + if(strcmp(argv[1],"asim") == 0) { + pDriver = (MotorDriver *)CreateASIM(pCon,argc-2,&argv[2]); + if(!pDriver){ + return NULL; + } + pNew = MotorInit("ASIM",argv[0],pDriver); + if(!pNew) { + sprintf(pBueffel,"ERROR:SITE: Failure to create motor %s",argv[1]); + SCWrite(pCon,pBueffel,eError); + return NULL; + } + } + + + + return pNew; +} +/*extern pCounterDriver CreateCtrNitio10(SConnection *pCon,char *name,int argc,char *argv[]); */ +/*-------------------------------------------------------------------*/ +static pCounterDriver CreateCounterDriverAnsto(SConnection *pCon, + int argc, + char *argv[]){ + pCounterDriver pNew = NULL; + if(strcmp(argv[2],"nitio10") == 0){ + if(argc < 4){ + SCWrite(pCon, + "ERROR:SITE: Insufficient arguments for NITIO10 counter", + eError); + return NULL; + } +/* pNew = CreateCtrNitio10(pCon,argv[1],argc-3,&argv[3]);*/ + } + return pNew; +} +/*-------------------------------------------------------------------*/ +static HistDriver *CreateHistMem(char *name, pStringDict pOptions){ + HistDriver *pNew = NULL; + + if(strcmp(name,"anstohm") == 0){ +//#ifdef __cplusplus + printf("try to CreateAnstoHM() ...\n"); +// pNew = CreateAnstoHM(pOptions); +//#endif /* __cplusplus */ + } + + if(strcmp(name,"hm_mrpd") == 0){ + printf("try to Create HM for MRPD ...\n"); +// pNew = CreateHmMrpd(pOptions); + } + + if(strcmp(name,"hm_asim") == 0){ +// pNew = CreateHmAsim(pOptions); + } + + return pNew; +} +/*-------------------------------------------------------------------*/ +static pVelSelDriv CreateVelSelDriv(char *name, char *array, + Tcl_Interp *pTcl){ + pVelSelDriv pNew = NULL; + return pNew; +} +/*-------------------------------------------------------------------*/ +static pCodri CreateController(SConnection *pCon,int argc, char *argv[]){ + pCodri pNew = NULL; + if(strcmp(argv[0],"tcpdocho") == 0){ + if(argc < 2){ + SCWrite(pCon,"ERROR: insufficient number of arguments for creating TcpDoCho", + eError); + return NULL; + } + return MakeTcpDoChoDriver(argv[1], pCon); + } + return pNew; +} +/*------------------------------------------------------------------*/ +static pEVControl InstallEnvironmentController(SicsInterp *pSics, + SConnection *pCon, + int argc, char *argv[]){ + int status; + pEVControl pNew = NULL; + pEVDriver pDriv = NULL; + strtolower(argv[3]); + + + /* Added code for new LH45 driver */ + if(strcmp(argv[3],"lh45") == 0) { + pDriv = CreateLH45Driver(argc-4,&argv[4]); + if(pDriv){ + pNew = CreateEVController(pDriv,argv[2],&status); + if(pNew != NULL){ + AddCommand(pSics,argv[2],LH45Wrapper,DeleteEVController, + pNew); + } + } + } + + /* Added code for new Lakeshore 340 driver */ + if(strcmp(argv[3],"lakeshore340") == 0) { + pDriv = CreateLAKESHORE340Driver(argc-4,&argv[4]); + if(pDriv){ + pNew = CreateEVController(pDriv,argv[2],&status); + if(pNew != NULL){ + AddCommand(pSics,argv[2],LAKESHORE340Wrapper,DeleteEVController, + pNew); + } + } + } + + return pNew; +} +/*-----------------------------------------------------------------*/ +static int ConfigureScan(pScanData self, char *option){ + if(!self) { + return 0; + } + + return 0; +} +/*--------------------------------------------------------------------*/ +static void KillSite(void *site){ + free(site); + siteANSTO = NULL; +} +/*--------------------------------------------------------------------- + The scheme here goes along the lines of the singleton design pattern + ---------------------------------------------------------------------*/ +pSite getSite(void) +{ + if(siteANSTO == NULL) + { + siteANSTO = (pSite)malloc(sizeof(Site)); + /* + we cannot go on if we do not even have enough memory to allocate + the site data structure + */ + assert(siteANSTO); + /* + initializing function pointers + */ + siteANSTO->AddSiteCommands = AddCommands; + siteANSTO->RemoveSiteCommands = RemoveCommands; + siteANSTO->CreateMotor = CreateMotorAnsto; + siteANSTO->CreateCounterDriver = CreateCounterDriverAnsto; + siteANSTO->CreateHistogramMemoryDriver = CreateHistMem; + siteANSTO->CreateVelocitySelector = CreateVelSelDriv; + siteANSTO->CreateControllerDriver = CreateController; + siteANSTO->InstallEnvironmentController = InstallEnvironmentController; + siteANSTO->ConfigureScan = ConfigureScan; + siteANSTO->KillSite = KillSite; + } + return siteANSTO; +} + diff --git a/site_ansto/site_dummy.c b/site_ansto/site_dummy.c new file mode 100644 index 00000000..0eb28b28 --- /dev/null +++ b/site_ansto/site_dummy.c @@ -0,0 +1,131 @@ +/*------------------------------------------------------------------------ + D U M M Y + + This is an empty site interface for SICS. Can be used as a starting + point for own site specific stuff. + + copyright: see file COPYRIGHT + + Mark Koennecke, June 2003 + -----------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include "anstohm.h" +#include "dmc2143.h" + +static pSite siteANSTO = NULL; + +/*----------------------------------------------------------------------*/ +static void AddCommands(SicsInterp *pInter){ + //AddCommand(pInter,"MakeRefl2T",Refl2TFactory,NULL,NULL); +} +/*---------------------------------------------------------------------*/ +static void RemoveCommands(SicsInterp *pSics){ + //RemoveCommand(pInter,"MakeRefl2T"); +} +/*-------------------------------------------------------------------*/ +static pMotor CreateMotor(SConnection *pCon, int argc, char *argv[]){ + + MotorDriver *pDriver = NULL; + pMotor pNew = NULL; + Tcl_Interp *pTcl = NULL; + char pBueffel[132]; + + /* create the motor */ + strtolower(argv[1]); + if(strcmp(argv[1],"dmc2143") == 0){ + pDriver = (MotorDriver *)CreateDMC2143(pCon,argc-2,&argv[2]); + if(!pDriver){ + return NULL; + } + pNew = MotorInit("DMC2143",argv[0],pDriver); + if(!pNew){ + sprintf(pBueffel,"Failure to create motor %s",argv[1]); + SCWrite(pCon,pBueffel,eError); + return NULL; + } + } + return pNew; +} +/*-------------------------------------------------------------------*/ +static pCounterDriver CreateAnstoCounterDriver(SConnection *pCon, + int argc, + char *argv[]){ + pCounterDriver pNew = NULL; + return pNew; +} +/*-------------------------------------------------------------------*/ +static HistDriver *CreateHistMem(char *name, pStringDict pOptions){ + HistDriver *pNew = NULL; + + if(strcmp(name,"anstohm") == 0){ + printf("try to CreateAnstoHM() ...\n"); +#ifdef __cplusplus + pNew = CreateAnstoHM(pOptions); +#endif /* __cplusplus */ + } + return pNew; +} +/*-------------------------------------------------------------------*/ +static pVelSelDriv CreateVelSelDriv(char *name, char *array, + Tcl_Interp *pTcl){ + pVelSelDriv pNew = NULL; + return pNew; +} +/*-------------------------------------------------------------------*/ +static pCodri CreateController(SConnection *pCon,int argc, char *argv[]){ + pCodri pNew = NULL; + return pNew; +} +/*------------------------------------------------------------------*/ +static pEVControl InstallEnvironmentController(SicsInterp *pSics, + SConnection *pCon, + int argc, char *argv[]){ + pEVControl pNew = NULL; + pEVDriver pDriv = NULL; + + return pNew; +} +/*-----------------------------------------------------------------*/ +static int ConfigureScan(pScanData self, char *option){ + return 0; +} +/*--------------------------------------------------------------------*/ +static void KillSite(void *site){ + free(site); + siteANSTO = NULL; +} +/*--------------------------------------------------------------------- + The scheme here goes along the lines of the singleton design pattern + ---------------------------------------------------------------------*/ +pSite getSite(void){ + if(siteANSTO == NULL){ + siteANSTO = (pSite)malloc(sizeof(Site)); + /* + we cannot go on if we do not even have enough memory to allocate + the site data structure + */ + assert(siteANSTO); + /* + initializing function pointers + */ + siteANSTO->AddSiteCommands = AddCommands; + siteANSTO->RemoveSiteCommands = RemoveCommands; + siteANSTO->CreateMotor = CreateMotor; + siteANSTO->CreateCounterDriver = CreateAnstoCounterDriver; + siteANSTO->CreateHistogramMemoryDriver = CreateHistMem; + siteANSTO->CreateVelocitySelector = CreateVelSelDriv; + siteANSTO->CreateControllerDriver = CreateController; + siteANSTO->InstallEnvironmentController = + InstallEnvironmentController; + siteANSTO->ConfigureScan = ConfigureScan; + siteANSTO->KillSite = KillSite; + } + return siteANSTO; +} +