From f54ac320e407f9f4b5131fd94fb3a256c3c4fe8f Mon Sep 17 00:00:00 2001 From: Alexander Soederqvist Date: Thu, 6 Aug 2026 15:15:36 +0200 Subject: [PATCH] Import default frontend and program from VMS to be used also on GPS --- CMakeLists.txt | 57 +- frontend/Zero_field_compens_ctrl_scfe.cxx | 1743 +++++++++++++++++++++ frontend/scs900_scfe.cxx | 155 +- 3 files changed, 1862 insertions(+), 93 deletions(-) create mode 100644 frontend/Zero_field_compens_ctrl_scfe.cxx diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b827dc..3829fe9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,28 +74,75 @@ target_link_libraries( ################################################################################ if(${BUILD_FRONTEND}) + set(SCS900_FRONTEND_NAME "Zero_field_compens" CACHE STRING "Overridable frontend name") add_executable( - scs900_fe + Zero_field_compens_scfe frontend/scs900_scfe.cxx ) + add_compile_definitions(Zero_field_compens_scfe PRIVATE FRONTEND_NAME="${SCS900_FRONTEND_NAME}") set_property( TARGET - scs900_fe + Zero_field_compens_scfe PROPERTY CXX_STANDARD 11 ) target_include_directories( - scs900_fe + Zero_field_compens_scfe PRIVATE $ENV{MIDASSYS}/drivers ) target_link_libraries( - scs900_fe + Zero_field_compens_scfe scs900 ) -endif() \ No newline at end of file + # Build belonging control program + add_executable( + Zero_field_compens_ctrl_scfe + frontend/Zero_field_compens_ctrl_scfe.cxx + ) + set_property( + TARGET + Zero_field_compens_ctrl_scfe + PROPERTY + CXX_STANDARD 11 + ) + + target_compile_definitions( + Zero_field_compens_ctrl_scfe + PUBLIC + EXPERIMENT=${EXPERIMENT} + ) + + + target_include_directories( + Zero_field_compens_ctrl_scfe + PRIVATE + $ENV{MIDASSYS}/drivers + $ENV{MIDASSYS}/include + $ENV{MIDASSYS}/include/mscb + ) + + target_link_directories( + Zero_field_compens_ctrl_scfe + PRIVATE + $ENV{MIDASSYS}/lib + ) + + target_link_libraries( + Zero_field_compens_ctrl_scfe + midas::midas + ) + + install( + TARGETS + Zero_field_compens_scfe + Zero_field_compens_ctrl_scfe + RUNTIME DESTINATION bin + ) + +endif() diff --git a/frontend/Zero_field_compens_ctrl_scfe.cxx b/frontend/Zero_field_compens_ctrl_scfe.cxx new file mode 100644 index 0000000..751dd06 --- /dev/null +++ b/frontend/Zero_field_compens_ctrl_scfe.cxx @@ -0,0 +1,1743 @@ +/*--------------------------------------------------------------------------- + + Name: Zero_field_compens_ctrl.c + Created by: Hubertus Luetkens 2005/02/05 + + Contents: Zero Field Compensation Control Program + + Zero Field Compensation program to control the ZFC device using midas +database information created and updated by the frontends zfc_scfe and +Ext_stray_field_status_scfe + +---------------------------------------------------------------------------*/ + +/* +Define the experiment via a compile time flag. This is terrible coding practice, +but that is true for the entire program anyway. Before, the experiment name was +hardcoded, so this at least allow some reusability. The experiment name needs to +be passed as a compile time flag, e.g. -DEXPERIMENT=VMS. See CMakeLists.txt. +*/ +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "midas.h" +#include "msystem.h" + +#define MIDEBUG /* log to log file or print important debug info */ +// #define MIDEBUG1 /* log to log file or print exhaustive debug info */ + +// defines +#define ZFC_AUTOMATIC_OFF 0 +#define ZFC_AUTOMATIC_ON 1 + +#define ZFC_MODE_NOT_CHANGED 0 +#define ZFC_MODE_CHANGED 1 + +#define ZFC_MODE_MANUAL 0 +#define ZFC_MODE_ACTIVE 1 +#define ZFC_MODE_TABLE 2 + +#define ZFC_PROBE_GEOMETRY_NOT_CALIBRATED 0 +#define ZFC_PROBE_GEOMETRY_CALIBRATED 1 + +// global variables +BOOL verbose = FALSE; /* -v argument */ +BOOL debug = FALSE; /* -d argument */ + +//! Stores all the parameters (Keys to ZFC settings and corresponding variables) +//! the +// control program needs +typedef struct { + HNDLE hDB; + HNDLE hkeyADC; + HNDLE hkeyDAC; + HNDLE hkeyAUTOMATIC; + HNDLE hkeyMODE; + HNDLE hkeyModeChanged; //!< shake hand variable (setting 1) after Mode + //!< variable + // (0=manual,1=active,2=table) changed and + // zfc control accomplished Mode change + HNDLE hkeyA1; + HNDLE hkeyA2; + HNDLE hkeyc1; + HNDLE hkeyc2; + HNDLE hkeyInvResp; + HNDLE hkeyR; + HNDLE hkeyProbeGeo; + HNDLE hkeyB2set; + HNDLE hkeyProbe1Calibration; + HNDLE hkeyProbe2Calibration; + HNDLE hkeyMaxDAC; + HNDLE hkeyCobra_SC_factor; //!< key for Factor for field of Cobra SC in + //!< Gauss/Amp + HNDLE hkeyCobra_SC_offset; //!< key for offset for field of Cobra SC in + //!< Gauss/Amp + HNDLE hkeyCobra_NC_factor; //!< key for Factor for field of Cobra NC in + //!< Gauss/Amp + HNDLE hkeyCobra_NC_offset; //!< key for offset for field of Cobra NC in + //!< Gauss/Amp + HNDLE hkeyComet1_factor; //!< key for Factor for field of Comet 1 in + //!< Gauss/Amp + HNDLE hkeyComet1_offset; //!< key for offset for field of Comet 1 in + //!< Gauss/Amp + HNDLE hkeyComet2_factor; //!< key for Factor for field of Comet 2 in + //!< Gauss/Amp + HNDLE hkeyComet2_offset; //!< key for offset for field of Comet 2 in + //!< Gauss/Amp + HNDLE hkeyStrayFieldStatus; //!< key Cobra & Comet Status (Ampere) + + float adc[8]; + float dac[8]; + + float B1[3]; //!< Field at probe 1 in Gauss + float B2[3]; //!< Field at probe 2 in Gauss + float B2set[3]; //!< Field Setpoint for field at sample position + // (probe 2 position) in Gauss + float B2calc[3]; //!< Field at probe 2 calculated from field at probe 1 in + //!< Gauss + float MaxDAC; //!< Maximum DAC value in Volts (usually 1V=0.5A output) + INT automatic; //!< Automatic Mode variable (0=off=manual,1=on=automatic) + INT mode; //!< Mode variable (0=manual,1=active,2=table) + INT mode_changed; //!< is set to 1 when Zero_field_compens_ctrl gets + //!< information that Mode + // was changed by another program. + // Zero_field_compens_ctrl changes to Mode and resets + // Mode_Changed to 0 (in DD/IN) in order to inform the + // other program (waiting for the change) that Mode + // change was done. + INT probe_geometry; //!< Probe geometries defined? (0=not + //!< calibrated,1=calibrated) + // when set to 0, calibration will be performed and + // Probe_Geometry will be reset to 1 in DD/IN. + float A1[3][3]; //!< Responsmatrix Probe1 in Gauss/DAC (=Gauss/Volt) + float A2[3][3]; //!< Responsmatrix Probe2 in Gauss/DAC (=Gauss/Volt) + float R[3][3]; //!< Rotationmatrix (Orientation of probes, + // B2=R*B1 for homogenous fields) + float c1[3]; //!< Background Probe1 in Gauss + float c2[3]; //!< Background Probe2 in Gauss + float InvResp[3][3]; //!< Inverse of Responsmatrix Probe2 (A2-1) + float Probe1CalibrationFactor; //!< Calibration of sensor output Gauss/Volt + float Probe2CalibrationFactor; //!< Calibration of sensor output Gauss/Volt + float Cobra_SC_factor[3]; //!< Factor for field of Cobra SC in Gauss/Ampere + float Cobra_SC_offset[3]; //!< offset for field of Cobra SC in Gauss/Ampere + float Cobra_NC_factor[3]; //!< Factor for field of Cobra NC in Gauss/Ampere + float Cobra_NC_offset[3]; //!< offset for field of Cobra NC in Gauss/Ampere + float Comet1_factor[3]; //!< Factor for field of Comet1 in Gauss/Ampere + float Comet1_offset[3]; //!< offset for field of Comet1 in Gauss/Ampere + float Comet2_factor[3]; //!< Factor for field of Comet1 in Gauss/Ampere + float Comet2_offset[3]; //!< offset for field of Comet1 in Gauss/Ampere + float StrayFieldStatus[4]; //!< Cobra Status [0]= SC, [1]=NC, + // Comet1 [2], Comet2 [3] in (Ampere) + INT intCycles; + DWORD NewAdcTime; +} ZFC_VARIABLES; + +// callback routine to handle changes in StrayField Input +void NewStrayFieldStatus(HNDLE dummy1, HNDLE dummy2, void *zfc_variables) { + ZFC_VARIABLES *var; + int ndx; + float dB2[3]; // dB2 = B2set - h2 - c2 + float h2cobra[3]; // field at probe 2 produced only by Cobra magnet + float h2comet[3]; // field at probe 2 produced only by Comet magnet +#ifdef MIDEBUG + float temp[3]; // helper variable to store temporary results + float h2[3]; // h2 = R*(B1-A1*I-c1) +#endif + var = (ZFC_VARIABLES *)zfc_variables; + +#ifdef MIDEBUG + if (debug) + printf("New Stray Field Status: %.2f %.2f %.2f %.2f\n", + var->StrayFieldStatus[0], var->StrayFieldStatus[1], + var->StrayFieldStatus[2], var->StrayFieldStatus[3]); +#endif + // if not in table mode return + if (var->mode != ZFC_MODE_TABLE) + return; + + // Calculate h2 from table values and status of Cobra and Comet magnet + for (ndx = 0; ndx < 3; ndx++) { + h2cobra[ndx] = var->Cobra_SC_factor[ndx] * var->StrayFieldStatus[0] + + var->Cobra_SC_offset[ndx] + + var->Cobra_NC_factor[ndx] * var->StrayFieldStatus[1] + + var->Cobra_NC_offset[ndx]; + + h2comet[ndx] = var->Comet1_factor[ndx] * var->StrayFieldStatus[2] + + var->Comet1_offset[ndx] + + var->Comet2_factor[ndx] * var->StrayFieldStatus[3] + + var->Comet2_offset[ndx]; + // difference demand-actual (dB) + dB2[ndx] = var->B2set[ndx] - h2cobra[ndx] - h2comet[ndx] - var->c2[ndx]; + } + + // here comes the control + for (ndx = 0; ndx < 3; ndx++) { + // I = A2-1 * (B2set - h2 -c2) = A2-1 * dB2 + var->dac[ndx] = var->InvResp[ndx][0] * dB2[0] + + var->InvResp[ndx][1] * dB2[1] + + var->InvResp[ndx][2] * dB2[2]; + + // set new DAC when within limits (otherwise set the limit) + if (var->dac[ndx] < -1.0 * var->MaxDAC) + var->dac[ndx] = -1.0 * var->MaxDAC; + if (var->dac[ndx] > var->MaxDAC) + var->dac[ndx] = var->MaxDAC; + + /* printf("Zero_field_compens_ctrl: New dac[%d] \n", ndx); */ + db_set_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[ndx], + sizeof(var->dac[ndx]), ndx, TID_FLOAT); + } + +#ifdef MIDEBUG + if (debug && (var->mode == ZFC_MODE_TABLE)) { + for (ndx = 0; ndx < 3; ndx++) { + var->B1[ndx] = var->Probe1CalibrationFactor * var->adc[ndx]; + var->B2[ndx] = var->Probe2CalibrationFactor * var->adc[ndx + 4]; + // Helper to Calculate field at h2 from B1 using: temp = B1 - A1*I + // -c1 + temp[ndx] = var->B1[ndx] - var->A1[ndx][0] * var->dac[0] - + var->A1[ndx][1] * var->dac[1] - + var->A1[ndx][2] * var->dac[2] - var->c1[ndx]; + } + for (ndx = 0; ndx < 3; ndx++) { + // Calculate field at h2 from B1 using: h2 = R*(B1 - A1*I - c1) = + // R*temp + h2[ndx] = var->R[ndx][0] * temp[0] + var->R[ndx][1] * temp[1] + + var->R[ndx][2] * temp[2]; + } + for (ndx = 0; ndx < 3; ndx++) { + // Calculate field at B2 from B1 using: + // B2 = A2*I +c2+ R*(B1 - A1*I - c1) = A2*I + c2 + h2 + var->B2calc[ndx] = + var->A2[ndx][0] * var->dac[0] + var->A2[ndx][1] * var->dac[1] + + var->A2[ndx][2] * var->dac[2] + var->c2[ndx] + h2[ndx]; + } + + printf("*** in Table mode ***\n"); + printf("DAC (Volts)= \t%.3f\t%.3f\t%.3f\n", var->dac[0], var->dac[1], + var->dac[2]); + printf("B1[0,1,2] Gauss: \t%.3f\t %.3f\t %.3f\n", var->B1[0], + var->B1[1], var->B1[2]); + printf("calc B2[0,1,2] Gauss: \t%.3f\t %.3f\t %.3f\n", var->B2calc[0], + var->B2calc[1], var->B2calc[2]); + printf("set B2[0,1,2] Gauss: \t%.3f\t %.3f\t %.3f\n", var->B2set[0], + var->B2set[1], var->B2set[2]); + printf("meas B2[0,1,2] Gauss: \t%.3f\t %.3f\t %.3f\n", var->B2[0], + var->B2[1], var->B2[2]); + printf("set-meas B2 Gauss: \t%.3f\t %.3f\t %.3f\n", + var->B2set[0] - var->B2[0], var->B2set[1] - var->B2[1], + var->B2set[2] - var->B2[2]); + } + // END debug info +#endif + return; +} + +void NewB2set(HNDLE dummy1, HNDLE dummy2, void *zfc_variables) { + ZFC_VARIABLES *var; + INT size; + + var = (ZFC_VARIABLES *)zfc_variables; + + // save new B2 set values in local variable structure so that it is used + // by other routines + size = sizeof(var->B2set[0]); + db_get_data_index(var->hDB, var->hkeyB2set, (void *)&var->B2set[0], &size, + 0, TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyB2set, (void *)&var->B2set[1], &size, + 1, TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyB2set, (void *)&var->B2set[2], &size, + 2, TID_FLOAT); + +#ifdef MIDEBUG + if (verbose) { + cm_msg(MINFO, "", "New B2 setpoint (G): %f %f %f", var->B2set[0], + var->B2set[1], var->B2set[2]); + cm_msg_flush_buffer(); + } +#endif +} + +void NewMaxDAC(HNDLE dummy1, HNDLE dummy2, void *zfc_variables) { + ZFC_VARIABLES *var; + INT size; + + var = (ZFC_VARIABLES *)zfc_variables; + + // save new MaxDAC set values in local variable structure so that it is used + // by other routines + size = sizeof(var->MaxDAC); + db_get_data(var->hDB, var->hkeyMaxDAC, &var->MaxDAC, &size, TID_FLOAT); + +#ifdef MIDEBUG + if (verbose) { + cm_msg(MINFO, "", "New Maximum DAC Value : %f Volts.", var->MaxDAC); + cm_msg_flush_buffer(); + } +#endif +} + +void NewADC(HNDLE dummy1, HNDLE dummy2, void *zfc_variables) { + ZFC_VARIABLES *var; + static int nCycles = 0; + static float B1mean[3] = {0.0, 0.0, 0.0}; // averaged B1 field after nCycles + int ndx; + INT size; + float dB2[3]; // difference of B2set - B2calc + float dacOld[3]; // old current (in unit of DAC, i.e. Volts) + float temp[3]; // helper variable to store temporatry results; + float h2[3]; // h2 = R*(B1-A1*I-c1) + float tval; + + var = (ZFC_VARIABLES *)zfc_variables; + +#ifdef MIDEBUG + if (debug) + printf("New ADC reading!\n"); +#endif + + // start time (must be larger than 2000 ms) + if (ss_millitime() - var->NewAdcTime < 2000) + return; + + // new start time + var->NewAdcTime = ss_millitime(); + +#ifdef MIDEBUG1 + if (verbose && (var->mode == ZFC_MODE_MANUAL)) { + // get the current DAC value + size = sizeof(var->dac[0]); + for (ndx = 0; ndx < 3; ndx++) { + var->B1[ndx] = var->Probe1CalibrationFactor * var->adc[ndx]; + var->B2[ndx] = var->Probe2CalibrationFactor * var->adc[ndx + 4]; + db_get_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[ndx], + &size, ndx, TID_FLOAT); + // Helper to Calculate field at h2 from B1 using: temp = B1 - A1*I + // -c1 + temp[ndx] = var->B1[ndx] - var->A1[ndx][0] * var->dac[0] - + var->A1[ndx][1] * var->dac[1] - + var->A1[ndx][2] * var->dac[2] - var->c1[ndx]; + } + + for (ndx = 0; ndx < 3; ndx++) { + // Calculate field at h2 from B1 using: h2 = R*(B1 - A1*I - c1) = + // R*temp + h2[ndx] = var->R[ndx][0] * temp[0] + var->R[ndx][1] * temp[1] + + var->R[ndx][2] * temp[2]; + } + + for (ndx = 0; ndx < 3; ndx++) { + // Calculate field at B2 from B1 using: + // B2 = A2*I +c2+ R*(B1 - A1*I - c1) = A2*I + c2 + h2 + var->B2calc[ndx] = + var->A2[ndx][0] * var->dac[0] + var->A2[ndx][1] * var->dac[1] + + var->A2[ndx][2] * var->dac[2] + var->c2[ndx] + h2[ndx]; + } + + printf("newADC but in *** Manual mode ***\n"); + printf("DAC (Volts)= \t%.3f\t%.3f\t%.3f\n", var->dac[0], var->dac[1], + var->dac[2]); + printf("B1[0,1,2] Gauss: \t%.3f\t %.3f\t %.3f\n", var->B1[0], + var->B1[1], var->B1[2]); + printf("calc B2[0,1,2] Gauss: \t%.3f\t %.3f\t %.3f\n", var->B2calc[0], + var->B2calc[1], var->B2calc[2]); + printf("meas B2[0,1,2] Gauss: \t%.3f\t %.3f\t %.3f\n", var->B2[0], + var->B2[1], var->B2[2]); + printf("calc-meas B2 Gauss: \t%.3f\t %.3f\t %.3f\n", + var->B2calc[0] - var->B2[0], var->B2calc[1] - var->B2[1], + var->B2calc[2] - var->B2[2]); + } + // END debug info +#endif + + // if not in active mode return + if (var->mode != ZFC_MODE_ACTIVE) + return; + + // get the current ADC value (to circumvent the piping) + for (ndx = 0; ndx < 3; ndx++) { + size = sizeof(var->adc[ndx]); + db_get_data_index(var->hDB, var->hkeyADC, (void *)&var->adc[ndx], &size, + ndx, TID_FLOAT); + size = sizeof(var->adc[ndx + 4]); + db_get_data_index(var->hDB, var->hkeyADC, (void *)&var->adc[ndx + 4], + &size, ndx + 4, TID_FLOAT); + } + +#ifdef MIDEBUG + if (verbose) + printf("New ADC X1=%.3f, Y1=%.3f, Z1=%.3f, X2=%.3f, Y2=%.3f, Z2=%.3f\n", + var->adc[0], var->adc[1], var->adc[2], var->adc[4], var->adc[5], + var->adc[6]); +#endif + // Calculate actual fields at probe1 and probe2 position + for (ndx = 0; ndx < 3; ndx++) { + var->B1[ndx] = + var->Probe1CalibrationFactor * var->adc[ndx]; // probe 1 (0,1,2) + var->B2[ndx] = + var->Probe2CalibrationFactor * var->adc[ndx + 4]; // probe 2 (4,5,6) + } + + nCycles++; + + for (ndx = 0; ndx < 3; ndx++) { + B1mean[ndx] += var->B1[ndx]; + } + + // The Control Algorithm and output of new DAC values + if (nCycles == var->intCycles) { + for (ndx = 0; ndx < 3; ndx++) { + B1mean[ndx] /= (float)var->intCycles; + + // get the current DAC value + tval = var->dac[ndx]; + size = sizeof(var->dac[0]); + if ((db_get_data_index(var->hDB, var->hkeyDAC, (void *)&tval, &size, + ndx, TID_FLOAT) == DB_SUCCESS) && + !isnan(tval)) + var->dac[ndx] = tval; + else if (isnan(tval)) + printf("ERROR Reading of Output[%d] is NotANumber\n", ndx); + else + printf("ERROR Reading Output[%d] from ODB\n", ndx); + + // store current reading of the DAC value as dacOld[] + dacOld[ndx] = var->dac[ndx]; + } + + for (ndx = 0; ndx < 3; ndx++) { + // Helper to Calculate field at h2 from B1 using: temp = B1 - A1*I + // -c1 + temp[ndx] = var->B1[ndx] - var->A1[ndx][0] * var->dac[0] - + var->A1[ndx][1] * var->dac[1] - + var->A1[ndx][2] * var->dac[2] - var->c1[ndx]; + } + + for (ndx = 0; ndx < 3; ndx++) { + // Calculate field at h2 from B1 using: h2 = R*(B1 - A1*I - c1) = + // R*temp + h2[ndx] = var->R[ndx][0] * temp[0] + var->R[ndx][1] * temp[1] + + var->R[ndx][2] * temp[2]; +#ifdef MIDEBUG1 + printf("R(%d) = %f; R(%d) = %f; R(%d) = %f; \n", ndx * 3 + 0, + var->R[ndx][0], ndx * 3 + 1, var->R[ndx][1], ndx * 3 + 2, + var->R[ndx][2]); +#endif + } + + for (ndx = 0; ndx < 3; ndx++) { + // Calculate field at B2 from B1 using: + // B2 = A2*I +c2+ R*(B1 - A1*I - c1) = A2*I + c2 + h2 + var->B2calc[ndx] = + var->A2[ndx][0] * var->dac[0] + var->A2[ndx][1] * var->dac[1] + + var->A2[ndx][2] * var->dac[2] + var->c2[ndx] + h2[ndx]; + + // difference demand-actual (dB) + dB2[ndx] = var->B2set[ndx] - var->B2calc[ndx]; + } + + for (ndx = 0; ndx < 3; ndx++) { + // I(n+1) = A2-1 * (B2set - B2_calculated(n)) + I(n) + var->dac[ndx] = var->InvResp[ndx][0] * dB2[0] + + var->InvResp[ndx][1] * dB2[1] + + var->InvResp[ndx][2] * dB2[2] + dacOld[ndx]; + + // take the previous value when result is NotANumber + if (isnan(var->dac[ndx])) { + printf("dac[%d] calculated is NotANumber -> taking previous " + "value\n", + ndx); + var->dac[ndx] = dacOld[ndx]; + } + // set new DAC when within limits (otherwise set the limit) + if (var->dac[ndx] < -1.0 * var->MaxDAC) { + printf("dac[%d] calculated value %f is below %f -> taking " + "lower limit \n", + ndx, var->dac[ndx], -1.0 * var->MaxDAC); + var->dac[ndx] = -1.0 * var->MaxDAC; + } + + if (var->dac[ndx] > var->MaxDAC) { + printf("dac[%d] calculated value %f is above %f -> taking " + "upper limit \n", + ndx, var->dac[ndx], var->MaxDAC); + var->dac[ndx] = var->MaxDAC; + } + + printf("Zero_field_compens_ctrl: New dac[%d]: old %f -> %f\n", ndx, + dacOld[ndx], var->dac[ndx]); + + db_set_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[ndx], + sizeof(var->dac[ndx]), ndx, TID_FLOAT); + } + + printf("B1[0,1,2] Gauss: %.3f\t %.3f\t %.3f\n", var->B1[0], var->B1[1], + var->B1[2]); + printf("calculated B2[0,1,2] Gauss: %.3f\t %.3f\t %.3f\n", + var->B2calc[0], var->B2calc[1], var->B2calc[2]); + printf("measured B2[0,1,2] Gauss: %.3f\t %.3f\t %.3f\n", var->B2[0], + var->B2[1], var->B2[2]); + printf("DAC (Volts)= %.3f\t%.3f\t%.3f\n", var->dac[0], var->dac[1], + var->dac[2]); + + // reset the integration variables + nCycles = 0; + for (ndx = 0; ndx < 3; ndx++) { + B1mean[ndx] = 0.0; + } + } + + return; +} + +void NewMODE(HNDLE dummy1, HNDLE dummy2, void *zfc_variables) { + ZFC_VARIABLES *var; + HNDLE dummy; + + var = (ZFC_VARIABLES *)zfc_variables; + + var->mode_changed = ZFC_MODE_NOT_CHANGED; + + switch (var->mode) { + case ZFC_MODE_MANUAL: + cm_msg(MINFO, "", "ZFC mode changed to manual compensation."); + var->mode_changed = ZFC_MODE_CHANGED; + db_set_data(var->hDB, var->hkeyModeChanged, &(var->mode_changed), + sizeof(var->mode_changed), 1, TID_INT); + break; + + case ZFC_MODE_ACTIVE: + cm_msg(MINFO, "", "ZFC mode changed to active compensation."); + var->mode_changed = ZFC_MODE_CHANGED; + db_set_data(var->hDB, var->hkeyModeChanged, &(var->mode_changed), + sizeof(var->mode_changed), 1, TID_INT); + break; + + case ZFC_MODE_TABLE: + cm_msg(MINFO, "", + "ZFC mode changed to compensation with tabulated fields."); + var->mode_changed = ZFC_MODE_CHANGED; + db_set_data(var->hDB, var->hkeyModeChanged, &(var->mode_changed), + sizeof(var->mode_changed), 1, TID_INT); + dummy = 0; + NewStrayFieldStatus(dummy, dummy, var); + break; + + default: + cm_msg(MERROR, "", "Wrong mode variable %d. Only 0,1,2 are accepted.", + var->mode); + var->mode_changed = ZFC_MODE_NOT_CHANGED; + db_set_data(var->hDB, var->hkeyModeChanged, &(var->mode_changed), + sizeof(var->mode_changed), 1, TID_INT); + break; + } + + cm_msg_flush_buffer(); + return; +} + +void MyWait(int wait) { + DWORD start, cour; + + if (wait < 0) + return; + + start = ss_millitime(); + + cour = start; + while (cour - start < (DWORD)wait) { + // do nothing + cour = ss_millitime(); + if (cour < start) + start = cour; // time was reset - wait full time again + if (cour + 100 - start < (DWORD)wait) + ss_sleep(100); + } + + return; +} + +void NewProbeGeometry(HNDLE dummy1, HNDLE dummy2, void *zfc_variables) { + ZFC_VARIABLES *var; + float buffer; + INT ndx, ndy, size; + float detA2; // Determinatnte of the Response matrix + BOOL ok; + + var = (ZFC_VARIABLES *)zfc_variables; + + if (var->probe_geometry == ZFC_PROBE_GEOMETRY_NOT_CALIBRATED) { + cm_msg(MINFO, "", + "Start calibration of magnetic field probe geometry."); + cm_msg_flush_buffer(); + + // Calibrate the probe geometry by setting different currents to the + // coils (I=0,Ix=1,Iy=1,Iz=1) and read back the field values + + // Set MODE to manual + var->mode = ZFC_MODE_MANUAL; + db_set_data(var->hDB, var->hkeyMODE, &var->mode, sizeof(var->mode), 1, + TID_INT); + + // Set all DAC to Zero + buffer = 0.0; + for (ndx = 0; ndx < 3; ndx++) + db_set_data_index(var->hDB, var->hkeyDAC, &buffer, sizeof(buffer), + ndx, TID_FLOAT); + cm_msg(MLOG, "", "Setting DAC[0], DAC[1] and DAC[2] to zero"); + + // wait until all DAC are zero + cm_msg(MLOG, "", "Waiting until readout is zero ..."); + ok = FALSE; + size = sizeof(var->dac[0]); + do { + // get the current DAC value + db_get_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[0], + &size, 0, TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[1], + &size, 1, TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[2], + &size, 2, TID_FLOAT); + if (var->dac[0] == 0.0 && var->dac[1] == 0.0 && + var->dac[2] == 0.0) { + ok = TRUE; + } + } while (!ok); + + // TODO:change this waiting for 30s to get correct readback + cm_msg(MINFO, "", + "Waiting 30s for stability after setting DAC[0], DAC[1] " + "and DAC[2] to zero"); + cm_msg_flush_buffer(); + MyWait(30000); + cm_msg(MINFO, "", "waited 30s"); + cm_msg_flush_buffer(); + + // read background fields (I=0) for probe 1 and 2 + //(here it is in ADC units (Volts) later it will be converted to Gauss) + size = sizeof(var->c1[0]); + // probe 1 (0,1,2) in Volts + db_get_data_index(var->hDB, var->hkeyADC, &var->c1[0], &size, 0, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->c1[1], &size, 1, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->c1[2], &size, 2, + TID_FLOAT); + // probe 2 (4,5,6) in Volts + db_get_data_index(var->hDB, var->hkeyADC, &var->c2[0], &size, 4, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->c2[1], &size, 5, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->c2[2], &size, 6, + TID_FLOAT); + + cm_msg(MINFO, "", "Background (DAC=0):"); + cm_msg(MINFO, "", + "ADC(V): c1[0,1,2]= %f %f %f and c2[0,1,2] = %f %f %f", + var->c1[0], var->c1[1], var->c1[2], var->c2[0], var->c2[1], + var->c2[2]); + + // Set DAC[0] to one + // TODO: make clever algorithm not to reach border of probe ... + cm_msg(MLOG, "", "Setting DAC[0] to 1 V"); + buffer = 1.0; + db_set_data_index(var->hDB, var->hkeyDAC, &buffer, sizeof(buffer), 0, + TID_FLOAT); + + // wait until DAC[0] is one and others zero + cm_msg(MLOG, "", + "Waiting until DAC[0] readout is one and DAC[1] and DAC[2] zero " + "..."); + ok = FALSE; + size = sizeof(var->dac[0]); + do { + // get the current DAC value + db_get_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[0], + &size, 0, TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[1], + &size, 1, TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[2], + &size, 2, TID_FLOAT); + if (var->dac[0] == 1.0 && var->dac[1] == 0.0 && + var->dac[2] == 0.0) { + ok = TRUE; + } + } while (!ok); + + // TODO:change this waiting for 30s to get correct readback + cm_msg(MINFO, "", + "Waiting 30s for stability after setting DAC[0] to 1.0 V, only"); + cm_msg_flush_buffer(); + MyWait(30000); + // cm_msg(MINFO,"","waited 30s"); + // cm_msg_flush_buffer(); + + // determine components of Response matrix for probe1 (A1) and probe2 + // (A2) + size = sizeof(var->A1[0][0]); + // probe 1 in Volt/DAC + db_get_data_index(var->hDB, var->hkeyADC, &var->A1[0][0], &size, 0, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->A1[1][0], &size, 1, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->A1[2][0], &size, 2, + TID_FLOAT); + + var->A1[0][0] -= var->c1[0]; + var->A1[1][0] -= var->c1[1]; + var->A1[2][0] -= var->c1[2]; + + // probe 2 in Volt/DAC + db_get_data_index(var->hDB, var->hkeyADC, &var->A2[0][0], &size, 4, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->A2[1][0], &size, 5, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->A2[2][0], &size, 6, + TID_FLOAT); + + var->A2[0][0] -= var->c2[0]; + var->A2[1][0] -= var->c2[1]; + var->A2[2][0] -= var->c2[2]; + + cm_msg(MLOG, "", "Setting DAC[1] to 1 V and DAC[0] to zero"); + + // Set DAC[0] back to zero + buffer = 0.0; + db_set_data_index(var->hDB, var->hkeyDAC, &buffer, sizeof(buffer), 0, + TID_FLOAT); + + // Set DAC[1] to one + buffer = 1.0; + db_set_data_index(var->hDB, var->hkeyDAC, &buffer, sizeof(buffer), 1, + TID_FLOAT); + + // wait until DAC[1] is one and others zero + cm_msg(MLOG, "", + "Waiting until DAC[1] readout is one and DAC[0] and DAC[2] zero " + "..."); + ok = FALSE; + size = sizeof(var->dac[0]); + do { + // get the current DAC value + db_get_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[0], + &size, 0, TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[1], + &size, 1, TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[2], + &size, 2, TID_FLOAT); + if (var->dac[0] == 0.0 && var->dac[1] == 1.0 && + var->dac[2] == 0.0) { + ok = TRUE; + } + } while (!ok); + + // TODO:change this waiting for 30s to get correct readback + cm_msg(MINFO, "", + "Waiting 30s for stability after setting DAC[1] to 1.0 V, only"); + cm_msg_flush_buffer(); + MyWait(30000); + // cm_msg(MINFO,"","waited 30s"); + // cm_msg_flush_buffer(); + + // determine components of Response matrix for probe1 (A1) and probe2 + // (A2) + size = sizeof(var->A1[0][0]); + + // probe 1 in Volt/DAC + db_get_data_index(var->hDB, var->hkeyADC, &var->A1[0][1], &size, 0, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->A1[1][1], &size, 1, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->A1[2][1], &size, 2, + TID_FLOAT); + + var->A1[0][1] -= var->c1[0]; + var->A1[1][1] -= var->c1[1]; + var->A1[2][1] -= var->c1[2]; + + // probe 2 in Volt/DAC + db_get_data_index(var->hDB, var->hkeyADC, &var->A2[0][1], &size, 4, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->A2[1][1], &size, 5, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->A2[2][1], &size, 6, + TID_FLOAT); + + var->A2[0][1] -= var->c2[0]; + var->A2[1][1] -= var->c2[1]; + var->A2[2][1] -= var->c2[2]; + + cm_msg(MLOG, "", "Setting DAC[2] to 1 V and DAC[1] to zero"); + + // Set DAC[1] back to zero + buffer = 0.0; + db_set_data_index(var->hDB, var->hkeyDAC, &buffer, sizeof(buffer), 1, + TID_FLOAT); + + // Set DAC[2] to one + buffer = 1.0; + db_set_data_index(var->hDB, var->hkeyDAC, &buffer, sizeof(buffer), 2, + TID_FLOAT); + + // wait until DAC[2] is one and others zero + cm_msg(MLOG, "", + "Waiting until DAC[2] readout is one and DAC[0] and DAC[1] zero " + "..."); + ok = FALSE; + size = sizeof(var->dac[0]); + do { + // get the current DAC value + db_get_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[0], + &size, 0, TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[1], + &size, 1, TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyDAC, (void *)&var->dac[2], + &size, 2, TID_FLOAT); + if (var->dac[0] == 0.0 && var->dac[1] == 0.0 && + var->dac[2] == 1.0) { + ok = TRUE; + } + } while (!ok); + + // TODO:change this waiting for 30s to get correct readback + cm_msg(MINFO, "", + "Waiting 30s for stability after setting DAC[2] to 1.0 V, only"); + cm_msg_flush_buffer(); + MyWait(30000); + cm_msg(MINFO, "", "waited 30s"); + cm_msg_flush_buffer(); + + // determine components of Response matrix for probe1 (A1) and probe2 + // (A2) + size = sizeof(var->A1[0][0]); + // probe 1 in Volt/DAC + db_get_data_index(var->hDB, var->hkeyADC, &var->A1[0][2], &size, 0, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->A1[1][2], &size, 1, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->A1[2][2], &size, 2, + TID_FLOAT); + + var->A1[0][2] -= var->c1[0]; + var->A1[1][2] -= var->c1[1]; + var->A1[2][2] -= var->c1[2]; + + // probe 2 in Volt/DAC + db_get_data_index(var->hDB, var->hkeyADC, &var->A2[0][2], &size, 4, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->A2[1][2], &size, 5, + TID_FLOAT); + db_get_data_index(var->hDB, var->hkeyADC, &var->A2[2][2], &size, 6, + TID_FLOAT); + + var->A2[0][2] -= var->c2[0]; + var->A2[1][2] -= var->c2[1]; + var->A2[2][2] -= var->c2[2]; + + // Set DAC[2] back to zero + buffer = 0.0; + db_set_data_index(var->hDB, var->hkeyDAC, &buffer, sizeof(buffer), 2, + TID_FLOAT); + + // Calculate A1, A2, c1, c2 in the correct units + // c1, c2 in Gauss + for (ndx = 0; ndx < 3; ndx++) { + var->c1[ndx] *= var->Probe1CalibrationFactor; + var->c2[ndx] *= var->Probe2CalibrationFactor; + } + // A2, A2 in Gauss/DAC (=Gauss/Volt) + for (ndy = 0; ndy < 3; ndy++) { + for (ndx = 0; ndx < 3; ndx++) { + var->A1[ndy][ndx] *= var->Probe1CalibrationFactor; + var->A2[ndy][ndx] *= var->Probe2CalibrationFactor; + } + } + + cm_msg(MINFO, "", "Background (DAC=0):"); + cm_msg(MINFO, "", "c1, c2 (Gauss): %f %f %f and %f %f %f", + var->c1[0], var->c1[1], var->c1[2], var->c2[0], var->c2[1], + var->c2[2]); + cm_msg_flush_buffer(); + + // Calculate inverse Response Matrix A2-1 + detA2 = var->A2[0][0] * (var->A2[1][1] * var->A2[2][2] - + var->A2[2][1] * var->A2[1][2]) - + var->A2[0][1] * (var->A2[1][0] * var->A2[2][2] - + var->A2[2][0] * var->A2[1][2]) + + var->A2[0][2] * (var->A2[1][0] * var->A2[2][1] - + var->A2[2][0] * var->A2[1][1]); + if (detA2 == 0.0) { + cm_msg(MERROR, "", + "ERROR when calculating Inverse of Responsematrix detM=0 !"); + cm_msg_flush_buffer(); + return; + } + + var->InvResp[0][0] = + (var->A2[1][1] * var->A2[2][2] - var->A2[2][1] * var->A2[1][2]) / + detA2; + var->InvResp[1][0] = + -1.0 * + (var->A2[1][0] * var->A2[2][2] - var->A2[2][0] * var->A2[1][2]) / + detA2; + var->InvResp[2][0] = + (var->A2[1][0] * var->A2[2][1] - var->A2[2][0] * var->A2[1][1]) / + detA2; + + var->InvResp[0][1] = + -1.0 * + (var->A2[0][1] * var->A2[2][2] - var->A2[2][1] * var->A2[0][2]) / + detA2; + var->InvResp[1][1] = + (var->A2[0][0] * var->A2[2][2] - var->A2[2][0] * var->A2[0][2]) / + detA2; + var->InvResp[2][1] = + -1.0 * + (var->A2[0][0] * var->A2[2][1] - var->A2[2][0] * var->A2[0][1]) / + detA2; + + var->InvResp[0][2] = + (var->A2[0][1] * var->A2[1][2] - var->A2[1][1] * var->A2[0][2]) / + detA2; + var->InvResp[1][2] = + -1.0 * + (var->A2[0][0] * var->A2[1][2] - var->A2[1][0] * var->A2[0][2]) / + detA2; + var->InvResp[2][2] = + (var->A2[0][0] * var->A2[1][1] - var->A2[1][0] * var->A2[0][1]) / + detA2; + + // update ODB entry of A1,c1,A2,c2,InvResp + for (ndx = 0; ndx < 3; ndx++) { + db_set_data_index(var->hDB, var->hkeyc1, &var->c1[ndx], + sizeof(var->c1[0]), ndx, TID_FLOAT); + db_set_data_index(var->hDB, var->hkeyc2, &var->c2[ndx], + sizeof(var->c2[0]), ndx, TID_FLOAT); + for (ndy = 0; ndy < 3; ndy++) { + db_set_data_index( + var->hDB, var->hkeyInvResp, &var->InvResp[ndx][ndy], + sizeof(var->InvResp[0][0]), 3 * ndx + ndy, TID_FLOAT); + db_set_data_index(var->hDB, var->hkeyA1, &var->A1[ndx][ndy], + sizeof(var->A1[0][0]), 3 * ndx + ndy, + TID_FLOAT); + db_set_data_index(var->hDB, var->hkeyA2, &var->A2[ndx][ndy], + sizeof(var->A2[0][0]), 3 * ndx + ndy, + TID_FLOAT); + } + } + + // set status flag in ODB for Calibrated Probe Geometrie + var->probe_geometry = ZFC_PROBE_GEOMETRY_CALIBRATED; + db_set_data(var->hDB, var->hkeyProbeGeo, &var->probe_geometry, + sizeof(var->probe_geometry), 1, TID_INT); + cm_msg(MINFO, "", + "Calibration of magnetic field probe geometry ended " + "successfully."); + cm_msg_flush_buffer(); + } + + return; +} + +/*------------------------------------------------------------------*/ + +int print_message(const char *msg) { + printf("%s\n", msg); + + return 0; +} + +// log error message and close connections +int error_disconnect(int reason) { + cm_msg(MERROR, "main", + "Zero_field_compens_ctrl terminated due to a FATAL error"); + cm_msg_flush_buffer(); + cm_disconnect_experiment(); + return reason; +} +/*------------------------------------------------------------------*/ + +int main(int argc, char *argv[]) { + INT status, size, i, daemon_flag; + INT time_start; + ZFC_VARIABLES zfc_variables; + + daemon_flag = 0; + + setbuf(stdout, 0); + setbuf(stderr, 0); + +#ifdef SIGPIPE + signal(SIGPIPE, SIG_IGN); +#endif + + /* parse command line parameters */ + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] == 'd') + debug = TRUE; + else if (argv[i][0] == '-' && argv[i][1] == 'v') + verbose = TRUE; + else if (argv[i][0] == '-' && argv[i][1] == 'D') + daemon_flag = 1; + else { + usage: + printf("usage: Zero_field_compens_ctrl [-d] [-v] [-D] \n"); + printf(" [-d] Used to debug the control program\n"); + printf(" [-v] Verbose\n"); + printf(" [-D] Become a daemon\n"); + } + } + + if (daemon_flag) { + if (debug && verbose) { + printf("\nBecoming a daemon (keeping stdout) ...\n"); + } else { + printf("\nBecoming a daemon...\n"); + debug = verbose = FALSE; + } + ss_daemon_init(debug && verbose); + } + + // initialization of variables + // set number of interaction cycles of ADC values + zfc_variables.intCycles = 1; + + // do not initialize timer to current time in order to allow initial update + // without hotlink + zfc_variables.NewAdcTime = 0; // RA36 15-MAR-2017 was = ss_millitime(); + + // connect to midas experiment on localhost + status = cm_connect_experiment("", TOSTRING(EXPERIMENT), + "Zero_field_compens_ctrl", NULL); + // status = cm_connect_experiment1("", "td_musr2n", + // "Zero_field_compens_ctrl", NULL, + // DEFAULT_ODB_SIZE, DEFAULT_FE_TIMEOUT); + if (status != CM_SUCCESS) { + printf("Could not connect to experiment %s\n", TOSTRING(EXPERIMENT)); + return EXIT_FAILURE; + } + + cm_msg_flush_buffer(); + + /* route local messages through print_message */ + cm_set_msg_print(MT_ALL, MT_ALL, print_message); + + // get handle to odb + status = cm_get_experiment_database(&zfc_variables.hDB, NULL); + if (status != CM_SUCCESS) { + cm_msg(MERROR, "", "Could not get handle to ODB"); + return error_disconnect(EXIT_FAILURE); + } + + // get data from odb + // get handle to ADC key + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Variables/Input", + &zfc_variables.hkeyADC); + if (status != DB_SUCCESS) { + cm_msg( + MERROR, "", + "Zero_field_compens_ctrl error: %d find key Variables/Input (ADC)", + status); + return error_disconnect(EXIT_FAILURE); + } else { + + // read ADC values to private variables + size = sizeof(zfc_variables.adc); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyADC, + &zfc_variables.adc, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg( + MERROR, "", + "Zero_field_compens_ctrl error: %d get Variables/Input (ADC)", + status); + return error_disconnect(EXIT_FAILURE); + } + } + + // get handle to ADC key + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Variables/Output", + &zfc_variables.hkeyDAC); + if (status != DB_SUCCESS) { + cm_msg( + MERROR, "", + "Zero_field_compens_ctrl error: %d find key Variables/Output (DAC)", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read DAC values to private variables + size = sizeof(zfc_variables.dac); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyDAC, + &zfc_variables.dac, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg( + MERROR, "", + "Zero_field_compens_ctrl error: %d get Variables/Output (DAC)", + status); + return error_disconnect(EXIT_FAILURE); + } + } + + // get handle to mode key + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD" + "/Mode (0,1,2)", + &zfc_variables.hkeyMODE); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Mode...", status); + return error_disconnect(EXIT_FAILURE); + } else { + // read mode to private variables + size = sizeof(zfc_variables.mode); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyMODE, + &zfc_variables.mode, &size, TID_INT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Mode...", status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to automatic mode key + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD" + "/Automatic (0,1)", + &zfc_variables.hkeyAUTOMATIC); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Automatic...", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read automatic mode to private variables + size = sizeof(zfc_variables.automatic); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyAUTOMATIC, + &zfc_variables.automatic, &size, TID_INT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Automatic...", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to mode changed key + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/" + "Mode Changed (0,1)", + &zfc_variables.hkeyModeChanged); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Mode Changed...", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read mode changed to private variables + size = sizeof(zfc_variables.mode_changed); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyModeChanged, + &zfc_variables.mode_changed, &size, TID_INT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Mode Changed...", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to maximum DAC value key + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD" + "/Max DAC (V)", + &zfc_variables.hkeyMaxDAC); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Max DAC", status); + return error_disconnect(EXIT_FAILURE); + } else { + // read maximum DAC value to private variables + size = sizeof(zfc_variables.MaxDAC); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyMaxDAC, + &zfc_variables.MaxDAC, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Max DAC", status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to InvResp key (inverse reponse matrix A2-1) + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD" + "/InvResp", + &zfc_variables.hkeyInvResp); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/InvResp", status); + return error_disconnect(EXIT_FAILURE); + } else { + // read inverse response matrix to private variables + size = sizeof(zfc_variables.InvResp); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyInvResp, + &zfc_variables.InvResp, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d get DD/InvResp", status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to A1 (Response Matrix for Probe 1) in Gauss/Volt + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD" + "/Matrix A1", + &zfc_variables.hkeyA1); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Matrix A1", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read A1 matrix to private variables + size = sizeof(zfc_variables.A1); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyA1, + &zfc_variables.A1, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d get DD/Matrix A1", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to c1 key + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD" + "/Offset c1", + &zfc_variables.hkeyc1); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", "Zero_field_compens_ctrl error: %d key DD/Offset c1", + status); + } else { + // read c1 vector to private variables + size = sizeof(zfc_variables.c1); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyc1, + &zfc_variables.c1, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", "Zero_field_compens_ctrl error: %d DD/Offset c1", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to A2 (Response Matrix for Probe 2) in Gauss/Volt + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD" + "/Matrix A2", + &zfc_variables.hkeyA2); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Matrix A2", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read A2 matrix to private variables + size = sizeof(zfc_variables.A2); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyA2, + &zfc_variables.A2, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Matrix A2", + status); + return error_disconnect(EXIT_FAILURE); + } + } + + // get handle to c2 key + status = db_find_key( + zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/Offset c2", + &zfc_variables.hkeyc2); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", "Zero_field_compens_ctrl error: %d key DD/Offset c2", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read c2 vector to private variables + size = sizeof(zfc_variables.c2); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyc2, + &zfc_variables.c2, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Offset c2", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to R (Rotation matrix) + status = db_find_key( + zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/Rotation R", + &zfc_variables.hkeyR); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Rotation R", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read R matrix to private variables + size = sizeof(zfc_variables.R); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyR, + &zfc_variables.R, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Rotation R", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to Probe1 Calibration Factor key + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/" + "Probe1 Calibration Factor", + &zfc_variables.hkeyProbe1Calibration); + if (status != DB_SUCCESS) { + cm_msg( + MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Probe1 Cal.n Factor", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read Probe1 Calibration Factor to private variables + size = sizeof(zfc_variables.Probe1CalibrationFactor); + status = db_get_data( + zfc_variables.hDB, zfc_variables.hkeyProbe1Calibration, + &zfc_variables.Probe1CalibrationFactor, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg( + MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Probe1 Cal.n Factor", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to Probe2 Calibration Factor key + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/" + "Probe2 Calibration Factor", + &zfc_variables.hkeyProbe2Calibration); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Probe2 " + "Calibration Factor", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read Probe2 Calibration Factor to private variables + size = sizeof(zfc_variables.Probe2CalibrationFactor); + status = db_get_data( + zfc_variables.hDB, zfc_variables.hkeyProbe2Calibration, + &zfc_variables.Probe2CalibrationFactor, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Probe2 " + "Calibration Factor", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to probe geometrie (calibration) key + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/" + "Probe Geometry (0,1)", + &zfc_variables.hkeyProbeGeo); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Probe Geometry " + "(0,1)", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read probe geometry to private variables + size = sizeof(zfc_variables.probe_geometry); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyProbeGeo, + &zfc_variables.probe_geometry, &size, TID_INT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Probe Geometry " + "(0,1)", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to Field Setpoint (at Sample position) key + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/" + "Field Setpoint B2set (Gauss)", + &zfc_variables.hkeyB2set); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Field Setpoint " + "B2set " + "(Gauss)", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read Field Setpoint to private variables + size = sizeof(zfc_variables.B2set); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyB2set, + &zfc_variables.B2set, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Field Setpoint " + "B2set (Gauss)", + status); + return error_disconnect(EXIT_FAILURE); + } else { + if ((zfc_variables.B2set[0] != 0.f) || + (zfc_variables.B2set[1] != 0.f) || + (zfc_variables.B2set[2] != 0.f)) { + cm_msg( + MINFO, "", + "*** B2set in " + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD is " + "[%.3f, %.3f, %.3f] ***", + zfc_variables.B2set[0], zfc_variables.B2set[1], + zfc_variables.B2set[2]); + cm_msg_flush_buffer(); + } + } + } + + // get handle to Cobra SC Factor key + status = db_find_key( + zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/Cobra SC Factor", + &zfc_variables.hkeyCobra_SC_factor); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Cobra SC Factor", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read Cobra SC Factor vector to private variables + size = sizeof(zfc_variables.Cobra_SC_factor); + status = + db_get_data(zfc_variables.hDB, zfc_variables.hkeyCobra_SC_factor, + &zfc_variables.Cobra_SC_factor, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Cobra SC Factor", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to Cobra SC Offset key + status = db_find_key( + zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/Cobra SC Offset", + &zfc_variables.hkeyCobra_SC_offset); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Cobra SC Offset", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read Cobra SC Offset vector to private variables + size = sizeof(zfc_variables.Cobra_SC_offset); + status = + db_get_data(zfc_variables.hDB, zfc_variables.hkeyCobra_SC_offset, + &zfc_variables.Cobra_SC_offset, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Cobra SC Offset", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to Cobra NC Factor key + status = db_find_key( + zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/Cobra NC Factor", + &zfc_variables.hkeyCobra_NC_factor); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Cobra NC Factor", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read Cobra NC Factor vector to private variables + size = sizeof(zfc_variables.Cobra_NC_factor); + status = + db_get_data(zfc_variables.hDB, zfc_variables.hkeyCobra_NC_factor, + &zfc_variables.Cobra_NC_factor, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Cobra NC Factor", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to Cobra NC Offset key + status = db_find_key( + zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/Cobra NC Offset", + &zfc_variables.hkeyCobra_NC_offset); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Cobra NC Offset", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read Cobra NC Offset vector to private variables + size = sizeof(zfc_variables.Cobra_NC_offset); + status = + db_get_data(zfc_variables.hDB, zfc_variables.hkeyCobra_NC_offset, + &zfc_variables.Cobra_NC_offset, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Cobra NC Offset", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to Comet 1 Factor key + status = db_find_key( + zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/Comet 1 Factor", + &zfc_variables.hkeyComet1_factor); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Comet 1 Factor", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read Comet 1 Factor vector to private variables + size = sizeof(zfc_variables.Comet1_factor); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyComet1_factor, + &zfc_variables.Comet1_factor, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Comet 1 Factor", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to Comet 1 Offset key + status = db_find_key( + zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/Comet 1 Offset", + &zfc_variables.hkeyComet1_offset); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Comet 1 Offset", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read Comet 1 Offset vector to private variables + size = sizeof(zfc_variables.Comet1_offset); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyComet1_offset, + &zfc_variables.Comet1_offset, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Comet 1 Offset", + status); + return error_disconnect(EXIT_FAILURE); + } + } + + // get handle to Comet 2 Factor key + status = db_find_key( + zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/Comet 2 Factor", + &zfc_variables.hkeyComet2_factor); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Comet 2 Factor", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read Comet 2 Factor vector to private variables + size = sizeof(zfc_variables.Comet2_factor); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyComet2_factor, + &zfc_variables.Comet2_factor, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Comet 2 Factor", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to Comet 2 Offset key + status = db_find_key( + zfc_variables.hDB, 0, + "/Equipment/Zero_field_compens/Settings/Devices/IN/DD/Comet 2 Offset", + &zfc_variables.hkeyComet2_offset); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d find key DD/Comet 2 Offset", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read Comet 2 Offset vector to private variables + size = sizeof(zfc_variables.Comet2_offset); + status = db_get_data(zfc_variables.hDB, zfc_variables.hkeyComet2_offset, + &zfc_variables.Comet2_offset, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d read DD/Comet 2 Offset", + status); + return error_disconnect(EXIT_FAILURE); + } + } + // get handle to Stray Field Status key + status = db_find_key(zfc_variables.hDB, 0, + "/Equipment/stray_field/Variables/Input", + &zfc_variables.hkeyStrayFieldStatus); + if (status != DB_SUCCESS) { + cm_msg( + MERROR, "", + "Zero_field_compens_ctrl error: %d find key /Equipment/stray_field/" + "Variables/Input", + status); + return error_disconnect(EXIT_FAILURE); + } else { + // read Stray Field Status values to private variables + size = sizeof(zfc_variables.StrayFieldStatus); + status = + db_get_data(zfc_variables.hDB, zfc_variables.hkeyStrayFieldStatus, + &zfc_variables.StrayFieldStatus, &size, TID_FLOAT); + if (status != DB_SUCCESS) { + cm_msg( + MERROR, "", + "Zero_field_compens_ctrl error: %d read /Equipment/stray_field/" + "Variables/Input", + status); + return error_disconnect(EXIT_FAILURE); + } + } + + // do initial calculations now to immediately update DAC values on device + NewADC(zfc_variables.hDB, zfc_variables.hkeyADC, (void *)&zfc_variables); + + NewStrayFieldStatus(zfc_variables.hDB, zfc_variables.hkeyStrayFieldStatus, + (void *)&zfc_variables); + + NewMODE(zfc_variables.hDB, zfc_variables.hkeyMODE, (void *)&zfc_variables); + + // hotlinks + // hotlink to odb variable Probe Geometry (0,1) 0=not calibrated, + // 1=calibrated + status = db_open_record(zfc_variables.hDB, zfc_variables.hkeyProbeGeo, + &zfc_variables.probe_geometry, + sizeof(zfc_variables.probe_geometry), MODE_READ, + NewProbeGeometry, (void *)&zfc_variables); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d hotlink Probe Geometry", + status); + goto close_records; + } + + // hotlink to odb variable mode + status = db_open_record(zfc_variables.hDB, zfc_variables.hkeyMODE, + &zfc_variables.mode, sizeof(zfc_variables.mode), + MODE_READ, NewMODE, (void *)&zfc_variables); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", "Zero_field_compens_ctrl error: %d hotlink DD/MODE", + status); + } + + // hotlink to odb variable ADC + status = db_open_record(zfc_variables.hDB, zfc_variables.hkeyADC, + &zfc_variables.adc, sizeof(zfc_variables.adc), + MODE_READ, NewADC, (void *)&zfc_variables); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d hotlink Variables/Input", + status); + goto close_records; + } + + // hotlink to odb variable Field Set Point B2 + status = db_open_record(zfc_variables.hDB, zfc_variables.hkeyB2set, + &zfc_variables.B2set, sizeof(zfc_variables.B2set), + MODE_READ, NewB2set, (void *)&zfc_variables); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d hotlink SetPoint B2", status); + goto close_records; + } + + // hotlink to maximum DAC variable + status = db_open_record(zfc_variables.hDB, zfc_variables.hkeyMaxDAC, + &zfc_variables.MaxDAC, sizeof(zfc_variables.MaxDAC), + MODE_READ, NewMaxDAC, (void *)&zfc_variables); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", "Zero_field_compens_ctrl error: %d hotlink MaxDAC", + status); + goto close_records; + } + + // hotlink to odb variable Stray Field Input + status = db_open_record( + zfc_variables.hDB, zfc_variables.hkeyStrayFieldStatus, + &zfc_variables.StrayFieldStatus, sizeof(zfc_variables.StrayFieldStatus), + MODE_READ, NewStrayFieldStatus, (void *)&zfc_variables); + if (status != DB_SUCCESS) { + cm_msg(MERROR, "", + "Zero_field_compens_ctrl error: %d hotlink StrayFieldInput", + status); + goto close_records; + } + + cm_msg_flush_buffer(); + + time_start = ss_millitime(); + + do { + // to periodically say the odb that this process is alive (feed + // watchdog) + status = cm_yield(100); + // checks for changes of hot link variables and calls their handler + // function + } while (status != RPC_SHUTDOWN && status != SS_ABORT); + + status = DB_SUCCESS; + + // unlink hotlinks +close_records: + db_close_record(zfc_variables.hDB, zfc_variables.hkeyMODE); + db_close_record(zfc_variables.hDB, zfc_variables.hkeyProbeGeo); + db_close_record(zfc_variables.hDB, zfc_variables.hkeyADC); + db_close_record(zfc_variables.hDB, zfc_variables.hkeyB2set); + db_close_record(zfc_variables.hDB, zfc_variables.hkeyMaxDAC); + db_close_record(zfc_variables.hDB, zfc_variables.hkeyStrayFieldStatus); + + if (status != DB_SUCCESS) + return error_disconnect(EXIT_FAILURE); + + cm_msg_flush_buffer(); + + // disconnect from experiment + cm_disconnect_experiment(); + + return EXIT_SUCCESS; +} + +/****************** +TODO: + +- was passiert wenn DAC wert in der datenbank geandert wird waehrend der +regelung (es wir ja auf differenz alter-neuer wert geregelt) + +- neue variablen zum COBRA status: COBRA_Bhall, COBRA_Imain, COBRA_Icomp + +- direct lesen in hotlinkroutine (NewADC), am anfang neu lesen + => kein alter wert auf den man regelt + + +*******************/ diff --git a/frontend/scs900_scfe.cxx b/frontend/scs900_scfe.cxx index 25472d0..653f323 100644 --- a/frontend/scs900_scfe.cxx +++ b/frontend/scs900_scfe.cxx @@ -1,34 +1,46 @@ /********************************************************************\ - Name: scs900_scfe.c - Created by: Andreas Suter + Name: zfc_scfe.c + Created by: Hubertus Luetkens - Contents: Midas frontend to readout the MSCB SCS900 DAC card - - $Log$ - Revision 1.2 2004/11/24 16:31:35 nemu - more elegant solution, which is solving the problem of doubled definitions (midas / mscb) + Contents: Midas frontend to readout the MSCB ZFC DAC card - Revision 1.1 2004/11/11 14:41:52 nemu - first experimental MSCB<->MIDAS slowcontrol modules + Revision 1.3 2017/04/10 07:56:21 raselli + frontend_loop() enabled and cm_client_in_list() and should_exit implemented + + Revision 1.2 2017/03/15 14:53:06 raselli + Adapted zero field compensation programs to Midas 2.1 + + Revision 1.1 2017/01/27 11:53:15 raselli + Original bulk muSR Midas 1.9.5 version + + Revision 1.9 2016/09/13 12:03:31 raselli + Removed unnecessary drivers and libraries. Avoiding interference between OS +versions. + + Revision 1.8 2016/09/09 13:16:25 raselli + Bulk musr 09-SEP-2016 + + Revision 1.2 2005/03/31 11:58:44 l_zfc + minor changes + + Revision 1.1 2005/03/31 10:03:57 l_zfc + initial file \********************************************************************/ #include #include "midas.h" -#include "mfe.h" - #include "class/multi.h" -#include "bus/null.h" - +// #include "device/nulldev.h" #include "device/scs900.h" +// #include "bus/null.h" /*-- Globals -------------------------------------------------------*/ /* The frontend name (client name) as seen by other MIDAS clients */ -const char *frontend_name = "SCS900 SC"; - +const char *frontend_name = FRONTEND_NAME; /* The frontend file name, don't change it */ const char *frontend_file_name = __FILE__; @@ -42,20 +54,12 @@ INT display_period = 1000; INT max_event_size = 10000; /* maximum event size for fragmented events (EQ_FRAGMENTED) */ -INT max_event_size_frag = 5*1024*1024; +INT max_event_size_frag = 5 * 1024 * 1024; /* buffer size to hold events */ -INT event_buffer_size = 10*10000; +INT event_buffer_size = 10 * 10000; -/*-- Equipment list ------------------------------------------------*/ - -/* device driver list */ - -DEVICE_DRIVER scs900_driver[] = { - { "SCS900ADC", scs900_in, 8, null, DF_INPUT}, - { "SCS900DAC", scs900_out, 8, null, DF_OUTPUT}, - { "" } -}; +extern BOOL should_exit; /*! * equipment_common_overwrite: @@ -68,96 +72,71 @@ DEVICE_DRIVER scs900_driver[] = { */ BOOL equipment_common_overwrite = FALSE; -/******************************************************************************* - * Equipment Structure Required by mfe.h - ******************************************************************************/ +/*-- Equipment list ------------------------------------------------*/ + +/* device driver list */ + +DEVICE_DRIVER zfc_driver[] = { + {"IN", scs900_in, 8, NULL, DF_INPUT}, /* MOD RA36 13-SEP-2016 was nulldev */ + {"OUT", scs900_out, 8, NULL, + DF_OUTPUT}, /* MOD RA36 13-SEP-2016 was nulldev */ + {""}}; EQUIPMENT equipment[] = { - {"SCS900", /* equipment name */ + { - 1, 0, /* event ID, trigger mask */ - "SYSTEM", /* event buffer */ - EQ_SLOW, /* equipment type */ - 0, /* event source */ - "FIXED", /* format */ - TRUE, /* enabled */ - RO_RUNNING | - RO_TRANSITIONS, /* read when running and on transitions */ - 10000, /* read every 10 sec */ - 0, /* stop run after this event limit */ - 0, /* number of sub events */ - 1, /* log history every event */ - "", "", "" + FRONTEND_NAME, /* equipment name */ + {93, 0, /* event ID, trigger mask */ + "SYSTEM", /* event buffer */ + EQ_SLOW, /* equipment type */ + 0, /* event source */ + "FIXED", /* format */ + TRUE, /* enabled */ + RO_RUNNING | RO_TRANSITIONS, /* read when running and on transitions */ + 10000, /* read every 10 sec */ + 0, /* stop run after this event limit */ + 0, /* number of sub events */ + 1, /* log history every event */ + "", "", ""}, + cd_multi_read, /* readout routine */ + cd_multi, /* class driver main routine */ + zfc_driver, /* device driver list */ + NULL, /* init string */ }, - cd_multi_read, /* readout routine */ - cd_multi, /* class driver main routine */ - scs900_driver, /* device driver list */ - NULL, /* init string */ - }, - - { "" } -}; - + {""}}; /*-- Dummy routines ------------------------------------------------*/ -INT poll_event(INT source, INT count, BOOL test) {return 1;}; -INT interrupt_configure(INT cmd, INT source, PTYPE adr) {return 1;}; +INT poll_event(INT source, INT count, BOOL test) { return 1; } +INT interrupt_configure(INT cmd, INT source, PTYPE adr) { return 1; } /*-- Frontend Init -------------------------------------------------*/ -INT frontend_init() -{ - // de-register run-transition notifications - cm_deregister_transition(TR_START); - cm_deregister_transition(TR_STOP); - cm_deregister_transition(TR_PAUSE); - cm_deregister_transition(TR_RESUME); - - return CM_SUCCESS; -} +INT frontend_init() { return CM_SUCCESS; } /*-- Frontend Exit -------------------------------------------------*/ -INT frontend_exit() -{ - return CM_SUCCESS; -} +INT frontend_exit() { return CM_SUCCESS; } /*-- Frontend Loop -------------------------------------------------*/ -INT frontend_loop() -{ - return CM_SUCCESS; -} +INT frontend_loop() { return CM_SUCCESS; } /*-- Begin of Run --------------------------------------------------*/ -INT begin_of_run(INT run_number, char *error) -{ - return CM_SUCCESS; -} +INT begin_of_run(INT run_number, char *error) { return CM_SUCCESS; } /*-- End of Run ----------------------------------------------------*/ -INT end_of_run(INT run_number, char *error) -{ - return CM_SUCCESS; -} +INT end_of_run(INT run_number, char *error) { return CM_SUCCESS; } /*-- Pause Run -----------------------------------------------------*/ -INT pause_run(INT run_number, char *error) -{ - return CM_SUCCESS; -} +INT pause_run(INT run_number, char *error) { return CM_SUCCESS; } /*-- Resuem Run ----------------------------------------------------*/ -INT resume_run(INT run_number, char *error) -{ - return CM_SUCCESS; -} +INT resume_run(INT run_number, char *error) { return CM_SUCCESS; } /*------------------------------------------------------------------*/ -- 2.54.0