//---------------------------------------------------------------------------// #ifndef IMCCHANNEL #define IMCCHANNEL #include "imc_datatype.hpp" #include "imc_conversion.hpp" #include #include #include #include //---------------------------------------------------------------------------// namespace imc { // collect uuid's of blocks required for full channel reconstruction struct channel_env { // define unique identifer for channel_env std::string uuid_; // collect affiliate blocks for a single channel std::string CBuuid_, CGuuid_, CCuuid_, CNuuid_; std::string CDuuid_, CTuuid_, Cbuuid_, CPuuid_, CRuuid_, CSuuid_; std::string NTuuid_, NOuuid_, NLuuid_; // reset all members void reset() { uuid_.clear(); CBuuid_.clear(); CGuuid_.clear(); CCuuid_.clear(); CNuuid_.clear(); CDuuid_.clear(); CTuuid_.clear(); Cbuuid_.clear(); CPuuid_.clear(); CRuuid_.clear(); CSuuid_.clear(); NTuuid_.clear(); NOuuid_.clear(); NLuuid_.clear(); } // get info std::string get_info(int width = 20) { std::stringstream ss; ss< std::string joinvec(std::vector
myvec, unsigned long int limit = 10, int prec = 10, bool fixed = true) { // include entire list for limit = 0 unsigned long int myvecsize = (unsigned long int)myvec.size(); limit = (limit == 0) ? myvecsize : limit; std::stringstream ss; ss<<"["; if ( myvec.size() <= limit ) { for ( dt el: myvec ) { customize_stream(ss,prec,fixed); ss< 1 ) sumstr.pop_back(); sumstr += std::string("]"); return sumstr; } // channel struct channel { // associated environment of blocks and map of blocks channel_env chnenv_; std::map* blocks_; std::vector* buffer_; // collect meta-data of channels according to env, // just everything valueable in here std::string uuid_; std::string name_, comment_; std::string origin_, origin_comment_, text_; std::chrono::system_clock::time_point trigger_time_, absolute_trigger_time_; double trigger_time_frac_secs_; std::string language_code_, codepage_; std::string yname_, yunit_; std::string xname_, xunit_; double xstepwidth_, xoffset_; int xprec_; // buffer and data int signbits_, num_bytes_; // unsigned long int byte_offset_; unsigned long int buffer_offset_, buffer_size_; long int addtime_; int datatp_; imc::datatype dattyp_; std::vector ydata_; std::vector xdata_; // range, factor and offset double factor_, offset_; // group reference the channel belongs to int group_index_; std::string group_uuid_, group_name_, group_comment_; // constructor takes channel's block environment channel(channel_env &chnenv, std::map* blocks, std::vector* buffer): chnenv_(chnenv), blocks_(blocks), buffer_(buffer), factor_(1.), offset_(0.), group_index_(-1) { // declare list of block parameters std::vector prms; // use uuid from CN block uuid_ = chnenv_.CNuuid_; // extract associated CB data if ( blocks_->count(chnenv_.CBuuid_) == 1 ) { prms = blocks_->at(chnenv_.CBuuid_).get_parameters(); group_index_ = std::stoi(blocks_->at(chnenv_.CBuuid_).get_parameter(prms[2])); group_name_ = blocks_->at(chnenv_.CBuuid_).get_parameter(prms[4]); group_comment_ = blocks_->at(chnenv_.CBuuid_).get_parameter(prms[6]); } // extract associated CT data if ( blocks_->count(chnenv_.CTuuid_) == 1 ) { prms = blocks_->at(chnenv_.CTuuid_).get_parameters(); text_ = blocks_->at(chnenv_.CTuuid_).get_parameter(prms[4]) + std::string(" - ") + blocks_->at(chnenv_.CTuuid_).get_parameter(prms[6]) + std::string(" - ") + blocks_->at(chnenv_.CTuuid_).get_parameter(prms[8]); } // extract associated CD data if ( blocks_->count(chnenv_.CDuuid_) == 1 ) { prms = blocks_->at(chnenv_.CDuuid_).get_parameters(); xstepwidth_ = std::stod(blocks_->at(chnenv_.CDuuid_).get_parameter(prms[2])); xunit_ = blocks_->at(chnenv_.CDuuid_).get_parameter(prms[5]); // TODO // xname_ = std::string("time"); // find appropriate precision for "xdata_" by means of "xstepwidth_" xprec_ = (xstepwidth_ > 0 ) ? (int)ceil(fabs(log10(xstepwidth_))) : 10; } // extract associated CP data if ( blocks_->count(chnenv_.CPuuid_) == 1 ) { prms = blocks_->at(chnenv_.CPuuid_).get_parameters(); num_bytes_ = std::stoi(blocks_->at(chnenv_.CPuuid_).get_parameter(prms[3])); datatp_ = std::stoi(blocks_->at(chnenv_.CPuuid_).get_parameter(prms[4])); signbits_ = std::stoi(blocks_->at(chnenv_.CPuuid_).get_parameter(prms[5])); // byte_offset_ = std::stoul(blocks_->at(chnenv_.CPuuid_).get_parameter(prms[7])); } // extract associated Cb data if ( blocks_->count(chnenv_.Cbuuid_) == 1 ) { prms = blocks_->at(chnenv_.Cbuuid_).get_parameters(); buffer_offset_ = std::stoul(blocks_->at(chnenv_.Cbuuid_).get_parameter(prms[6])); buffer_size_ = std::stoul(blocks_->at(chnenv_.Cbuuid_).get_parameter(prms[7])); xoffset_ = std::stod(blocks_->at(chnenv_.Cbuuid_).get_parameter(prms[11])); addtime_ = (long int)std::stod(blocks_->at(chnenv_.Cbuuid_).get_parameter(prms[12])); } // extract associated CR data if ( blocks_->count(chnenv_.CRuuid_) == 1 ) { prms = blocks_->at(chnenv_.CRuuid_).get_parameters(); factor_ = std::stod(blocks_->at(chnenv_.CRuuid_).get_parameter(prms[3])); offset_ = std::stod(blocks_->at(chnenv_.CRuuid_).get_parameter(prms[4])); yunit_ = blocks_->at(chnenv_.CRuuid_).get_parameter(prms[7]); } // extract associated CN data if ( blocks_->count(chnenv_.CNuuid_) == 1 ) { prms = blocks_->at(chnenv_.CNuuid_).get_parameters(); name_ = blocks_->at(chnenv_.CNuuid_).get_parameter(prms[6]); yname_ = name_; comment_ = blocks_->at(chnenv_.CNuuid_).get_parameter(prms[8]); // group_index_ = std::stoi(blocks_->at(chnenv_.CNuuid_).get_parameter(prms[2])); } // extract associated NO data if ( blocks_->count(chnenv_.NOuuid_) == 1 ) { prms = blocks_->at(chnenv_.NOuuid_).get_parameters(); origin_ = blocks_->at(chnenv_.NOuuid_).get_parameter(prms[4]); origin_comment_ = blocks_->at(chnenv_.NOuuid_).get_parameter(prms[6]); } // extract associated NL data // codepage: // - http://www.iana.org/assignments/character-sets/character-sets.xhtml // - https://de.wikipedia.org/wiki/Zeichensatztabelle // language-code: // - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c?redirectedfrom=MSDN if ( blocks_->count(chnenv_.NLuuid_) == 1 ) { prms = blocks_->at(chnenv_.NLuuid_).get_parameters(); codepage_ = blocks_->at(chnenv_.NLuuid_).get_parameter(prms[2]); language_code_ = blocks_->at(chnenv_.NLuuid_).get_parameter(prms[3]); } // obtain NT data // - https://en.cppreference.com/w/cpp/chrono/c/tm // - https://en.cppreference.com/w/cpp/io/manip/put_time if ( blocks_->count(chnenv_.NTuuid_) == 1 ) { prms = blocks_->at(chnenv_.NTuuid_).get_parameters(); //std::tm tm{}; std::tm tms = std::tm(); tms.tm_mday = std::stoi(blocks_->at(chnenv_.NTuuid_).get_parameter(prms[2])); tms.tm_mon = std::stoi(blocks_->at(chnenv_.NTuuid_).get_parameter(prms[3])) - 1; tms.tm_year = std::stoi(blocks_->at(chnenv_.NTuuid_).get_parameter(prms[4])) - 1900; tms.tm_hour = std::stoi(blocks_->at(chnenv_.NTuuid_).get_parameter(prms[5])); tms.tm_min = std::stoi(blocks_->at(chnenv_.NTuuid_).get_parameter(prms[6])); long double secs = std::stold(blocks_->at(chnenv_.NTuuid_).get_parameter(prms[7])); double secs_int; trigger_time_frac_secs_ = modf((double)secs,&secs_int); tms.tm_sec = (int)secs_int; // generate std::chrono::system_clock::time_point type std::time_t ts = std::mktime(&tms); trigger_time_ = std::chrono::system_clock::from_time_t(ts); } // start converting binary buffer to imc::datatype if ( !chnenv_.CSuuid_.empty() ) convert_buffer(); // calculate absolute trigger-time absolute_trigger_time_ = trigger_time_ + std::chrono::seconds(addtime_); // + std::chrono::nanoseconds((long int)(trigger_time_frac_secs_*1.e9)); } // convert buffer to actual datatype void convert_buffer() { // TODO no clue how/if/when to handle buffer offset/mask/subsequent_bytes // etc. and whatever that shit is! std::vector prms = blocks_->at(chnenv_.CSuuid_).get_parameters(); if ( prms.size() < 4) { throw std::runtime_error("CS block is invalid and features to few parameters"); } unsigned long int buffstrt = prms[3].begin(); std::vector CSbuffer( buffer_->begin()+buffstrt+1, buffer_->begin()+buffstrt+buffer_size_+1 ); // determine number of values in buffer unsigned long int num_values = (unsigned long int)(CSbuffer.size()/(signbits_/8)); if ( num_values*(signbits_/8) != CSbuffer.size() ) { throw std::runtime_error("CSbuffer and significant bits of datatype don't match"); } // adjust size of ydata ydata_.resize(num_values); // distinguish numeric datatypes included in "imc_datatype" if ( datatp_ == 1 ) { imc::convert_data_to_type(CSbuffer,ydata_); } else if ( datatp_ == 2 ) { imc::convert_data_to_type(CSbuffer,ydata_); } else if ( datatp_ == 3 ) { imc::convert_data_to_type(CSbuffer,ydata_); } else if ( datatp_ == 4 ) { imc::convert_data_to_type(CSbuffer,ydata_); } else if ( datatp_ == 5 ) { imc::convert_data_to_type(CSbuffer,ydata_); } else if ( datatp_ == 6 ) { imc::convert_data_to_type(CSbuffer,ydata_); } else if ( datatp_ == 7 ) { imc::convert_data_to_type(CSbuffer,ydata_); } else if ( datatp_ == 8 ) { imc::convert_data_to_type(CSbuffer,ydata_); } // ... else if ( datatp_ == 11 ) { imc::convert_data_to_type(CSbuffer,ydata_); } else { throw std::runtime_error(std::string("unsupported/unknown datatype") + std::to_string(datatp_)); } // fill xdata_ for ( unsigned long int i = 0; i < num_values; i++ ) { xdata_.push_back(xoffset_+(double)i*xstepwidth_); } // employ data transformation if ( factor_ != 1.0 || offset_ != 0.0 ) { for ( imc::datatype& el: ydata_ ) { // std::cout<<"value:"<(ydata_,6,9,true)<<"\n" <(xdata_,6,xprec_,true)<<"\n"; // <(ydata_,0,9,true) <<",\"xdata\":"<(xdata_,0,xprec_,true); } // ss<<"\",\"aff. blocks\":\""<