diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bd66994753ed2ef8ab8553e1678087cdf22fc95b..2c5c730e8eac0a08c2a81ddaedb97fae38e396a8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -65,6 +65,7 @@ target_include_directories(${LIBNAME} $<BUILD_INTERFACE:${SPDLOG_INCLUDE_DIR}> $<INSTALL_INTERFACE:${SPDLOG_INCLUDE_DIR}> $<BUILD_INTERFACE:${FMT_INCLUDE_DIR}> + /site/coda/3.10/Linux-x86_64/include ) target_compile_options(${LIBNAME} @@ -77,10 +78,16 @@ if(WITH_DEBUG) target_compile_definitions(${LIBNAME} PUBLIC WITH_DEBUG) endif() +target_link_directories(${LIBNAME} + PUBLIC + "/site/coda/3.10/Linux-x86_64/lib" + ) + target_link_libraries(${LIBNAME} PUBLIC Podd::Podd Podd::Decode + et ) set_target_properties(${LIBNAME} PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} @@ -111,6 +118,7 @@ build_root_dictionary(${LIBNAME} ${headers} -I${CMAKE_CURRENT_SOURCE_DIR}/include/hcana -I${Podd_DIR}/../../include -I${Podd_DIR}/../../include/podd2 + -I/site/coda/3.10/Linux-x86_64/include TARGETS ${LIBNAME} LINKDEF include/HallC_LinkDef.h ) diff --git a/src/PRadETChannel.cxx b/src/PRadETChannel.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3f4d13c78fbed0d94f9b367e87df35a81830e411 --- /dev/null +++ b/src/PRadETChannel.cxx @@ -0,0 +1,301 @@ +//============================================================================// +// 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; +} + +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); +} + diff --git a/src/PRadETChannel.h b/src/PRadETChannel.h new file mode 100644 index 0000000000000000000000000000000000000000..975670f6224dbc9281b1e3986cd3267f1dc084f0 --- /dev/null +++ b/src/PRadETChannel.h @@ -0,0 +1,78 @@ +#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(); + 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 diff --git a/src/PRadETStation.cxx b/src/PRadETStation.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4c814f71a170496aa28b1ed583ef622a0116c037 --- /dev/null +++ b/src/PRadETStation.cxx @@ -0,0 +1,189 @@ +//============================================================================// +// 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); +} + diff --git a/src/PRadETStation.h b/src/PRadETStation.h new file mode 100644 index 0000000000000000000000000000000000000000..8745dc4a0c137b6a8614ed452025273d69c867ed --- /dev/null +++ b/src/PRadETStation.h @@ -0,0 +1,60 @@ +#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 diff --git a/src/PRadException.cxx b/src/PRadException.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e27e420616524730582ade6cad1cfbb7b995296c --- /dev/null +++ b/src/PRadException.cxx @@ -0,0 +1,83 @@ +//============================================================================// +// A exception class for PRad Event Viewer // +// // +// Chao Peng // +// 02/27/2016 // +//============================================================================// + +#include "PRadException.h" + +using namespace std; + +PRadException::PRadException(const string &typ, const string &txt, const string &aux) +: title(typ), text(txt), auxText(aux) +{ +} + +PRadException::PRadException(PRadExceptionType typ, const string &txt, const string &aux) +: type(typ), text(txt), auxText(aux) +{ +} + +PRadException::PRadException(PRadExceptionType typ, const string &txt, const string &file, const string &func, int line) +: type(typ), text(txt) +{ + ostringstream oss; + oss << " evioException occured in file " << file << ", function " << func << ", line " << line; + auxText=oss.str(); +} + + +string PRadException::FailureDesc(void) const +{ + ostringstream oss; + oss << text << endl + << auxText; + return(oss.str()); +} + +string PRadException::FailureType(void) const +{ + if(!title.empty()) + return title; + + string oss; + switch(type) + { + case ET_CONNECT_ERROR: + oss = "ET CONNECT ERROR"; + break; + case ET_CONFIG_ERROR: + oss = "ET CONFIG ERROR"; + break; + case ET_STATION_CONFIG_ERROR: + oss = "ET STATION CONFIG ERROR"; + break; + case ET_STATION_CREATE_ERROR: + oss = "ET STATION CREATE ERROR"; + break; + case ET_STATION_ATTACH_ERROR: + oss = "ET ATTACH ERROR"; + break; + case ET_READ_ERROR: + oss = "ET READ ERROR"; + break; + case ET_PUT_ERROR: + oss = "ET PUT ERROR"; + break; + case HIGH_VOLTAGE_ERROR: + oss = "HIGH VOLTAGE SYSTEM ERROR"; + break; + default: + oss = "UNKNOWN ERROR"; + break; + } + + return(oss); +} + +const char* PRadException::what() const noexcept +{ + string failure = FailureType() + ": " + FailureDesc(); + return failure.c_str(); +} diff --git a/src/PRadException.h b/src/PRadException.h new file mode 100644 index 0000000000000000000000000000000000000000..ca721b3b2d8be2087e15904601f3235ff7151622 --- /dev/null +++ b/src/PRadException.h @@ -0,0 +1,43 @@ +#ifndef PRAD_EXCEPTION_H +#define PRAD_EXCEPTION_H + + +#include <stdlib.h> +#include <string.h> +#include <exception> +#include <string> +#include <sstream> + +class PRadException : public std::exception +{ +public: + enum PRadExceptionType + { + UNKNOWN_ERROR, + ET_CONNECT_ERROR, + ET_CONFIG_ERROR, + ET_STATION_CONFIG_ERROR, + ET_STATION_CREATE_ERROR, + ET_STATION_ATTACH_ERROR, + ET_READ_ERROR, + ET_PUT_ERROR, + HIGH_VOLTAGE_ERROR, + }; + PRadException(const std::string &typ, const std::string &txt = "", const std::string &aux = ""); + PRadException(PRadExceptionType typ = UNKNOWN_ERROR, const std::string &txt = "", const std::string &aux = ""); + PRadException(PRadExceptionType typ, const std::string &txt, const std::string &file, const std::string &func, int line); + virtual ~PRadException(void) {} + virtual std::string FailureDesc(void) const; + virtual std::string FailureType(void) const; + const char *what() const noexcept; + +public: + PRadExceptionType type; // exception type + std::string title; + std::string text; // primary text + std::string auxText; // auxiliary text +}; + +#endif + + diff --git a/src/Scandalizer.h b/src/Scandalizer.h index ab2a41d615eac4b4e263d9d2ed43c1d337668831..f3e21e8c48c3514b350b0b61d5c0fbc2501a7e99 100644 --- a/src/Scandalizer.h +++ b/src/Scandalizer.h @@ -3,6 +3,7 @@ #include "THaBenchmark.h" #include "THcAnalyzer.h" +#include "PRadETChannel.h" #include <iostream> @@ -16,9 +17,13 @@ namespace hcana { virtual Int_t Process(THaRunBase* run = nullptr); virtual Int_t ReadOneEvent(); //Int_t GoToEndOfCodaFile(); + void SetETChannel(PRadETChannel *ch) { online_ch = ch; } + PRadETChannel *GetETChannel() { return online_ch; } int _skip_events = 0; + PRadETChannel *online_ch; + ClassDef(Scandalizer, 0) // Hall C Analyzer Standard Event Loop };