Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • jlab/hallc/analyzer_software/hcana
  • whit/hcana
2 results
Show changes
Showing
with 2 additions and 3383 deletions
Hall A/C Software
=================
Images for running containers for all aspects of the SANE experimental
analysis.
The starting point is a pre-built image for the ROOT libraries. (ubuntu + ROOT)
Main software libraries:
- `evio`: Built from https://github.com/whit2333/hallac_evio
- `analyzer`: Hall A analyzer (podd)from https://github.com/whit2333/analyzer
- `hcana`: Hall C analyzer from https://github.com/whit2333/hcana
These are all built using the super build project `cool_halls` (https://github.com/whit2333/cool_halls)
# You have to define the values in {}
#DOCKER_REPO={account-nr}.dkr.ecr.{region}.amazonaws.com
## optional aws-cli options
#AWS_CLI_PROFILE={aws-cli-profile}
#AWS_CLI_REGION={aws-cli-region}
# INSTALL
# - copy the files deploy.env, config.env, version.sh and Makefile to your repo
# - replace the vars in deploy.env
# - define the version script
# Build the container
make build
# Build and publish the container
make release
# Publish a container to AWS-ECR.
# This includes the login to the repo
make publish
# Run the container
make run
# Build an run the container
make up
# Stop the running container
make stop
# Build the container with differnt config and deploy file
make cnf=another_config.env dpl=another_deploy.env build
\ No newline at end of file
Bootstrap: docker
From: eicweb.phy.anl.gov:4567/jlab/hallc/analyzer_software/hcana:latest
%help
Hall A/C container.
Tools:
- evio : EVIO DAQ data format
- analyzer : Hall A analyzer (podd)
- hcana : Hall C analyzer (hcana)
- root : root version used for the analyzer
- rootls, rootbrowse, root_config
%labels
Maintainer "Whitney Armstrong, Sylvester Joosten"
Version v1.0
%setup -c /bin/bash
export SINGULARITY_SHELL=/bin/bash
%environment -c /bin/bash
export PYTHONPATH=/usr/local/lib:${PYTHONPATH}
export PATH=/usr/local/bin:${PATH}
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
export ROOT_INCLUDE_PATH=/usr/local/include:/usr/local/include/podd:/usr/local/include/hcana
%post -c /bin/bash
echo "Hello from post"
echo "Install additional software here"
source /usr/local/bin/thisroot.sh
## libformat and nlohmann json used heavily in new generation replay scripts
## libformat
#cd /tmp && git clone https://github.com/fmtlib/fmt.git && cd fmt && \
# git checkout 5.3.0 && mkdir /tmp/build && cd /tmp/build && \
# cmake -DBUILD_SHARED_LIBS=TRUE ../fmt &&
# make -j4 install && cd /tmp && rm -r /tmp/build && rm -r /tmp/fmt
### json
# =======================
# global
# =======================
%runscript
echo "Launching a shell in the Hall A/C singularity container
exec bash
# =======================
# root
# =======================
%apprun root
root "$@"
%appenv root
export PYTHONPATH=/usr/local/lib:${PYTHONPATH}
export PATH=/usr/local/bin:${PATH}
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
export ROOT_INCLUDE_PATH=/usr/local/include/podd:/usr/local/include/hcana
# =======================
# analyzer
# =======================
%apprun analyzer
analyzer "$@"
%appenv analyzer
export PYTHONPATH=/usr/local/lib:${PYTHONPATH}
export PATH=/usr/local/bin:${PATH}
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
export ROOT_INCLUDE_PATH=/usr/local/include/podd:/usr/local/include/hcana
# =======================
# hcana
# =======================
%apphelp hcana
Run the Hall-C analyzer with same root-style arguments.
%apprun hcana
source /usr/local/bin/thisroot.sh
hcana "$@"
%appenv hcana
export DB_DIR=DBASE
export PYTHONPATH=/usr/local/lib:${PYTHONPATH}
export PATH=/usr/local/bin:${PATH}
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
export ROOTSYS=/usr/local
export ROOT_INCLUDE_PATH=/usr/local/include
export ROOT_INCLUDE_PATH=/usr/local/include:/usr/local/include/podd:/usr/local/include/hcana
# =======================
# root-config
# =======================
%apprun root_config
root-config "$@"
%appenv root_config
export PYTHONPATH=/usr/local/lib:${PYTHONPATH}
export PATH=/usr/local/bin:${PATH}
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
export ROOT_INCLUDE_PATH=/usr/local/include/podd:/usr/local/include/hcana
# =======================
# rootbrowse
# =======================
%apprun rootbrowse
rootbrowse "$@"
%appenv rootbrowse
export PYTHONPATH=/usr/local/lib:${PYTHONPATH}
export PATH=/usr/local/bin:${PATH}
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
export ROOT_INCLUDE_PATH=/usr/local/include/podd:/usr/local/include/hcana
# =======================
# rootls
# =======================
%apprun rootls
rootls "$@"
%appenv rootls
export PYTHONPATH=/usr/local/lib:${PYTHONPATH}
export PATH=/usr/local/bin:${PATH}
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
export ROOT_INCLUDE_PATH=/usr/local/include/podd:/usr/local/include/hcana
Subproject commit 9001670be3944886c4936d2b2eac8a94935b4390
Subproject commit 355b3ce629f8f47f107e2a0fcfa7ee55b3463b6c
......@@ -8,7 +8,7 @@ include(FindThreads)
#----------------------------------------------------------------------------
# Sources and headers
file(GLOB src "*.cxx" "*.cpp")
file(GLOB src "*.cxx")
file(GLOB allheaders RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.h")
list(REMOVE_ITEM allheaders
"${CMAKE_CURRENT_SOURCE_DIR}/${LIBNAME}_LinkDef.h"
......@@ -66,7 +66,6 @@ target_include_directories(${LIBNAME}
$<BUILD_INTERFACE:${SPDLOG_INCLUDE_DIR}>
$<INSTALL_INTERFACE:${SPDLOG_INCLUDE_DIR}>
$<BUILD_INTERFACE:${FMT_INCLUDE_DIR}>
$<BUILD_INTERFACE:${CODA_ET_INCLUDE_DIR}>
)
target_compile_options(${LIBNAME}
......@@ -83,7 +82,6 @@ target_link_libraries(${LIBNAME}
PUBLIC
Podd::Podd
Podd::Decode
coda_et::coda_et
)
set_target_properties(${LIBNAME} PROPERTIES
SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
......@@ -109,7 +107,6 @@ build_root_dictionary(${LIBNAME} ${headers}
INCLUDEDIRS
$<BUILD_INTERFACE:-I${SPDLOG_INCLUDE_DIR}>
$<BUILD_INTERFACE:-I${FMT_INCLUDE_DIR}>
$<BUILD_INTERFACE:-I${CODA_ET_INCLUDE_DIR}>
-I${CMAKE_CURRENT_SOURCE_DIR}
-I${CMAKE_CURRENT_SOURCE_DIR}/include
-I${CMAKE_CURRENT_SOURCE_DIR}/include/hcana
......
//============================================================================//
// A class based on the support from ConfigParser and ConfigValue //
// It provides a simple way to read text file as configuration file, and read //
// or modify a parameter in the inherited class //
// The Configure() function should be overloaded according to specialized //
// requirements, and be called after the parameters being configured //
// //
// Chao Peng //
// 10/31/2016 //
//============================================================================//
#include <fstream>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include "ConfigObject.h"
//============================================================================//
// Constructor, Destructor //
//============================================================================//
// constructor
ConfigObject::ConfigObject(const std::string &splitter, const std::string &ignore, bool case_ins)
: split_chars(splitter), ignore_chars(ignore), case_insensitive(case_ins), __empty_value("")
{
// set default replace bracket
replace_pair = std::make_pair("{", "}");
}
// destructor
ConfigObject::~ConfigObject()
{
// place holder
}
//============================================================================//
// Public Member Function //
//============================================================================//
// configure the cluster method
void ConfigObject::Configure(const std::string &path)
{
// save the path
config_path = path;
// clear the map
config_map.clear();
// read configuration file in
ReadConfigFile(path);
}
// clear all the loaded configuration values
void ConfigObject::ClearConfig()
{
config_path = "";
config_map.clear();
}
// read configuration file and build the configuration map
bool ConfigObject::ReadConfigFile(const std::string &path)
{
ConfigParser c_parser;
c_parser.SetSplitters(split_chars); // self-defined splitters
if (c_parser.ReadFile(path)) {
// current directory
parserProcess(c_parser, path);
return true;
} else {
std::cerr << "Cannot open configuration file "
<< "\"" << path << "\""
<< std::endl;
return false;
}
}
// read the configuration string directly
void ConfigObject::ReadConfigString(const std::string &content)
{
ConfigParser c_parser;
c_parser.SetSplitters(split_chars);
c_parser.ReadBuffer(content.c_str());
parserProcess(c_parser, "buffer_string");
}
// continue parse the terms
void ConfigObject::parserProcess(ConfigParser &c_parser, const std::string &source)
{
std::string cur_dir = ConfigParser::decompose_path(source).dir;
while (c_parser.ParseLine()) {
// possible control words
if (c_parser.NbofElements() == 1) {
std::string control = c_parser.TakeFirst();
size_t pos = control.find("{THIS_DIR}");
if(pos != std::string::npos)
control.replace(pos, 10, cur_dir);
parseControl(control);
// var_name and var_value
} else if (c_parser.NbofElements() == 2) {
std::string var_name, key, var_value;
c_parser >> var_name >> var_value;
size_t pos = var_value.find("{THIS_DIR}");
if(pos != std::string::npos)
var_value.replace(pos, 10, cur_dir);
parseTerm(std::move(var_name), std::move(var_value));
// unsupported format
} else {
std::cout << "Warning: Unsupported format at line "
<< c_parser.LineNumber() << " from " << source << "\n"
<< "\"" << c_parser.CurrentLine() << "\""
<< std::endl;
}
}
}
// check if a certain term is configured
bool ConfigObject::HasKey(const std::string &var_name)
const
{
auto key = formKey(var_name);
if (config_map.find(key) != config_map.end())
return true;
return false;
}
// list all the existing configuration keys
void ConfigObject::ListKeys()
const
{
for (auto &it : config_map) {
std::cout << it.first << std::endl;
}
}
// get all the existing configuration keys
std::vector<std::string> ConfigObject::GetKeyList()
const
{
std::vector<std::string> res;
for (auto &it : config_map) {
res.push_back(it.first);
}
return res;
}
// save current configuration into a file
void ConfigObject::SaveConfig(const std::string &path)
const
{
std::string save_path;
if (path.empty())
save_path = config_path;
if(save_path.empty())
save_path = "latest.conf";
std::ofstream save(save_path);
for (auto &it : config_map) {
save << it.first
<< " " << split_chars.front() << " "
<< it.second
<< std::endl;
}
}
// get configuration value by its name/key
ConfigValue ConfigObject::GetConfigValue(const std::string &var_name)
const
{
// convert to lower case and remove uninterested characters
auto key = formKey(var_name);
auto it = config_map.find(key);
if (it == config_map.end()) {
return __empty_value;
} else {
ConfigValue result(it->second);
reform(result._value, replace_pair.first, replace_pair.second);
return result;
}
}
// set configuration value by its name/key
void ConfigObject::SetConfigValue(const std::string &var_name, const ConfigValue &c_value)
{
// convert to lower case and remove uninterested characters
auto key = formKey(var_name);
config_map[key] = c_value;
}
// get configuration value from the map
// if no such config value exists, it will fill the default value in
ConfigValue ConfigObject::GetConfigValue(const std::string &var_name, const ConfigValue &def_value, bool verbose)
{
auto key = formKey(var_name);
auto it = config_map.find(key);
if (it == config_map.end()) {
if (def_value.IsEmpty())
return __empty_value;
if (verbose) {
std::cout << var_name << " (key: " << key << ")"
<< " not defined in configuration file, set to default value "
<< def_value
<< std::endl;
}
config_map[key] = def_value;
return def_value;
}
ConfigValue result(it->second);
reform(result._value, replace_pair.first, replace_pair.second);
return result;
}
//============================================================================//
// Protected Member Function //
//============================================================================//
// build the key
std::string ConfigObject::formKey(const std::string &rawKey)
const
{
std::string key = ConfigParser::str_remove(rawKey, ignore_chars);
if (case_insensitive) {
key = ConfigParser::str_lower(key);
}
return key;
}
// replace the contents inside replace_pair with the configuration value
void ConfigObject::reform(std::string &input, const std::string &op, const std::string &cl)
const
{
// loop until no pair found
while (true) {
auto rpair = ConfigParser::find_pair(input, op, cl);
if (rpair.first != std::string::npos && rpair.second != std::string::npos) {
// get content inside the bracket
std::string var = input.substr(rpair.first + op.size(),
rpair.second - op.size() - rpair.first);
// deal with nested structure
reform(var, op, cl);
// replace content
std::string val;
// environment variable
if (rpair.first > 0 && input.at(rpair.first - 1) == '$') {
val = std::getenv(var.c_str());
// replace $ mark also
rpair.first--;
// ConfigObject variable
} else {
val = GetConfigValue(var)._value;
}
// replace variable with configuration value
input.replace(rpair.first, rpair.second - rpair.first + cl.size(), val);
} else {
// no pair found any more
return;
}
}
}
//============================================================================//
// Private Member Function //
//============================================================================//
// parse the control word and respond
void ConfigObject::parseControl(const std::string &word)
{
if (ConfigParser::str_upper(word.substr(0, 7)) == "INCLUDE") {
// need the most outer pair
auto p = ConfigParser::find_pair(word, "(", ")");
// not find pair
if (p.first == std::string::npos || p.second == std::string::npos) {
std::cout << "Unsupported control word format: " << word << "."
<< "Expected: INCLUDE(path)"
<< std::endl;
return;
}
int begin = p.first + 1;
int length = p.second - begin;
std::string new_path = word.substr(begin, length);
reform(new_path, replace_pair.first, replace_pair.second);
ReadConfigFile(new_path);
}
else {
std::cout << "Unsupported control word: " << word << std::endl;
}
}
// parse the configuration term
void ConfigObject::parseTerm(std::string &&var_name, std::string &&var_value)
{
// convert to lower case and remove uninterested characters
auto key = formKey(var_name);
if (key.back() == '+') {
key.pop_back();
auto it = config_map.find(key);
if (it != config_map.end())
it->second += var_value;
else
config_map[key] = var_value;
} else {
config_map[key] = var_value;
}
}
#ifndef CONFIG_OBJECT_H
#define CONFIG_OBJECT_H
#include <string>
#include <utility>
#include <vector>
#include <unordered_map>
#include "ConfigParser.h"
#define CONF_CONN(val, str, def, warn) val=GetConfigValue<decltype(val)>(str, def, warn)
#define CONF_CONN2(val, def, warn) val=GetConfiValue<decltype(val)>(str, def, warn)
#define GET_CONF(obj, val, str, def, warn) val=obj.GetConfiValue<decltype(val)>(str, def, warn)
#define GET_CONF2(obj, val, def, warn) val=GetConfiValue<decltype(val)>(#val, def, warn)
class ConfigObject
{
public:
// constructor, desctructor
ConfigObject(const std::string &spliiter = ":=", const std::string &ignore = " _\t", bool case_ins = true);
virtual ~ConfigObject();
// public member functions
void ClearConfig();
void SaveConfig(const std::string &path = "") const;
void ListKeys() const;
bool HasKey(const std::string &name) const;
bool ReadConfigFile(const std::string &path);
void ReadConfigString(const std::string &content);
void SetConfigValue(const std::string &var_name, const ConfigValue &c_value);
void SetIgnoreChars(const std::string &ignore) {ignore_chars = ignore;}
void SetSplitChars(const std::string &splitter) {split_chars = splitter;}
void SetReplacePair(const std::string &open, const std::string &close)
{
replace_pair = std::make_pair(open, close);
}
// get members
ConfigValue GetConfigValue(const std::string &var_name) const;
template<typename T>
T GetConfigValue(const std::string &var_name)
const
{
return GetConfigValue(var_name).Convert<T>();
}
ConfigValue GetConfigValue(const std::string &var_name, const ConfigValue &def_value, bool verbose = true);
template<typename T>
T GetConfigValue(const std::string &var_name, const T &val, bool verbose = true)
{
return GetConfigValue(var_name, ConfigValue(val), verbose).Convert<T>();
}
const std::string &GetConfigPath() const {return config_path;}
const std::string &GetSplitChars() const {return split_chars;}
const std::string &GetSpaceChars() const {return ignore_chars;}
const std::pair<std::string, std::string> &GetReplacePair() const {return replace_pair;}
std::vector<std::string> GetKeyList() const;
// functions that to be overloaded
virtual void Configure(const std::string &path = "");
protected:
// protected member functions
void reform(std::string &input, const std::string &open, const std::string &close) const;
std::string formKey(const std::string &raw_key) const;
private:
void parserProcess(ConfigParser &p, const std::string &source);
void parseControl(const std::string &control_word);
void parseTerm(std::string &&var_name, std::string &&var_value);
protected:
std::string split_chars;
std::string ignore_chars;
bool case_insensitive;
std::pair<std::string, std::string> replace_pair;
std::string config_path;
std::unordered_map<std::string, std::string> config_map;
// return this reference when there is no value found in the map
ConfigValue __empty_value;
};
#endif
//============================================================================//
// A class to simplify the argument parsing procedure //
// //
// Chao Peng //
// 07/26/2017 //
//============================================================================//
#include "ConfigOption.h"
#include "ConfigParser.h"
#include <iostream>
#include <cstring>
ConfigOption::ConfigOption()
{
// place holder
}
ConfigOption::~ConfigOption()
{
// place holder
}
void ConfigOption::AddOpt(OptType type, char s_term)
{
AddOpt(type, s_term, s_term);
}
void ConfigOption::AddLongOpt(OptType type, const char *l_term)
{
AddLongOpt(type, l_term, *l_term);
}
void ConfigOption::AddOpts(OptType type, char s_term, const char *l_term)
{
AddOpts(type, s_term, l_term, s_term);
}
void ConfigOption::AddOpt(OptType type, char s_term, char mark)
{
if(s_opt_map.find(s_term) != s_opt_map.end()) {
std::cerr << "ConfigOption: Short option " << s_term
<< " has already been added, abort AddOpt."
<< std::endl;
return;
}
s_opt_map[s_term] = Opt(mark, type);
}
void ConfigOption::AddLongOpt(OptType type, const char *l_term, char mark)
{
if(l_opt_map.find(l_term) != l_opt_map.end()) {
std::cerr << "ConfigOption: Long option " << l_term
<< " has already been added, abort AddOpt."
<< std::endl;
return;
}
l_opt_map[l_term] = Opt(mark, type);
}
void ConfigOption::AddOpts(OptType type, char s_term, const char *l_term, char mark)
{
AddOpt(type, s_term, mark);
AddLongOpt(type, l_term, mark);
}
bool ConfigOption::parseLongOpt(const char *arg)
{
auto vars = ConfigParser::split(arg, strlen(arg), "=");
std::string key = std::move(vars.front());
vars.pop_front();
auto it = l_opt_map.find(key);
if(it == l_opt_map.end()) {
std::cerr << "Unknown option --" << key << std::endl;
return false;
}
switch(it->second.type)
{
case arg_require:
if(vars.empty()) {
std::cerr << "Lack of argument for option --" << key << std::endl;
return false;
}
opt_pack.emplace_back(it->second.mark, it->second.type, std::move(vars.front()));
break;
case arg_none:
opt_pack.emplace_back(it->second.mark, it->second.type);
break;
case help_message:
return false;
}
return true;
}
bool ConfigOption::parseShortOpt(char key, int argc, char *argv[], int &idx)
{
auto it = s_opt_map.find(key);
if(it == s_opt_map.end()) {
std::cerr << "Unknown option -" << key << std::endl;
return false;
}
switch(it->second.type)
{
case arg_require:
if((idx + 1) >= argc || *argv[idx + 1] == '-') {
std::cerr << "Lack of argument for option -" << key << std::endl;
return false;
}
opt_pack.emplace_back(it->second.mark, it->second.type, ConfigValue(argv[++idx]));
break;
case arg_none:
opt_pack.emplace_back(it->second.mark, it->second.type);
break;
case help_message:
return false;
}
return true;
}
bool ConfigOption::ParseArgs(int argc, char *argv[])
{
if (argc < 1)
return false;
argv0 = argv[0];
bool success = true;
arg_pack.clear();
opt_pack.clear();
for(int i = 1; i < argc; ++i)
{
char* ptr = argv[i];
// option
if(*ptr == '-') {
// long option
if(*(ptr + 1) == '-') {
success &= parseLongOpt(ptr + 2);
// short option
} else {
success &= parseShortOpt(*(ptr + 1), argc, argv, i);
}
// arguments
} else {
arg_pack.emplace_back(ptr);
}
}
return success;
}
void ConfigOption::SetDesc(const char *desc)
{
base_desc = desc;
}
void ConfigOption::SetDesc(char mark, const char *desc)
{
std::string option;
bool found_mark = false;
for(auto &it : s_opt_map)
{
if(it.second.mark != mark) continue;
option = " - ";
option.back() = it.first;
if(it.second.type == arg_require)
option += " <arg>";
option += ",";
found_mark = true;
}
for(auto &it : l_opt_map)
{
if(it.second.mark != mark) continue;
option += " --" + it.first;
if(it.second.type == arg_require)
option += "=<arg>";
option += ",";
found_mark = true;
}
if(!found_mark) {
std::cerr << "Config Option: Cannot find any option with mark <"
<< mark << ">, abort adding description." << std::endl;
return;
}
option.back() = ':';
option += " ";
option += desc;
option_desc.emplace_back(option);
}
std::string ConfigOption::GetInstruction()
{
std::string res = base_desc + "\noptions:\n";
auto pvar = res.find("%0");
if (pvar != std::string::npos) {
res.replace(pvar, 2, argv0);
}
for(auto &option : option_desc)
{
res += "\t" + option + "\n";
}
return res;
}
#ifndef CONFIG_OPTION_H
#define CONFIG_OPTION_H
#include "ConfigValue.h"
#include <vector>
#include <string>
#include <unordered_map>
class ConfigOption
{
public:
enum OptType : int
{
arg_none = 0,
arg_require,
help_message,
};
struct Opt
{
char mark;
OptType type;
ConfigValue var;
Opt() : mark(-1), type(arg_none) {}
Opt(char m, OptType t) : mark(m), type(t) {}
Opt(char m, OptType t, ConfigValue v) : mark(m), type(t), var(v) {}
};
public:
ConfigOption();
virtual ~ConfigOption();
void AddOpt(OptType type, char s_term);
void AddOpt(OptType type, char s_term, char mark);
void AddLongOpt(OptType type, const char *l_term);
void AddLongOpt(OptType type, const char *l_term, char mark);
void AddOpts(OptType type, char s_term, const char *l_term);
void AddOpts(OptType type, char s_term, const char *l_term, char mark);
void SetDesc(const char *desc);
void SetDesc(char mark, const char *desc);
std::string GetInstruction();
bool ParseArgs(int argc, char *argv[]);
size_t NbofArgs() const {return arg_pack.size();}
size_t NbofOpts() const {return opt_pack.size();}
const std::string &GetArgv0() {return argv0;}
const ConfigValue &GetArgument(size_t i) {return arg_pack.at(i);}
const std::vector<ConfigValue> &GetArguments() {return arg_pack;}
const std::vector<Opt> &GetOptions() {return opt_pack;}
private:
bool parseLongOpt(const char *arg);
bool parseShortOpt(char key, int argc, char *argv[], int &idx);
private:
std::unordered_map<char, Opt> s_opt_map;
std::unordered_map<std::string, Opt> l_opt_map;
std::vector<Opt> opt_pack;
std::vector<ConfigValue> arg_pack;
std::string argv0;
std::string base_desc;
std::vector<std::string> option_desc;
};
#endif // CONFIG_OPTION_H
This diff is collapsed.
#ifndef CONFIG_PARSER_H
#define CONFIG_PARSER_H
#include <string>
#include <vector>
#include <deque>
#include <fstream>
#include "ConfigValue.h"
// a macro to auto generate enum2str and str2enum
// name mapping begins at bias and continuously increase, split by '|'
// an example:
// enum ABC {a = 3, b, c};
// ENUM_MAP(ABC, 3, "a|b|c")
// ABC2str(3) = "a"
// str2ABC("b") = 4
#define ENUM_MAP(type, bias, strings) \
static std::string type ## 2str(int T) \
{ \
return ConfigParser::get_split_part(T - (bias), strings, '|'); \
}; \
static type str2 ## type(const char *str) \
{ \
return static_cast<type>(bias + ConfigParser::get_part_count(str, strings, '|')); \
}
// config parser class
class ConfigParser
{
typedef std::pair<std::string, std::string> string_pair;
public:
struct Format
{
std::string split; // element splitters (chars)
std::string white; // white spaces (chars)
std::string delim; // line delimiter (string)
std::string glue; // line glue (string)
std::string cmtmark; // comment marks (string), until the line breaker '\n'
std::string cmtopen; // comment-block opening mark (string)
std::string cmtclose; // comment-block closing mark (string)
static Format Basic() {return {" \t,", " \t", "\n", "", "", "", ""};}
static Format BashLike() {return {" \t,", " \t", "\n", "\\", "#", "\'", "\'"};}
static Format CLike() {return {" \t,\n", " \t\n", ";", "", "//", "/*", "*/"};}
};
struct CharBuffer
{
std::vector<char> data;
size_t begin, end;
CharBuffer(size_t cap = 256) : begin(0), end(0)
{
data.resize(cap);
}
void Reset() {begin = 0; end = 0; data.clear();}
void Add(char ch)
{
if(data.size() <= end)
data.resize(2*data.size());
data[end++] = ch;
}
std::string String()
const
{
std::string str;
if(end > begin)
str.assign(&data[begin], end - begin);
return str;
}
inline const char &operator [] (size_t idx) const {return data[idx];}
inline char &operator [] (size_t idx) {return data[idx];}
};
public:
ConfigParser(Format f = Format::BashLike());
ConfigParser(ConfigParser &&that);
ConfigParser(const ConfigParser &that);
virtual ~ConfigParser();
ConfigParser &operator = (ConfigParser &&rhs);
ConfigParser &operator = (const ConfigParser &rhs);
// format related
inline void SetFormat(Format &&f) {form = f;}
inline void SetFormat(const Format &f) {form = f;}
inline void SetSplitters(std::string s) {form.split = s;}
inline void SetWhiteSpaces(std::string w) {form.white = w;}
inline void SetCommentMark(std::string c) {form.cmtmark = c;}
inline void SetCommentPair(std::string o, std::string c) {form.cmtopen = o; form.cmtclose = c;}
inline void SetLineGlues(std::string g) {form.glue = g;}
inline void SetLineBreaks(std::string b) {form.delim = b;}
const Format &GetFormat() const {return form;}
// dealing with file/buffer
bool OpenFile(const std::string &path, size_t cap = 64*1024);
bool ReadFile(const std::string &path);
void ReadBuffer(const char*);
void CloseFile();
void Clear();
// parse line, return false if no more line to parse
bool ParseLine();
// parse the whole file or buffer, return false if no elements found
bool ParseAll();
// parse a string, trim and split it into elements
int ParseString(const std::string &line);
// get current parsing status
bool CheckElements(int num, int optional = 0);
int NbofElements() const {return elements.size();}
int LineNumber() const {return line_number;}
std::string CurrentLine() const {return cur_line.String();}
// take the elements
ConfigValue TakeFirst();
template<typename T>
T TakeFirst()
{
return TakeFirst().Convert<T>();
}
template<typename T>
ConfigParser &operator >>(T &t)
{
t = (*this).TakeFirst().Convert<T>();
return *this;
}
template<class BidirIt>
int Take(BidirIt first, BidirIt last)
{
int count = 0;
for(auto it = first; it != last; ++it, ++count)
{
if(elements.empty())
break;
*it = elements.front();
elements.pop_front();
}
return count;
}
template<template<class, class> class Container>
Container<ConfigValue, std::allocator<ConfigValue>> TakeAll()
{
Container<ConfigValue, std::allocator<ConfigValue>> res;
while(elements.size())
{
res.emplace_back(std::move(elements.front()));
elements.pop_front();
}
return res;
}
template<template<class, class> class Container, class T>
Container<T, std::allocator<T>> TakeAll()
{
Container<T, std::allocator<T>> res;
while(elements.size())
{
ConfigValue tmp(std::move(elements.front()));
elements.pop_front();
res.emplace_back(tmp.Convert<T>());
}
return res;
}
private:
// private functions
bool getBuffer();
bool getLine(CharBuffer &line_buf, bool recursive = false);
int parseBuffer(const CharBuffer &line);
private:
// private members
Format form;
std::ifstream infile;
CharBuffer buf, cur_line;
int line_number;
std::deque<std::string> elements;
public:
// static functions
static void comment_line(std::string &str, const std::string &cmt, const std::string &brk);
static void comment_between(std::string &str, const std::string &open, const std::string &close);
static std::string trim(const std::string &str, const std::string &w);
static std::deque<std::string> split(const std::string &str, const std::string &s);
static std::deque<std::string> split(const char* str, const size_t &len, const std::string &s);
static std::string get_split_part(int num, const char *str, const char &s);
static int get_part_count(const char *cmp, const char *str, const char &s);
static std::vector<int> stois(const std::string &str, const std::string &s, const std::string &w);
static std::vector<float> stofs(const std::string &str, const std::string &s, const std::string &w);
static std::vector<double> stods(const std::string &str, const std::string &s, const std::string &w);
static std::string str_remove(const std::string &str, const std::string &ignore);
static std::string str_replace(const std::string &str, const std::string &ignore, const char &rc = ' ');
static std::string str_lower(const std::string &str);
static std::string str_upper(const std::string &str);
static std::pair<size_t, size_t> find_pair(const std::string &str,
const std::string &open,
const std::string &close,
size_t pos = 0);
static bool case_ins_equal(const std::string &str1, const std::string &str2);
static int find_integer(const std::string &str, const size_t &pos = 0);
static std::vector<int> find_integers(const std::string &str);
static void find_integer_helper(const std::string &str, std::vector<int> &result);
struct PathInfo { std::string dir, name, ext; };
static PathInfo decompose_path(const std::string &path);
static std::string compose_path(const PathInfo &path);
static std::string form_path(const std::string &dir, const std::string &file);
static std::string file_to_string(const std::string &path);
// break text file into several blocks in the format
// <label> <open_mark> <content> <close_mark>, this structure can be separated by sep characters
// return extracted <residual> {<label> <content>} with white characters trimmed
struct TextBlock {std::string label, content;};
struct TextBlocks {std::string residual; std::vector<TextBlock> blocks;};
static TextBlocks break_into_blocks(const std::string &buf,
const std::string &open = "{",
const std::string &close = "}",
const std::string &seps = " \t\n");
};
#endif
//============================================================================//
// A string wrapper class that convert string to other data types //
// //
// Chao Peng //
// 06/07/2016 //
//============================================================================//
#include "ConfigValue.h"
#include "ConfigParser.h"
#include <climits>
#include <algorithm>
using namespace std;
//============================================================================//
// Constructors, Destructor and Assignment Operators //
//============================================================================//
ConfigValue::ConfigValue(const string &value)
: _value(value)
{}
ConfigValue::ConfigValue(string &&value)
: _value(move(value))
{}
ConfigValue::ConfigValue(const char *value)
: _value(value)
{}
ConfigValue::ConfigValue(const bool &value)
{
if(value)
_value = "1";
else
_value = "0";
}
ConfigValue::ConfigValue(const int &value)
: _value(to_string(value))
{}
ConfigValue::ConfigValue(const long &value)
: _value(to_string(value))
{}
ConfigValue::ConfigValue(const long long &value)
: _value(to_string(value))
{}
ConfigValue::ConfigValue(const unsigned &value)
: _value(to_string(value))
{}
ConfigValue::ConfigValue(const unsigned long &value)
: _value(to_string(value))
{}
ConfigValue::ConfigValue(const unsigned long long &value)
: _value(to_string(value))
{}
ConfigValue::ConfigValue(const float &value)
: _value(to_string(value))
{}
ConfigValue::ConfigValue(const double &value)
: _value(to_string(value))
{}
ConfigValue::ConfigValue(const long double &value)
: _value(to_string(value))
{}
ConfigValue &ConfigValue::operator =(const string &str)
{
(*this)._value = str;
return *this;
}
ConfigValue &ConfigValue::operator =(string &&str)
{
(*this)._value = move(str);
return *this;
}
//============================================================================//
// Public Member functions //
//============================================================================//
bool ConfigValue::Bool()
const
{
if((_value == "1") ||
(ConfigParser::case_ins_equal(_value, "T")) ||
(ConfigParser::case_ins_equal(_value, "True")) ||
(ConfigParser::case_ins_equal(_value, "Y")) ||
(ConfigParser::case_ins_equal(_value, "Yes")))
return true;
if((_value == "0") ||
(ConfigParser::case_ins_equal(_value, "F")) ||
(ConfigParser::case_ins_equal(_value, "False")) ||
(ConfigParser::case_ins_equal(_value, "N")) ||
(ConfigParser::case_ins_equal(_value, "No")))
return false;
cout << "Config Value: Failed to convert "
<< _value << " to bool type. Return false."
<< endl;
return false;
}
char ConfigValue::Char()
const
{
try {
int value = stoi(_value);
if(value > CHAR_MAX)
cout << "Config Value: Limit exceeded while converting "
<< _value << " to char." << endl;
return (char) value;
} catch (exception &e) {
cerr << e.what() << endl;
cerr << "Config Value: Failed to convert "
<< _value << " to char. 0 returned." << endl;
return 0;
}
}
unsigned char ConfigValue::UChar()
const
{
try {
unsigned long value = stoul(_value);
if(value > UCHAR_MAX)
cout << "Config Value: Limit exceeded while converting "
<< _value << " to unsigned char." << endl;
return (unsigned char) value;
} catch (exception &e) {
cerr << e.what() << endl;
cerr << "Config Value: Failed to convert "
<< _value << " to unsigned char. 0 returned." << endl;
return 0;
}
}
short ConfigValue::Short()
const
{
try {
int value = stoi(_value);
if(value > SHRT_MAX)
cout << "Config Value: Limit exceeded while converting "
<< _value << " to short." << endl;
return (short) value;
} catch (exception &e) {
cerr << e.what() << endl;
cerr << "Config Value: Failed to convert "
<< _value << " to short. 0 returned." << endl;
return 0;
}
}
unsigned short ConfigValue::UShort()
const
{
try {
unsigned long value = stoul(_value);
if(value > USHRT_MAX)
cout << "Config Value: Limit exceeded while converting "
<< _value << " to unsigned short." << endl;
return (unsigned short) value;
} catch (exception &e) {
cerr << e.what() << endl;
cerr << "Config Value: Failed to convert "
<< _value << " to unsigned short. 0 returned." << endl;
return 0;
}
}
int ConfigValue::Int()
const
{
try {
return stoi(_value);
} catch (exception &e) {
cerr << e.what() << endl;
cerr << "Config Value: Failed to convert "
<< _value << " to int. 0 returned." << endl;
return 0;
}
}
unsigned int ConfigValue::UInt()
const
{
try {
return (unsigned int)stoul(_value);
} catch (exception &e) {
cerr << e.what() << endl;
cerr << "Config Value: Failed to convert "
<< _value << " to unsigned int. 0 returned." << endl;
return 0;
}
}
long ConfigValue::Long()
const
{
try {
return stol(_value);
} catch (exception &e) {
cerr << e.what() << endl;
cerr << "Config Value: Failed to convert "
<< _value << " to long. 0 returned." << endl;
return 0;
}
}
long long ConfigValue::LongLong()
const
{
try {
return stoll(_value);
} catch (exception &e) {
cerr << e.what() << endl;
cerr << "Config Value: Failed to convert "
<< _value << " to long long. 0 returned." << endl;
return 0;
}
}
unsigned long ConfigValue::ULong()
const
{
try {
return stoul(_value);
} catch (exception &e) {
cerr << e.what() << endl;
cerr << "Config Value: Failed to convert "
<< _value << " to unsigned long. 0 returned." << endl;
return 0;
}
}
unsigned long long ConfigValue::ULongLong()
const
{
try {
return stoull(_value);
} catch (exception &e) {
cerr << e.what() << endl;
cerr << "Config Value: Failed to convert "
<< _value << " to unsigned long long. 0 returned." << endl;
return 0;
}
}
float ConfigValue::Float()
const
{
try {
return stof(_value);
} catch (exception &e) {
cerr << e.what() << endl;
cerr << "Config Value: Failed to convert "
<< _value << " to float. 0 returned." << endl;
return 0;
}
}
double ConfigValue::Double()
const
{
try {
return stod(_value);
} catch (exception &e) {
cerr << e.what() << endl;
cerr << "Config Value: Failed to convert "
<< _value << " to double. 0 returned." << endl;
return 0;
}
}
long double ConfigValue::LongDouble()
const
{
try {
return stold(_value);
} catch (exception &e) {
cerr << e.what() << endl;
cerr << "Config Value: Failed to convert "
<< _value << " to long double. 0 returned." << endl;
return 0;
}
}
const char *ConfigValue::c_str()
const
{
return _value.c_str();
}
//============================================================================//
// Other functions //
//============================================================================//
ostream &operator << (ostream &os, const ConfigValue &b)
{
return os << b.c_str();
}
#ifndef CONFIG_VALUE_H
#define CONFIG_VALUE_H
#include <string>
#include <iostream>
#include <sstream>
#include <utility>
#include <typeinfo>
// demangle type name
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
// gnu compiler needs to demangle type info
static inline std::string demangle(const char* name)
{
int status = 0;
//enable c++11 by passing the flag -std=c++11 to g++
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status==0) ? res.get() : name ;
}
#else
// do nothing if not gnu compiler
static inline std::string demangle(const char* name)
{
return name;
}
#endif
// this helps template specialization in class
template <typename T>
struct __cv_id { typedef T type; };
class ConfigValue
{
public:
friend class ConfigParser;
friend class ConfigObject;
public:
ConfigValue() {}
ConfigValue(const std::string &value);
ConfigValue(std::string &&value);
ConfigValue(const int &value);
ConfigValue(const double &value);
explicit ConfigValue(const char *value);
explicit ConfigValue(const bool &value);
explicit ConfigValue(const long &value);
explicit ConfigValue(const long long &value);
explicit ConfigValue(const unsigned &value);
explicit ConfigValue(const unsigned long &value);
explicit ConfigValue(const unsigned long long &value);
explicit ConfigValue(const float &value);
explicit ConfigValue(const long double &value);
ConfigValue &operator =(const std::string &str);
ConfigValue &operator =(std::string &&str);
bool Bool() const;
char Char() const;
unsigned char UChar() const;
short Short() const;
unsigned short UShort() const;
int Int() const;
unsigned int UInt() const;
long Long() const;
long long LongLong() const;
unsigned long ULong() const;
unsigned long long ULongLong() const;
float Float() const;
double Double() const;
long double LongDouble() const;
const char *c_str() const;
const std::string &String() const {return _value;}
bool IsEmpty() const {return _value.empty();}
operator std::string()
const
{
return _value;
}
bool operator ==(const std::string &rhs)
const
{
return _value == rhs;
}
template<typename T>
T Convert()
const
{
return convert( __cv_id<T>());
}
private:
std::string _value;
template<typename T>
T convert(__cv_id<T> &&)
const
{
std::stringstream iss(_value);
T _cvalue;
if(!(iss >> _cvalue)) {
std::cerr << "Config Value Warning: Undefined value returned, failed to convert "
<< _value
<< " to "
<< demangle(typeid(T).name())
<< std::endl;
}
return _cvalue;
}
ConfigValue convert(__cv_id<ConfigValue>) const {return *this;}
bool convert(__cv_id<bool> &&) const {return (*this).Bool();}
float convert(__cv_id<float> &&) const {return (*this).Float();}
double convert(__cv_id<double> &&) const {return (*this).Double();}
long double convert(__cv_id<long double> &&) const {return (*this).LongDouble();}
std::string convert(__cv_id<std::string> &&) const {return (*this)._value;}
const char* convert(__cv_id<const char*> &&) const {return (*this)._value.c_str();}
};
// show string content of the config value to ostream
std::ostream &operator << (std::ostream &os, const ConfigValue &b);
#endif
#include "OnlineMonitor.h"
#include "PRadETChannel.h"
using namespace std::chrono;
namespace hcana {
Int_t OnlineMonitor::Monitor(PRadETChannel *ch, std::chrono::seconds interval)
{
Int_t total = 0;
fMonitor = true;
static const char* const here = "Monitor";
fBench->Begin("Total");
void (*prev_handler)(int);
prev_handler = signal(SIGINT, handle_sig);
while (!fMonitor) {
system_clock::time_point start(system_clock::now());
system_clock::time_point next(start + interval);
total += ReadOnce(ch);
std::this_thread::sleep_until(next);
}
signal(SIGINT, prev_handler);
if (fDoBench)
fBench->Begin("Output");
if (fOutput && fOutput->GetTree()) {
fFile = fOutput->GetTree()->GetCurrentFile();
}
if (fFile)
fFile->cd();
if (fOutput)
fOutput->End();
if (fFile) {
fRun->Write("Run Data");
fFile->Purge();
}
if (fDoBench)
fBench->Stop("Output");
return total;
}
Int_t OnlineMonitor::ReadOnce(PRadETChannel *ch, size_t max_events)
try {
Int_t count = 0;
for(size_t num = 0; ch->Read() && (num < max_events); ++num) {
auto buf = ch->GetBuffer();
count += ReadBuffer((uint32_t*)(ch->GetBuffer()));
}
return count;
}
catch (PRadException e) {
std::cerr << e.FailureType() << ": " << e.FailureDesc() << std::endl;
fMonitor = false;
return 0;
}
Int_t OnlineMonitor::ReadBuffer(uint32_t *buf)
try {
switch (fEvData->LoadEvent(buf)) {
case THaEvData::HED_WARN:
case THaEvData::HED_OK:
break;
default:
return 0;
}
Int_t count = 0;
do {
count += ProcOneEvent();
} while ( fEvData->IsMultiBlockMode() &&
!fEvData->BlockIsDone() &&
(fEvData->LoadFromMultiBlock() == THaEvData::HED_OK) );
return count;
}
catch (...) {
throw;
}
Int_t OnlineMonitor::ProcOneEvent()
{
UInt_t evnum = fEvData->GetEvNum();
switch (fCountMode) {
case kCountPhysics:
if (fEvData->IsPhysicsTrigger())
fNev++;
break;
case kCountAll:
fNev++;
break;
case kCountRaw:
fNev = evnum;
break;
default:
break;
}
if (fUpdateRun)
fRun->Update(fEvData);
if (fDoBench)
fBench->Begin("Cuts");
gHaCuts->ClearAll();
if (fDoBench)
fBench->Stop("Cuts");
switch (MainAnalysis()) {
case kOK:
return 1;
case kSkip:
default:
break;
case kTerminate:
throw(PRadException("Termination", "analysis is terminated."));
case kFatal:
throw(PRadException("Fatal Error", "analysis encountered fatal error."));
}
return 0;
}
} // namespace hcana
#ifndef hcana_OnlineMonitor_h_
#define hcana_OnlineMonitor_h_
#include "THaBenchmark.h"
#include "THcAnalyzer.h"
#include <thread>
#include <chrono>
#include <iostream>
class PRadETChannel;
namespace hcana {
class OnlineMonitor : public THcAnalyzer {
public:
OnlineMonitor() : THcAnalyzer() {}
virtual ~OnlineMonitor() {}
virtual Int_t Monitor(PRadETChannel *ch, std::chrono::seconds interval = std::chrono::seconds(10));
virtual Int_t ReadOnce(PRadETChannel *ch, size_t max_events = 10000);
Int_t ReadBuffer(uint32_t *buf);
Int_t ProcOneEvent();
//Int_t GoToEndOfCodaFile();
ClassDef(OnlineMonitor, 0) // Hall C Analyzer Standard Event Loop
private:
bool fMonitor;
};
} // namespace hcana
#endif
//============================================================================//
// A C++ wrapper class for C based ET //
// //
// Chao Peng //
// 02/27/2016 //
//============================================================================//
#include "PRadETChannel.h"
#include "PRadETStation.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
using namespace std;
PRadETChannel::PRadETChannel(size_t size)
: curr_stat(nullptr), et_id(nullptr), bufferSize(size)
{
buffer = new uint32_t[bufferSize];
}
PRadETChannel::~PRadETChannel()
{
if(buffer != nullptr)
delete[](buffer), buffer = nullptr;
// force close ET
ForceClose();
}
// Close ET connection
void PRadETChannel::ForceClose()
{
if((et_id != nullptr) && et_alive(et_id)) {
et_forcedclose(et_id);
et_id = nullptr;
}
}
// Open ET
void PRadETChannel::Open(const char* ipAddr, int tcpPort, const char* etFile)
{
// Use a direct connection to the ET system
config.SetCast(ET_DIRECT);
// Set the ip address and tcp port
config.SetHost(ipAddr);
config.SetServerPort(tcpPort);
int charSize = strlen(etFile)+1;
char *fileName = new char[charSize];
strncpy(fileName, etFile, charSize);
// Open et client
int status = et_open(&et_id, fileName, config.Get());
delete fileName;
if(status != ET_OK) {
throw(PRadException(PRadException::ET_CONNECT_ERROR, "et_client: cannot open et client!"));
}
/* set level of debug output */
et_system_setdebug(et_id, ET_DEBUG_INFO);
}
void PRadETChannel::NewStation(const string &name)
{
auto it = stations.find(name);
if(it == stations.end()) {
curr_stat = new PRadETStation(this, name);
stations[string(name)] = curr_stat;
}
}
void PRadETChannel::SwitchStation(const string &name)
{
auto it = stations.find(name);
if(it != stations.end()) {
curr_stat = it->second;
} else {
cout << "ET Channel Warning: station " << name << " does not exist!" << endl;
}
}
void PRadETChannel::RemoveStation(const string &name)
{
try {
if(et_id != nullptr && et_alive(et_id)) {
auto it = stations.find(name);
if(it != stations.end()) {
it->second->Remove();
stations.erase(it);
} else {
cout << "ET Channel Warning: station " << name << " does not exist!" << endl;
}
} else {
cout << "ET Channel Warning: cannot remove station while disconnected from ET!" << endl;
}
} catch (PRadException e) {
throw e;
}
}
PRadETStation* PRadETChannel::GetStation(const string &name)
{
auto it = stations.find(name);
if(it != stations.end()) {
return it->second;
} else {
return nullptr;
}
}
// Attach station
void PRadETChannel::AttachStation()
{
try {
curr_stat->Create();
curr_stat->Attach();
} catch (PRadException e) {
throw(e);
}
cout << "Successfully attached to ET!" << endl;
}
// Read one event from ET station, return true if success
bool PRadETChannel::Read()
{
// check if et is opened or alive
if(et_id == nullptr || !et_alive(et_id))
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: et is not opened or dead!"));
et_att_id att = curr_stat->GetAttachID();
// get the event
int status = et_event_get(et_id, att, &etEvent, ET_ASYNC, nullptr);
switch(status)
{
case ET_OK:
break;
case ET_ERROR_EMPTY:
return false;
case ET_ERROR_DEAD:
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: et is dead!"));
case ET_ERROR_TIMEOUT:
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: got timeout!!"));
case ET_ERROR_BUSY:
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: station is busy!"));
case ET_ERROR_WAKEUP:
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: someone told me to wake up."));
default:
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: unkown error!"));
}
// copy the data buffer
copyEvent();
// put back the event
status = et_event_put(et_id, att, etEvent);
switch(status)
{
case ET_OK:
break;
case ET_ERROR_DEAD:
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: et is dead!"));
default:
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: unkown error!"));
}
return true;
}
bool PRadETChannel::Write(void *buf, int nbytes)
{
// check if et is opened or alive
if(et_id == nullptr || !et_alive(et_id))
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: et is not opened or dead!"));
et_att_id att = curr_stat->GetAttachID();
int status = et_event_new(et_id, att, &etEvent, ET_SLEEP, nullptr, nbytes);
switch(status) {
case ET_OK:
break;
case ET_ERROR_EMPTY:
return false;
case ET_ERROR_DEAD:
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: et is dead!"));
case ET_ERROR_TIMEOUT:
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: got timeout!!"));
case ET_ERROR_BUSY:
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: station is busy!"));
case ET_ERROR_WAKEUP:
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: someone told me to wake up."));
default:
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: unkown error!"));
}
// build et event
void *data;
et_event_getdata(etEvent, &data);
memcpy((void *) data, (const void *) buf, nbytes);
et_event_setlength(etEvent, nbytes);
// put back the event
status = et_event_put(et_id, att, etEvent);
switch(status)
{
case ET_OK:
break;
case ET_ERROR_DEAD:
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: et is dead!"));
default:
throw(PRadException(PRadException::ET_READ_ERROR,"et_client: unkown error!"));
}
return true;
}
void PRadETChannel::copyEvent()
{
void *data;
et_event_getdata(etEvent, &data);
et_event_getlength(etEvent, &bufferSize);
bufferSize /= 4; // from byte to int32 words
uint32_t *data_buffer = (uint32_t*) data;
size_t index = 0;
// check if it is a block header
if(bufferSize >= 8 && data_buffer[7] == 0xc0da0100) {
index += 8;
bufferSize -= 8;
}
for(size_t i = 0; i < bufferSize; ++i)
{
buffer[i] = data_buffer[index+i];
}
}
// nested config classes
// et_openconfig
PRadETChannel::Configuration::Configuration()
{
Initialize();
}
PRadETChannel::Configuration::~Configuration()
{
et_open_config_destroy(config);
}
// wrapper functions
void PRadETChannel::Configuration::Initialize()
{
et_open_config_init(&config);
}
void PRadETChannel::Configuration::SetWait(int val)
{
et_open_config_setwait(config, val);
}
void PRadETChannel::Configuration::SetTimeOut(struct timespec val)
{
et_open_config_settimeout(config, val);
}
void PRadETChannel::Configuration::SetHost(const char *val)
{
et_open_config_sethost(config, val);
}
void PRadETChannel::Configuration::SetCast(int val)
{
et_open_config_setcast(config, val);
}
void PRadETChannel::Configuration::SetTTL(int val)
{
et_open_config_setTTL(config, val);
}
void PRadETChannel::Configuration::SetPort(unsigned short val)
{
et_open_config_setport(config, val);
}
void PRadETChannel::Configuration::SetServerPort(unsigned short val)
{
et_open_config_setserverport(config, val);
}
void PRadETChannel::Configuration::AddBroadCast(const char *val)
{
et_open_config_addbroadcast(config, val);
}
void PRadETChannel::Configuration::RemoveBroadCast(const char *val)
{
et_open_config_removebroadcast(config, val);
}
void PRadETChannel::Configuration::AddMultiCast(const char *val)
{
et_open_config_addmulticast(config, val);
}
void PRadETChannel::Configuration::RemoveMultiCast(const char *val)
{
et_open_config_removemulticast(config, val);
}
void PRadETChannel::Configuration::SetPolicy(int val)
{
et_open_config_setpolicy(config, val);
}
void PRadETChannel::Configuration::SetMode(int val)
{
et_open_config_setmode(config, val);
}
void PRadETChannel::Configuration::SetDebugDefault(int val)
{
et_open_config_setdebugdefault(config, val);
}
void PRadETChannel::Configuration::SetInterface(const char *val)
{
et_open_config_setinterface(config, val);
}
void PRadETChannel::Configuration::SetTCP(int rBufSize, int sBufSize, int noDelay)
{
et_open_config_settcp(config, rBufSize, sBufSize, noDelay);
}
#ifndef PRAD_ET_CHANNEL_H
#define PRAD_ET_CHANNEL_H
#include <unordered_map>
#include <string>
#include <stdint.h>
#include "et.h"
#include "PRadException.h"
#include "PRadETStation.h"
#define ET_CHUNK_SIZE 500
class PRadETChannel
{
public:
class Configuration
{
public:
Configuration();
virtual ~Configuration();
et_openconfig &Get() {return config;}
// wrapper functions
void Initialize();
void SetWait(int val);
void SetTimeOut(struct timespec val);
void SetHost(const char *val);
void SetCast(int val);
void SetTTL(int val);
void SetPort(unsigned short val);
void SetServerPort(unsigned short val);
void AddBroadCast(const char *val);
void RemoveBroadCast(const char *val);
void AddMultiCast(const char *val);
void RemoveMultiCast(const char *val);
void SetPolicy(int val);
void SetMode(int val);
void SetDebugDefault(int val);
void SetInterface(const char *val);
void SetTCP(int rBufSize, int sBufSize, int noDelay);
private:
et_openconfig config;
};
public:
PRadETChannel(size_t size = 1048576);
virtual ~PRadETChannel();
void Open(const char *ipAddr, int tcpPort, const char *etFile);
void NewStation(const std::string &name);
void SwitchStation(const std::string &name);
void RemoveStation(const std::string &name);
void AttachStation();
void DetachStation();
void ForceClose();
bool Read();
bool Write(void *buf, int nbytes);
void *GetBuffer() {return (void*) buffer;}
size_t GetBufferLength() {return bufferSize;}
Configuration &GetConfig() {return config;}
et_sys_id &GetID() {return et_id;}
PRadETStation *GetCurrentStation() {return curr_stat;}
PRadETStation *GetStation(const std::string &name);
private:
Configuration config;
PRadETStation *curr_stat;
std::unordered_map<std::string, PRadETStation*> stations;
et_sys_id et_id;
et_event *etEvent;
uint32_t *buffer;
size_t bufferSize;
void copyEvent();
};
#endif
//============================================================================//
// A C++ wrapper class for C based ET station //
// //
// Chao Peng //
// 04/01/2016 //
//============================================================================//
#include "PRadETStation.h"
#include "PRadETChannel.h"
PRadETStation::PRadETStation(PRadETChannel *p, std::string n, int mode)
: et_system(p), name(n)
{
PreSetting(mode);
}
PRadETStation::~PRadETStation()
{
Remove();
}
void PRadETStation::PreSetting(int mode)
{
// Generic settings
config.SetUser(ET_STATION_USER_MULTI);
config.SetRestore(ET_STATION_RESTORE_OUT);
config.SetPrescale(1);
config.SetCUE(ET_CHUNK_SIZE);
// TODO, change to meaningful settings
int selections[] = {17,15,-1,-1};
char fName[] = "et_my_function";
char libName[] = "libet_user.so";
// some pre-defined settings
// TODO, make these settings selectable
switch(mode)
{
case 1:
config.SetSelect(ET_STATION_SELECT_ALL);
config.SetBlock(ET_STATION_BLOCKING);
break;
case 2:
config.SetSelect(ET_STATION_SELECT_ALL);
config.SetBlock(ET_STATION_NONBLOCKING);
break;
case 3:
config.SetSelect(ET_STATION_SELECT_MATCH);
config.SetBlock(ET_STATION_BLOCKING);
config.SetSelectWords(selections);
break;
case 4:
config.SetSelect(ET_STATION_SELECT_MATCH);
config.SetBlock(ET_STATION_NONBLOCKING);
config.SetSelectWords(selections);
break;
case 5:
config.SetSelect(ET_STATION_SELECT_USER);
config.SetBlock(ET_STATION_BLOCKING);
config.SetSelectWords(selections);
config.SetFunction(fName);
config.SetLib(libName);
break;
case 6:
config.SetSelect(ET_STATION_SELECT_USER);
config.SetBlock(ET_STATION_NONBLOCKING);
config.SetSelectWords(selections);
config.SetFunction(fName);
config.SetLib(libName);
break;
}
}
// Create station
void PRadETStation::Create()
{
char s_name[256];
strcpy(s_name, name.c_str());
/* create the station */
int status = et_station_create(et_system->GetID(), &station_id, s_name, config.Get());
if(status < ET_OK) {
if(status == ET_ERROR_EXISTS) {
/* station_id contains pointer to existing station */;
throw(PRadException(PRadException::ET_STATION_CREATE_ERROR, "et_client: station already exists!"));
} else if(status == ET_ERROR_TOOMANY) {
throw(PRadException(PRadException::ET_STATION_CREATE_ERROR, "et_client: too many stations created!"));
} else {
throw(PRadException(PRadException::ET_STATION_CREATE_ERROR, "et_client: error in station creation!"));
}
}
}
void PRadETStation::Attach()
{
if(et_station_attach(et_system->GetID(), station_id, &attach_id) < ET_OK) {
throw(PRadException(PRadException::ET_STATION_ATTACH_ERROR, "et_client: error in station attach!"));
}
}
void PRadETStation::Detach()
{
if(et_station_detach(et_system->GetID(), attach_id) < ET_OK) {
throw(PRadException(PRadException::ET_STATION_ATTACH_ERROR, "et_client: error in station dettach!"));
}
}
void PRadETStation::Remove()
{
if(et_station_remove(et_system->GetID(), station_id) < ET_OK) {
throw(PRadException(PRadException::ET_STATION_ATTACH_ERROR, "et_client: error in station remove!"));
}
}
// et_station_config
PRadETStation::Configuration::Configuration()
{
Initialize();
}
PRadETStation::Configuration::~Configuration()
{
et_station_config_destroy(config);
}
// wrapper functions
void PRadETStation::Configuration::Initialize()
{
et_station_config_init(&config);
}
void PRadETStation::Configuration::SetBlock(int val)
{
et_station_config_setblock(config, val);
}
void PRadETStation::Configuration::SetFlow(int val)
{
et_station_config_setflow(config, val);
}
void PRadETStation::Configuration::SetSelect(int val)
{
et_station_config_setselect(config, val);
}
void PRadETStation::Configuration::SetUser(int val)
{
et_station_config_setuser(config, val);
}
void PRadETStation::Configuration::SetRestore(int val)
{
et_station_config_setrestore(config, val);
}
void PRadETStation::Configuration::SetCUE(int val)
{
et_station_config_setcue(config, val);
}
void PRadETStation::Configuration::SetPrescale(int val)
{
et_station_config_setprescale(config, val);
}
void PRadETStation::Configuration::SetSelectWords(int val[])
{
et_station_config_setselectwords(config, val);
}
void PRadETStation::Configuration::SetFunction(const char *val)
{
et_station_config_setfunction(config, val);
}
void PRadETStation::Configuration::SetLib(const char *val)
{
et_station_config_setlib(config, val);
}
void PRadETStation::Configuration::SetClass(const char *val)
{
et_station_config_setclass(config, val);
}
#ifndef PRAD_ET_STATION_H
#define PRAD_ET_STATION_H
#include "et.h"
#include "PRadException.h"
#include <string>
class PRadETChannel;
class PRadETStation
{
public:
class Configuration
{
public:
Configuration();
virtual ~Configuration();
et_statconfig &Get() {return config;}
//wrapper functions
void Initialize();
void SetBlock(int val);
void SetFlow(int val);
void SetSelect(int val);
void SetUser(int val);
void SetRestore(int val);
void SetCUE(int val);
void SetPrescale(int val);
void SetSelectWords(int val[]);
void SetFunction(const char *val);
void SetLib(const char *val);
void SetClass(const char *val);
private:
et_statconfig config;
};
public:
PRadETStation(PRadETChannel *p, std::string n, int mode = 2);
virtual ~PRadETStation();
Configuration &GetConfig() {return config;}
et_stat_id &GetID() {return station_id;}
et_att_id &GetAttachID() {return attach_id;}
std::string GetName() {return name;}
void PreSetting(int mode);
void Create();
void Attach();
void Detach();
void Remove();
private:
PRadETChannel *et_system;
std::string name;
et_att_id attach_id;
et_stat_id station_id;
Configuration config;
};
#endif