IMCtermite/lib/imc_object.hpp
2025-01-23 14:15:52 +00:00

704 lines
24 KiB
C++

//---------------------------------------------------------------------------//
#ifndef IMCOBJECT
#define IMCOBJECT
#include <time.h>
#include <math.h>
#include "imc_key.hpp"
//---------------------------------------------------------------------------//
namespace imc
{
// obtain specific parameters as string
std::string get_parameter(const std::vector<unsigned char>* buffer, const imc::parameter* param)
{
std::string prm("");
for ( unsigned long int i = param->begin()+1; i <= param->end(); i++ )
{
prm.push_back((char)(*buffer)[i]);
}
return prm;
}
// format and processor (corresponds to key CF)
struct format
{
int fileformat_;
int processor_;
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 3 ) throw std::runtime_error("invalid number of parameters in CF");
fileformat_ = std::stoi(get_parameter(buffer,&parameters[0]));
processor_ = std::stoi(get_parameter(buffer,&parameters[2]));
}
format(): fileformat_(-1), processor_(-1) {}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"format:"<<fileformat_<<"\n"
<<std::setw(width)<<std::left<<"processor:"<<processor_<<"\n";
return ss.str();
}
};
// start of group of keys (corresponds to key CK)
struct keygroup
{
int version_;
int length_;
bool closed_; // corresponds to true = 1 and false = 0 in file
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 2 ) throw std::runtime_error("invalid number of parameters in CK");
version_ = std::stoi(get_parameter(buffer,&parameters[0]));
length_ = std::stoi(get_parameter(buffer,&parameters[1]));
closed_ = ( get_parameter(buffer,&parameters[3])==std::string("1") );
}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"version:"<<version_<<"\n"
<<std::setw(width)<<std::left<<"length:"<<length_<<"\n"
<<std::setw(width)<<std::left<<"closed:"<<(closed_?"yes":"no")<<"\n";
return ss.str();
}
};
// group definition (corresponds to key CB)
struct groupobj
{
unsigned long int group_index_;
std::string name_;
std::string comment_;
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 7 ) throw std::runtime_error("invalid number of parameters in CB");
group_index_ = std::stoul(get_parameter(buffer,&parameters[2]));
name_ = get_parameter(buffer,&parameters[4]);
comment_ = get_parameter(buffer,&parameters[6]);
}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"group-index:"<<group_index_<<"\n"
<<std::setw(width)<<std::left<<"name:"<<name_<<"\n"
<<std::setw(width)<<std::left<<"comment:"<<comment_<<"\n";
return ss.str();
}
};
// text definition (corresponds to key CT)
struct text
{
unsigned long int group_index_; // corresponding to group-index in CB block
std::string name_;
std::string text_;
std::string comment_;
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 9 ) throw std::runtime_error("invalid number of parameters in CT");
group_index_ = std::stoul(get_parameter(buffer,&parameters[2]));
name_ = get_parameter(buffer,&parameters[4]);
text_ = get_parameter(buffer,&parameters[6]);
comment_ = get_parameter(buffer,&parameters[8]);
}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"group-index:"<<group_index_<<"\n"
<<std::setw(width)<<std::left<<"name:"<<name_<<"\n"
<<std::setw(width)<<std::left<<"text:"<<text_<<"\n"
<<std::setw(width)<<std::left<<"comment:"<<comment_<<"\n";
return ss.str();
}
};
enum fieldtype {
realnumber = 1, // 1
xmonotony, // 2
xy, // 3
complexrealimag, // 4
complexabsphase, // 5
complexdbphase // 6
};
// definition of data field (corresponds to key CG)
struct datafield
{
unsigned long int number_components_;
fieldtype fldtype_;
int dimension_; // corresponding to fieldtype \in {1,}
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 5 ) throw std::runtime_error("invalid number of parameters in CG");
number_components_ = std::stoul(get_parameter(buffer,&parameters[2]));
fldtype_ = (fieldtype)std::stoi(get_parameter(buffer,&parameters[3]));
dimension_ = std::stoi(get_parameter(buffer,&parameters[4]));
}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"#components:"<<number_components_<<"\n"
<<std::setw(width)<<std::left<<"fieldtype:"<<fldtype_<<"\n"
<<std::setw(width)<<std::left<<"dimension:"<<dimension_<<"\n";
return ss.str();
}
};
// definition of abscissa (corresponds to key CD1)
struct abscissa
{
double dx_;
bool calibration_;
std::string unit_;
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 6 ) throw std::runtime_error("invalid number of parameters in CD1");
dx_ = std::stod(get_parameter(buffer,&parameters[2]));
calibration_ = ( get_parameter(buffer,&parameters[3]) == std::string("1") );
unit_ = get_parameter(buffer,&parameters[5]);
}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"dx:"<<dx_<<"\n"
<<std::setw(width)<<std::left<<"calibration:"<<(calibration_?"yes":"no")<<"\n"
<<std::setw(width)<<std::left<<"unit:"<<unit_<<"\n";
return ss.str();
}
};
// definition of abscissa (corresponds to key CD2)
struct abscissa2
{
double dx_;
bool calibration_;
std::string unit_;
bool reduction_;
bool ismultievent_;
bool sortbuffer_;
double x0_;
int pretriggerapp_;
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 11 ) throw std::runtime_error("invalid number of parameters in CD2");
dx_ = std::stod(get_parameter(buffer,&parameters[2]));
calibration_ = ( get_parameter(buffer,&parameters[3]) == std::string("1") );
unit_ = get_parameter(buffer,&parameters[5]);
reduction_ = ( get_parameter(buffer,&parameters[6]) == std::string("1") );
ismultievent_ = ( get_parameter(buffer,&parameters[7]) == std::string("1") );
sortbuffer_ = ( get_parameter(buffer,&parameters[8]) == std::string("1") );
x0_ = std::stod(get_parameter(buffer,&parameters[9]));
pretriggerapp_ = std::stoi( get_parameter(buffer,&parameters[10]) );
}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"dx:"<<dx_<<"\n"
<<std::setw(width)<<std::left<<"calibration:"<<(calibration_?"yes":"no")<<"\n"
<<std::setw(width)<<std::left<<"unit:"<<unit_<<"\n"
<<std::setw(width)<<std::left<<"reduction:"<<reduction_<<"\n"
<<std::setw(width)<<std::left<<"ismultievent:"<<ismultievent_<<"\n"
<<std::setw(width)<<std::left<<"sortbuffer:"<<sortbuffer_<<"\n"
<<std::setw(width)<<std::left<<"x0:"<<x0_<<"\n"
<<std::setw(width)<<std::left<<"pretriggerapp:"<<pretriggerapp_<<"\n";
return ss.str();
}
};
// start of component (corresponds to key CC)
struct component
{
int component_index_;
bool analog_digital_; // 1 => false (analog), 2 => true (digital)
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 4 ) throw std::runtime_error("invalid number of parameters in CC");
component_index_ = std::stoi(get_parameter(buffer,&parameters[2]));
analog_digital_ = ( std::stoi(get_parameter(buffer,&parameters[3])) == 2 );
}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"index:"<<component_index_<<"\n"
<<std::setw(width)<<std::left<<"analog/digital:"<<(analog_digital_?"digital":"analog")<<"\n";
return ss.str();
}
};
enum numtype {
unsigned_byte = 1,
signed_byte,
unsigned_short,
signed_short,
unsigned_long,
signed_long,
ffloat,
ddouble,
imc_devices_transitional_recording,
timestamp_ascii,
two_byte_word_digital,
eight_byte_unsigned_long,
six_byte_unsigned_long,
eight_byte_signed_long
};
// packaging information of component (corresponds to key CP)
struct packaging
{
unsigned long int buffer_reference_;
int bytes_;
numtype numeric_type_;
int signbits_;
int mask_;
unsigned long int offset_;
unsigned long int number_subsequent_samples_;
unsigned long int distance_bytes_;
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 10 ) throw std::runtime_error("invalid number of parameters in CP");
buffer_reference_ = std::stoi(get_parameter(buffer,&parameters[2]));
bytes_ = std::stoi(get_parameter(buffer,&parameters[3]));
numeric_type_ = (numtype)std::stoi(get_parameter(buffer,&parameters[4]));
signbits_ = std::stoi(get_parameter(buffer,&parameters[5]));
mask_ = std::stoi(get_parameter(buffer,&parameters[6]));
offset_ = std::stoul(get_parameter(buffer,&parameters[7]));
number_subsequent_samples_ = std::stoul(get_parameter(buffer,&parameters[8]));
distance_bytes_ = std::stoul(get_parameter(buffer,&parameters[9]));
}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"buffer-reference:"<<buffer_reference_<<"\n"
<<std::setw(width)<<std::left<<"datatype:"<<numeric_type_<<"\n"
<<std::setw(width)<<std::left<<"significant bits:"<<signbits_<<"\n"
<<std::setw(width)<<std::left<<"mask:"<<mask_<<"\n"
<<std::setw(width)<<std::left<<"offset:"<<offset_<<"\n"
<<std::setw(width)<<std::left<<"#subseq.-samples:"<<number_subsequent_samples_<<"\n"
<<std::setw(width)<<std::left<<"distance in bytes:"<<distance_bytes_<<"\n";
return ss.str();
}
};
// buffer description (corresponds to key Cb)
struct buffer
{
unsigned long int number_buffers_;
unsigned long int bytes_userinfo_;
// for every single buffer
unsigned long int buffer_reference_; // corresponds to buffer_reference_ in key CP
unsigned long int sample_index_; // corresponds to index of CS key
unsigned long int offset_buffer_; // number of bytes from beginning of CS key
unsigned long int number_bytes_; // number of bytes in buffer
unsigned long int offset_first_sample_;
unsigned long int number_filled_bytes_;
double x0_;
double add_time_; // start of trigger time = NT + add_time
// bool user_info_;
// bool new_event_;
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 13 ) throw std::runtime_error("invalid number of parameters in Cb");
number_buffers_ = std::stoul(get_parameter(buffer,&parameters[2]));
bytes_userinfo_ = std::stoul(get_parameter(buffer,&parameters[3]));
buffer_reference_ = std::stoul(get_parameter(buffer,&parameters[4]));
sample_index_ = std::stoul(get_parameter(buffer,&parameters[5]));
offset_buffer_ = std::stoul(get_parameter(buffer,&parameters[6]));
number_bytes_ = std::stoul(get_parameter(buffer,&parameters[7]));
offset_first_sample_ = std::stoul(get_parameter(buffer,&parameters[8]));
number_filled_bytes_ = std::stoul(get_parameter(buffer,&parameters[9]));
x0_ = std::stod(get_parameter(buffer,&parameters[11]));
add_time_ = std::stod(get_parameter(buffer,&parameters[12]));
}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"#buffers:"<<number_buffers_<<"\n"
<<std::setw(width)<<std::left<<"bytes user info:"<<bytes_userinfo_<<"\n"
<<std::setw(width)<<std::left<<"buffer reference:"<<buffer_reference_<<"\n"
<<std::setw(width)<<std::left<<"sample index:"<<sample_index_<<"\n"
<<std::setw(width)<<std::left<<"offset buffer:"<<offset_buffer_<<"\n"
<<std::setw(width)<<std::left<<"buffer size:"<<number_bytes_<<"\n"
<<std::setw(width)<<std::left<<"offset sample:"<<offset_first_sample_<<"\n"
<<std::setw(width)<<std::left<<"#filled bytes:"<<number_filled_bytes_<<"\n"
<<std::setw(width)<<std::left<<"time offset:"<<x0_<<"\n"
<<std::setw(width)<<std::left<<"add time:"<<add_time_<<"\n";
return ss.str();
}
};
// range of values of component (corresponds to key CR)
struct range
{
bool transform_; // 1 = true: yes, requires offset + factor, 0 = false: no
double factor_, offset_; // value = raw value * factor + offset
bool calibration_; // 1 = true: calibration, 0 = false: no calibration
std::string unit_;
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 8 ) throw std::runtime_error("invalid number of parameters in CR");
transform_ = (get_parameter(buffer,&parameters[2]) == std::string("1"));
factor_ = std::stod(get_parameter(buffer,&parameters[3]));
offset_ = std::stod(get_parameter(buffer,&parameters[4]));
calibration_ = (get_parameter(buffer,&parameters[5]) == std::string("1"));
unit_ = get_parameter(buffer,&parameters[7]);
}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"transform:"<<(transform_?"yes":"no")<<"\n"
<<std::setw(width)<<std::left<<"factor:"<<factor_<<"\n"
<<std::setw(width)<<std::left<<"offset:"<<offset_<<"\n"
<<std::setw(width)<<std::left<<"calibration:"<<(calibration_?"yes":"no")<<"\n"
<<std::setw(width)<<std::left<<"unit:"<<unit_<<"\n";
return ss.str();
}
};
// channel (corresponds to key CN)
struct channelobj
{
unsigned long int group_index_; // corresponds to group-index in CB key
bool index_bit_; // true = 1: digital, false = 0: analog
std::string name_;
std::string comment_;
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 9 ) throw std::runtime_error("invalid number of parameters in CN");
group_index_ = std::stoul(get_parameter(buffer,&parameters[2]));
index_bit_ = (get_parameter(buffer,&parameters[4]) == std::string("1"));
name_ = get_parameter(buffer,&parameters[6]);
comment_ = get_parameter(buffer,&parameters[8]);
}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"group-index:"<<group_index_<<"\n"
<<std::setw(width)<<std::left<<"index-bit:"<<index_bit_<<"\n"
<<std::setw(width)<<std::left<<"name:"<<name_<<"\n"
<<std::setw(width)<<std::left<<"comment:"<<comment_<<"\n";
return ss.str();
}
};
// rawdata (corresponds to key CS)
struct data
{
unsigned long int index_; // starting from 1 in first CS block in file
// std::vector<unsigned char> rawdata_;
// unsigned long int begin_buffer_, end_buffer_;
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 4 ) throw std::runtime_error("invalid number of parameters in CS");
index_ = std::stoul(get_parameter(buffer,&parameters[2]));
}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"index:"<<index_<<"\n";
// <<std::setw(width)<<std::left<<"(begin,end) buffer:"
// <<"("<<begin_buffer_<<","<<end_buffer_<<")"<<"\n";
return ss.str();
}
};
// language (corresponds to key NL)
struct language
{
std::string codepage_;
std::string language_code_;
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if (parameters.size() < 4) throw std::runtime_error("invalid number of parameters in NL");
codepage_ = get_parameter(buffer, &parameters[2]);
language_code_ = get_parameter(buffer, &parameters[3]);
}
};
// origin of data (corresponds to key NO)
struct origin_data
{
bool origin_; // corresponds to true = 1 ("verrechnet") and false = 0 ("Original")
std::string generator_;
std::string comment_;
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 7 ) throw std::runtime_error("invalid number of parameters in NO");
origin_ = ( get_parameter(buffer,&parameters[2]) == std::string("1") );
generator_ = get_parameter(buffer,&parameters[4]);
comment_ = get_parameter(buffer,&parameters[6]);
}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"origin:"<<(origin_?"verrechnet":"Original")<<"\n"
<<std::setw(width)<<std::left<<"generator:"<<generator_<<"\n"
<<std::setw(width)<<std::left<<"comment:"<<comment_<<"\n";
return ss.str();
}
};
// trigger timestamp (corresponds to key NT1)
struct triggertime
{
std::tm tms_;
double trigger_time_frac_secs_;
// construct members by parsing particular parameters from buffer
void parse(const std::vector<unsigned char>* buffer, const std::vector<parameter>& parameters)
{
if ( parameters.size() < 8 ) throw std::runtime_error("invalid number of parameters in NT1");
tms_ = std::tm();
tms_.tm_mday = std::stoi( get_parameter(buffer,&parameters[2]) );
tms_.tm_mon = std::stoi( get_parameter(buffer,&parameters[3]) ) - 1;
tms_.tm_year = std::stoi( get_parameter(buffer,&parameters[4]) ) - 1900;
tms_.tm_hour = std::stoi( get_parameter(buffer,&parameters[5]) );
tms_.tm_min = std::stoi( get_parameter(buffer,&parameters[6]) );
long double secs = std::stold( get_parameter(buffer,&parameters[7]) );
double secs_int;
trigger_time_frac_secs_ = modf((double)secs,&secs_int);
tms_.tm_sec = (int)secs_int;
}
// get info string
std::string get_info(int width = 20)
{
std::stringstream ss;
ss<<std::setw(width)<<std::left<<"timestamp:"<<std::put_time(&tms_, "%Y-%m-%dT%H:%M:%S")<<"\n";
return ss.str();
}
};
}
namespace imc {
// create wrapper for imc_object types
// (not particularly memory-efficient but it simplifies the remaining stuff
// considerably and the structs are pretty small anyway!)
class rawobject
{
format fmt_; // 0
keygroup kyg_; // 1
groupobj grp_; // 2
text txt_; // 3
datafield dtf_; // 4
abscissa abs_; // 5
component cmt_; // 6
packaging pkg_; // 7
buffer bfr_; // 8
range rng_; // 9
channelobj chn_; // 10
data dat_; // 11
origin_data org_; // 12
triggertime trt_; // 13
abscissa2 abs2_; // 14
int objidx_;
public:
rawobject(): objidx_(-1) { }
void parse(imc::key key, const std::vector<unsigned char>* buffer,
const std::vector<parameter>& parameters)
{
if ( key.name_ == std::string("CF") )
{
fmt_.parse(buffer,parameters);
objidx_ = 0;
}
else if ( key.name_ == std::string("CK") )
{
kyg_.parse(buffer,parameters);
objidx_ = 1;
}
else if ( key.name_ == std::string("CB") )
{
grp_.parse(buffer,parameters);
objidx_ = 2;
}
else if ( key.name_ == std::string("CT") )
{
txt_.parse(buffer,parameters);
objidx_ = 3;
}
else if ( key.name_ == std::string("CG") )
{
dtf_.parse(buffer,parameters);
objidx_ = 4;
}
else if ( key.name_ == std::string("CD") && key.version_ == 1 )
{
abs_.parse(buffer,parameters);
objidx_ = 5;
}
else if ( key.name_ == std::string("CC") )
{
cmt_.parse(buffer,parameters);
objidx_ = 6;
}
else if ( key.name_ == std::string("CP") )
{
pkg_.parse(buffer,parameters);
objidx_ = 7;
}
else if ( key.name_ == std::string("Cb") )
{
bfr_.parse(buffer,parameters);
objidx_ = 8;
}
else if ( key.name_ == std::string("CR") )
{
rng_.parse(buffer,parameters);
objidx_ = 9;
}
else if ( key.name_ == std::string("CN") )
{
chn_.parse(buffer,parameters);
objidx_ = 10;
}
else if ( key.name_ == std::string("CS") )
{
dat_.parse(buffer,parameters);
objidx_ = 11;
}
else if ( key.name_ == std::string("NO") )
{
org_.parse(buffer,parameters);
objidx_ = 12;
}
else if ( key.name_ == std::string("NT") && key.version_ == 1 )
{
trt_.parse(buffer,parameters);
objidx_ = 13;
}
else if ( key.name_ == std::string("CD") && key.version_ == 2 )
{
abs2_.parse(buffer,parameters);
objidx_ = 14;
}
else
{
if ( key.name_.at(0) == 'C' )
{
throw std::logic_error(
std::string("unsupported block associated to critical key ")
+ key.name_ + std::to_string(key.version_)
);
}
else
{
std::cout<<"WARNING: unsupported block associated to noncritical key "
<<key.name_<<key.version_<<"\n";
}
}
}
// provide info string
std::string get_info(int width = 20)
{
switch (objidx_) {
case 0:
return fmt_.get_info();
case 1:
return kyg_.get_info();
case 2:
return grp_.get_info();
case 3:
return txt_.get_info();
case 4:
return dtf_.get_info();
case 5:
return abs_.get_info();
case 6:
return cmt_.get_info();
case 7:
return pkg_.get_info();
case 8:
return bfr_.get_info();
case 9:
return rng_.get_info();
case 10:
return chn_.get_info();
case 11:
return dat_.get_info();
case 12:
return org_.get_info();
case 13:
return trt_.get_info();
case 14:
return abs2_.get_info();
default:
return std::string("");
}
}
};
}
#endif
//---------------------------------------------------------------------------//