Initial working commit
This commit is contained in:
+246
@@ -0,0 +1,246 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveShortCaseStatements:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCaseColons: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments:
|
||||
Kind: Always
|
||||
OverEmptyLines: 0
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowBreakBeforeNoexceptSpecifier: Never
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortCompoundRequirementOnASingleLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BitFieldColonSpacing: Both
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterExternBlock: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakAdjacentStringLiterals: true
|
||||
BreakAfterAttributes: Leave
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakArrays: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: Always
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInlineASMColon: OnlyMultiline
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: "^ IWYU pragma:"
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: ".*"
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: "(Test)?$"
|
||||
IncludeIsMainSourceRegex: ""
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseBlocks: false
|
||||
IndentCaseLabels: false
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentRequiresClause: true
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertBraces: false
|
||||
InsertNewlineAtEOF: false
|
||||
InsertTrailingCommas: None
|
||||
IntegerLiteralSeparator:
|
||||
Binary: 0
|
||||
BinaryMinDigits: 0
|
||||
Decimal: 0
|
||||
DecimalMinDigits: 0
|
||||
Hex: 0
|
||||
HexMinDigits: 0
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
KeepEmptyLinesAtEOF: false
|
||||
LambdaBodyIndentation: Signature
|
||||
LineEnding: DeriveLF
|
||||
MacroBlockBegin: ""
|
||||
MacroBlockEnd: ""
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PackConstructorInitializers: BinPack
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakScopeResolution: 500
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
PPIndentWidth: -1
|
||||
QualifierAlignment: Leave
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: true
|
||||
RemoveBracesLLVM: false
|
||||
RemoveParentheses: Leave
|
||||
RemoveSemicolon: false
|
||||
RequiresClausePosition: OwnLine
|
||||
RequiresExpressionIndentation: OuterScope
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SkipMacroDefinitionBody: false
|
||||
SortIncludes: CaseSensitive
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: LexicographicNumeric
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeJsonColon: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
AfterForeachMacros: true
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: true
|
||||
AfterOverloadedOperator: false
|
||||
AfterPlacementOperator: true
|
||||
AfterRequiresInClause: false
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParens: Never
|
||||
SpacesInParensOptions:
|
||||
InCStyleCasts: false
|
||||
InConditionalStatements: false
|
||||
InEmptyParentheses: false
|
||||
Other: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Latest
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
VerilogBreakBetweenInstancePorts: true
|
||||
WhitespaceSensitiveMacros:
|
||||
- BOOST_PP_STRINGIZE
|
||||
- CF_SWIFT_NAME
|
||||
- NS_SWIFT_NAME
|
||||
- PP_STRINGIZE
|
||||
- STRINGIZE
|
||||
---
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
build
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
cmake_minimum_required(VERSION 3.03)
|
||||
|
||||
project(hvr800_scfe VERSION 0.1)
|
||||
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wformat=2
|
||||
-Wno-format-nonliteral
|
||||
-Wno-strict-aliasing
|
||||
-Wuninitialized
|
||||
-Wno-unused-function
|
||||
)
|
||||
|
||||
option(
|
||||
BUILD_FRONTEND
|
||||
"If ON, build the default frontend executable"
|
||||
OFF
|
||||
)
|
||||
|
||||
|
||||
set(
|
||||
DRIVERS
|
||||
$ENV{MIDASSYS}/drivers/bus/null.cxx
|
||||
$ENV{MIDASSYS}/drivers/class/multi.cxx
|
||||
$ENV{MIDASSYS}/drivers/class/hv.cxx
|
||||
$ENV{MIDASSYS}/mscb/src/mscb.cxx
|
||||
)
|
||||
|
||||
set(
|
||||
LIBS
|
||||
# -lz # compression library
|
||||
-lpthread
|
||||
-lutil
|
||||
-lrt # librt for real time guarantees (really just backwards compat)
|
||||
-ldl # libdl for dynamic loading
|
||||
$ENV{MIDASSYS}/lib/libmfe.a
|
||||
$ENV{MIDASSYS}/lib/libmidas.a
|
||||
)
|
||||
|
||||
################################################################################
|
||||
## Device Library
|
||||
################################################################################
|
||||
|
||||
add_library(
|
||||
hvr800
|
||||
device/hvr800.cxx
|
||||
${DRIVERS}
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
hvr800
|
||||
PROPERTY
|
||||
CXX_STANDARD 11
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
hvr800
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
PRIVATE
|
||||
$ENV{MIDASSYS}/drivers
|
||||
$ENV{MIDASSYS}/include
|
||||
$ENV{MIDASSYS}/mscb/include
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
hvr800
|
||||
${LIBS}
|
||||
)
|
||||
|
||||
################################################################################
|
||||
## Test Frontend
|
||||
################################################################################
|
||||
|
||||
if(${BUILD_FRONTEND})
|
||||
|
||||
add_executable(
|
||||
hvr800_fe
|
||||
frontend/hvr800_scfe.cxx
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
hvr800_fe
|
||||
PROPERTY
|
||||
CXX_STANDARD 11
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
hvr800_fe
|
||||
PRIVATE
|
||||
$ENV{MIDASSYS}/drivers
|
||||
$ENV{MIDASSYS}/include
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
hvr800_fe
|
||||
hvr800
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
# Running this executable for the first time "registers" it in the ODB
|
||||
add_custom_target(init_hvr800_scfe
|
||||
# The -e flag specifies the experiment name
|
||||
# <TARGET_FILE:frontend_name> is a generator expression which provided the full path to the frontend executable
|
||||
# Any errors returned by the frontend executable should be ignored
|
||||
COMMAND timeout --preserve-status 2s $<TARGET_FILE:hvr800_fe> -e ${MIDAS_EXPTAB_NAME} || true
|
||||
COMMENT "Initial run of frontend to register it in the ODB"
|
||||
)
|
||||
@@ -0,0 +1,69 @@
|
||||
# MSCB (Midas slow control bus) high voltage divider HVR 800 voltage
|
||||
|
||||
This repository contains the driver code and "default" Midas frontend for the
|
||||
Midas slow control bus (MSCB) high voltage divider.
|
||||
|
||||
## Requirements
|
||||
|
||||
Requires a Midas installation with the environment variable `MIDASSYS` pointing
|
||||
to the built Midas artifacts and headers.
|
||||
|
||||
## Build
|
||||
|
||||
Clone this repository, enter the cloned directory, and then build via CMake.
|
||||
|
||||
```bash
|
||||
cmake -S "$(pwd)" -B <directory-to-build-in> -DBUILD_FRONTEND=ON
|
||||
cmake --build <directory-to-build-in> --clean-first -- -j8
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
/build/driver/hvr800_fe -e flame
|
||||
```
|
||||
|
||||
## Including in Custom Frontend
|
||||
|
||||
To include this driver in a custom frontend, you should ensure the environment
|
||||
variable `MIDASSYS` points to your system install and include a snippet in your
|
||||
`CMakeLists.txt` similar to the following:
|
||||
|
||||
```CMake
|
||||
# If the path to the hvr800 repository is outside of the frontend
|
||||
# repository, you also need to provide a location for the hvr800
|
||||
# artifacts as a second argument to `add_subdirectory`
|
||||
# e.g. `./device/hvr800`
|
||||
add_subdirectory(
|
||||
<path-to-hvr800-repository>
|
||||
)
|
||||
|
||||
add_executable(
|
||||
<frontend-name>
|
||||
<frontend-code-path-1>
|
||||
<frontend-code-path-2>
|
||||
:
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
<frontend-name>
|
||||
PROPERTY
|
||||
CXX_STANDARD 11
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
<frontend-name>
|
||||
PRIVATE
|
||||
$ENV{MIDASSYS}/drivers
|
||||
$ENV{MIDASSYS}/include
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
<frontend-name>
|
||||
hvr800
|
||||
<additional-library-1>
|
||||
<additional-library-2>
|
||||
:
|
||||
)
|
||||
```
|
||||
@@ -0,0 +1,804 @@
|
||||
/*----------------------------------------------------------------------------
|
||||
|
||||
Name: hvr800.cxx
|
||||
Created by: Andreas Suter 2009/09/25
|
||||
Modified by: Jonas A. Krieger 2024/02/12 (ported to c++)
|
||||
|
||||
Contents: MIDAS device driver declaration for the MSCB high voltage
|
||||
dividers hvr_800.
|
||||
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
#include "midas.h"
|
||||
#include "mfe.h"
|
||||
#include "msystem.h"
|
||||
#include "mscb.h"
|
||||
|
||||
#include "hvr800.h"
|
||||
|
||||
// --------- to handle error messages ------------------------------
|
||||
|
||||
#define HVR800_INIT_ERROR -2 //!< tag: initializing error
|
||||
|
||||
#define HVR800_MAX_ERROR 5 //!< maximum number of error messages
|
||||
#define HVR800_DELTA_TIME_ERROR 600 //!< reset error counter after DELTA_TIME_ERROR seconds
|
||||
|
||||
// ----------- HVR800 related infos ---------------------------------
|
||||
//! MSCB debug flag
|
||||
#define MSCB_DEBUG FALSE
|
||||
|
||||
// HVR800 offsets ---------------------------------------------------
|
||||
#define HVR800_CONTROL 0
|
||||
#define HVR800_VDEMAND 1
|
||||
#define HVR800_VMEAS 2
|
||||
#define HVR800_IMEAS 3
|
||||
#define HVR800_STATUS 4
|
||||
#define HVR800_TRIPCNT 5
|
||||
#define HVR800_RAMPUP 6
|
||||
#define HVR800_RAMPDOWN 7
|
||||
#define HVR800_VLIMIT 8
|
||||
#define HVR800_ILIMIT 9
|
||||
#define HVR800_RILIMIT 10
|
||||
#define HVR800_TRIPMAX 11
|
||||
#define HVR800_TRIPTIME 12
|
||||
|
||||
// HVR800 Control Bits ----------------------------------------------
|
||||
#define HVR800_CTRL_HV_ON 0x01
|
||||
#define HVR800_CTRL_REGULATION 0x02
|
||||
#define HVR800_CTRL_IDLE 0x04
|
||||
|
||||
/*!
|
||||
* <p>Stores all the parameters the device driver needs.
|
||||
*/
|
||||
typedef struct {
|
||||
BOOL enabled; //!< flag indicating if the device is enabled or disabled
|
||||
INT detailed_msg; //!< flag indicating if detailed status/error messages are wanted
|
||||
char port[NAME_LENGTH]; //!< MSCB port, e.g. /dev/parport0 or usb1
|
||||
char pwd[NAME_LENGTH]; //!< MSCB password for MSCB ethernet modules
|
||||
INT group_addr; //!< group address within the MSCB
|
||||
INT node_addr; //!< node address of the first HV channel within the MSCB
|
||||
char name[NAME_LENGTH]; //!< name of the hvr_800 card
|
||||
INT odb_offset; //!< HV channel offset within ODB
|
||||
} HVR800_SETTINGS;
|
||||
|
||||
//! Initializing string for the struct HVR800_SETTINGS
|
||||
#define HVR800_SETTINGS_STR "\
|
||||
Enabled = BOOL : 0\n\
|
||||
Detailed Messages = INT : 0\n\
|
||||
MSCB Port = STRING : [32] usb1\n\
|
||||
MSCB Pwd = STRING : [32]\n\
|
||||
Group Addr = INT : 800\n\
|
||||
Node Addr = INT : 1\n\
|
||||
HVR800 Name = STRING : [32] HVR800_1\n\
|
||||
HV ODB Offset = INT : 0\n\
|
||||
"
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/*!
|
||||
* <p>Variable set of a hvr800 channel.
|
||||
*
|
||||
* <p>The control byte can be or'ed with the following values:
|
||||
* - 0x0 HV off
|
||||
* - 0x1 HV on
|
||||
* - 0x2 HV regulated
|
||||
* - 0x4 HV idle
|
||||
*
|
||||
* <p>The status byte can be or'ed with the following states:
|
||||
* - 0x00 happy (??)
|
||||
* - 0x01 negative (??)
|
||||
* - 0x02 low current
|
||||
* - 0x04 ramping up
|
||||
* - 0x08 ramping down
|
||||
* - 0x10 voltage limit reached
|
||||
* - 0x20 current limit reached
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char control; //!< control tag
|
||||
float u_demand; //!< demand HV in (V)
|
||||
float u_meas; //!< measured HV in (V)
|
||||
float i_meas; //!< measured current in (uA)
|
||||
unsigned char status; //!< status tag
|
||||
unsigned char trip_cnt; //!< trip counter
|
||||
|
||||
float ramp_up; //!< ramp up speed in (V/s)
|
||||
float ramp_down; //!< ramp down speed in (V/s)
|
||||
float u_limit; //!< voltage limit in (V)
|
||||
float i_limit; //!< current limit in (uA)
|
||||
float ri_limit; //!< ??
|
||||
unsigned char trip_max; //!< maximal allowed number of HV trips
|
||||
unsigned char trip_time; //!< ??
|
||||
|
||||
unsigned char cached; //!< cache flag
|
||||
} HVR800_NODE_VARS;
|
||||
|
||||
|
||||
//! This structure contains private variables for the device driver.
|
||||
typedef struct {
|
||||
HVR800_SETTINGS settings; //!< stores the internal DD settings
|
||||
HVR800_NODE_VARS *node_vars; //!< stores the variables of all HVR800 node
|
||||
INT fd; //!< MSCB file desciptor
|
||||
INT errcount; //!< error counter in order not to flood the message queue
|
||||
INT startup_error; //!< initializer error tag, if set, hvr800_get and hvr800_set won't do anything
|
||||
DWORD lasterrtime; //!< last error time stamp
|
||||
} HVR800_INFO;
|
||||
|
||||
|
||||
// device driver support routines -------------------------------------------------
|
||||
/*!
|
||||
* <p>
|
||||
*
|
||||
* \param info
|
||||
* \param channel
|
||||
*/
|
||||
INT hvr800_read_all(HVR800_INFO* info, int channel)
|
||||
{
|
||||
int size, status;
|
||||
unsigned char buffer[256], *pbuf;
|
||||
|
||||
size = sizeof(buffer);
|
||||
status = mscb_read_range(info->fd, info->settings.node_addr+channel, 0, 12, buffer, &size);
|
||||
if (status != MSCB_SUCCESS) {
|
||||
cm_msg(MERROR, "hvr800_read_all",
|
||||
"Cannot access MSCB HVR800 address \"%d\". Check power and connection.",
|
||||
info->settings.node_addr);
|
||||
return FE_ERR_HW;
|
||||
}
|
||||
|
||||
/* decode variables from buffer */
|
||||
pbuf = buffer;
|
||||
info->node_vars[channel].control = *((unsigned char *)pbuf); // 0
|
||||
pbuf += sizeof(char);
|
||||
DWORD_SWAP(pbuf);
|
||||
info->node_vars[channel].u_demand = *((float *)pbuf); // 1
|
||||
pbuf += sizeof(float);
|
||||
DWORD_SWAP(pbuf);
|
||||
info->node_vars[channel].u_meas = *((float *)pbuf); // 2
|
||||
pbuf += sizeof(float);
|
||||
DWORD_SWAP(pbuf);
|
||||
info->node_vars[channel].i_meas = *((float *)pbuf); // 3
|
||||
pbuf += sizeof(float);
|
||||
info->node_vars[channel].status = *((unsigned char *)pbuf); // 4
|
||||
pbuf += sizeof(char);
|
||||
info->node_vars[channel].trip_cnt = *((unsigned char *)pbuf); // 5
|
||||
pbuf += sizeof(char);
|
||||
DWORD_SWAP(pbuf);
|
||||
info->node_vars[channel].ramp_up = *((float *)pbuf); // 6
|
||||
pbuf += sizeof(float);
|
||||
DWORD_SWAP(pbuf);
|
||||
info->node_vars[channel].ramp_down = *((float *)pbuf); // 7
|
||||
pbuf += sizeof(float);
|
||||
DWORD_SWAP(pbuf);
|
||||
info->node_vars[channel].u_limit = *((float *)pbuf); // 8
|
||||
pbuf += sizeof(float);
|
||||
DWORD_SWAP(pbuf);
|
||||
info->node_vars[channel].i_limit = *((float *)pbuf); // 9
|
||||
pbuf += sizeof(float);
|
||||
DWORD_SWAP(pbuf);
|
||||
info->node_vars[channel].ri_limit = *((float *)pbuf); // 10
|
||||
pbuf += sizeof(float);
|
||||
info->node_vars[channel].trip_max = *((unsigned char *)pbuf); // 11
|
||||
pbuf += sizeof(char);
|
||||
info->node_vars[channel].trip_time = *((unsigned char *)pbuf); // 12
|
||||
|
||||
/* mark voltage/current as valid in cache */
|
||||
info->node_vars[channel].cached = 1;
|
||||
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
//---- device driver routines --------------------------------------
|
||||
/*!
|
||||
* <p>Initializes the thermo element MSCB device driver, i.e. generates all the necessary
|
||||
* structures in the ODB if necessary, and initializes the MSCB. Furthermore it makes
|
||||
* some consitency checks to verify that the addressed module is indeed a thermo element
|
||||
* MSCB card.</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)
|
||||
*/
|
||||
INT hvr800_init(HNDLE hKey, HVR800_INFO **pinfo, INT channels)
|
||||
{
|
||||
INT status, size;
|
||||
INT i;
|
||||
HNDLE hDB, hkeydd;
|
||||
MSCB_INFO node_info;
|
||||
HVR800_INFO *info;
|
||||
|
||||
// allocate info structure
|
||||
info = (HVR800_INFO *) calloc(1, sizeof(HVR800_INFO));
|
||||
info->node_vars = (HVR800_NODE_VARS *) calloc(channels, sizeof(HVR800_NODE_VARS));
|
||||
*pinfo = info;
|
||||
|
||||
cm_get_experiment_database(&hDB, NULL);
|
||||
|
||||
// create HVR800 settings record
|
||||
status = db_create_record(hDB, hKey, "DD/HVR800", HVR800_SETTINGS_STR);
|
||||
if ((status != DB_SUCCESS) && (status != DB_OPEN_RECORD)) {
|
||||
cm_msg(MERROR, "hvr800_init", "hvr800_init: Error creating DD/HVR800 record in ODB, status=%d", status);
|
||||
cm_yield(0);
|
||||
return FE_ERR_ODB;
|
||||
}
|
||||
|
||||
db_find_key(hDB, hKey, "DD/HVR800", &hkeydd);
|
||||
size = sizeof(info->settings);
|
||||
db_get_record(hDB, hkeydd, &info->settings, &size, 0);
|
||||
|
||||
// initialize driver
|
||||
info->errcount = 0;
|
||||
info->startup_error = 0;
|
||||
info->lasterrtime = ss_time();
|
||||
|
||||
if (!info->settings.enabled) {
|
||||
cm_msg(MINFO, "hvr800_init", "hvr800_init: %s not enabled", info->settings.name);
|
||||
cm_yield(0);
|
||||
info->startup_error = 1;
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
// initialize MSCB
|
||||
info->fd = mscb_init(info->settings.port, sizeof(info->settings.port), info->settings.pwd, MSCB_DEBUG);
|
||||
if (info->fd < 0) {
|
||||
cm_msg(MINFO, "hvr800_init", "hvr800_init: Couldn't initialize MSCB port %s, Error no: %d",
|
||||
info->settings.port, info->fd);
|
||||
cm_yield(0);
|
||||
info->startup_error = 1;
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
// check first node
|
||||
status = mscb_info(info->fd, info->settings.node_addr, &node_info);
|
||||
if (status != MSCB_SUCCESS) {
|
||||
cm_msg(MINFO, "hvr800_init", "Cannot access HVR node at address \"%d\". Please check cabling and power.",
|
||||
info->settings.node_addr);
|
||||
cm_yield(0);
|
||||
info->startup_error = 1;
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
// check if it is a HVR800
|
||||
if (strcmp(node_info.node_name, "HVR-800") != 0) {
|
||||
cm_msg(MINFO, "hvr800_init",
|
||||
"Found unexpected node \"%s\" at address \"%d\".",
|
||||
node_info.node_name, info->settings.node_addr);
|
||||
cm_yield(0);
|
||||
info->startup_error = 1;
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
// read all values from the HVR800 devices
|
||||
for (i=0; i<channels; i++) {
|
||||
status = hvr800_read_all(info, i);
|
||||
if (status != FE_SUCCESS) {
|
||||
info->startup_error = 1;
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// turn on the HV main switch
|
||||
flag = HVR800_CTRL_HV_ON | HVR800_CTRL_REGULATION;
|
||||
mscb_write_group(info->fd, 800, 0, &flag, 1);
|
||||
*/
|
||||
|
||||
cm_msg(MINFO, "hvr800_init", "hvr800_init: %s initialized", info->settings.name);
|
||||
cm_yield(0);
|
||||
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/*!
|
||||
* <p>terminates the MSCB and free's the memory allocated for the DD info structure.</p>
|
||||
*
|
||||
* <p><b>Return:</b> FE_SUCCESS</p>
|
||||
*
|
||||
* \param info is a pointer to the DD specific info structure
|
||||
*/
|
||||
INT hvr800_exit(HVR800_INFO *info)
|
||||
{
|
||||
// call EXIT function of MSCB driver, usually closes device
|
||||
if (!info->startup_error)
|
||||
mscb_exit(info->fd);
|
||||
|
||||
free(info->node_vars);
|
||||
free(info);
|
||||
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/*!
|
||||
* <p>set a high voltage value of a hvr_800 channel.</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 high voltage value in (kV) to be set
|
||||
*/
|
||||
INT hvr800_set(HVR800_INFO *info, INT channel, float value)
|
||||
{
|
||||
INT status;
|
||||
unsigned char hv_on_off;
|
||||
float mscb_value;
|
||||
|
||||
if ( info->startup_error ) {
|
||||
ss_sleep(10);
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
// set HV value
|
||||
mscb_value = fabs(value); // V
|
||||
status=mscb_write(info->fd, (unsigned short) (info->settings.node_addr+channel),
|
||||
(unsigned char) HVR800_VDEMAND, &mscb_value, 4);
|
||||
|
||||
// check if it is necessay to switch HV on/off
|
||||
if (value == 0.0) { // demand HV==0 -> switch HV off
|
||||
if ((info->node_vars[channel].control & HVR800_CTRL_HV_ON) != 0) { // HV still on, hence switch it off
|
||||
hv_on_off = HVR800_CTRL_REGULATION;
|
||||
status=mscb_write(info->fd, (unsigned short) (info->settings.node_addr+channel),
|
||||
(unsigned char) HVR800_CONTROL, &hv_on_off, 1);
|
||||
}
|
||||
} else {
|
||||
if ((info->node_vars[channel].control & HVR800_CTRL_HV_ON) == 0) { // HV has been off so far, hence switch it on
|
||||
hv_on_off = HVR800_CTRL_HV_ON | HVR800_CTRL_REGULATION;
|
||||
status=mscb_write(info->fd, (unsigned short) (info->settings.node_addr+channel),
|
||||
(unsigned char) HVR800_CONTROL, &hv_on_off, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/*!
|
||||
* <p>get a high voltage value from a hvr_800 channel.</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 hvr800_get(HVR800_INFO *info, INT channel, float *pvalue)
|
||||
{
|
||||
INT status, size;
|
||||
DWORD nowtime, difftime;
|
||||
unsigned char buffer[256], *pbuf;
|
||||
|
||||
// error timeout facility
|
||||
nowtime = ss_time();
|
||||
difftime = nowtime - info->lasterrtime;
|
||||
if ( difftime > HVR800_DELTA_TIME_ERROR ) {
|
||||
info->errcount = 0;
|
||||
info->lasterrtime = ss_time();
|
||||
}
|
||||
|
||||
// check if there was a startup error
|
||||
if ( info->startup_error ) {
|
||||
*pvalue = (float) HVR800_INIT_ERROR;
|
||||
ss_sleep(10); // to keep CPU load low when Run active
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
// check if the value was previously read by hvr800_read_all
|
||||
if (info->node_vars[channel].cached) {
|
||||
*pvalue = info->node_vars[channel].u_meas;
|
||||
info->node_vars[channel].cached = 0;
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
// read voltage and current at the same time
|
||||
size = sizeof(buffer);
|
||||
status = mscb_read_range(info->fd, info->settings.node_addr+channel, HVR800_CONTROL, HVR800_IMEAS, buffer, &size);
|
||||
if (status != MSCB_SUCCESS) {
|
||||
info->errcount++;
|
||||
if (info->errcount < HVR800_MAX_ERROR) {
|
||||
cm_msg(MINFO, "hvr800_get",
|
||||
"Cannot access MSCB HVR address \"%d\". Check power and connection.",
|
||||
info->settings.node_addr+channel);
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
// decode variables from buffer
|
||||
pbuf = buffer;
|
||||
info->node_vars[channel].control = *((unsigned char *)pbuf); // 0
|
||||
pbuf += sizeof(char);
|
||||
DWORD_SWAP(pbuf);
|
||||
info->node_vars[channel].u_demand = *((float *)pbuf); // 1
|
||||
pbuf += sizeof(float);
|
||||
DWORD_SWAP(pbuf);
|
||||
info->node_vars[channel].u_meas = *((float *)pbuf); // 2
|
||||
pbuf += sizeof(float);
|
||||
DWORD_SWAP(pbuf);
|
||||
info->node_vars[channel].i_meas = *((float *)pbuf); // 3
|
||||
|
||||
|
||||
*pvalue = info->node_vars[channel].u_meas;
|
||||
|
||||
|
||||
|
||||
ss_sleep(10); // to keep CPU load low
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/*!
|
||||
* <p>sets the current limit of a channel of the hvr_800's.
|
||||
*
|
||||
* <p><b>return:</b> FE_SUCCESS</p>
|
||||
*
|
||||
* \param info is a pointer to the DD specific info structure.
|
||||
* \param channel is the channel number of the nhq
|
||||
* \param limit is the current limit value
|
||||
*/
|
||||
INT hvr800_set_current_limit(HVR800_INFO *info, INT channel, float limit)
|
||||
{
|
||||
INT status;
|
||||
DWORD nowtime, difftime;
|
||||
float mscb_value;
|
||||
|
||||
if ( info->startup_error ) {
|
||||
ss_sleep(10);
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
// error timeout facility
|
||||
nowtime = ss_time();
|
||||
difftime = nowtime - info->lasterrtime;
|
||||
if ( difftime > HVR800_DELTA_TIME_ERROR ) {
|
||||
info->errcount = 0;
|
||||
info->lasterrtime = ss_time();
|
||||
}
|
||||
|
||||
// set current limit value
|
||||
mscb_value = limit; // uA
|
||||
status=mscb_write(info->fd, (unsigned short) (info->settings.node_addr+channel),
|
||||
(unsigned char) HVR800_ILIMIT, &mscb_value, 4);
|
||||
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/*!
|
||||
* <p>sets the voltage limit of a channel of the hvr_800's.
|
||||
*
|
||||
* <p><b>return:</b> FE_SUCCESS</p>
|
||||
*
|
||||
* \param info is a pointer to the DD specific info structure.
|
||||
* \param channel is the channel number of the nhq
|
||||
* \param limit is the voltage limit value
|
||||
*/
|
||||
INT hvr800_set_voltage_limit(HVR800_INFO *info, INT channel, float limit)
|
||||
{
|
||||
INT status;
|
||||
DWORD nowtime, difftime;
|
||||
float mscb_value;
|
||||
|
||||
if ( info->startup_error ) {
|
||||
ss_sleep(10);
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
// error timeout facility
|
||||
nowtime = ss_time();
|
||||
difftime = nowtime - info->lasterrtime;
|
||||
if ( difftime > HVR800_DELTA_TIME_ERROR ) {
|
||||
info->errcount = 0;
|
||||
info->lasterrtime = ss_time();
|
||||
}
|
||||
|
||||
// set voltage limit value
|
||||
mscb_value = limit; // V
|
||||
status=mscb_write(info->fd, (unsigned short) (info->settings.node_addr+channel),
|
||||
(unsigned char) HVR800_VLIMIT, &mscb_value, 4);
|
||||
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/*!
|
||||
* <p>sets the ramping up speed in (kV/s) of a channel of the hvr_800's.
|
||||
* If the value is "0", ramping is performed as fast as possible.
|
||||
*
|
||||
* <p><b>return:</b> FE_SUCCESS</p>
|
||||
*
|
||||
* \param info is a pointer to the DD specific info structure.
|
||||
* \param channel is the channel number of the nhq
|
||||
* \param ramp is the ramping up value in (V/s)
|
||||
*/
|
||||
INT hvr800_set_rampup(HVR800_INFO *info, INT channel, float ramp)
|
||||
{
|
||||
INT status;
|
||||
DWORD nowtime, difftime;
|
||||
float mscb_value;
|
||||
|
||||
if ( info->startup_error ) {
|
||||
ss_sleep(10);
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
// error timeout facility
|
||||
nowtime = ss_time();
|
||||
difftime = nowtime - info->lasterrtime;
|
||||
if ( difftime > HVR800_DELTA_TIME_ERROR ) {
|
||||
info->errcount = 0;
|
||||
info->lasterrtime = ss_time();
|
||||
}
|
||||
|
||||
// set ramp up value
|
||||
mscb_value = ramp; // V/s
|
||||
status=mscb_write(info->fd, (unsigned short) (info->settings.node_addr+channel),
|
||||
(unsigned char) HVR800_RAMPUP, &mscb_value, 4);
|
||||
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/*!
|
||||
* <p>sets the ramping down speed in (V/s) of a channel of the hvr_800's.
|
||||
* If the value is "0", ramping is performed as fast as possible.
|
||||
*
|
||||
* <p><b>return:</b> FE_SUCCESS</p>
|
||||
*
|
||||
* \param info is a pointer to the DD specific info structure.
|
||||
* \param channel is the channel number of the nhq
|
||||
* \param ramp is the ramping up value in (V/s)
|
||||
*/
|
||||
INT hvr800_set_rampdown(HVR800_INFO *info, INT channel, float ramp)
|
||||
{
|
||||
INT status;
|
||||
DWORD nowtime, difftime;
|
||||
float mscb_value;
|
||||
|
||||
if ( info->startup_error ) {
|
||||
ss_sleep(10);
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
// error timeout facility
|
||||
nowtime = ss_time();
|
||||
difftime = nowtime - info->lasterrtime;
|
||||
if ( difftime > HVR800_DELTA_TIME_ERROR ) {
|
||||
info->errcount = 0;
|
||||
info->lasterrtime = ss_time();
|
||||
}
|
||||
|
||||
// set ramp down value
|
||||
mscb_value = ramp; // V/s
|
||||
status=mscb_write(info->fd, (unsigned short) (info->settings.node_addr+channel),
|
||||
(unsigned char) HVR800_RAMPDOWN, &mscb_value, 4);
|
||||
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/*!
|
||||
* <p>sets the trip time of a channel of the hvr_800's.
|
||||
*
|
||||
* <p><b>return:</b> FE_SUCCESS</p>
|
||||
*
|
||||
* \param info is a pointer to the DD specific info structure.
|
||||
* \param channel is the channel number of the nhq
|
||||
* \param trip_time is the trip time
|
||||
*/
|
||||
INT hvr800_set_triptime(HVR800_INFO *info, INT channel, float trip_time)
|
||||
{
|
||||
INT status;
|
||||
DWORD nowtime, difftime;
|
||||
unsigned char mscb_value;
|
||||
|
||||
if ( info->startup_error ) {
|
||||
ss_sleep(10);
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
// error timeout facility
|
||||
nowtime = ss_time();
|
||||
difftime = nowtime - info->lasterrtime;
|
||||
if ( difftime > HVR800_DELTA_TIME_ERROR ) {
|
||||
info->errcount = 0;
|
||||
info->lasterrtime = ss_time();
|
||||
}
|
||||
|
||||
// set trip time value
|
||||
mscb_value = (unsigned char) trip_time;
|
||||
status=mscb_write(info->fd, (unsigned short) (info->settings.node_addr+channel),
|
||||
(unsigned char) HVR800_TRIPTIME, &mscb_value, 1);
|
||||
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//---- device driver entry point ---------------------------------------------
|
||||
//----------------------------------------------------------------------------
|
||||
INT hvr800(INT cmd, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
HNDLE hKey;
|
||||
INT channel, status;
|
||||
float value, *pvalue;
|
||||
HVR800_INFO *info;
|
||||
|
||||
va_start(argptr, cmd);
|
||||
status = FE_SUCCESS;
|
||||
|
||||
switch (cmd) {
|
||||
case CMD_INIT:
|
||||
{
|
||||
hKey = va_arg(argptr, HNDLE);
|
||||
HVR800_INFO **pinfo = va_arg(argptr, HVR800_INFO**);
|
||||
channel = va_arg(argptr, INT);
|
||||
status = hvr800_init(hKey, pinfo, channel);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_EXIT:
|
||||
info = va_arg(argptr, HVR800_INFO *);
|
||||
status = hvr800_exit(info);
|
||||
break;
|
||||
|
||||
case CMD_SET:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
value = (float) va_arg(argptr, double);
|
||||
status = hvr800_set(info, channel, value);
|
||||
break;
|
||||
|
||||
case CMD_GET:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
pvalue = va_arg(argptr, float*);
|
||||
status = hvr800_get(info, channel, pvalue);
|
||||
break;
|
||||
|
||||
case CMD_GET_DEMAND:
|
||||
case CMD_GET_DEMAND_DIRECT:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
pvalue = va_arg(argptr, float*);
|
||||
*pvalue = info->node_vars[channel].u_demand; // V
|
||||
break;
|
||||
|
||||
case CMD_GET_CURRENT:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
pvalue = va_arg(argptr, float*);
|
||||
*pvalue = info->node_vars[channel].i_meas; // uA
|
||||
break;
|
||||
|
||||
case CMD_GET_LABEL:
|
||||
break;
|
||||
|
||||
case CMD_SET_LABEL:
|
||||
break;
|
||||
|
||||
|
||||
case CMD_GET_STATUS:
|
||||
//info = va_arg (argptr, void *);
|
||||
//channel = (WORD) va_arg (argptr, INT);
|
||||
//pstate = (DWORD *) va_arg (argptr, DWORD *);
|
||||
//status = dd_device_chStatus_get (info, channel, pstate);
|
||||
break;
|
||||
|
||||
case CMD_SET_CURRENT_LIMIT:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
value = (float) va_arg(argptr, double);
|
||||
status = hvr800_set_current_limit(info, channel, value);
|
||||
break;
|
||||
|
||||
case CMD_SET_VOLTAGE_LIMIT:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
value = (float) va_arg(argptr, double);
|
||||
status = hvr800_set_voltage_limit(info, channel, value);
|
||||
break;
|
||||
|
||||
case CMD_GET_VOLTAGE_LIMIT:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
pvalue = va_arg(argptr, float *);
|
||||
*pvalue = info->node_vars[channel].u_limit; // V
|
||||
break;
|
||||
|
||||
case CMD_GET_THRESHOLD:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
pvalue = va_arg(argptr, float*);
|
||||
*pvalue = 0.1f;
|
||||
break;
|
||||
|
||||
case CMD_GET_THRESHOLD_CURRENT:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
pvalue = va_arg(argptr, float*);
|
||||
*pvalue = 0.001f;
|
||||
break;
|
||||
|
||||
case CMD_GET_THRESHOLD_ZERO:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
pvalue = va_arg(argptr, float*);
|
||||
*pvalue = 0.02f;
|
||||
break;
|
||||
|
||||
case CMD_GET_CURRENT_LIMIT:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
pvalue = va_arg(argptr, float*);
|
||||
*pvalue = info->node_vars[channel].i_limit; // uA
|
||||
break;
|
||||
|
||||
case CMD_SET_RAMPUP:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
value = (float) va_arg(argptr, double);
|
||||
hvr800_set_rampup(info, channel, value);
|
||||
break;
|
||||
|
||||
case CMD_SET_RAMPDOWN:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
value = (float) va_arg(argptr, double);
|
||||
hvr800_set_rampdown(info, channel, value);
|
||||
break;
|
||||
|
||||
case CMD_GET_RAMPUP:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
pvalue = va_arg(argptr, float*);
|
||||
*pvalue = info->node_vars[channel].ramp_up;
|
||||
break;
|
||||
|
||||
case CMD_GET_RAMPDOWN:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
pvalue = va_arg(argptr, float*);
|
||||
*pvalue = info->node_vars[channel].ramp_down;
|
||||
break;
|
||||
|
||||
case CMD_SET_TRIP_TIME:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
value = (float) va_arg(argptr, double);
|
||||
hvr800_set_triptime(info, channel, value);
|
||||
break;
|
||||
|
||||
case CMD_GET_TRIP_TIME:
|
||||
info = va_arg(argptr, HVR800_INFO*);
|
||||
channel = va_arg(argptr, INT);
|
||||
pvalue = va_arg(argptr, float*);
|
||||
*pvalue = info->node_vars[channel].trip_time;
|
||||
break;
|
||||
|
||||
case CMD_STOP:
|
||||
status = FE_SUCCESS;
|
||||
break;
|
||||
|
||||
default:
|
||||
cm_msg(MERROR, "hvr800 device driver", "Received unkown command %d", cmd);
|
||||
status = FE_ERR_DRIVER;
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(argptr);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// end -----------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -0,0 +1,18 @@
|
||||
/*---------------------------------------------------------------------
|
||||
|
||||
Name: hvr800.h
|
||||
Created by: Andreas Suter 2009/09/25
|
||||
|
||||
Contents: MIDAS device driver declaration for the MSCB high voltage
|
||||
dividers hvr_500.
|
||||
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
/*---- device driver declaration -----------------------------------*/
|
||||
|
||||
/*!
|
||||
* <p>MIDAS device driver for the MSCB high voltage dividers hvr_800
|
||||
* (positive and negative).
|
||||
*/
|
||||
INT hvr800(INT cmd, ...);
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
#include "midas.h"
|
||||
#include "mfe.h"
|
||||
|
||||
#include "class/hv.h"
|
||||
#include "device/hvr800.h"
|
||||
#include "bus/null.h"
|
||||
|
||||
//-- Globals -------------------------------------------------------
|
||||
|
||||
//! The frontend name (client name) as seen by other MIDAS clients
|
||||
const char *frontend_name = "HVR800 high voltage divider";
|
||||
|
||||
//! The frontend file name, don't change it
|
||||
const char *frontend_file_name = __FILE__;
|
||||
|
||||
//! frontend_loop is called periodically if this variable is TRUE
|
||||
BOOL frontend_call_loop = FALSE; //TODO: enable HV monitoring.
|
||||
|
||||
//! a frontend status page is displayed with this frequency in ms
|
||||
INT display_period = 1000;
|
||||
|
||||
//! maximum event size produced by this frontend
|
||||
INT max_event_size = 10000;
|
||||
|
||||
//! maximum event size for fragmented events (EQ_FRAGMENTED)
|
||||
INT max_event_size_frag = 5*1024*1024;
|
||||
|
||||
//! buffer size to hold events
|
||||
INT event_buffer_size = 10*10000;
|
||||
|
||||
//! device driver list
|
||||
DEVICE_DRIVER hv_driver[] = {
|
||||
{ "HVR800_1", hvr800, 8, null, DF_PRIO_DEVICE | DF_HW_RAMP | DF_REPORT_STATUS},
|
||||
{ "HVR800_2", hvr800, 8, null, DF_PRIO_DEVICE | DF_HW_RAMP | DF_REPORT_STATUS},
|
||||
{ "HVR800_3", hvr800, 8, null, DF_PRIO_DEVICE | DF_HW_RAMP | DF_REPORT_STATUS},
|
||||
{ "HVR800_4", hvr800, 8, null, DF_PRIO_DEVICE | DF_HW_RAMP | DF_REPORT_STATUS},
|
||||
{ "HVR800_5", hvr800, 8, null, DF_PRIO_DEVICE | DF_HW_RAMP | DF_REPORT_STATUS},
|
||||
{ ""},//List needs to be terminated by an empty name. Otherwise, unallocated memory is accessed during initialization!
|
||||
};
|
||||
|
||||
/*!
|
||||
* equipment_common_overwrite:
|
||||
*
|
||||
* - If that flag is TRUE, then the contents of the "equipment" structure is copied to
|
||||
* the ODB on each start of the front-end.
|
||||
*
|
||||
* - If the flag is FALSE, then the ODB values are kept on the start of the front-end
|
||||
*/
|
||||
BOOL equipment_common_overwrite = FALSE;
|
||||
|
||||
//! equipment structure for the mfe.c
|
||||
EQUIPMENT equipment[] = {
|
||||
|
||||
{ "HV Detectors", // equipment name
|
||||
{203, 0, // event ID, trigger mask
|
||||
"SYSTEM", // event buffer
|
||||
EQ_SLOW, // equipment type
|
||||
0, // event source
|
||||
"FIXED", // format
|
||||
TRUE, // enabled
|
||||
RO_RUNNING |
|
||||
RO_TRANSITIONS, // read when running and on transitions
|
||||
30000, // read every 30 sec
|
||||
0, // stop run after this event limit
|
||||
0, // number of sub events
|
||||
1, // log history every event
|
||||
"", "", "",},
|
||||
cd_hv_read, // readout routine
|
||||
cd_hv, // class driver main routine
|
||||
hv_driver, // device driver list
|
||||
NULL, // init string
|
||||
},
|
||||
|
||||
{ "" }
|
||||
};
|
||||
|
||||
INT poll_event(INT source, INT count, BOOL test) {return CM_SUCCESS;};
|
||||
|
||||
INT interrupt_configure(INT cmd, INT source, POINTER_T adr) {return CM_SUCCESS;};
|
||||
|
||||
INT frontend_init()
|
||||
{
|
||||
// de-register run-transition notifications
|
||||
cm_deregister_transition(TR_START);
|
||||
cm_deregister_transition(TR_STOP);
|
||||
cm_deregister_transition(TR_PAUSE);
|
||||
cm_deregister_transition(TR_RESUME);
|
||||
|
||||
return CM_SUCCESS;
|
||||
}
|
||||
|
||||
INT frontend_exit()
|
||||
{
|
||||
return CM_SUCCESS;
|
||||
}
|
||||
|
||||
INT frontend_loop()
|
||||
{
|
||||
return CM_SUCCESS;
|
||||
}
|
||||
|
||||
INT begin_of_run(INT run_number, char *error)
|
||||
{
|
||||
return CM_SUCCESS;
|
||||
}
|
||||
|
||||
INT end_of_run(INT run_number, char *error)
|
||||
{
|
||||
return CM_SUCCESS;
|
||||
}
|
||||
|
||||
INT pause_run(INT run_number, char *error)
|
||||
{
|
||||
return CM_SUCCESS;
|
||||
}
|
||||
|
||||
INT resume_run(INT run_number, char *error)
|
||||
{
|
||||
return CM_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user