2792 lines
97 KiB
C++
2792 lines
97 KiB
C++
/********************************************************************\
|
|
|
|
Name: bronkhorst.cxx
|
|
Created by: Andreas Suter 2003/09/12
|
|
Modified by: RA36 to be able to set Helium flow in liter/minutes
|
|
and to have a flow limit.
|
|
This was suggested by SR35.
|
|
|
|
Contents: device driver for Bronkhorst He gas flowcontroller,
|
|
defined as a multi class device.
|
|
|
|
RS232: 38400 baud, 8 data bits, 1 stop bit, no parity bit,
|
|
protocol: no flow control, termination \r\n (CR\LF)
|
|
|
|
device driver: Naming of the input and output channels must be done in
|
|
"../Settings/Names Input" and "../Settings/Names Ouput".
|
|
|
|
The channel names keywords defined in the device driver settings
|
|
key ("../Settings/Device/<Abbreviated Name of Device>in/DD")
|
|
for Input and .../<Abbreviated Name of Device>out/DD for
|
|
Output should not be changed! They are used to assign the
|
|
Bronkhorst command to the Midas channel for commands and queries.
|
|
If more than one Bronkhorst flow controller is being used,
|
|
the prefix may be changed from BH to e.g: BH0 and BH1
|
|
* Input in DD
|
|
[32] BH Flow (l/min)\n\
|
|
[32] BH FlowDAC\n\
|
|
[32] BH Flow_SP (readback l/min)\n\
|
|
[32] BH FlowDAC_SP (readback)\n\
|
|
[32] BH ControlMode (readback)\n\
|
|
[32] BH Temperature (C)\n\
|
|
[32] BH Valve Position (rdbck 0..1)\n\
|
|
* Output in DD
|
|
[32] BH FlowSP\n\
|
|
[32] BH ValvePosSP_TST\n\
|
|
|
|
* without Flow l/min
|
|
[0] BH Flow Measured
|
|
[1] BH Valve Position (rdbck 0..1)
|
|
[2] BH Flow Setpoint (readback)
|
|
[3] BH Control Mode (readback)
|
|
[4] BH Temperature(C)
|
|
|
|
[0] BH Flow Setpoint
|
|
[1] BH Valve Position Setpoint TST
|
|
|
|
"FlowDAC_SP", "Flow_SP", "FlowSP" or "Flow Setpoint" are keywords for
|
|
BH_SETPOINT 9
|
|
"FlowDAC" or "Flow" are keywords for BH_MEASURE 8
|
|
"Temperature" is the keyword for BH_TEMPERATURE 142
|
|
"Valve Position" or "ValvePosSP" BH_VALVEOUT 55
|
|
"ControlMode" or "Control Mode" BH_CNTRLMODE 12
|
|
|
|
Date Name Modification
|
|
-----------------------------------------------------------------
|
|
16-APR-2025 RA36 Modified disconnect/reconnect and added watchdog
|
|
|
|
\********************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#include "midas.h"
|
|
//#include "mfe.h"
|
|
#include "msystem.h"
|
|
#include "math.h" // for rintf
|
|
|
|
#include "bronkhorst_flowmeter.h"
|
|
|
|
#ifndef TCPIP_RECONNECT
|
|
#define TCPIP_RECONNECT
|
|
#endif
|
|
|
|
/*---- when TCPIP_RECONNECT is #defined before tcpip.h is included the tcpip bus driver
|
|
* structure is defined to be able to reset tcp/ip communication --------*/
|
|
#include "bus/tcpip.h"
|
|
|
|
#ifdef HAVE_ETS
|
|
#include "ets_logout.h"
|
|
#endif
|
|
#ifdef HAVE_EDS
|
|
#include "eds_logout.h"
|
|
#endif
|
|
|
|
#ifdef SCW_USED
|
|
#include "lemSCWatchdog.h"
|
|
#endif
|
|
|
|
/*---- extern globals from mfe.c -----------------------------------*/
|
|
|
|
extern INT run_number;
|
|
extern INT run_state;
|
|
|
|
/*---- globals -----------------------------------------------------*/
|
|
|
|
#ifndef SCW_USED // when LEM slow control watchdog is not used
|
|
#define WATCHDOG_USED // disable checking of this front end by watchdog during
|
|
#endif // communication to EL-FLOW or during reconnection attempts
|
|
|
|
//! timeout in (ms) for the communication between pc and bronkhorst
|
|
#define BH_TIME_OUT 2000
|
|
|
|
//! timeout in (sec) between logout terminal server an reconnection trial
|
|
#define BH_RECONNECTION_TIMEOUT 5
|
|
//! maximum number of readback failures before a reconnect will take place
|
|
#define BH_MAX_READBACK_FAILURE 5
|
|
//! maximum number of reconnections before bailing off
|
|
#define BH_MAX_RECONNECTION_FAILURE 5
|
|
|
|
/* --------- to handle error messages ------------------------------*/
|
|
#define BH_MAX_ERROR 10 //!< maximum number of error messages
|
|
#define BH_DELTA_TIME_ERROR 3600 //!< reset error counter after BH_DELTA_TIME_ERROR seconds
|
|
|
|
#define BH_WAIT 500 //!< time (ms) to BH_WAIT between commands
|
|
|
|
#define BH_CMD_ERROR -3 //!< unvalid command error
|
|
#define BH_INIT_ERROR -2 //!< initialize error tag
|
|
#define BH_READ_ERROR -1 //!< read error tag
|
|
|
|
//! sleep time (us) between the telnet commands of the ets_logout
|
|
#define BH_ETS_LOGOUT_SLEEP 10000
|
|
//! sleep time (us) between the telnet commands of the eds_logout
|
|
#define BH_EDS_LOGOUT_SLEEP 10000
|
|
|
|
//#define MIDEBUG // General
|
|
//#define MIDEBUG1 //
|
|
//#define MIDEBUG2 //
|
|
//#define MIDEBUGF1 // function calls
|
|
//#define MIDEBUGF2 // function calls
|
|
//#define MIDEBUGF3 // _in() and _out()
|
|
|
|
/* --------- Bronkhorst stuff --------------------------------------*/
|
|
|
|
/*!
|
|
* bronkhorst <-> midas tags.
|
|
* def's starting with BH_ aren't documented here. For a detailed
|
|
* description of them see the bronkhorst manual 'RS232 INTERFACE
|
|
* with FLOW-BUS protocol' Doc. no.: 9.17.027 D
|
|
*/
|
|
#define BH_SUCCESS 1
|
|
|
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
|
|
|
#define BH_CMD_UNKNOWN 2
|
|
#define BH_COMM_ERR 3
|
|
#define BH_STATUS_ERR 4
|
|
#define BH_DECODE_ERR 5
|
|
#define BH_CMD_PARAM 6
|
|
|
|
// bronkhorst commands See Parameter number (DDE) in Parameter properties table
|
|
#define BH_NO_CMD -1
|
|
#define BH_IDENTSTRNG 1 // R Identification string e.g.: SNM22214346B reply is null terminated string (length = -2)
|
|
#define BH_MEASURE 8 // R Measure (measured value 100% = 32000) named Flow DAC
|
|
#define BH_SETPOINT 9 // RW Setpoint (wanted value 100% = 32000) named Flow DAC SP
|
|
#define BH_SETSLOPE 10
|
|
#define BH_CNTRLMODE 12
|
|
#define BH_POLYCNSTA 13
|
|
#define BH_POLYCNSTB 14
|
|
#define BH_POLYCNSTC 15
|
|
#define BH_POLYCNSTD 16
|
|
#define BH_POLYCNSTE 17
|
|
#define BH_POLYCNSTF 18
|
|
#define BH_POLYCNSTG 19
|
|
#define BH_POLYCNSTH 20
|
|
#define BH_CAPACITY 21
|
|
#define BH_SENSORTYPE 22 // Sensor type e.g.: 3 (3= gas volume)
|
|
#define BH_CAPUNIT 23
|
|
#define BH_FLUIDNR 24
|
|
#define BH_FLUIDNAME 25 // Fluid name e.g.: He
|
|
#define BH_ALARMINFO 28
|
|
#define BH_ALARMMSGTA 33
|
|
#define BH_ALARMMSGNR 34
|
|
#define BH_VALVEOUT 55 // RW Valve output (valve output signal) scaled 0..1
|
|
#define BH_VALVEOFFSET 59 // Valve offset e.g.: 0
|
|
#define BH_IOSTATUS 86 // IOS Status e.g.: 15
|
|
#define BH_DEVICETYPE 90 // Device type e.g.: DMFC
|
|
#define BH_MODELNUM 91 // BHTModel number e.g.: F-111AC-50K-ABD-92-V for 50 l/min Helium
|
|
// F-201CV-10 for 19 l/min Helium
|
|
// F-201CV-5K for 9 l/min Helium
|
|
// 00000000011
|
|
// 12345678901
|
|
#define BH_SERIALNUM 92 // Serial number e.g.: M22214346B
|
|
#define BH_VERSION 105 // Firmware version e.g.: V1.26e
|
|
#define BH_TEMPERATURE 142 // Temperature [degC] e.g.: 22.559591
|
|
#define BH_CALIBVOLLT 145 // Calibrated volume in liter
|
|
#define BH_PRESSURE 143 // Not present? Command not understood
|
|
#define BH_CONTRFEAT 166 // Controller features
|
|
#define BH_PID_KP 167 // PID factor Kp
|
|
#define BH_PID_TI 168 // PID factor Ti
|
|
#define BH_PID_TD 169 // PID factor Td
|
|
#define BH_FLUIDTEMP 181 // Not present? Returns always -10.000000
|
|
// etc, rest still missing
|
|
|
|
// bronkhorst flowbus commands, addresses
|
|
#define BH_STATUSMSG 0
|
|
#define BH_SETPARAM 1
|
|
#define BH_GETPARAM 4
|
|
|
|
#define BH_CHAR 0x00
|
|
#define BH_INTEGER 0x20
|
|
#define BH_LONG 0x40
|
|
#define BH_FLOAT 0x40
|
|
#define BH_STRING 0x60
|
|
|
|
// bronkhorst status and error messages
|
|
#define BH_NOERROR 0x00
|
|
#define BH_PROCESS_CLAIMED 0x01
|
|
#define BH_CMD_ERR 0x02
|
|
#define BH_PROC_ERR 0x03
|
|
// etc, rest still missing
|
|
|
|
// bronkhorst node
|
|
#define BH_NODE 0x80
|
|
|
|
// bronkhorst chained
|
|
#define BH_UNCHAINED 0x00
|
|
#define BH_CHAINED 0x80
|
|
|
|
// bronkhorst max needle valve value = 2^24 - 1
|
|
#define BH_MAX_NEEDLE_VALVE 16777215
|
|
|
|
#define BH_IN_CHANNELS 7 //!< number of input channels
|
|
#define BH_OUT_CHANNELS 2 //!< number of output channels
|
|
|
|
// NOTE: if these lines are commented the driver returns to Flow DAC implementation
|
|
// in addition BH_IN_CHANNELS, BH_IN_SETTINGS structure and const char *bh_in_settings_str =
|
|
// have to be edited to eliminate l/min input channels and settings
|
|
#define bronkhorst_flowmeter_inCHANINDEX 0 //!< index of Flow readout (l/min)
|
|
#define BH_SETPOINT_INCHANINDEX 2 //!< index of Flow Setpoint readout (l/min)
|
|
#define BH_SETPOINT_OUTCHANINDEX 0 //!< index of Flow Setpoint (l/min)
|
|
|
|
#define BH_VALVEPOS_INCHANINDEX 6 //!< index of Valve Position readout 0..1
|
|
#define BH_VALVEPOS_OUTCHANINDEX 1 //!< index of Valve Position setpoint 0..1
|
|
|
|
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
|
|
|
/*!
|
|
* <p> generally it stores internal informations within the DD. In this
|
|
* case this are the names for the ODB describing the <b>in-channels</b>.
|
|
*/
|
|
typedef struct {
|
|
float Flow_lpm_Max;
|
|
float Flow_lpm_Offset;
|
|
float Flow_lpm_to_DAC_Scale;
|
|
INT FlowDAC_Max;
|
|
INT FlowDAC_Offset;
|
|
char SetOutofRangeSetpoint_to_Max;
|
|
char reset_to_defaults;;
|
|
|
|
INT detailed_msg; //!< flag indicating if detailed status/error messages are wanted
|
|
#ifdef HAVE_ETS
|
|
INT ets_in_use; //!< flag indicating if the rs232 terminal server is in use
|
|
#endif
|
|
#ifdef HAVE_EDS
|
|
INT eds_in_use; //!< flag indicating if the rs232 terminal server is in use
|
|
#endif
|
|
#ifdef SCW_USED
|
|
INT scw_in_use; //!< flag indicating if the slowcontrol watchdog shall be used
|
|
#endif
|
|
char name[BH_IN_CHANNELS][32]; //!< input channel names
|
|
} BH_IN_SETTINGS;
|
|
|
|
/*!
|
|
* <p> generally it stores internal informations within the DD. In this
|
|
* case this are the names for the ODB describing the <b>out-channels</b>.
|
|
*/
|
|
typedef struct {
|
|
char name[BH_OUT_CHANNELS][32]; //!< output channel names
|
|
} BH_OUT_SETTINGS;
|
|
|
|
//! initializing string for the BH_IN_SETTINGS structure.
|
|
const char *bh_in_settings_str =
|
|
|
|
#ifdef HAVE_ETS // ----------------------------------------
|
|
|
|
// 1234567890123456789012345678901
|
|
#ifdef SCW_USED
|
|
"Flow lpmin Maximum = FLOAT : 50.0 \n\
|
|
Flow lpmin Offset = FLOAT : 0.0 \n\
|
|
Flow lpmin to DAC Scale = FLOAT : 640.0 \n\
|
|
Flow DAC Maximum = INT : 32000 \n\
|
|
Flow DAC Offset = INT : 0 \n\
|
|
Set out of Range FlowSP to Max = CHAR : N \n\
|
|
Reset to Defaults of Type = CHAR : Y \n\
|
|
Detailed Messages = INT : 0\n\
|
|
ETS_IN_USE = INT : 1\n\
|
|
SCW_IN_USE = INT : 0\n\
|
|
Input = STRING[7]:\n\
|
|
[32] BH Flow (l/min)\n\
|
|
[32] BH FlowDAC\n\
|
|
[32] BH Flow_SP (readback l/min)\n\
|
|
[32] BH FlowDAC_SP (readback)\n\
|
|
[32] BH ControlMode (readback)\n\
|
|
[32] BH Temperature (C)\n\
|
|
[32] BH Valve Position (rdbck 0..1)\n\
|
|
";
|
|
#else
|
|
"Flow lpmin Maximum = FLOAT : 50.0 \n\
|
|
Flow lpmin Offset = FLOAT : 0.0 \n\
|
|
Flow lpmin to DAC Scale = FLOAT : 640.0 \n\
|
|
Flow DAC Maximum = INT : 32000 \n\
|
|
Flow DAC Offset = INT : 0 \n\
|
|
Set out of Range FlowSP to Max = CHAR : N \n\
|
|
Reset to Defaults of Type = CHAR : Y \n\
|
|
Detailed Messages = INT : 0\n\
|
|
Detailed Messages = INT : 0\n\
|
|
ETS_IN_USE = INT : 1\n\
|
|
Input = STRING[7]:\n\
|
|
[32] BH Flow (l/min)\n\
|
|
[32] BH FlowDAC\n\
|
|
[32] BH Flow_SP (readback l/min)\n\
|
|
[32] BH FlowDAC_SP (readback)\n\
|
|
[32] BH ControlMode (readback)\n\
|
|
[32] BH Temperature (C)\n\
|
|
[32] BH Valve Position (rdbck 0..1)\n\
|
|
";
|
|
#endif
|
|
|
|
#elif defined( HAVE_EDS ) //-------------------------------
|
|
|
|
#ifdef SCW_USED
|
|
"Flow lpmin Maximum = FLOAT : 50.0 \n\
|
|
Flow lpmin Offset = FLOAT : 0.0 \n\
|
|
Flow lpmin to DAC Scale = FLOAT : 640.0 \n\
|
|
Flow DAC Maximum = INT : 32000 \n\
|
|
Flow DAC Offset = INT : 0 \n\
|
|
Set out of Range FlowSP to Max = CHAR : N \n\
|
|
Reset to Defaults of Type = CHAR : Y \n\
|
|
Detailed Messages = INT : 0\n\
|
|
Detailed Messages = INT : 0\n\
|
|
EDS_IN_USE = INT : 1\n\
|
|
SCW_IN_USE = INT : 0\n\
|
|
Input = STRING[7]:\n\
|
|
";
|
|
#else
|
|
"Flow lpmin Maximum = FLOAT : 50.0 \n\
|
|
Flow lpmin Offset = FLOAT : 0.0 \n\
|
|
Flow lpmin to DAC Scale = FLOAT : 640.0 \n\
|
|
Flow DAC Maximum = INT : 32000 \n\
|
|
Flow DAC Offset = INT : 0 \n\
|
|
Set out of Range FlowSP to Max = CHAR : N \n\
|
|
Reset to Defaults of Type = CHAR : Y \n\
|
|
Detailed Messages = INT : 0\n\
|
|
Detailed Messages = INT : 0\n\
|
|
EDS_IN_USE = INT : 1\n\
|
|
Input = STRING[7]:\n\
|
|
[32] BH Flow (l/min)\n\
|
|
[32] BH FlowDAC\n\
|
|
[32] BH Flow_SP (readback l/min)\n\
|
|
[32] BH FlowDAC_SP (readback)\n\
|
|
[32] BH ControlMode (readback)\n\
|
|
[32] BH Temperature (C)\n\
|
|
[32] BH Valve Position (rdbck 0..1)\n\
|
|
";
|
|
#endif
|
|
|
|
#else // ---- NOT HAVE_ETS AND NOT HAVE_EDS --------------
|
|
|
|
#ifdef SCW_USED
|
|
"Flow lpmin Maximum = FLOAT : 50.0 \n\
|
|
Flow lpmin Offset = FLOAT : 0.0 \n\
|
|
Flow lpmin to DAC Scale = FLOAT : 640.0 \n\
|
|
Flow DAC Maximum = INT : 32000 \n\
|
|
Flow DAC Offset = INT : 0 \n\
|
|
Set out of Range Flow to Max = CHAR : N \n\
|
|
Reset to Defaults of Type = CHAR : Y \n\
|
|
Detailed Messages = INT : 0\n\
|
|
Detailed Messages = INT : 0\n\
|
|
SCW_IN_USE = INT : 0\n\
|
|
Input = STRING[7]:\n\
|
|
[32] BH Flow (l/min)\n\
|
|
[32] BH FlowDAC\n\
|
|
[32] BH Flow_SP (readback l/min)\n\
|
|
[32] BH FlowDAC_SP (readback)\n\
|
|
[32] BH ControlMode (readback)\n\
|
|
[32] BH Temperature (C)\n\
|
|
[32] BH Valve Position (rdbck 0..1)\n\
|
|
";
|
|
#else
|
|
"Flow lpmin Maximum = FLOAT : 50.0 \n\
|
|
Flow lpmin Offset = FLOAT : 0.0 \n\
|
|
Flow lpmin to DAC Scale = FLOAT : 640.0 \n\
|
|
Flow DAC Maximum = INT : 32000 \n\
|
|
Flow DAC Offset = INT : 0 \n\
|
|
Set out of Range Flow to Max = CHAR : N \n\
|
|
Reset to Defaults of Type = CHAR : Y \n\
|
|
Detailed Messages = INT : 0\n\
|
|
Detailed Messages = INT : 0\n\
|
|
Input = STRING[7]:\n\
|
|
[32] BH Flow (l/min)\n\
|
|
[32] BH FlowDAC\n\
|
|
[32] BH Flow_SP (readback l/min)\n\
|
|
[32] BH FlowDAC_SP (readback)\n\
|
|
[32] BH ControlMode (readback)\n\
|
|
[32] BH Temperature (C)\n\
|
|
[32] BH Valve Position (rdbck 0..1)\n\
|
|
";
|
|
#endif
|
|
#endif // -------------------------------------------------
|
|
|
|
//! initializing string for the BH_OUT_SETTINGS structure.
|
|
// 1234567890123456789012345678901
|
|
#ifdef BH_SETPOINT_OUTCHANINDEX //!< Flow Setpoint (l/min)
|
|
const char *bh_out_settings_str =
|
|
"Output = STRING[2] :\n\
|
|
[32] BH FlowSP\n\
|
|
[32] BH ValvePosSP_TST\n\
|
|
";
|
|
#else
|
|
const char *bh_out_settings_str =
|
|
"Output = STRING[2] :\n\
|
|
[32] BH Flow Setpoint\n\
|
|
[32] BH ValvePosSP_TST\n\
|
|
";
|
|
#endif
|
|
|
|
//! defines the slowcontrol default watchdog info structure
|
|
const char *bh_scw_str =
|
|
"Proc Name = STRING : [32]\n\
|
|
PID = INT : -1\n\
|
|
Log Name = STRING : [64]\n\
|
|
DD Name = STRING : [32] bronkhorst\n\
|
|
Last Updated = DWORD : 0\n\
|
|
Timeout = DWORD : 180\n\
|
|
";
|
|
|
|
/*!
|
|
* <p> This structure contains private variables for the device driver.
|
|
*/
|
|
typedef struct {
|
|
BH_IN_SETTINGS bh_in_settings; //!< internal DD settings for the <b>in-channels</b>
|
|
BH_OUT_SETTINGS bh_out_settings; //!< internal DD settings for the <b>out-channels</b>
|
|
#ifdef SCW_USED
|
|
LEM_SC_WATCHDOG scw; //!< slowcontrol watchdog info structure
|
|
#endif
|
|
HNDLE hkey; //!< ODB key for bus driver info
|
|
INT num_channels_in; //!< number of <b>in-channels</b>
|
|
INT num_channels_out; //!< number of <b>out-channels</b>
|
|
INT (*bd)(INT cmd, ...); //!< bus driver entry function
|
|
void *bd_info; //!< private info of bus driver
|
|
int bd_connected; //!< flag showing if bus driver is connected
|
|
int first_bd_error; //!< flag showing if the bus driver error message
|
|
// is already given
|
|
INT errorcount; //!< error coutner
|
|
INT startup_error; //!< startup error tag; if set, the get and bh_set
|
|
// and bh_get routines wont do anything
|
|
DWORD lasterrtime; //!< timer for error handling
|
|
INT readback_failure; //!< counts the number of readback failures
|
|
float last_valid_value[BH_IN_CHANNELS];//!< stores the last valid value of the Input channel
|
|
float last_set[BH_OUT_CHANNELS]; //!< stores the last valid value of the Output channel
|
|
float last_setval[BH_OUT_CHANNELS]; //!< stores the last valid value of the Output channel
|
|
// sent to the controller
|
|
DWORD last_reconnect; //!< timer for bus driver reconnect error handling
|
|
int reconnection_failures; //!< how often reconnection failed
|
|
INT startup_tag; //!< tag indicating that the DD is starting
|
|
// (see bh_in_init and BH_out_init)
|
|
HNDLE keyOut; //!< HNDLE to /Equipment/<name>/Variables/Output
|
|
HNDLE keyDDin; //!< HNDLE to BHFCin/DD
|
|
char name[NAME_LENGTH]; //!< equipment <name>
|
|
float volume; //!< volume ln/min deduced from BHTModel number
|
|
} BH_INFO;
|
|
|
|
BH_INFO *bh_info; //!< global info structure since port (rs232 or terminal server)
|
|
// can only be initialized once.
|
|
|
|
typedef INT(func_t) (INT cmd, ...);
|
|
|
|
/*---- support routines ------------------------------------------------------------*/
|
|
|
|
INT bh_get(BH_INFO *, INT , float *);
|
|
INT bh_set(BH_INFO *, INT , float );
|
|
INT bh_show_param(BH_INFO *info);
|
|
|
|
float bh_afdiff(float , float);
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
float bh_afdiff(float a, float b) { // return absolute difference of a-b
|
|
float diff;
|
|
|
|
diff = a-b;
|
|
if (diff < 0.0) diff = -diff;
|
|
|
|
return diff;
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
INT fatal_error_message(void) {
|
|
cm_msg(MERROR, "BH", "**** FATAL SET-UP ERROR! FIX ERROR IN DEVICE DRIVER ODB "
|
|
"AND RESTART FRONTEND! ****");
|
|
cm_msg_flush_buffer();
|
|
return CM_SUCCESS;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/*!
|
|
* <p> Remove trailing blanks (and carriage control characters) from char buf </p>
|
|
*/
|
|
INT remove_trailing_blanks(char *buf) {
|
|
INT len;
|
|
|
|
len = 0;
|
|
if (buf) {
|
|
len = strlen(buf);
|
|
while (len > 0) {
|
|
if (isspace(*(buf+len-1))) {
|
|
*(buf+(--len)) = '\0';
|
|
} else
|
|
break;
|
|
}
|
|
}
|
|
return len;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------*/
|
|
/*!
|
|
* <p>decodes for any error messages coming from the bronkhorst flow meter.</p>
|
|
* <p><b>return error tag:</b>
|
|
* - BH_SUCCESS = no error
|
|
* - BH_STATUS_ERR = bronkhost status error
|
|
* </p>
|
|
* \param str return string from the flowmeter
|
|
* \param error_msg error message return string (if error), otherwise empty string.
|
|
*/
|
|
int bh_success(char *str, char *error_msg)
|
|
{
|
|
int error = 0;
|
|
int error_byte = 0;
|
|
|
|
#ifdef MIDEBUGF2
|
|
cm_msg(MLOG,"",">>bh_success(%s)", str);
|
|
#endif
|
|
strcpy(error_msg, ""); // initialize error message
|
|
|
|
// data link error message HOST -> PC ":01<error code>"
|
|
if (strncmp(str, ":01",3)==0) {
|
|
|
|
if (sscanf(str, ":01%02d", &error) == 1) {
|
|
switch (error) {
|
|
case 1: // ":0101"
|
|
#ifdef OLDMBC
|
|
strcpy(error_msg, "BH ERROR :0101 no ':' at the start of the message.");
|
|
#else
|
|
strcpy(error_msg, "BH ERROR :0101 general error.");
|
|
#endif
|
|
break;
|
|
case 2: // ":0102"
|
|
#ifdef OLDMBC
|
|
strcpy(error_msg, "BH ERROR :0102 error in 1st byte.");
|
|
#else
|
|
strcpy(error_msg, "BH ERROR :0102 general error.");
|
|
#endif
|
|
break;
|
|
case 3: // ":0103"
|
|
#ifdef OLDMBC
|
|
strcpy(error_msg, "BH ERROR :0103 error in 2nd byte or number of bytes is 0 "
|
|
"or message too long.");
|
|
#else
|
|
strcpy(error_msg, "BH ERROR :0103 propar protocol error.");
|
|
#endif
|
|
break;
|
|
case 4: // ":0104"
|
|
#ifdef OLDMBC
|
|
strcpy(error_msg, "BH ERROR :0104 error in received message (receiver overrun"
|
|
", framing error, etc.).");
|
|
#else
|
|
strcpy(error_msg, "BH ERROR :0104 propar protocol error (or CRC error).");
|
|
#endif
|
|
break;
|
|
case 5: // ":0105"
|
|
#ifdef OLDMBC
|
|
strcpy(error_msg, "BH ERROR :0105 flowbus communication BH ERROR: timeout or "
|
|
"message rejected by receiver.");
|
|
#else
|
|
strcpy(error_msg, "BH ERROR :0105 general error.");
|
|
#endif
|
|
break;
|
|
case 8:
|
|
#ifdef OLDMBC
|
|
strcpy(error_msg, "BH ERROR :0108 timeout during sending.");
|
|
#else
|
|
strcpy(error_msg, "BH ERROR :0108 general error.");
|
|
#endif
|
|
break;
|
|
case 9:
|
|
#ifdef OLDMBC
|
|
strcpy(error_msg, "BH ERROR :0109 no answer received within timeout.");
|
|
#else
|
|
strcpy(error_msg, "BH ERROR :0109 reponse message timeout.");
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
snprintf(error_msg, 128, "BH ERROR :01%2.2d unknown error, obscure.", error);
|
|
break;
|
|
} // end switch
|
|
|
|
} else {
|
|
snprintf(error_msg, 128, "BH ERROR \"%s\" may not be read by sscanf()", str);
|
|
} // end if (sscanf())
|
|
|
|
} else if (strncmp(str, ":04", 3) == 0) { // status error messages
|
|
|
|
// :048000<error><error_byte>
|
|
// : and 04 (message length) 80 (default node 80hex = 128 dec) 00 (Command status)
|
|
if (sscanf(str, ":048000%02d%02d", &error, &error_byte) == 2) {
|
|
switch (error) {
|
|
|
|
case 0x00: // 00 : No error
|
|
break;
|
|
|
|
case 0x01:
|
|
sprintf(error_msg, "BH ERROR 01 : Process claimed. Claimed process = %x",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x02:
|
|
sprintf(error_msg, "BH ERROR 02 : Command error. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x03:
|
|
sprintf(error_msg, "BH ERROR 03 : Process error. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x04:
|
|
sprintf(error_msg, "BH ERROR 04 : Parameter error. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x05:
|
|
sprintf(error_msg, "BH ERROR 05 : Parameter type error. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x06:
|
|
sprintf(error_msg, "BH ERROR 06 : Parameter value error. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x07:
|
|
sprintf(error_msg, "BH ERROR 07 : Network not active. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x08:
|
|
sprintf(error_msg, "BH ERROR 08 : Time-out start character. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x09:
|
|
sprintf(error_msg, "BH ERROR 09 : Time-out serial line. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x0A:
|
|
sprintf(error_msg, "BH ERROR 0A : Hardware memory error. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x0B:
|
|
sprintf(error_msg, "BH ERROR 0B : Node number error. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x0C:
|
|
sprintf(error_msg, "BH ERROR 0C : General communication error. "
|
|
"Error_byte = %d", error_byte);
|
|
break;
|
|
|
|
case 0x0D:
|
|
sprintf(error_msg, "BH ERROR 0D : Read only parameter. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x0E:
|
|
sprintf(error_msg, "BH ERROR 0E : Error PC-communication. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x0F:
|
|
sprintf(error_msg, "BH ERROR 0F : No RS232 connection. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x10:
|
|
sprintf(error_msg, "BH ERROR 10 : PC out of memory. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x11:
|
|
sprintf(error_msg, "BH ERROR 11 : Write only parameter. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x12:
|
|
sprintf(error_msg, "BH ERROR 12 : System configuration unknown. "
|
|
"Error_byte = %d", error_byte);
|
|
break;
|
|
|
|
case 0x13:
|
|
sprintf(error_msg, "BH ERROR 13 : No free node address. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x14:
|
|
sprintf(error_msg, "BH ERROR 14 : Wrong interface type. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x15:
|
|
sprintf(error_msg, "BH ERROR 15 : Error serial port connection. "
|
|
"Error_byte = %d", error_byte);
|
|
break;
|
|
|
|
case 0x16:
|
|
sprintf(error_msg, "BH ERROR 16 : Error opening communication. "
|
|
"Error_byte = %d", error_byte);
|
|
break;
|
|
|
|
case 0x17:
|
|
sprintf(error_msg, "BH ERROR 17 : Communication error. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x18:
|
|
sprintf(error_msg, "BH ERROR 18 : Error interface bus master. "
|
|
"Error_byte = %d", error_byte);
|
|
break;
|
|
|
|
case 0x19:
|
|
sprintf(error_msg, "BH ERROR 19 : Timeout answer. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x1A:
|
|
sprintf(error_msg, "BH ERROR 1A : No start character. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x1B:
|
|
sprintf(error_msg, "BH ERROR 1B : Error first digit. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x1C:
|
|
sprintf(error_msg, "BH ERROR 1C : Buffer overflow in host. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x1D:
|
|
sprintf(error_msg, "BH ERROR 1D : Buffer overflow. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x1E:
|
|
sprintf(error_msg, "BH ERROR 1E : No answer found. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x1F:
|
|
sprintf(error_msg, "BH ERROR 1F : Error closing communication. "
|
|
"Error_byte = %d", error_byte);
|
|
break;
|
|
|
|
case 0x20:
|
|
sprintf(error_msg, "BH ERROR 20 : Synchronization error. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x21:
|
|
sprintf(error_msg, "BH ERROR 21 : Send error. Error_byte = %d", error_byte);
|
|
break;
|
|
|
|
case 0x22:
|
|
sprintf(error_msg, "BH ERROR 22 : Protocol error. Error_byte = %d",
|
|
error_byte);
|
|
break;
|
|
|
|
case 0x23:
|
|
sprintf(error_msg, "BH ERROR 23 : Buffer overflow in module. "
|
|
"Error_byte = %d", error_byte);
|
|
break;
|
|
|
|
default:
|
|
sprintf(error_msg, "BH ERROR: Unknown error %2.2d, obscure. "
|
|
"Error_byte = %d", error, error_byte);
|
|
break;
|
|
} // end switch
|
|
|
|
} else {
|
|
snprintf(error_msg, 128, "BH ERROR \"%s\" may not be read by sscanf()", str);
|
|
} // end if (sscanf())
|
|
|
|
} // end if
|
|
|
|
if (strlen(error_msg)>0) {
|
|
#ifdef MIDEBUGF2
|
|
cm_msg(MLOG,"","<<bh_success(ERROR %s)", error_msg);
|
|
#endif
|
|
return BH_STATUS_ERR;
|
|
} else {
|
|
return BH_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------*/
|
|
/*!
|
|
* converts a hex string into a readable ascii string.
|
|
*
|
|
* \param str hex input string
|
|
* \param len length of 'str'
|
|
* \param result converted ascii string
|
|
*/
|
|
void hex2ascii(char *str, int len, char *result)
|
|
{
|
|
int i, j;
|
|
char hexchar[3];
|
|
|
|
strcpy(result, "");
|
|
for (i=0; i<len; i++) {
|
|
strncpy(hexchar, str+2*i, 2);
|
|
hexchar[2]='\0';
|
|
sscanf(hexchar, "%x", &j);
|
|
strcat(result, (const char *)&j);
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------------*/
|
|
/*!
|
|
* <p> if the return message of the flowcontroller is a number, this routine
|
|
* is used to decode the return string into a number.</p>
|
|
* <p><b>Return:</b>
|
|
* - BH_SUCCESS if everthing went fine
|
|
* - BH_DECODE_ERR otherwise
|
|
* </p>
|
|
* \param rply return string from flowcontroller
|
|
* \param decode_tag BH_CHAR, BH_INTEGER, BH_FLOAT, BH_LONG
|
|
* \param err_msg error message if something went wrong
|
|
* \param result decoded value
|
|
*/
|
|
int bh_decode_number(char *rply, int decode_tag, char *err_msg, float *result)
|
|
{
|
|
int totlen, len;
|
|
int ivalue;
|
|
char str[128];
|
|
union {
|
|
int ival;
|
|
float fval;
|
|
} hexfloat;
|
|
|
|
totlen = strlen(rply);
|
|
if (totlen == 0) { // no input string
|
|
strcpy(err_msg, "BH ERROR: no string to decode ...");
|
|
return BH_DECODE_ERR; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
switch (decode_tag) {
|
|
case BH_CHAR:
|
|
case BH_INTEGER:
|
|
sscanf(rply, ":%02x%s", &len, str);
|
|
if (totlen != 2*len+5) {
|
|
strcpy(err_msg, "BH ERROR: wrong string length ...");
|
|
return BH_DECODE_ERR; // ----->>>>>>>>>>>>>!
|
|
}
|
|
sscanf(rply, ":%10x%x", &len, &ivalue);
|
|
*result = (float)ivalue;
|
|
break;
|
|
case BH_FLOAT:
|
|
/* case BH_LONG: // identical value as BH_FLOAT therefore omitted */
|
|
sscanf(rply, ":%02x%s", &len, str);
|
|
if (totlen != 2*len+5) {
|
|
strcpy(err_msg, "BH ERROR: wrong string length ...");
|
|
return BH_DECODE_ERR; // ----->>>>>>>>>>>>>!
|
|
}
|
|
sscanf(rply, ":%10x%x", &len, &(hexfloat.ival));
|
|
*result = hexfloat.fval;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return BH_SUCCESS;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------*/
|
|
/*!
|
|
* <p>if the return message of the flowcontroller is a string, this routine
|
|
* is used to decode the return string.</p>
|
|
* <p><b>Return:</b>
|
|
* - BH_SUCCESS if everthing went fine
|
|
* - BH_DECODE_ERR otherwise
|
|
* </p>
|
|
* \param rply return string from flowcontroller to be decoded
|
|
* \param err_msg error message if something went wrong
|
|
* \param result decoded message
|
|
*/
|
|
int bh_decode_string(char *rply, char *err_msg, char *result)
|
|
{
|
|
int totlen, len;
|
|
int ivalue;
|
|
char str[128];
|
|
|
|
totlen = strlen(rply);
|
|
if (totlen == 0) { // no string to decode
|
|
strcpy(err_msg, "BH ERROR: no string to decode ...");
|
|
return BH_DECODE_ERR; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
sscanf(rply, ":%02x%s", &len, str);
|
|
if (totlen != 2*len+5) {
|
|
strcpy(err_msg, "BH ERROR: wrong string length ...");
|
|
return BH_DECODE_ERR; // ----->>>>>>>>>>>>>!
|
|
}
|
|
sscanf(rply, ":%10x%02x%s", &ivalue, &len, str);
|
|
hex2ascii(str, len, result);
|
|
|
|
return BH_SUCCESS;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------*/
|
|
/*!
|
|
* <p>routine which is used to read back values from the flowcontroller.</p>
|
|
* <p><b>Return:</b>
|
|
* - BH_SUCCESS if everything went fine
|
|
* - BH_COMM_ERR, BH_CMD_UNKNOWN or BH_CMD_PARAM otherwise
|
|
* \param info info structure used by BD_PUTS and BD_GETS macros
|
|
* \param cmd command tag telling which value to read back from the flowcontroller.
|
|
* \param result return string from the flowcontroller.
|
|
*/
|
|
INT bh_get_send_rcv(BH_INFO *info, INT cmd, char *result)
|
|
{
|
|
char str[128], err_msg[128], send[128];
|
|
int status;
|
|
int cmd_length, process, parameter, decode_tag, str_length;
|
|
#ifdef WATCHDOG_USED
|
|
BOOL wflag;
|
|
DWORD wtimeout;
|
|
#endif
|
|
|
|
status = -1;
|
|
|
|
// RA36 10-JUL-2023 init receive buffer
|
|
if (result != NULL) *result = '\0';
|
|
|
|
if ((info == NULL) || (info->bd_info == NULL)) {
|
|
#ifdef MIDEBUG1
|
|
cm_msg(MLOG, "", "bh_get_send_rcv((NULL pointer to BusDriver info) Returning -1");
|
|
cm_msg_flush_buffer();
|
|
#endif
|
|
return BH_COMM_ERR; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"",">>bh_get_send_rcv(cmd=%d)", cmd);
|
|
#endif
|
|
|
|
cmd_length = 6; // default for requests except when returning strings
|
|
process = 0; parameter = 0; decode_tag = -1; str_length = 0;
|
|
|
|
// filter command and prepare command string for device
|
|
switch (cmd) {
|
|
|
|
case BH_IDENTSTRNG:// 1 = Identification string (process 0, parameter 0)
|
|
// 12 char string returned
|
|
// reply is a null terminated string (length = -2) max. length is unknown. 30 is the length which does not return error 17.
|
|
cmd_length = 7; process = 0; parameter = 0; decode_tag = BH_STRING; str_length = 30; // was 12 (-2) Null terminated
|
|
break;
|
|
|
|
case BH_MEASURE: // 8 = Measure (process <> 0?, parameter 0)
|
|
// integer (2 byte int) returned according to manual 32000 is 100%
|
|
process = 1; parameter = 0; decode_tag = BH_INTEGER;
|
|
break;
|
|
|
|
case BH_SETPOINT: // 9 = Setpoint (process <> 0?, parameter 1)
|
|
// long(4 byte int) returned according to manual 32000 is 100%
|
|
process = 1; parameter = 1; decode_tag = BH_INTEGER;
|
|
break;
|
|
|
|
case BH_CNTRLMODE: // 12 = Controlmode (process <> 0?, parameter 4) 1 byte returned
|
|
process = 1; parameter = 4; decode_tag = BH_CHAR;
|
|
break;
|
|
|
|
case BH_SENSORTYPE: // 22
|
|
process = 1; parameter = 14; decode_tag = BH_CHAR;
|
|
break;
|
|
|
|
case BH_FLUIDNAME: // 25
|
|
cmd_length = 7; process = 1; parameter = 17; decode_tag = BH_STRING; str_length = 10;
|
|
break;
|
|
|
|
case BH_VALVEOUT: // 55 = Valve output (process 114, parameter 1)
|
|
// according to manual valve output signal is a 24-bit number
|
|
// in the range 0..14.3Vdc/0..23.3Vdc
|
|
process = 114; parameter = 1; decode_tag = BH_LONG;
|
|
break;
|
|
|
|
case BH_VALVEOFFSET: // 59
|
|
process = 116; parameter = 7; decode_tag = BH_INTEGER;
|
|
break;
|
|
|
|
case BH_IOSTATUS: // 86 = IO status (process 114, parameter 11) 1 byte returned
|
|
process = 114; parameter = 11; decode_tag = BH_CHAR;
|
|
break;
|
|
|
|
case BH_DEVICETYPE: // 90
|
|
cmd_length=7; process = 113; parameter = 1; decode_tag = BH_STRING; str_length = 6;
|
|
break;
|
|
|
|
case BH_MODELNUM: // 91
|
|
// reply is a null terminated string (length = -2) max. length is unknown. 30 is the length which does not return error 17.
|
|
cmd_length=7; process = 113; parameter = 2; decode_tag = BH_STRING; str_length = 30; // was 10 (-2) Null terminated
|
|
break;
|
|
|
|
case BH_SERIALNUM: // 92
|
|
// reply is a null terminated string (length = -2) max. length is unknown. 30 is the length which does not return error 17.
|
|
cmd_length=7; process = 113; parameter = 3; decode_tag = BH_STRING; str_length = 30; // was 10 (-2) Null terminated
|
|
break;
|
|
|
|
case BH_VERSION: // 105
|
|
cmd_length=7; process = 113; parameter = 5; decode_tag = BH_STRING; str_length = 6;
|
|
break;
|
|
|
|
case BH_TEMPERATURE: // 142
|
|
process = 33; parameter = 7; decode_tag = BH_FLOAT;
|
|
break;
|
|
|
|
case BH_CALIBVOLLT: // 145
|
|
process = 33; parameter = 10; decode_tag = BH_FLOAT;
|
|
break;
|
|
|
|
case BH_PRESSURE: // 143
|
|
process = 33; parameter = 8; decode_tag = BH_FLOAT;
|
|
break;
|
|
|
|
case BH_CONTRFEAT: // 166
|
|
process = 114; parameter = 20; decode_tag = BH_CHAR;
|
|
break;
|
|
|
|
case BH_PID_KP: // 167
|
|
process = 114; parameter = 21; decode_tag = BH_FLOAT;
|
|
break;
|
|
|
|
case BH_PID_TI: // 168
|
|
process = 114; parameter = 22; decode_tag = BH_FLOAT;
|
|
break;
|
|
|
|
case BH_PID_TD: // 169
|
|
process = 114; parameter = 23; decode_tag = BH_FLOAT;
|
|
break;
|
|
|
|
case BH_FLUIDTEMP: // 181
|
|
process = 113; parameter = 16; decode_tag = BH_FLOAT;
|
|
break;
|
|
|
|
default:
|
|
cm_msg(MLOG,"","bh_get_send_rcv() Unknown command %d", cmd);
|
|
return BH_CMD_UNKNOWN; // ----->>>>>>>>>>>>>!
|
|
break;
|
|
}
|
|
|
|
#ifdef MIDEBUG2
|
|
cm_msg(MLOG,"","cmd_length=%d, process=%d, decode_tag=%d, parameter=%d, str_length=%d",
|
|
cmd_length, process, decode_tag, parameter, str_length);
|
|
#endif
|
|
|
|
// generate command for string request
|
|
if (decode_tag == BH_STRING) {
|
|
|
|
if ((cmd_length == 7) && (str_length > 0)) {
|
|
// for BH_IDENSTRING :078004006000600C
|
|
// : 07 80 04 00 60 00 60 0C
|
|
sprintf(str, ":%02X%02X%02X%02X%02X%02X%02X%02X",
|
|
cmd_length, BH_NODE, BH_GETPARAM, BH_UNCHAINED|process,
|
|
BH_UNCHAINED|decode_tag, process, decode_tag|parameter, str_length);
|
|
} else {
|
|
if (cmd_length != 7)
|
|
cm_msg(MLOG,"","bh_get_send_rcv() Command %d : Unexpected cmd_length %d "
|
|
"instead of 7 for string", cmd, cmd_length);
|
|
if (str_length <= 0)
|
|
cm_msg(MLOG,"","bh_get_send_rcv() Command %d : str_length %d to return "
|
|
"string <= 0", cmd, str_length);
|
|
return BH_CMD_PARAM; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
// generate command for all other requests
|
|
} else if (cmd_length == 6) {
|
|
|
|
if (decode_tag >= 0) {
|
|
sprintf(str, ":%02X%02X%02X%02X%02X%02X%02X",
|
|
cmd_length, BH_NODE, BH_GETPARAM, BH_UNCHAINED|process,
|
|
BH_UNCHAINED|decode_tag, process, decode_tag|parameter);
|
|
} else {
|
|
cm_msg(MLOG,"","bh_get_send_rcv() Command %d : Unexpected or undefined (= -1) decode_tag %d", cmd,
|
|
decode_tag);
|
|
return BH_CMD_PARAM; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
} else {
|
|
cm_msg(MLOG,"","bh_get_send_rcv() Command %d : Unexpected cmd_length %d", cmd,
|
|
cmd_length);
|
|
return BH_CMD_PARAM; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
strcpy(send,str);
|
|
|
|
#ifdef MIDEBUG2
|
|
cm_msg(MLOG, "", "Command to query is _%s_", str);
|
|
#endif
|
|
|
|
// append carriage return at the end
|
|
strcat(str,"\r\n");
|
|
|
|
#ifdef WATCHDOG_USED
|
|
cm_get_watchdog_params(&wflag, &wtimeout); // remember watchdog parameters
|
|
cm_set_watchdog_params(FALSE,0); // disable watchdog while
|
|
// accessing device to learn how to handle network problems
|
|
#endif
|
|
|
|
// send command to device
|
|
BD_PUTS(str);
|
|
// read back response from device
|
|
str[0] = '\0';
|
|
status = BD_GETS(str, sizeof(str), "\r\n", BH_TIME_OUT);
|
|
strcpy(result, str); // cr/lf should be returned
|
|
remove_trailing_blanks(str); // remove space (cr,lf) for cm_msg, only
|
|
|
|
|
|
#ifdef WATCHDOG_USED
|
|
cm_set_watchdog_params(wflag, wtimeout); // restore watchdog parameters
|
|
#endif
|
|
|
|
if (status <= 0) { // no response or no connection
|
|
if ( info->errorcount < BH_MAX_ERROR ) {
|
|
if (info->bh_in_settings.detailed_msg)
|
|
cm_msg(MERROR, "bh_get_send_rcv", "Communication error with bronkhorst "
|
|
"flowcontroller.");
|
|
info->errorcount++;
|
|
}
|
|
return BH_COMM_ERR; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
// check for errors
|
|
if (bh_success(str, err_msg) != BH_SUCCESS) {
|
|
if ( info->errorcount < BH_MAX_ERROR ) {
|
|
if (info->bh_in_settings.detailed_msg) {
|
|
cm_msg(MLOG,"","Send: \"%s\", Answer: \"%s\"", send, str);
|
|
cm_msg(MERROR, "bh_get_send_rcv", "cmd=%d : %s", cmd, err_msg);
|
|
}
|
|
info->errorcount++;
|
|
}
|
|
return BH_COMM_ERR; // ----->>>>>>>>>>>>>!
|
|
#ifdef MIDEBUGF1
|
|
} else {
|
|
cm_msg(MINFO, "", "<<bh_get_send_rcv() Reply of query %s is %s", send, str);
|
|
#endif
|
|
}
|
|
|
|
return BH_SUCCESS;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------*/
|
|
/*!
|
|
* <p>routine which is used to set values of the flowcontroller.</p>
|
|
* <p><b>Return:</b>
|
|
* - BH_SUCCESS if everthing went fine
|
|
* - BH_COMM_ERR if there was a communication problem
|
|
* - BH_CMD_UNKNOWN if the command is unkown
|
|
* \param info info structure used by BD_PUTS and BD_GETS macros
|
|
* \param cmd command tag telling which value to read back from the flowcontroller.
|
|
* \param value value to be set
|
|
*/
|
|
INT bh_set_send_rcv(BH_INFO *info, INT cmd, float value)
|
|
{
|
|
char str[128], err_msg[128];
|
|
int status;
|
|
int cmd_length, process, parameter, decode_tag;
|
|
#ifdef WATCHDOG_USED
|
|
BOOL wflag;
|
|
DWORD wtimeout;
|
|
#endif
|
|
|
|
status = -1;
|
|
|
|
if ((info == NULL) || (info->bd_info == NULL)) {
|
|
#ifdef MIDEBUG1
|
|
cm_msg(MLOG, "", "bh_set_send_rcv((NULL pointer to BusDriver info) Returning -1");
|
|
cm_msg_flush_buffer();
|
|
#endif
|
|
return BH_COMM_ERR; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"",">>bh_set_send_rcv(cmd=%d, value=%f)", cmd, value);
|
|
#endif
|
|
|
|
decode_tag = 0;
|
|
|
|
// filter command and generate command string for device
|
|
switch (cmd) {
|
|
|
|
case BH_SETPOINT: // 9
|
|
if ((value >= 0) && (value <= 32767)) { // if value < 0 or > 32767 do nothing!!
|
|
cmd_length = 6;
|
|
process = 1;
|
|
parameter = 1;
|
|
decode_tag = BH_INTEGER;
|
|
sprintf(str, ":%02X%02X%02X%02X%02X%04X\r\n",
|
|
cmd_length, BH_NODE, BH_SETPARAM, BH_UNCHAINED|process,
|
|
BH_UNCHAINED|decode_tag|parameter, (int)value);
|
|
} else {
|
|
// NIY if out of range value was not set before -> write message
|
|
cm_msg(MLOG,"","Flow Setpoint NOT SET! Value %d to be set is out of range | 0 - 32767 |",
|
|
(int)value);
|
|
return BH_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
break;
|
|
|
|
case BH_VALVEOUT: // 55
|
|
if ((value >= 0.f) && (value <= 1.f)) { // if value < 0 or > 1 do nothing!!
|
|
cmd_length = 8;
|
|
process = 114;
|
|
parameter = 1;
|
|
decode_tag = BH_LONG;
|
|
sprintf(str, ":%02X%02X%02X%02X%02X%08X\r\n",
|
|
cmd_length, BH_NODE, BH_SETPARAM, BH_UNCHAINED|process,
|
|
BH_UNCHAINED|BH_LONG|parameter, (int)(value*BH_MAX_NEEDLE_VALVE));
|
|
} else {
|
|
// NIY if out of range value was not set before -> write message
|
|
cm_msg(MLOG,"","Valve Position Setpoint: Value %.3f to be set is out of range | 0 - 1 |", value);
|
|
return BH_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return BH_CMD_UNKNOWN; // ----->>>>>>>>>>>>>!
|
|
break;
|
|
}
|
|
|
|
#ifdef WATCHDOG_USED
|
|
cm_get_watchdog_params(&wflag, &wtimeout); // remember watchdog parameters
|
|
cm_set_watchdog_params(FALSE,0); // disable watchdog while
|
|
// accessing device to learn how to handle network problems
|
|
#endif
|
|
|
|
// send command to device
|
|
BD_PUTS(str);
|
|
|
|
// read back response from device
|
|
str[0] = '\0';
|
|
status = BD_GETS(str, sizeof(str), "\r\n", BH_TIME_OUT);
|
|
remove_trailing_blanks(str); // eliminate carriage control for cm_msg
|
|
|
|
|
|
#ifdef WATCHDOG_USED
|
|
cm_set_watchdog_params(wflag, wtimeout); // restore watchdog parameters
|
|
#endif
|
|
|
|
if (status <= 0) { // no response
|
|
if ( info->errorcount < BH_MAX_ERROR ) {
|
|
if (info->bh_in_settings.detailed_msg)
|
|
cm_msg(MERROR, "bh_set_send_rcv", "Communication error with bronkhorst "
|
|
"flowcontroller.");
|
|
info->errorcount++;
|
|
}
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"","<<bh_set_send_rcv(cmd=%d) BH_COMM_ERR", cmd);
|
|
#endif
|
|
return BH_COMM_ERR; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
// decode return string and check for errors
|
|
if (bh_success(str, err_msg) != BH_SUCCESS) {
|
|
if ( info->errorcount < BH_MAX_ERROR ) {
|
|
if (info->bh_in_settings.detailed_msg)
|
|
cm_msg(MERROR, "bh_set_send_rcv", "%s", err_msg);
|
|
info->errorcount++;
|
|
}
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"","<<bh_set_send_rcv(cmd=%d) BH_COMM_ERR", cmd);
|
|
#endif
|
|
return BH_COMM_ERR; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"","<<bh_set_send_rcv(cmd=%d) BH_SUCCESS", cmd);
|
|
#endif
|
|
return BH_SUCCESS;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------*/
|
|
/*!
|
|
* <p>routine which filters the channel name and generates the decode command tag</p>
|
|
* <p><b>Return:</b> decode command tag</p>
|
|
* \param str channel name
|
|
* \param decode_tag decode tag needed for the decode routines
|
|
* bh_set_send_rcv, bh_get_send_rcv
|
|
*/
|
|
INT bh_get_cmd(char *str, int *decode_tag)
|
|
{
|
|
int cmd;
|
|
|
|
#ifdef MIDEBUGF2
|
|
cm_msg(MLOG,"",">>bh_get_cmd(%s)", str);
|
|
#endif
|
|
|
|
cmd=BH_NO_CMD;
|
|
/* Input in DD
|
|
[32] BH Flow (l/min)\n\
|
|
[32] BH FlowDAC\n\
|
|
[32] BH Flow_SP (readback l/min)\n\
|
|
[32] BH FlowDAC_SP (readback)\n\
|
|
[32] BH ControlMode (readback)\n\
|
|
[32] BH Temperature (C)\n\
|
|
[32] BH Valve Position (rdbck 0..1)\n\
|
|
* Output in DD
|
|
[32] BH FlowSP\n\
|
|
[32] BH ValvePosSP_TST\n\
|
|
|
|
// without Flow l/min
|
|
[0] BH Flow Measured
|
|
[1] BH Valve Position (rdbck 0..1)
|
|
[2] BH Flow Setpoint (readback)
|
|
[3] BH Control Mode (readback)
|
|
[4] BH Temperature(C)
|
|
|
|
[0] BH Flow Setpoint
|
|
[1] BH Valve Position Setpoint TST
|
|
*/
|
|
|
|
if (strstr(str,"FlowDAC_SP")||strstr(str,"Flow_SP")||strstr(str,"FlowSP")||
|
|
strstr(str,"Flow Setpoint")) {
|
|
cmd = BH_SETPOINT; // 9
|
|
*decode_tag = BH_INTEGER;
|
|
} else if (strstr(str,"FlowDAC")||strstr(str,"Flow")) {
|
|
cmd = BH_MEASURE; // 8
|
|
*decode_tag = BH_INTEGER;
|
|
}
|
|
if (strstr(str,"Temperature")) {
|
|
cmd = BH_TEMPERATURE; // 142
|
|
*decode_tag = BH_FLOAT;
|
|
}
|
|
if (strstr(str, "Valve Position")||strstr(str, "ValvePosSP")) {
|
|
cmd = BH_VALVEOUT; // 55
|
|
*decode_tag = BH_INTEGER;
|
|
}
|
|
if (strstr(str,"ControlMode")||strstr(str,"Control Mode")) {
|
|
cmd = BH_CNTRLMODE; // 12
|
|
*decode_tag = BH_CHAR;
|
|
}
|
|
|
|
#ifdef MIDEBUGF2
|
|
cm_msg(MLOG,"","<<bh_get_cmd(%s) = %d", str, cmd);
|
|
#endif
|
|
return cmd;
|
|
}
|
|
|
|
/*---- device driver routines ---------------------------------------------------------*/
|
|
/*!
|
|
* <p>Initializes the bronkhorst device driver, i.e. generates all the necessary
|
|
* structures in the ODB if necessary, initializes the bus driver and the bronkhorst
|
|
* mass flow meter.</p>
|
|
* <p><b>Return:</b>
|
|
* - FE_SUCCESS if everything went smooth
|
|
* - FE_ERR_ODB otherwise
|
|
* \param hKey is the device driver handle given from the class driver
|
|
* \param pinfo is needed to store the internal info structure
|
|
* \param channels is the number of channels of the device (from the class driver)
|
|
* \param bd is a pointer to the bus driver
|
|
*/
|
|
INT bh_in_init(HNDLE hKey, BH_INFO **pinfo, INT channels, func_t *bd)
|
|
{
|
|
INT status, size, chno;
|
|
INT cmd;
|
|
HNDLE hDB, hkeydd;
|
|
char tpath[MAX_ODB_PATH];
|
|
char bh_id[128], result[128], err_msg[128];
|
|
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"",">>bh_in_init(channels=%d)",channels);
|
|
#endif
|
|
|
|
size = 0;
|
|
cm_get_experiment_database(&hDB, NULL);
|
|
|
|
// allocate info structure
|
|
BH_INFO *info = (BH_INFO*)calloc(1, sizeof(BH_INFO));
|
|
if (pinfo) *pinfo = info;
|
|
if (info == NULL) {
|
|
cm_msg(MERROR,"bh_in_init","NULL pointer to BH_INFO");
|
|
fatal_error_message();
|
|
return FE_ERR_DRIVER; // ----->>>>>>>>>>>>>!
|
|
}
|
|
bh_info = info; // keep global pointer
|
|
|
|
info->volume = 0.0;
|
|
|
|
if ((status = db_get_path(hDB, hKey, tpath, sizeof(tpath))) == DB_SUCCESS) {
|
|
int i;
|
|
for (i = strlen("/Equipment/"); i < strlen(tpath); i++) {
|
|
if (tpath[i] == '/') {
|
|
tpath[i] = '\0';
|
|
strncpy(info->name, &tpath[strlen("/Equipment/")], NAME_LENGTH);
|
|
info->name[NAME_LENGTH - 1] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MINFO, "bh_in_init", " Equipment name is %s", info->name);
|
|
#endif
|
|
} else {
|
|
cm_msg(MERROR, "bh_in_init", "ERROR %d getting key path", status);
|
|
}
|
|
cm_msg_flush_buffer();
|
|
|
|
// create DD settings record
|
|
//status = db_create_record(hDB, hKey, "DD/BH", bh_in_settings_str);
|
|
status = db_create_record(hDB, hKey, "DD", bh_in_settings_str);
|
|
if ((status != DB_SUCCESS) && (status != DB_OPEN_RECORD)) {
|
|
cm_msg(MERROR, "bh_in_init", "bh_in_init: Couldn't create DD/BH in ODB: status=%d",
|
|
status);
|
|
fatal_error_message();
|
|
return FE_ERR_ODB; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
// create BH slowcontrol watchdog DD settings
|
|
#ifdef SCW_USED
|
|
status = db_create_record(hDB, hKey, "DD/SCW", bh_scw_str);
|
|
if ((status != DB_SUCCESS) && (status != DB_OPEN_RECORD)) {
|
|
cm_msg(MERROR, "bh_in_init", "bh_in_init: Couldn't create DD/SCW in ODB: status=%d",
|
|
status);
|
|
cm_msg_flush_buffer();
|
|
return FE_ERR_ODB; // ----->>>>>>>>>>>>>!
|
|
}
|
|
#endif
|
|
|
|
// copy DD entries into the info structure
|
|
//db_find_key(hDB, hKey, "DD/BH", &hkeydd);
|
|
db_find_key(hDB, hKey, "DD", &hkeydd);
|
|
db_open_record(hDB, hkeydd, &info->bh_in_settings, sizeof(info->bh_in_settings),
|
|
MODE_READ, NULL, NULL);
|
|
|
|
/* initialize driver */
|
|
info->hkey = hKey;
|
|
info->keyDDin = hkeydd;
|
|
info->num_channels_in = channels;
|
|
info->bd = bd;
|
|
info->errorcount = 0;
|
|
info->lasterrtime = ss_time();
|
|
info->startup_error = 0;
|
|
info->readback_failure = 0;
|
|
info->last_reconnect = ss_time();
|
|
info->reconnection_failures = 0;
|
|
info->first_bd_error = 1;
|
|
info->startup_tag = 0;
|
|
|
|
if ( info->num_channels_in > BH_IN_CHANNELS ) {
|
|
chno = BH_IN_CHANNELS;
|
|
cm_msg(MERROR,"BH_in_init", "Error, max. number of BH input channels is %d, not %d.",
|
|
chno, info->num_channels_in);
|
|
cm_msg_flush_buffer();
|
|
info->startup_error = 1;
|
|
fatal_error_message();
|
|
return FE_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
if (!bd) {
|
|
fatal_error_message();
|
|
return FE_ERR_DRIVER; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
/* initialize bus driver */
|
|
status = info->bd(CMD_INIT, hKey, &info->bd_info);
|
|
if (status != FE_SUCCESS) {
|
|
info->startup_error = 1;
|
|
cm_msg(MLOG,"","info->bd(CMD_INIT,...) returned status %d", status);
|
|
cm_msg_flush_buffer();
|
|
fatal_error_message();
|
|
return status; // ----->>>>>>>>>>>>>!
|
|
}
|
|
info->bd_connected = TRUE;
|
|
|
|
/* initialize BH */
|
|
cmd = BH_IDENTSTRNG;
|
|
status = bh_get_send_rcv(info, cmd, result);
|
|
|
|
if ( status != BH_SUCCESS ) { // error occurred
|
|
cm_msg(MERROR,"BH_in_init", "Error getting device query from BH, %s",
|
|
info->bh_in_settings.name[0]);
|
|
cm_msg_flush_buffer();
|
|
info->startup_error = 1;
|
|
fatal_error_message();
|
|
return FE_ERR_HW; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
if (bh_decode_string(result, err_msg, bh_id) != BH_SUCCESS) {
|
|
cm_msg(MERROR,"BH_in_init", "%s", err_msg);
|
|
cm_msg_flush_buffer();
|
|
info->startup_error = 1;
|
|
return FE_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
// NOTE first character is 0x07 = ^G or \a control character for Bell.
|
|
// This is currently not filtered but it does not seem to harm the message log.
|
|
// e.g: <Bell>SNM22214346
|
|
cm_msg(MINFO,"BH_in_init", "Device query of BH returns Identification string %s", bh_id);
|
|
bh_show_param(info);
|
|
cm_msg_flush_buffer();
|
|
|
|
#ifdef SCW_USED
|
|
if (info->bh_in_settings.scw_in_use) { // slowcontrol watchdog shall be used
|
|
// register with the slowcontrol watchdog -------------------------------------
|
|
// find scw record in DD
|
|
db_find_key(hDB, hKey, "DD/SCW", &hkeydd);
|
|
// get record
|
|
size = sizeof(info->scw);
|
|
db_get_record(hDB, hkeydd, &info->scw, &size, 0);
|
|
// fill watchdog structure
|
|
info->scw.pid = ss_getpid();
|
|
info->scw.last_updated = ss_time();
|
|
// write info back into ODB
|
|
db_set_record(hDB, hkeydd, &info->scw, sizeof(info->scw), 0);
|
|
|
|
// register with slowcontrol watchdog
|
|
status = lem_scw_init(&info->scw);
|
|
if (status != LEM_SCW_SUCCESS) {
|
|
cm_msg(MINFO, "bh_in_init", "Couldn't register with lem watchdog");
|
|
cm_yield(0);
|
|
}
|
|
}
|
|
#endif /* #ifdef SCW_USED */
|
|
|
|
result[0] = '\0';
|
|
info->volume = -1.0;
|
|
status = bh_get_send_rcv(info, BH_MODELNUM, result);
|
|
if (status == BH_SUCCESS) {
|
|
char model[128];
|
|
|
|
// string was returned
|
|
model[0] = '\0';
|
|
status = bh_decode_string(result, err_msg, model);
|
|
|
|
if (status == BH_SUCCESS) {
|
|
#ifdef MIDEBUG1
|
|
cm_msg(MLOG,"","DDE Parameter %d : %s = %s", BH_MODELNUM, "BHTModel number", model);
|
|
#endif
|
|
if (strncmp(model,"F-111AC-50K",11) == 0) {
|
|
info->volume = 50.0;
|
|
} else if (strncmp(model,"F-201CV-10",10) == 0) {
|
|
info->volume = 19.0;
|
|
} else if (strncmp(model,"F-201CV-5K",10) == 0) {
|
|
info->volume = 9.0;
|
|
} else {
|
|
cm_msg(MERROR,"bh_in_init","WARNING BHTModel number \"%s\" is not known! "
|
|
"Check currently set DD parameter and adapt them when they "
|
|
"are not correct! Add model case here", model);
|
|
info->volume = -4.0;
|
|
}
|
|
} else {
|
|
cm_msg(MERROR,"bh_in_init","cmd=%d, para_name=\"BHTModel number\": bh_decode_string() "
|
|
"returned : %s", BH_MODELNUM, err_msg);
|
|
info->volume = -3.0;
|
|
}
|
|
} else {
|
|
cm_msg(MERROR,"bh_in_init","cmd=%d, para_name=\"BHTModel number\": bh_get_send_rcv() "
|
|
"returned : %d", BH_MODELNUM, status);
|
|
info->volume = -2.0;
|
|
}
|
|
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"","<<bh_in_init()");
|
|
#endif
|
|
return FE_SUCCESS;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------*/
|
|
/*!
|
|
* <p>Initializes the bronkhorst device driver, i.e. generates all the necessary
|
|
* structures in the ODB if necessary, <b>no</b> initialization of the bus driver etc.
|
|
* is done, since this is part of BH_in_init.</p>
|
|
* <p><b>Return:</b>
|
|
* - FE_SUCCESS if everything went smooth
|
|
* - FE_ERR_ODB otherwise
|
|
* \param hKey is the device driver handle given from the class driver
|
|
* \param pinfo is needed to store the internal info structure
|
|
* \param channels is the number of channels of the device (from the class driver)
|
|
* \param bd is a pointer to the bus driver
|
|
*/
|
|
INT bh_out_init(HNDLE hKey, BH_INFO **pinfo, INT channels, func_t *bd)
|
|
{
|
|
INT status, chno;
|
|
HNDLE hDB, hkeydd;
|
|
BH_INFO *info;
|
|
char odb_output[MAX_ODB_PATH];
|
|
float dummy;
|
|
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"",">>bh_out_init(channels=%d)",channels);
|
|
#endif
|
|
|
|
cm_get_experiment_database(&hDB, NULL);
|
|
|
|
info = bh_info;
|
|
if (pinfo) *pinfo = info;
|
|
|
|
if (bh_info == NULL) {
|
|
cm_msg(MERROR,"bh_out_init","NULL pointer to BH_INFO allocated in "
|
|
"bh_in_init()");
|
|
fatal_error_message();
|
|
return FE_ERR_DRIVER; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
/* create DD settings record */
|
|
status = db_create_record(hDB, hKey, "DD", bh_out_settings_str);
|
|
if ((status != DB_SUCCESS) && (status != DB_OPEN_RECORD)) {
|
|
cm_msg(MERROR, "bh_out_init", "Couldn't create DD: status=%d", status);
|
|
return FE_ERR_ODB; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
// copy DD entries into the info structure
|
|
db_find_key(hDB, hKey, "DD", &hkeydd);
|
|
db_open_record(hDB, hkeydd, &info->bh_out_settings, sizeof(info->bh_out_settings),
|
|
MODE_READ, NULL, NULL);
|
|
|
|
/* initialize driver */
|
|
info->num_channels_out = channels;
|
|
|
|
if ( info->num_channels_out != BH_OUT_CHANNELS ) {
|
|
chno = BH_OUT_CHANNELS;
|
|
cm_msg(MERROR,"bh_out_init", "Error, allowed number of BH output channels is %d, "
|
|
"not %d.", chno, info->num_channels_out);
|
|
info->startup_error = 1;
|
|
return FE_ERR_HW; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
sprintf(odb_output, "/Equipment/%s/Variables/Output",info->name);
|
|
status = db_find_key(hDB, 0, odb_output, &info->keyOut);
|
|
if (status != FE_SUCCESS) { // couldn't get the output key maybe it is not there yet
|
|
info->keyOut = 0; // but we got another chance
|
|
} else {
|
|
|
|
// get and then set Flow Setpoint in the ODB to readback value of Flow Setpoint
|
|
#ifdef BH_SETPOINT_INCHANINDEX
|
|
bh_get(info, BH_SETPOINT_INCHANINDEX, &dummy);
|
|
#ifdef BH_SETPOINT_OUTCHANINDEX
|
|
// initialize
|
|
info->last_set[BH_SETPOINT_OUTCHANINDEX] = dummy;
|
|
info->last_setval[BH_SETPOINT_OUTCHANINDEX] = info->last_valid_value[BH_SETPOINT_INCHANINDEX+1];
|
|
// update ODB
|
|
db_set_data_index(hDB, info->keyOut, &dummy, sizeof(float),BH_SETPOINT_OUTCHANINDEX,TID_FLOAT);
|
|
#endif /* #ifdef BH_SETPOINT_OUTCHANINDEX */
|
|
#endif /* #ifdef BH_SETPOINT_INCHANINDEX */
|
|
|
|
// get and set the Valve Position (to make reconnect smoother when already initialized)
|
|
#ifdef BH_VALVEPOS_INCHANINDEX
|
|
bh_get(info, BH_VALVEPOS_INCHANINDEX, &dummy);
|
|
#ifdef BH_VALVEPOS_OUTCHANINDEX
|
|
db_set_data_index(hDB, info->keyOut, &dummy, sizeof(float), BH_VALVEPOS_OUTCHANINDEX, TID_FLOAT);
|
|
#endif /* #ifdef BH_VALVEPOS_OUTCHANINDEX */
|
|
#endif /* #ifdef BH_VALVEPOS_INCHANINDEX */
|
|
|
|
|
|
}
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"","<<bh_out_init()");
|
|
#endif
|
|
return FE_SUCCESS;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------*/
|
|
/*!
|
|
* <p>terminates the bus driver and free's the memory allocated for the info structure
|
|
* BH_INFO.</p>
|
|
* <p><b>Return:</b> FE_SUCCESS</p>
|
|
* \param info is a pointer to the DD specific info structure
|
|
*/
|
|
INT bh_exit(BH_INFO *info)
|
|
{
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"",">>bh_exit()");
|
|
#endif
|
|
|
|
// call EXIT function of bus driver, usually closes device
|
|
info->bd(CMD_EXIT, info->bd_info);
|
|
|
|
#ifdef SCW_USED
|
|
if (info->bh_in_settings.scw_in_use && !info->startup_error) { // slowcontrol watchdog in use
|
|
// deregister from the slowcontrol watchdog
|
|
lem_scw_exit(&info->scw);
|
|
}
|
|
#endif
|
|
|
|
free(info);
|
|
bh_info = NULL;
|
|
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"","<<bh_exit()");
|
|
#endif
|
|
return FE_SUCCESS;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------*/
|
|
/*!
|
|
* <p>set a value of the bronkhorst mass flow meter.</p>
|
|
* <p><b>Return:</b> FE_SUCCESS</p>
|
|
* \param info is a pointer to the DD specific info structure.
|
|
* \param channel is the channel number
|
|
* \param value to be set
|
|
*/
|
|
INT bh_set(BH_INFO *info, INT channel, float value) {
|
|
int cmd, status, decode_tag, i;
|
|
float setval;
|
|
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"",">>bh_set(channel=%d, value=%f)", channel, value);
|
|
#endif
|
|
status = BH_SUCCESS;
|
|
|
|
// always remember that value will be stored in info->last_set[channel]
|
|
// and setval will be sent to the controller
|
|
setval = value;
|
|
|
|
if (info->startup_error)
|
|
return FE_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
|
|
if (!info->bd_connected) {
|
|
if (info->first_bd_error) {
|
|
info->first_bd_error = 0;
|
|
cm_msg(MINFO, "BH_set",
|
|
"BH_set: set values not possible at the moment, since the bus driver is "
|
|
"not available!");
|
|
}
|
|
ss_sleep(10);
|
|
return FE_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
// if dd is starting up, do not actually send a command!!
|
|
if (info->startup_tag < 2) {
|
|
|
|
// write channel information about output and input instead
|
|
if (info->startup_tag == 0) {
|
|
float dummy;
|
|
int has_changed;
|
|
has_changed = 0;
|
|
|
|
cm_msg(MLOG,"","Parameter .../BHFCin/DD/\"Reset to Defaults of Type\" is %c",
|
|
info->bh_in_settings.reset_to_defaults);
|
|
|
|
if ((info->bh_in_settings.reset_to_defaults=='Y')||(info->bh_in_settings.reset_to_defaults=='y')) {
|
|
float tvalp;
|
|
INT tivalp;
|
|
HNDLE hDB;
|
|
|
|
cm_get_experiment_database(&hDB, NULL);
|
|
|
|
if (info->bh_in_settings.Flow_lpm_Offset != 0.0) {
|
|
tvalp = info->bh_in_settings.Flow_lpm_Offset = 0.0;
|
|
has_changed++;
|
|
db_set_value(hDB, info->keyDDin, "Flow lpmin Offset",&tvalp,sizeof(tvalp),1,TID_FLOAT);
|
|
}
|
|
if (info->bh_in_settings.FlowDAC_Offset != 0) {
|
|
tivalp = info->bh_in_settings.FlowDAC_Offset = 0;
|
|
has_changed++;
|
|
db_set_value(hDB, info->keyDDin, "Flow DAC Offset",&tivalp,sizeof(tivalp),1,TID_INT);
|
|
}
|
|
if (info->bh_in_settings.FlowDAC_Max != 32000) {
|
|
tivalp = info->bh_in_settings.FlowDAC_Max = 32000;
|
|
has_changed++;
|
|
db_set_value(hDB, info->keyDDin, "Flow DAC Maximum",&tivalp,sizeof(tivalp),1,TID_INT);
|
|
}
|
|
if (info->volume == 50.0) {
|
|
if (bh_afdiff(info->bh_in_settings.Flow_lpm_Max, 50.0) > 0.001) {
|
|
tvalp = info->bh_in_settings.Flow_lpm_Max = 50.0;
|
|
has_changed++;
|
|
db_set_value(hDB, info->keyDDin, "Flow lpmin Maximum",&tvalp,sizeof(tvalp),1,TID_FLOAT);
|
|
}
|
|
if (bh_afdiff(info->bh_in_settings.Flow_lpm_to_DAC_Scale,640.0) > 0.001) {
|
|
tvalp = info->bh_in_settings.Flow_lpm_to_DAC_Scale = 640.0;
|
|
has_changed++;
|
|
db_set_value(hDB, info->keyDDin, "Flow lpmin to DAC Scale",&tvalp,sizeof(tvalp),1,TID_FLOAT);
|
|
}
|
|
} else if (info->volume == 19.0) {
|
|
if (bh_afdiff(info->bh_in_settings.Flow_lpm_Max, 19.0) > 0.001) {
|
|
tvalp = info->bh_in_settings.Flow_lpm_Max = 19.0;
|
|
has_changed++;
|
|
db_set_value(hDB, info->keyDDin, "Flow lpmin Maximum",&tvalp,sizeof(tvalp),1,TID_FLOAT );
|
|
}
|
|
if (bh_afdiff(info->bh_in_settings.Flow_lpm_to_DAC_Scale, 1684.210) > 0.001) {
|
|
tvalp = info->bh_in_settings.Flow_lpm_to_DAC_Scale = 1684.21;
|
|
has_changed++;
|
|
db_set_value(hDB, info->keyDDin, "Flow lpmin to DAC Scale",&tvalp,sizeof(tvalp),1,TID_FLOAT);
|
|
}
|
|
} else if (info->volume == 9.0) {
|
|
if (bh_afdiff(info->bh_in_settings.Flow_lpm_Max, 9.0) > 0.001) {
|
|
tvalp = info->bh_in_settings.Flow_lpm_Max = 9.0;
|
|
has_changed++;
|
|
db_set_value(hDB, info->keyDDin, "Flow lpmin Maximum",&tvalp,sizeof(tvalp),1,TID_FLOAT );
|
|
}
|
|
if (bh_afdiff(info->bh_in_settings.Flow_lpm_to_DAC_Scale, 3555.560) > 0.001) {
|
|
tvalp = info->bh_in_settings.Flow_lpm_to_DAC_Scale = 3555.560;
|
|
has_changed++;
|
|
db_set_value(hDB, info->keyDDin, "Flow lpmin to DAC Scale",&tvalp,sizeof(tvalp),1,TID_FLOAT);
|
|
}
|
|
} else {
|
|
// NIY hier TODO Msg case not handled
|
|
}
|
|
if (has_changed) {
|
|
// NIY hier TODO Msg that # of DD ODB parameter were updated
|
|
cm_msg(MLOG,"","%d DD Parameter have been updated to their default values",has_changed);
|
|
}
|
|
} else {
|
|
}
|
|
|
|
for (i=0; i < info->num_channels_out; i++) {
|
|
#ifdef BH_SETPOINT_OUTCHANINDEX
|
|
if (i == BH_SETPOINT_OUTCHANINDEX) {
|
|
// show info about channel and limits and flags
|
|
// and conversion to DAC and information about DAC
|
|
cm_msg(MLOG,"","Output Channel [%d] \"%s\" : Range to enter is | 0.0 - %.3f | "
|
|
"see BHFCin/DD/\"Flow lpmin Maximum\"", i, info->bh_out_settings.name[i],
|
|
info->bh_in_settings.Flow_lpm_Max);
|
|
cm_msg(MLOG,"","Output Channel [%d] Parameter .../DD/\"Flow [l/min] Offset\" is %.3f", i,
|
|
info->bh_in_settings.Flow_lpm_Offset);
|
|
cm_msg(MLOG,"","Output Channel [%d] Parameter .../DD/\"Flow [l/min] to DAC Scale\" is %.3f", i,
|
|
info->bh_in_settings.Flow_lpm_to_DAC_Scale);
|
|
cm_msg(MLOG,"","Output Channel [%d] Parameter .../DD/\"Flow DAC Offset\" is %d", i,
|
|
info->bh_in_settings.FlowDAC_Offset);
|
|
cm_msg(MLOG,"","Output Channel [%d] Parameter .../DD/\"Flow DAC Maximum\" is %d", i,
|
|
info->bh_in_settings.FlowDAC_Max);
|
|
// warning when DAC Maximum > 32000
|
|
if (info->bh_in_settings.FlowDAC_Max > 32000) {
|
|
cm_msg(MERROR,"bh_set","**** WARNING Flow DAC SP. Maximum set value may not be larger than "
|
|
"32000 (100%% Flow) ****");
|
|
}
|
|
if ( (int) ((info->bh_in_settings.Flow_lpm_Max - info->bh_in_settings.Flow_lpm_Offset) *
|
|
info->bh_in_settings.Flow_lpm_to_DAC_Scale +info->bh_in_settings.FlowDAC_Offset) > 32000) {
|
|
// warning when (maxflow-flowoffset)*scal-DACoffset > 32000
|
|
cm_msg(MERROR,"bh_set","**** WARNING (Max Flow - offset [l/min])*scale + DAC offset"
|
|
" is larger than 32000 (100%% Flow) ****");
|
|
}
|
|
|
|
// valid volume ?
|
|
if (info->volume > 0.0) {
|
|
if (info->volume == 50.0) { // volume is 50 l/min He
|
|
// max flow should be less or equal 50
|
|
if (info->bh_in_settings.Flow_lpm_Max > 50.0) {
|
|
cm_msg(MLOG,"bh_set","ERROR .../DD/\"Flow lpm Maximum\" (%.1f) is larger than 50 l/min "
|
|
"(will internally change it)", info->bh_in_settings.Flow_lpm_Max);
|
|
info->bh_in_settings.Flow_lpm_Max = 50.0;
|
|
}
|
|
|
|
// NIY hier TODO scale should be near <= 640
|
|
|
|
// warning when max flow is less or equal 19
|
|
if (info->bh_in_settings.Flow_lpm_Max <= 19.0) {
|
|
cm_msg(MLOG,"bh_set","WARNING .../DD/\"Flow lpm Maximum\" (%.1f) is rather low for "
|
|
"50 l/min", info->bh_in_settings.Flow_lpm_Max);
|
|
}
|
|
|
|
} else if (info->volume == 19.0) { // volume is 19 l/min He
|
|
// max flow should be less or equal 19
|
|
if (info->bh_in_settings.Flow_lpm_Max > 19.0) {
|
|
cm_msg(MLOG,"bh_set","ERROR .../DD/\"Flow lpm Maximum\" (%.1f) is larger than 19 l/min "
|
|
"(will internally change it)", info->bh_in_settings.Flow_lpm_Max);
|
|
info->bh_in_settings.Flow_lpm_Max = 19.0;
|
|
}
|
|
|
|
// NIY hier TODO scale should be near <= 1684.21
|
|
|
|
// warning when max flow is less or equal 9
|
|
if (info->bh_in_settings.Flow_lpm_Max <= 9.0) {
|
|
cm_msg(MLOG,"bh_set","WARNING .../DD/\"Flow lpm Maximum\" (%.1f) is rather low for "
|
|
"19 l/min", info->bh_in_settings.Flow_lpm_Max);
|
|
}
|
|
|
|
} else if (info->volume == 9.0) { // volume is 9 l/min He
|
|
|
|
// max flow should be less or equal 9
|
|
if (info->bh_in_settings.Flow_lpm_Max > 9.0) {
|
|
cm_msg(MLOG,"bh_set","ERROR .../DD/\"Flow lpm Maximum\" (%.1f) is larger than 9 l/min"
|
|
"(will internally change it)", info->bh_in_settings.Flow_lpm_Max);
|
|
info->bh_in_settings.Flow_lpm_Max = 9.0;
|
|
}
|
|
|
|
// NIY hier TODO scale should be near <= 3555.56
|
|
|
|
// } else if (info->volume == ???) {
|
|
//
|
|
} else {
|
|
cm_msg(MERROR,"bh_set","WARNING no information about this BHTModel number (%.3f l/min)! "
|
|
"Current DD Parameter might not be appropriate. "
|
|
"Add case for this volume here",info->volume);
|
|
}
|
|
|
|
} else {
|
|
cm_msg(MERROR,"bh_set","WARNING no information about the BHTModel number available! "
|
|
"Current DD Parameter might not be appropriate");
|
|
|
|
}
|
|
|
|
cm_msg(MLOG,"","Output Channel [%d] Parameter .../DD/\"Set out of Range Flow to Max\" is %c",
|
|
i, info->bh_in_settings.SetOutofRangeSetpoint_to_Max);
|
|
|
|
cm_msg(MLOG,"","Parameter .../BHFCin/DD/\"Set out of Range FlowSP to Max\" is %c",
|
|
info->bh_in_settings.SetOutofRangeSetpoint_to_Max);
|
|
|
|
if ((info->bh_in_settings.SetOutofRangeSetpoint_to_Max == 'Y') ||
|
|
(info->bh_in_settings.SetOutofRangeSetpoint_to_Max == 'y')) {
|
|
cm_msg(MLOG,"","Output Channel [%d] *** An out of range Flow SP will be set to Maximum "
|
|
"flow (%.3f l/min)!", i, info->bh_in_settings.Flow_lpm_Max);
|
|
} else {
|
|
cm_msg(MLOG,"","Output Channel [%d] *** An out of range Flow SP will be reset to the "
|
|
"previously set Flow SP!", i);
|
|
}
|
|
continue;
|
|
}
|
|
#endif
|
|
// get command from the name
|
|
cmd = bh_get_cmd(info->bh_out_settings.name[i], &decode_tag);
|
|
switch (cmd) {
|
|
|
|
#ifndef BH_SETPOINT_OUTCHANINDEX
|
|
// write information only when not using l/min
|
|
case BH_SETPOINT:
|
|
cm_msg(MLOG,"","Output Channel [%d] \"%s\" : Range to enter is | 0 - 32767 | "
|
|
"(32000=100%%)", i, info->bh_out_settings.name[i]);
|
|
break;
|
|
#endif
|
|
case BH_VALVEOUT:
|
|
cm_msg(MLOG,"","Output Channel [%d] \"%s\" : Range to enter is | 0 - 1 | (will be "
|
|
"scaled by %d)", i, info->bh_out_settings.name[i], BH_MAX_NEEDLE_VALVE);
|
|
break;
|
|
|
|
default:
|
|
;
|
|
} // switch
|
|
} // for all output channels
|
|
|
|
for (i=0; i < info->num_channels_in; i++) {
|
|
#ifdef bronkhorst_flowmeter_inCHANINDEX //!< index of Flow readout (l/min)
|
|
if (i== bronkhorst_flowmeter_inCHANINDEX) {
|
|
cm_msg(MLOG,"","Input Channel [%d] \"%s\" : Range shown is | 0.0 - %.3f | l/min",
|
|
i, info->bh_in_settings.name[i], info->bh_in_settings.Flow_lpm_Max);
|
|
continue;
|
|
}
|
|
#endif
|
|
#ifdef BH_SETPOINT_INCHANINDEX //!< index of Flow Setpoint readout (l/min)
|
|
if (i == BH_SETPOINT_INCHANINDEX) {
|
|
cm_msg(MLOG,"","Input Channel [%d] \"%s\" : Range shown is | 0.0 - %.3f | l/min",
|
|
i, info->bh_in_settings.name[i], info->bh_in_settings.Flow_lpm_Max);
|
|
continue;
|
|
}
|
|
#endif
|
|
// get command from the name
|
|
cmd = bh_get_cmd(info->bh_in_settings.name[i], &decode_tag);
|
|
switch (cmd) {
|
|
|
|
case BH_SETPOINT:
|
|
case BH_MEASURE:
|
|
cm_msg(MLOG,"","Input Channel [%d] \"%s\" : Range shown is | 0 - 32767 | "
|
|
"(32000=100%%)", i, info->bh_in_settings.name[i]);
|
|
break;
|
|
|
|
case BH_VALVEOUT:
|
|
cm_msg(MLOG,"","Input Channel [%d] \"%s\" : Range shown is | 0 - 1 |"
|
|
"(reading scaled by 1/%d)", i, info->bh_in_settings.name[i],
|
|
BH_MAX_NEEDLE_VALVE);
|
|
break;
|
|
|
|
case BH_CNTRLMODE:
|
|
cm_msg(MLOG,"","Input Channel [%d] \"%s\" : Controller modes are 0,1,3,4,5,7,"
|
|
"9,12,18", i, info->bh_in_settings.name[i]);
|
|
break;
|
|
|
|
case BH_TEMPERATURE: // 142
|
|
cm_msg(MLOG,"","Input Channel [%d] \"%s\" : Temperature [C] range is | -250 - 500 |",
|
|
i, info->bh_in_settings.name[i]);
|
|
break;
|
|
|
|
case BH_FLUIDTEMP: // 181
|
|
cm_msg(MLOG,"","Input Channel [%d] \"%s\" : Fluid Temperature [C] range is | -273.15 - "
|
|
"3.40282E+38 |", i, info->bh_in_settings.name[i]);
|
|
break;
|
|
|
|
default:
|
|
;
|
|
} // switch
|
|
} // for all input channels
|
|
|
|
// update internal array of input channels
|
|
for (i=0; i < info->num_channels_in; i++) {
|
|
bh_get(info, i, &dummy);
|
|
} // for all input channels
|
|
}
|
|
|
|
info->startup_tag++;
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"","<<bh_set(channel=%d) startup_tag < 2 - No command sent to controller", channel);
|
|
#endif
|
|
return FE_SUCCESS; // --->>>>>>>>>>>>>>>>>>>
|
|
}
|
|
|
|
#ifdef BH_SETPOINT_OUTCHANINDEX //!< index of Flow Setpoint (l/min) defined
|
|
if (channel == BH_SETPOINT_OUTCHANINDEX) { // channel is Flow SP (l/min)
|
|
HNDLE hDB;
|
|
INT setvali;
|
|
|
|
cm_get_experiment_database(&hDB, NULL);
|
|
|
|
if (value > info->bh_in_settings.Flow_lpm_Max) { // above upper limit
|
|
if ((info->bh_in_settings.SetOutofRangeSetpoint_to_Max == 'Y') ||
|
|
(info->bh_in_settings.SetOutofRangeSetpoint_to_Max == 'y')) { // set to limit when Y
|
|
cm_msg(MERROR,"bh_set","Flow SP %.3f l/min is out of upper range %.3f. Will set it to the Limit",
|
|
value, info->bh_in_settings.Flow_lpm_Max);
|
|
value = info->bh_in_settings.Flow_lpm_Max;
|
|
|
|
// update ODB channel to (new) value and continue setting
|
|
if (info->keyOut > 0)
|
|
db_set_data_index(hDB, info->keyOut, &value,sizeof(float),BH_SETPOINT_OUTCHANINDEX, TID_FLOAT);
|
|
|
|
} else { // or reset to last value when N
|
|
cm_msg(MERROR,"bh_set","Flow SP %.3f l/min is out of upper range %.3f. Will reset it to %.3f "
|
|
"l/min",value,info->bh_in_settings.Flow_lpm_Max,info->last_set[channel]);
|
|
value = info->last_set[channel];
|
|
|
|
// reset ODB channel to value and return
|
|
if (info->keyOut > 0)
|
|
db_set_data_index(hDB, info->keyOut, &value,sizeof(float),BH_SETPOINT_OUTCHANINDEX,TID_FLOAT);
|
|
return FE_SUCCESS; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
|
}
|
|
|
|
}
|
|
|
|
// NOTE Flow SP l/min < 0 is not checked here as it may still be >= 0 after conversion to FlowDAC
|
|
|
|
// calculate DAC value
|
|
setvali = (value -info->bh_in_settings.Flow_lpm_Offset)*info->bh_in_settings.Flow_lpm_to_DAC_Scale
|
|
+info->bh_in_settings.FlowDAC_Offset;
|
|
|
|
// check limits and if OK send command
|
|
if (setvali < 0) { // DAC value is lower than lower range
|
|
cm_msg(MERROR,"bh_set","FlowDAC SP %d is below the lower FlowDAC range 0. Will reset Flow SP "
|
|
"from %.3f l/min to %.3f l/min", setvali, value, info->last_set[channel]);
|
|
value = info->last_set[channel];
|
|
|
|
// reset ODB channel to value and return
|
|
if (info->keyOut > 0)
|
|
db_set_data_index(hDB, info->keyOut, &value,sizeof(float),BH_SETPOINT_OUTCHANINDEX,TID_FLOAT);
|
|
return FE_SUCCESS; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
|
}
|
|
|
|
if (setvali > info->bh_in_settings.FlowDAC_Max) {
|
|
float newval;
|
|
|
|
// avoid division by 0
|
|
if (info->bh_in_settings.Flow_lpm_to_DAC_Scale > 0.001) {
|
|
newval = (info->bh_in_settings.FlowDAC_Max
|
|
-info->bh_in_settings.FlowDAC_Offset)/info->bh_in_settings.Flow_lpm_to_DAC_Scale
|
|
+info->bh_in_settings.Flow_lpm_Offset;
|
|
|
|
cm_msg(MERROR,"bh_set","FlowDAC SP %d is above the upper FlowDAC range %d. "
|
|
"Will set %d and change Flow SP from %.3f l/min to "
|
|
"%.3f l/min in the ODB", setvali, info->bh_in_settings.FlowDAC_Max,
|
|
info->bh_in_settings.FlowDAC_Max, value, newval);
|
|
setvali = info->bh_in_settings.FlowDAC_Max;
|
|
value = newval;
|
|
|
|
// update ODB channel to value and continue setting
|
|
if (info->keyOut > 0)
|
|
db_set_data_index(hDB, info->keyOut, &value,sizeof(float),BH_SETPOINT_OUTCHANINDEX,TID_FLOAT);
|
|
}
|
|
}
|
|
setval = setvali;
|
|
}
|
|
#endif
|
|
|
|
// get command and decode tag from the name
|
|
cmd = bh_get_cmd(info->bh_out_settings.name[channel], &decode_tag);
|
|
|
|
// set value in the flowcontroller
|
|
status = bh_set_send_rcv(info, cmd, setval);
|
|
|
|
if (status != BH_SUCCESS) {
|
|
if ( info->errorcount < BH_MAX_ERROR ) {
|
|
if (info->bh_in_settings.detailed_msg)
|
|
cm_msg(MERROR, "bh_set", "BH communication or command error. status = %d", status);
|
|
info->errorcount++;
|
|
}
|
|
} else {
|
|
float diff;
|
|
#ifdef BH_SETPOINT_OUTCHANINDEX //!< index of Flow Setpoint (l/min) defined
|
|
if (channel == BH_SETPOINT_OUTCHANINDEX) { // channel is Flow SP (l/min)
|
|
|
|
diff = bh_afdiff( info->last_set[channel],value);
|
|
if (diff > 0.001) { // FlowSP l/min has changed
|
|
cm_msg(MLOG,"","Output Channel[%d] \"%s\" changed to %.3f l/min. Sending DAC Setpoint "
|
|
"%.0f (%.1f%%) to Bronkhorst.", channel, info->bh_out_settings.name[channel],
|
|
value, setval, setval/320.0);
|
|
}
|
|
} else {
|
|
|
|
diff = bh_afdiff( info->last_setval[channel],setval);
|
|
if (diff > 0.001) {
|
|
cm_msg(MLOG,"","Output Channel[%d] \"%s\" changed to %f", channel,
|
|
info->bh_out_settings.name[channel], setval);
|
|
}
|
|
}
|
|
#else
|
|
diff = bh_afdiff( info->last_setval[channel],setval);
|
|
if (diff > 0.001) {
|
|
cm_msg(MLOG,"","Output Channel[%d] \"%s\" changed to %f", channel,
|
|
info->bh_out_settings.name[channel], setval);
|
|
}
|
|
#endif
|
|
|
|
info->last_set[channel] = value;
|
|
info->last_setval[channel] = setval;
|
|
}
|
|
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"","<<bh_set(channel=%d, value=%f, setval=%f)", channel, value, setval);
|
|
#endif
|
|
return FE_SUCCESS;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------*/
|
|
/*!
|
|
* <p>get a value from the bronkhorst mass flow meter.</p>
|
|
* <p><b>Return:</b> FE_SUCCESS</p>
|
|
* \param info is a pointer to the DD specific info structure.
|
|
* \param channel is the channel number
|
|
* \param pvalue read
|
|
*/
|
|
INT bh_get(BH_INFO *info, INT channel, float *pvalue)
|
|
{
|
|
int cmd, status, decode_tag;
|
|
char str[128], err_msg[128];
|
|
DWORD nowtime, difftime;
|
|
INT tchannel;
|
|
float diff, previous_value_tchannel;
|
|
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"",">>bh_get(channel=%d)", channel);
|
|
cm_msg_flush_buffer();
|
|
#endif
|
|
tchannel = channel;
|
|
|
|
// error timeout facility
|
|
nowtime = ss_time();
|
|
difftime = nowtime - info->lasterrtime;
|
|
if ( difftime > BH_DELTA_TIME_ERROR ) {
|
|
info->errorcount = 0;
|
|
info->lasterrtime = ss_time();
|
|
}
|
|
|
|
if (!pvalue) {
|
|
ss_sleep(10); // to keep CPU load low when Run active
|
|
return FE_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
// check if there was a startup error
|
|
if ( info->startup_error ) {
|
|
*pvalue = (float) BH_INIT_ERROR;
|
|
ss_sleep(10); // to keep CPU load low when Run active
|
|
return FE_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
// check if they where too many reconnection failures
|
|
if (info->reconnection_failures > BH_MAX_RECONNECTION_FAILURE) {
|
|
*pvalue = (float) BH_READ_ERROR;
|
|
if (info->reconnection_failures == BH_MAX_RECONNECTION_FAILURE+1) {
|
|
cm_msg(MERROR, "BH_get", "too many reconnection failures, bailing out :-(");
|
|
cm_msg_flush_buffer();
|
|
info->reconnection_failures++;
|
|
}
|
|
return FE_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
#ifdef SCW_USED
|
|
if (info->bh_in_settings.scw_in_use) { // slowcontrol watchdog in use
|
|
// feed slowcontrol watchdog
|
|
info->scw.last_updated = ss_time();
|
|
lem_scw_update(&info->scw);
|
|
}
|
|
#endif
|
|
|
|
// if disconnected, try to reconnect after the timeout expires
|
|
if (!info->bd_connected) {
|
|
if (ss_time()-info->last_reconnect > BH_RECONNECTION_TIMEOUT) { // timeout expired
|
|
BOOL wflag;
|
|
DWORD wtimeout,wtimeoutn;
|
|
|
|
if (info->bh_in_settings.detailed_msg) {
|
|
cm_msg(MINFO, "BH_get", "Bronkhorst: reconnection trial ...");
|
|
cm_msg_flush_buffer();
|
|
}
|
|
#ifdef WATCHDOG_USED
|
|
// turn off watchdog as fe might wait forever
|
|
cm_get_watchdog_params(&wflag, &wtimeout);
|
|
wtimeoutn = 0;
|
|
cm_set_watchdog_params(wflag,wtimeoutn);
|
|
#endif
|
|
status = info->bd(CMD_INIT, info->hkey, &info->bd_info);
|
|
#ifdef WATCHDOG_USED
|
|
// restore watchdog params
|
|
cm_set_watchdog_params(wflag, wtimeout);
|
|
#endif
|
|
|
|
if (status != FE_SUCCESS) {
|
|
info->reconnection_failures++;
|
|
*pvalue = (float) BH_READ_ERROR;
|
|
if (info->bh_in_settings.detailed_msg) {
|
|
cm_msg(MINFO, "BH_get", "Bronkhorst EL-FLOW reconnection attempt failed");
|
|
cm_msg_flush_buffer();
|
|
}
|
|
return FE_ERR_HW; // ----->>>>>>>>>>>>>!
|
|
} else {
|
|
info->bd_connected = 1; // bus driver is connected again
|
|
info->last_reconnect = ss_time();
|
|
info->reconnection_failures = 0;
|
|
info->first_bd_error = 1;
|
|
|
|
cm_msg(MINFO, "BH_get", "Bronkhorst EL-FLOW successfully reconnected");
|
|
cm_msg_flush_buffer();
|
|
}
|
|
} else { // wait time interval not yet expired
|
|
// cm_msg(MINFO, "BH_get", "Bronkhorst: last reconnection attempt not yet expired");
|
|
// cm_msg_flush_buffer();
|
|
*pvalue = info->last_valid_value[channel];
|
|
return FE_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
}
|
|
|
|
#ifdef bronkhorst_flowmeter_inCHANINDEX
|
|
// if FLOW liter/min channel add 1 to tchannel
|
|
if (channel == bronkhorst_flowmeter_inCHANINDEX) { //!< index of Flow readout (l/min)
|
|
tchannel += 1;
|
|
|
|
// else if (channel is Flow liter/min channel+1) return the channels value
|
|
} else if (channel == bronkhorst_flowmeter_inCHANINDEX+1) { // Index of corresponding SP DAC channel
|
|
*pvalue = info->last_valid_value[channel];
|
|
#ifdef MIDEBUGF1
|
|
if (pvalue)
|
|
cm_msg(MLOG,"","<<bh_get(channel=%d, *pvalue=%f)", channel, *pvalue);
|
|
#endif
|
|
return FE_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
#endif
|
|
|
|
#ifdef BH_SETPOINT_INCHANINDEX
|
|
// if FLOWSP liter/min channel add 1 to tchannel
|
|
if (channel == BH_SETPOINT_INCHANINDEX) { //!< index of Flow Setpoint readout (l/min)
|
|
tchannel += 1;
|
|
|
|
// else if (channel is Flowliter channel+1) return the channels value
|
|
} else if (channel == bronkhorst_flowmeter_inCHANINDEX+1) { // Index of corresponding DAC channel
|
|
*pvalue = info->last_valid_value[channel];
|
|
#ifdef MIDEBUGF1
|
|
if (pvalue)
|
|
cm_msg(MLOG,"","<<bh_get(channel=%d, *pvalue=%f)", channel, *pvalue);
|
|
#endif
|
|
return FE_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
#endif
|
|
|
|
// get command and decode tag from the name
|
|
cmd = bh_get_cmd(info->bh_in_settings.name[tchannel], &decode_tag);
|
|
if (cmd == BH_NO_CMD) { // error
|
|
*pvalue = BH_CMD_ERROR;
|
|
|
|
return FE_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
// get value from the flowcontroller
|
|
status = bh_get_send_rcv(info, cmd, str);
|
|
|
|
if (status != BH_SUCCESS) {
|
|
if ( info->errorcount < BH_MAX_ERROR ) {
|
|
if (info->bh_in_settings.detailed_msg) {
|
|
cm_msg(MERROR, "BH_get", "BH communication or command error.");
|
|
cm_msg_flush_buffer();
|
|
}
|
|
info->errorcount++;
|
|
}
|
|
info->readback_failure++;
|
|
|
|
if (info->readback_failure == BH_MAX_READBACK_FAILURE) {
|
|
info->readback_failure = 0;
|
|
// try to disconnect and reconnect the bus driver
|
|
if ((ss_time()-info->last_reconnect > BH_RECONNECTION_TIMEOUT) &&
|
|
info->bd_connected) {
|
|
|
|
// logout ets/eds before bus driver is freed
|
|
#ifdef HAVE_ETS
|
|
if (info->bh_in_settings.ets_in_use)
|
|
ets_logout(info->bd_info, BH_ETS_LOGOUT_SLEEP,
|
|
info->bh_in_settings.detailed_msg);
|
|
#endif
|
|
#ifdef HAVE_EDS
|
|
if (info->bh_in_settings.eds_in_use)
|
|
eds_logout(info->bd_info, BH_EDS_LOGOUT_SLEEP,
|
|
info->bh_in_settings.detailed_msg);
|
|
#endif
|
|
/* info->bd(CMD_EXIT, info->bd_info); */ // disconnect bus driver
|
|
if (info->bd_info) {
|
|
free(info->bd_info); info->bd_info = NULL;
|
|
}
|
|
|
|
cm_msg(MERROR, "BH_get", "Communication error: trying to disconnect and reconnect the "
|
|
"bus driver");
|
|
cm_msg_flush_buffer();
|
|
info->last_reconnect = ss_time();
|
|
info->bd_connected = 0;
|
|
}
|
|
}
|
|
return FE_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
// decode return hexcode string
|
|
status = bh_decode_number(str, decode_tag, err_msg, pvalue);
|
|
|
|
if (status != BH_SUCCESS) {
|
|
if ( info->errorcount < BH_MAX_ERROR ) {
|
|
if (info->bh_in_settings.detailed_msg)
|
|
cm_msg(MERROR, "BH_get", "%s", err_msg);
|
|
info->errorcount++;
|
|
}
|
|
*pvalue = info->last_valid_value[channel];
|
|
} else {
|
|
|
|
// rescale needle valve position from 0..2^24 - 1 to the interval 0..1
|
|
if (cmd == BH_VALVEOUT) {
|
|
*pvalue /= BH_MAX_NEEDLE_VALVE;
|
|
}
|
|
}
|
|
|
|
// channel readout changed or device is not initialized yet
|
|
diff = bh_afdiff(info->last_valid_value[tchannel],*pvalue);
|
|
if ((tchannel == channel)&&((diff > 0.001)||(info->startup_tag <= 1))) {
|
|
|
|
if (info->startup_tag <= 1) {
|
|
if (cmd == BH_CNTRLMODE) {
|
|
//
|
|
//*0 = setpoint = BUS setpoint -> also called save mode
|
|
//*1 = setpoint = analog input
|
|
// 2 = setpoint = master output (FLOW-BUS)*slave factor(FLOW-BUS)
|
|
//*3 = close valve
|
|
//*4 = controller idle (no reaction on sensor signal changes)
|
|
//*5 = testmode enable -> (select with par 70)
|
|
// 6 = tuningmode enable -> (select with par 79)
|
|
//*7 = setpoint = 100%
|
|
// 8 = purge valve (fully open)
|
|
//*9 = calibration mode enable -> (select with par 58)
|
|
// :
|
|
//*12 = setpoint = 0%
|
|
// :
|
|
// 18 = setpoint = RS232 setpoint -> bypass of save mode
|
|
|
|
if ((int)*pvalue == 0) {
|
|
cm_msg(MLOG,"","Input Channel [%d] \"%s\" is %d : \"Setpoint = BUS setpoint\"", tchannel,
|
|
info->bh_in_settings.name[tchannel], (int)*pvalue);
|
|
} else {
|
|
cm_msg(MLOG,"","Input Channel [%d] \"%s\" is %d : \"Unexpected setting of Control mode "
|
|
"parameter!\"", tchannel, info->bh_in_settings.name[tchannel], (int)*pvalue);
|
|
cm_msg(MERROR,"bh_get","*** Check the instruction manual for \"DDE Parameter 12 Control "
|
|
"mode\" ***");
|
|
}
|
|
} else if (cmd == BH_SETPOINT) {
|
|
cm_msg(MLOG,"","Input Channel [%d] \"%s\" initial value is %.3f", tchannel,
|
|
info->bh_in_settings.name[tchannel], *pvalue);
|
|
} else {
|
|
cm_msg(MLOG,"","Input Channel [%d] \"%s\" initial value is %.3f", tchannel,
|
|
info->bh_in_settings.name[tchannel], *pvalue);
|
|
}
|
|
} else {
|
|
if (cmd == BH_CNTRLMODE) {
|
|
cm_msg(MLOG,"","Input Channel [%d] \"%s\" changed from %d to %d", tchannel,
|
|
info->bh_in_settings.name[tchannel], (int) info->last_valid_value[tchannel],
|
|
(int)*pvalue);
|
|
} else if (cmd == BH_SETPOINT) {
|
|
cm_msg(MLOG,"","Input Channel[%d] \"%s\" changed from %.3f to %.3f", tchannel,
|
|
info->bh_in_settings.name[tchannel],
|
|
info->last_valid_value[tchannel], *pvalue);
|
|
} else {
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"","Input Channel[%d] \"%s\" changed from %.3f to %.3f", tchannel,
|
|
info->bh_in_settings.name[tchannel],
|
|
info->last_valid_value[tchannel], *pvalue);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
previous_value_tchannel = info->last_valid_value[tchannel];
|
|
info->last_valid_value[tchannel] = *pvalue;
|
|
info->readback_failure = 0;
|
|
|
|
// readout was actually done for DAC channel following the Flow l/min channel
|
|
if (channel+1 == tchannel) {
|
|
|
|
// avoid division by 0
|
|
if (info->bh_in_settings.Flow_lpm_to_DAC_Scale > 0.001) {
|
|
float flowlpmin;
|
|
|
|
// calculate Flow or FlowSP l/min from DAC or DAC SP
|
|
flowlpmin = (*pvalue - info->bh_in_settings.FlowDAC_Offset)
|
|
/info->bh_in_settings.Flow_lpm_to_DAC_Scale + info->bh_in_settings.Flow_lpm_Offset;
|
|
|
|
// return Flow calculated from DAC for this channel (with 3 decimals)
|
|
*pvalue = rintf(flowlpmin*1000)/1000.0;
|
|
|
|
// log changes or startup values
|
|
diff = bh_afdiff(info->last_valid_value[channel], *pvalue);
|
|
if ((diff > 0.001) || (info->startup_tag <= 1)) {
|
|
if (info->startup_tag <= 1) {
|
|
if (cmd == BH_SETPOINT) {
|
|
cm_msg(MLOG,"","Input Channel[%d] \"%s\" initial value is %.0f (%.1f%%)", tchannel,
|
|
info->bh_in_settings.name[tchannel],
|
|
info->last_valid_value[tchannel],
|
|
(float) info->last_valid_value[tchannel]/320.0);
|
|
cm_msg(MLOG,"","Input Channel[%d] \"%s\" initial value is %.3f l/min", channel,
|
|
info->bh_in_settings.name[channel], *pvalue);
|
|
} else {
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"","Input Channel[%d] \"%s\" initial value is %.0f (%.1f%%)", tchannel,
|
|
info->bh_in_settings.name[tchannel],
|
|
info->last_valid_value[tchannel],
|
|
(float) info->last_valid_value[tchannel]/320.0);
|
|
cm_msg(MLOG,"","Input Channel[%d] \"%s\" initial value is %.3f l/min", channel,
|
|
info->bh_in_settings.name[channel], *pvalue);
|
|
#endif
|
|
}
|
|
} else {
|
|
if (cmd == BH_SETPOINT) {
|
|
cm_msg(MLOG,"","Input Channel[%d] \"%s\" changed from %.0f (%.1f%%) to %.0f (%.1f%%)",
|
|
tchannel, info->bh_in_settings.name[tchannel], previous_value_tchannel,
|
|
(float)previous_value_tchannel/320.0, info->last_valid_value[tchannel],
|
|
(float) info->last_valid_value[tchannel]/320.0);
|
|
cm_msg(MLOG,"","Input Channel[%d] \"%s\" changed from %.3f to %.3f l/min", channel,
|
|
info->bh_in_settings.name[channel], info->last_valid_value[channel], *pvalue);
|
|
} else {
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"","Input Channel[%d] \"%s\" changed from %.0f (%.1f%%) to %.0f (%.1f%%)",
|
|
tchannel, info->bh_in_settings.name[tchannel], previous_value_tchannel,
|
|
(float)previous_value_tchannel/320.0, info->last_valid_value[tchannel],
|
|
(float) info->last_valid_value[tchannel]/320.0);
|
|
cm_msg(MLOG,"","Input Channel[%d] \"%s\" changed from %.3f to %.3f l/min", channel,
|
|
info->bh_in_settings.name[channel],info->last_valid_value[channel],*pvalue);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
info->last_valid_value[channel] = *pvalue;
|
|
}
|
|
}
|
|
if (channel == BH_IN_CHANNELS -1)
|
|
ss_sleep(100);
|
|
|
|
#ifdef MIDEBUGF1
|
|
if (pvalue)
|
|
cm_msg(MLOG,"","<<bh_get(channel=%d, *pvalue=%f)", channel, *pvalue);
|
|
#endif
|
|
cm_msg_flush_buffer();
|
|
return FE_SUCCESS;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------*/
|
|
INT bh_get_show_param(BH_INFO *info, INT cmd, INT decode_tag, char *para_name) {
|
|
int status;
|
|
char reply[128], error_msg[128];
|
|
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"",">>bh_get_show_param(cmd=%d, decode_tag=%d, para_name=%s)", cmd,
|
|
decode_tag, para_name);
|
|
#endif
|
|
// check if there was a startup error
|
|
if ( info->startup_error ) {
|
|
ss_sleep(10); // to keep CPU load low when Run active
|
|
return FE_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
|
|
// get value from the flowcontroller
|
|
status = bh_get_send_rcv(info, cmd, reply);
|
|
if (status == BH_SUCCESS) {
|
|
// string was returned
|
|
if (decode_tag == BH_STRING) {
|
|
char result[128];
|
|
|
|
status = bh_decode_string(reply, error_msg, result);
|
|
if (status == BH_SUCCESS) {
|
|
cm_msg(MLOG,"","DDE Parameter %d : %s = %s", cmd, para_name, result);
|
|
} else {
|
|
cm_msg(MERROR,"bh_get_show_param","cmd=%d, para_name=%s: bh_decode_string() "
|
|
"returned : %s", cmd, para_name, error_msg);
|
|
}
|
|
|
|
// char, integer or float
|
|
// BH_CHAR, BH_INTEGER, BH_FLOAT, BH_LONG
|
|
} else {
|
|
float result;
|
|
|
|
result = -1.f;
|
|
status = bh_decode_number(reply, decode_tag, error_msg, &result);
|
|
if (status == BH_SUCCESS) {
|
|
if ((decode_tag == BH_FLOAT) || (decode_tag == BH_LONG)) {
|
|
cm_msg(MLOG,"","DDE Parameter %d : %s = %f", cmd, para_name, result);
|
|
} else if (decode_tag == BH_CHAR) {
|
|
cm_msg(MLOG,"","DDE Parameter %d : %s = %d = 0x0%x", cmd, para_name, (int)result, (unsigned int)result);
|
|
} else {
|
|
cm_msg(MLOG,"","DDE Parameter %d : %s = %d", cmd, para_name, (int)result);
|
|
}
|
|
} else {
|
|
cm_msg(MERROR,"bh_get_show_param","cmd=%d, para_name=%s: bh_decode_number() "
|
|
"returned : %s", cmd, para_name, error_msg);
|
|
cm_msg(MLOG,"","DDE Parameter %d : %s = ???", cmd, para_name);
|
|
}
|
|
}
|
|
} else {
|
|
cm_msg(MLOG,"","DDE Parameter %d : %s = ???", cmd, para_name);
|
|
}
|
|
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"","<<bh_get_show_param()");
|
|
#endif
|
|
cm_msg_flush_buffer();
|
|
return BH_SUCCESS;
|
|
}
|
|
/*----------------------------------------------------------------------------------*/
|
|
|
|
INT bh_show_param(BH_INFO *info) {
|
|
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"",">>sh_show_param()");
|
|
#endif
|
|
|
|
bh_get_show_param(info, BH_SENSORTYPE, BH_CHAR, "Sensor type"); // 22
|
|
bh_get_show_param(info, BH_FLUIDNAME, BH_STRING, "Fluid name"); // 25 10char
|
|
bh_get_show_param(info, BH_VALVEOFFSET,BH_INTEGER,"Valve offset"); // 59
|
|
bh_get_show_param(info, BH_IOSTATUS, BH_CHAR, "IO status"); // 86
|
|
bh_get_show_param(info, BH_DEVICETYPE, BH_STRING, "Device type"); // 90 6 char
|
|
bh_get_show_param(info, BH_MODELNUM, BH_STRING, "BHTModel number"); // 91 10 char?
|
|
bh_get_show_param(info, BH_SERIALNUM, BH_STRING, "Serial number"); // 92 10 char?
|
|
bh_get_show_param(info, BH_VERSION, BH_STRING, "Firmware version");// 105 6 char
|
|
bh_get_show_param(info, BH_TEMPERATURE,BH_FLOAT, "Temperature"); // 142
|
|
//bh_get_show_param(info, BH_CALIBVOLLT, BH_FLOAT, "Calibrated Volume"); // 145 not relevant?
|
|
//bh_get_show_param(info, BH_PRESSURE, BH_FLOAT, "Pressure"); // 143 not implemented?
|
|
bh_get_show_param(info, BH_CONTRFEAT, BH_CHAR, "Controller features");
|
|
bh_get_show_param(info, BH_PID_KP, BH_FLOAT, "PID factor Kp");
|
|
bh_get_show_param(info, BH_PID_TI, BH_FLOAT, "PID factor Ti");
|
|
bh_get_show_param(info, BH_PID_TD, BH_FLOAT, "PID factor Td");
|
|
//bh_get_show_param(info, BH_FLUIDTEMP, BH_FLOAT, "Fluid Temperature"); // 181 not relevant?
|
|
|
|
#ifdef MIDEBUGF1
|
|
cm_msg(MLOG,"","<<bh_show_param()");
|
|
#endif
|
|
|
|
return BH_SUCCESS;
|
|
}
|
|
/*----------------------------------------------------------------------------------*/
|
|
/*!
|
|
* <p>at startup, after initialization of the DD, this routine allows to write
|
|
* default names of the in-channels into the ODB.</p>
|
|
* <p><b>Return:</b> FE_SUCCESS
|
|
* \param info is a pointer to the DD specific info structure
|
|
* \param channel of the name to be set
|
|
* \param name pointer to the ODB name
|
|
*/
|
|
INT bh_in_get_label(BH_INFO *info, INT channel, char *name) {
|
|
if (name) {
|
|
*name = '\0';
|
|
if ((channel >= 0) && (channel < BH_IN_CHANNELS)) {
|
|
strncpy(name, info->bh_in_settings.name[channel], NAME_LENGTH-1);
|
|
*(name+NAME_LENGTH-1) = '\0';
|
|
} else {
|
|
cm_msg(MERROR,"bh_in_get_label","Channel number out of range 0 - %d",BH_IN_CHANNELS-1);
|
|
}
|
|
} else {
|
|
cm_msg(MERROR,"bh_in_get_label","NULL pointer to return label");
|
|
}
|
|
cm_msg_flush_buffer();
|
|
return FE_SUCCESS;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/*!
|
|
* <p>at startup, after initialization of the DD, this routine allows to write
|
|
* default thresholds of the channels into the ODB.</p>
|
|
* <p><b>Return:</b> FE_SUCCESS
|
|
* \param info is a pointer to the DD specific info structure
|
|
* \param channel of the threshold to be set
|
|
* \param pvalue pointer to the returned threshold
|
|
*/
|
|
INT bh_in_get_default_threshold(BH_INFO * info, INT channel, float *pvalue)
|
|
{
|
|
if (pvalue == NULL) {
|
|
#ifdef MIDEBUGF2
|
|
cm_msg(MLOG, "", ">>bh_in_get_default_threshold(%d,NULL)", channel);
|
|
cm_msg_flush_buffer();
|
|
#endif
|
|
return FE_SUCCESS; // ----->>>>>>>>>>>>>!
|
|
}
|
|
#ifdef MIDEBUGF2
|
|
cm_msg(MLOG, "", ">>bh_in_get_default_threshold(%d)", channel);
|
|
#endif
|
|
if ((channel >= 0) && (channel < info->num_channels_in)) {
|
|
switch (channel) {
|
|
case 0: // Flow (l/min)
|
|
case 2: // Flow_SP (readback l/min)
|
|
*pvalue = 0.01f;
|
|
break;
|
|
case 1: // FlowDAC
|
|
case 3: // FlowDAC_SP (readback)
|
|
case 4: // ControlMode (readback)
|
|
*pvalue = 0.1f;
|
|
break;
|
|
case 5: // Temperature (C)
|
|
*pvalue = 0.001f;
|
|
break;
|
|
case 6: // ValvePosition(readback 0..1)
|
|
*pvalue = 0.0001f;
|
|
break;
|
|
|
|
default:
|
|
*pvalue = 0.1f;
|
|
}
|
|
} else {
|
|
#ifdef MIDEBUGF2
|
|
cm_msg(MLOG,"","<<bh_in_get_default_threshold(%d) Channel out of range |0 - %d|",
|
|
channel, info->num_channels_in-1);
|
|
#endif
|
|
}
|
|
|
|
#ifdef MIDEBUGF2
|
|
cm_msg(MLOG, "", "bh_in_get_default_threshold(%d,%f)", channel, *pvalue);
|
|
cm_msg_flush_buffer();
|
|
#endif
|
|
return FE_SUCCESS;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------*/
|
|
/*!
|
|
* <p>at startup, after initialization of the DD, this routine allows to write
|
|
* default names of the out-channels into the ODB.</p>
|
|
* <p><b>Return:</b> FE_SUCCESS
|
|
* \param info is a pointer to the DD specific info structure
|
|
* \param channel of the name to be set
|
|
* \param name pointer to the ODB name
|
|
*/
|
|
INT bh_out_get_label(BH_INFO *info, INT channel, char *name) {
|
|
if (name) {
|
|
if ((channel >= 0) && (channel < BH_OUT_CHANNELS)) {
|
|
strncpy(name, info->bh_out_settings.name[channel],NAME_LENGTH-1);
|
|
name[NAME_LENGTH-1] = '\0';
|
|
} else {
|
|
cm_msg(MERROR,"bh_out_get_label","Channel number out of range | 0 - %d |",BH_OUT_CHANNELS-1);
|
|
}
|
|
} else {
|
|
cm_msg(MERROR,"bh_out_get_label","NULL pointer to return label");
|
|
}
|
|
cm_msg_flush_buffer();
|
|
return FE_SUCCESS;
|
|
}
|
|
|
|
/*---- device driver entry point ---------------------------------------------------*/
|
|
INT bronkhorst_flowmeter_in(INT cmd, ...)
|
|
{
|
|
va_list argptr;
|
|
HNDLE hKey;
|
|
INT channel, status;
|
|
float *pvalue;
|
|
BH_INFO *info;
|
|
BH_INFO **pinfo;
|
|
char *name;
|
|
|
|
va_start(argptr, cmd);
|
|
status = FE_SUCCESS;
|
|
|
|
#ifdef MIDEBUGF3
|
|
cm_msg(MLOG,"",">>bronkhorst_flowmeter_in(cmd=%d)",cmd);
|
|
#endif
|
|
|
|
switch (cmd) {
|
|
case CMD_INIT: // 1
|
|
{
|
|
hKey = va_arg(argptr, HNDLE);
|
|
pinfo = va_arg(argptr, BH_INFO **);
|
|
channel = va_arg(argptr, INT);
|
|
va_arg(argptr, DWORD); // flags - currently not used
|
|
func_t *bd = va_arg(argptr, func_t *);
|
|
status = bh_in_init(hKey, pinfo, channel, bd);
|
|
}
|
|
break;
|
|
|
|
case CMD_EXIT: // 2
|
|
info = va_arg(argptr, BH_INFO *);
|
|
status = bh_exit(info);
|
|
break;
|
|
|
|
case CMD_GET: // 20
|
|
info = va_arg(argptr, BH_INFO *);
|
|
channel = va_arg(argptr, INT);
|
|
pvalue = va_arg(argptr, float*);
|
|
status = bh_get(info, channel, pvalue);
|
|
break;
|
|
|
|
case CMD_GET_LABEL: // 10
|
|
info = va_arg(argptr, BH_INFO *);
|
|
channel = va_arg(argptr, INT);
|
|
name = va_arg(argptr, char *);
|
|
status = bh_in_get_label(info, channel, name);
|
|
break;
|
|
|
|
case CMD_GET_THRESHOLD: // 6
|
|
info = va_arg(argptr, BH_INFO *);
|
|
channel = va_arg(argptr, INT);
|
|
pvalue = va_arg(argptr, float *);
|
|
status = bh_in_get_default_threshold(info, channel, pvalue);
|
|
break;
|
|
|
|
// case SET_LABEL: // 9 is not handled
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
va_end(argptr);
|
|
return status;
|
|
}
|
|
|
|
/************************************************************************/
|
|
|
|
INT bronkhorst_flowmeter_out(INT cmd, ...)
|
|
{
|
|
va_list argptr;
|
|
HNDLE hKey;
|
|
INT channel, status;
|
|
float value;
|
|
BH_INFO *info;
|
|
char *name;
|
|
|
|
va_start(argptr, cmd);
|
|
status = FE_SUCCESS;
|
|
|
|
#ifdef MIDEBUGF3
|
|
cm_msg(MLOG,"",">>bh_out(cmd=%d)",cmd);
|
|
#endif
|
|
|
|
switch (cmd) {
|
|
case CMD_INIT: // 1
|
|
{
|
|
hKey = va_arg(argptr, HNDLE);
|
|
BH_INFO **pinfo = va_arg(argptr, BH_INFO**);
|
|
channel = va_arg(argptr, INT);
|
|
va_arg(argptr, DWORD); // flags - currently not used
|
|
func_t *bd = va_arg(argptr, func_t *);
|
|
status = bh_out_init(hKey, pinfo, channel, bd);
|
|
}
|
|
break;
|
|
|
|
case CMD_SET: // 13
|
|
info = va_arg(argptr, BH_INFO*);
|
|
channel = va_arg(argptr, INT);
|
|
value = (float) va_arg(argptr, double);
|
|
status = bh_set(info, channel, value);
|
|
break;
|
|
|
|
// NO 9 SET_LABEL
|
|
|
|
case CMD_GET_LABEL: // 10
|
|
info = va_arg(argptr, BH_INFO*);
|
|
channel = va_arg(argptr, INT);
|
|
name = va_arg(argptr, char *);
|
|
status = bh_out_get_label(info, channel, name);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
va_end(argptr);
|
|
|
|
return status;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|