From 37262eed19bbdc3876aa0620bd37fcd9876be19d Mon Sep 17 00:00:00 2001 From: smathis Date: Wed, 19 Nov 2025 16:10:05 +0100 Subject: [PATCH] First compiling commit --- .gitignore | 1 + .gitmodules | 3 + CMakeLists.txt | 143 + README.md | 70 + device/expmag.cxx | 7361 ++++++++++++++++++++++++++++++++++++++ device/expmag.h | 10 + device/spline.cxx | 741 ++++ device/spline.h | 40 + frontend/expmag_scfe.cxx | 123 + midas_lan_gpib | 1 + 10 files changed, 8493 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 device/expmag.cxx create mode 100644 device/expmag.h create mode 100644 device/spline.cxx create mode 100644 device/spline.h create mode 100644 frontend/expmag_scfe.cxx create mode 160000 midas_lan_gpib diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c795b05 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e156538 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "midas_lan_gpib"] + path = midas_lan_gpib + url = git@gitea.psi.ch:lin-midas-drivers/midas_lan_gpib.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..84a01f3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,143 @@ +cmake_minimum_required(VERSION 3.03) + +project(expmag VERSION 0.1) + +add_compile_options( + -Wall + -Wformat=2 + -Wno-format-nonliteral + -Wno-strict-aliasing + -Wuninitialized + -Wno-unused-function +) + +option( + BUILD_FRONTEND + "If ON, build the default frontend executable" + OFF +) + +set( + TCPIP_DRIVER_DIR + $ENV{MIDASSYS}/drivers/bus/tcpip.cxx + CACHE STRING + "path to tcpip driver that should be used" +) + +set( + DRIVERS + $ENV{MIDASSYS}/drivers/class/generic.cxx +) + +set(SYS_LIBS + pthread + util + rt + dl +) + +link_directories($ENV{MIDASSYS}/lib) +# Links to libmfe.a and libmidas.a +set(MIDAS_LIBS + mfe + midas + mscb +) + +set(LIBS ${SYS_LIBS} ${MIDAS_LIBS}) + +add_subdirectory(midas_lan_gpib) + +################################################################################ +## make tcpip library configurable +################################################################################ + +if(IS_DIRECTORY ${TCPIP_DRIVER_DIR}) + add_subdirectory( + # TODO not sure, should it be a submodule? does it really make sense to + # separate everything? + ${TCPIP_DRIVER_DIR} ./bus/tcpip + ) + + set( + LIBS + ${LIBS} + tcpip + ) +else() + set( + DRIVERS + ${DRIVERS} + ${TCPIP_DRIVER_DIR} + ) +endif() + +################################################################################ +## Device Library +################################################################################ + +add_library( + expmag + device/expmag.cxx + device/spline.cxx + ${DRIVERS} +) + +set_property( + TARGET + expmag + PROPERTY + CXX_STANDARD 11 +) + +target_include_directories( + expmag + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE + $ENV{MIDASSYS}/drivers + $ENV{MIDASSYS}/include + # This is redundant if MIDASSYS =/ Midas repo, since in that case the Midas + # CMakeLists.txt copies the needed file mstrlcpy.h into $ENV{MIDASSYS}/include + # But it doesn't do any harm here, so it is kept. + $ENV{MIDASSYS}/include/mscb +) + +target_link_libraries( + expmag + PUBLIC + midas_lan_gpib + ${LIBS} +) + +################################################################################ +## Test Frontend +################################################################################ + +if(${BUILD_FRONTEND}) + + add_executable( + expmag_fe + frontend/expmag_scfe.cxx + ) + + set_property( + TARGET + expmag_fe + PROPERTY + CXX_STANDARD 11 + ) + + target_include_directories( + expmag_fe + PRIVATE + $ENV{MIDASSYS}/drivers + $ENV{MIDASSYS}/include + ) + + target_link_libraries( + expmag_fe + expmag + ) + +endif() diff --git a/README.md b/README.md new file mode 100644 index 0000000..d8201da --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +# Main experimental magnet PS + +This repository contains the driver code and Midas frontend for the main +experimental magnet PS. + +TODO: Document flag EPICSGFA + +## Requirements + +Requires a Midas installation with the environment variable `MIDASSYS` pointing +to the built Midas artifacts and headers. + +## Build + +Clone this repository, enter the cloned directory, and then build via CMake. + +```bash +cmake -S "$(pwd)" -B -DBUILD_FRONTEND=ON +cmake --build --clean-first -- -j8 +``` + +## Run + +```bash +/expmag_scfe -e +``` + +## Including in Custom Frontend +To include this driver in a custom frontend, you should ensure the environment +variable `MIDASSYS` points to your system install and include a snippet in your +`CMakeLists.txt` similar to the following: + +```CMake +# If the path to the expmag repository is outside of the frontend +# repository, you also need to provide a location for the expmag +# artifacts as a second argument to `add_subdirectory` +# e.g. `./device/expmag` +add_subdirectory( + +) + +add_executable( + + + + : +) + +set_property( + TARGET + + PROPERTY + CXX_STANDARD 11 +) + +target_include_directories( + + PRIVATE + $ENV{MIDASSYS}/drivers + $ENV{MIDASSYS}/include +) + +target_link_libraries( + + expmag + + + : +) +``` diff --git a/device/expmag.cxx b/device/expmag.cxx new file mode 100644 index 0000000..babb684 --- /dev/null +++ b/device/expmag.cxx @@ -0,0 +1,7361 @@ +/* + 1 2 3 4 5 6 7 8 +12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +*/ +/********************************************************************\ + + Name: expmag_ebmusr.c + Created by: RA35 + + Contents: Experimental Magnets Device Driver. + Handles correlations between beam line power supplies + (PSIBL or EPICSGFA) and Gossen power supply. + + class driver is generic with Demand and Measured Variables + DF_PRIO_DEVICE device has priority over initial ODB value during startup + Demand[] channels are updated when Demand key is updated + but no Demand[] value changed. + generic.c has to be compiled without updating mirrored demand. + compilation flag is -DOMIT_GENERIC_MIRROR_UPDATE + +\******************************************************************/ + +#include +#include +#include +#include +#include "midas.h" +#include "msystem.h" +#include "device/spline.h" +#include "midas_lan_gpib.h" +#include "bus/tcpip.h" + +#ifdef EPICSGFA +#define GFA_SPECIFIC /* GFA specific handling of EPICS channels :COM: :SOL: */ +#include "epics_ca_private.h" /* device driver routines */ +#endif + +/* Modification history + *--------------------- + * 17-JUN-2013 RA36 Setting WEV again when not able to set field after set to zero + * and (idle > 24h) + * 17-JUN-2013 RA36 Bug Fix cm_msg( ,...%s... , ..) without argument. + * 17-JUN-2013 RA36 Increased wait time for WEH82 to ramp to zero + * 28-MAY-2016 RA36 Changed db_set_... and replaced sprintf by snprintf + * 27-JAN-2017 RA36 Fixed compilation errors + * 27-MAR-2017 RA36 WED not anymore set to -1 (neg. polarity) when setting WEDL + * 24-NOV-2017 RA36 porting to Midas 2.1 replaced tcpip_open by tcpip_connect, + * CMD_SET_ALL and CMD_GET_ALL are now obsolete, CMD_GET_DEFAULT_NAME + * is now CMD_GET_LABEL, CMD_GET_DEFAULT_THRESHOLD is now + * CMD_GET_THRESHOLD + * 14-JUL-2020 RA36 WEUL (-50 - 50A) for small field helmholtz coil added for DOLLY in PIE1 + * 27-APR-2023 RA36 wrapping #ifndef DOLLY_SET_TWO #endif around #define DOLLY_OTHER_SET_ZERO + * 01-APR-2025 RA36 Instrument DOLLY and definitions changed to VMS + * + */ + +//#define MIDEBUG /* essentials */ +//#define MIDEBUG1 /* more */ +//#define MIDEBUG2 /* exhaustive */ +//#define MIDEBUGC /* COMMANDS */ +//#define MIDEBUGT /* TCP/IP */ +//#define MIDEBUGG /* LAN/GPIB */ +//#define MIDEBUGE /* EPICS */ + +#ifndef VMS_SET_TWO +#define VMS_OTHER_SET_ZERO /* when setting a magnet set the other magnet to zero */ + /* was the default behavior before 2017 */ +#endif /* #ifndef VMS_SET_TWO */ + +#define EXPMAG_NONE 0 +#define EXPMAG_POWEROFF 2 +#define EXPMAG_POWERON 4 +#define EXPMAG_SETTING 8 +#define EXPMAG_ATVALUE 16 +#define EXPMAG_DEVICEERROR 32 +#define EXPMAG_OUTOFRANGE 64 + +/*---- globals -----------------------------------------------------*/ + +#define MAX_ERROR 15 /* max. number of error messages per device */ +#define DELTA_TIME_ERROR 3600 /* reset errorcount of device after this time [sec] */ +#define DEFAULT_TIMEOUT 10000 /* 10 sec. */ + +#define SSP120_LANGPIB_SUPPORT /* use Gossen SSPxxx with lan/GPIB server */ +//#define SSP120_TCPIP_SUPPORT /* use Gossen SSPxxx with RS232 terminal server */ + +#ifdef SSP120_TCPIP_SUPPORT +#define SSP120_TCPIP_RECONNECT /* try reconnect after communication error */ +#endif + +#ifdef SSP120_LANGPIB_SUPPORT +#define SSP120_LANGPIB_RECONNECT /* try reconnect after communication error */ +#endif + +#define MAX_ERROR_SSP 15 /* max. number of error messages for Gossen SSP */ +#define DEFAULT_TIMEOUT_SSP 4000 /* default timeout for Gossen SSP */ + +/* Store any parameters the device driver needs in the following + structure. Edit the EXPMAG_SETTINGS_STR accordingly. */ +#ifndef EMNDEVS +#define EMNDEVS 9 /* number of experimental magnets */ +#endif + +typedef struct { + char instrument[16]; /* instrument GPS, DOLLY now VMS, GPD */ + char area[16]; /* 2ndary beamline area PIM3, MUE1, PIE1, ... */ + char zfc_used; /* zero field compensation used : Y/N */ + int epics_channels; /* number of EPICS channels in /Devices/EXPMAG/EPICS/DD*/ + char device[EMNDEVS][16]; /* device names WEDAMP WEUDAC WED .... */ + char type[EMNDEVS][16]; /* device type MAG|PSIBL|GOSSEN|IPS120|EPICSGFA */ + char server[EMNDEVS][32]; /* "information server" : + * CHAN|MAG|EPICS|| + * CHAN : use communication handle of CHAN + * + * MAG : forward result to magnet + * EPICS: set channel is address/1000 + * get channel is rest of division address/1000*/ + int address[EMNDEVS]; /* ||| + *1000 + */ + char calibration[EMNDEVS][32]; /* calibration file name */ + char direction[EMNDEVS]; /* calibration direction */ + float scale[EMNDEVS]; /* scale */ + float offset[EMNDEVS]; /* offset */ + char unit[EMNDEVS][8]; /* unit G,T,DAC,... */ + int minval[EMNDEVS]; /* min. value of device DAC */ + int maxval[EMNDEVS]; /* max. value of device DAC */ + float minrval[EMNDEVS]; /* min. value of device G,T,A,... */ + float maxrval[EMNDEVS]; /* max. value of device G,T,A,... */ + char title[EMNDEVS]; /* update run title flag */ + int ndigits[EMNDEVS]; /* number of decimal digits */ + char used[EMNDEVS]; /* Y=device is used N=device is not used */ + DWORD expiration[EMNDEVS]; /* expiration time */ + int status[EMNDEVS]; /* status */ +} EXPMAG_SETTINGS; + +#define EXPMAG_SETTINGS_STR "\ +Instrument = STRING : [16] NONE\n\ +Area = STRING : [16] NONE\n\ +ZFC Used = CHAR : N\n\ +EPICS Channels = INT : 0\n\ +Device = STRING[9] : \n\ +[16] NONE \n\ +[16] NONE \n\ +[16] NONE \n\ +[16] NONE \n\ +[16] NONE \n\ +[16] NONE \n\ +[16] NONE \n\ +[16] NONE \n\ +[16] NONE \n\ +Type = STRING[9] : \n\ +[16] NONE \n\ +[16] NONE \n\ +[16] NONE \n\ +[16] NONE \n\ +[16] NONE \n\ +[16] NONE \n\ +[16] NONE \n\ +[16] NONE \n\ +[16] NONE \n\ +Server = STRING[9] : \n\ +[32] NONE \n\ +[32] NONE \n\ +[32] NONE \n\ +[32] NONE \n\ +[32] NONE \n\ +[32] NONE \n\ +[32] NONE \n\ +[32] NONE \n\ +[32] NONE \n\ +Address = INT[9] : \n\ +[0] -1 \n\ +[1] -1 \n\ +[2] -1 \n\ +[3] -1 \n\ +[4] -1 \n\ +[5] -1 \n\ +[6] -1 \n\ +[7] -1 \n\ +[8] -1 \n\ +Calibration = STRING[9] : \n\ +[32] NONE \n\ +[32] NONE \n\ +[32] NONE \n\ +[32] NONE \n\ +[32] NONE \n\ +[32] NONE \n\ +[32] NONE \n\ +[32] NONE \n\ +[32] NONE \n\ +Direction = CHAR[9] : \n\ +[0] N \n\ +[1] N \n\ +[2] N \n\ +[3] N \n\ +[4] N \n\ +[5] N \n\ +[6] N \n\ +[7] N \n\ +[8] N \n\ +Scale = FLOAT[9] : \n\ +[0] 0.0 \n\ +[1] 0.0 \n\ +[2] 0.0 \n\ +[3] 0.0 \n\ +[4] 0.0 \n\ +[5] 0.0 \n\ +[6] 0.0 \n\ +[7] 0.0 \n\ +[8] 0.0 \n\ +Offset = FLOAT[9] : \n\ +[0] 0.0 \n\ +[1] 0.0 \n\ +[2] 0.0 \n\ +[3] 0.0 \n\ +[4] 0.0 \n\ +[5] 0.0 \n\ +[6] 0.0 \n\ +[7] 0.0 \n\ +[8] 0.0 \n\ +Unit = STRING[9] : \n\ +[8] NONE \n\ +[8] NONE \n\ +[8] NONE \n\ +[8] NONE \n\ +[8] NONE \n\ +[8] NONE \n\ +[8] NONE \n\ +[8] NONE \n\ +[8] NONE \n\ +Minval = INT[9] : \n\ +[0] 0 \n\ +[1] 0 \n\ +[2] 0 \n\ +[3] 0 \n\ +[4] 0 \n\ +[5] 0 \n\ +[6] 0 \n\ +[7] 0 \n\ +[8] 0 \n\ +Maxval = INT[9] : \n\ +[0] 0 \n\ +[1] 0 \n\ +[2] 0 \n\ +[3] 0 \n\ +[4] 0 \n\ +[5] 0 \n\ +[6] 0 \n\ +[7] 0 \n\ +[8] 0 \n\ +Minrval = FLOAT[9] : \n\ +[0] 0.0 \n\ +[1] 0.0 \n\ +[2] 0.0 \n\ +[3] 0.0 \n\ +[4] 0.0 \n\ +[5] 0.0 \n\ +[6] 0.0 \n\ +[7] 0.0 \n\ +[8] 0.0 \n\ +Maxrval = FLOAT[9] : \n\ +[0] 0.0 \n\ +[1] 0.0 \n\ +[2] 0.0 \n\ +[3] 0.0 \n\ +[4] 0.0 \n\ +[5] 0.0 \n\ +[6] 0.0 \n\ +[7] 0.0 \n\ +[8] 0.0 \n\ +Title = CHAR[9] : \n\ +[0] N \n\ +[1] N \n\ +[2] N \n\ +[3] N \n\ +[4] N \n\ +[5] N \n\ +[6] N \n\ +[7] N \n\ +[8] N \n\ +Ndigits = INT[9] : \n\ +[0] 0 \n\ +[1] 0 \n\ +[2] 0 \n\ +[3] 0 \n\ +[4] 0 \n\ +[5] 0 \n\ +[6] 0 \n\ +[7] 0 \n\ +[8] 0 \n\ +Used = CHAR[9] : \n\ +[0] N \n\ +[1] N \n\ +[2] N \n\ +[3] N \n\ +[4] N \n\ +[5] N \n\ +[6] N \n\ +[7] N \n\ +[8] N \n\ +Expiration = DWORD[9] : \n\ +[0] 0 \n\ +[1] 0 \n\ +[2] 0 \n\ +[3] 0 \n\ +[4] 0 \n\ +[5] 0 \n\ +[6] 0 \n\ +[7] 0 \n\ +[8] 0 \n\ +Status = INT[9] : \n\ +[0] 0 \n\ +[1] 0 \n\ +[2] 0 \n\ +[3] 0 \n\ +[4] 0 \n\ +[5] 0 \n\ +[6] 0 \n\ +[7] 0 \n\ +[8] 0 \n\ +" + +/*----------------------------------------------------------------------------*/ + /* data necessary to perform cubic spline interpolation */ +typedef struct _CalibrationRec { + int direction; /* interpolation direction 1=forward, 0=reverse */ + int ncals; /* number of calibration points */ + double *x; + double *y; + double *s2f; /* coefficients for forward interpolation */ + double *s3f; + double *dyf; + double *s2r; /* coefficients for reverse interpolation */ + double *s3r; + double *dyr; +} CalibrationRec, *CalibrationPtr; + +/*----------------------------------------------------------------------------*/ + /* data necessary to handle RoadC device */ +typedef struct _RoadCRec { + char device[16]; + int number; + int DAClowlim; + int DACuplim; + double scale; + double precision; + double fullscale; + int DACtype; + char ioflag; + int ADCtype; + int DACspecialbit; + int DACroadaddress; + int DACCAMACstation; + int ADCspecialbit; + int ADCroadaddress; + int ADCCAMACstation; + int ADCchannel; + int ADCrange; + int poweron; /* TRUE=power is on, FALSE=power is off */ +} RoadCRec, *RoadCPtr; + +/*----------------------------------------------------------------------------*/ +typedef struct _DummyRec { /* dummy structure to avoid void * and pointer arithmetic */ + int dummy; +} DummyRec, *DummyPtr; + +/*----------------------------------------------------------------------------*/ + /* NOTE: this is copied from tcpip.c to be able to access fd */ +typedef struct { + char host[256]; + int port; + int debug; +} TCPIP_SETTINGS; + +typedef struct { + TCPIP_SETTINGS settings; + int fd; /* device handle for socket device */ +} TCPIP_INFO; + +int tcpip_connect(char *, int); +// 1.9.5 was int tcpip_open(char *, int); + +/*----------------------------------------------------------------------------*/ + +/* following structure contains private variables to the device + driver. It is necessary to store it here in case the device + driver is used for more than one device in one frontend. If it + would be stored in a global variable, one device could over- + write the other device's variables. */ + +typedef struct { + EXPMAG_SETTINGS expmag_settings; + RoadCPtr *roadc; + DummyPtr *tcpip; + DummyPtr *langpib; + CalibrationPtr *calibration; + float *threshold; + char varpath[512]; /* ODB path to variables directory */ + HNDLE hkey_demand; /* ODB key to demand array */ + HNDLE hkey_measured; /* ODB key to measured array */ + float set_values[EMNDEVS]; /* set values used to filter ODB array */ + float last_demand[EMNDEVS]; /* demand value when last reading */ + INT num_channels; + INT(*bd) (INT cmd, ...); /* bus driver entry function */ + void *bd_info; /* private info of bus driver */ + HNDLE hkey; /* ODB key for bus driver info */ + INT errorcount[EMNDEVS]; + DWORD lasterrtime[EMNDEVS]; + INT comerror[EMNDEVS]; /* communication error for Gosssen */ + INT state[EMNDEVS]; /* state of Gossen communication */ + /* tolerance checks for non epics devices e.g. GOSSEN */ + /* epics_ca_set_pending calls are used to block when out of tolerance range */ + INT tolisactive[EMNDEVS]; /* tolerance checking is active */ + INT tolwasout[EMNDEVS]; /* previous reading was out of tolerance */ +#ifdef EPICSGFA + CA_INFO *cainfo; /* EPICS Channel Access device driver */ + INT do_epics_reading; +#endif +} EXPMAG_INFO; + +/*----------------------------------------------------------------------------*/ + +typedef struct _ExpmagRec { + char instrument[16]; /* instrument GPS, DOLLY now VMS, GPD */ + char area[16]; /* 2ndary beamline area PIM3, MUE1, PIE1, ... */ + int channel; /* channel number of device */ + char device[16]; /* device names WEDDAC WEDAMP WED .... */ + char type[16]; /* device type MAG|PSIBL|GOSSEN|EPICSGFA */ + char server[32]; /* "information server" + * CHAN|MAG|EPICS|| + * */ + /* CHAN: use communication handle of CHAN */ + /* MAG : write result to demand value of MAG[address] */ + /* EPICS: decode set channel or get channel then call epics_ca_... function */ + int address; /* || + * <<:SOL:2 chan#>*1000+<:IST:2 chan#>>*/ + char calibration[32]; /* calibration file name */ + char direction; /* calibration direction F/R */ + float scale; /* scale */ + float offset; /* offset */ + char unit[8]; /* unit G,T,DAC,AMP,... */ + int minval; /* min. value of device DAC */ + int maxval; /* max. value of device DAC */ + float minrval; /* min. value of device G,T,AMP,... */ + float maxrval; /* max. value of device G,T,AMP,... */ + int title; /* 1 = update title */ + int ndigits; /* number of decimal digits */ + float threshold; +} ExpmagRec, *ExpmagPtr; + +/* + * NOTE: A REFERENCED DEVICE MUST BE FURTHER UP IN THE TABLE TO BE SURE THE DEVICE IS + * INITIALISED BEFORE THE REFERENCING DEVICE IS INITIALISED + */ + +ExpmagRec gtable[] = { +/* inst area ch device type server addr calibration file + cal. direction + scale offst unit + min max minr maxr title ndig threshold */ +#ifdef EPICSGFA + {"VMS", "PIE1", 0, "WEUAMP", "EPICSGFA", "EPICS", 2003, "NONE", 'N', 1.0, 0.0,"AMP", + 0, 0, 0.0, 500.0, 0, 3, 0.1}, + {"VMS", "PIE1", 1, "WEU", "MAG", "MAG", 0, "WEU_PIE1_NOV_12.TAB", 'R', 1.0, 0.0,"G", + 0, 0, 0.0, 4934.0, 1, 3, 0.001}, + {"VMS", "PIE1", 2, "WEULAMP", "EPICSGFA", "EPICS", 6007, "NONE", 'N', 1.0, 0.0,"AMP", + 0, 0, -50.0, 50.0, 0, 3, 0.1}, + {"VMS", "PIE1", 3, "WEUL", "MAG", "MAG", 2, "WEUL_PIE1_NOV_12.TAB", 'R', 1.0, 0.0,"G", + 0, 0,-500.0, 500.0, 1, 3, 0.001}, + {"VMS", "PIE1", 4, "WEVAMP", "EPICSGFA", "EPICS", 10011, "NONE", 'N', 1.0, 0.0,"AMP", + 0, 0,-110.0, 110.0, 0, 3, 0.1}, + {"VMS", "PIE1", 5, "WEV", "MAG", "MAG", 4, "WEV_PIE1_NOV_12.TAB", 'R', 1.0, 0.0,"G", + 0, 0,-145.434, 145.434, 1, 3, 0.001}, +#else + {"VMS", "PIE1", 0, "WEUDAC", "PSIBL", "server", 10000, "NONE", 'N', 1.0, 0.0, "DAC", + 1, 4095, 0.0, 0.0, 0, 0, 1.0}, + {"VMS", "PIE1", 1, "WEU", "MAG", "MAG", 0, "WEU_PIE1_AUG_98.TAB", 'R', 1.0, 0.0,"G", + 0, 0, 0.599, 4932.581, 1, 3, 0.001}, + //{"VMS", "PIE1", 2, "WEVDAC", "PSIBL", "CHAN", 0, "NONE", 'N', 1.0, 0.0, "DAC", 13, + // 692, 0.0, 0.0, 0, 0, 1.0}, /* MOD 24-SEP-2006 RA36 larger values */ + {"VMS", "PIE1", 2, "WEVDAC", "PSIBL", "CHAN", 0, "NONE", 'N', 1.0, 0.0, "DAC", 1, + 910, 0.0, 0.0, 0, 0, 1.0}, + //{"VMS", "PIE1", 3, "WEV", "MAG", "MAG", 2, "WEV_PIE1_SEP_02.TAB", 'R',1.0,0.0,"G", + // 0, 0, 2.86, 114.894, 1, 3, 0.001}, /* MOD 25-SEP-2006 RA36 larger values */ + {"VMS", "PIE1", 3, "WEV", "MAG", "MAG", 2, "NONE", 'N', 6.070, -2.154, "G", + 0, 0, 0.358, 150.25, 1, 3, 0.001}, +#endif +#ifdef EPICSGFA + /* currently not used in PIE3 */ +#endif +#ifdef EPICSGFA + {"GPS", "PIM3", 0, "WEDAMP", "EPICSGFA", "EPICS", 2003, "NONE", 'N', 1.0, 0.0, "AMP", + 0, 0, 0, 794.91, 0, 3, 0.001}, + {"GPS", "PIM3", 1, "WED", "MAG", "MAG", 0, "WED_MAY_17.TAB", 'R', 1.0, 0.0, "G", 0, 0, + 49.4795, 7800.0, 1, 3, 0.001}, + {"GPS", "PIM3", 2, "WEDLAMP", "EPICSGFA", "EPICS", 6007, "NONE", 'N', 1.0, 0.0, "AMP", + 0, 0, -50.0, 50.0, 0, 3, 0.001}, + {"GPS", "PIM3", 3, "WEDL", "MAG", "MAG", 2, "WEDL_MAY_17.TAB", 'R', 1.0, 0.0, "G", 0, + 0,-490.27, 490.27, 1, 3, 0.001}, + {"GPS", "PIM3", 4, "WEPAMP", "EPICSGFA", "EPICS", 10011, "NONE", 'N', 1.0, 0.0, "AMP", + 0, 0,-160.0, 160.0, 0, 3, 0.001}, + {"GPS", "PIM3", 5, "WEP", "MAG", "MAG", 4, "WEP_MAY_17.TAB", 'R', 1.0, 0.0, "G", 0, 0, + -108.457, 107.927, 1, 3, 0.001}, +#else + {"GPS", "PIM3", 0, "WEDDAC", "PSIBL", "server", 10000, "NONE", 'N', 1.0, 0.0, "DAC", + -1, 65535, 0.0, 0.0, 0, 0, 1.0}, + {"GPS", "PIM3", 1, "WED", "MAG", "MAG", 0, "WED_FEB_97.TAB", 'R', 1.0, 0.0, "G", 0, 0, + 8.118, 6421.500, 1, 3, 0.001}, + {"GPS", "PIM3", 2, "WEDLDAC", "PSIBL", "CHAN", 0, "NONE", 'N', 1.0, 0.0, "DAC", 1, + 1881, 0.0, 0.0, 0, 0, 1.0}, + {"GPS", "PIM3", 3, "WEDL", "MAG", "MAG", 2, "WEDL_MAY_95.TAB", 'R', 1.0, 0.0, "G", 0, + 0, 0.525, 451.838, 1, 3, 0.001}, + {"GPS", "PIM3", 4, "WEPDAC", "PSIBL", "CHAN", 0, "NONE", 'N', 1.0, 0.0, "DAC", 21, + 4095, 0.0, 0.0, 0, 0, 1.0}, + {"GPS", "PIM3", 5, "WEP", "MAG", "MAG", 4, "WEP_MAR_94.TAB", 'R', 1.0, 0.0, "G", 0, 0, + 0.001, 132.317, 1, 3, 0.001}, +#endif +#ifdef EPICSGFA + {"GPD", "MUE1", 0, "WEH82", "EPICSGFA", "EPICS", 2003, "NONE",'N', 1.0, 0.0,"AMP", + 0, 0, -1.0, 650.0, 0, 3, 0.1}, + {"GPD", "MUE1", 1, "HELM", "MAG", "MAG", 0, "WEH82_APR_12.TAB", 'R', 1.0, 0.0, "G",0, + 0, 0.0, 6666.0, 1, 3, 0.001}, +#else + {"GPD", "MUE1", 0, "HELMH2DAC", "PSIBL", "server", 10000, "NONE",'N', 1.0, 0.0, "DAC", + -1, 65535, 0.0, 0.0, 0, 0, 1.0}, + {"GPD", "MUE1", 1, "HELM", "MAG", "MAG", 0, "HELMH2_JUL_06.TAB", 'R', 1.0, 0.0, "G",0, + 0, 0.0, 6667.430, 1, 3, 0.001}, +#endif + {"GPD", "MUE1", 2, "GOSSENA", "GOSSEN", "PSGSXXX", 12, "NONE", 'N', 1.0, 0.0, "AMPS", + 0, 0, 0.0, 25.0, 0, 4, 0.0001}, // GOSSEN SSP 520 50 01-JUN-2007 RA36 + {"GPD", "MUE1", 3, "GOSSEN", "MAG", "MAG", 2, "NONE", 'N', 0.0954522, 0.0, "G", 0,0, + 0.0, 261.911, 1, 3, 0.001}, // GOSSEN SSP 520 50 + + {"TEST", "MUET", 0, "HELMHDAC", "PSIBL", "pc4656", 10000, "NONE", 'N', 1.0, 0.0,"DAC", + -65535, 1, 0.0, 0.0, 0, 0, 1.0}, + {"TEST", "MUET", 1, "HELM", "MAG", "MAG", 0, "NONE", 'N', -8.5062887, 0.0, "G", 0, 0, + 0.0, 5800.0, 1, 3, 0.001}, + {"TEST", "MUET", 2, "GOSSENA", "GOSSEN", "psgs001", 13, "NONE", 'N', 1.0, 0.0, "AMPS", + 0, 0, 0.0, 1.0, 0, 4, 0.0001}, + {"TEST", "MUET", 3, "GOSSEN", "MAG", "MAG", 2, "NONE", 'N', 0.095452228, 0.0, "G",0,0, + 0.0, 6.000, 1, 3, 0.001}, + {"TEST", "MUET", 4, "WEPDAC", "PSIBL", "CHAN", 0, "NONE", 'N', 1.0, 0.0, "DAC", 0, + 4096, 0.0, 0.0, 0, 0, 1.0}, + {"TEST", "MUET", 5, "WEDDAC", "PSIBL", "CHAN", 0, "NONE", 'N', 1.0, 0.0, "DAC", -1, + 65535, 0.0, 0.0, 0, 0, 1.0}, + {"TEST", "MUET", 6, "WED", "MAG", "MAG", 5, "WED_FEB_97.TAB", 'R', 1.0, 0.0, "G", 0,0, + 8.118, 6421.500, 1, 3, 0.001}, + {"TEST", "MUET", 7, "WEDLDAC", "PSIBL", "CHAN", 0, "NONE", 'N', 1.0, 0.0, "DAC", 1, + 1881, 0.0, 0.0, 0, 0, 1.0}, + {"TEST", "MUET", 8, "WEDL", "MAG", "MAG", 7, "WEDL_MAY_95.TAB", 'R', 1.0, 0.0, "G", 0, + 0, 0.525, 451.838, 1, 3, 0.001}, + +/* + * + * GPD MUE1 : HELMH2 = 65535/5100.0 [DAC]/[G] = 12.85 [DAC/G] + * new GPD negative DAC is used to connect Gossen + * + */ + + {""} /* empty record to signal end of table */ +}; + +#define NTABENT ((sizeof(gtable)/sizeof(ExpmagRec))-1) + +/*----------------------------------------------------------------------------*/ +INT gngets = 0; +/*----------------------------------------------------------------------------*/ + +INT expmag_exit(EXPMAG_INFO * info); +INT expmag_get(EXPMAG_INFO * info, INT channel, float *pvalue); + +INT odb_keepalive(EXPMAG_INFO * info); +INT roadc_device_init(EXPMAG_INFO *, INT); +INT odb_measured_update(EXPMAG_INFO *info); + +/*----------------------------------------------------------------------------*/ +/* remove trailing blanks */ +int strip_str(char *string) +{ + int len, lenn, i; + len = lenn = 0; + if (string != NULL) { + len = strlen(string); + for (i = len - 1; i >= 0; i--) { + if (*(string + i) == ' ') { + *(string + i) = '\0'; + } else + break; + } + lenn = strlen(string); + +#ifdef MIDEBUG2 + if (len != lenn) + cm_msg(MLOG, "", "strip_str : %s : %d blank(s) removed", string, len - lenn); +#endif + } + return (len - lenn); +} + +/*----------------------------------------------------------------------------*/ +/* remove trailing blanks from expmag settings */ +int expmag_settings_strip(EXPMAG_SETTINGS * pems) +{ + if (pems != NULL) { + int i; + + strip_str(pems->instrument); + strip_str(pems->area); + for (i = 0; i < EMNDEVS; i++) { + strip_str(pems->device[i]); + strip_str(pems->type[i]); + strip_str(pems->server[i]); + strip_str(pems->calibration[i]); + strip_str(pems->unit[i]); + } + } + return FE_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/* instrument is in global table */ +int expmag_instrument_there(EXPMAG_INFO * info) +{ + int retval; + + retval = 0; + if (info != NULL) { + int i; + for (i = 0; i < NTABENT; i++) { + if (strcmp(info->expmag_settings.instrument, gtable[i].instrument) == 0) { +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_instrument_there : instrument %s found", + info->expmag_settings.instrument); +#endif + retval++; + } + } +#ifdef MIDEBUG + if (retval == 0) + cm_msg(MLOG, "", "expmag_instrument_there : instrument %s not found", + info->expmag_settings.instrument); +#endif + } else { + cm_msg(MLOG, "", "expmag_instrument_there : Error NULL pointer to EXPMAG_INFO"); + } + + return retval; +} + +/*----------------------------------------------------------------------------*/ + +/* area of instrument is in global table */ +int expmag_area_there(EXPMAG_INFO * info) +{ + int retval; + + retval = 0; + if (info != NULL) { + int i; + for (i = 0; i < NTABENT; i++) { + if ((strcmp(info->expmag_settings.instrument, gtable[i].instrument) == 0) && + (strcmp(info->expmag_settings.area, gtable[i].area) == 0)) { +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_area_there : area %s for instrument %s found", + info->expmag_settings.area, info->expmag_settings.instrument); +#endif + retval++; + } + } +#ifdef MIDEBUG1 + if (retval == 0) + cm_msg(MLOG, "", "expmag_area_there : area %s for instrument %s not found", + info->expmag_settings.area, info->expmag_settings.instrument); +#endif + } else { + cm_msg(MLOG, "", "expmag_area_there : Error NULL pointer to EXPMAG_INFO"); + } + return retval; +} + +/*----------------------------------------------------------------------------*/ +/* copy table entry of channel of instrument in area */ +int get_expmag(char *instrument, char *area, int chan, ExpmagRec * pmrec) +{ + int retval; + + retval = 0; + if ((instrument != NULL) && (strlen(instrument) > 0) && (area != NULL) + && (strlen(area) > 0)) { + int i; + for (i = 0; i < NTABENT; i++) { + if ((strcmp(instrument, gtable[i].instrument) == 0) && + (strcmp(area, gtable[i].area) == 0) && (chan == gtable[i].channel)) { +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "get_expmag : %s %s channel %d found", instrument, area, + chan); + cm_msg(MLOG, "", "get_expmag : threshold = %f", gtable[i].threshold); +#endif + if (pmrec != NULL) + memcpy(pmrec, >able[i], sizeof(ExpmagRec)); + retval = 1; + break; + } + } +#ifdef MIDEBUG1 + if (retval == 0) + cm_msg(MLOG, "", "get_expmag : %s %s channel %d not found", instrument, area, + chan); +#endif + } else { + cm_msg(MLOG, "","get_expmag : Error invalid instrument name or invalid area name"); + retval = -1; + } + return retval; +} + +/*----------------------------------------------------------------------------*/ + +int expmag_get_default_settings(EXPMAG_INFO * info) +{ + + int retval; + + retval = 0; + if (info != NULL) { + int i, j; + ExpmagRec mrec; + + /* devices not initialised yet? */ + for (i = 0; i < EMNDEVS; i++) { + + if (get_expmag(info->expmag_settings.instrument, + info->expmag_settings.area, i, &mrec) > 0) { + + if (strncmp(info->expmag_settings.device[i], "NONE", 4) == 0) { + + /* copy default settings from table */ + strcpy(info->expmag_settings.device[i], mrec.device); + strcpy(info->expmag_settings.type[i], mrec.type); + strcpy(info->expmag_settings.server[i], mrec.server); + info->expmag_settings.address[i] = mrec.address; + strcpy(info->expmag_settings.calibration[i], mrec.calibration); + info->expmag_settings.direction[i] = mrec.direction; + info->expmag_settings.scale[i] = mrec.scale; + info->expmag_settings.offset[i] = mrec.offset; + strcpy(info->expmag_settings.unit[i], mrec.unit); + info->expmag_settings.minval[i] = mrec.minval; + info->expmag_settings.maxval[i] = mrec.maxval; + info->expmag_settings.minrval[i] = mrec.minrval; + info->expmag_settings.maxrval[i] = mrec.maxrval; + if (mrec.title == 1) + info->expmag_settings.title[i] = 'Y'; + else + info->expmag_settings.title[i] = 'N'; + + info->expmag_settings.ndigits[i] = mrec.ndigits; + /* NOTE: magnet entry in ODB must be checked, updated and initialised + * manually by setting Used to Y */ + info->expmag_settings.used[i] = 'N'; + + retval++; + + } else { +#ifdef MIDEBUG1 + cm_msg(MLOG, "", + "expmag_get_default_settings : Device %s already initialised", + info->expmag_settings.device[i]); +#endif + } + + /* copy threshold to device data */ + if (info->threshold != NULL) { + *(info->threshold + i) = mrec.threshold; +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "get_default_settings : threshold = %f", + *(info->threshold + i)); + } else { + cm_msg(MLOG, "", + "get_default_settings : info->threshold is NULL pointer"); +#endif + } + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_get_default_settings : channel %d found device=%s", + i, mrec.device); +#endif + } else { +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_get_default_settings : channel %d not found", i); +#endif + /* prevent channel from being used? */ + if (info->expmag_settings.used[i] == 'Y') { + info->expmag_settings.used[i] = 'N'; + cm_msg(MLOG, "", + "expmag_get_default_settings : WARNING channel %d was not " + "found in the table and is now disabled!", i); + } + } + + info->expmag_settings.expiration[i] = 0; + info->expmag_settings.status[i] = EXPMAG_NONE; + + } /* for all magnets */ + + } else { + cm_msg(MLOG, "", "expmag_get_default_settings Error NULL pointer to EXPMAG_INFO"); + retval = -1; + } + return retval; +} + +/*----------------------------------------------------------------------------*/ + +INT free_calibrationrec(CalibrationPtr pcal) +{ + if (pcal != NULL) { + if (pcal->x != NULL) { + free(pcal->x); + pcal->x = NULL; + } + if (pcal->y != NULL) { + free(pcal->y); + pcal->y = NULL; + } + if (pcal->s2f != NULL) { + free(pcal->s2f); + pcal->s2f = NULL; + } + if (pcal->s3f != NULL) { + free(pcal->s3f); + pcal->s3f = NULL; + } + if (pcal->dyf != NULL) { + free(pcal->dyf); + pcal->dyf = NULL; + } + if (pcal->s2r != NULL) { + free(pcal->s2r); + pcal->s2r = NULL; + } + if (pcal->s3r != NULL) { + free(pcal->s3r); + pcal->s3r = NULL; + } + if (pcal->dyr != NULL) { + free(pcal->dyr); + pcal->dyr = NULL; + } + } + return FE_SUCCESS; +} + +/*---- device driver routines --------------------------------------*/ + +INT expmag_settings_update(EXPMAG_INFO * info) +{ + HNDLE hDB, hkeydd; + int size; + INT status1; + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_settings_update DD settings update necessary"); +#endif + + if (info != NULL) { + + cm_get_experiment_database(&hDB, NULL); + + if ((status1 = db_find_key(hDB, info->hkey, "DD", &hkeydd)) == DB_SUCCESS) { + size = sizeof(info->expmag_settings); + db_set_record(hDB, hkeydd, &info->expmag_settings, size, 0); +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_settings_update() Updating DD settings"); +#endif + } else { + cm_msg(MLOG, "", "expmag_settings_update() ERROR key for DD not found" + " db_find_key() status = %d", status1); + } + } + return FE_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +int expmag_tcpip_sendr(EXPMAG_INFO * info, TCPIP_INFO * ptcpipinfo, int comchan, + char *send, char *recv, int *plen) +{ + int status, len, nerrs; + + nerrs = 0; + + cmd_again: + nerrs++; + status = CM_SUCCESS; + + if (ptcpipinfo != NULL) { + if (send != NULL) { +#ifdef MIDEBUGT + cm_msg(MLOG, "", "expmag_tcpip_sendr() sending >%s<", send); +#endif + /* NOTE: '\0' must be sent here to terminate command */ + len = tcpip(CMD_WRITE, ptcpipinfo, send, strlen(send) + 1); + if (len == -1) { + cm_msg(MLOG, "", "expmag_tcpip_sendr() : communication error while sending"); + info->errorcount[comchan]++; + } else if (len < strlen(send) + 1) { + cm_msg(MLOG, "", "expmag_tcpip_sendr() : ERROR sending >%s< was incomplete", + send); + info->errorcount[comchan]++; + } + } + + if (recv != NULL) { + *recv = '\0'; + if (plen != NULL) { +#ifdef MIDEBUGT1 + cm_msg(MLOG, "", "expmag_tcpip_sendr() receiving(*plen=%d)....", *plen); +#endif + /* + * replaced by CMD_GETS to be able to increase timeout without slowing down + * len = tcpip(CMD_READ, ptcpipinfo, recv, *plen, 500); // was 1000 + * // was 1000, problem with 50 14-SEP-2005 + * // now 500 + */ + /* reply from beamline server should always be terminated by \0 */ + len = tcpip(CMD_GETS, ptcpipinfo, recv, *plen, "", 15000); + +#ifdef MIDEBUGT + cm_msg(MLOG, "", "expmag_tcpip_sendr() status == len=%d", len); +#endif + if (len > 0) { + //int i; +#ifdef MIDEBUGT + cm_msg(MLOG, "", "expmag_tcpip_sendr() received >%s<", recv); + //for (i=0;ierrorcount[comchan]++; + *plen = 0; + *recv = '\0'; + if (len < 0) { + cm_msg(MLOG, "", + "expmag_tcpip_sendr() : comm error while receiving data"); + status = FE_ERR_DRIVER; + } else { +#ifdef MIDEBUGT + cm_msg(MLOG, "", "expmag_tcpip_sendr() : TIMEOUT receiving data"); +#endif + odb_keepalive(info); + + if (nerrs < 5) + goto cmd_again; + cm_msg(MERROR, "expmag_tcpip_sendr", "TIMEOUT receiving data"); + } + } + } else { + cm_msg(MLOG, "", "expmag_tcpip_sendr() : " + "ERROR NULL pointer to return number of characters read"); + status = FE_ERR_DRIVER; + } + } + + /* many errors try to reconnect to server */ + if ((nerrs > 0) && (info->errorcount[comchan] > MAX_ERROR + 60)) { + + info->errorcount[comchan] = MAX_ERROR + 1; + /* close connection */ + if (ptcpipinfo->fd != -1) { + shutdown(ptcpipinfo->fd, 2); + closesocket(ptcpipinfo->fd); + ptcpipinfo->fd = -1; + } + + /* open connection */ + ptcpipinfo->fd = + tcpip_connect(ptcpipinfo->settings.host, ptcpipinfo->settings.port); + // 1.9.5 was tcpip_open(ptcpipinfo->settings.host, ptcpipinfo->settings.port); + if (ptcpipinfo->fd != -1) + cm_msg(MLOG, "", "expmag_tcpip_sendr() : Reconnected to Beamline server %s", + ptcpipinfo->settings.host); + else + cm_msg(MERROR, "expmag_tcpip_sendr", + "Failed to reconnect to Beamline server %s", + ptcpipinfo->settings.host); + } + + } else { + cm_msg(MLOG, "", "expmag_tcpip_sendr() : ERROR NULL pointer to TCPIP_INFO record"); + status = FE_ERR_DRIVER; + } + return status; +} + +/*----------------------------------------------------------------------------*/ +#ifdef OBSOLETE_DEVICE +int gossen_gpib_send_status(DummyPtr gpibinfo, char *send) +{ + int status, stat; + char recv[512]; + BOOL wflag; + DWORD wtimeout; + INT ret,ret1; + +#ifdef MIDEBUGG + cm_msg(MLOG, "", "++gossen_gpib_send_status(%s)", send); +#endif + // quick fix RA36 10-NOV-2006 + cm_msg(MLOG,"", "Communication to Gossen is currently disabled!"); + return CM_SUCCESS; + + cm_get_watchdog_params(&wflag, &wtimeout); // remember watchdog parameters + cm_set_watchdog_params(FALSE,0); // disable watchdog while + // accessing device + + status = CM_SUCCESS; + if (gpibinfo != NULL) { + // lock device access + if ((ret=langpib(CMD_LOCK, gpibinfo, 0)) == CM_SUCCESS) { + int nall; + + nall = 0; +all_again: + nall++; + ss_sleep(1000); // slow down + /* langpib(CMD_FLUSH, gpibinfo, 300); does not help */ + + // something to send? + if ((send != NULL) && (strlen(send) >0)) { + int ncmd; + + ncmd = 0; +cmd_again: + if (ncmd > 0) ss_sleep(500); + ncmd++; +#ifdef MIDEBUGG + cm_msg(MLOG, "", "gossen_gpib_send_status() sending %s", send); +#endif + ret1 = langpib(CMD_WRITE, gpibinfo, send, strlen(send)); + if (ret1 > 0) { +#ifdef MIDEBUGG + cm_msg(MINFO, "", "Command %s sent to GOSSEN", send); +#endif + status = CM_SUCCESS; + } else if (ret1 == 0) { + if (ncmd < 3) goto cmd_again; + cm_msg(MERROR, "gossen_gpib_send_status", "Command %s not sent to GOSSEN", + send); + status = FE_ERR_DRIVER; + } else if (ret1 == -1) { + cm_msg(MERROR, "gossen_gpib_send_status", "Communication error sending " + "command %s to GOSSEN", send); + status = FE_ERR_DRIVER; + } else { + cm_msg(MERROR, "gossen_gpib_send_status", "Unknown error %d sending " + "command %s to GOSSEN", ret1, send); + status = FE_ERR_DRIVER; + } + ss_sleep(1000); + + } else + ret1 = 1; + + if (ret1 > 0) { + stat = + langpib(CMD_READ, gpibinfo, recv, sizeof(recv), 3000); + +#ifdef MIDEBUGG + if (stat > 0) + cm_msg(MLOG, "", "gossen_gpib_send_status() received %s", recv); +#endif + + if (stat >= 3) { + /* error status is 00 for no error */ + if (strncmp(recv, "F00,00,00,00,00,00,00,00,0",26) == 0) { +#ifdef MIDEBUGG + printf("Status OK\n"); +#endif + status = CM_SUCCESS; + } else { + status = FE_ERR_DRIVER; + cm_msg(MLOG, "gossen_gpib_send_status"," status %s received instead of " + "F00,00,00,00,00,00,00,00,0", recv); + if ( (strlen(recv) >= 3) && (recv[0] == 'F')) { + int errcode; + if (sscanf(&recv[1],"%d,",&errcode) == 1) { + char errstring[50]; + + errstring[0] = '\0'; + switch (errcode) { + case 0: strncpy(errstring,"No ERROR",sizeof(errstring)-1); + status = CM_SUCCESS; // return success + break; + case 1: strncpy(errstring,"No Datastring before Terminator", + sizeof(errstring)-1); + break; + case 2: strncpy(errstring,"Datastring larger (>128) than buffer" + "can hold",sizeof(errstring)-1); + break; + case 3: strncpy(errstring,"T: invalid or too many characters", + sizeof(errstring)-1); + break; + case 4: strncpy(errstring,"V: too many characters or no decimals", + sizeof(errstring)-1); + break; + case 5: strncpy(errstring,"W: Exponent has no sign", + sizeof(errstring)-1); + break; + case 6: strncpy(errstring,"W: Exponent without decimal", + sizeof(errstring)-1); + break; + case 7: strncpy(errstring,"T..:X: invalid characters received", + sizeof(errstring)-1); + break; + case 8: strncpy(errstring,"U/V/W: mantissa is missing after sign " + "or before exponent",sizeof(errstring)-1); + break; + case 9: strncpy(errstring,"U/V: spaces between sign and mantissa", + sizeof(errstring)-1); + break; + case 10: strncpy(errstring,"T: Undefined ASCII parameter to set", + sizeof(errstring)-1); + break; + case 20: strncpy(errstring,"Power ON: No DAC card found", + sizeof(errstring)-1); + break; + case 21: strncpy(errstring,"KN: DAC card not reachable", + sizeof(errstring)-1); + break; + case 22: strncpy(errstring,"Kn: invalid card address - not 0..7", + sizeof(errstring)-1); + break; + case 25: strncpy(errstring,"U: negative voltage on unipolar DAC card", + sizeof(errstring)-1); + break; + case 26: strncpy(errstring,"I: negative current requested", + sizeof(errstring)-1); + break; + case 27: strncpy(errstring,"U/I: demand value too large", + sizeof(errstring)-1); + break; + case 28: strncpy(errstring,"U: missing demand value", + sizeof(errstring)-1); + break; + case 29: strncpy(errstring,"I: missing demand value", + sizeof(errstring)-1); + break; + case 31: strncpy(errstring,"An: invalid n - not (0,1)", + sizeof(errstring)-1); + break; + case 32: strncpy(errstring,"Sn: invalid n - not (0,1)", + sizeof(errstring)-1); + break; + case 33: strncpy(errstring,"Qn: invalid n - not (0..7)", + sizeof(errstring)-1); + break; + case 37: strncpy(errstring,"Tn: invalid n - not (0,1)", + sizeof(errstring)-1); + break; + case 38: strncpy(errstring,"Cn: invalid n - not (0,1)", + sizeof(errstring)-1); + break; + case 39: strncpy(errstring,"Pn: invalid n - not (0,1) or " + "bipolar card settings",sizeof(errstring)-1); + break; + case 40: strncpy(errstring,"IEC-interface test function Xn " + " invalid n - not (1..255)",sizeof(errstring)-1); + break; + case 44: strncpy(errstring,"Trigger error",sizeof(errstring)-1); + break; + case 46: strncpy(errstring,"IEC-interface handshake error " + "Device can not send message",sizeof(errstring)-1); + break; + case 99: strncpy(errstring,"device failure or data error", + sizeof(errstring)-1); + break; + default: + strncpy(errstring,"Unknown error",sizeof(errstring)-1); + } + if (strlen(errstring) > 0) + cm_msg(MLOG,"","GOSSEN returned : %s",errstring); + } else + cm_msg(MLOG,"","gossen_gpib_send_status() Not able to read error string"); + } else { + cm_msg(MLOG,"","gossen_gpib_send_status() Not able to decode error string"); + } + } + } else { + cm_msg(MLOG, "", "gossen_gpib_send_status() ERROR no status returned"); + status = FE_ERR_DRIVER; + } + } + + //if ((status != CM_SUCCESS)&&(nall < 10)) { + if (nall < 10) { // status is not checked as it is not corresp'ng with real status + //printf("again\n"); + goto all_again; + } + langpib(CMD_UNLOCK, gpibinfo); + } else { + cm_msg(MERROR, "gossen_gpib_send_status", + "ERROR %d executing LAN/GPIB device lock", ret); + } + } + cm_set_watchdog_params(wflag, wtimeout); // restore watchdog parameters +#ifdef MIDEBUGG + cm_msg(MLOG, "", "--gossen_gpib_send_status()", send); +#endif + status = CM_SUCCESS; // fake success + return status; +} + +#endif + +/*----------------------------------------------------------------------------*/ +INT replace_newline(char *ans) +{ + +#ifdef MIDEBUG2 + cm_msg(MLOG, "", "replace_newline()"); +#endif + if ((ans != NULL) && (*ans != '\0')) { + int i; + /* replace newline by semicolon ; the command and answer separator */ + for (i = 0; *(ans + i) != '\0'; i++) + if (*(ans + i) == '\x0a') + *(ans + i) = ';'; + } +#ifdef MIDEBUG2 + cm_msg(MLOG, "", "<< replace_newline()"); +#endif + return FE_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + *

Send command to device and receive answer from device + * + *

Return: + * - > 0 1 (cmd sent) or number of characters received + * - == 0 no characters sent or nothing received + * - -1 communication error + * - < -1 unknown error + * + * \param info is a pointer to the DD specific info structure + * \param comchan is the communication channel being used + * \param businfo is the bus driver specific info structure + * \param dev is the device number + * \param send is the command to be sent or NULL + * \param recv is the receive buffer or NULL to be returned + * \param size is the length of the receive buffer + * \param tmo is the IO timeout [msec] to wait for reply + * \param fflag NIY if fflag = 1 flush buffer before sending next query + * \param ntries is the number of tries + * \param sflag if sflag == 1 check state + */ + +INT gossen_ssp120_sendr_status(EXPMAG_INFO * info, int comchan, DummyPtr businfo, + int dev, char *send, + char *recv, int size, INT tmo, INT fflag, INT ntries, + INT sflag) +{ + int status, errcnto; + int state, ostate, itries, nerrs; + BOOL wflag; + DWORD wtimeout; +static int sdevaddress = -1; + +#ifdef MIDEBUG + cm_msg(MLOG, "", "++gossen_ssp120_sendr_status(%s,tmo=%d,%s)", send ? send : "", + tmo, fflag ? "FLUSH" : "NO FLUSH"); +#endif + + cm_get_watchdog_params(&wflag, &wtimeout); // remember watchdog parameters + cm_set_watchdog_params(FALSE,0); // disable watchdog while + // accessing device + // to be able to handle large + // network problems + + errcnto = info->errorcount[comchan]; + + state = ostate = info->state[comchan]; + itries = 0; + nerrs = 0; + + try_again: + itries++; + + if (send != NULL) { +#ifdef SSP120_LANGPIB_SUPPORT +#ifdef MIDEBUG + cm_msg(MLOG, "", ">>langpib(CMD_WRITE) send = %s", send); +#endif + status = langpib(CMD_WRITE, businfo, send, strlen(send)); +#ifdef MIDEBUG + cm_msg(MLOG, "", "<>tcpip(CMD_WRITE) cmd = %s", cmd); +#endif + status = tcpip(CMD_WRITE, businfo, cmd, strlen(cmd)); +#ifdef MIDEBUG + cm_msg(MLOG, "", "<>tcpip(CMD_WRITE) send = %s", send); +#endif + status = tcpip(CMD_WRITE, businfo, send, strlen(send)); +#ifdef MIDEBUG + cm_msg(MLOG, "", "< 0) + cm_msg(MLOG, "", "recv = %s", recv); +#endif +#elif defined( SSP120_TCPIP_SUPPORT ) + status = tcpip(CMD_READ, businfo, recv, size, tmo); +#ifdef MIDEBUG + cm_msg(MLOG, "", "langpib(CMD_READ) status = %d", status); + if (status > 0) + cm_msg(MLOG, "", "recv = %s", recv); +#endif +#endif + } else { +#ifdef MIDEBUG + cm_msg(MLOG, "", "recv == NULL"); +#endif + } + } + + /* test if (itries == 1) status = -1; */ + + /* no communication error? */ + if (status != -1) { + + if (state & 64) + state -= 64; /* reset communication error */ + if (state & 128) + state -= 128; /* reset general error */ + + /* avoid recursive calls */ + if ((sflag == TRUE) + && ((strncmp(send, "CRA?", 4) != 0) && (strncmp(send, "OUT?", 4) != 0))) { + char buffer[256]; + int len; + + cra_again: + buffer[0] = '\0'; + if ((len = gossen_ssp120_sendr_status(info, comchan, businfo, dev, "CRA?\n", + buffer,sizeof(buffer),DEFAULT_TIMEOUT_SSP, + FALSE, ntries, FALSE)) != -1) { + + if (len > 0) { + + replace_newline(buffer); + + if (sscanf(buffer, "%d", &state) != 1) { + info->errorcount[comchan]++; + state |= 64; + if (info->errorcount[comchan] < MAX_ERROR_SSP) + cm_msg(MLOG, "", "gossen_ssp120_sendr_status : " + "ERROR processing CRA? of device %d : >%s<", dev, buffer); + } else { + +#ifdef MIDEBUG + cm_msg(MLOG, "", "gossen_ssp120_sendr_status : " + "CRA? of device %d returned >%s<", dev, buffer); +#endif + nerrs = 0; + out_again: + buffer[0] = '\0'; + gossen_ssp120_sendr_status(info, comchan, businfo, dev, "OUT?\n", + buffer, sizeof(buffer), DEFAULT_TIMEOUT_SSP, FALSE, ntries, FALSE); + replace_newline(buffer); + + if (strlen(buffer) > 0) { +#ifdef MIDEBUG + cm_msg(MLOG, "", "gossen_ssp120_sendr_status : " + "OUT? of device %d returned >%s<", dev, buffer); +#endif + if (strncmp(buffer, "OUTPUT OFF", strlen("OUTPUT OFF")) == 0) + state |= 8; /* set Output off flag */ + else if (state & 0x08) + state -= 0x08; /* clear Output off flag */ + + } else { + + cm_msg(MLOG, "", + "gossen_ssp120_sendr_status Timeout sending OUT?"); + ss_sleep(100); + info->errorcount[comchan]++; + nerrs++; + if (nerrs < 8) + goto out_again; + + state |= 64; + if (info->errorcount[comchan] < MAX_ERROR_SSP) + cm_msg(MERROR, "gossen_ssp120_sendr_status", + " sending OUT?"); + // more than 8 times problems -> force reconnect (maybe only for + info->comerror[comchan] = MAX_ERROR + 61; //tcp/ip) RA36 18-APR-2006 + } + + if ((state & 1) && !(ostate & 1)) + cm_msg(MLOG, "", "Device %d is in Constant Voltage Regulation",dev); + + if ((state & 2) && !(ostate & 2)) + cm_msg(MLOG, "", "Device %d is in Constant Current Regulation",dev); + + if ((state & 4) && !(ostate & 4)) + cm_msg(MLOG, "", "Device %d Overload", dev); + + if ((state & 8) && !(ostate & 8)) + cm_msg(MLOG, "", "Device %d Output is disabled", dev); + + if ((state & 16) && !(ostate & 16)) + cm_msg(MLOG, "", "Device %d Overvoltage", dev); + + if ((state & 32) && !(ostate & 32)) + cm_msg(MLOG, "", "Device %d Overtemperature", dev); + + if ((state & 64) && !(ostate & 64) && + (info->errorcount[comchan] < MAX_ERROR_SSP)) + cm_msg(MLOG, "", "Device %d communication error", dev); + + if ((state & 128) && !(ostate & 128) && + (info->errorcount[comchan] < MAX_ERROR_SSP)) + cm_msg(MLOG, "", "Device %d error", dev); + } + + } else { + cm_msg(MLOG, "", "gossen_ssp120_sendr_status Timeout sending CRA?"); + ss_sleep(100); + info->errorcount[comchan]++; + nerrs++; + if (nerrs < 8) + goto cra_again; + + state |= 64; + if (info->errorcount[comchan] < MAX_ERROR_SSP) + cm_msg(MERROR, "gossen_ssp120_sendr_status", "Timeout sending CRA?"); + + // more than 8 times problems -> force reconnect (maybe only for + info->comerror[comchan] = MAX_ERROR_SSP + 61; // tcp/ip) RA36 18-APR-2006 + } + + } else { + // Do nothing as communication errors are already handled + } + } + } else { + + if (itries < ntries) { + state = ostate; + if (send != NULL) + cm_msg(MLOG, "gossen_ssp120_sendr_status", + "Communication error sending \"%s\"!", send); + goto try_again; + } + info->errorcount[comchan]++; + if (info->errorcount[comchan] < MAX_ERROR_SSP) { + if (send != NULL) + cm_msg(MERROR, "gossen_ssp120_sendr_status", + "Communication error sending \"%s\"!", send); + else + cm_msg(MERROR, "gossen_ssp120_sendr_status", "Communication error!"); + } + if (ntries > 1) { + // problem occured more than once -> force reconnect (maybe only for + info->comerror[comchan] = MAX_ERROR_SSP + 61; // tcp/ip) RA36 18-APR-2006 + } + /* Bus error */ + state = 64; + info->comerror[comchan]++; + } + + if (state != ostate) { + ostate = state; + info->state[comchan] = state; + } + + /* info->comerror++; test */ + + /* many errors? try to reconnect to GOSSEN SSP120 */ + if (info->comerror[comchan] > MAX_ERROR_SSP + 60) { + char name[NAME_LENGTH]; + + name[0] = '\0'; +// info->bd(CMD_NAME, info->bd_info, name); /* get name of bus driver */ + strcpy(name,"langpib"); + + if (strcmp(name, "tcpip") == 0) { /* TCP/IP bus driver? */ + +#ifdef SSP120_TCPIP_RECONNECT + TCPIP_INFO *ptcpinfo; + + ptcpinfo = (TCPIP_INFO *) businfo; /* get bus driver info */ + + if (ptcpinfo != NULL) { + /* code from info->bd(CMD_EXIT,info->bd_info); *//* close connection */ + if (ptcpinfo->fd != -1) { + shutdown(ptcpinfo->fd, 2); + closesocket(ptcpinfo->fd); + ptcpinfo->fd = -1; + } + ss_sleep(3000); /* wait 3 seconds */ + /* open TCP/IP connection */ + ptcpinfo->fd=tcpip_connect(ptcpinfo->settings.host,ptcpinfo->settings.port); + // 1.9.5 ptcpinfo->fd = tcpip_open(ptcpinfo->settings.host, ptcpinfo->settings.port); + if (ptcpinfo->fd != -1) + cm_msg(MLOG,"gossen_ssp120_sendr_status", "Reconnected to Gossen SSP120"); + else + cm_msg(MERROR, "gossen_ssp120_sendr_status", + "Failed to reconnect to Gossen SSP120!"); + info->comerror = 0; + + } +#else + if (info->errorcount[comchan] < MAX_ERROR_SSP) + cm_msg(MERROR, "gossen_ssp120_sendr_status", "TCPIP_RECONNECT not defined" + " - Not able to reconnect to TCP/IP device!"); +#endif /* TCPIP_RECONNECT */ + + } else if (strcmp(name, "langpib") == 0) { /* LAN/GPIB bus driver? */ + +#ifdef SSP120_LANGPIB_RECONNECT + langpib(CMD_RECONNECT, businfo, 3000); + info->comerror[comchan] = 0; +#else + if (info->errorcount[comchan] < MAX_ERROR_SSP) + cm_msg(MERROR, "gossen_ssp120_sendr_status", "LANGPIB_RECONNECT not defined" + " - Not able to reconnect to LAN/GPIB device!"); +#endif + + } else { + if (info->errorcount[comchan] < MAX_ERROR_SSP) + cm_msg(MERROR, "gossen_ssp120_sendr_status", "Unknown bus driver %s" + " - Not able to reconnect!", name); + } + + } + + cm_set_watchdog_params(wflag, wtimeout); // restore watchdog parameters +#ifdef MIDEBUG + if (recv) + cm_msg(MLOG, "", "--gossen_ssp120_sendr_status(status=%d,recv=%s)",status,recv); + else + cm_msg(MLOG, "", "--gossen_ssp120_sendr_status(status=%d)",status); +#endif + return status; +} + +/*----------------------------------------------------------------------------*/ +#ifdef EPICSGFA +// update all epics channels +INT epics_channels_update(EXPMAG_INFO *info) { + INT status; + if ((info != NULL) && (info->cainfo != NULL)) { + INT status1; + int i; + float dummy; + + status = CM_SUCCESS; + + for (i=0; i < info->expmag_settings.epics_channels; i++) { + dummy = 0.f; + status1 = epics_ca_get(info->cainfo, i, &dummy); + if (status1 != CM_SUCCESS) status = status1; + } + info->do_epics_reading = 1; + } else { + if (info == NULL) + cm_msg(MERROR,"epics_channels_update","NULL pointer to EXPMAG_INFO"); +// else +// cm_msg(MERROR,"epics_channels_update","NULL pointer to CA_INFO"); + + status = FE_ERR_DRIVER; + } + return status; +} + +// wait updating epics channels info ntimes after waiting interval msec +INT epics_wait(EXPMAG_INFO *info, int ntimes, INT interval) { + INT status; + status = CM_SUCCESS; + if ((ntimes > 0) && (interval > 0)) { + int i; + for (i=0; i < ntimes; i++) { + ss_sleep(interval); + status = epics_channels_update(info); + } + } else { + status = epics_channels_update(info); + } + + return status; +} +#endif +/*----------------------------------------------------------------------------*/ +/* the init function creates a ODB record which contains the + settings and initialized it variables as well as the bus driver */ + +INT expmag_init(HNDLE hkey, void **pinfo, INT channels, INT(*bd) (INT cmd, ...)) +{ + int status, size; + HNDLE hDB, hkeydd; + EXPMAG_INFO *info; + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "++expmag_init"); +#endif + /* allocate info structure */ + info = (EXPMAG_INFO*) calloc(1, sizeof(EXPMAG_INFO)); + *pinfo = info; + + { /* initialise last set values and error count */ + int i; + for (i = 0; i < EMNDEVS; i++) + info->set_values[i] = -2.0; + for (i = 0; i < EMNDEVS; i++) + info->errorcount[i] = 0; + for (i = 0; i < EMNDEVS; i++) + info->lasterrtime[i] = ss_time(); + } + + cm_get_experiment_database(&hDB, NULL); + + /* get absolute ODB path to be able to read/write Variables/Measured,Demand */ + if (db_get_path(hDB, hkey, info->varpath, sizeof(info->varpath)) == CM_SUCCESS) { + int i, j; +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_init : db_get_path = %s", info->varpath); +#endif + /* separate /Equipment// from path */ + for (i = 0, j = 0; i < strlen(info->varpath); i++) + if (*(info->varpath + i) == '/') { + j++; + if (j == 3) + break; + } + + if (j == 3) { + char tstr[512]; + + *(info->varpath + i + 1) = '\0'; + strcat(info->varpath, "Variables/"); + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_init : varpath = %s", info->varpath); +#endif + /* get ODB key of ../Variables/Demand */ + sprintf(tstr, "%sDemand", info->varpath); + if (db_find_key(hDB, 0, tstr, &info->hkey_demand) != DB_SUCCESS) { + cm_msg(MLOG, "", "expmag_init : WARNING ODB key %s not found", tstr); + info->hkey_demand = 0; +#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "expmag_init : db_find_key(%s)", tstr); +#endif + } + + /* get ODB key of ../Variables/Measured */ + sprintf(tstr, "%sMeasured", info->varpath); + if (db_find_key(hDB, 0, tstr, &info->hkey_measured) != DB_SUCCESS) { + cm_msg(MLOG, "", "expmag_init : WARNING ODB key %s not found", tstr); + info->hkey_measured = 0; +#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "expmag_init : db_find_key(%s)", tstr); +#endif + } + + } else { + cm_msg(MLOG, "", "expmag_init : ERROR invalid ODB path (%s)", info->varpath); + } + } else { + cm_msg(MLOG, "", "expmag_init : ERROR returned from db_get_path()"); + } + + /* create settings record */ + status = db_create_record(hDB, hkey, "DD", EXPMAG_SETTINGS_STR); + if (status != DB_SUCCESS) + return FE_ERR_ODB; + + db_find_key(hDB, hkey, "DD", &hkeydd); + size = sizeof(info->expmag_settings); + db_get_record(hDB, hkeydd, &info->expmag_settings, &size, 0); + + expmag_settings_strip(&info->expmag_settings); + + if (channels > EMNDEVS) { + cm_msg(MLOG, "", "expmag_init : ERROR number of channels %d is larger than %d! " + "Increase EMNDEVS and recompile", channels, EMNDEVS); + return FE_ERR_DRIVER; + } + + /* initialize driver */ + info->num_channels = channels; + info->roadc = (_RoadCRec**) calloc(channels, sizeof(void *)); + info->tcpip = (_DummyRec**) calloc(channels, sizeof(void *)); + info->langpib = (_DummyRec**) calloc(channels, sizeof(void *)); + info->calibration = (_CalibrationRec**) calloc(channels, sizeof(CalibrationPtr)); + info->threshold = (float*) calloc(channels, sizeof(float)); + info->bd = bd; + info->hkey = hkey; + + if (bd) { + + /* initialize bus driver */ + status = info->bd(CMD_INIT, info->hkey, &info->bd_info); + + if (status != SUCCESS) { + cm_msg(MERROR,"expmag_init","During bus driver init - EXIT"); + expmag_exit(info); + *pinfo = NULL; + return status; + } + } + + /* Create EPICS DD and init EPICS channel access as sub device driver */ +#ifdef EPICSGFA + if (info->expmag_settings.epics_channels > 0) { + HNDLE tkey; + + // create EPICS DD + if (db_find_key(hDB, info->hkey, "EPICS", &tkey) == DB_NO_KEY) { + db_create_key(hDB, info->hkey, "EPICS", TID_KEY); + } + + if (db_find_key(hDB, info->hkey, "EPICS", &tkey) == DB_SUCCESS) { + // init EPICS channel access + status = epics_ca_init( tkey, (void **)&info->cainfo, + info->expmag_settings.epics_channels); + if (status != SUCCESS) { + cm_msg(MERROR,"expmag_init","ERROR returned from epics_ca_init() - EXIT"); + expmag_exit(info); + *pinfo = NULL; + return status; + } + } else { + cm_msg(MERROR,"expmag_init","ERROR EPICS ODB key not found"); + expmag_exit(info); + *pinfo = NULL; + return status; + } + + } +#endif + + /* initialization of configured devices */ + if (strncmp(info->expmag_settings.instrument, "NONE", 4) != 0) {// instrument defined? + if (strncmp(info->expmag_settings.area, "NONE", 4) != 0) { // area defined? + + if (expmag_instrument_there(info)) { // instrument handled? + if (expmag_area_there(info)) { // area handled? + if (expmag_get_default_settings(info) >= 0) { + int i, status1; + char channam[6]; + HNDLE hkey, hdb; + + cm_get_experiment_database(&hdb, NULL); + + /* process devices */ + for (i = 0; i < EMNDEVS; i++) { + + status1 = SS_SUCCESS; + info->last_demand[i] = 0.0f; + sprintf(channam, "%d", i); + + /* device used ? */ + if (strncmp(info->expmag_settings.device[i], "NONE", 4) != 0) { +#ifdef MIDEBUG + cm_msg(MLOG, "", "expmag_init : processing device %s", + info->expmag_settings.device[i]); +#endif + /* -- device type is PSIBL */ + if (strncmp(info->expmag_settings.type[i], "PSIBL", 5) == 0) { + HNDLE hkeybd; + int fd, ref; + TCPIP_INFO *tinfo; + + fd = -1; + tinfo = NULL; + + /* try to get reference to opened TCP/IP comm channel */ + if (strcmp(info->expmag_settings.server[i], "CHAN") == 0) { + + ref = info->expmag_settings.address[i]; + /* channel reference in range */ + if ((ref >= 0) && (ref < EMNDEVS)) { + if (info->expmag_settings.used[ref] != 'Y') { + cm_msg(MLOG, "", + "expmag_init : WARNING %s : referenced device" + " %d %s is disabled!", + info->expmag_settings.device[i], ref, + info->expmag_settings.device[ref]); + } else { + + /* get fd of referenced device */ + if ((info->tcpip != NULL) + && (*(info->tcpip + ref) != NULL)) { + tinfo = (TCPIP_INFO *) * (info->tcpip + ref); + fd = tinfo->fd; + if (fd != -1) { +#ifdef MIDEBUG + cm_msg(MLOG, "", + "expmag_init : %s : fd of reference " + "device %s is %d", + info->expmag_settings.device[i], + info->expmag_settings.device[ref], fd); +#endif + } else { + cm_msg(MLOG, "", + "expmag_init : ERROR %s : TCP/IP " + "communication connection of device %s " + "is not open!", + info->expmag_settings.device[i], + info->expmag_settings.device[ref]); + } + } else { + if (info->tcpip == NULL) { + cm_msg(MLOG, "", + "expmag_init : ERROR %s : TCP/IP " + "communication data not allocated!", + info->expmag_settings.device[i]); + } else { + cm_msg(MLOG, "", + "expmag_init : ERROR %s : TCP/IP " + "communication data for device %s not " + "allocated!", + info->expmag_settings.device[i], + info->expmag_settings.device[ref]); + } + } + } + + } else { + cm_msg(MLOG, "", + "expmag_init : ERROR %s : referenced device %d " + "is not in range |0 -%d|!", + info->expmag_settings.device[i], ref, + EMNDEVS - 1); + } + + /* comm. channel to TCP/IP must be set-up and opened */ + } else { + /* create ODB sub directory */ + /* ...// */ + if (db_find_key(hdb, info->hkey, channam, &hkey) == + DB_NO_KEY) { + db_create_key(hdb, info->hkey, channam, TID_KEY); + db_find_key(hdb, info->hkey, channam, &hkey); + /* .../BD/ */ + db_create_key(hdb, hkey, "BD", TID_KEY); + db_find_key(hdb, hkey, "BD", &hkeybd); + /* Host */ + db_create_key(hdb, hkeybd, "Host", TID_STRING); + /* Port */ + db_create_key(hdb, hkeybd, "Port", TID_INT); + } else { + if ((status1 = + db_find_key(hdb, info->hkey, channam, + &hkey)) == DB_SUCCESS) { + status1 = db_find_key(hdb, hkey, "BD", &hkeybd); + } + } + + if (status1 == DB_SUCCESS) { + /* always copy TCP/IP host name and TCP/IP port from + * set-up to BD subpath */ + db_set_value(hdb, hkeybd, "Host", + &info->expmag_settings.server[i], 256, 1, + TID_STRING); + db_set_value(hdb, hkeybd, "Port", + &info->expmag_settings.address[i], + sizeof(int), 1, TID_INT); + + /* open connection to tcpip device, if device is used */ + if (info->expmag_settings.used[i] == 'Y') { + status1 = tcpip(CMD_INIT, hkey, info->tcpip + i); + if (status1 == CM_SUCCESS) { + tinfo = (TCPIP_INFO *) * (info->tcpip + i); + fd = tinfo->fd; +#ifdef MIDEBUG + cm_msg(MLOG, "", + "expmag_init : %s : fd of TCPIP connection is " + "%d", info->expmag_settings.device[i], fd); +#endif + } else { + cm_msg(MLOG, "", + "expmag_init : ERROR opening tcpip connection " + "(%s,%d) for %s (%s)", + info->expmag_settings.server[i], + info->expmag_settings.address[i], + info->expmag_settings.device[i], + info->expmag_settings.type[i]); + } + } else { + cm_msg(MLOG, "", + "expmag_init : WARNING Device %s is disabled! " + "TCP/IP Communication will not be initiated!", + info->expmag_settings.device[i]); + } + } + } + + /* get information about device from ROADC server */ + if (info->expmag_settings.used[i] == 'Y') { + if ((tinfo != NULL) && (fd != -1)) { + + status1 = roadc_device_init(info, i); + + } else { + cm_msg(MLOG, "", + "expmag_init : ERROR No tcpip connection! " + "Not able to get set-up of ROADC device!"); + status1 = FE_ERR_DRIVER; + } + } else { + cm_msg(MLOG, "", + "expmag_init : WARNING Device %s is disabled! " + "ROADC set-up will not be read!", + info->expmag_settings.device[i]); + } + + /* -- device type is GOSSEN */ + } else if (strncmp(info->expmag_settings.type[i], "GOSSEN", 6) == + 0) { + HNDLE hkeybd; + + /* NOTE: there is only one channel (device subaddress) used + * CHANnel referencing is therefore not implemented for + * Gossen */ + + /* create ODB sub directory */ + if (db_find_key(hdb,info->hkey, channam, &hkey)==DB_NO_KEY) { + INT locktmo; + + locktmo = 30000; + /* ...// */ + db_create_key(hdb, info->hkey, channam, TID_KEY); + db_find_key(hdb, info->hkey, channam, &hkey); + db_create_key(hdb, hkey, "BD", TID_KEY); + db_find_key(hdb, hkey, "BD", &hkeybd); /*.../BD/ */ +#ifdef SSP120_LANGPIB_SUPPORT + db_create_key(hdb, hkeybd,"Server",TID_STRING);/* Server */ + db_create_key(hdb, hkeybd,"Address",TID_INT); /* Address*/ + db_create_key(hdb, hkeybd,"LockTMO",TID_INT); /* LockTMO*/ + db_set_value(hdb, hkeybd, "LockTMO", &locktmo, + sizeof(locktmo), 1, TID_INT); +#elif defined(SSP120_TCPIP_SUPPORT) + /* Host */ + db_create_key(hdb, hkeybd, "Host", TID_STRING); + /* Port */ + db_create_key(hdb, hkeybd, "Port", TID_INT); +#else + ERROR UNKNOWN MIDAS COMMUNICATION BUS +#endif + } else { + if ((status1 = + db_find_key(hdb, info->hkey, channam, + &hkey)) == DB_SUCCESS) { + status1 = db_find_key(hdb, hkey, "BD", &hkeybd); + } + } + + if (status1 == DB_SUCCESS) { +#ifdef SSP120_LANGPIB_SUPPORT + /* copy GPIB server name and GPIB address from setup to + BD subpath */ + /* RA36 28-MAY_2016 changed from 32 to 256 */ + db_set_value(hdb, hkeybd, "Server", + &info->expmag_settings.server[i], 256, 1, + TID_STRING); + db_set_value(hdb, hkeybd, "Address", + &info->expmag_settings.address[i],sizeof(int), + 1, TID_INT); +#elif defined(SSP120_TCPIP_SUPPORT) + /* always copy TCP/IP host name and TCP/IP port from set-up + * to BD subpath */ + db_set_value(hdb, hkeybd, "Host", + &info->expmag_settings.server[i], 256, 1, + TID_STRING); + db_set_value(hdb, hkeybd, "Port", + &info->expmag_settings.address[i], + sizeof(int), 1, TID_INT); +#else + ERROR UNKNOWN MIDAS COMMUNICATION BUS +#endif + + /* open connection to device, if device is used */ + if (info->expmag_settings.used[i] == 'Y') { + int comchan; + + if (strcmp(info->expmag_settings.server[i], "CHAN")==0){ + comchan = info->expmag_settings.address[i]; +#ifdef SSP120_LANGPIB_SUPPORT + if (*(info->langpib + comchan) == NULL) { +#elif defined(SSP120_TCPIP_SUPPORT) + if (*(info->tcpip + comchan) == NULL) { +#else + ERROR UNKNOWN MIDAS COMMUNICATION BUS +#endif + status1 = SS_INVALID_ADDRESS; + } else + status1 = CM_SUCCESS; + } else { + comchan = i; +#ifdef MIDEBUG + cm_msg(MLOG, "", +#ifdef SSP120_LANGPIB_SUPPORT + "expmag_init : opening LAN/GPIB connection (%s,%d) " +#elif defined(SSP120_TCPIP_SUPPORT) + "expmag_init : opening RS232 terminal server " + "connection (%s,%d) " +#else + ERROR UNKNOWN MIDAS COMMUNICATION BUS +#endif + "for %s (%s)", info->expmag_settings.server[i], + info->expmag_settings.address[i], + info->expmag_settings.device[i], + info->expmag_settings.type[i]); +#endif + +#ifdef SSP120_LANGPIB_SUPPORT + status1 = langpib(CMD_INIT, hkey, info->langpib + i); +#elif defined(SSP120_TCPIP_SUPPORT) + status1 = tcpip(CMD_INIT, hkey, info->tcpip + i); +#else + ERROR UNKNOWN MIDAS COMMUNICATION BUS +#endif + } + + if (status1 == CM_SUCCESS) { + char cmd[20],cmd1[20],ans[512]; + int status2; + DummyPtr businfo; + + /* send gossen setup string */ + /* if ((strcmp(info->expmag_settings.instrument, + "GPD")==0) && + (strcmp(info->expmag_settings.area, + "MUE1")==0)) { */ + status2 = SS_IO_ERROR; + +#ifdef SSP120_LANGPIB_SUPPORT + businfo = *(info->langpib + comchan); +#elif defined(SSP120_TCPIP_SUPPORT) + businfo = *(info->tcpip + comchan); +#else + ERROR UNKNOWN MIDAS COMMUNICATION BUS +#endif + // get identification + sprintf(cmd,"*IDN?"); + strcpy(cmd1,cmd); + strcat(cmd,"\n"); + if (gossen_ssp120_sendr_status(info,comchan,businfo, + i,cmd,ans,sizeof(ans), DEFAULT_TIMEOUT_SSP, + FALSE,5,FALSE) <= 0) { + status1 = status2; + } else { + cm_msg(MLOG,"","expmag_init : Gossen *IDN? = %s", + ans); + // NIY check device type + } + + // get all setup parameter + sprintf(cmd,"*LRN?"); + strcpy(cmd1,cmd); + strcat(cmd,"\n"); + if (gossen_ssp120_sendr_status(info, comchan, + businfo,i, cmd, ans, sizeof(ans), + DEFAULT_TIMEOUT_SSP, + FALSE,5,FALSE) <= 0) { + cm_msg(MERROR,"expmag_init", + "ERROR Sending %s to GOSSEN device %s", + cmd1, info->expmag_settings.device[i]); + status1 = status2; + } else { + if (strlen(ans) > 100) { + if (strlen(ans) > 200) { + cm_msg(MLOG, "", "GOSSEN : LRN of device %d " + "returned %100.100s", i, ans); + cm_msg(MLOG, "", "GOSSEN : " + " %100.100s", &ans[100]); + cm_msg(MLOG, "", "GOSSEN : " + " %s", &ans[200]); + } else { + cm_msg(MLOG, "", "GOSSEN : LRN of device %d " + "returned %100.100s", i, ans); + cm_msg(MLOG, "", "gossen_ssp120_init : " + " %s",&ans[100]); + } + } else { + cm_msg(MLOG, "", "GOSSEN : LRN of device %d " + "returned %s", i, ans); + } + + } + + // set U (must be less than ULIM) + sprintf(cmd,"USET 25.0"); // GOSSEN SSP 520 50 + strcpy(cmd1,cmd); + strcat(cmd,"\n"); + if (gossen_ssp120_sendr_status(info, comchan, + businfo,i, + cmd, NULL, 0, DEFAULT_TIMEOUT_SSP, + FALSE,5,FALSE) <= 0) { + cm_msg(MERROR,"expmag_init", "ERROR Sending %s to " + "GOSSEN device %s", + cmd1, info->expmag_settings.device[i]); + status1 = status2; + } else { + cm_msg(MLOG,"","GOSSEN : Setting voltage to %s " + "[V]",&cmd1[5]); + } + + // set U limit (must be greater or equal to set USET) + sprintf(cmd,"ULIM 25.1"); // GOSSEN SSP 520 50 + strcpy(cmd1,cmd); + strcat(cmd,"\n"); + if (gossen_ssp120_sendr_status(info, comchan, + businfo,i, + cmd, NULL, 0, DEFAULT_TIMEOUT_SSP, + FALSE,5,FALSE) <= 0) { + cm_msg(MERROR,"expmag_init", "ERROR Sending %s to " + "GOSSEN device %s", + cmd1, info->expmag_settings.device[i]); + status1 = status2; + } else { + cm_msg(MLOG,"","GOSSEN : Setting voltage limit to " + "%s [V]",&cmd1[5]); + } + + // set I limit (must be greater or equal to set ISET) + sprintf(cmd,"ILIM %f",info->expmag_settings.maxrval[i]); + strcpy(cmd1,cmd); + strcat(cmd,"\n"); + if (gossen_ssp120_sendr_status(info, comchan, + businfo,i, + cmd, NULL, 0, DEFAULT_TIMEOUT_SSP, + FALSE,5,FALSE) <= 0) { + cm_msg(MERROR,"expmag_init", "ERROR Sending %s to " "GOSSEN device %s", + cmd1, info->expmag_settings.device[i]); + status1 = status2; + } else { + cm_msg(MLOG,"","GOSSEN : Setting current limit to " + "%f [A]",info->expmag_settings.maxrval[i]); + } + /* } */ + } else { + cm_msg(MLOG, "", +#ifdef SSP120_LANGPIB_SUPPORT + "expmag_init : ERROR opening LAN/GPIB connection " +#elif defined(SSP120_TCPIP_SUPPORT) + "expmag_init : ERROR opening RS232 terminal " + "server connection " +#endif + "(%s,%d) for %s (%s)", + info->expmag_settings.server[comchan], + info->expmag_settings.address[comchan], + info->expmag_settings.device[comchan], + info->expmag_settings.type[comchan]); + } + } else { + cm_msg(MLOG, "", + "expmag_init : WARNING Device %s is disabled! " + "LAN/GPIB Communication will not be initiated!", + info->expmag_settings.device[i]); + } + } + + /* -- device type is MAG */ + } else if (strncmp(info->expmag_settings.type[i], "MAG", 3) ==0){ + + /* nothing to do but checking */ + if (strncmp(info->expmag_settings.server[i], "MAG", 3) == 0) { + if ((info->expmag_settings.address[i] < 0) || + (info->expmag_settings.address[i] >= EMNDEVS)) { + cm_msg(MLOG, "", + "expmag_init : Invalid channel %d |0-%d| for " + "device %s", info->expmag_settings.address[i], + EMNDEVS-1, info->expmag_settings.device[i]); + status1 = FE_ERR_DRIVER; + } + } else { + cm_msg(MLOG, "", + "expmag_init : Error server field of device %s (MAG) " + "should be MAG", info->expmag_settings.device[i]); + status1 = FE_ERR_DRIVER; + } + +#ifdef EPICSGFA + /* -- device type is EPICSGFA */ + } else if (strncmp(info->expmag_settings.type[i],"EPICSGFA",8) + ==0){ + + /* nothing to do but checking */ + if (strncmp(info->expmag_settings.server[i], "EPICS", 5)==0) { + INT setchan, getchan; + + setchan = info->expmag_settings.address[i]/1000; + if ((setchan < 0) || + (setchan >= info->expmag_settings.epics_channels)) { + cm_msg(MLOG, "", + "expmag_init : Invalid EPICS demand channel %d (" + "NOT in range |0-%d|) for device %s", setchan, + info->expmag_settings.epics_channels-1, + info->expmag_settings.device[i]); + status1 = FE_ERR_DRIVER; + } else { + // NIY EPICS check DESC:TYP + // NIY check name of epics channel to end with :SOL:2 + // NIY check if COM & STA exist + // NIY check CHn_Flags of :SOL:2 : + // - I,M,C,T,R should be specified + // - should NOT contain Z or N flag + // - should NOT contain G or F flag + } + getchan = info->expmag_settings.address[i] -setchan*1000; + if ((getchan < 0) || + (getchan >= info->expmag_settings.epics_channels)) { + cm_msg(MLOG, "", + "expmag_init : Invalid EPICS measured channel %d" + "(NOT in range |0-%d|) for device %s", getchan, + info->expmag_settings.epics_channels-1, + info->expmag_settings.device[i]); + status1 = FE_ERR_DRIVER; + } else { + // NIY EPICS check name of EPICS chan to end with :IST:2 + } + } else { + cm_msg(MLOG, "", "expmag_init : Error server field of " + "device %s (EPIGSGFA) should be EPICS", + info->expmag_settings.device[i]); + status1 = FE_ERR_DRIVER; + } +#endif + + } else { + cm_msg(MLOG, "", + "expmag_init : Error unknown device type %s for device" + " %s", info->expmag_settings.type[i], + info->expmag_settings.device[i]); + status1 = FE_ERR_DRIVER; + } + + /* -- a calibration file name is specified */ + if (status1 == SS_SUCCESS) { + if (strncmp(info->expmag_settings.calibration[i], "NONE", 4)!= + 0) { + CalibrationPtr pcal; + + /* allocate space for one calibration structure */ + pcal = (CalibrationPtr) calloc(1, sizeof(CalibrationRec)); + if (pcal != NULL) { + + /* get direction from device's channel settings */ + if (info->expmag_settings.direction[i] == 'F') { + pcal->direction = 1; + } else if (info->expmag_settings.direction[i] == 'R') { + pcal->direction = 0; + } else { + cm_msg(MLOG, "", + "expmag_init : Error unknown interpolation " + "direction %c for device %s", + info->expmag_settings.direction[i], + info->expmag_settings.device[i]); + status1 = FE_ERR_DRIVER; + } + + if (status1 == SS_SUCCESS) { +#ifdef MIDEBUG + cm_msg(MLOG, "", + "expmag_init : opening calibration file %s " + "for device %s", + info->expmag_settings.calibration[i], + info->expmag_settings.device[i]); +#endif + /* read information from file */ + if ((status1 = + splineo(info->expmag_settings.calibration[i], + &pcal->ncals, &pcal->x, &pcal->y, + TRUE)) == CM_SUCCESS) { + + /* allocate interpolation coefficients for forward + * and reverse interpolation */ + pcal->s2f = + (double *) calloc(pcal->ncals, sizeof(double)); + pcal->s3f = + (double *) calloc(pcal->ncals, sizeof(double)); + pcal->dyf = + (double *) calloc(pcal->ncals, sizeof(double)); + pcal->s2r = + (double *) calloc(pcal->ncals, sizeof(double)); + pcal->s3r = + (double *) calloc(pcal->ncals, sizeof(double)); + pcal->dyr = + (double *) calloc(pcal->ncals, sizeof(double)); + + if ((pcal->s2f != NULL) && (pcal->s3f != NULL) + && (pcal->dyf != NULL) && (pcal->s2r != NULL) + && (pcal->s3r != NULL) + && (pcal->dyr != NULL)) { + /* calculate spline coeffs in both directions*/ + status1 = + splinec(pcal->ncals, pcal->x, pcal->y, + pcal->s2f, pcal->s3f, pcal->dyf, + TRUE); + if (status1 == CM_SUCCESS) { + + status1 = + splinec(pcal->ncals, pcal->y, pcal->x, + pcal->s2r, pcal->s3r, pcal->dyr, + TRUE); + if (status1 != CM_SUCCESS) { + cm_msg(MLOG, "", + "expmag_init : Error doing reverse " + "spline interpolation for device %s", + info->expmag_settings.device[i]); + status1 = FE_ERR_DRIVER; + } else { + info->calibration[i] = pcal; + } + } else { + cm_msg(MLOG, "", + "expmag_init : Error doing forward spline" + " interpolation for device %s", + info->expmag_settings.device[i]); + status1 = FE_ERR_DRIVER; + } + } else { + cm_msg(MLOG, "", + "expmag_init : Error allocating spline " + "interpolation coefficients for device %s", + info->expmag_settings.device[i]); + status1 = FE_ERR_DRIVER; + } + } else { + cm_msg(MLOG, "", + "expmag_init : Error processing calibration " + "file %s for device %s", + info->expmag_settings.calibration[i], + info->expmag_settings.device[i]); + status1 = FE_ERR_DRIVER; + } + } + } else { + cm_msg(MLOG, "", + "expmag_init : Error allocating CalibrationRec for " + "device %s", info->expmag_settings.device[i]); + status1 = FE_ERR_DRIVER; + } + + if (status1 != SS_SUCCESS) { +#ifdef MIDEBUG + cm_msg(MLOG, "", + "expmag_init : Freeing CalibrationRec for device %s", + info->expmag_settings.device[i]); +#endif + free_calibrationrec(pcal); + free(pcal); + } + } + } +#ifdef MIDEBUG + if (status1 == SS_SUCCESS) { + if ((info->expmag_settings.scale[i] != 1.0) || + (info->expmag_settings.offset[i] != 0.0)) { + cm_msg(MLOG, "", "expmag_init : %s scale=%f, offset=%f", + info->expmag_settings.device[i], + info->expmag_settings.scale[i], + info->expmag_settings.offset[i]); + } + } +#endif + if (status1 != SS_SUCCESS) + status = status1; + } + + } /* for all devices */ + + /* check definition of server && address */ + for (i = 0; i < EMNDEVS; i++) { + int j; + + /* only check used devices */ + if (info->expmag_settings.used[i] == 'Y') { + + /* device is Magnet, check existence of referenced device */ + if (strcmp(info->expmag_settings.server[i], "MAG") == 0) { + + j = info->expmag_settings.address[i]; + /* device reference in range */ + if ((j >= 0) && (j < EMNDEVS)) { + if (info->expmag_settings.used[j] != 'Y') { + cm_msg(MLOG, "", + "expmag_init : WARNING %s referenced device %d %s " + "is disabled!", info->expmag_settings.device[i], + j, info->expmag_settings.device[j]); + } else { + if (strncmp(info->expmag_settings.device[j], "NONE", 4) + == 0) { + cm_msg(MLOG, "", + "expmag_init : WARNING %s referenced device %d " + "is %s!", info->expmag_settings.device[i], j, + info->expmag_settings.device[j]); + } + } + + } else { + cm_msg(MLOG, "", + "expmag_init : ERROR %s referenced device %d is not " + "in range |0 , %d|!", + info->expmag_settings.device[i], j, EMNDEVS - 1); + } + + /* channel reference to other device, check channel number */ + } else if (strcmp(info->expmag_settings.server[i], "CHAN")==0) { + + j = info->expmag_settings.address[i]; + + /* device reference in range */ + if ((j >= 0) && (j < EMNDEVS)) { + if (info->expmag_settings.used[j] != 'Y') { + cm_msg(MLOG, "", + "expmag_init : WARNING %s device %s of referenced " + "channel %d is disabled!", + info->expmag_settings.device[i], + info->expmag_settings.device[j], j); + } else { + if (strncmp(info->expmag_settings.device[j], "NONE", 4) + == 0) { + cm_msg(MLOG, "", + "expmag_init : WARNING %s referenced device %d " + "for CHANnel is %s!", + info->expmag_settings.device[i], j, + info->expmag_settings.device[j]); + } + } + + } else { + cm_msg(MLOG, "", + "expmag_init : ERROR %s referenced device %d is not " + "in range |0 , %d|!", + info->expmag_settings.device[i], j, EMNDEVS - 1); + } +#ifdef EPICSGFA + } else if (strcmp(info->expmag_settings.server[i], "EPICS")==0) { + // NOTHING TO DO +#endif + } + } + } + + expmag_settings_update(info); + + /* NOTE: Returning anything else than FE_SUCCESS will prevent shutdown + * of communication connections during exit. As a result + * communication to devices will be blocked. e.g. LAN/GPIB! + * Therefore always return SS_SUCCESS or execute expmag_exit + * prior to returning an error. + */ + if (status != SS_SUCCESS) { + cm_msg(MERROR,"expmag_init","During set-up of magnets - EXIT!"); + expmag_exit(info); + *pinfo = NULL; + return status; + } + + } else { + cm_msg(MLOG, "", + "expmag_init : Error reading default settings for instrument " + "%s in area %s", info->expmag_settings.instrument, + info->expmag_settings.area); + return FE_ERR_DRIVER; + } + + } else { + cm_msg(MLOG, "", + "expmag_init : Error unknown area name %s for instrument %s", + info->expmag_settings.area, info->expmag_settings.instrument); + return FE_ERR_DRIVER; + } + + } else { + cm_msg(MLOG, "", "expmag_init : Error unknown instrument name %s", + info->expmag_settings.instrument); + return FE_ERR_DRIVER; + } + + } else { + cm_msg(MLOG, "", + "expmag_init : Error area name is not defined for instrument %s", + info->expmag_settings.instrument); + return FE_ERR_DRIVER; + } + } else { + cm_msg(MLOG, "", "expmag_init : Error instrument name is not defined"); + return FE_ERR_DRIVER; + } + cm_msg_flush_buffer(); + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "--expmag_init"); +#endif + return FE_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ + +INT expmag_exit(EXPMAG_INFO * info) +{ + int i, status1; + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_exit"); +#endif + + /* call EXIT function of bus driver, usually closes device */ + if (info->bd) + info->bd(CMD_EXIT, info->bd_info); + + /* free local variables */ + +#ifdef EPICSGFA + if (info->cainfo) { + /* free EPICS channel access (sub) device driver */ + epics_ca_exit(info->cainfo); + info->cainfo = NULL; + } +#endif + + if (info->roadc) { + /* free ROAD C structure */ + for (i = 0; i < EMNDEVS; i++) { + if (*(info->roadc + i) != NULL) { + free(*(info->roadc + i)); + } + } + free(info->roadc); + } + + if (info->tcpip) { + /* free TCP/IP connections */ + for (i = 0; i < EMNDEVS; i++) { + if (*(info->tcpip + i) != NULL) { +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_exit : tcpip(EXIT)"); +#endif + status1 = tcpip(CMD_EXIT, *(info->tcpip + i)); + /* free(*(info->tcpip+i)); RA35 08-NOV-2004 Obsolete + * NOTE: Now handled in tcpip_exit() */ + } + } + free(info->tcpip); + } + + if (info->langpib) { + /* close LAN/GPIB connections */ + for (i = 0; i < EMNDEVS; i++) { + if (*(info->langpib + i) != NULL) { +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_exit : langpib(EXIT)"); +#endif + status1 = langpib(CMD_EXIT, *(info->langpib + i)); + /* free(*(info->langpib+i)); RA35 08-NOV-2004 Obsolete + * NOTE: Now handled in langpib_exit() */ + } + } + free(info->langpib); + } + + if (info->calibration) { + /* free calibration record */ + for (i = 0; i < EMNDEVS; i++) { + if (*(info->calibration + i) != NULL) { + free_calibrationrec(*(info->calibration + i)); + free(*(info->calibration + i)); + } + } + free(info->calibration); + } + + if (info->threshold) + free(info->threshold); + + free(info); + + cm_msg_flush_buffer(); + return FE_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ + +INT update_run_title_field(EXPMAG_INFO * info, INT channel, float value) +{ + HNDLE hDB; + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "update_run_title_field(channel=%d,value=%f)", channel, value); +#endif + cm_get_experiment_database(&hDB, NULL); + + if (info->expmag_settings.title[channel] == 'Y') { + char title[41]; + int size, i; + + size = sizeof(title); + for (i = 0; i < size; i++) title[i] = '\0'; + + /* read run title from ODB */ + if (db_get_value(hDB, 0, "/musr/td_musr/runinfo/runtitle", + (void *) &title[0], &size, TID_STRING, FALSE) == DB_SUCCESS) { + char field[40]; + + size = strlen(title); // returned length may not always be correct + if (size >= 41) title[40] = '\0'; + +//#ifdef MIDEBUG1 + cm_msg(MLOG, "", "update_run_title_field : old title : %s", title); +//#endif + + if (info->expmag_settings.ndigits[channel] >= 0) { + if ((value <= -1000.f) && + (info->expmag_settings.ndigits[channel] >= 3)) + snprintf(field, sizeof(field), "%.2f %s ", + value, info->expmag_settings.unit[channel]); + else if ((value <= -100.f) && + (info->expmag_settings.ndigits[channel] >= 4)) + snprintf(field, sizeof(field),"%.3f %s ", + value, info->expmag_settings.unit[channel]); + else if ((value >= 10000.f) && + (info->expmag_settings.ndigits[channel] >= 3)) + snprintf(field, sizeof(field),"%.2f %s ", + value, info->expmag_settings.unit[channel]); + else if ((value >= 1000.f) && + (info->expmag_settings.ndigits[channel] >= 4)) + snprintf(field, sizeof (field), "%.3f %s ", + value, info->expmag_settings.unit[channel]); + else + snprintf(field, sizeof(field), "%.*f %s ", + MIN(info->expmag_settings.ndigits[channel], 10), + value, info->expmag_settings.unit[channel]); + + } else { + snprintf(field, sizeof(field), "%f %s ", + value,info->expmag_settings.unit[channel]); + } + + /* fill rest of title with blanks */ + for (i = strlen(title); i < 40; i++) title[i] = ' '; + title[40] = '\0'; + + /* copy magnetic field to title = 0-9 Sample, 10-19 Temperature, + * 20-29 Magnetic field, 30-39 orientation */ + for (i = 0; i < 10; i++) title[20+i] = field[i]; + + /* write run title to ODB */ + size = sizeof(title); + if (db_set_value(hDB, 0, "/musr/td_musr/runinfo/runtitle", + (void *) title, size, 1, TID_STRING) != DB_SUCCESS) { + cm_msg(MLOG, "", "update_run_title_field : ERROR writing run title to ODB!"); +//#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "update_run_title_field : new title : %s", title); +//#endif + } + } else { + cm_msg(MLOG, "", "update_run_title_field : ERROR reading run title from ODB!"); + } + } + cm_msg_flush_buffer(); + return FE_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ + +INT roadc_device_init(EXPMAG_INFO * info, INT channel) +{ + INT ret; + + ret = CM_SUCCESS; +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "roadc_device_init(channel=%d)", channel); +#endif + /* is device used? */ + if (info->expmag_settings.used[channel] == 'Y') { + RoadCPtr proad; + + proad = (RoadCPtr) calloc(1, sizeof(RoadCRec)); + + if (proad != NULL) { + int comchan; + TCPIP_INFO *tcpipinfo; + + + /* get reference to TCP/IP communication channel of device */ + if (strcmp(info->expmag_settings.server[channel], "CHAN") == 0) { + comchan = info->expmag_settings.address[channel]; + } else { + comchan = channel; + } + + if ((comchan >= 0) && (comchan < EMNDEVS)) { + if (info->tcpip != NULL) + tcpipinfo = (TCPIP_INFO *) * (info->tcpip + comchan); + else + tcpipinfo = NULL; + + + /* send command to ROADC server */ + if ((tcpipinfo != NULL) && (tcpipinfo->fd != -1)) { + char send[512]; + char recv[512]; + char answ[30]; + int len, i; + + /* strip DAC from device name */ + strcpy(proad->device, info->expmag_settings.device[channel]); + + if ((len = strlen(proad->device)) > 3) { + if ((proad->device[len - 3] == 'D') && + (proad->device[len - 2] == 'A') && + (proad->device[len - 1] == 'C')) { + + proad->device[len - 3] = '\0'; + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "roadc_device_init RoadC device name is %s", + proad->device); + } else { + cm_msg(MLOG, "", + "roadc_device_init RoadC device name (%s) has no DAC attached", + proad->device); +#endif + } + } + + /* get device name of device number until device name is found */ + for (i = 0, proad->number = -1;; i++) { + sprintf(send, "DEVN %d", i); + sprintf(answ, "*DEVN* %d= %s", i, proad->device); + len = sizeof(recv); + + if (expmag_tcpip_sendr(info, tcpipinfo, comchan, send, recv, &len) == + CM_SUCCESS) { +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "roadc_device_init DEVN %d = >%s<", i, recv); +#endif + /* "*DEVN* error" is returned when number is not in list */ + if (strncmp(recv, "*DEVN* error", 12) == 0) { + cm_msg(MLOG, "", + "roadc_device_init RoadC device %s (%s) not found", + proad->device, info->expmag_settings.device[channel]); + ret = FE_ERR_HW; + break; + /* answer is as expected */ + } else if (strcmp(recv, answ) == 0) { + proad->number = i; /* remember device number */ + break; + /* empty string = timeout */ + } else if (len == 0) { + cm_msg(MLOG, "", + "roadc_device_init RoadC device %s (%s) ", + proad->device, info->expmag_settings.device[channel]); + ret = FE_ERR_HW; + break; + /* returned answer ("*DEVN* nnn= ") is incomplete */ + } else if (strncmp(recv, answ, strlen(answ) - strlen(proad->device)) + != 0) { + cm_msg(MLOG, "", + "roadc_device_init RoadC device %s (%s), " + "answer %s incomplete", proad->device, + info->expmag_settings.device[channel], recv); + ret = FE_ERR_HW; + break; + } + } else { + cm_msg(MLOG, "", "roadc_device_init communication ERROR sending %s", + send); + ret = FE_ERR_HW; + break; + } + } /* get device name until device name matches */ + + /* device was found get device parameter */ + if (proad->number != -1) { + + sprintf(send, "DEPA %d", proad->number); + sprintf(answ, "*DEPA* %s", proad->device); + + len = sizeof(recv); + if (expmag_tcpip_sendr(info, tcpipinfo, comchan, send, recv, &len) == + CM_SUCCESS) { + if (strncmp(recv, "*DEPA* error", 12) != 0) { + if (strncmp(recv, answ, strlen(answ)) == 0) { +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "roadc_device_init DEPA %d = >%s<", + proad->number, recv); +#endif + if (sscanf(&recv[8 + strlen(proad->device)], +/* *DEPA* SR2HV- 0 300 1.0 0.01 300000.0 2 X 2 0 0 2 0 0 2 0 0 */ + "%d %d %lf %lf %lf %d %c %d %d %d %d %d %d %d %d %d", + &proad->DAClowlim, + &proad->DACuplim, + &proad->scale, + &proad->precision, + &proad->fullscale, + &proad->DACtype, + &proad->ioflag, + &proad->ADCtype, + &proad->DACspecialbit, + &proad->DACroadaddress, + &proad->DACCAMACstation, + &proad->ADCspecialbit, + &proad->ADCroadaddress, + &proad->ADCCAMACstation, + &proad->ADCchannel, &proad->ADCrange) == 16) { + + } else { + cm_msg(MLOG, "", "roadc_device_init " + "ERROR not able to process DEPA result %s", recv); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", "roadc_device_init RoadC device %s (%s) " + "Unexpected answer %s", + proad->device, info->expmag_settings.device[channel], + recv); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", + "roadc_device_init RoadC device %s (%s) *DEPA* error", + proad->device, info->expmag_settings.device[channel]); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", "roadc_device_init communication ERROR sending %s", + send); + ret = FE_ERR_HW; + } + } + } else { + cm_msg(MLOG, "", + "roadc_device_init ERROR invalid TCP/IP communication handle"); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", + "roadc_device_init ERROR invalid communication channel number %d", + comchan); + ret = FE_ERR_HW; + } + + if (ret == CM_SUCCESS) { + if (info->roadc != NULL) { + *(info->roadc + channel) = proad; + } else { + cm_msg(MLOG, "", "roadc_device_init ERROR not able to attach RoadCRec to " + "info->roadc for %s", info->expmag_settings.device[channel]); + free(proad); + ret = FE_ERR_HW; + } + } else + free(proad); + } else { + cm_msg(MLOG, "", "roadc_device_init ERROR not able to allocate RoadCRec for %s", + info->expmag_settings.device[channel]); + } +#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "roadc_device_init Device %s (channel %d) is not used", + info->expmag_settings.device[channel], channel); +#endif + } + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "roadc_device_init(ret=%d)", ret); +#endif + + return ret; +} + +/*----------------------------------------------------------------------------*/ + +INT roadc_device_poweroff(EXPMAG_INFO * info, INT channel) +{ + INT ret; + + ret = CM_SUCCESS; + + /* is device used? */ + if ((info != NULL) && (info->expmag_settings.used[channel] == 'Y')) { + int comchan; + TCPIP_INFO *tcpipinfo; + + /* get reference to TCP/IP communication channel of device */ + if (strcmp(info->expmag_settings.server[channel], "CHAN") == 0) { + comchan = info->expmag_settings.address[channel]; + } else { + comchan = channel; + } + + if (info->tcpip != NULL) + tcpipinfo = (TCPIP_INFO *) * (info->tcpip + comchan); + else + tcpipinfo = NULL; + + + /* send command to ROADC server */ + if ((tcpipinfo != NULL) && (tcpipinfo->fd != -1)) { + RoadCPtr proad; + + if ((proad = *(info->roadc + channel)) != NULL) { + + /* if device is combi device */ + if ((proad->DACtype == 2) || (proad->DACtype == 4) || + (proad->DACtype == 5) || (proad->DACtype == 7) || (proad->DACtype == 8)) { + char send[128]; + char recv[512]; + char answ[40]; + char anse[40]; + int len; + + sprintf(send, "SWOF %s", proad->device); + sprintf(answ, "*SWOF* %s 1", proad->device); + sprintf(anse, "*SWOF* %s 0", proad->device); + + len = sizeof(recv); + if (expmag_tcpip_sendr(info, tcpipinfo, comchan, send, recv, &len) == + CM_SUCCESS) { + if (strncmp(recv, answ, strlen(answ)) == 0) { + cm_msg(MLOG, "", "RoadC device %s power off",proad->device); +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "roadc_device_poweroff SWOF %s = >%s<", + proad->device, recv); +#endif + /* OK */ + proad->poweron = FALSE; + } else if (strncmp(recv, anse, strlen(anse)) == 0) { + cm_msg(MLOG, "", + "roadc_device_poweroff ERROR turning power of device %s off", + info->expmag_settings.device[channel]); + ret = FE_ERR_HW; + } else { + cm_msg(MLOG, "", + "roadc_device_poweroff Unexpected answer SWOF %s = >%s<", + proad->device, recv); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "","roadc_device_poweroff communication ERROR sending %s", + send); + ret = FE_ERR_HW; + } + } else { + /* this device type may not be turned off */ + proad->poweron = FALSE; + } + + } else { + cm_msg(MLOG, "", + "roadc_device_poweroff ERROR NULL pointer to roadc device data " + "of %s", info->expmag_settings.device[channel]); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", + "roadc_device_poweroff ERROR invalid TCP/IP communication handle"); + ret = FE_ERR_HW; + } + +#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "roadc_device_poweroff Device %s (channel %d) is not used", + info->expmag_settings.device[channel], channel); +#endif + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ +INT roadc_device_poweron(EXPMAG_INFO * info, INT channel) +{ + INT ret; + + ret = CM_SUCCESS; + + /* is device used? */ + if (info->expmag_settings.used[channel] == 'Y') { + int comchan; + TCPIP_INFO *tcpipinfo; + + /* get reference to TCP/IP communication channel of device */ + if (strcmp(info->expmag_settings.server[channel], "CHAN") == 0) { + comchan = info->expmag_settings.address[channel]; + } else { + comchan = channel; + } + + if (info->tcpip != NULL) + tcpipinfo = (TCPIP_INFO *) * (info->tcpip + comchan); + else + tcpipinfo = NULL; + + + /* send command to ROADC server */ + if ((tcpipinfo != NULL) && (tcpipinfo->fd != -1)) { + RoadCPtr proad; + + if ((proad = *(info->roadc + channel)) != NULL) { + + /* if device is combi device */ + if ((proad->DACtype == 2) || (proad->DACtype == 4) || + (proad->DACtype == 5) || (proad->DACtype == 7) || (proad->DACtype == 8)){ + char send[128]; + char recv[512]; + char answ[40]; + char anse[40]; + int len; + + sprintf(send, "SWCO %s", proad->device); + sprintf(answ, "*SWCO* %s 1", proad->device); + sprintf(anse, "*SWCO* %s 0", proad->device); + len = sizeof(recv); + if (expmag_tcpip_sendr(info, tcpipinfo, comchan, send, recv, &len) == + CM_SUCCESS) { + if (strncmp(recv, answ, strlen(answ)) == 0) { + cm_msg(MLOG, "", "RoadC device %s power on",proad->device); +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "roadc_device_poweron SWCO %s = >%s<", + proad->device, recv); +#endif + /* OK */ + proad->poweron = TRUE; + } else if (strncmp(recv, anse, strlen(anse)) == 0) { + cm_msg(MLOG, "", + "roadc_device_poweron ERROR turning power of device %s on", + info->expmag_settings.device[channel]); + ret = FE_ERR_HW; + } else { + cm_msg(MLOG, "", + "roadc_device_poweron Unexpected answer SWCO %s = >%s<", + proad->device, recv); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", "roadc_device_poweron communication ERROR sending %s", + send); + ret = FE_ERR_HW; + } + } else { + /* this device type may not be turned on */ + proad->poweron = FALSE; + } + + } else { + cm_msg(MLOG, "", + "roadc_device_poweron ERROR NULL pointer to roadc device data " + "of %s", info->expmag_settings.device[channel]); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", + "roadc_device_poweron ERROR invalid TCP/IP communication handle"); + ret = FE_ERR_HW; + } + +#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "roadc_device_poweron Device %s (channel %d) is not used", + info->expmag_settings.device[channel], channel); +#endif + } + return ret; +} + +/*----------------------------------------------------------------------------*/ +INT roadc_device_set(EXPMAG_INFO * info, INT channel, float value) +{ + INT ret; +#ifdef MIDEBUG + cm_msg(MLOG, "", "roadc_device_set %s : (channel=%d,value=%f)", + info->expmag_settings.device[channel], channel, value); +#endif + ret = CM_SUCCESS; + + /* is device used? */ + if (info->expmag_settings.used[channel] == 'Y') { + int comchan; + TCPIP_INFO *tcpipinfo; + + /* get reference to TCP/IP communication channel of device */ + if (strcmp(info->expmag_settings.server[channel], "CHAN") == 0) { + comchan = info->expmag_settings.address[channel]; + } else { + comchan = channel; + } + + if (info->tcpip != NULL) + tcpipinfo = (TCPIP_INFO *) * (info->tcpip + comchan); + else + tcpipinfo = NULL; + + + /* get information about device from ROADC server */ + if ((tcpipinfo != NULL) && (tcpipinfo->fd != -1)) { + RoadCPtr proad; + + if ((proad = *(info->roadc + channel)) != NULL) { + char send[512]; + char recv[512]; + char answ[40]; + int len; + + sprintf(send, "RDAC %s", proad->device); + sprintf(answ, "*RDAC* %s= ", proad->device); + len = sizeof(recv); + if (expmag_tcpip_sendr(info, tcpipinfo, comchan, send, recv, &len) == + CM_SUCCESS) { + + if (strncmp(recv, "*RDAC* error", 12) != 0) { /* No error? */ + if (strncmp(recv, answ, strlen(answ)) == 0) { /* expected answer? */ + int olddac; + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "roadc_device_set RDAC %s = >%s<", proad->device, + recv); +#endif + if (sscanf(&recv[9 + strlen(proad->device)], "%d", &olddac) == 1) { + int curdac; + + /* curdac = (int) (value+0.5); MODIFIED RA36 19-OCT-2006 */ + curdac = (int) value; + + if ((curdac >= proad->DAClowlim) && (curdac <= proad->DACuplim)){ + + sprintf(send, "WDAC %s %d", proad->device, curdac); + sprintf(answ, "*WDAC* %s= %d", proad->device, curdac); + len = sizeof(recv); + + if (expmag_tcpip_sendr + (info, tcpipinfo, comchan, send, recv, + &len) == CM_SUCCESS) { +//#ifdef MIDEBUG1 + cm_msg(MLOG, "", "roadc_device_set WDAC %s = >%s<", + proad->device, recv); +//#endif + if (strncmp(recv, "*WDAC* error", 12) != 0) { + if (strncmp(recv, answ, strlen(answ)) == 0) { + int i; + + odb_keepalive(info); + odb_measured_update(info); + + if (((curdac <= -1) && (olddac <= -1)) || + ((curdac >= 0) && (olddac >= 0))) { + /* if direction did not change + wait 7 sec for field + else + wait 27 sec for polarity change and field + */ + /* add settling time to device expiration */ + if (info->expmag_settings.expiration[channel] < + ss_time() + 37) { + info->expmag_settings.expiration[channel] = + ss_time() + 37; + expmag_settings_update(info); + } + for (i=0; i < 7; i++) { + ss_sleep(1000); + odb_keepalive(info); + odb_measured_update(info); + } + } else { + + /* add settling time to device expiration */ + if (info->expmag_settings.expiration[channel] < + ss_time() + 57) { + info->expmag_settings.expiration[channel] = + ss_time() + 57; + expmag_settings_update(info); + } + //for (i=0; i < 30; i++) { // RA36 30-MAR-2006 + for (i=0; i < 10; i++) { + ss_sleep(1000); /* changed 15-SEP-2005 */ + odb_keepalive(info); + odb_measured_update(info); + } + } + /* NOTE: ODB watch dog will terminate ODB connection + * after 60 seconds of inactivity. Wait time + * should be less than 30 seconds to be sure + * that connection is not terminated! + */ + /* omit polarity changes of WED & HELM */ + //NIY if (curdac != -1) + cm_msg(MLOG, "", "ROADC device %s set to %d DAC", + proad->device, curdac); + } else { + cm_msg(MLOG, "", "roadc_device_set : ERROR WDAC %s " + "%d = >%s<", proad->device, curdac, recv); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", "roadc_device_set ERROR setting new " + "DAC value (%d) of device %s", curdac, + info->expmag_settings.device[channel]); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", + "roadc_device_set communication ERROR sending %s", + send); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", + "roadc_device_set(channel=%d : %s : RoadC = %s) " + "ERROR DAC value %d out of range |%d,%d|!", channel, + info->expmag_settings.device[channel], proad->device, + curdac, proad->DAClowlim, proad->DACuplim); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", + "roadc_device_set ERROR processing answer >%s< of RDAC " + "%s", recv, proad->device); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", + "roadc_device_set ERROR Unexpected answer RDAC %s = >%s<", + proad->device, recv); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", + "roadc_device_set ERROR getting currently set DAC value " + "of device %s", info->expmag_settings.device[channel]); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", "roadc_device_set communication ERROR sending %s", send); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", + "roadc_device_set ERROR NULL pointer to roadc device data of %s", + info->expmag_settings.device[channel]); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", "roadc_device_set ERROR invalid TCP/IP communication handle"); + ret = FE_ERR_HW; + } + +#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "roadc_device_set Device %s (channel %d) is not used", + info->expmag_settings.device[channel], channel); +#endif + } + return ret; +} + +/*----------------------------------------------------------------------------*/ +INT roadc_device_get(EXPMAG_INFO * info, INT channel, float *pvalue) +{ + INT ret; + + ret = CM_SUCCESS; + + if (pvalue != NULL) + *pvalue = 0.0; + + /* is device used? */ + if (info->expmag_settings.used[channel] == 'Y') { + int comchan; + TCPIP_INFO *tcpipinfo; + + /* get reference to TCP/IP communication channel of device */ + if (strcmp(info->expmag_settings.server[channel], "CHAN") == 0) { + comchan = info->expmag_settings.address[channel]; + } else { + comchan = channel; + } + + if (info->tcpip != NULL) + tcpipinfo = (TCPIP_INFO *) * (info->tcpip + comchan); + else + tcpipinfo = NULL; + + /* reopen connection RA36 10-MAY-2006 */ + if ((tcpipinfo != NULL) && (tcpipinfo->fd == -1) && + strlen(tcpipinfo->settings.host) && (tcpipinfo->settings.port>0)) + tcpipinfo->fd = + tcpip_connect(tcpipinfo->settings.host, tcpipinfo->settings.port); + // 1.9.5 was tcpip_open(tcpipinfo->settings.host, tcpipinfo->settings.port); + + /* get information about device from ROADC server */ + if ((tcpipinfo != NULL) && (tcpipinfo->fd != -1)) { + RoadCPtr proad; + + if ((proad = *(info->roadc + channel)) != NULL) { + char send[512]; + char recv[512]; + char answ[40]; + int len; + +#ifdef MIDEBUG + cm_msg(MLOG, "", "roadc_device_get %s ", proad->device); +#endif + /* Combi Device? read status word from CAMAC */ + if ((proad->DACtype == 2) || (proad->DACtype == 4) || (proad->DACtype == 5) || + (proad->DACtype == 7) || (proad->DACtype == 8)) { + + /* CAMAC N A f command to read DAC status word */ + if (proad->DACspecialbit == 0) // function = 2 + sprintf(send, "RCAM %d %d 02", proad->DACCAMACstation, + proad->DACroadaddress); + else // DAC special bit set f = 3 + sprintf(send, "RCAM %d %d 03", proad->DACCAMACstation, + proad->DACroadaddress); + len = sizeof(recv); + if (expmag_tcpip_sendr(info, tcpipinfo, comchan, send, recv, &len) == + CM_SUCCESS) { + if (strncmp(recv, "*RCAM* error", 12) != 0) { + int cstatus, status; + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "roadc_device_get %s : %s = >%s<", proad->device, + send, recv); +#endif + + cstatus = status = 0; + if (sscanf(&recv[7], "%d %d", &cstatus, &status) == 2) { + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "roadc_device_get %s : CAMACstatus = %d, " + "DEVICEstatus = %d", proad->device, cstatus, status); +#endif + // NIY check CAMAC status + //if (cstatus == 1) { + if (status & 0x100) { +#ifdef MIDEBUGT + cm_msg(MLOG, "", "roadc_device_get %s : power switched ON", + proad->device); +#endif +#ifdef MIDEBUG + if (!proad->poweron) + cm_msg(MLOG, "", "roadc_device_get %s : power switched ON", + proad->device); +#endif + proad->poweron = TRUE; + } else { +#ifdef MIDEBUGT + cm_msg(MLOG, "", "roadc_device_get %s : power switched OFF", + proad->device); +#endif +#ifdef MIDEBUG + if (proad->poweron) + cm_msg(MLOG, "", "roadc_device_get %s : power switched OFF", + proad->device); +#endif + proad->poweron = FALSE; + } + //} else { + // proad->poweron = FALSE; + // NIY Invalid CAMAC status + //} + } else { + cm_msg(MLOG, "", + "roadc_device_get : ERROR processing status byte (%s) " + "returned by command %s of device %s", recv, send, + info->expmag_settings.device[channel]); + } + } else { + cm_msg(MLOG, "", + "roadc_device_get : ERROR getting CAMAC status word of " + "device %s", info->expmag_settings.device[channel]); + } + } else { + cm_msg(MLOG, "", "roadc_device_get %s communication ERROR sending %s", + proad->device, send); + } + } + + sprintf(send, "RADC %s", proad->device); + sprintf(answ, "*RADC* %s= ", proad->device); + len = sizeof(recv); + if (expmag_tcpip_sendr(info, tcpipinfo, comchan, send, recv, &len) == + CM_SUCCESS) { + + if (strcmp(recv, "*RADC* error") != 0) { + if (strncmp(recv, answ, strlen(answ)) == 0) { + float curadc; + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "roadc_device_get RADC %s = >%s<", proad->device, + recv); +#endif + /* current ADC value */ + if (sscanf(&recv[9 + strlen(proad->device)], "%f", &curadc) == 1) { + int dacuplim; + + //dacuplim = proad->DACuplim; // RA36 07-SEP-2006 + // problems when upper limit in device != limit of DACType + dacuplim = 0; + if (dacuplim == 0) { // always take limit of DACType + switch (proad->DACtype) { + case 0: + case 2: + case 7: + dacuplim = 4095; + break; + case 1: + case 4: + dacuplim = 65535; + break; + case 5: + case 8: + dacuplim = 2047; + break; + case 9: + dacuplim = 5999; + break; + case 3: /* not used anymore */ + case 6: /* not used */ + + default: + dacuplim = 0; + } + } + + /* converted value of ADC readout of device to DAC readout */ + if (proad->scale != 0.0f) { + if (proad->ADCrange == 1) + curadc = curadc / 10.0f * (float) dacuplim / proad->scale; + else + curadc = curadc * (float) dacuplim / proad->scale; + // QUICK FIX to be able to test HELMH + // not used anymore RA36 14-JUL-06 + //if (strcmp(proad->device,"HELMH") == 0) + // HELMH replaced by HELMH2 + // curadc = -curadc; + } else { + cm_msg(MLOG, "", + "roadc_device_get ERROR zero divide calculating DAC " + " from ADC : scale of device %s is 0.0", + info->expmag_settings.device[channel]); + } + + /* only return non zero value if power is on */ + if ((pvalue != NULL) && (proad->poweron)) + *pvalue = curadc; + + } else { + cm_msg(MLOG, "", + "roadc_device_get ERROR processing answer >%s< of RADC " + "%s", recv, proad->device); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "","roadc_device_get Unexpected answer RADC %s = >%s<", + proad->device, recv); + } + } else { + cm_msg(MLOG, "", + "roadc_device_get ERROR getting currently set ADC value of " + "device %s", info->expmag_settings.device[channel]); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", "roadc_device_get communication ERROR sending %s", send); + ret = FE_ERR_HW; + } + +#ifdef MIDEBUG1 + if (pvalue != NULL) + cm_msg(MLOG, "", "roadc_device_get : %s : ROADC=%s value = %f", + info->expmag_settings.device[channel], proad->device, *pvalue); +#endif + + } else { + cm_msg(MLOG, "", + "roadc_device_get ERROR NULL pointer to roadc device data of %s", + info->expmag_settings.device[channel]); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", "roadc_device_get ERROR invalid TCP/IP communication handle"); + ret = FE_ERR_HW; + } + +#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "roadc_device_get Device %s (channel %d) is not used", + info->expmag_settings.device[channel], channel); +#endif + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ + +INT roadc_device_get_demand(EXPMAG_INFO * info, INT channel, float *pvalue) +{ + + INT ret; + + ret = CM_SUCCESS; + + /* if (pvalue != NULL) *pvalue = 0.0; *//* RA36 15-SEP-2005 keep last value */ + + /* is device used? */ + if (info->expmag_settings.used[channel] == 'Y') { + int comchan; + TCPIP_INFO *tcpipinfo; + + /* get reference to TCP/IP communication channel of device */ + if (strcmp(info->expmag_settings.server[channel], "CHAN") == 0) { + comchan = info->expmag_settings.address[channel]; + } else { + comchan = channel; + } + + if (info->tcpip != NULL) + tcpipinfo = (TCPIP_INFO *) * (info->tcpip + comchan); + else + tcpipinfo = NULL; + + + /* get information about device from ROADC server */ + if ((tcpipinfo != NULL) && (tcpipinfo->fd != -1)) { + RoadCPtr proad; + + if ((proad = *(info->roadc + channel)) != NULL) { + char send[512]; + char recv[512]; + char answ[40]; + int len; + + sprintf(send, "RDAC %s", proad->device); + sprintf(answ, "*RDAC* %s= ", proad->device); + len = sizeof(recv); + if (expmag_tcpip_sendr(info, tcpipinfo, comchan, send, recv, &len) == + CM_SUCCESS) { + + if (strncmp(recv, "*RDAC* error", 12) != 0) { + if (strncmp(recv, answ, strlen(answ)) == 0) { + int curdac; + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "roadc_device_get_demand RDAC %s = >%s<", + proad->device, recv); +#endif + if (sscanf(&recv[9 + strlen(proad->device)], "%d", &curdac) == 1) { + + /* only return non zero value if power is on */ + /* dropped this to avoid database value being set to 0 + * if power is still off RA36 19-SEP-2005 */ + + /* if ((pvalue!=NULL)&&(proad->poweron)) *pvalue=(float)curdac;*/ + if (pvalue != NULL) + *pvalue = (float) curdac; + + } else { + cm_msg(MLOG, "", + "roadc_device_get_demand ERROR processing answer >%s< " + "of RDAC %s", recv, proad->device); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", + "roadc_device_get_demand Unexpected answer RDAC %s = >%s<", + proad->device, recv); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", + "roadc_device_get_demand ERROR getting currently set DAC " + "value of device %s", info->expmag_settings.device[channel]); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", "roadc_device_get_demand communication ERROR sending %s", + send); + ret = FE_ERR_HW; + } + +#ifdef MIDEBUG + if (pvalue != NULL) + cm_msg(MLOG, "", "roadc_device_get_demand : %s : ROADC=%s value = %f", + info->expmag_settings.device[channel], proad->device, *pvalue); +#endif + + } else { + cm_msg(MLOG, "", + "roadc_device_get_demand ERROR NULL pointer to roadc device " + "data of %s", info->expmag_settings.device[channel]); + ret = FE_ERR_HW; + } + } else { + cm_msg(MLOG, "", + "roadc_device_get_demand ERROR invalid TCP/IP communication handle"); + ret = FE_ERR_HW; + } + +#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "roadc_device_get_demand Device %s (channel %d) is not used", + info->expmag_settings.device[channel], channel); +#endif + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ +INT get_device_channel(EXPMAG_INFO * info, char *device) +{ + INT ret; + + ret = -1; + if ((device != NULL) && (strlen(device) > 0)) { + int i; + + for (i = 0; i < EMNDEVS; i++) + if (strcmp(info->expmag_settings.device[i], device) == 0) { + ret = i; +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "get_device_channel : %s = channel %d", device, ret); +#endif + break; + } + + if (ret == -1) + cm_msg(MLOG, "", "get_device_channel WARNING %s : channel not found!", device); + + } else { + if (device == NULL) + cm_msg(MLOG, "", + "get_device_channel ERROR null pointer to device name supplied!"); + else + cm_msg(MLOG, "", + "get_device_channel ERROR empty string supplied as device name!"); + } + return ret; +} + +/*----------------------------------------------------------------------------*/ +INT get_demand_array(EXPMAG_INFO * info, float *pfla) +{ + INT ret; + + ret = SS_INVALID_ADDRESS; + + if ((info != NULL) && (pfla != NULL)) { + HNDLE hdb; + + cm_get_experiment_database(&hdb, NULL); + + if (info->hkey_demand == 0) { + char tstr[512]; + + /* get ODB key of ../Variables/Demand */ + sprintf(tstr, "%sDemand", info->varpath); + if (db_find_key(hdb, 0, tstr, &info->hkey_demand) != DB_SUCCESS) { + cm_msg(MLOG, "", "get_demand_array : ERROR ODB key %s not found", tstr); + info->hkey_demand = 0; +#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "get_demand_array : db_find_key(%s)", tstr); +#endif + } + } + + if (info->hkey_demand != 0) { + int bufsize; + + /* get demand array */ + bufsize = EMNDEVS * sizeof(float); + ret = db_get_data(hdb, info->hkey_demand, (void *) pfla, &bufsize, TID_FLOAT); + } + + } else { + if (info == NULL) + cm_msg(MLOG, "", "get_demand_array : ERROR NULL pointer to expmag info!"); + if (pfla == NULL) + cm_msg(MLOG, "", "get_demand_array : ERROR NULL pointer return demand array!"); + } + return ret; +} + +/*----------------------------------------------------------------------------*/ +INT odb_keepalive(EXPMAG_INFO * info) +{ + float dummy[EMNDEVS]; +#ifdef MIDEBUG2 + cm_msg(MLOG, "", "odb_keepalive"); +#endif + return get_demand_array(info, dummy); +} + +/*----------------------------------------------------------------------------*/ +// directly update Measured variables in ODB +INT odb_measured_update(EXPMAG_INFO *info){ + INT ret; + + ret = SS_INVALID_ADDRESS; + + if (info != NULL) { + HNDLE hdb; + + cm_get_experiment_database(&hdb, NULL); + + if (info->hkey_measured == 0) { + char tstr[512]; + + /* get ODB key of ../Variables/Measured */ + sprintf(tstr, "%sMeasured", info->varpath); + if (db_find_key(hdb, 0, tstr, &info->hkey_measured) != DB_SUCCESS) { + cm_msg(MLOG, "", "odb_measured_update : ERROR ODB key %s not found", tstr); + info->hkey_measured = 0; + ret = DB_NO_KEY; +#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "odb_measured_update : db_find_key(%s)", tstr); +#endif + } + } + + if (info->hkey_measured != 0) { + INT i,ret1; + float value; + + for (i=0; i < EMNDEVS; i++) { + if (expmag_get(info, i, &value) == FE_SUCCESS) { + if ((ret1 = db_set_data_index(hdb, info->hkey_measured, &value, + sizeof(value), i, TID_FLOAT)) != DB_SUCCESS) { + cm_msg(MLOG, "", "odb_measured_update : ERROR Not able to set " + "Measured[%d]!",i); + ret = ret1; +#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "odb_measured_update : [%d] = %f",i,value); +#endif + } + } + } + } +#ifdef EPICSGFA + epics_channels_update(info); +#endif + } else { + cm_msg(MLOG, "", "odb_measured_update : ERROR NULL pointer to expmag info!"); + } + return ret; +} +/*----------------------------------------------------------------------------*/ + +// directly update Demand variables in ODB +INT update_demand_array(EXPMAG_INFO * info, float *pfla, int channel) +{ + INT ret; + + ret = SS_INVALID_ADDRESS; + + if ((info != NULL) && (pfla != NULL)) { + HNDLE hdb; + + cm_get_experiment_database(&hdb, NULL); + + if (info->hkey_demand == 0) { + char tstr[512]; + + /* get ODB key of ../Variables/Demand */ + sprintf(tstr, "%sDemand", info->varpath); + if (db_find_key(hdb, 0, tstr, &info->hkey_demand) != DB_SUCCESS) { + cm_msg(MLOG, "", "update_demand_array : ERROR ODB key %s not found", tstr); + info->hkey_demand = 0; +#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "update_demand_array : db_find_key(%s)", tstr); +#endif + } + } + + if (info->hkey_demand != 0) { + float tfla[EMNDEVS]; + int bufsize; + + get_demand_array(info, tfla); + + if ((channel >= 0) && (channel < EMNDEVS)) { + if (tfla[channel] != *(pfla + channel)) { + tfla[channel] = *(pfla + channel); +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "update_demand_array : %d = %f", channel, tfla[channel]); +#endif + bufsize = EMNDEVS * sizeof(float); + + /* set demand array */ + ret = db_set_data(hdb, info->hkey_demand, (void *) tfla, bufsize, EMNDEVS, + TID_FLOAT); + } + } else { + cm_msg(MLOG, "", "update_demand_array : ERROR channel %d out of range " + "|0-%d|!", channel, EMNDEVS - 1); + } + } + } else { + if (info == NULL) + cm_msg(MLOG, "", "update_demand_array : ERROR NULL pointer to expmag info!"); + if (pfla == NULL) + cm_msg(MLOG, "", "update_demand_array : ERROR NULL pointer to demand array!"); + } + return ret; +} + +/*----------------------------------------------------------------------------*/ + +/* + * set Zero Field Compensation Mode + * flag = TRUE : called prior to setting device to value setting ZFC to TABLE mode + * flag = FALSE: called after setting device to value if no field setting ZFC to ACTIVE + */ +INT set_zfc_mode(EXPMAG_INFO *info, INT channel, float value, INT flag) { + INT status; + + status = FE_SUCCESS; + + if (( info != NULL) && ((info->expmag_settings.zfc_used == 'Y') || + (info->expmag_settings.zfc_used == 'y'))) { + HNDLE hDB; + INT odbstat, odbvalue, size; + INT itries, ntries; + + cm_get_experiment_database(&hDB, NULL); + ntries = 3; + itries = 0; + + // get auto mode key +auto_again: + odbvalue = 0; + size = sizeof(odbvalue); + odbstat = db_get_value(hDB,0,"/Equipment/ZFC/Settings/Devices/IN/DD/Automatic (0,1)", + &odbvalue, &size, TID_INT, FALSE); + + if (odbstat == DB_SUCCESS) { + if (odbvalue == 1) { + INT oldmode; + itries = 0; +mode_again: + oldmode = 1; + size = sizeof(oldmode); + odbstat=db_get_value(hDB,0,"/Equipment/ZFC/Settings/Devices/IN/DD/Mode (0,1,2)", + &oldmode, &size, TID_INT, FALSE); + if (odbstat == DB_SUCCESS) { + INT newmode; + + newmode = oldmode; + + // before changing magnet channel to value + if (flag) { + + if (oldmode == 1) { // in active compensation + if (value != 0.0) newmode = 2; // -> switch to table mode + } else if (oldmode == 2) { // in table mode + /* do nothing */ // already in table mode + } else { // in unknown and invalid mode + newmode = 2; // -> switch to table mode + } + + // after changing magnet channel to value + } else { + + if (value == 0.0) { // if this device was set to 0.0 + int i; + + newmode = 1; // assume ACTIVE mode + // and check other magnets + for (i=0;iexpmag_settings.used[i] == 'Y') { + if (info->set_values[i] != 0.0) { + // HELM == -1 and HELMH2DAC or WEH82 == -1 are special cases. + // special case: HELM is not used to set field (-1). + // -1 is used to change polarity to attach another power + // supply to the magnet. power of HELM is off. + // + // NOTE: due to new power supplies WED special case is now obsolete + if (((strcmp(info->expmag_settings.device[i],"HELM") == 0) || +#ifdef EPICSGFA + (strcmp(info->expmag_settings.device[i],"WEH82") == 0) +#else + (strcmp(info->expmag_settings.device[i],"HELMH2DAC") == 0) +#endif + ) && (info->set_values[i] == -1.0)) { + /* do nothing */; + } else { + newmode = 2; // switch to TABLE mode + break; + } + } + } + } + + } else + newmode = 2; // switch to TABLE mode + } + + // mode should be changed + if (newmode != oldmode) { + + itries = 0; +init_mode_changed: + // init Mode changed to 0 to be able to synchronize with zfc_control + odbvalue = 0; + size = sizeof(odbvalue); + odbstat = db_set_value(hDB,0, + "/Equipment/ZFC/Settings/Devices/IN/DD/Mode Changed (0,1)", + &odbvalue, size, 1, TID_INT); + if (odbstat == DB_SUCCESS) { + + // set Mode to newmode + itries = 0; +mode_change: + odbvalue = newmode; + size = sizeof(odbvalue); + odbstat = db_set_value(hDB,0, + "/Equipment/ZFC/Settings/Devices/IN/DD/Mode (0,1,2)", + &odbvalue, size, 1, TID_INT); + if (odbstat == DB_SUCCESS) { + DWORD timeo; + + // wait until Mode Changed is 1 + // but not longer than 60 seconds + timeo = ss_time()+60; + do { +#ifdef EPICSGFA + epics_wait(info,3, 333); +#else + ss_sleep(1000); +#endif + odbvalue = 0; + size = sizeof(odbvalue); + odbstat = db_get_value(hDB,0, + "/Equipment/ZFC/Settings/Devices/IN/DD/Mode Changed (0,1)", + &odbvalue, &size, TID_INT, FALSE); + if (timeo > ss_time() + 60) timeo = ss_time()+30; + } while ((odbvalue == 0) && (ss_time() < timeo)); + + if (odbstat != DB_SUCCESS) { + cm_msg(MERROR,"set_zfc_mode","ERROR %d reading \"Mode Changed\" to " + "synchronise with zfc_control", odbstat); + } + if (odbvalue == 0) { + cm_msg(MERROR,"set_zfc_mode","Timeout waiting for \"Mode Changed\" to " + "be set to 1! zfc_control may not be running"); + } + // reset "Mode Changed" back to 0 + itries = 0; +reset_mode_changed: + odbvalue = 0; + size = sizeof(odbvalue); + odbstat = db_set_value(hDB,0, + "/Equipment/ZFC/Settings/Devices/IN/DD/Mode Changed (0,1)", + &odbvalue, size, 1, TID_INT); + if (odbstat != DB_SUCCESS) { + itries++; + cm_msg(MERROR,"set_zfc_mode","ERROR %d resetting \"Mode Changed\" to " + "zero", odbstat); + if (itries < ntries) goto reset_mode_changed; + } + } else { + itries++; + cm_msg(MERROR,"set_zfc_mode","ERROR %d setting \"Mode\" to %d", + odbstat,odbvalue); + if (itries < ntries) goto mode_change; + } + } else { + itries++; + cm_msg(MERROR,"set_zfc_mode","ERROR %d setting \"Mode Changed\" to zero", + odbstat); + if (itries < ntries) goto init_mode_changed; + } + } + + } else { + itries++; + // NIY check if retry is reasonable + cm_msg(MERROR,"set_zfc_mode","db_get_value(...Mode (0,1,2)) returned ERROR %d", + odbstat); + if (itries < ntries) goto auto_again; + } + } else { + cm_msg(MLOG,"","ZFC Automatic (0,1) is in User operation mode (0) - " + "Not changing mode!"); + } + } else { + itries++; + // NIY check if retry is reasonable + cm_msg(MERROR,"set_zfc_mode","db_get_value(...Automatic (0,1)) returned ERROR %d", + odbstat); + if (itries < ntries) goto auto_again; + } + } else { +#ifdef MIDEBUG + if (info == NULL) + cm_msg(MLOG,"","NULL pointer to device info"); + else + cm_msg(MLOG,"","\"ZFC used\" set to FALSE. Setting ZFC is currently disabled"); +#endif + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/* pfla == NULL -> value set by ODB change */ +INT expmag_set(EXPMAG_INFO * info, INT channel, float value, float *pfla) +{ + HNDLE hdb; + char path[512]; + + if (strncmp(info->expmag_settings.device[channel], "NONE", 4) != 0) { + if (info->expmag_settings.used[channel] == 'Y') { + float prevval; + +#ifdef MIDEBUG + cm_msg(MLOG, "", "expmag_set %s : (channel=%d,value=%f %s)", + info->expmag_settings.device[channel], channel, value, + pfla ? "local" : "ODB"); +#endif + + /* init */ + if (info->set_values[channel] == -2.0) { + info->set_values[channel] = value; + } else { + /* filter : do not execute command if called by ODB change and value did not + * change */ + if (pfla == NULL) { + if (info->set_values[channel] == value) { +#ifdef MIDEBUG + cm_msg(MLOG, "", "expmag_set %s (channel=%d) already set", + info->expmag_settings.device[channel], channel); +#endif + return FE_SUCCESS; + + } + } + } + + /* remember previously set value */ + prevval = info->set_values[channel]; + + /* update local copy of last set value */ + info->set_values[channel] = value; + + /* flagged device? + * NOTE: a negative field tells that this device's field should not be set now. + * Midas periodically tries to set each channnel, which leads to problems + * with HELM & GOSSEN (but not anymore WED and WEDL). + */ + if ((strncmp(info->expmag_settings.type[channel], "MAG", 3) == 0) + && (value < 0.0)) { + /* + * Exceptions having positive and negative polarity: WEUL, WEV, WEDL, WEP + */ + if ((strcmp(info->expmag_settings.device[channel], "WEUL") == 0) || + (strcmp(info->expmag_settings.device[channel], "WEV") == 0) || + (strcmp(info->expmag_settings.device[channel], "WEDL") == 0) || + (strcmp(info->expmag_settings.device[channel], "WEP") == 0)) { + cm_msg(MLOG, "", "expmag_set %s (channel=%d) negative value NOT flagged " + "(will be set)", info->expmag_settings.device[channel], channel); + } else { +#ifdef MIDEBUG + cm_msg(MLOG, "", "expmag_set %s (channel=%d) negative value flagged (will " + "no be set)", info->expmag_settings.device[channel], channel); +#endif + return FE_SUCCESS; + } + } + + cm_msg(MLOG, "", "expmag_set %s : (channel=%d,value=%f)", + info->expmag_settings.device[channel], channel, value); + + /* check if value is in range */ + if ((value == 0.0) || + /* for PSIBL take minval/maxval and for MAG&GOSSEN take minrval/maxrval */ + ((strncmp(info->expmag_settings.type[channel], "PSIBL", 5) == 0) && + (value >= info->expmag_settings.minval[channel]) && + (value <= info->expmag_settings.maxval[channel])) || +#ifdef EPICSGFA + ((strncmp(info->expmag_settings.type[channel], "EPICSGFA",8) == 0) && + (value >= info->expmag_settings.minrval[channel]) && + (value <= info->expmag_settings.maxrval[channel])) || +#endif + ((strncmp(info->expmag_settings.type[channel], "GOSSEN", 6) == 0) && + (value >= info->expmag_settings.minrval[channel]) && + (value <= info->expmag_settings.maxrval[channel])) || + ((strncmp(info->expmag_settings.type[channel], "MAG", 3) == 0) && + (value >= info->expmag_settings.minrval[channel]) && + (value <= info->expmag_settings.maxrval[channel]))) { + float result; + +#ifdef EPICSGFA + // block evaluation of in range tolerance + if (info->cainfo) epics_ca_set_pending(info->cainfo, TRUE); +#endif + /* 0.0 is always 0.0 */ + if (value != 0.0) { + + /* do calibration? */ + if (*(info->calibration + channel) != NULL) { + double valued, resultd; + + /* forward interpolation? */ + if ((*(info->calibration + channel))->direction) { + + valued = value; + + if (splines((*(info->calibration + channel))->ncals, + (*(info->calibration + channel))->x, + (*(info->calibration + channel))->y, + (*(info->calibration + channel))->s2f, + (*(info->calibration + channel))->s3f, + (*(info->calibration + channel))->dyf, + 1, &valued, &resultd, 0) != SS_SUCCESS) { + cm_msg(MLOG, "", + "expmag_set(channel=%d,value=%f) forward interpolation " + "out of range", channel, valued); + } +#ifdef MIDEBUG + cm_msg(MLOG, "", + "expmag_set(channel=%d,value=%f,forw interpolation=%f)", + channel, valued, resultd); +#endif + + /* result = scale*value +offset */ + result = info->expmag_settings.scale[channel] * resultd + + info->expmag_settings.offset[channel]; + +#ifdef MIDEBUG + cm_msg(MLOG, "", + "expmag_set(channel=%d,value=%f,value*scale+offset=%f)", + channel, resultd, result); +#endif + + /* reverse interpolation */ + } else { + if (info->expmag_settings.scale[channel] != 0.0) { + /* result = (value -offset)/scale */ + valued = (value - info->expmag_settings.offset[channel]) / + info->expmag_settings.scale[channel]; +#ifdef MIDEBUG + cm_msg(MLOG, "", + "expmag_set(channel=%d,value=%f,(value-offset)/scale=%f)", + channel, value, valued); +#endif + + if (splines((*(info->calibration + channel))->ncals, + (*(info->calibration + channel))->y, + (*(info->calibration + channel))->x, + (*(info->calibration + channel))->s2r, + (*(info->calibration + channel))->s3r, + (*(info->calibration + channel))->dyr, + 1, &valued, &resultd, 0) != SS_SUCCESS) { + cm_msg(MLOG, "", + "expmag_set(channel=%d,value=%f) reverse interpolation " + "out of range", channel, valued); + } +#ifdef MIDEBUG + cm_msg(MLOG, "", + "expmag_set(channel=%d,value=%f,rev interpolation=%f)", + channel, valued, resultd); +#endif + result = resultd; + } else { + cm_msg(MLOG, "", + "expmag_set(channel=%d) (value-offset)/scale undefined " + "with scale = 0.0!", channel); + result = 0.0; + } + + } + + /* no calibration file */ + } else { + + /* result = scale*value +offset */ + result = info->expmag_settings.scale[channel] * value + + info->expmag_settings.offset[channel]; + +#ifdef MIDEBUG + cm_msg(MLOG, "", + "expmag_set(channel=%d,value=%f,value*scale+offset=%f)", channel, + value, result); +#endif + } + + } else { +#ifdef MIDEBUG + cm_msg(MLOG, "", "expmag_set(channel=%d,value=%f)", channel, value); +#endif + result = 0.0; + } + + /* if type == MAG */ + if (strncmp(info->expmag_settings.type[channel], "MAG", 3) == 0) { + if (strncmp(info->expmag_settings.server[channel], "MAG", 3) == 0) { + int ref; + + ref = info->expmag_settings.address[channel]; + + /* integer expected -> round to nearest integer? */ + if (strncmp(info->expmag_settings.type[ref], "PSIBL", 5) == 0) { + float rest, resultt; +#ifdef MIDEBUG + float resulto; + + resulto = result; +#endif + resultt = (float) ((int) result); + rest = result - resultt; + result = resultt; + if (rest >= 0.0) { + if (rest > 0.50) + result = resultt + 1.0; + } else { + if (rest < -0.50) + result = resultt - 1.0; + } +#ifdef MIDEBUG + cm_msg(MLOG, "", "expmag_set Round %f -> %f + %f -> %f", resulto, + resultt, rest, result); +#endif + } + + /* check if calculated value is in range of referenced device */ + if ((result == 0.0) || + /* for PSIBL take minval/maxval and for MAG,EPICSGFA&GOSSEN + * take minrval/maxrval */ + ((strncmp(info->expmag_settings.type[ref], "PSIBL", 5) == 0) && + (result >= info->expmag_settings.minval[ref]) && + (result <= info->expmag_settings.maxval[ref])) || +#ifdef EPICSGFA + ((strncmp(info->expmag_settings.type[ref], "EPICSGFA",8) == 0) && + (result >= info->expmag_settings.minrval[ref]) && + (result <= info->expmag_settings.maxrval[ref])) || +#endif + ((strncmp(info->expmag_settings.type[ref], "GOSSEN", 6) == 0) && + (result >= info->expmag_settings.minrval[ref]) && + (result <= info->expmag_settings.maxrval[ref])) || + ((strncmp(info->expmag_settings.type[ref], "MAG", 3) == 0) && + (result >= info->expmag_settings.minrval[ref]) && + (result <= info->expmag_settings.maxrval[ref]))) { + float fla[EMNDEVS]; + int i, ret; + + if (pfla != NULL) { + for (i = 0; i < EMNDEVS; i++) + fla[i] = *(pfla + i); + ret = DB_SUCCESS; + } else { + for (i = 0; i < EMNDEVS; i++) + fla[i] = 0.0; + /* get demand array */ + ret = get_demand_array(info, fla); + } + + if (ret == DB_SUCCESS) { + int setref, tchan; + + setref = -1; +#ifdef MIDEBUG + for (i = 0; i < EMNDEVS; i++) + cm_msg(MLOG, "", "expmag_set channel=%d ODB = %f", i, fla[i]); +#endif + + /* if value changed forward calc. value to referenced device */ + if (fla[ref] != result) { + + /* replace demand value of reference */ + fla[ref] = result; +#ifdef MIDEBUG + cm_msg(MLOG, "", "expmag_set channel=%d -> %f", ref, result); +#endif + setref = ref; + + /* set demand array */ + if (update_demand_array(info, fla, ref) == CM_SUCCESS) { + update_run_title_field(info, channel, value); + } else { + cm_msg(MLOG, "", "expmag_set : ERROR Not able to update " + "demand array on ODB!"); + } + } + + /* routine was called by ODB update */ + if (pfla == NULL) { + + /* -- VMS in PIE1 */ + if ((strcmp(info->expmag_settings.instrument, "VMS") == 0)&& + (strcmp(info->expmag_settings.area, "PIE1") == 0)) { + + if (strcmp(info->expmag_settings.device[channel], "WEU") == + 0) { + int setweul = 1; +#ifdef EPICSGFA + int setwev, setwevamp, setweulamp; + setwev = setwevamp = setweulamp = -1; +#else + int setwev, setwevdac; + setwev = setwevdac = -1; +#endif + + /* WEU <> 0.0 */ + if (value != 0.0) { + /* SET WEUL = 0.0 */ + if ((tchan = get_device_channel(info, "WEUL")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setweul = tchan; + } + } + +#ifdef EPICSGFA + /* SET WEULAMP = 0 */ + if ((tchan=get_device_channel(info,"WEULAMP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setweulamp = tchan; + } + } +#endif + +#ifdef VMS_OTHER_SET_ZERO + /* SET WEV = 0.0 */ + if ((tchan = get_device_channel(info, "WEV")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwev = tchan; + } + } + +#ifdef EPICSGFA + /* SET WEVAMP = 0 */ + if ((tchan=get_device_channel(info,"WEVAMP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwevamp = tchan; + } + } +#else + /* SET WEVDAC = 0 */ + if ((tchan=get_device_channel(info,"WEVDAC")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwevdac = tchan; + } + } +#endif +#endif /* #ifdef VMS_OTHER_SET_ZERO */ + + } + + if (setweul != -1) + expmag_set(info, setweul, fla[setweul], fla); +#ifdef EPICSGFA + if (setweulamp != -1) + expmag_set(info, setweulamp, fla[setweulamp], fla); +#endif + if (setwev != -1) + expmag_set(info, setwev, fla[setwev], fla); +#ifdef EPICSGFA + if (setwevamp != -1) + expmag_set(info, setwevamp, fla[setwevamp], fla); +#else + if (setwevdac != -1) + expmag_set(info, setwevdac, fla[setwevdac], fla); +#endif + } /* WEU */ + + if (strcmp(info->expmag_settings.device[channel], "WEUL") == + 0) { + int setweu = 1; +#ifdef EPICSGFA + int setwev, setwevamp, setweuamp; + setwev = setwevamp = setweuamp = -1; +#else + int setwev, setwevdac; + setwev = setwevdac = -1; +#endif + + /* WEUL <> 0.0 */ + if (value != 0.0) { + /* SET WEU = 0.0 */ + if ((tchan = get_device_channel(info, "WEU")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setweu = tchan; + } + } + +#ifdef EPICSGFA + /* SET WEUAMP = 0 */ + if ((tchan=get_device_channel(info,"WEUAMP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setweuamp = tchan; + } + } +#endif + +#ifdef VMS_OTHER_SET_ZERO + /* SET WEV = 0.0 */ + if ((tchan = get_device_channel(info, "WEV")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwev = tchan; + } + } + +#ifdef EPICSGFA + /* SET WEVAMP = 0 */ + if ((tchan=get_device_channel(info,"WEVAMP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwevamp = tchan; + } + } +#else + /* SET WEVDAC = 0 */ + if ((tchan=get_device_channel(info,"WEVDAC")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwevdac = tchan; + } + } +#endif +#endif /* #ifdef VMS_OTHER_SET_ZERO */ + + } + + if (setweu != -1) + expmag_set(info, setweu, fla[setweu], fla); +#ifdef EPICSGFA + if (setweuamp != -1) + expmag_set(info, setweuamp, fla[setweuamp], fla); +#endif + if (setwev != -1) + expmag_set(info, setwev, fla[setwev], fla); +#ifdef EPICSGFA + if (setwevamp != -1) + expmag_set(info, setwevamp, fla[setwevamp], fla); +#else + if (setwevdac != -1) + expmag_set(info, setwevdac, fla[setwevdac], fla); +#endif + } /* WEUL */ + + if (strcmp(info->expmag_settings.device[channel], "WEV") == + 0) { + int setweul = 1; +#ifdef EPICSGFA + int setweu, setweuamp, setweulamp; + setweu = setweuamp = setweulamp = -1; +#else + int setweu, setweudac; + setweu = setweudac = -1; +#endif + + /* WEV <> 0.0 */ + if (value != 0.0) { + +#ifdef VMS_OTHER_SET_ZERO + /* SET WEU = 0.0 */ + if ((tchan = get_device_channel(info, "WEU")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setweu = tchan; + } + } + +#ifdef EPICSGFA + /* SET WEUAMP = 0 */ + if ((tchan=get_device_channel(info,"WEUAMP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setweuamp = tchan; + } + } +#else + /* SET WEUDAC = 0 */ + if ((tchan=get_device_channel(info,"WEUDAC")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setweudac = tchan; + } + } +#endif + /* SET WEUL = 0.0 */ + if ((tchan = get_device_channel(info, "WEUL")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setweul = tchan; + } + } + +#ifdef EPICSGFA + /* SET WEULAMP = 0 */ + if ((tchan=get_device_channel(info,"WEULAMP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setweulamp = tchan; + } + } +#endif +#endif /* #ifdef VMS_OTHER_SET_ZERO */ + + } + + if (setweu != -1) + expmag_set(info, setweu, fla[setweu], fla); +#ifdef EPICSGFA + if (setweuamp != -1) + expmag_set(info, setweuamp, fla[setweuamp], fla); +#else + if (setweudac != -1) + expmag_set(info, setweudac, fla[setweudac], fla); +#endif + if (setweul != -1) + expmag_set(info, setweul, fla[setweul], fla); +#ifdef EPICSGFA + if (setweulamp != -1) + expmag_set(info, setweulamp, fla[setweulamp], fla); +#endif + + } /* WEV */ + } /* VMS in PIE1 */ + + /* -- GPS in PIM3 */ + if (((strcmp(info->expmag_settings.instrument, "GPS") == 0) && + (strcmp(info->expmag_settings.area, "PIM3") == 0)) || + ((strcmp(info->expmag_settings.instrument, "TEST") == 0)&& + (strcmp(info->expmag_settings.area, "MUET") == 0))) { + + /* - WED */ + if (strcmp(info->expmag_settings.device[channel], "WED") == + 0) { +#ifdef EPICSGFA + int setwep, setwepamp, setwedl, setwedlamp; + setwep = setwepamp = setwedl = setwedlamp = -1; +#else + int setwep, setwepdac, setwedl, setwedldac; + setwep = setwepdac = setwedl = setwedldac = -1; +#endif + + if (fla[channel] > 0.0) { // WED is unipolar + if ((tchan = get_device_channel(info, "WEP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwep = tchan; + } + } +#ifdef EPICSGFA + if ((tchan=get_device_channel(info, "WEPAMP")) >= 0){ + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwepamp = tchan; + } + } +#else + if ((tchan=get_device_channel(info, "WEPDAC")) >= 0){ + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwepdac = tchan; + } + } +#endif + if ((tchan=get_device_channel(info,"WEDL")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedl = tchan; + } + } +#ifdef EPICSGFA + if ((tchan = + get_device_channel(info, "WEDLAMP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedlamp = tchan; + } + } +#else + if ((tchan = + get_device_channel(info, "WEDLDAC")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedldac = tchan; + } + } +#endif + + /* special cases WEDL & WEDLAMP/DAC when WED = 0 */ + } else if (fla[channel] == 0.0) { +// polarity switch (WED=-1) is not used anymore -> not necessary to set WEDL to zero +#ifdef OBSOLETE_NEW_GPS_POWERSUPPLIES + if ((tchan = get_device_channel(info, "WEDL")) >= 0){ + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedl = tchan; + } + } +#ifdef EPICSGFA + if ((tchan = + get_device_channel(info, "WEDLAMP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedlamp = tchan; + } + } +#else + if ((tchan = + get_device_channel(info, "WEDLDAC")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedldac = tchan; + } + } +#endif +#endif /* #ifdef OBSOLETE_NEW_GPS_POWERSUPPLIES */ + } + + if (setwep != -1) + expmag_set(info, setwep, fla[setwep], fla); +#ifdef EPICSGFA + if (setwepamp != -1) + expmag_set(info, setwepamp, fla[setwepamp], fla); +#else + if (setwepdac != -1) + expmag_set(info, setwepdac, fla[setwepdac], fla); +#endif + if (setwedl != -1) + expmag_set(info, setwedl, fla[setwedl], fla); +#ifdef EPICSGFA + if (setwedlamp != -1) + expmag_set(info, setwedlamp, fla[setwedlamp], fla); +#else + if (setwedldac != -1) + expmag_set(info, setwedldac, fla[setwedldac], fla); +#endif + } /* WED */ + + /* - WEDL */ + if (strcmp(info->expmag_settings.device[channel], "WEDL")== + 0) { +#ifdef EPICSGFA + int setwep, setwepamp, setwed, setwedamp; + setwep = setwepamp = setwed = setwedamp = -1; +#else + int setwep, setwepdac, setwed, setweddac; + setwep = setwepdac = setwed = setweddac = -1; +#endif + + if (fla[channel] != 0.0) { + if ((tchan = get_device_channel(info, "WEP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwep = tchan; + } + } +#ifdef EPICSGFA + if ((tchan=get_device_channel(info,"WEPAMP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwepamp = tchan; + } + } +#else + if ((tchan=get_device_channel(info,"WEPDAC")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwepdac = tchan; + } + } +#endif + /* set WED to zero */ + if ((tchan = get_device_channel(info, "WED")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwed = tchan; + } + } +#ifdef EPICSGFA + /* set WEDAMP to zero */ + if ((tchan=get_device_channel(info,"WEDAMP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedamp = tchan; + } + } +#else + if ((tchan=get_device_channel(info,"WEDDAC")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setweddac = tchan; + } + } +#endif + } + + if (setwep != -1) + expmag_set(info, setwep, fla[setwep], fla); +#ifdef EPICSGFA + if (setwepamp != -1) + expmag_set(info, setwepamp, fla[setwepamp], fla); +#else + if (setwepdac != -1) + expmag_set(info, setwepdac, fla[setwepdac], fla); +#endif + if (setwed != -1) + expmag_set(info, setwed, fla[setwed], fla); +#ifdef EPICSGFA + if (setwedamp != -1) + expmag_set(info, setwedamp, fla[setwedamp], fla); +#else + if (setweddac != -1) + expmag_set(info, setweddac, fla[setweddac], fla); +#endif + } /* WEDL */ + + /* - WEP */ + if (strcmp(info->expmag_settings.device[channel], "WEP") == + 0) { +#ifdef EPICSGFA + int setwed, setwedamp, setwedl, setwedlamp; + setwed = setwedamp = setwedl = setwedlamp = -1; +#else + int setwed, setweddac, setwedl, setwedldac; + setwed = setweddac = setwedl = setwedldac = -1; +#endif + + if (fla[channel] != 0.0) { + if ((tchan = get_device_channel(info, "WED")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwed = tchan; + } + } +#ifdef EPICSGFA + if ((tchan=get_device_channel(info,"WEDAMP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedamp = tchan; + } + } +#else + if ((tchan=get_device_channel(info,"WEDDAC")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setweddac = tchan; + } + } +#endif + if ((tchan=get_device_channel(info,"WEDL")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedl = tchan; + } + } +#ifdef EPICSGFA + if ((tchan = + get_device_channel(info, "WEDLAMP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedlamp = tchan; + } + } +#else + if ((tchan = + get_device_channel(info, "WEDLDAC")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedldac = tchan; + } + } +#endif + } + + if (setwed != -1) + expmag_set(info, setwed, fla[setwed], fla); +#ifdef EPICSGFA + if (setwedamp != -1) + expmag_set(info, setwedamp, fla[setwedamp], fla); +#else + if (setweddac != -1) + expmag_set(info, setweddac, fla[setweddac], fla); +#endif + if (setwedl != -1) + expmag_set(info, setwedl, fla[setwedl], fla); +#ifdef EPICSGFA + if (setwedlamp != -1) + expmag_set(info, setwedlamp, fla[setwedlamp], fla); +#else + if (setwedldac != -1) + expmag_set(info, setwedldac, fla[setwedldac], fla); +#endif + + } /* WEP */ + } /* GPS in PIM3 */ + + /* -- GPD in MUE1 */ + if (((strcmp(info->expmag_settings.instrument, "GPD") == 0) && + (strcmp(info->expmag_settings.area, "MUE1") == 0)) || + ((strcmp(info->expmag_settings.instrument, "TEST") == 0)&& + (strcmp(info->expmag_settings.area, "MUET") == 0))) { + + /* - HELM > 0 : set GOSSENA to zero and GOSSEN to 0 */ + if (strcmp(info->expmag_settings.device[channel], "HELM")== + 0) { + int setgossen, setgossena; + + setgossen = setgossena = -1; + + if (fla[channel] > 0.0) { + if ((tchan=get_device_channel(info,"GOSSEN")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setgossen = tchan; + } + } + } + + if ((tchan=get_device_channel(info,"GOSSENA")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setgossena = tchan; + } + } + + if (setgossen != -1) + expmag_set(info, setgossen, fla[setgossen], fla); + if (setgossena != -1) + expmag_set(info, setgossena, fla[setgossena], fla); + + } /* HELM */ + + /* - GOSSEN > 0 : set HELMH2DAC or WEH82 to -1 and HELM + * to -1 */ + if (strcmp(info->expmag_settings.device[channel], "GOSSEN") + == 0) { + /* GOSSEN field > 0 */ + if (fla[channel] > 0.0) { +#ifdef EPICSGFA + int sethelm, sethelmamp; + sethelm = sethelmamp = -1; +#else + int sethelm, sethelmdac; + sethelm = sethelmdac = -1; +#endif + + /* flag HELM */ + if ((tchan=get_device_channel(info, "HELM")) >= 0) { + if (fla[tchan] != -1.0) { + fla[tchan] = -1.0; + update_demand_array(info, fla, tchan); + sethelm = tchan; + } + } +#ifdef EPICSGFA + if ((tchan = + get_device_channel(info, "WEH82")) >= 0) { + /* WEH82 not negative? */ + /* NOTE: the switching to negative polarity of + * WEH82 is used to get GOSSEN + * connected to the coil + */ + if (fla[tchan] != -1.0) { + fla[tchan] = -1.0; + update_demand_array(info, fla, tchan); + sethelmamp = tchan; + } + } +#else + if ((tchan = + get_device_channel(info, "HELMH2DAC")) >= 0) { + /* HELMH2DAC not negative? */ + /* NOTE: the switching to negative polarity of + * HELMH2DAC is used to get GOSSEN + * connected to the coil + */ + if (fla[tchan] > -1.0) { + fla[tchan] = -1.0; + update_demand_array(info, fla, tchan); + sethelmdac = tchan; + } + } +#endif + if (sethelm != -1) + expmag_set(info, sethelm, fla[sethelm], fla); +#ifdef EPICSGFA + if (sethelmamp != -1) + expmag_set(info,sethelmamp, fla[sethelmamp], fla); +#else + if (sethelmdac != -1) + expmag_set(info,sethelmdac, fla[sethelmdac], fla); +#endif + } + } /* GOSSEN */ + } /* GPD in MUE1 */ + } + /* routine was called by ODB update */ + if (setref != -1) + expmag_set(info, setref, fla[setref], fla); + + } else { + cm_msg(MLOG, "", + "expmag_set : ERROR Not able to read demand array from " + "ODB!"); + } + + /* demand value of referenced device is out of range */ + } else { + + char tstr[50]; + + /* for PSIBL take minval/maxval and for MAG,EPICS & GOSSEN take + * minrval/maxrval */ + if (strncmp(info->expmag_settings.type[ref], "PSIBL", 5) == 0) { + sprintf(tstr, "%+d , %+d", info->expmag_settings.minval[ref], + info->expmag_settings.maxval[ref]); +#ifdef EPICSGFA + } else if (strncmp(info->expmag_settings.type[ref], "EPICSGFA",8) == + 0) { + sprintf(tstr, "%+f , %+f", info->expmag_settings.minrval[ref], + info->expmag_settings.maxrval[ref]); +#endif + } else if (strncmp(info->expmag_settings.type[ref], "GOSSEN", 6) == + 0) { + sprintf(tstr, "%+f , %+f", info->expmag_settings.minrval[ref], + info->expmag_settings.maxrval[ref]); + } else if (strncmp(info->expmag_settings.type[ref], "MAG", 3) == 0){ + sprintf(tstr, "%+f , %+f", info->expmag_settings.minrval[ref], + info->expmag_settings.maxrval[ref]); + } else { + strcpy(tstr, "Unknown range"); + } + cm_msg(MLOG, "", + "expmag_set(channel=%d : %s) demand value %f out of range " + "|%s|!", ref, info->expmag_settings.device[ref], result, + tstr); + } + + } + + /* else send value to a real device */ + } else { + + float fla[EMNDEVS]; + int i; + + /* PSIBL : round to nearest integer? */ + if (strncmp(info->expmag_settings.type[channel], "PSIBL", 5) == 0) { + float rest, resultt; +#ifdef MIDEBUG + float resulto; + + resulto = result; +#endif + resultt = (float) ((int) result); + rest = result - resultt; + result = resultt; + if (rest >= 0.0) { + if (rest > 0.50) + result = resultt + 1.0; + } else { + if (rest < -0.50) + result = resultt - 1.0; + } +#ifdef MIDEBUG + cm_msg(MLOG, "", "expmag_set Round %f -> %f + %f -> %f", resulto, + resultt, rest, result); +#endif + } + + if (pfla != NULL) { + for (i = 0; i < EMNDEVS; i++) + fla[i] = *(pfla + i); + } else { + for (i = 0; i < EMNDEVS; i++) + fla[i] = 0.0; + + if (info->hkey_demand != 0) { + /* get demand array to be able to set field of other magnets */ + if (get_demand_array(info, fla) == DB_SUCCESS) { +#ifdef MIDEBUG + for (i = 0; i < EMNDEVS; i++) + cm_msg(MLOG, "", "expmag_set channel=%d ODB = %f", i,fla[i]); +#endif + } else { + cm_msg(MLOG, "", + "expmag_set : ERROR Not able to read Variables/Demand " + "array from ODB!"); + } + } else { + cm_msg(MLOG, "", + "expmag_set : ERROR Not able to locate Variables/Demand " + "array!"); + } + } + + /* --- PSIBL device */ + if (strncmp(info->expmag_settings.type[channel], "PSIBL", 5) == 0) { + int tchan; + int poweron; + + poweron = TRUE; + + /* no field or negative DAC : switch power of device off */ + if (result <= 0.0) + poweron = FALSE; + + /* -- GPD in MUE1 exception */ + if (((strcmp(info->expmag_settings.instrument, "GPD") == 0) && + (strcmp(info->expmag_settings.area, "MUE1") == 0)) || + ((strcmp(info->expmag_settings.instrument, "TEST") == 0) && + (strcmp(info->expmag_settings.area, "MUET") == 0))) { + + /* - HELMH2DAC < 0 : switch power of HELMH2DAC off + >= 0 : set GOSSEN & GOSSENA to zero + > 0 : switch power of HELMH2DAC on */ + if (strcmp(info->expmag_settings.device[channel],"HELMH2DAC") == 0){ + int setgossen, setgossena; + + setgossen = setgossena = -1; + + if (fla[channel] < 0.0) { /* HELMH2DAC < 0 */ + poweron = FALSE; + } else if (fla[channel] >= 0.0) { + if (fla[channel] > 0.0) + poweron = TRUE; /* HELMH2DAC > 0 */ + + /* special case : GOSSEN must be set to 0 */ + if ((tchan = get_device_channel(info, "GOSSEN")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setgossen = tchan; + } + } + + if ((tchan = get_device_channel(info, "GOSSENA")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setgossena = tchan; + } + } + } + + if (setgossen != -1) + expmag_set(info, setgossen, fla[setgossen], fla); + if (setgossena != -1) + expmag_set(info, setgossena, fla[setgossena], fla); + } + + } + /* GPD in MUE1 */ + + /* -- GPS in PIM3 exception */ + if (((strcmp(info->expmag_settings.instrument, "GPS") == 0) && + (strcmp(info->expmag_settings.area, "PIM3") == 0)) || + ((strcmp(info->expmag_settings.instrument, "TEST") == 0) && + (strcmp(info->expmag_settings.area, "MUET") == 0))) { + + /* - WEDDAC */ + if (strcmp(info->expmag_settings.device[channel], "WEDDAC") == 0) { + int setwedl, setwedldac; + + setwedl = setwedldac = -1; + + /* special cases WEDL & WEDLDAC must be set to zero */ + if (fla[channel] != 0.0) { + if ((tchan = get_device_channel(info, "WEDL")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedl = tchan; + } + } + if ((tchan = get_device_channel(info, "WEDLDAC")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedldac = tchan; + } + } + } + + if (setwedl != -1) + expmag_set(info, setwedl, fla[setwedl], fla); + if (setwedldac != -1) + expmag_set(info, setwedldac, fla[setwedldac], fla); + + } + /* WEDDAC */ + /* - WEDLDAC */ + if (strcmp(info->expmag_settings.device[channel], "WEDLDAC") == 0) { + int setwed, setweddac; + + setwed = setweddac = -1; + + if (fla[channel] != 0.0) { + /* FLAG WED */ + if ((tchan = get_device_channel(info, "WED")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwed = tchan; + } + } + if ((tchan = get_device_channel(info, "WEDDAC")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setweddac = tchan; + } + } + } + + if (setwed != -1) + expmag_set(info, setwed, fla[setwed], fla); + if (setweddac != -1) + expmag_set(info, setweddac, fla[setweddac], fla); + + } + /* WEDLDAC */ + } + /* GPS in PIM3 */ + + set_zfc_mode(info,channel, result, TRUE); + + /* before final DAC value is set */ + if (!poweron) { /* device should be turned off */ + + /* HELMH2 or WEU has to be set to zero to ramp to zero before + power off*/ + if ((strcmp(info->expmag_settings.device[channel],"HELMH2DAC")==0)|| + (strcmp(info->expmag_settings.device[channel],"WEUDAC")==0)) { + float curadcindac; + /* Get current ADC readout in DAC units */ + if (roadc_device_get(info, channel, &curadcindac) == CM_SUCCESS){ + /* current DAC is not zero */ + if ((curadcindac > 1.0f) && (result <= 0.0f)) { + if (strcmp(info->expmag_settings.device[channel], + "HELMH2DAC") == 0) + cm_msg(MLOG, "", + "expmag_set : Trying to set field of HELMH2 to zero" + " before poweroff"); + if (strcmp(info->expmag_settings.device[channel],"WEUDAC") + == 0) + cm_msg(MLOG, "", "expmag_set : Trying to set field of WEU " + "to zero before poweroff"); + + /* set HELMH2 or WEU to zero */ + if (roadc_device_set(info, channel, 0.0f) == CM_SUCCESS) { + int iw,iwt; + + if (strcmp(info->expmag_settings.device[channel], + "HELMH2DAC") == 0) + iwt = (curadcindac/185)+1;// 10000/53 = 185 DAC/sec for + else if (strcmp(info->expmag_settings.device[channel], + "WEUDAC") == 0) + iwt = (curadcindac/22)+1; + // was 4095/30 sec = 137 DAC/sec + // now 30-SEP-2008 4095/180 = 22 + else + iwt = 30; + + if (strcmp(info->expmag_settings.device[channel], + "HELMH2DAC") == 0) + cm_msg(MLOG, "", "expmag_set : Waiting %d secs for " + "HELMH2 to ramp to zero",iwt); + else if (strcmp(info->expmag_settings.device[channel], + "WEUDAC") == 0) + cm_msg(MLOG, "", "expmag_set : Waiting %d secs for " + "WEU to go to zero",iwt); + else + cm_msg(MLOG, "", "expmag_set : Waiting %d secs for %s " + "to ramp to zero",iwt, + info->expmag_settings.device[channel]); + iwt *= 2; // convert secs to 0.5 secs + for (iw=0; iw < iwt; iw++) { + odb_measured_update(info); + ss_sleep(500); + } + odb_measured_update(info); + } + } + } + } + roadc_device_poweroff(info, channel); /* -> turn device off */ + + /* special treatment of some devices */ + } else { /* device should be turned on */ +#ifdef OBSOLETE_NEW_POWERSUPPLY + /* WEDL above 200G = 800 DAC has to be set in two steps if power is + * currently off */ + if (strcmp(info->expmag_settings.device[channel], "WEDLDAC") == 0) { + float curadcindac; + /* Get current ADC readout in DAC units */ + if (roadc_device_get(info, channel, &curadcindac) == CM_SUCCESS){ + /* current DAC is zero (= power off) */ + if ((curadcindac == 0.0f) && (result > 800.0f)) { + + cm_msg(MLOG, "", "expmag_set : Trying to set field (%.0f " + "DAC) of WEDL in two steps as power is " + "currently off", result); + + /* set WEDL to 200G = 800 DAC and turn power on */ + if (roadc_device_set(info, channel, 800.0f) == CM_SUCCESS) + roadc_device_poweron(info, channel); + } + } + } /* special case WEDL */ +#endif + /* WEV has to be set twice when power was off for a long time */ + if (strcmp(info->expmag_settings.device[channel], "WEVDAC") == 0) { + float curadcindac; + /* Get current ADC readout in DAC units */ + if (roadc_device_get(info, channel, &curadcindac) == CM_SUCCESS){ + /* current DAC is zero (= power off) */ + if ((curadcindac == 0.0f) && (result > 0.0f)) { + + cm_msg(MLOG, "", + "expmag_set : Setting field (%.0fDAC) of WEV " + " twice as power is currently off", result); + + /* set WEV and turn power on */ + if (roadc_device_set(info, channel, result) == CM_SUCCESS){ + roadc_device_poweron(info, channel); + // wait 18 secs before setting magnet again + cm_msg(MLOG, "", "expmag_set : Waiting 18 seconds " + "before setting WEV a second time"); + for (i=0; i<18; i++) { + ss_sleep(1000); + odb_keepalive(info); + odb_measured_update(info); + } + } + } + } + } /* special case WEV */ + } + + /* send new DAC value to device */ + roadc_device_set(info, channel, result); + + /* to be at field switch power of device on */ + if (poweron) + roadc_device_poweron(info, channel); + + set_zfc_mode(info, channel, result, FALSE); + +#ifdef EPICSGFA + /* --- EPICSGFA device */ + } else if (strncmp(info->expmag_settings.type[channel],"EPICSGFA",8)==0) { + int tchan; + int poweron; + + poweron = TRUE; + + /* no field or negative AMP : default is switch power of device off */ + if (result <= 0.0) + poweron = FALSE; + + /* -- GPD in MUE1 exception */ + if (((strcmp(info->expmag_settings.instrument, "GPD") == 0) && + (strcmp(info->expmag_settings.area, "MUE1") == 0)) || + ((strcmp(info->expmag_settings.instrument, "TEST") == 0) && + (strcmp(info->expmag_settings.area, "MUET") == 0))) { + + /* - WEH82 < 0 : switch power of WEH82 off + >= 0 : set GOSSEN & GOSSENA to zero + > 0 : switch power of WEH82 on */ + if (strcmp(info->expmag_settings.device[channel], "WEH82") == 0){ + int setgossen, setgossena; + + setgossen = setgossena = -1; + + if (fla[channel] < 0.0) { /* WEH82 < 0 */ + poweron = FALSE; + } else if (fla[channel] >= 0.0) { + if (fla[channel] > 0.0) + poweron = TRUE; /* WEH82 > 0 */ + + /* special case : GOSSEN must be set to 0 */ + if ((tchan = get_device_channel(info, "GOSSEN")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setgossen = tchan; + } + } + + if ((tchan = get_device_channel(info, "GOSSENA")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setgossena = tchan; + } + } + } + + if (setgossen != -1) + expmag_set(info, setgossen, fla[setgossen], fla); + if (setgossena != -1) + expmag_set(info, setgossena, fla[setgossena], fla); + } + + } + /* GPD in MUE1 */ + + /* -- GPS in PIM3 exception */ + if (((strcmp(info->expmag_settings.instrument, "GPS") == 0) && + (strcmp(info->expmag_settings.area, "PIM3") == 0)) || + ((strcmp(info->expmag_settings.instrument, "TEST") == 0) && + (strcmp(info->expmag_settings.area, "MUET") == 0))) { + + /* - WEDAMP */ + if (strcmp(info->expmag_settings.device[channel], "WEDAMP") == 0) { + int setwedl, setwedlamp; + + setwedl = setwedlamp = -1; + + /* unipolar : do not switch power on */ + if (result < 0.0) + poweron = FALSE; + + /* special cases WEDL & WEDLAMP must be set to zero */ + if (fla[channel] != 0.0) { + if ((tchan = get_device_channel(info, "WEDL")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedl = tchan; + } + } + if ((tchan = get_device_channel(info, "WEDLAMP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedlamp = tchan; + } + } + } + + if (setwedl != -1) + expmag_set(info, setwedl, fla[setwedl], fla); + if (setwedlamp != -1) + expmag_set(info, setwedlamp, fla[setwedlamp], fla); + + } /* WEDAMP */ + + /* - WEDLAMP */ + if (strcmp(info->expmag_settings.device[channel], "WEDLAMP") == 0) { + int setwed, setwedamp; + + setwed = setwedamp = -1; + + /* negative AMP : switch power of device on */ + if (result < 0.0) + poweron = TRUE; + + if (fla[channel] != 0.0) { + + /* set WED & WEDAMP to zero */ + if ((tchan = get_device_channel(info, "WED")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwed = tchan; + } + } + if ((tchan = get_device_channel(info, "WEDAMP")) >= 0) { + if (fla[tchan] != 0.0) { + fla[tchan] = 0.0; + update_demand_array(info, fla, tchan); + setwedamp = tchan; + } + } + } + + if (setwed != -1) + expmag_set(info, setwed, fla[setwed], fla); + if (setwedamp != -1) + expmag_set(info, setwedamp, fla[setwedamp], fla); + + } /* WEDLAMP */ + + /* - WEPAMP */ + if (strcmp(info->expmag_settings.device[channel], "WEPAMP") == 0) { + /* negative AMP : switch power of device on */ + if (result < 0.0) + poweron = TRUE; + } /* WEPAMP */ + } /* GPS in PIM3 */ + /* -- VMS in PIE1 exception */ + if (((strcmp(info->expmag_settings.instrument, "VMS") == 0) && + (strcmp(info->expmag_settings.area, "PIE1") == 0))) { + /* - WEULAMP */ + if (strcmp(info->expmag_settings.device[channel], "WEULAMP") == 0) { + /* negative AMP : switch power of device on */ + if (result < 0.0) + poweron = TRUE; + } /* WEULAMP */ + /* - WEVAMP */ + if (strcmp(info->expmag_settings.device[channel], "WEVAMP") == 0) { + /* negative AMP : switch power of device on */ + if (result < 0.0) + poweron = TRUE; + } /* WEVAMP */ + } /* VMS in PIE1 */ + + // before setting device set ZF control to TABLE mode + set_zfc_mode(info,channel, result, TRUE); + + /* send new value to device */ + if (info->cainfo) { + INT setchan, getchan, comchan, stachan, staro; + char epicschan[CHN_NAME_LENGTH]; + char *tpos; + int itchan; + float starro,dummy; + BOOL statOK; + + staro = 0x0000; + + // block evaluation of in range tolerance + epics_ca_set_pending(info->cainfo, TRUE); + + // decode EPICS channels + setchan = info->expmag_settings.address[channel]/1000; + getchan = info->expmag_settings.address[channel] -setchan*1000; + + // get index of :COM:2 channel + strncpy(epicschan, + info->cainfo->settings.channel_names+setchan*CHN_NAME_LENGTH, + CHN_NAME_LENGTH); + epicschan[CHN_NAME_LENGTH-1] = '\0'; + comchan = -1; + if ((tpos=strstr(epicschan,":SOL:2"))) { + strcpy(tpos,":COM:2"); + for (itchan=0; itchan < info->expmag_settings.epics_channels; + itchan++){ + if (strcmp(epicschan, info->cainfo->settings.channel_names + + itchan*CHN_NAME_LENGTH) == 0) { + comchan = itchan; + break; + } + } + *tpos = '\0'; /* remove channel specific part of name */ + } + + // get index of :STA:1 channel + strncpy(epicschan, + info->cainfo->settings.channel_names+setchan*CHN_NAME_LENGTH, + CHN_NAME_LENGTH); + epicschan[CHN_NAME_LENGTH-1] = '\0'; + stachan = -1; + if ((tpos=strstr(epicschan,":SOL:2"))) { + strcpy(tpos,":STA:1"); + for (itchan=0; itchan < info->expmag_settings.epics_channels; + itchan++){ + if (strcmp(epicschan, info->cainfo->settings.channel_names + + itchan*CHN_NAME_LENGTH) == 0) { + stachan = itchan; + break; + } + } + *tpos = '\0'; /* remove channel specific part of name */ + } + + if (strcmp(info->expmag_settings.device[channel],"WEH82")==0) { + /* reset masked T flag of WEH82 */ + if (result >= 0.f) { + if ((tpos=strchr(info->cainfo->settings.chnflags+ + setchan*CHNFLAGS_LENGTH,'t'))) + *tpos = 'T'; + + // release GOSSEN tolerance check + if ((tchan = get_device_channel(info, "GOSSENA")) >= 0) { + if (info->tolisactive[tchan]) { + if (info->tolwasout[tchan]) { + // unblock evaluation of in range tolerance + epics_ca_set_pending(info->cainfo, FALSE); + + info->tolwasout[tchan] = FALSE; + } + info->tolisactive[tchan] = FALSE; + } + } + + /* mask T flag of WEH82 when set negative to set GOSSEN */ + } else { + if ((tpos=strchr(info->cainfo->settings.chnflags+ + setchan*CHNFLAGS_LENGTH,'T'))) + *tpos = 't'; + + // activate GOSSEN tolerance check + if ((tchan = get_device_channel(info, "GOSSENA")) >= 0) { + if (info->tolisactive[tchan] != TRUE) { + info->tolisactive[tchan] = TRUE; + } + if (info->tolwasout[tchan] != TRUE) { + // block evaluation of in range tolerance + epics_ca_set_pending(info->cainfo, TRUE); + + cm_msg(MLOG,"","expmag_set: GOSSENA set to be out of " + "tolerance range"); + info->tolwasout[tchan] = TRUE; + } + } + + } + } + +#ifdef OBSOLETE_NEW_GPS_POWERSUPPLIES + if (strcmp(info->expmag_settings.device[channel],"WEDAMP")==0) { + int setchanwedl; + + if ((tchan = get_device_channel(info, "WEDLAMP")) >= 0) { + setchanwedl = info->expmag_settings.address[tchan]/1000; + } else + setchanwedl = -1; + + /* reset masked T flag of WED and mask WEDL */ + if (result >= 0.f) { + if ((tpos=strchr(info->cainfo->settings.chnflags+ + setchan*CHNFLAGS_LENGTH,'t'))) + *tpos = 'T'; + + if ((setchanwedl >= 0) && + (tpos=strchr(info->cainfo->settings.chnflags+ + setchanwedl*CHNFLAGS_LENGTH,'T'))) + *tpos = 't'; + + /* mask T flag of WED when WED was set negative to set WEDL and + * set T-flag of WEDL */ + } else { + if ((tpos=strchr(info->cainfo->settings.chnflags+ + setchan*CHNFLAGS_LENGTH,'T'))) + *tpos = 't'; + + if ((setchanwedl >= 0) && + (tpos=strchr(info->cainfo->settings.chnflags+ + setchanwedl*CHNFLAGS_LENGTH,'t'))) + *tpos = 'T'; + } + } +#endif /* #ifdef OBSOLETE_NEW_GPS_POWERSUPPLIES */ + if (comchan != -1) { + + /* to be at field switch power of device on */ + if (poweron) { + INT ison,nsets,itry; + + nsets = 0; + itry = 0; +set_poweron_again: + nsets++; + starro = 0.f; + epics_channels_update(info); + ison = FALSE; + if (stachan != -1) { + epics_ca_get(info->cainfo, stachan, &starro); + staro = (INT) starro; + if ((staro & 0x000f) == 0x0005) { + ison = TRUE; + } + } + + /* + * Would switch power of device ON automatically when Chn_Flags + * Z or N is set and result is non-zero or > 0 + * NOTE: Z or N is not set to prevent immediate power OFF when + * setpoint is set to 0! + */ + +#ifdef OBSOLETE_NEW_GPS_POWERSUPPLIES + /* WEDL above 200G > 15 A has to be set in two steps if power is + * OFF now, otherwise readout will overshoot causing poweroff*/ + if (strcmp(info->expmag_settings.device[channel],"WEDLAMP")==0) { + if (!ison) { + dummy = 15.f; + if (dummy > result) dummy = result; + epics_ca_set(info->cainfo, setchan, dummy, TRUE, TRUE); + } else + epics_ca_set(info->cainfo, setchan, result, TRUE, TRUE); + + } else +#endif /* #ifdef OBSOLETE_NEW_GPS_POWERSUPPLIES */ + epics_ca_set(info->cainfo, setchan, result, TRUE, TRUE); + + epics_channels_update(info); + // NIY check if setpoint is set + + /* turn power of device MultiIO or KombiPS1 ON sending + * 0 (= power on) to :COM:2 */ + if (!ison && (nsets < 15)) { + cm_msg(MLOG,"","%s : Sending \"Turn power ON\"", epicschan); + cm_msg_flush_buffer(); + epics_ca_set(info->cainfo, comchan, 0.f, TRUE, TRUE); + epics_wait(info, 6, 500); + goto set_poweron_again; + } + +#ifdef OBSOLETE_NEW_GPS_POWERSUPPLIES + if (strcmp(info->expmag_settings.device[channel],"WEDLAMP")==0) { + if (!ison) { + if (result > 15.f) { + epics_wait(info,20,500); + epics_ca_set(info->cainfo, setchan, result, TRUE, TRUE); + epics_wait(info,6,500); + /* turn power of device ON */ + epics_ca_set(info->cainfo, comchan, 0.f, TRUE, TRUE); + epics_channels_update(info); + } + } + } /* special case WEDL */ +#endif /* #ifdef OBSOLETE_NEW_GPS_POWERSUPPLIES */ + + /* WEV has to be set twice when power was off for a long time + * or when polarity changes power on has to be set again */ + if (strcmp(info->expmag_settings.device[channel],"WEVAMP") == 0){ + if (!ison || ((result < 0.f) && (prevval > 0.f)) || + ((result > 0.f) && (prevval < 0.f)) ) { + if (!ison) { + cm_msg(MLOG,"","%s : Failed to \"Turn power ON\"", + epicschan); + cm_msg_flush_buffer(); + } else + prevval = result; /* to avoid eternal loop */ + epics_wait(info,20,500); + itry++; + if (itry < 3) { + if (!ison) { + cm_msg(MLOG,"","%s : Sending \"Turn power OFF\" to " + "reset", epicschan); + cm_msg_flush_buffer(); + } + epics_ca_set(info->cainfo, comchan, 1.f, TRUE, TRUE); + epics_wait(info, 6, 500); + nsets = 0; + epics_ca_set(info->cainfo, setchan, result, TRUE, TRUE); + epics_channels_update(info); + goto set_poweron_again; + } + } + } /* special case WEV */ + + /* to be at zero wait until ramped to zero then switch power of + * device off + * NOTE: Chn_flags N or Z are therefore not set! */ + } else { + float ampro; + INT itry,nsets,nwait; + + nsets = 0; + nwait = 60; // takes approx. 1 1/2 secs per step + // WEH82 needs more time to ramp to zero + if (strcmp(info->expmag_settings.device[channel],"WEH82") == 0){ + if (getchan != -1) { + ampro = 0.f; + epics_ca_get(info->cainfo, getchan, &ro); + if (ampro > 60.f) nwait = ampro/2 + 10; // approx 2A/step + } + } +set_zero_again: + nsets++; + dummy = 0.f; + // if WEH82 and demand already -1 && power off + // skip setting to zero + if ((strcmp(info->expmag_settings.device[channel],"WEH82") + == 0) && (result == -1.f)) { + epics_channels_update(info); + if (stachan != -1) { + epics_ca_get(info->cainfo, stachan, &starro); + staro = (INT) starro; + if ((staro & 0x000f) != 0x0005) { + epics_ca_get_demand(info->cainfo, setchan, &ro); + if (result == ampro) { + cm_msg(MLOG,"","%s : Magnet demand is already %f (A) " + " and Power OFF", epicschan, ampro); + cm_msg_flush_buffer(); + goto neg_and_power_off; + } + } + } + } + + cm_msg(MLOG,"","%s : Sending \"Set demand %f\"",epicschan,dummy); + cm_msg_flush_buffer(); + epics_ca_set(info->cainfo, setchan, dummy, TRUE, TRUE); + epics_channels_update(info); + + // wait until readout is close to 0 or timeout + ampro = 0.f; + itry = 0; + statOK = FALSE; + + do { + epics_wait(info,2,500); + if (getchan != -1) { + float ampror; + + epics_ca_get(info->cainfo, getchan, &ro); + ampror = ampro; +#ifdef OBSOLETE_NEW_GPS_POWERSUPPLIES + // BUG FIX : a large negative WEDL readout is invalid + if (strcmp(info->expmag_settings.device[channel],"WEDLAMP") + == 0) { + if (ampro < 0.f) ampro = 0.f; + } +#endif + // BUG FIX : WEH82 is close to zero when |readout| < 0.3A + // WEU is close to zero when |readout| < 0.3A + if ((strcmp(info->expmag_settings.device[channel],"WEH82") + == 0) || + (strcmp(info->expmag_settings.device[channel],"WEUAMP") + == 0)) { + if ((ampro < 0.3f) && (ampro > -0.3f)) ampro = 0.f; + } + + // BUG FIX : WEDAMP is close to zero when |readout| < 2.0A + // 18-DEC-2017 was +/-0.6 now +/-2.0 + if (strcmp(info->expmag_settings.device[channel],"WEDAMP") + == 0) { + if ((ampro < 2.0f) && (ampro > -2.0f)) ampro = 0.f; + } + + if ((ampro < 0.1f) && (ampro > -0.1f)) { + cm_msg(MLOG,"","%s : Magnet field (%f A) is close to ZERO", + epicschan, ampror); + statOK = TRUE; + } else { + cm_msg(MLOG,"","%s : Magnet field is %f A", + epicschan, ampro); + } + cm_msg_flush_buffer(); + } + // keep watchdog happy + odb_keepalive(info); + odb_measured_update(info); + itry++; + // timeout? + if (itry >= nwait) { + cm_msg(MLOG,"","%s : Timeout waiting for magnet to be " + "at zero field", epicschan); + if (!statOK) cm_msg(MLOG,"","%s : Magnet field is %f A", + epicschan, ampro); + cm_msg_flush_buffer(); + } + } while (!statOK && (itry < nwait)); + + if (!statOK && (nsets <= 3)) { + goto set_zero_again; + } + + nsets = 0; +turn_poweroff_again: + nsets++; + /* turn power of device OFF */ + cm_msg(MLOG,"","%s : Sending \"Turn power OFF\"",epicschan); + cm_msg_flush_buffer(); + epics_ca_set(info->cainfo, comchan, 1.f, TRUE, TRUE); + epics_channels_update(info); + + // wait until status is OFF (actually not on) or timeout + starro = 0.f; + statOK = FALSE; + itry = 0; + do { + epics_wait(info,3,500); + if (stachan != -1) { + epics_ca_get(info->cainfo, stachan, &starro); + staro = (INT) starro; + if ((staro & 0x000f) != 0x0005) { + cm_msg(MLOG, "", "%s : Magnet status (0X%4.4x) is NOT ON", + epicschan, staro & 0x000f ); + statOK = TRUE; + } else { + cm_msg(MLOG,"","%s : Magnet status is 0X%4.4x", epicschan, + staro & 0x000f); + } + cm_msg_flush_buffer(); + } + // keep watchdog happy + odb_keepalive(info); + odb_measured_update(info); + itry++; + // timeout? + if (itry >= 60) { + cm_msg(MLOG,"","%s : Timeout waiting for magnet to be OFF", + epicschan); + if (!statOK) + cm_msg(MLOG, "", "%s : Magnet status (0X%4.4x) is NOT OFF", + epicschan, staro & 0x000f ); + cm_msg_flush_buffer(); + } + } while (!statOK && (itry < 60)); + + if (!statOK && (nsets <= 3)) { + goto turn_poweroff_again; + } + + if (result != 0.f) { + nsets = 0; + epics_wait(info,20,500); +set_nonzero_again: + nsets++; + cm_msg(MLOG,"","%s : Sending \"Set demand %f\" (without " + "turning power ON)", epicschan, result); + cm_msg_flush_buffer(); + epics_ca_set(info->cainfo, setchan, result, TRUE, TRUE); + epics_wait(info,20,500); + odb_keepalive(info); + statOK = FALSE; + itry = 0; + do { + if (itry != 0) + epics_wait(info,2,500); + else + epics_channels_update(info); + epics_ca_get_demand(info->cainfo, setchan, &ro); + cm_msg(MLOG,"","%s : Magnet demand is %f (A)", + epicschan, ampro); + cm_msg_flush_buffer(); + itry++; + if (ampro > result) { + if (ampro-result < 0.1f) statOK = TRUE; + } else { + if (result-ampro < 0.1f) statOK = TRUE; + } + } while (!statOK && itry < 3); + + if (!statOK && (nsets <= 5)) { + goto set_nonzero_again; + } + } +neg_and_power_off: ; + } + } else { + cm_msg(MLOG,"","ERROR corresponding :COM:2 channel of %s NOT FOUND" + "!",info->cainfo->settings.channel_names+setchan*CHN_NAME_LENGTH); + cm_msg_flush_buffer(); + } + + // unblock evaluation of in range tolerance + epics_ca_set_pending(info->cainfo, FALSE); + } + + // will set ZF control to active compensation when all magnets are zero + set_zfc_mode(info, channel, result, FALSE); + +#endif /* #ifdef EPICSGFA */ + + /* --- GOSSEN device */ + } else if (strncmp(info->expmag_settings.type[channel],"GOSSEN",6) == 0) { + int tchan,comchan; + char cmd[80],cmd1[80]; + + /* -- GPD in MUE1 */ + if (((strcmp(info->expmag_settings.instrument, "GPD") == 0) && + (strcmp(info->expmag_settings.area, "MUE1") == 0)) || + ((strcmp(info->expmag_settings.instrument, "TEST") == 0) && + (strcmp(info->expmag_settings.area, "MUET") == 0))) { + + // NIY check if device name is GOSSEN + + /* GOSSEN field > 0 */ + if (fla[channel] > 0.0) { +#ifdef EPICSGFA + int sethelm, sethelmamp; + sethelm = sethelmamp = -1; +#else + int sethelm, sethelmdac; + sethelm = sethelmdac = -1; +#endif + + /* flag HELM */ + if ((tchan = get_device_channel(info, "HELM")) >= 0) { + if (fla[tchan] != -1.0) { + fla[tchan] = -1.0; + update_demand_array(info, fla, tchan); + sethelm = tchan; + } + } +#ifdef EPICSGFA + if ((tchan = get_device_channel(info, "WEH82")) >= 0) { + /* WEH82 not negative? */ + /* NOTE: the switching to negative polarity of WEH82 is + * used to get GOSSEN connected to the coil + */ + if (fla[tchan] != -1.0) { + fla[tchan] = -1.0; + update_demand_array(info, fla, tchan); + sethelmamp = tchan; + } + } +#else + if ((tchan = get_device_channel(info, "HELMH2DAC")) >= 0) { + /* HELMH2DAC not negative? */ + /* NOTE: the switching to negative polarity of HELMH2DAC is + * used to get GOSSEN connected to the coil + */ + if (fla[tchan] > -1.0) { + fla[tchan] = -1.0; + update_demand_array(info, fla, tchan); + sethelmdac = tchan; + } + } +#endif + if (sethelm != -1) + expmag_set(info, sethelm, fla[sethelm], fla); +#ifdef EPICSGFA + if (sethelmamp != -1) + expmag_set(info, sethelmamp, fla[sethelmamp], fla); +#else + if (sethelmdac != -1) + expmag_set(info, sethelmdac, fla[sethelmdac], fla); +#endif + } + } + + set_zfc_mode(info, channel, result, TRUE); + + /* GPD in MUE1 */ + if (result < 0.0f) { + cm_msg(MLOG,"","expmag_set : invalid value %f to be sent to Gossen", + result); + result = 0.0; + } + + if (strcmp(info->expmag_settings.server[channel], "CHAN") == 0) { + comchan = info->expmag_settings.address[channel]; + } else { + comchan = channel; + } + + if (result > 0.0f) + sprintf(cmd,"USET 25.000; ISET %7.4f; OUTPUT ON",result); //04-JUN-07 + else // NOTE: USET must be lower than ULIM value specified above!! + sprintf(cmd, "OUTPUT OFF; USET 0.000; ISET 0.0000"); + + strcpy(cmd1,cmd); + strcat(cmd,"\n"); +//#ifdef MIDEBUG + cm_msg(MLOG, "", "expmag_set : sending %s to GOSSEN device %s", + cmd1, info->expmag_settings.device[channel]); + cm_msg_flush_buffer(); +//#endif +#ifdef SSP120_LANGPIB_SUPPORT + if (gossen_ssp120_sendr_status(info, comchan, + *(info->langpib + comchan),channel, + cmd, NULL, 0, DEFAULT_TIMEOUT_SSP, + FALSE,5,FALSE) <= 0) { +#elif defined(SSP120_TCPIP_SUPPORT) + if (gossen_ssp120_sendr_status(info, comchan, + *(info->tcpip + comchan),channel, + cmd, NULL, 0, DEFAULT_TIMEOUT_SSP, + FALSE,5,FALSE) <= 0) { +#else + ERROR UNKNOWN MIDAS COMMUNICATION BUS +#endif + cm_msg(MERROR,"expmag_set", "ERROR Sending %s to GOSSEN device %s", + cmd1, info->expmag_settings.device[channel]); + cm_msg_flush_buffer(); + } else { + + /* add settling time to device expiration */ + if (info->expmag_settings.expiration[channel] < ss_time() + 30) { + info->expmag_settings.expiration[channel] = ss_time() + 30; + expmag_settings_update(info); + } + } + + set_zfc_mode(info, channel, result, FALSE); + /* device type is GOSSEN */ + } else { + cm_msg(MLOG,"","expmag_set: Device type %s is not handled!", + info->expmag_settings.type[channel]); + } + + if (info->expmag_settings.title[channel] == 'Y') + update_run_title_field(info, channel, value); + + /* wait some time for field to be set */ + odb_keepalive(info); + +//#ifdef MIDEBUG + cm_msg(MLOG, "","expmag_set(channel=%d : %s) waiting for field to be set", + channel, info->expmag_settings.device[channel]); + cm_msg_flush_buffer(); +//#endif + odb_measured_update(info); +#ifdef EPICSGFA + epics_wait(info,14,500); +#else + ss_sleep(7000); +#endif + odb_measured_update(info); + + } /* end else send value to a real device */ + +#ifdef EPICSGFA + // unblock evaluation of in range tolerance + if (info->cainfo) epics_ca_set_pending(info->cainfo, FALSE); +#endif + /* demand value is out of range */ + } else { + char tstr[50]; + + /* for PSIBL take minval/maxval and for MAG&GOSSEN take minrval/maxrval */ + if (strncmp(info->expmag_settings.type[channel], "PSIBL", 5) == 0) { + sprintf(tstr, "%+d , %+d", info->expmag_settings.minval[channel], + info->expmag_settings.maxval[channel]); +#ifdef EPICSGFA + } else if (strncmp(info->expmag_settings.type[channel], "EPICSGFA",8) == 0) { + sprintf(tstr, "%+f , %+f", info->expmag_settings.minrval[channel], + info->expmag_settings.maxrval[channel]); +#endif + } else if (strncmp(info->expmag_settings.type[channel], "GOSSEN", 6) == 0) { + sprintf(tstr, "%+f , %+f", info->expmag_settings.minrval[channel], + info->expmag_settings.maxrval[channel]); + } else if (strncmp(info->expmag_settings.type[channel], "MAG", 3) == 0) { + sprintf(tstr, "%+f , %+f", info->expmag_settings.minrval[channel], + info->expmag_settings.maxrval[channel]); + } else { + strcpy(tstr, "Unknown range"); + } + cm_msg(MLOG, "", + "expmag_set(channel=%d : %s) demand value %f out of range |%s|!", + channel, info->expmag_settings.device[channel], value, tstr); + cm_msg_flush_buffer(); + } +#ifdef MIDEBUG + } else { + cm_msg(MLOG, "", "expmag_set(channel=%d) disabled!", channel); +#endif + } +#ifdef MIDEBUG2 + } else { + cm_msg(MLOG, "", "expmag_set(channel=%d) Not used!", channel); +#endif + } + return FE_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ + +INT expmag_get(EXPMAG_INFO * info, INT channel, float *pvalue) +{ + HNDLE hdb; + char path[512]; + +#ifdef EPICSGFA + if (channel == 0) info->do_epics_reading = 0; +#endif + if ((ss_time() - info->lasterrtime[channel]) > DELTA_TIME_ERROR) { + info->errorcount[channel] = 0; + info->lasterrtime[channel] = ss_time(); + } + + if (strncmp(info->expmag_settings.device[channel], "NONE", 4) != 0) { + + if (info->expmag_settings.used[channel] == 'Y') { + float value, result; + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_get(channel=%d)", channel); +#endif + + cm_get_experiment_database(&hdb, NULL); + + /* if type == MAG */ + if (strncmp(info->expmag_settings.type[channel], "MAG", 3) == 0) { + + /* get ODB key of ../Variables/Measured */ + if (info->hkey_measured == 0) { + char tstr[512]; + + sprintf(tstr, "%sMeasured", info->varpath); + if (db_find_key(hdb, 0, tstr, &info->hkey_measured) != DB_SUCCESS) { + cm_msg(MLOG, "", "expmag_get : ERROR ODB key %s not found", tstr); + info->hkey_measured = 0; +#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "expmag_get : db_find_key(%s)", tstr); +#endif + } + + } + + if (info->hkey_measured != 0) { + int ref; + + ref = info->expmag_settings.address[channel]; +#ifdef MIDEBUG2 + cm_msg(MLOG, "", "expmag_get channel=%d ref chan=%d", channel, ref); +#endif + + /* is referenced device used */ + if (info->expmag_settings.used[ref] == 'Y') { + /* take value of referenced device (conversion will be done below ) */ + float fla[EMNDEVS]; + int bufs, i; + + /* get measured array to be able to get field of referenced device */ + bufs = sizeof(fla); + db_get_data(hdb, info->hkey_measured, (void *) fla, &bufs, TID_FLOAT); +#ifdef MIDEBUG2 + for (i = 0; i < EMNDEVS; i++) + cm_msg(MLOG, "", "expmag_get channel=%d ODB = %f", i, fla[i]); +#endif + + value = fla[ref]; + + /* consider special cases */ + /* NOTE: this cases should not happen as power of devices should be off + * and if power is off measured field 0.0 will be returned + */ + + /* -- GPS in PIM3 */ + if (((strcmp(info->expmag_settings.instrument, "GPS") == 0) && + (strcmp(info->expmag_settings.area, "PIM3") == 0)) || + ((strcmp(info->expmag_settings.instrument, "TEST") == 0) && + (strcmp(info->expmag_settings.area, "MUET") == 0))) { + +#ifdef EPICSGFA + /* - WEDAMP < 0 : value = 0.0; */ + if (strcmp(info->expmag_settings.device[ref], "WEDAMP") == 0) { + if (value < 0.0) + value = 0.0; + } +#else + /* - WEDDAC < 0 : value = 0.0; */ + if (strcmp(info->expmag_settings.device[ref], "WEDDAC") == 0) { + if (value < 0.0) + value = 0.0; + } +#endif + } + + /* -- GPD in MUE1 */ + if (((strcmp(info->expmag_settings.instrument, "GPD") == 0) && + (strcmp(info->expmag_settings.area, "MUE1") == 0)) || + ((strcmp(info->expmag_settings.instrument, "TEST") == 0) && + (strcmp(info->expmag_settings.area, "MUET") == 0))) { + +#ifdef EPICSGFA + /* - WEH82 < 0 : value = 0.0; */ + if (strcmp(info->expmag_settings.device[ref], "WEH82") == 0) { + if (value < 0.0) + value = 0.0; + } +#else + /* - HELMH2DAC < 0 : value = 0.0; */ + if (strcmp(info->expmag_settings.device[ref], "HELMH2DAC") == 0) { + if (value < 0.0) + value = 0.0; + } +#endif + } + + } else { +#ifdef MIDEBUG + cm_msg(MLOG, "", + "expmag_get : WARNING channel=%d (%s) is disabled! (Used=N)", + ref, info->expmag_settings.device[ref]); +#endif + value = 0.0; + } + } else { + cm_msg(MLOG, "", + "expmag_get : ERROR reading ../Variables/Measured from ODB!"); + value = 0.0; + } + + /* else get value from real device */ + } else { + if (strncmp(info->expmag_settings.type[channel], "PSIBL", 5) == 0) { + + roadc_device_get(info, channel, &value); + +#ifdef EPICSGFA + } else if (strncmp(info->expmag_settings.type[channel], "EPICSGFA", 8) == 0){ + INT itchan, setchan, getchan; + + // read all EPICS channels to update everything + epics_channels_update(info); + + // decode EPICS channel + setchan = info->expmag_settings.address[channel]/1000; + getchan = info->expmag_settings.address[channel] -setchan*1000; + + if (info->cainfo) { +#ifdef MIDEBUGE + cm_msg(MLOG,"","expmag_get(channel=%d) Address %d -> epics_ca_get(%d)", + channel,info->expmag_settings.address[channel], getchan); +#endif + epics_ca_get(info->cainfo, getchan, &value); +#ifdef MIDEBUGE + cm_msg(MLOG,"","expmag_get(channel=%d) epics_ca_get(%d) returned %f", + channel, getchan, value); +#endif +#ifdef OBSOLETE_NEW_GPS_POWERSUPPLIES + // BUG FIX : negative WEDL readout is invalid + if (strcmp(info->expmag_settings.device[channel],"WEDLAMP") == 0) { + if (value < 0.f) value = 0.f; + } +#endif /* #ifdef OBSOLETE_NEW_GPS_POWERSUPPLIES */ + } +#endif + + } else if (strncmp(info->expmag_settings.type[channel], "GOSSEN", 6) == 0) { + int comchan; + char cmd[30],ans[80]; + + if (strcmp(info->expmag_settings.server[channel], "CHAN") == 0) { + comchan = info->expmag_settings.address[channel]; + } else { + comchan = channel; + } + + if ((gngets == 0)||(gngets == 5)||(gngets == 10)||((gngets%1000) == 999)) + strcpy(cmd,"USET?;UOUT?;OUTPUT?; IOUT?\n"); + else + strcpy(cmd,"OUTPUT?; IOUT?\n"); + + value = -1.0; + +#ifdef SSP120_LANGPIB_SUPPORT + if (gossen_ssp120_sendr_status(info, comchan, *(info->langpib + comchan), + channel, cmd, ans, sizeof(ans), + DEFAULT_TIMEOUT_SSP, FALSE, 5, TRUE) <= 0){ +#elif defined (SSP120_TCPIP_SUPPORT) + if (gossen_ssp120_sendr_status(info, comchan, *(info->tcpip + comchan), + channel, cmd, ans, sizeof(ans), + DEFAULT_TIMEOUT_SSP, FALSE, 5, TRUE) <= 0){ +#else + ERROR UNKNOWN MIDAS COMMUNICATION BUS +#endif + cm_msg(MERROR,"expmag_get", "ERROR Sending \"OUTPUT?; IOUT?\" to " + "GOSSEN device %s", info->expmag_settings.device[channel]); + value = 0.0; + } else { + +#ifdef MIDEBUG + cm_msg(MINFO,"","expmag_get: \"IOUT?\" reply from GOSSEN device %s is " + "%s", info->expmag_settings.device[channel], ans); +#endif + if (strstr(ans,"OUTPUT ON") != NULL) { + char *pos; + + if ((pos = strstr(ans,"IOUT")) != NULL) { + if (sscanf(pos+4,"%f",&value) != 1) { + cm_msg(MERROR,"expmag_get", "ERROR Reading \"IOUT?\" reply from " + "GOSSEN device %s", info->expmag_settings.device[channel]); + value = 0.0; + } else { +#ifdef MIDEBUG + cm_msg(MINFO,"","expmag_get: \"IOUT?\" reply from GOSSEN device " + "%s is %f", info->expmag_settings.device[channel], value); +#endif + if ((gngets==0)||(gngets==5)||(gngets==10)||((gngets%1000)==999)){ + replace_newline(ans); + cm_msg(MINFO,"","expmag_get: GOSSEN device %s : %s", + info->expmag_settings.device[channel], ans); + } + } + } else { + cm_msg(MERROR,"expmag_get", "ERROR Finding \"IOUT\" reply from " + "GOSSEN device %s", info->expmag_settings.device[channel]); + value = 0.0; + } + } else + value = 0.0; + } + + if (info->tolisactive[channel] == TRUE) { + float tdiff; + + if (value >= info->set_values[channel]) + tdiff = value -info->set_values[channel]; + else + tdiff = info->set_values[channel]-value; + + // is difference in tolerance range? + if (tdiff < 0.1f) { + // was previously out of tolerance range + if (info->tolwasout[channel] == TRUE) { +#ifdef EPICSGFA + // decrement sum out of tolerance range + if (info->cainfo) epics_ca_set_pending(info->cainfo, FALSE); +#endif + cm_msg(MLOG,"","expmag_get: GOSSENA (%.3f,%3f) is in tolerance " + "range (%.3f < 0.1)",info->set_values[channel],value,tdiff); + info->tolwasout[channel] = FALSE; + } + } else { + // was previously in tolerance range + if (info->tolwasout[channel] == FALSE) { +#ifdef EPICSGFA + // increment sum out of tolerance range + if (info->cainfo) epics_ca_set_pending(info->cainfo, TRUE); +#endif + cm_msg(MLOG,"","expmag_get: GOSSENA (%.3f,%3f) is out of tolerance " + "range (%.3f < 0.1)",info->set_values[channel],value,tdiff); + info->tolwasout[channel] = TRUE; + } + } + } + + } + } + + if (value != 0.0) { + + /* do inverted calibration? */ + if (*(info->calibration + channel) != NULL) { + double valued, resultd; + + /* direction for setting is forward interpolation */ + if ((*(info->calibration + channel))->direction) { + + /* do reverse cubic spline interpolation */ + + if (info->expmag_settings.scale[channel] != 0.0) { + /* result = (value -offset)/scale */ + valued = (value - info->expmag_settings.offset[channel]) / + info->expmag_settings.scale[channel]; +#ifdef MIDEBUG1 + cm_msg(MLOG, "", + "expmag_get(channel=%d,value=%f,(value-offset)/scale=%f)", + channel, value, valued); +#endif + + if (splines((*(info->calibration + channel))->ncals, + (*(info->calibration + channel))->y, + (*(info->calibration + channel))->x, + (*(info->calibration + channel))->s2r, + (*(info->calibration + channel))->s3r, + (*(info->calibration + channel))->dyr, + 1, &valued, &resultd, 0) != SS_SUCCESS) { + cm_msg(MLOG, "", + "expmag_get(channel=%d,value=%f) reverse interpolation " + "out of range)", channel, valued); + } +#ifdef MIDEBUG1 + cm_msg(MLOG, "", + "expmag_get(channel=%d,value=%f,rev interpolation=%f)", + channel, valued, resultd); +#endif + result = resultd; + } else { + cm_msg(MLOG, "", + "expmag_get(channel=%d) (value-offset)/scale undefined " + "with scale = 0.0!", channel); + result = 0.0; + } + + /* direction for setting is reverse interpolation */ + } else { + + /* do forward cubic spline interpolation */ + + valued = value; + + if (splines((*(info->calibration + channel))->ncals, + (*(info->calibration + channel))->x, + (*(info->calibration + channel))->y, + (*(info->calibration + channel))->s2f, + (*(info->calibration + channel))->s3f, + (*(info->calibration + channel))->dyf, + 1, &valued, &resultd, 0) != SS_SUCCESS) { + cm_msg(MLOG, "", + "expmag_get(channel=%d,value=%f) forward interpolation out " + "of range)", channel, valued); + } +#ifdef MIDEBUG1 + cm_msg(MLOG, "", + "expmag_get(channel=%d,value=%f,forw interpolation=%f)",channel, + valued, resultd); +#endif + + /* result = scale*value + offset */ + result = info->expmag_settings.scale[channel] * resultd + + info->expmag_settings.offset[channel]; + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", + "expmag_get(channel=%d,value=%f,value*scale+offset=%f)",channel, + resultd, result); +#endif + + } + + /* no calibration */ + } else { + /* calculate value=(value-offset)/scale */ + if (info->expmag_settings.scale[channel] != 0.0) { + result = (value - info->expmag_settings.offset[channel]) / + info->expmag_settings.scale[channel]; + } else { + cm_msg(MLOG, "", "expmag_get channel %d (%s) ERROR Division by zero : " + "scale = 0.0!", channel, info->expmag_settings.device[channel]); + result = 0.0; + } + } + } else { + result = 0.0; + } + + /* PSIBL: round to nearest integer? */ + if (strncmp(info->expmag_settings.type[channel], "PSIBL", 5) == 0) { + float rest, resultt; +#ifdef MIDEBUG1 + float resulto; + + resulto = result; +#endif + resultt = (float) ((int) result); + rest = result - resultt; + result = resultt; + if (rest >= 0.0) { + if (rest > 0.50) + result = resultt + 1.0; + } else { + if (rest < -0.50) + result = resultt - 1.0; + } +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_get Round %f -> %f + %f -> %f", resulto, resultt, + rest, result); +#endif + } else if ((strncmp(info->expmag_settings.type[channel], "MAG", 3) == 0) || +#ifdef EPICSGFA + (strncmp(info->expmag_settings.type[channel], "EPICSGFA",8) == 0) || +#endif + (strncmp(info->expmag_settings.type[channel], "GOSSEN", 6) == 0)) { + if (info->expmag_settings.ndigits[channel] >= 0) { + char field[40]; + sprintf(field, "%.*f", MIN(info->expmag_settings.ndigits[channel], 10), + result); + sscanf(field, "%f", &result); + } + } +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_get(channel=%d,value=%f)", channel, result); +#endif + if (pvalue != NULL) + *pvalue = result; + + } else { + if (pvalue != NULL) + *pvalue = 0.0; +#ifdef MIDEBUG2 + cm_msg(MLOG, "", "expmag_get(channel=%d) disabled!", channel); +#endif + } + } else { + if (pvalue != NULL) + *pvalue = 0.0; +#ifdef MIDEBUG2 + cm_msg(MLOG, "", "expmag_get(channel=%d) Not used!", channel); +#endif + } + + cm_msg_flush_buffer(); + return FE_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ + +INT expmag_get_demand(EXPMAG_INFO * info, INT channel, float *pvalue) +{ + HNDLE hdb; + char path[512]; + + if (pvalue != NULL) + *pvalue = info->last_demand[channel]; + if (strncmp(info->expmag_settings.device[channel], "NONE", 4) != 0) { + if (info->expmag_settings.used[channel] == 'Y') { + float value, result; + + if (pvalue != NULL) + result = value = *pvalue; +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_get_demand(channel=%d)", channel); +#endif + cm_get_experiment_database(&hdb, NULL); + + /* if type == MAG */ + if (strncmp(info->expmag_settings.type[channel], "MAG", 3) == 0) { + + /* get ODB key of ../Variables/Demand */ + if (info->hkey_demand == 0) { + char tstr[512]; + + sprintf(tstr, "%sDemand", info->varpath); + if (db_find_key(hdb, 0, tstr, &info->hkey_demand) != DB_SUCCESS) { + cm_msg(MLOG, "", "expmag_get_demand : ERROR ODB key %s not found", + tstr); + info->hkey_demand = 0; +#ifdef MIDEBUG1 + } else { + cm_msg(MLOG, "", "expmag_get_demand : db_find_key(%s)", tstr); +#endif + } + } + + if (info->hkey_demand != 0) { + int ref; + + ref = info->expmag_settings.address[channel]; +#ifdef MIDEBUG2 + cm_msg(MLOG, "", "expmag_get_demand channel=%d referenced channel=%d", + channel, ref); +#endif + + /* is referenced device used */ + if (info->expmag_settings.used[ref] == 'Y') { + /* take value of referenced device (conversion will be done below )*/ + float fla[EMNDEVS]; + int bufs, i; + + /* get demand array to be able to get field of referenced device */ + bufs = sizeof(fla); + db_get_data(hdb, info->hkey_demand, (void *) fla, &bufs, TID_FLOAT); +#ifdef MIDEBUG2 + for (i = 0; i < EMNDEVS; i++) + cm_msg(MLOG, "", "expmag_get_demand channel=%d ODB = %f", i, + fla[i]); +#endif + + value = fla[ref]; + + /* consider special cases */ + /* NOTE: this cases should not happen as power of devices should be off + * and if power is off measured field 0.0 will be returned + */ + + /* -- GPS in PIM3 */ + if (((strcmp(info->expmag_settings.instrument, "GPS") == 0) && + (strcmp(info->expmag_settings.area, "PIM3") == 0)) || + ((strcmp(info->expmag_settings.instrument, "TEST") == 0) && + (strcmp(info->expmag_settings.area, "MUET") == 0))) { +#ifdef EPICSGFA +#ifdef OBSOLETE_NEW_GPS_POWERSUPPLIES + /* - WEDAMP < 0 : result = 0.0; */ + if (strcmp(info->expmag_settings.device[ref], "WEDAMP") == 0) { + if (value < 0.0) { + result = 0.0; + goto raw_value; + } + } +#endif /* #ifdef OBSOLETE_NEW_GPS_POWERSUPPLIES */ +#else + /* - WEDDAC < 0 : result = 0.0; */ + if (strcmp(info->expmag_settings.device[ref], "WEDDAC") == 0) { + if (value < 0.0) { + result = 0.0; + goto raw_value; + } + } +#endif + } + + /* -- GPD in MUE1 */ + if (((strcmp(info->expmag_settings.instrument, "GPD") == 0) && + (strcmp(info->expmag_settings.area, "MUE1") == 0)) || + ((strcmp(info->expmag_settings.instrument, "TEST") == 0) && + (strcmp(info->expmag_settings.area, "MUET") == 0))) { + +#ifdef EPICSGFA + /* - WEH82 < 0 : result = -1.0; */ + if (strcmp(info->expmag_settings.device[ref], "WEH82") == 0) { + if (value < 0.0) { + result = -1.0; + goto raw_value; + } + } +#else + /* - HELMH2DAC > 0 : result = -1.0; */ + if (strcmp(info->expmag_settings.device[ref], "HELMH2DAC") == 0) { + if (value > 0.0) { + result = -1.0; + goto raw_value; + } + } +#endif + } + + } else { +#ifdef MIDEBUG + cm_msg(MLOG, "", + "expmag_get_demand : WARNING channel=%d (%s) is disabled! " + "(Used=N)", ref, info->expmag_settings.device[ref]); +#endif + value = 0.0; + } + } else { + cm_msg(MLOG, "", + "expmag_get_demand : ERROR reading ../Variables/Demand from ODB!"); + value = 0.0; + } + + /* else get value from real device */ + } else { + + if (strncmp(info->expmag_settings.type[channel], "PSIBL", 5) == 0) { + + roadc_device_get_demand(info, channel, &value); +#ifdef EPICSGFA + } else if (strncmp(info->expmag_settings.type[channel], "EPICSGFA", 8) == 0){ + INT setchan; + + epics_channels_update(info); + // Decode EPICS channel + setchan = info->expmag_settings.address[channel]/1000; + if (info->cainfo) epics_ca_get_demand(info->cainfo, setchan, &value); +#endif + } else if (strncmp(info->expmag_settings.type[channel], "GOSSEN", 6) == 0) { + if (pvalue != NULL) { + int comchan; + char cmd[30],ans[80]; + + if (strcmp(info->expmag_settings.server[channel], "CHAN") == 0) { + comchan = info->expmag_settings.address[channel]; + } else { + comchan = channel; + } + + strcpy(cmd,"OUTPUT?; ISET?\n"); + + value = *pvalue; + +#ifdef SSP120_LANGPIB_SUPPORT + if (gossen_ssp120_sendr_status(info, comchan, *(info->langpib+comchan), + channel, cmd, ans, sizeof(ans), + DEFAULT_TIMEOUT_SSP, FALSE, 5, TRUE) <= 0) { +#elif defined (SSP120_TCPIP_SUPPORT) + if (gossen_ssp120_sendr_status(info, comchan, *(info->tcpip+comchan), + channel, cmd, ans, sizeof(ans), + DEFAULT_TIMEOUT_SSP, FALSE, 5, TRUE) <= 0) { +#else + ERROR UNKNOWN MIDAS COMMUNICATION BUS +#endif + cm_msg(MERROR,"expmag_get_demand", "ERROR Sending \"OUTPUT?; ISET?\"" + " to GOSSEN device %s", info->expmag_settings.device[channel]); + value = 0.0; + } else { + char *pos; + + if ((pos = strstr(ans,"ISET")) != NULL) { + if (sscanf(pos+4,"%f",&value) != 1) { + cm_msg(MERROR,"expmag_get_demand", "ERROR Processing \"ISET?\" " + "reply (%s) from GOSSEN device %s", + ans,info->expmag_settings.device[channel]); + value = 0.0; + } else if ((value != 0.0f) && + (strstr(ans,"OUTPUT OFF") != NULL)) { + cm_msg(MERROR,"expmag_get_demand", "WARNING GOSSEN device %s " + "OUTPUT is turned OFF", + info->expmag_settings.device[channel]); + } + + } else { + cm_msg(MERROR,"expmag_get_demand", "ERROR Finding \"ISET\" reply " + "from GOSSEN device %s", + info->expmag_settings.device[channel]); + value = 0.0; + } + } + + } else { + value = 0.0; + } + } + } + + if (value != 0.0) { + + /* do inverted calibration? */ + if (*(info->calibration + channel) != NULL) { + double valued, resultd; + + /* direction for setting is forward interpolation */ + if ((*(info->calibration + channel))->direction) { + + /* do reverse cubic spline interpolation */ + + if (info->expmag_settings.scale[channel] != 0.0) { + /* result = (value -offset)/scale */ + valued = (value - info->expmag_settings.offset[channel]) / + info->expmag_settings.scale[channel]; +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_get_demand(channel=%d,value=%f," + "(value-offset)/scale=%f)", channel, value, valued); +#endif + + if (splines((*(info->calibration + channel))->ncals, + (*(info->calibration + channel))->y, + (*(info->calibration + channel))->x, + (*(info->calibration + channel))->s2r, + (*(info->calibration + channel))->s3r, + (*(info->calibration + channel))->dyr, + 1, &valued, &resultd, 0) != SS_SUCCESS) { + cm_msg(MLOG, "","expmag_get_demand(channel=%d,value=%f) reverse " + "interpolation out of range", channel, valued); + } +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_get_demand(channel=%d,value=%f," + "rev interpolation=%f)", channel, valued, resultd); +#endif + result = resultd; + } else { + cm_msg(MLOG, "", + "expmag_get_demand(channel=%d) (value-offset)/scale " + "undefined with scale = 0.0!", channel); + result = 0.0; + } + + /* direction for setting is reverse interpolation */ + } else { + + /* do forward cubic spline interpolation */ + + valued = value; + + if (splines((*(info->calibration + channel))->ncals, + (*(info->calibration + channel))->x, + (*(info->calibration + channel))->y, + (*(info->calibration + channel))->s2f, + (*(info->calibration + channel))->s3f, + (*(info->calibration + channel))->dyf, + 1, &valued, &resultd, 0) != SS_SUCCESS) { + cm_msg(MLOG, "", "expmag_get_demand(channel=%d,value=%f) forward " + "interpolation out of range", channel, valued); + } +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_get_demand(channel=%d,value=%f," + "forw interpolation=%f)", channel, valued, resultd); +#endif + + /* result = scale*value + offset */ + result = info->expmag_settings.scale[channel] * resultd + + info->expmag_settings.offset[channel]; + +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_get_demand(channel=%d,value=%f," + "value*scale+offset=%f)", channel, resultd, result); +#endif + + } + + /* no calibration */ + } else { + /* calculate value=(value-offset)/scale */ + if (info->expmag_settings.scale[channel] != 0.0) { + result = (value - info->expmag_settings.offset[channel]) / + info->expmag_settings.scale[channel]; +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_get_demand(channel=%d,value=%f," + "value*scale+offset=%f)", channel, value, result); +#endif + } else { + cm_msg(MLOG, "", + "expmag_get_demand channel %d (%s) ERROR Division by zero : " + "scale = 0.0!", channel, info->expmag_settings.device[channel]); + result = 0.0; + } + } + } else { + result = 0.0; + } + + /* PSIBL : round to nearest integer? */ + if (strncmp(info->expmag_settings.type[channel], "PSIBL", 5) == 0) { + float rest, resultt; +#ifdef MIDEBUG1 + float resulto; + + resulto = result; +#endif + resultt = (float) ((int) result); + rest = result - resultt; + result = resultt; + if (rest >= 0.0) { + if (rest > 0.50) + result = resultt + 1.0; + } else { + if (rest < -0.50) + result = resultt - 1.0; + } +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_get_demand Round %f -> %f + %f -> %f", resulto, + resultt, rest, result); +#endif + } else if ((strncmp(info->expmag_settings.type[channel], "MAG", 3) == 0) || +#ifdef EPICSGFA + (strncmp(info->expmag_settings.type[channel], "EPICSGFA",8) == 0) || +#endif + (strncmp(info->expmag_settings.type[channel], "GOSSEN", 6) == 0)) { + if (info->expmag_settings.ndigits[channel] >= 0) { + char field[40]; + sprintf(field, "%.*f", MIN(info->expmag_settings.ndigits[channel], 10), + result); + sscanf(field, "%f", &result); + } + } +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_get_demand(channel=%d,value=%f)", channel, result); +#endif + + raw_value: + + if (pvalue != NULL) + *pvalue = result; + + } else { + if (pvalue != NULL) + *pvalue = 0.0; +#ifdef MIDEBUG2 + cm_msg(MLOG, "", "expmag_get_demand(channel=%d) disabled!", channel); +#endif + } + } else { + if (pvalue != NULL) + *pvalue = 0.0; +#ifdef MIDEBUG2 + cm_msg(MLOG, "", "expmag_get_demand(channel=%d) Not used!", channel); +#endif + } + + if (pvalue != NULL) + info->last_demand[channel] = *pvalue; + cm_msg_flush_buffer(); + return FE_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ + +INT expmag_get_name(EXPMAG_INFO * info, INT channel, char *name) +{ + if ((info != NULL) && (channel >= 0) && (channel < EMNDEVS) && (name != NULL)) { + strncpy(name, info->expmag_settings.device[channel],NAME_LENGTH); + name[NAME_LENGTH-1] = '\0'; + } + return FE_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +INT expmag_get_default_threshold(EXPMAG_INFO * info, INT channel, float *pthreshold) +{ + + if ((info != NULL) && (channel >= 0) && (channel < EMNDEVS) && (pthreshold != NULL)) { + if (info->threshold != NULL) { + if (strncmp(info->expmag_settings.device[channel], "NONE", 4) != 0) { + *pthreshold = *(info->threshold + channel); +#ifdef MIDEBUG1 + cm_msg(MLOG, "", "expmag_get_default_threshold(%d) threshold = %f", channel, + *pthreshold); +#endif + } else { + *pthreshold = 1.0; + } + } else { + *pthreshold = 1.0; + cm_msg(MLOG, "", "expmag_get_default_threshold(%d) threshold not available!", + channel); + } + } + return FE_SUCCESS; +} + +/*---- device driver entry point -----------------------------------*/ + +INT expmag(INT cmd, ...) +{ + va_list argptr; + HNDLE hKey; + INT channel, status; + DWORD flags; + float value, *pvalue; + void *info, *bd; + char *name; + + va_start(argptr, cmd); + status = FE_SUCCESS; + +#ifdef MIDEBUGC + cm_msg(MLOG, "", "expmag(cmd=%d)", cmd); +#endif + + switch (cmd) { + case CMD_INIT: + hKey = va_arg(argptr, HNDLE); + info = va_arg(argptr, void *); + channel = va_arg(argptr, INT); + flags = va_arg(argptr, DWORD); + bd = va_arg(argptr, void *); + status = expmag_init(hKey, &info, channel, (INT (*)(INT, ...))bd); + break; + + case CMD_EXIT: + info = va_arg(argptr, void *); + status = expmag_exit((EXPMAG_INFO *)info); + break; + + case CMD_SET: + gngets = 0; /* reset readout count */ + info = va_arg(argptr, void *); + channel = va_arg(argptr, INT); + value = (float) va_arg(argptr, double); // floats are passed as double + status = expmag_set((EXPMAG_INFO *)info, channel, value, NULL); + break; + +#ifdef OBSOLETE_2_1 + case CMD_SET_ALL: + status = 0; + break; +#endif + + case CMD_GET: + info = va_arg(argptr, void *); + channel = va_arg(argptr, INT); + pvalue = va_arg(argptr, float *); + status = expmag_get((EXPMAG_INFO *)info, channel, pvalue); + /* slow down after setting device */ + if (gngets < 1000) { + gngets++; + if (gngets > 100) { +#ifdef EPICSGFA + epics_wait(info, 3, 333); +#else + ss_sleep(1000); +#endif + } + } else { +#ifdef EPICSGFA + epics_wait(info, 6, 500); +#else + ss_sleep(3000); +#endif + } + break; + +#ifdef OBSOLETE_2_1 + case CMD_GET_ALL: + status = 0; + break; +#endif + + case CMD_GET_DEMAND: + info = va_arg(argptr, void *); + channel = va_arg(argptr, INT); + pvalue = va_arg(argptr, float *); + status = expmag_get_demand((EXPMAG_INFO *)info, channel, pvalue); + break; + +#ifdef OBSOLETE_2_1 + case CMD_GET_DEFAULT_NAME: +#else + case CMD_GET_LABEL: +#endif + info = va_arg(argptr, void *); + channel = va_arg(argptr, INT); + name = va_arg(argptr, char *); + status = expmag_get_name((EXPMAG_INFO *)info, channel, name); + break; +#ifdef OBSOLETE_2_1 + case CMD_GET_DEFAULT_THRESHOLD: +#else + case CMD_GET_THRESHOLD: +#endif + info = va_arg(argptr, void *); + channel = va_arg(argptr, INT); + pvalue = va_arg(argptr, float *); + status = expmag_get_default_threshold((EXPMAG_INFO *)info, channel, pvalue); + break; + + case CMD_SET_LABEL: + /* label may not be set */ + break; + + default: + break; + } + + va_end(argptr); + +#ifdef MIDEBUGC + cm_msg(MLOG, "", "expmag(status=%d)", status); +#endif + + return status; +} + +/*################################################################# + + Set-up and usage of this EXPMAG Midas front-end using EPICS Channel Access + ========================================================================== + + Requirements + ------------ + + - Devices of this instrument in this area must be in the global table (gtable) above + with the respective type, ranges, calibration (type, file name), scale, offset, + information server and channel/adress/port specified. + There usually exists a virtual device (MAG) to set the demand value in magnetic + field units and a corresponding real device (PSIBL,EPICSGFA,GOSSEN) to set the + field in device specific units. The result of the conversion (interpolation and/or + scaling) of the virtual device will be forwarded to the real device and sent to the + device. + The readout of the real device will be forwarded to the virtual device and + converted to respective field units. + + - The possible range of the real devices (PSIBL,EPICSGFA,GOSSEN) has to be known + and the respective values of the virtual devices have to be known. + + - The min. and max. allowed field of virtual devices and corresponding real device + values have to be known. + + - If a calibration file (max. 31 char) is specified it has to be present in the + current directory, usually /userdisk0/musr/exp/td_musr2n/expmag when this front end + is started. + + The structure of the calibration file is + . ASCII file containing lines of corresponding data pairs. + . Values of the real device (e.g. DAC or AMP) versus the magnetic field value + (e.g. G or T) of the corresponding virtual device should be entered. e.g. + 0 0.285 + 2000 480.405 + A backward cubic spline interpolation will be performed to calculate the real + device value of the corresponding magnetic field value. + . Everything following ! will be ignored as comments. + . The entire range of the real device should be covered by data pairs in order to + be able to convert the device readout to magnetic field units. + NOTE: demand values are limited by minval/maxval and minrval/maxrval. + + A forward cubic spline interpolation of value x is + + = + *INTERPOLATION(x) + + A backward cubic spline interpolation of value y is + + = BACK_INTERPOLATION{(y-)/} + + - ROADC device controls of the devices are turned on and switched to remote. + NOTE: TCPIP bus driver will be attached during compilation and linkage of frontend. + + - EPICS device controls of the devices are turned on and EPICS channels are then + available. + + NOTE: EPICS device driver used as sub device driver will be attached during + compilation and linkage of frontend. During execution LD_LIBRARY_PATH + environment variable has to specify the location of the EPICS shareable + object libraries (libca.so and libCom.so). Environment variable PATH + has to contain the location of the caRepeater executable. + + - GOSSEN is connected to LAN/GPIB device and GPIB address is set. + NOTE: LAN/GPIB bus driver will be attached during compilation and linkage of fe. + + + Initial set-up of the ODB + ------------------------- + + - The minimal EPICS library for bulk muSR including defepics.bash and epicsrun.bash + contained in the Midas bulk muSR distribution must be installed in /usr/local/midas2n_32. + + - (Default) Location of .setup is /usr/local/midas2n_32 + + - Change the directory to /usr/local/midas2n_32 or midas2n_64 + + - Start the EPICS specific front-end EXPMAG_eexpmag_scfe using command + /usr/local/midas2n_32/epicsrun.bash EXPMAG_eexpmag_scfe -h -e td_musr2n + to create the EXPMAG equipment path (name = expmag) in the /Equipment directory of + the ODB. + + - Stop the front-end. + + - Use odbedit or web access to the ODB to go to ODB directory + + /Equipment//Settings/Devices/EXPMAG/DD/ + + - Change the "Instrument" key to the respective instrument name GPS, GPD or VMS. + + - Change the "Area" key to the respective area name. PIM3 for GPS, MUE1 for GPD, + PIE1 for VMS. + + - Specify the number of EPICS Channels (Usually four per magnet) + + - Start the frontend to create /Equipment//Settings/Devices/EXPMAG/EPICS/DD/ + + - Stop the front-end. + + - Prepare the EPICS setup-file .setup and enter the file name in + /Equipment//Settings/Devices/EXPMAG/EPICS/DD/Loadfile using odbedit. + + e.g. EPICSGFA_PIM3_expmag.setup for GPS + +# Loadfile for PIM3 experiment magnets using EPICSGFA fe +# CA_Name,,,,,,,, +# , y/[n], [y]/n , [US] , [CA_Name] , [0.0] , [0.0] , [0.1] ,[0.0] +# <40Char, , <32Char +# CA_NAME U Ro Fl Midas_Name Minval Maxval Threshold Tolerance +# Helmholtz Magnet 650 A || beam +WEH82:COM:2 , y , n , I # EXPMAG +WEH82:STA:1 , y , y , I +WEH82:SOL:2 , y , n , IMCTR, , -1.0 , 650.0 , , 1.3 +WEH82:IST:2 , y , y , I +# Helmholtz Magnet 50 A || beam +WEDL:COM:2 , y , n , I # EXPMAG +WEDL:STA:1 , y , y , I +WEDL:SOL:2 , y , n , IMCTR, , -50.0 , 50.0 , , 0.1 +WEDL:IST:2 , y , y , I +# Magnet 200 A | beam +WEP:COM:2 , y , n , I # EXPMAG +WEP:STA:1 , y , y , I +WEP:SOL:2 , y , n , IMCTR, , 0.0 , 200.0 , , 0.4 +WEP:IST:2 , y , y , I + + NOTE: F and G Chn_Flags should not be set! + + Minval of WEH82:SOL:2 is -1.0. Polarity change is used to connect GOSSEN to the magnet + + + Read drivers/device/epics_ca_private.h for details about Chn_Flags. + + - Start the front-end again to load the EPICS setup file to .../EXPMAG/EPICS/DD and to + initialise the rest of the device driver information for the devices of + in in .../EXPMAG . + NOTE: If a Device[I] is set to "NONE" all parameters of this device will be + initialised taking values from the internal table. + + - Stop the front-end again. + + - Verify the "Title" key. If set to "Y" ODB key /musr/td_musr/runinfo/runtitle + field will be updated when setting a new value for device [i]. + + - Verify the "Ndigits" key. The magnetic field values and the current of device [i] + will be rounded to Ndigits decimal places. + + - Verify the "Server" key. For PSIBL change "server" to the name of the beamline + server of the area. Specify CHAN if the channel should be forwarded to the "server" + connection of another PSIBL channel. For GOSSEN change "langpib" to the hostname of + the LAN/GPIB server. + For EPICSGFA type devices specify EPICS. + + - Verify the "Address" key. For "PSIBL" type devices this should be the port number of + the beamline server if "Server" is not "CHAN". If server is "CHAN" this should be the + channel number of the device being owner the "server" connection to the beamline + server. + For GOSSEN type devices this should be the GPIB address of the GOSSEN device. + For EPICSGFA type devices specify the "coded" EPICS channels which is the + EPICS channnel index of EPICS channel :SOL:2 * 1000 + the EPICS channel + index of EPICS channel :IST:2. e.g. for WED this would be 2003. + + - Verify the "Used" key. Change to "Y" if device [i] is used. + NOTE: Both Virtual and real device of a magnet have to be set to "Y"! + + - Start the front-end. Use odbedit or web access to the ODB to read the logged + messages. + + - If there is no problem stop the front-end again. + + - Using odbedit create alarm "ExpMags connected" by copying "Demo ODB" in directory + /Alarms/Alarms and changing Condition to + /Equipment/expmag/Settings/Devices/EXPMAG/EPICS/DD/Sum_NOT_Connected > 0. + To automatically reset the alarm when Sum_NOT_Connected <= 0, specify + "ExpMAGS connected" in AlarmWhenNOTConnected in /Equipment/.../EXPMAG/EPICS/DD. + + - Create alarm "ExpMags tolerance" when Sum_NOT_in_Tolerance > 0 and to automatically + reset the alarm specify "ExpMags tolerance" in AlarmWhenNOTinTolerance in + /Equipment/expmag/.../EXPMAG/EPICS/DD + + - If ZFC is used, start ZFC, Stray Field and zfc_control first. If everything + is working set "ZFC used" to Y. When a device current or a magnetic field is set + ZFC control should switch to TABLE mode. + "/Equipment/ZFC/Settings/Devices/IN/DD/Mode (0,1,2)" should then be set to 2. + + - Follow https://lmu.web.psi.ch/software/bulkmusr/daq/epics_expmag.txt how to create + calibration tables + + - Location of calibration files is /userdisk0/musr/exp/td_musr2n/expmag on the respective + Midas back end. + + - Change the current directory to /userdisk0/musr/exp/td_musr2n/expmag + + - Using odbedit or web access to enter the name of the calibration file in the + Calibration [i] field and the interpolation direction in the respective Direction [i] + field. + + - Start the front-end again + using the -p /userdisk0/musr/exp/td_musr2n/expmag command line argument to change + the working directory to /userdisk0/musr/exp/td_musr2n/expmag and -D to start it as + a daemon. + + - Use the browser to select the instrument specific web page http://pswXXX:8083 + Click the Programs button and select the EXPMAG expmag line. Set Required Y + and enter /usr/local/midas2n_32/epicsrun.bash EXPMAG_eexpmag_scfe -p (continued next page) + /userdisk0/musr/exp/td_musr2n/expmag/ -h pswXXX -e td_musr2n -D + as Start command. + + + Front-end Usage + --------------- + Use odbedit or web access to the ODB to change Demand + + MAG type devices : demand field in respective units may be set. + Converted demand value will be sent to PSIBL, EPICSGFA or + GOSSEN type devices (device ending with DAC, AMP or GOSSENA), + respectively. + PSIBL type devices : demand value in DAC will be sent to the beamline server. + EPICSGFA type devices : demand value in AMP will be sent to the EPICS channel + GOSSEN type devices : demand value in AMPS will be sent to GOSSEN. + + Deltat usage + ------------ + Equipment must be defined in /userdisk0/musr/exp/td_musr2n/midas2n/deltat.set : + EQUIPMENT EXPMAG expmag /userdisk0/musr/exp/td_musr2n/expmag S + Only MAG devices will be shown. + The magnetic field of the shown magnets may be set. The user will be informed about + the device limits if a value outside the range should be set. + + Autorun sequences + ----------------- + SET expmag WEDL 200 120 + WAIT expmag INRANGE 240 + + + ODB Variables + ------------- + /Equipment//Settings/Devices/EXPMAG/DD/ + Instrument instrument name + Area area name + ZFC used Y=ZeroFieldCompensation used + EPICS channels number of EPICS channels used + Device[i] device name + Type[i] device type + Server[i] server|CHANnel|MAGnet|EPICS + Address[i] ||| + + Calibration[i] calibration file name (max. 31 char) + Direction[i] F/R interpolation direction + Scale[i] scale + Offset[i] offset + Unit[i] unit G|T|DAC|uA|AMP|AMPS + Minval[i] minimum allowed value for PSIBL type + Maxval[i] maximum allowed value for PSIBL type + Minrval[i] minimum allowed value for MAG, GOSSEN, EPICSGFA + type + Maxrval[i] minimum allowed value for MAG, GOSSEN, EPICSGFA + type + Title[i] update run title when updating table + Ndigits[i] number of decimal digits + Used[i] Y/N device is used + Expiration[i] Settling time in seconds since 1.1.1970 UTC. + Status[i] status of device NIY + + /Equipment//Settings/Devices/EXPMAG/DD//BD/ + /Equipment//Settings/Devices/EXPMAG/DD//BD/ + copy of Server and Adress information to be able to use BusDriver software + will be overwritten during front end startup. + + /Equipment//Settings/Devices/EXPMAG/EPICS/DD/ + epics settings of EPICS channel access device driver + + /Equipment//Variables/Demand Array of demand values. If value changed + demand value will be sent to real device. + NOTE: The device may not be set to the same + value again. If there is a problem + set the magnet to a slightly different + value. + /Equipment//Variables/Measured Array of measured values. + + ################################################################# */ + +/*------------------------------------------------------------------*/ diff --git a/device/expmag.h b/device/expmag.h new file mode 100644 index 0000000..15f7d28 --- /dev/null +++ b/device/expmag.h @@ -0,0 +1,10 @@ +/********************************************************************\ + + Created by: RA35 + + Contents: Device driver function declarations for experimental magnets device + + +\********************************************************************/ + +INT expmag(INT cmd, ...); \ No newline at end of file diff --git a/device/spline.cxx b/device/spline.cxx new file mode 100644 index 0000000..ccb648c --- /dev/null +++ b/device/spline.cxx @@ -0,0 +1,741 @@ +/********************************************************************\ + + Name: spline.c + Created by: RA95 + + Contents: Routines to perform cubic spline interpolation + + Revision 1.2 2017/01/26 07:45:52 raselli + Fixed compilation errors + + Revision 1.1 2017/01/26 07:37:25 raselli + Original bulk muSR Midas 1.9.5 version + + Revision 1.8 2016/09/09 13:14:40 raselli + Bulk musr 09-SEP-2016 + + Revision 1.0 2003/09/29 12:18:57 midas + + Date Name Modification + ----------------------------------------------------------------- + 25-OCT-2003 RA95 Initial version + 09-JUN-2004 RA35 splines() interval search modified for descending + x values of calibration data to handle reverse + interpolation + +\********************************************************************/ + +#define SPLIN_INF 1.0e36 /* infinite value */ +#define SPLIN_U6 (1.0/6.0) /* coefficient */ +#define SPLIN_EPSLN 1.0e-3 /* convergence limit */ +#define SPLIN_OG 1.0717968 + +#define ABS(a) ((a) >= 0.0)?(a):-(a) + +#include +#include +#include +#include +#include +#include +#include "midas.h" +#include "spline.h" + +/* ------------------------------------------------------------------------- */ +/* #define MIDEBUGD /* display information */ +/* #define MIDEBUG1 /* function calls and essential */ +/* #define MIDEBUG2 /* additional info */ +/* #define MIDEBUG3 /* exhaustive */ +/* ------------------------------------------------------------------------- */ + +INT splineo(char *, INT *, double **, double **, BOOL); +INT splinec(INT, double *, double *, double *, double *, double *, BOOL); +INT splines(INT, double *, double *, double *, double *, double *, + INT, double *, double *, BOOL); + +/* ------------------------------------------------------------------------- */ + +INT splineo(char *filename, INT *npoints, double **X, double **Y, BOOL verbose) { + +/********************************************************************\ + + Routine: splineo + + Purpose: open and process calibration file + return number of data points and data points + + Input: + char *filename file containing interpolation input data + BOOL verbose show information on display if TRUE + + Output: + INT *npoints address of number of data points read from file + double **X address of pointer to X values + double **Y address of pointer to corresponding Y values + + Function value: + INT SS_SUCCESS : Success + +\********************************************************************/ + + INT ret; + +#ifdef MIDEBUG1 + printf(">> splineo (%s)\n",filename); +#endif + +#ifdef MIDEBUGD + verbose = TRUE; +#endif + + ret = CM_SUCCESS; + + if ((filename != NULL) && (strlen(filename) > 0) && (npoints != NULL) && + (X != NULL) && (Y != NULL)) { + FILE *pfile; + + /* initialise return parameters */ + *npoints = 0; + *X = NULL; + *Y = NULL; + + /* open and process calibration file */ + if ((pfile = fopen(filename,"r")) != NULL) { + char line[255]; + INT i,n; + INT len; + double *x, *y; + double xi, yi; + + n = 0; + x = NULL; + y = NULL; + +read_again: ; + + /* process file */ + while (!feof(pfile)) { + + /* + * file contents + * -------------- + ! comment + xxx.xxx yyy.yyy ! table of data pairs + ! x and y are separated by space + ! each pair is on a separate line + ! x values of table are continuous in + ! ascending order + ! y values are continuous + */ + + if (fgets(line,sizeof(line),pfile)!=NULL) { + if ((len=strlen(line))>0) { +#ifdef MIDEBUG3 + printf("last char : %d\n",line[len-1]); +#endif + /* remove cr & lf */ + while ((len >=0) && ((line[len-1] == '\x0a')||(line[len-1] == '\r'))) + line[--len] = '\0'; + +#ifdef MIDEBUG3 + printf("Line : >%s<\n",line); +#endif + /* remove comments */ + for(i=len-1;i>=0;i--) + if (line[i] == '!') { + line[i] = '\0'; + len=i; + } +#ifdef MIDEBUG3 + printf("comment removed : >%s<\n",line); +#endif + + /* remove trailing blanks */ + while ((len>0)&& isspace(line[len-1])) line[--len] = '\0'; + +#ifdef MIDEBUG3 + printf("trailing spaces removed : >%s<\n",line); +#endif + + /* remove leading blanks and multiple spaces */ + if (len > 0) { + BOOL space; + INT j; + + j=-1; + for(i=0,space=FALSE;i%s<\n",line); +#endif + + } + + if (len > 0) { + + /* read values */ + if (sscanf(line,"%lf %lf",&xi,&yi)==2) { + + /* store values */ + if (x != NULL) *(x+n) = xi; + if (y != NULL) *(y+n) = yi; + n++; + + } else { + cm_msg(MERROR,"splineo","ERROR reading x and y as floating point numbers."); + ret = CM_SET_ERROR; + } + } + } else { +#ifdef MIDEBUG2 + cm_msg(MERROR,"splineo","WARNING empty line in calibration file %s", + filename); +#endif + } + } else { + if (ferror(pfile)) { + cm_msg(MERROR,"splineo", + "fgets error %d reading line from calibration file",errno); + ret = CM_SET_ERROR; + } + } + } + + /* any points found and data not allocated? */ + if ((n > 0) && (x == NULL)) { + + /* allocate storage space */ + x = (double *) calloc(n,sizeof(double)); + y = (double *) calloc(n,sizeof(double)); + + n = 0; /* reset number of processed data pairs */ + + /* reposition to beginning of file (if data is now allocated) */ + if ( (x != NULL) && (y != NULL)) { + fseek(pfile,0,SEEK_SET); + goto read_again; + } + + if (x != NULL) free(x); + if (y != NULL) free(y); + x = NULL; + y = NULL; + + /* not able to allocate data */ + cm_msg(MERROR,"splineo","ERROR not able to allocate memory for x or y data"); + ret = SS_NO_MEMORY; + + } else if (n==0) { + cm_msg(MERROR,"splineo","ERROR no valid x y data in %s",filename); + ret = CM_SET_ERROR; + } + + if (fclose(pfile) == EOF) { + cm_msg(MERROR,"splineo","fclose error %d closing calibration file", errno); + ret = CM_SET_ERROR; + } + + /* check values */ + if ((x != NULL)&&(y != NULL)) { + if (n >= 3) { + BOOL xcont,ycont,yasc; + + xcont = TRUE; + ycont = TRUE; + + if (*y < *(y+n-1)) + yasc = TRUE; + else + yasc = FALSE; + + for (i=0;i= *(x+i+1)) xcont = FALSE; + + /* y ascending or descending? */ + if (yasc) { + if (*(y+i) >= *(y+i+1)) ycont = FALSE; + } else { + if (*(y+i) <= *(y+i+1)) ycont = FALSE; + } + } + + if (!xcont) { + cm_msg(MERROR,"splineo", + "X data points in calibration file %s are not continuously ascending", + filename); + ret = CM_SET_ERROR; + } + + if (!ycont) { + cm_msg(MERROR,"splineo", + "Non continuous Y data points in calibration file %s",filename); + ret = CM_SET_ERROR; + } + + } else { + cm_msg(MERROR,"splineo","Not enough data points in calibration file %s", + filename); + ret = CM_SET_ERROR; + } + } + + /* everything OK? */ + if ((n >= 3) && (ret == CM_SUCCESS)) { + + if (verbose) { + printf("\n"); + for (i=0; i> splinec\n"); +#endif + +#ifdef MIDEBUGD + verbose = TRUE; +#endif + + ret = CM_SUCCESS; + + if ((N > 2) &&(X != NULL) && (Y != NULL) && (s2 != NULL) && (s3 != NULL)&& + (dy != NULL)) { + + double *w; + double *eta; + double *h; + double *g; + double *c2; + double *b; + double *vv; + INT i,n1,n2; + BOOL conv; + + n1 = N-1; + n2 = n1-1; + +#ifdef MIDEBUG2 + printf(" N = %d, n1 = %d, n2 = %d\n",N,n1,n2); +#endif + + /* allocate temporary arrays */ + w = (double *) calloc(N-2,sizeof(double)); + eta = (double *) calloc(N-2,sizeof(double)); + + h = (double *) calloc(N-1,sizeof(double)); + g = (double *) calloc(N-1,sizeof(double)); + c2 = (double *) calloc(N-1,sizeof(double)); + b = (double *) calloc(N-1,sizeof(double)); + vv = (double *) calloc(N-1,sizeof(double)); + + /* allocation OK? */ + if ((w!=NULL) && (eta!=NULL) && (h!=NULL) && (g!=NULL) && (c2!=NULL) && + (b!=NULL) && (vv!=NULL)) { + + /* initialise variables */ + for (i=0;i *(eta+i)) *(eta+i) = ABS(*(w+i)); + + if (*(eta+i)>SPLIN_EPSLN) { +#ifdef MIDEBUG2 + printf("-> eta[%d] = %lf, s2[%d] = %lf, w[%d] = %lf\n", + i+1,*(eta+i),i+2,*(s2+i+1),i+1,*(w+i)); +#endif + *(s2+i+1) = *(s2+i+1) + *(w+i); + conv = FALSE; + } + + } + } while (!conv); + + /* calculate s' */ + for (i=0;i> splines\n"); +#endif + +#ifdef MIDEBUGD + verbose = TRUE; +#endif + ret = CM_SUCCESS; + + /* check parameter */ + if ((N>2) && (M>0) && (X!=NULL) && (Y!=NULL) && (s2 != NULL) && + (s3 != NULL) && (dy != NULL) && (t!=NULL) && (sp!=NULL)) { + + if (*X < *(X+N-1)) + asc = 1; /* x values of calibration data are ascending */ + else + asc = 0; /* x values of calibration data are descending */ + + /* for all values to interpolate */ + for(j=0;j= *X) && (curx <= *(X+N-1)))|| + ((curx <= *X) && (curx >= *(X+N-1))) ) { + + /* ascending x values of calibration data? */ + if (asc) { + + /* upper limit? */ + if (curx < *(X+N-1)) { + + /* find interval of value */ + for (i=0,i1=-1;i curx) { + i1 = i; + break; + } + } /* for all values in the calibration table */ + + } else { + /* for upper limit take last interval */ + i1 = N-1; + } + + /* descending x values of calibration data? */ + } else { + /* lower limit? */ + if (curx > *(X+N-1)) { + + /* find interval of value */ + for (i=0,i1=-1;i y[%d] = %lf\n", j, curx, j, caly); + } + } /* for all values to be calculated */ + + } else { + + /* check parameter */ + if (N <= 2) + cm_msg(MERROR,"splines","Not enough data points"); + + if (X == NULL) + cm_msg(MERROR,"splines","NULL pointer supplied as X data values"); + + if (Y == NULL) + cm_msg(MERROR,"splines","NULL pointer supplied as Y data values"); + + if (s2 == NULL) + cm_msg(MERROR,"splines","NULL pointer supplied as s2 spline coefficient"); + + if (s3 == NULL) + cm_msg(MERROR,"splines","NULL pointer supplied as s3 spline coefficient"); + + if (dy == NULL) + cm_msg(MERROR,"splines","NULL pointer supplied as dy spline coefficient"); + + if (M<=0) + cm_msg(MERROR,"splines","Not enough data points"); + + if (t==NULL) + cm_msg(MERROR,"splines","NULL pointer supplied as t data array"); + + if (sp==NULL) + cm_msg(MERROR,"splines","NULL pointer to return interpolated values"); + + ret = SS_INVALID_ADDRESS; + } + +#ifdef MIDEBUG1 + printf("<< splines\n"); +#endif + + return ret; +} + +/* ----------------------------------------------------------------------- */ + +#ifdef SPLINE_MAIN + +main () { + +#ifdef CHECK4 +#define NCALS 4 +#else +#define NCALS 5 +#endif + + double x [NCALS]; + double y [NCALS]; + double s2[NCALS]; + double s3[NCALS]; + double dy[NCALS]; + double val[5], res[5]; + + x[0] = 0.0; + x[1] = 1.0; + x[2] = 2.0; + x[3] = 3.0; +#if (NCALS == 5) + x[4] = 4.0; +#endif + + y[0] = 0.0; + y[1] = 1.0; + y[2] = 4.0; + y[3] = 9.0; +#if (NCALS == 5) + y[4] = 16.0; +#endif + + /* calculate coefficients */ + splinec(sizeof(x)/sizeof(double),x,y,s2,s3,dy); + + val[0] = 0.0; + val[1] = 1.0; + val[2] = 2.0; + val[3] = 3.0; + val[4] = 1.7; + + /* perform cubic spline interpolation */ + splines(sizeof(x)/sizeof(double),x,y,s2,s3,dy, + sizeof(val)/sizeof(double),val,res); + +} +#endif /* SPLINE_MAIN */ + +/* -------------------------------------------------------- EOF spline.c */ diff --git a/device/spline.h b/device/spline.h new file mode 100644 index 0000000..21ceb76 --- /dev/null +++ b/device/spline.h @@ -0,0 +1,40 @@ +/********************************************************************\ + + Name: spline.h + Created by: RA95 + + Contents: Header file to perform cubic spline interpolation + + Revision 1.1 2017/01/26 07:37:25 raselli + Original bulk muSR Midas 1.9.5 version + + Revision 1.8 2016/09/09 13:14:40 raselli + Bulk musr 09-SEP-2016 + + Revision 1.0 2003/09/29 12:18:57 midas + + Date Name Modification + ----------------------------------------------------------------- + 25-SEP-2003 RA95 Initial version + +\********************************************************************/ + +#ifndef _SPLINE_H_ +#define _SPLINE_H_ + +#define SPLIN_INF 1.0e36 /* infinite value */ + +#include +#include +#include +#include "midas.h" + +/* ------------------------------------------------------------------------- */ + +INT splineo(char *, INT *, double **, double **, BOOL); +INT splinec(INT, double *, double *, double *, double *, double *, BOOL); +INT splines(INT, double *, double *, double *, double *, double *, + INT, double *, double *, BOOL); + +/* ------------------------------------------------------------------------- */ +#endif /* #ifndef _SPLINE_H */ \ No newline at end of file diff --git a/frontend/expmag_scfe.cxx b/frontend/expmag_scfe.cxx new file mode 100644 index 0000000..8fc7d6b --- /dev/null +++ b/frontend/expmag_scfe.cxx @@ -0,0 +1,123 @@ +/*******************************************************************\ + + Name: expmag_fe.cxx + Created by: Stefan Mathis + Contents: Slow Control Frontend for beamline magnets + +\********************************************************************/ + +#include "midas.h" + +#include "mfe.h" + +#include "bus/tcpip.h" +#include "class/generic.h" + +#include "device/expmag.h" + +/******************************************************************************* + * Global Variables Required by mfe.h + ******************************************************************************/ + +//! The frontend name (client name) as seen by other MIDAS clients +const char *frontend_name = "Experiment magnet"; + +//! The frontend file name, don't change it +const char *frontend_file_name = __FILE__; + +//! frontend_loop is called periodically if this variable is TRUE +BOOL frontend_call_loop = TRUE; + +//! a frontend status page is displayed with this frequency in ms +INT display_period = 1000; + +//! maximum event size produced by this frontend +INT max_event_size = 10000; + +//! maximum event size for fragmented events (EQ_FRAGMENTED) +INT max_event_size_frag = 5 * 1024 * 1024; + +//! buffer size to hold events +INT event_buffer_size = 10 * 10000; + +/******************************************************************************* + * Equipment List Required by mfe.h + ******************************************************************************/ + +DEVICE_DRIVER expmag_driver[] = { + // { name, *dd, channels, *bd, flags } + {"expmag", expmag, 9, NULL, DF_INPUT}, +}; + +/*! + * equipment_common_overwrite: + * + * - If that flag is TRUE, then the contents of the "equipment" structure is + * copied to the ODB on each start of the front-end. + * + * - If the flag is FALSE, then the ODB values are kept on the start of the + * front-end + */ +BOOL equipment_common_overwrite = FALSE; + +/******************************************************************************* + * Equipment Structure Required by mfe.h + ******************************************************************************/ + +EQUIPMENT equipment[] = { + { + "expmag", /* equipment name */ + { + 16, /* Event ID associated with equipm. */ + 0, /* Trigger mask */ + "SYSTEM", /* Event buffer to send events into */ + EQ_SLOW, /* equipment type */ + 0, /* Event source (LAM/IRQ) */ + "FIXED", /* Data format to produce */ + TRUE, /* Enable flag */ + RO_RUNNING | + RO_TRANSITIONS, /* Combination of Read-On flags RO_xxx */ + 60000, /* Readout interval/Polling time in ms */ + 0, /* Stop run when limit is reached */ + 0, /* Number of events in super event */ + 1, /* log history every event */ + "", /* Host on which FE is running */ + "", /* Frontend name */ + "" /* Source file used for user FE */ + }, + cd_gen_read, /* readout routine */ + cd_gen, /* class driver main routine */ + expmag_driver, /* device driver list */ + NULL, /* init string */ + }, + {""}}; + +/******************************************************************************* + * Routines Required by mfe.h + * + * Can be overwritten to modify the default frontend behaviour. + ******************************************************************************/ + +INT poll_event(INT source, INT count, BOOL test) { return CM_SUCCESS; }; + +INT interrupt_configure(INT cmd, INT source, POINTER_T adr) { + return CM_SUCCESS; +}; + +INT frontend_init() { + return CM_SUCCESS; +} + +INT frontend_loop() { + return CM_SUCCESS; +} + +INT frontend_exit() { return CM_SUCCESS; } + +INT begin_of_run(INT run_number, char *error) { return CM_SUCCESS; } + +INT pause_run(INT run_number, char *error) { return CM_SUCCESS; } + +INT resume_run(INT run_number, char *error) { return CM_SUCCESS; } + +INT end_of_run(INT run_number, char *error) { return CM_SUCCESS; } diff --git a/midas_lan_gpib b/midas_lan_gpib new file mode 160000 index 0000000..adba882 --- /dev/null +++ b/midas_lan_gpib @@ -0,0 +1 @@ +Subproject commit adba88295e9342fb9240ced04337abf6e1e3dec3