$treeview $search $mathjax $extrastylesheet
otsdaq
v2_03_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h" 00002 #include "otsdaq-core/Macros/TablePluginMacros.h" 00003 #include "otsdaq-core/TablePluginDataFormats/ARTDAQBoardReaderTable.h" 00004 #include "otsdaq-core/TablePluginDataFormats/XDAQContextTable.h" 00005 00006 #include <stdio.h> 00007 #include <sys/stat.h> //for mkdir 00008 #include <fstream> // std::fstream 00009 #include <iostream> 00010 00011 using namespace ots; 00012 00013 #define ARTDAQ_FCL_PATH std::string(getenv("USER_DATA")) + "/" + "ARTDAQConfigurations/" 00014 #define ARTDAQ_FILE_PREAMBLE "boardReader" 00015 00016 // helpers 00017 #define OUT out << tabStr << commentStr 00018 #define PUSHTAB tabStr += "\t" 00019 #define POPTAB tabStr.resize(tabStr.size() - 1) 00020 #define PUSHCOMMENT commentStr += "# " 00021 #define POPCOMMENT commentStr.resize(commentStr.size() - 2) 00022 00023 //======================================================================================================================== 00024 ARTDAQBoardReaderTable::ARTDAQBoardReaderTable(void) : TableBase("ARTDAQBoardReaderTable") 00025 { 00027 // WARNING: the names used in C++ MUST match the Table INFO // 00029 } 00030 00031 //======================================================================================================================== 00032 ARTDAQBoardReaderTable::~ARTDAQBoardReaderTable(void) {} 00033 00034 //======================================================================================================================== 00035 void ARTDAQBoardReaderTable::init(ConfigurationManager* configManager) 00036 { 00037 // make directory just in case 00038 mkdir((ARTDAQ_FCL_PATH).c_str(), 0755); 00039 00040 __COUT__ << "*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*" << __E__; 00041 __COUT__ << configManager->__SELF_NODE__ << __E__; 00042 00043 const XDAQContextTable* contextConfig = 00044 configManager->__GET_CONFIG__(XDAQContextTable); 00045 00046 std::vector<const XDAQContextTable::XDAQContext*> readerContexts = 00047 contextConfig->getBoardReaderContexts(); 00048 00049 // for each reader context 00050 // do NOT output associated fcl config file 00051 // but do check the link is to a DataManager-esque thing 00052 for(auto& readerContext : readerContexts) 00053 { 00054 try 00055 { 00056 ConfigurationTree readerConfigNode = contextConfig->getSupervisorConfigNode( 00057 configManager, 00058 readerContext->contextUID_, 00059 readerContext->applications_[0].applicationUID_); 00060 00061 __COUT__ << "Path for this reader config is " << readerContext->contextUID_ 00062 << "/" << readerContext->applications_[0].applicationUID_ << "/" 00063 << readerConfigNode.getValueAsString() << __E__; 00064 00065 __COUT__ << "Checking that this reader supervisor node is DataManager-like." 00066 << __E__; 00067 00068 readerConfigNode.getNode("LinkToDataBufferTable").getChildren(); 00069 } 00070 catch(const std::runtime_error& e) 00071 { 00072 __SS__ << "artdaq Board Readers must be instantiated as a Consumer within a " 00073 "DataManager table. " 00074 << "Error found while checking for LinkToDataBufferTable: " << e.what() 00075 << __E__; 00076 __COUT_ERR__ << ss.str(); 00077 __COUT__ << "Path for this reader config is " << readerContext->contextUID_ 00078 << "/" << readerContext->applications_[0].applicationUID_ << "/X" 00079 << __E__; 00080 __COUT_ERR__ << "This board reader will likely not get instantiated " 00081 "properly! Proceeding anyway with fcl generation." 00082 << __E__; 00083 00084 // proceed anyway, because it was really annoying to not be able to activate 00085 // the table group when the context is being developed also. 00086 //__SS_THROW__; 00087 } 00088 00089 // artdaq Reader is not at Supervisor level like other apps 00090 // it is at Consumer level! 00091 // outputFHICL(readerConfigNode, 00092 // contextConfig); 00093 } 00094 00095 // handle fcl file generation, wherever the level of this table 00096 00097 auto childrenMap = configManager->__SELF_NODE__.getChildren(); 00098 std::string appUID, buffUID, consumerUID; 00099 for(auto& child : childrenMap) 00100 { 00101 const XDAQContextTable::XDAQContext* thisContext = nullptr; 00102 for(auto& readerContext : readerContexts) 00103 { 00104 ConfigurationTree readerConfigNode = contextConfig->getSupervisorConfigNode( 00105 configManager, 00106 readerContext->contextUID_, 00107 readerContext->applications_[0].applicationUID_); 00108 auto dataManagerConfMap = 00109 readerConfigNode.getNode("LinkToDataBufferTable").getChildren(); 00110 for(auto dmc : dataManagerConfMap) 00111 { 00112 auto dataBufferConfMap = 00113 dmc.second.getNode("LinkToDataProcessorTable").getChildren(); 00114 for(auto dbc : dataBufferConfMap) 00115 { 00116 auto processorConfUID = 00117 dbc.second.getNode("LinkToProcessorUID").getUIDAsString(); 00118 if(processorConfUID == child.second.getValue()) 00119 { 00120 __COUT__ << "Found match for context UID: " 00121 << readerContext->contextUID_ << __E__; 00122 thisContext = readerContext; 00123 } 00124 } 00125 } 00126 } 00127 00128 if(thisContext == nullptr) 00129 { 00130 __COUT_ERR__ << "Could not find matching context for this table!" << __E__; 00131 } 00132 else 00133 { 00134 if(child.second.getNode(TableViewColumnInfo::COL_NAME_STATUS) 00135 .getValue<bool>()) 00136 { 00137 outputFHICL(configManager, 00138 child.second, 00139 contextConfig->getARTDAQAppRank(thisContext->contextUID_), 00140 contextConfig->getContextAddress(thisContext->contextUID_), 00141 contextConfig->getARTDAQDataPort(configManager, 00142 thisContext->contextUID_), 00143 contextConfig); 00144 } 00145 } 00146 } 00147 } 00148 00150 // void ARTDAQBoardReaderTable::getBoardReaderParents(const ConfigurationTree 00151 // &readerNode, const ConfigurationTree &contextNode, std::string &applicationUID, 00152 // std::string &bufferUID, std::string &consumerUID) 00153 //{ 00154 // //search through all board reader contexts 00155 // contextNode.getNode() 00156 //} 00157 00158 //======================================================================================================================== 00159 std::string ARTDAQBoardReaderTable::getFHICLFilename( 00160 const ConfigurationTree& boardReaderNode) 00161 { 00162 __COUT__ << "ARTDAQ BoardReader UID: " << boardReaderNode.getValue() << __E__; 00163 std::string filename = ARTDAQ_FCL_PATH + ARTDAQ_FILE_PREAMBLE + "-"; 00164 std::string uid = boardReaderNode.getValue(); 00165 for(unsigned int i = 0; i < uid.size(); ++i) 00166 if((uid[i] >= 'a' && uid[i] <= 'z') || (uid[i] >= 'A' && uid[i] <= 'Z') || 00167 (uid[i] >= '0' && uid[i] <= '9')) // only allow alpha numeric in file name 00168 filename += uid[i]; 00169 00170 filename += ".fcl"; 00171 00172 __COUT__ << "fcl: " << filename << __E__; 00173 00174 return filename; 00175 } 00176 00177 //======================================================================================================================== 00178 void ARTDAQBoardReaderTable::outputFHICL(ConfigurationManager* configManager, 00179 const ConfigurationTree& boardReaderNode, 00180 unsigned int selfRank, 00181 std::string selfHost, 00182 unsigned int selfPort, 00183 const XDAQContextTable* contextConfig) 00184 { 00185 /* 00186 the file will look something like this: 00187 00188 daq: { 00189 fragment_receiver: { 00190 mpi_sync_interval: 50 00191 00192 # CommandableFragmentGenerator Table: 00193 fragment_ids: [] 00194 fragment_id: -99 # Please define only one of these 00195 00196 sleep_on_stop_us: 0 00197 00198 requests_enabled: false # Whether to set up the socket for listening for 00199 trigger messages request_mode: "Ignored" # Possible values are: Ignored, Single, 00200 Buffer, Window 00201 00202 data_buffer_depth_fragments: 1000 00203 data_buffer_depth_mb: 1000 00204 00205 request_port: 3001 00206 request_address: "227.128.12.26" # Multicast request address 00207 00208 request_window_offset: 0 # Request message contains tzero. Window will be from 00209 tzero - offset to tzero + width request_window_width: 0 stale_request_timeout: 00210 "0xFFFFFFFF" # How long to wait before discarding request messages that are outside 00211 the available data request_windows_are_unique: true # If request windows are 00212 unique, avoids a copy operation, but the same data point cannot be used for two 00213 requests. If this is not anticipated, leave set to "true" 00214 00215 separate_data_thread: false # MUST be true for triggers to be applied! If 00216 triggering is not desired, but a separate readout thread is, set this to true, 00217 triggers_enabled to false and trigger_mode to ignored. separate_monitoring_thread: 00218 false # Whether a thread should be started which periodically calls checkHWStatus_, 00219 a user-defined function which should be used to check hardware status registers and 00220 report to MetricMan. poll_hardware_status: false # Whether checkHWStatus_ will be 00221 called, either through the thread or at the start of getNext 00222 hardware_poll_interval_us: 1000000 # If hardware monitoring thread is enabled, 00223 how often should it call checkHWStatus_ 00224 00225 00226 # Generated Parameters: 00227 generator: ToySimulator 00228 fragment_type: TOY1 00229 fragment_id: 0 00230 board_id: 0 00231 starting_fragment_id: 0 00232 random_seed: 5780 00233 sleep_on_stop_us: 500000 00234 00235 # Generator-Specific Table: 00236 00237 nADCcounts: 40 00238 00239 throttle_usecs: 100000 00240 00241 distribution_type: 1 00242 00243 timestamp_scale_factor: 1 00244 00245 00246 destinations: { 00247 d2: { transferPluginType: MPI 00248 destination_rank: 2 00249 max_fragment_size_bytes: 2097152 00250 host_map: [ 00251 { 00252 host: "mu2edaq01.fnal.gov" 00253 rank: 0 00254 }, 00255 { 00256 host: "mu2edaq01.fnal.gov" 00257 rank: 1 00258 }] 00259 } 00260 d3: { transferPluginType: MPI 00261 destination_rank: 3 00262 max_fragment_size_bytes: 2097152 00263 host_map: [ 00264 { 00265 host: "mu2edaq01.fnal.gov" 00266 rank: 0 00267 }, 00268 { 00269 host: "mu2edaq01.fnal.gov" 00270 rank: 1 00271 }] 00272 } 00273 00274 } 00275 } 00276 00277 metrics: { 00278 brFile: { 00279 metricPluginType: "file" 00280 level: 3 00281 fileName: "/tmp/boardreader/br_%UID%_metrics.log" 00282 uniquify: true 00283 } 00284 # ganglia: { 00285 # metricPluginType: "ganglia" 00286 # level: %{ganglia_level} 00287 # reporting_interval: 15.0 00288 # 00289 # configFile: "/etc/ganglia/gmond.conf" 00290 # group: "ARTDAQ" 00291 # } 00292 # msgfac: { 00293 # level: %{mf_level} 00294 # metricPluginType: "msgFacility" 00295 # output_message_application_name: "ARTDAQ Metric" 00296 # output_message_severity: 0 00297 # } 00298 # graphite: { 00299 # level: %{graphite_level} 00300 # metricPluginType: "graphite" 00301 # host: "localhost" 00302 # port: 20030 00303 # namespace: "artdaq." 00304 # } 00305 } 00306 } 00307 00308 */ 00309 00310 std::string filename = getFHICLFilename(boardReaderNode); 00311 00313 // generate xdaq run parameter file 00314 std::fstream out; 00315 00316 std::string tabStr = ""; 00317 std::string commentStr = ""; 00318 00319 out.open(filename, std::fstream::out | std::fstream::trunc); 00320 if(out.fail()) 00321 { 00322 __SS__ << "Failed to open ARTDAQ Builder fcl file: " << filename << __E__; 00323 __SS_THROW__; 00324 } 00325 00326 //-------------------------------------- 00327 // header 00328 OUT << "###########################################################" << __E__; 00329 OUT << "#" << __E__; 00330 OUT << "# artdaq reader fcl configuration file produced by otsdaq." << __E__; 00331 OUT << "# Creation timestamp: " << StringMacros::getTimestampString() << __E__; 00332 OUT << "# Original filename: " << filename << __E__; 00333 OUT << "# otsdaq-ARTDAQ Reader UID: " << boardReaderNode.getValue() << __E__; 00334 OUT << "#" << __E__; 00335 OUT << "###########################################################" << __E__; 00336 OUT << "\n\n"; 00337 00338 // no primary link to table tree for reader node! 00339 try 00340 { 00341 if(boardReaderNode.isDisconnected()) 00342 { 00343 // create empty fcl 00344 OUT << "{}\n\n"; 00345 out.close(); 00346 return; 00347 } 00348 } 00349 catch(const std::runtime_error) 00350 { 00351 __COUT__ << "Ignoring error, assume this a valid UID node." << __E__; 00352 // error is expected here for UIDs.. so just ignore 00353 // this check is valuable if source node is a unique-Link node, rather than UID 00354 } 00355 00356 //-------------------------------------- 00357 // handle daq 00358 OUT << "daq: {\n"; 00359 00360 // fragment_receiver 00361 PUSHTAB; 00362 OUT << "fragment_receiver: {\n"; 00363 00364 PUSHTAB; 00365 { 00366 // plugin type and fragment data-type 00367 OUT << "generator" 00368 << ": " << boardReaderNode.getNode("daqGeneratorPluginType").getValue() 00369 << ("\t #daq generator plug-in type") << "\n"; 00370 OUT << "fragment_type" 00371 << ": " << boardReaderNode.getNode("daqGeneratorFragmentType").getValue() 00372 << ("\t #generator data fragment type") << "\n\n"; 00373 00374 // shared and unique parameters 00375 auto parametersLink = boardReaderNode.getNode("daqParametersLink"); 00376 if(!parametersLink.isDisconnected()) 00377 { 00378 auto parameters = parametersLink.getChildren(); 00379 for(auto& parameter : parameters) 00380 { 00381 if(!parameter.second.getNode(TableViewColumnInfo::COL_NAME_STATUS) 00382 .getValue<bool>()) 00383 PUSHCOMMENT; 00384 00385 // __COUT__ << 00386 // parameter.second.getNode("daqParameterKey").getValue() << 00387 // ": " << 00388 // parameter.second.getNode("daqParameterValue").getValue() 00389 // << 00390 // "\n"; 00391 00392 auto comment = parameter.second.getNode("CommentDescription"); 00393 OUT << parameter.second.getNode("daqParameterKey").getValue() << ": " 00394 << parameter.second.getNode("daqParameterValue").getValue() 00395 << (comment.isDefaultValue() ? "" : ("\t # " + comment.getValue())) 00396 << "\n"; 00397 00398 if(!parameter.second.getNode(TableViewColumnInfo::COL_NAME_STATUS) 00399 .getValue<bool>()) 00400 POPCOMMENT; 00401 } 00402 } 00403 OUT << "\n"; // end daq board reader parameters 00404 } 00405 // { //unique parameters 00406 // auto parametersLink = boardReaderNode.getNode("daqUniqueParametersLink"); 00407 // if(!parametersLink.isDisconnected()) 00408 // { 00409 // 00410 // auto parameters = parametersLink.getChildren(); 00411 // for(auto ¶meter:parameters) 00412 // { 00413 // if(!parameter.second.getNode(TableViewColumnInfo::COL_NAME_STATUS).getValue<bool>()) 00414 // PUSHCOMMENT; 00415 // 00416 // auto comment = parameter.second.getNode("CommentDescription"); 00417 // OUT << parameter.second.getNode("daqParameterKey").getValue() << 00418 // ": " << 00419 // parameter.second.getNode("daqParameterValue").getValue() 00420 // << 00421 // (comment.isDefaultValue()?"":("\t # " + comment.getValue())) 00422 //<< 00423 // "\n"; 00424 // 00425 // if(!parameter.second.getNode(TableViewColumnInfo::COL_NAME_STATUS).getValue<bool>()) 00426 // POPCOMMENT; 00427 // } 00428 // } 00429 // OUT << "\n"; //end shared daq board reader parameters 00430 // } 00431 00432 OUT << "destinations: {\n"; 00433 00434 PUSHTAB; 00435 auto destinationsGroup = boardReaderNode.getNode("daqDestinationsLink"); 00436 if(!destinationsGroup.isDisconnected()) 00437 { 00438 try 00439 { 00440 auto destinations = destinationsGroup.getChildren(); 00441 for(auto& destination : destinations) 00442 { 00443 auto destinationContextUID = 00444 destination.second.getNode("destinationARTDAQContextLink") 00445 .getValueAsString(); 00446 00447 unsigned int destinationRank = 00448 contextConfig->getARTDAQAppRank(destinationContextUID); 00449 std::string host = 00450 contextConfig->getContextAddress(destinationContextUID); 00451 unsigned int port = contextConfig->getARTDAQDataPort( 00452 configManager, destinationContextUID); 00453 00454 // open destination object 00455 OUT << destination.second.getNode("destinationKey").getValue() << ": {\n"; 00456 PUSHTAB; 00457 00458 OUT << "transferPluginType: " 00459 << destination.second.getNode("transferPluginType").getValue() 00460 << __E__; 00461 00462 OUT << "destination_rank: " << destinationRank << __E__; 00463 00464 try 00465 { 00466 OUT << "max_fragment_size_bytes: " 00467 << destination.second 00468 .getNode("ARTDAQGlobalTableLink/maxFragmentSizeBytes") 00469 .getValue<unsigned long long>() 00470 << __E__; 00471 } 00472 catch(...) 00473 { 00474 __SS__ << "The field ARTDAQGlobalTableLink/maxFragmentSizeBytes " 00475 "could not be accessed. Make sure the link is valid." 00476 << __E__; 00477 __SS_THROW__; 00478 } 00479 00480 OUT << "host_map: [\n"; 00481 PUSHTAB; 00482 OUT << "{\n"; 00483 PUSHTAB; 00484 OUT << "rank: " << destinationRank << __E__; 00485 OUT << "host: \"" << host << "\"" << __E__; 00486 OUT << "portOffset: " << std::to_string(port) << __E__; 00487 POPTAB; 00488 OUT << "},\n"; 00489 OUT << "{\n"; 00490 PUSHTAB; 00491 OUT << "rank: " << selfRank << __E__; 00492 OUT << "host: \"" << selfHost << "\"" << __E__; 00493 OUT << "portOffset: " << std::to_string(selfPort) << __E__; 00494 POPTAB; 00495 OUT << "}" << __E__; 00496 POPTAB; 00497 OUT << "]" << __E__; // close host_map 00498 00499 POPTAB; 00500 OUT << "}" << __E__; // close destination object 00501 } 00502 } 00503 catch(const std::runtime_error& e) 00504 { 00505 __SS__ << "Are the DAQ destinations valid? Error occurred looking for Board " 00506 "Reader DAQ sources for UID '" 00507 << boardReaderNode.getValue() << "': " << e.what() << __E__; 00508 __SS_THROW__; 00509 } 00510 } 00511 POPTAB; 00512 OUT << "}\n\n"; // end destinations 00513 00514 POPTAB; 00515 OUT << "}\n\n"; // end fragment_receiver 00516 00517 OUT << "metrics: {\n"; 00518 00519 PUSHTAB; 00520 auto metricsGroup = boardReaderNode.getNode("daqMetricsLink"); 00521 if(!metricsGroup.isDisconnected()) 00522 { 00523 auto metrics = metricsGroup.getChildren(); 00524 00525 for(auto& metric : metrics) 00526 { 00527 if(!metric.second.getNode(TableViewColumnInfo::COL_NAME_STATUS) 00528 .getValue<bool>()) 00529 PUSHCOMMENT; 00530 00531 OUT << metric.second.getNode("metricKey").getValue() << ": {\n"; 00532 PUSHTAB; 00533 00534 OUT << "metricPluginType: " 00535 << metric.second.getNode("metricPluginType").getValue() << "\n"; 00536 OUT << "level: " << metric.second.getNode("metricLevel").getValue() << "\n"; 00537 00538 auto metricParametersGroup = metric.second.getNode("metricParametersLink"); 00539 if(!metricParametersGroup.isDisconnected()) 00540 { 00541 auto metricParameters = metricParametersGroup.getChildren(); 00542 for(auto& metricParameter : metricParameters) 00543 { 00544 if(!metricParameter.second 00545 .getNode(TableViewColumnInfo::COL_NAME_STATUS) 00546 .getValue<bool>()) 00547 PUSHCOMMENT; 00548 00549 OUT << metricParameter.second.getNode("metricParameterKey").getValue() 00550 << ": " 00551 << metricParameter.second.getNode("metricParameterValue") 00552 .getValue() 00553 << "\n"; 00554 00555 if(!metricParameter.second 00556 .getNode(TableViewColumnInfo::COL_NAME_STATUS) 00557 .getValue<bool>()) 00558 POPCOMMENT; 00559 } 00560 } 00561 POPTAB; 00562 OUT << "}\n\n"; // end metric 00563 00564 if(!metric.second.getNode(TableViewColumnInfo::COL_NAME_STATUS) 00565 .getValue<bool>()) 00566 POPCOMMENT; 00567 } 00568 } 00569 POPTAB; 00570 OUT << "}\n\n"; // end metrics 00571 00572 POPTAB; 00573 OUT << "}\n\n"; // end daq 00574 00575 out.close(); 00576 } 00577 00578 DEFINE_OTS_TABLE(ARTDAQBoardReaderTable)