From a41fe1784d4f334fd8d2c3e0771e87a323f645fa Mon Sep 17 00:00:00 2001 From: Jonathan Hanks <jonathan.hanks@ligo.org> Date: Fri, 23 Aug 2019 14:32:33 -0700 Subject: [PATCH] Created a 'multi' fe stream generator. fe_stream_test is a single front end outputing a rmIpcStr to mbuf. fe_multi_stream_test can be used to simulate fe systems in bulk, it outputs to a dac_multi_cycle_t in mbuf, along with populating a ini directory and master file. This is targeted for daqd development and testing. This adds a fe_generator_support library which holds some common code between the two generators. This also adds another check to fe_stream_check, verifying the data crc. --- src/fe_stream_test/CMakeLists.txt | 27 +- src/fe_stream_test/fe_generator_support.cc | 111 +++++ src/fe_stream_test/fe_generator_support.hh | 55 +++ src/fe_stream_test/fe_multi_stream_test.cc | 506 +++++++++++++++++++++ src/fe_stream_test/fe_stream_check.cc | 19 + src/fe_stream_test/fe_stream_generator.cc | 63 +++ src/fe_stream_test/fe_stream_generator.hh | 59 +-- src/fe_stream_test/fe_stream_test.cc | 93 +--- 8 files changed, 775 insertions(+), 158 deletions(-) create mode 100644 src/fe_stream_test/fe_generator_support.cc create mode 100644 src/fe_stream_test/fe_generator_support.hh create mode 100644 src/fe_stream_test/fe_multi_stream_test.cc create mode 100644 src/fe_stream_test/fe_stream_generator.cc diff --git a/src/fe_stream_test/CMakeLists.txt b/src/fe_stream_test/CMakeLists.txt index ccbe6c8de..03c7e6c5d 100644 --- a/src/fe_stream_test/CMakeLists.txt +++ b/src/fe_stream_test/CMakeLists.txt @@ -1,9 +1,14 @@ add_library(fe_stream_generator STATIC + fe_stream_generator.cc fe_stream_generator.hh str_split.cc str_split.hh) target_include_directories(fe_stream_generator PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +add_library(fe_generator_support STATIC + fe_generator_support.hh + fe_generator_support.cc) + add_executable(fe_stream_test fe_stream_test.cc gps.hh @@ -11,8 +16,19 @@ add_executable(fe_stream_test target_link_libraries(fe_stream_test PRIVATE fe_stream_generator + fe_generator_support + rt) + +add_executable(fe_multi_stream_test + fe_multi_stream_test.cc + gps.hh) +target_link_libraries(fe_multi_stream_test + PRIVATE + fe_stream_generator + fe_generator_support rt) + add_executable(fe_stream_check fe_stream_check.cc ) @@ -28,14 +44,3 @@ target_link_libraries(fe_check rt driver::shmem) -if (${libNDS2Client_FOUND}) - -# add_executable(fe_stream_check -# fe_stream_check.cc -# ) -# target_link_libraries(fe_stream_check -# PRIVATE -# fe_stream_generator -# nds2client::cxx) - -endif (${libNDS2Client_FOUND}) diff --git a/src/fe_stream_test/fe_generator_support.cc b/src/fe_stream_test/fe_generator_support.cc new file mode 100644 index 000000000..ef427dbcd --- /dev/null +++ b/src/fe_stream_test/fe_generator_support.cc @@ -0,0 +1,111 @@ +// +// Created by jonathan.hanks on 8/22/19. +// +#include <fstream> + +#include "fe_generator_support.hh" + +extern "C" { + +#include "../drv/crc.c" +} + +std::string +cleaned_system_name( const std::string& system_name ) +{ + std::vector< char > buf; + for ( int i = 0; i < system_name.size( ); ++i ) + { + if ( system_name[ i ] == ':' ) + continue; + buf.push_back( (char)tolower( system_name[ i ] ) ); + } + buf.push_back( '\0' ); + return std::string( buf.data( ) ); +} + +std::string +generate_ini_filename( const std::string& ini_dir, + const std::string& system_name ) +{ + std::ostringstream ss; + ss << ini_dir << "/" << system_name << ".ini"; + return ss.str( ); +} + +std::string +generate_par_filename( const std::string& ini_dir, + const std::string& system_name ) +{ + std::ostringstream ss; + ss << ini_dir << "/tpchn_" << system_name << ".par"; + return ss.str( ); +} + +void +output_ini_files( const std::string& ini_dir, + const std::string& system_name, + std::vector< GeneratorPtr > channels, + std::vector< GeneratorPtr > tp_channels, + int dcuid, + int model_rate) +{ + using namespace std; + + string clean_name = cleaned_system_name( system_name ); + string fname_ini = generate_ini_filename( ini_dir, clean_name ); + string fname_par = generate_par_filename( ini_dir, clean_name ); + ofstream os_ini( fname_ini.c_str( ) ); + ofstream os_par( fname_par.c_str( ) ); + os_ini << "[default]\ngain=1.0\nacquire=3\ndcuid=" << dcuid + << "\nifoid=0\n"; + os_ini << "datatype=2\ndatarate=" << model_rate << "\noffset=0\nslope=1.0\nunits=undef\n\n"; + + vector< GeneratorPtr >::iterator cur = channels.begin( ); + for ( ; cur != channels.end( ); ++cur ) + { + Generator* gen = ( cur->get( ) ); + ( *cur )->output_ini_entry( os_ini ); + } + + for ( cur = tp_channels.begin( ); cur != tp_channels.end( ); ++cur ) + { + Generator* gen = ( cur->get( ) ); + ( *cur )->output_par_entry( os_par ); + } +} + +unsigned int +calculate_ini_crc( const std::string& ini_dir, const std::string& system_name ) +{ + std::string fname_ini = + generate_ini_filename( ini_dir, cleaned_system_name( system_name ) ); + std::ifstream is( fname_ini.c_str( ), std::ios::binary ); + + std::vector< char > buffer( 64 * 1024 ); + + size_t file_size = 0; + unsigned int file_crc = 0; + while ( is.read( &buffer[ 0 ], buffer.size( ) ) ) + { + file_crc = crc_ptr( &buffer[ 0 ], buffer.size( ), file_crc ); + file_size += buffer.size( ); + } + if ( is.gcount( ) > 0 ) + { + file_crc = crc_ptr( &buffer[ 0 ], is.gcount( ), file_crc ); + file_size += is.gcount( ); + } + file_crc = crc_len( file_size, file_crc ); + return file_crc; +} + +unsigned int +calculate_crc( const void* buffer, size_t len ) +{ + if (!buffer || len <= 0) + { + return 0; + } + return crc_len(len, crc_ptr( reinterpret_cast<char*>(const_cast<void*>(buffer)), len, 0)); +} \ No newline at end of file diff --git a/src/fe_stream_test/fe_generator_support.hh b/src/fe_stream_test/fe_generator_support.hh new file mode 100644 index 000000000..9532dffc8 --- /dev/null +++ b/src/fe_stream_test/fe_generator_support.hh @@ -0,0 +1,55 @@ +// +// Created by jonathan.hanks on 8/22/19. +// + +#ifndef DAQD_TRUNK_FE_GENERATOR_SUPPORT_HH +#define DAQD_TRUNK_FE_GENERATOR_SUPPORT_HH + +#include <string> +#include <vector> + +#include "fe_stream_generator.hh" + +class ChNumDb +{ +private: + int max_; + +public: + ChNumDb( ) : max_( 40000 ) + { + } + explicit ChNumDb( int start ) : max_( start ) + { + } + + int + next( int channel_type ) + { + max_++; + return max_; + } +}; + +std::string cleaned_system_name( const std::string& system_name ); + +std::string generate_ini_filename( const std::string& ini_dir, + const std::string& system_name ); + +std::string generate_par_filename( const std::string& ini_dir, + const std::string& system_name ); + +void output_ini_files( const std::string& ini_dir, + const std::string& system_name, + std::vector< GeneratorPtr > channels, + std::vector< GeneratorPtr > tp_channels, + int dcuid, + int model_rate=2048); + +unsigned int calculate_ini_crc( const std::string& ini_dir, + const std::string& system_name ); + +unsigned int +calculate_crc( const void* buffer, size_t len ); + +#endif // DAQD_TRUNK_FE_GENERATOR_SUPPORT_HH diff --git a/src/fe_stream_test/fe_multi_stream_test.cc b/src/fe_stream_test/fe_multi_stream_test.cc new file mode 100644 index 000000000..5739c27a8 --- /dev/null +++ b/src/fe_stream_test/fe_multi_stream_test.cc @@ -0,0 +1,506 @@ +// +// Created by jonathan.hanks on 8/22/19. +// +#include <cstdio> +#include <cstdlib> +#include <fstream> +#include <iostream> +#include <iterator> +#include <numeric> +#include <map> +#include <string> +#include <sstream> + +#include "fe_stream_generator.hh" +#include "fe_generator_support.hh" +#include "../include/daq_core.h" + +#include "gps.hh" + +extern "C" { + +#include "../drv/rfm.c" +} + +struct ModelParams +{ + ModelParams(): name(), model_rate(2048), dcuid(-1), data_rate(10000) {} + std::string name; + int model_rate; + int dcuid; + int data_rate; +}; + +struct Options +{ + Options(): models(), ini_root(), master_path("master"), mbuf_name("local_dc"),mbuf_size_mb(100), show_help(false) {} + std::vector<ModelParams> models; + std::string ini_root; + std::string master_path; + std::string mbuf_name; + size_t mbuf_size_mb; + bool show_help; +}; + +class GeneratorStore +{ +public: + GeneratorStore( ) : store_( ) + { + } + + GeneratorPtr + get( const std::string& name ) + { + std::map<std::string, GeneratorPtr>::iterator it = store_.find( name ); + return ( it == store_.end() ? GeneratorPtr((Generator*)0) : it->second); + } + + void + set( const std::string& name, GeneratorPtr& g ) + { + std::map<std::string, GeneratorPtr>::iterator it = store_.find( name ); + if (it == store_.end()) + { + store_.insert(std::make_pair(name, g)); + } + } + +private: + std::map< std::string, GeneratorPtr > store_; +}; + +class IniManager +{ +public: + IniManager(const std::string& ini_root, const std::string& master_path): + ini_root_(ini_root), + master_path_(master_path) + { + } + + int + add(const std::string& model_name, int dcu_id, int model_rate, std::vector<GeneratorPtr> chans, + std::vector<GeneratorPtr> test_points) + { + output_ini_files(ini_root_, model_name, chans, test_points, dcu_id, model_rate); + add_to_master(model_name); + return calculate_ini_crc(ini_root_, model_name); + } + +private: + void + add_to_master(const std::string& model_name) + { + std::string name = cleaned_system_name(model_name); + master_contents_.push_back(generate_ini_filename(ini_root_, model_name)); + master_contents_.push_back(generate_par_filename(ini_root_, model_name)); + + rewrite_master(); + } + + void + rewrite_master() + { + std::string tmp_name = master_path_; + tmp_name += ".tmp"; + + { + std::ofstream out(tmp_name.c_str()); + std::ostream_iterator<std::string> it(out, "\n"); + std::copy(master_contents_.begin(), master_contents_.end(), it); + } + + if (std::rename(tmp_name.c_str(), master_path_.c_str()) == -1) + { + throw std::runtime_error("Unable to replace the master file"); + } + + } + + std::vector<std::string> master_contents_; + + std::string ini_root_; + std::string master_path_; +}; + +/** + * @brief Represent a model (essentially a list of channels + testpoints) + */ +class Model +{ +public: + /** + * @brief Initialize a model, generating a set of channels + * @param name model name + * @param dcu_id dcu + * @param model_rate rate + * @param data_rate_bytes The max number of bytes to use. Should be a multiple + * of 4 (sizeof float) + */ + Model( IniManager& ini_manager, const std::string& name, int dcu_id, int model_rate, int data_rate_bytes): + name_(name), dcu_id_(dcu_id), model_rate_(model_rate), + data_rate_bytes_(data_rate_bytes), + config_crc_(0), + tp_table_(32, 0), + generators_(), + tp_generators_(), + null_tp_((Generator*)0) + { + size_t fast_data_bytes = data_rate_bytes_/2; + size_t mid_data_bytes = data_rate_bytes/4; + size_t slow_data_bytes = data_rate_bytes/4; + + if (fast_data_bytes + mid_data_bytes + slow_data_bytes != data_rate_bytes_) + { + std::cerr << fast_data_bytes << "\n"; + std::cerr << mid_data_bytes << "\n"; + std::cerr << slow_data_bytes << "\n"; + std::cerr << data_rate_bytes_ << "\n"; + throw std::runtime_error("Fast/mid/slow mix is bad, rates do not add up"); + } + + int mid_rate = model_rate_/2; + + size_t fast_channel_num = fast_data_bytes/(sizeof(float)*model_rate_); + size_t mid_channel_num = mid_data_bytes/(sizeof(float)*mid_rate); + size_t slow_channel_num = slow_data_bytes/(sizeof(float)*16); + size_t channel_num = fast_channel_num + slow_channel_num; + + generators_.reserve(channel_num); + tp_generators_.reserve(tp_table_.size()); + + ChNumDb chDb; + ChNumDb tpDb; + + for (size_t i = 0; i < fast_channel_num; ++i) + { + int chnum = chDb.next(4); + + std::ostringstream ss; + ss << name_ << "-" << i; + generators_.push_back(GeneratorPtr(new Generators::GPSSecondWithOffset<int>(SimChannel(ss.str(), 2, model_rate_, chnum), (i + dcu_id_)%21))); + } + for (size_t i = fast_channel_num; i < mid_channel_num; ++i) + { + int chnum = chDb.next(4); + + std::ostringstream ss; + ss << name_ << "-" << i; + generators_.push_back(GeneratorPtr(new Generators::GPSSecondWithOffset<int>(SimChannel(ss.str(), 2, mid_rate, chnum), (i + dcu_id_)%21))); + } + for (size_t i = mid_channel_num; i < channel_num; ++i) + { + int chnum = chDb.next(4); + + std::ostringstream ss; + ss << name_ << "-" << i; + generators_.push_back(GeneratorPtr(new Generators::GPSSecondWithOffset<int>(SimChannel(ss.str(), 2, 16, chnum), (i + dcu_id_)%21))); + } + + + for (size_t i = 0; i < tp_table_.size(); ++i) + { + int chnum = tpDb.next(4); + + std::ostringstream ss; + ss << name_ << "-TP" << i; + // TP need truncated + tp_generators_.push_back(GeneratorPtr(new Generators::GPSMod100kSecWithOffset<float>(SimChannel(ss.str(), 4, model_rate_, chnum, dcu_id_), (i + dcu_id_)%21))); + } + GeneratorPtr null_tp = GeneratorPtr(new Generators::StaticValue<float>(SimChannel("null_tp_value", 4, model_rate_, 0x7fffffff), 0.0)); + config_crc_ = ini_manager.add(name, dcu_id, model_rate, generators_, tp_generators_); + } + + const std::string& + name() const + { + return name_; + } + + int + dcu_id() const + { + return dcu_id_; + } + + size_t + model_rate() const + { + return model_rate_; + } + + size_t + chan_count() const + { + return generators_.size(); + } + + std::vector<GeneratorPtr>& + generators() + { + return generators_; + } + + std::vector<GeneratorPtr>& + tp_generators() + { + return tp_generators_; + } + + int + config_crc() const + { + return config_crc_; + } +private: + std::string name_; + int dcu_id_; + size_t model_rate_; + size_t data_rate_bytes_; + int config_crc_; + std::vector< int > tp_table_; + std::vector< GeneratorPtr > generators_; + std::vector< GeneratorPtr > tp_generators_; + GeneratorPtr null_tp_; +}; + +typedef std::tr1::shared_ptr<Model> ModelPtr; + +/** + * @brief Given a set of models, and a data block, fill the data block with the models data. + * @param models Set of models + * @param dest Where to put the data + * @param max_data_size The data block size + * @param cycle cycle number + * @param cur_time gps time to generate data for + */ +void +generate_models(std::vector<ModelPtr>& models, daq_dc_data_t& dest, size_t max_data_size, int cycle, const GPS::gps_time& cur_time ) +{ + dest.header.dcuTotalModels = models.size(); + dest.header.fullDataBlockSize = 0; + char* data = dest.dataBlock; + char* data_end = data+max_data_size; + for (int i = 0; i < models.size(); ++i) + { + char *start = data; + ModelPtr& mp = models[i]; + daq_msg_header_t& dcu_header = dest.header.dcuheader[i]; + dcu_header.dcuId = mp->dcu_id(); + dcu_header.fileCrc = mp->config_crc(); + dcu_header.status = 2; + dcu_header.cycle = cycle; + dcu_header.timeSec = cur_time.sec; + dcu_header.timeNSec = cur_time.nanosec; + dcu_header.dataCrc = 0; + dcu_header.dataBlockSize = 0; + dcu_header.tpBlockSize = 0; + dcu_header.tpCount = 0; + std::fill(&dcu_header.tpNum[0], &dcu_header.tpNum[DAQ_GDS_MAX_TP_NUM], 0); + + std::vector<GeneratorPtr>& gen = mp->generators(); + std::vector<GeneratorPtr>::iterator it = gen.begin(); + for (; it != gen.end(); ++it ) + { + char* next_data = (*it)->generate(static_cast<int>(cur_time.sec), static_cast<int>(cur_time.nanosec), data); + dest.header.fullDataBlockSize += static_cast<int>(next_data - data); + data = next_data; + } + dcu_header.dataBlockSize = static_cast<unsigned int>(data - start); + dcu_header.dataCrc = calculate_crc( reinterpret_cast<void*>(start), dcu_header.dataBlockSize); + } +} + +void +usage(const char* progname) +{ + std::cout << progname << " simulation for multiple LIGO FE computers\n"; + std::cout << "\nUsage: " << progname << " options\n"; + std::cout << "Where options are:\n"; + std::cout << "\t-i path - Path to the ini/par file folder to use (should be a full path)\n"; + std::cout << "\t-M path - Path to the master file (will be overwritten) [master]\n"; + std::cout << "\t-b name - Name of the output mbuf [local_dc]\n"; + std::cout << "\t-m size_mb - Size in MB of the output mbuf [100]\n"; + std::cout << "\t-k size_kb - Default data rate of each model in kB\n"; + std::cout << "\t-R num - number of models to simulate [1-120]\n"; + std::cout << "\t-h - this help\n"; +} + +Options +parse_arguments(int argc, char* argv[]) +{ + Options opts; + int c; + int model_data_size = 700*1024; + + while ((c = getopt(argc, argv, "i:M:b:m:R:k:h")) != -1) + { + switch (c) + { + case 'i': + opts.ini_root = optarg; + break; + case 'M': + opts.master_path = optarg; + break; + case 'b': + opts.mbuf_name = optarg; + break; + case 'm': + opts.mbuf_size_mb = std::atoi(optarg); + break; + case 'k': + model_data_size = std::atoi(optarg); + if (model_data_size < 10 || model_data_size > 3900) + { + throw std::runtime_error("Invalid model_data_size [10-3900]k"); + } + model_data_size *= 1024; + break; + case 'R': + { + int count = std::atoi(optarg); + if (count > 120 || count < 1) + { + throw std::runtime_error("Must specify [1-128] models"); + } + if (!opts.models.empty()) + { + throw std::runtime_error("Models already specified"); + } + if (model_data_size*count >= (opts.mbuf_size_mb*1024*1024)) + { + throw std::runtime_error("Too much data, increase the buffer size or reduce models or data rate"); + } + opts.models.reserve(count); + int dcuid = 5; + for (int i = 0; i < count; ++i) + { + ModelParams params; + params.dcuid = dcuid; + params.model_rate = 2048; + params.data_rate = model_data_size; + std::ostringstream os; + os << "mod" << dcuid; + params.name = os.str(); + opts.models.push_back(params); + ++dcuid; + } + } + break; + case 'h': + default: + opts.show_help = true; + break; + } + } + return opts; +} + + +/** + * @brief helper function to sum models channel count via std::accumulate + * @param current current value + * @param m model ptr + * @return current + m->chan_count + */ +size_t +sum_channels(const size_t current, const ModelPtr& m) +{ + return current + m->chan_count(); +} + +int +main(int argc, char* argv[]) +{ + Options opts = parse_arguments(argc, argv); + if (opts.show_help) + { + usage(argv[0]); + exit(1); + } + std::vector<ModelPtr> models; + IniManager ini_manager(opts.ini_root, opts.master_path); + + models.reserve(opts.models.size()); + for (int i = 0; i < opts.models.size(); ++i) + { + ModelParams& param = opts.models[i]; + models.push_back(ModelPtr(new Model(ini_manager, param.name, param.dcuid, param.model_rate, param.data_rate))); + } + + size_t total_chans = std::accumulate(models.begin(), models.end(), (size_t)0, sum_channels); + std::cout << "Model count: " << models.size() << "\n"; + std::cout << "Channel count: " << total_chans << "\n"; + + std::cout << "Sizeof daq_multi_cycle_data_t: " << sizeof(daq_multi_cycle_data_t) << "\n"; + std::cout << "Sizeof daq_multi_cycle_data_t: " << sizeof(daq_multi_cycle_data_t)/(1024*1024) << "MB\n"; + std::cout << "Sizeof daq_multi_cycle_data_t data: " << DAQ_TRANSIT_DC_DATA_BLOCK_SIZE * DAQ_NUM_DATA_BLOCKS_PER_SECOND << "\n"; + std::cout << "Sizeof daq_multi_cycle_data_t data: " << (DAQ_TRANSIT_DC_DATA_BLOCK_SIZE * DAQ_NUM_DATA_BLOCKS_PER_SECOND)/(1024*1024) << "MB\n"; + + std::vector<daq_dc_data_t> buffer(1); + + volatile char *shmem = 0; + + std::string shmem_sysname = opts.mbuf_name; + + size_t buffer_size_mb = opts.mbuf_size_mb; + size_t buffer_size = buffer_size_mb*1024*1024; + shmem = reinterpret_cast<volatile char*>(findSharedMemorySize(const_cast<char*>(shmem_sysname.c_str()), buffer_size_mb)); + if (shmem == 0) + { + std::cerr << "Unable to open shmem buffer\n"; + exit(1); + } + volatile daq_multi_cycle_header_t* ifo_header = reinterpret_cast<volatile daq_multi_cycle_header_t*>(shmem); + ifo_header->maxCycle = 16; + size_t data_size = buffer_size - sizeof(*ifo_header); + data_size /= 16; + data_size -= (data_size % 8); + ifo_header->cycleDataSize = static_cast<unsigned int>(data_size); + volatile char* ifo_data = shmem + sizeof(*ifo_header); + + GPS::gps_clock clock(0); + + GPS::gps_time time_step = GPS::gps_time(0, 1000000000/16); + GPS::gps_time transmit_time = clock.now(); + ++transmit_time.sec; + transmit_time.nanosec = 0; + + int delay_multiplier = 0; + int cycle = 0; + + while (true) + { + // The simulation writes 1/16s behind real time + // So we wait until the cycle start, then compute + // then write and wait for the next cycle. + GPS::gps_time now = clock.now(); + while (now < transmit_time) + { + usleep(1); + now = clock.now(); + } + usleep(delay_multiplier * 1000); + + generate_models(models, buffer.front(), sizeof(buffer.front().dataBlock), cycle, transmit_time); + + volatile char* dest = ifo_data + (cycle*data_size); + char *start = reinterpret_cast<char*>(&buffer.front()); + std::copy(start, start+sizeof(daq_dc_data_t), dest); + + ifo_header->curCycle = cycle; + + if (cycle == 0) + { + GPS::gps_time end = clock.now(); + GPS::gps_time delta = end - now; + std::cout << "Cycle took " << static_cast<double>(delta.nanosec)/1000000000.0 << "s\n"; + } + + cycle = (cycle + 1) % 16; + transmit_time = transmit_time + time_step; + } + return 0; +} \ No newline at end of file diff --git a/src/fe_stream_test/fe_stream_check.cc b/src/fe_stream_test/fe_stream_check.cc index a80f90112..1184b8ee2 100644 --- a/src/fe_stream_test/fe_stream_check.cc +++ b/src/fe_stream_test/fe_stream_check.cc @@ -22,6 +22,11 @@ #include "daq_core.h" +extern "C" { + +#include "../drv/crc.c" +} + /*! * @brief Generic buffer typedef */ @@ -506,6 +511,7 @@ public: std::vector<char> tmp(model.meta_data.rate*8); const char* data = &(slice_header->dataBlock[dcu_data_offset]); + char* data_start = const_cast<char*>(data); for (int i = 0; i < model.channels.size(); ++i) { std::fill(tmp.begin(), tmp.end(), 1); @@ -523,6 +529,15 @@ public: data += gen_size; } + + int dcu_data_size = static_cast<int>(data - data_start); + unsigned int data_crc = crc_len(dcu_data_size, crc_ptr(data_start, dcu_data_size, 0)); + if (data_crc != dcu_header->dataCrc) + { + std::cerr << "CRC mismatch on dcu id " << dcu_header->dcuId << "\n"; + throw std::runtime_error("CRC Mismatch"); + } + for (int i = 0; i < dcu_header->tpCount; ++i) { int expected_len = (model.meta_data.rate * sizeof(float))/16; @@ -623,5 +638,9 @@ main(int argc, char* argv[]) CheckDCUData check_dcu_data(opts, header); std::for_each( models.begin(), models.end(), check_dcu_data); + if (opts.verbose) + { + std::cout << "Tests passed\n"; + } return 0; } \ No newline at end of file diff --git a/src/fe_stream_test/fe_stream_generator.cc b/src/fe_stream_test/fe_stream_generator.cc new file mode 100644 index 000000000..e0a22f12a --- /dev/null +++ b/src/fe_stream_test/fe_stream_generator.cc @@ -0,0 +1,63 @@ +// +// Created by jonathan.hanks on 8/22/19. +// +#include "fe_stream_generator.hh" + +GeneratorPtr +create_generator(const std::string& generator, const SimChannel& ch) +{ + if (ch.data_type() != 2) + throw std::runtime_error("Invalid/unsupported data type for a generator"); + if (generator == "gps_sec") { + return GeneratorPtr(new Generators::GPSSecondGenerator(ch)); + } + throw std::runtime_error("Unknown generator type"); +} + +GeneratorPtr +create_generator(const std::string& channel_name) +{ + std::vector<std::string> parts = split(channel_name, "--"); + if (parts.size() < 4) + throw std::runtime_error("Generator name has too few parts, invalid input"); + int data_type = 0; + { + std::istringstream is (parts[parts.size()-2]); + is >> data_type; + } + int rate = 0; + { + std::istringstream is (parts[parts.size()-1]); + is >> rate; + } + if (!(data_type == 2 || data_type == 4) || rate < 16) + throw std::runtime_error("Invalid data type or rate found"); + std::string& base = parts[0]; + std::string& name = parts[1]; + int arg_count = parts.size()-4; // ignore base channel name, data type, rate + if (name == "gpssoff1p" && arg_count == 1) + { + std::istringstream is(parts[2]); + int offset = 0; + is >> offset; + if (data_type == 2) + return GeneratorPtr(new Generators::GPSSecondWithOffset<int>(SimChannel(base, data_type, rate, 0), offset)); + else + return GeneratorPtr(new Generators::GPSSecondWithOffset<float>(SimChannel(base, data_type, rate, 0), offset)); + + } + else if (name == "gpssmd100koff1p" && arg_count == 1) + { + std::istringstream is(parts[2]); + int offset = 0; + is >> offset; + if (data_type == 2) + return GeneratorPtr(new Generators::GPSMod100kSecWithOffset<int>(SimChannel(base, data_type, rate, 0), offset)); + else + return GeneratorPtr(new Generators::GPSMod100kSecWithOffset<float>(SimChannel(base, data_type, rate, 0), offset)); + } + else + { + throw std::runtime_error("Unknown generator type"); + } +} diff --git a/src/fe_stream_test/fe_stream_generator.hh b/src/fe_stream_test/fe_stream_generator.hh index b58ee22c2..1c8bf4453 100644 --- a/src/fe_stream_test/fe_stream_generator.hh +++ b/src/fe_stream_test/fe_stream_generator.hh @@ -232,61 +232,10 @@ namespace Generators { }; } -GeneratorPtr create_generator(const std::string& generator, const SimChannel& ch) -{ - if (ch.data_type() != 2) - throw std::runtime_error("Invalid/unsupported data type for a generator"); - if (generator == "gps_sec") { - return GeneratorPtr(new Generators::GPSSecondGenerator(ch)); - } - throw std::runtime_error("Unknown generator type"); -} - -GeneratorPtr create_generator(const std::string& channel_name) -{ - std::vector<std::string> parts = split(channel_name, "--"); - if (parts.size() < 4) - throw std::runtime_error("Generator name has too few parts, invalid input"); - int data_type = 0; - { - std::istringstream is (parts[parts.size()-2]); - is >> data_type; - } - int rate = 0; - { - std::istringstream is (parts[parts.size()-1]); - is >> rate; - } - if (!(data_type == 2 || data_type == 4) || rate < 16) - throw std::runtime_error("Invalid data type or rate found"); - std::string& base = parts[0]; - std::string& name = parts[1]; - int arg_count = parts.size()-4; // ignore base channel name, data type, rate - if (name == "gpssoff1p" && arg_count == 1) - { - std::istringstream is(parts[2]); - int offset = 0; - is >> offset; - if (data_type == 2) - return GeneratorPtr(new Generators::GPSSecondWithOffset<int>(SimChannel(base, data_type, rate, 0), offset)); - else - return GeneratorPtr(new Generators::GPSSecondWithOffset<float>(SimChannel(base, data_type, rate, 0), offset)); +GeneratorPtr +create_generator(const std::string& generator, const SimChannel& ch); - } - else if (name == "gpssmd100koff1p" && arg_count == 1) - { - std::istringstream is(parts[2]); - int offset = 0; - is >> offset; - if (data_type == 2) - return GeneratorPtr(new Generators::GPSMod100kSecWithOffset<int>(SimChannel(base, data_type, rate, 0), offset)); - else - return GeneratorPtr(new Generators::GPSMod100kSecWithOffset<float>(SimChannel(base, data_type, rate, 0), offset)); - } - else - { - throw std::runtime_error("Unknown generator type"); - } -} +GeneratorPtr +create_generator(const std::string& channel_name); #endif //DAQD_FE_STREAM_GENERATOR_HH diff --git a/src/fe_stream_test/fe_stream_test.cc b/src/fe_stream_test/fe_stream_test.cc index 8848f2c39..60f9d618b 100644 --- a/src/fe_stream_test/fe_stream_test.cc +++ b/src/fe_stream_test/fe_stream_test.cc @@ -3,7 +3,6 @@ // #include <algorithm> -#include <fstream> #include <iostream> #include <sstream> #include <string> @@ -16,6 +15,7 @@ #include "../include/daq_core.h" #include "fe_stream_generator.hh" +#include "fe_generator_support.hh" #include "gps.hh" @@ -25,99 +25,8 @@ extern "C" { #include "../drv/rfm.c" -#include "../drv/crc.c" - -} - - -class ChNumDb -{ -private: - int max_; -public: - ChNumDb(): max_(40000) {} - explicit ChNumDb(int start): max_(start) {} - - int next(int channel_type) { max_++; return max_; } -}; - -std::string cleaned_system_name(const std::string& system_name) -{ - std::vector<char> buf; - for (int i = 0; i < system_name.size(); ++i) - { - if (system_name[i] == ':') continue; - buf.push_back((char)tolower(system_name[i])); - } - buf.push_back('\0'); - return std::string(buf.data()); -} - -std::string generate_ini_filename(const std::string &ini_dir, const std::string &system_name) -{ - std::ostringstream ss; - ss << ini_dir << "/" << system_name << ".ini"; - return ss.str(); -} - -std::string generate_par_filename(const std::string &ini_dir, const std::string &system_name) -{ - std::ostringstream ss; - ss << ini_dir << "/tpchn_" << system_name << ".par"; - return ss.str(); } -void output_ini_files(const std::string& ini_dir, const std::string& system_name, std::vector<GeneratorPtr> channels, std::vector<GeneratorPtr> tp_channels, int dcuid) -{ - using namespace std; - - string clean_name = cleaned_system_name(system_name); - string fname_ini = generate_ini_filename(ini_dir, clean_name); - string fname_par = generate_par_filename(ini_dir, clean_name); - ofstream os_ini(fname_ini.c_str()); - ofstream os_par(fname_par.c_str()); - os_ini << "[default]\ngain=1.0\nacquire=3\ndcuid=" << dcuid << "\nifoid=0\n"; - os_ini << "datatype=2\ndatarate=2048\noffset=0\nslope=1.0\nunits=undef\n\n"; - - vector<GeneratorPtr>::iterator cur = channels.begin(); - for(; cur != channels.end(); ++cur) - { - Generator* gen = (cur->get()); - (*cur)->output_ini_entry(os_ini); - } - - for (cur = tp_channels.begin(); cur != tp_channels.end(); ++cur) - { - Generator* gen = (cur ->get()); - (*cur)->output_par_entry(os_par); - } -} - -unsigned int calculate_ini_crc(const std::string& ini_dir, const std::string& system_name) -{ - std::string fname_ini = generate_ini_filename(ini_dir, cleaned_system_name(system_name)); - std::ifstream is(fname_ini.c_str(), std::ios::binary); - - std::vector<char> buffer(64*1024); - - size_t file_size = 0; - unsigned int file_crc = 0; - while (is.read(&buffer[0], buffer.size())) - { - file_crc = crc_ptr(&buffer[0], buffer.size(), file_crc); - file_size += buffer.size(); - } - if (is.gcount() > 0) - { - file_crc = crc_ptr(&buffer[0], is.gcount(), file_crc); - file_size += is.gcount(); - } - file_crc = crc_len(file_size, file_crc); - return file_crc; - -} - - void usage() { using namespace std; -- GitLab