$treeview $search $mathjax $extrastylesheet
otsdaq
v2_03_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #include "otsdaq-core/FECore/FEVInterface.h" 00002 #include "otsdaq-core/CoreSupervisors/CoreSupervisorBase.h" 00003 #include "otsdaq-core/FECore/FEVInterfacesManager.h" 00004 #include "otsdaq-core/NetworkUtilities/UDPDataStreamerBase.h" 00005 00006 #include <iostream> 00007 #include <sstream> 00008 #include <thread> //for std::thread 00009 00010 using namespace ots; 00011 00012 //======================================================================================================================== 00013 FEVInterface::FEVInterface(const std::string& interfaceUID, 00014 const ConfigurationTree& theXDAQContextConfigTree, 00015 const std::string& configurationPath) 00016 : WorkLoop(interfaceUID) 00017 , Configurable(theXDAQContextConfigTree, configurationPath) 00018 , interfaceUID_(interfaceUID) 00019 //, interfaceType_ 00020 //(theXDAQContextConfigTree_.getBackNode(theConfigurationPath_).getNode("FEInterfacePluginName").getValue<std::string>()) 00021 //, daqHardwareType_ ("NOT SET") 00022 //, firmwareType_ ("NOT SET") 00023 , slowControlsWorkLoop_(interfaceUID + "-SlowControls", this) 00024 { 00025 // NOTE!! be careful to not decorate with __FE_COUT__ because in the constructor the 00026 // base class versions of function (e.g. getInterfaceType) are called because the 00027 // derived class has not been instantiate yet! 00028 __COUT__ << "'" << interfaceUID << "' Constructed." << __E__; 00029 } 00030 00031 //======================================================================================================================== 00032 FEVInterface::~FEVInterface(void) 00033 { 00034 // NOTE:: be careful not to call __FE_COUT__ decoration because it uses the tree and 00035 // it may already be destructed partially 00036 __COUT__ << FEVInterface::interfaceUID_ << " Destructed." << __E__; 00037 } 00038 00039 //======================================================================================================================== 00040 void FEVInterface::configureSlowControls(void) 00041 { 00042 // START IT HERE 00043 if(metricMan && !metricMan->Running() && metricMan->Initialized()) 00044 metricMan->do_start(); 00045 00046 ConfigurationTree slowControlsGroupLink = 00047 theXDAQContextConfigTree_.getBackNode(theConfigurationPath_) 00048 .getNode("LinkToSlowControlsChannelTable"); 00049 00050 if(slowControlsGroupLink.isDisconnected()) 00051 { 00052 __FE_COUT__ 00053 << "slowControlsGroupLink is disconnected, so done configuring slow controls." 00054 << __E__; 00055 return; 00056 } 00057 __FE_COUT__ << "slowControlsGroupLink is valid! Configuring slow controls..." 00058 << __E__; 00059 00060 mapOfSlowControlsChannels_.clear(); 00061 std::vector<std::pair<std::string, ConfigurationTree> > groupLinkChildren = 00062 slowControlsGroupLink.getChildren(); 00063 for(auto& groupLinkChild : groupLinkChildren) 00064 { 00065 // skip channels that are off 00066 if(!(groupLinkChild.second.getNode(TableViewColumnInfo::COL_NAME_STATUS) 00067 .getValue<bool>())) 00068 continue; 00069 00070 __FE_COUT__ << "Channel:" << getInterfaceUID() << "/" << groupLinkChild.first 00071 << "\t Type:" << groupLinkChild.second.getNode("ChannelDataType") 00072 << __E__; 00073 00074 mapOfSlowControlsChannels_.insert(std::pair<std::string, FESlowControlsChannel>( 00075 groupLinkChild.first, 00076 FESlowControlsChannel( 00077 getInterfaceUID(), 00078 groupLinkChild.first, 00079 groupLinkChild.second.getNode("ChannelDataType").getValue<std::string>(), 00080 universalDataSize_, 00081 universalAddressSize_, 00082 groupLinkChild.second.getNode("UniversalInterfaceAddress") 00083 .getValue<std::string>(), 00084 groupLinkChild.second.getNode("UniversalDataBitOffset") 00085 .getValue<unsigned int>(), 00086 groupLinkChild.second.getNode("ReadAccess").getValue<bool>(), 00087 groupLinkChild.second.getNode("WriteAccess").getValue<bool>(), 00088 groupLinkChild.second.getNode("MonitoringEnabled").getValue<bool>(), 00089 groupLinkChild.second.getNode("RecordChangesOnly").getValue<bool>(), 00090 groupLinkChild.second.getNode("DelayBetweenSamplesInSeconds") 00091 .getValue<time_t>(), 00092 groupLinkChild.second.getNode("LocalSavingEnabled").getValue<bool>(), 00093 groupLinkChild.second.getNode("LocalFilePath").getValue<std::string>(), 00094 groupLinkChild.second.getNode("RadixFileName").getValue<std::string>(), 00095 groupLinkChild.second.getNode("SaveBinaryFile").getValue<bool>(), 00096 groupLinkChild.second.getNode("AlarmsEnabled").getValue<bool>(), 00097 groupLinkChild.second.getNode("LatchAlarms").getValue<bool>(), 00098 groupLinkChild.second.getNode("LowLowThreshold").getValue<std::string>(), 00099 groupLinkChild.second.getNode("LowThreshold").getValue<std::string>(), 00100 groupLinkChild.second.getNode("HighThreshold").getValue<std::string>(), 00101 groupLinkChild.second.getNode("HighHighThreshold") 00102 .getValue<std::string>()))); 00103 } 00104 } // end configureSlowControls() 00105 00106 //======================================================================================================================== 00107 bool FEVInterface::slowControlsRunning(void) 00108 try 00109 { 00110 __FE_COUT__ << "slowControlsRunning" << __E__; 00111 00112 if(mapOfSlowControlsChannels_.size() == 0) 00113 { 00114 __FE_COUT__ 00115 << "No slow controls channels to monitor, exiting slow controls workloop." 00116 << __E__; 00117 return false; 00118 } 00119 std::string readVal; 00120 readVal.resize(universalDataSize_); // size to data in advance 00121 00122 FESlowControlsChannel* channel; 00123 00124 const unsigned int txBufferSz = 1500; 00125 const unsigned int txBufferFullThreshold = 750; 00126 std::string txBuffer; 00127 txBuffer.reserve(txBufferSz); 00128 00129 ConfigurationTree FEInterfaceNode = 00130 theXDAQContextConfigTree_.getBackNode(theConfigurationPath_); 00131 00132 00133 //attempt to make Slow Controls transfer socket 00134 std::unique_ptr<UDPDataStreamerBase> slowContrlolsTxSocket; 00135 std::string slowControlsSupervisorIPAddress = "", slowControlsSelfIPAddress = ""; 00136 int slowControlsSupervisorPort = 0, slowControlsSelfPort = 0; 00137 try 00138 { 00139 ConfigurationTree slowControlsInterfaceLink = 00140 FEInterfaceNode.getNode("LinkToSlowControlsSupervisorTable"); 00141 00142 00143 if(slowControlsInterfaceLink.isDisconnected()) 00144 { 00145 __FE_SS__ << "slowControlsInterfaceLink is disconnected, so no socket made." 00146 << __E__; 00147 __FE_SS_THROW__; 00148 } 00149 00150 slowControlsSelfIPAddress = FEInterfaceNode.getNode("SlowControlsTxSocketIPAddress") 00151 .getValue<std::string>(); 00152 slowControlsSelfPort = FEInterfaceNode.getNode("SlowControlsTxSocketPort").getValue<int>(); 00153 slowControlsSupervisorIPAddress = slowControlsInterfaceLink.getNode( 00154 "IPAddress").getValue<std::string>(); 00155 slowControlsSupervisorPort = slowControlsInterfaceLink.getNode("Port").getValue<int>(); 00156 } 00157 catch(...) 00158 { 00159 __FE_COUT__ << "Link to slow controls supervisor is missing, so no socket made." 00160 << __E__; 00161 } 00162 00163 if(slowControlsSupervisorPort && slowControlsSelfPort && 00164 slowControlsSupervisorIPAddress != "" && 00165 slowControlsSelfIPAddress != "") 00166 { 00167 00168 __FE_COUT__ << "slowControlsInterfaceLink is valid! Create tx socket..." << __E__; 00169 slowContrlolsTxSocket.reset(new UDPDataStreamerBase( 00170 slowControlsSelfIPAddress, 00171 slowControlsSelfPort, 00172 slowControlsSupervisorIPAddress, 00173 slowControlsSupervisorPort)); 00174 } 00175 else 00176 { 00177 __FE_COUT__ << "Invalid Slow Controls socket parameters, so no socket made." << __E__; 00178 } 00179 00180 00181 // check if aggregate saving 00182 00183 FILE* fp = 0; 00184 bool aggregateFileIsBinaryFormat = false; 00185 if(FEInterfaceNode.getNode("SlowControlsLocalAggregateSavingEnabled") 00186 .getValue<bool>()) 00187 { 00188 aggregateFileIsBinaryFormat = 00189 FEInterfaceNode.getNode("SlowControlsSaveBinaryFile").getValue<bool>(); 00190 00191 __FE_COUT_INFO__ << "Slow Controls Aggregate Saving turned On BinaryFormat=" 00192 << aggregateFileIsBinaryFormat << __E__; 00193 00194 std::string saveFullFileName = 00195 FEInterfaceNode.getNode("SlowControlsLocalFilePath").getValue<std::string>() + 00196 "/" + 00197 FEInterfaceNode.getNode("SlowControlsRadixFileName").getValue<std::string>() + 00198 "-" + FESlowControlsChannel::underscoreString(getInterfaceUID()) + "-" + 00199 std::to_string(time(0)) + (aggregateFileIsBinaryFormat ? ".dat" : ".txt"); 00200 00201 fp = fopen(saveFullFileName.c_str(), aggregateFileIsBinaryFormat ? "ab" : "a"); 00202 if(!fp) 00203 { 00204 __FE_COUT_ERR__ << "Failed to open slow controls channel file: " 00205 << saveFullFileName << __E__; 00206 // continue on, just nothing will be saved 00207 } 00208 else 00209 __FE_COUT_INFO__ << "Slow controls aggregate file opened: " 00210 << saveFullFileName << __E__; 00211 } 00212 else 00213 __FE_COUT_INFO__ << "Slow Controls Aggregate Saving turned off." << __E__; 00214 00215 time_t timeCounter = 0; 00216 00217 while(slowControlsWorkLoop_.getContinueWorkLoop()) 00218 { 00219 sleep(1); // seconds 00220 ++timeCounter; 00221 00222 if(txBuffer.size()) 00223 __FE_COUT__ << "txBuffer sz=" << txBuffer.size() << __E__; 00224 00225 txBuffer.resize(0); // clear buffer a la txBuffer = ""; 00226 00227 //__FE_COUT__ << "timeCounter=" << timeCounter << __E__; 00228 //__FE_COUT__ << "txBuffer sz=" << txBuffer.size() << __E__; 00229 00230 for(auto& slowControlsChannelPair : mapOfSlowControlsChannels_) 00231 { 00232 channel = &slowControlsChannelPair.second; 00233 00234 // skip if no read access 00235 if(!channel->readAccess_) 00236 continue; 00237 00238 // skip if not a sampling moment in time for channel 00239 if(timeCounter % channel->delayBetweenSamples_) 00240 continue; 00241 00242 __FE_COUT__ << "Channel:" << getInterfaceUID() << "/" 00243 << slowControlsChannelPair.first << __E__; 00244 __FE_COUT__ << "Monitoring..." << __E__; 00245 00246 universalRead(channel->getUniversalAddress(), &readVal[0]); 00247 00248 // { //print 00249 // __FE_SS__ << "0x "; 00250 // for(int i=(int)universalAddressSize_-1;i>=0;--i) 00251 // ss << std::hex << (int)((readVal[i]>>4)&0xF) << 00252 // (int)((readVal[i])&0xF) << " " << std::dec; 00253 // ss << __E__; 00254 // __FE_COUT__ << "Sampled.\n" << ss.str(); 00255 // } 00256 00257 // have sample 00258 channel->handleSample(readVal, txBuffer, fp, aggregateFileIsBinaryFormat); 00259 if(txBuffer.size()) 00260 __FE_COUT__ << "txBuffer sz=" << txBuffer.size() << __E__; 00261 00262 //"Channel:" << getInterfaceUID() << "/" 00263 // << slowControlsChannelPair.first << __E__; 00264 // Value << readVal 00265 00266 // For example, 00267 if(metricMan && universalAddressSize_ <= 8) 00268 { 00269 00270 uint64_t val = 0; // 64 bits! 00271 for(size_t ii = 0; ii < universalAddressSize_; ++ii) 00272 val += (uint8_t)readVal[ii] << (ii * 4); 00273 00274 00275 00276 __FE_COUT__ << "Sending sample to Metric Manager..." << __E__; 00277 metricMan->sendMetric( 00278 getInterfaceUID() + "/" + slowControlsChannelPair.first, 00279 val, 00280 "", 00281 3, 00282 artdaq::MetricMode::LastPoint); 00283 } 00284 00285 // make sure buffer hasn't exploded somehow 00286 if(txBuffer.size() > txBufferSz) 00287 { 00288 __FE_SS__ << "This should never happen hopefully!" << __E__; 00289 __FE_SS_THROW__; 00290 } 00291 00292 // send early if threshold reached 00293 if(slowContrlolsTxSocket && txBuffer.size() > txBufferFullThreshold) 00294 { 00295 __FE_COUT__ << "Sending now! txBufferFullThreshold=" 00296 << txBufferFullThreshold << __E__; 00297 slowContrlolsTxSocket->send(txBuffer); 00298 txBuffer.resize(0); // clear buffer a la txBuffer = ""; 00299 } 00300 } 00301 00302 if(txBuffer.size()) 00303 __FE_COUT__ << "txBuffer sz=" << txBuffer.size() << __E__; 00304 00305 // send anything left 00306 if(slowContrlolsTxSocket && txBuffer.size()) 00307 { 00308 __FE_COUT__ << "Sending now!" << __E__; 00309 slowContrlolsTxSocket->send(txBuffer); 00310 } 00311 00312 if(fp) 00313 fflush(fp); // flush anything in aggregate file for reading ease 00314 } 00315 00316 if(fp) 00317 fclose(fp); 00318 00319 return false; 00320 } // end slowControlsRunning() 00321 catch(const std::runtime_error& e) 00322 { 00323 __FE_COUT__ << "Error caught during slow controls running thread: " << e.what() << __E__; 00324 return false; 00325 } 00326 catch(...) 00327 { 00328 __FE_COUT__ << "Unknown error caught during slow controls running thread." << __E__; 00329 return false; 00330 } // end slowControlsRunning() 00331 00332 //======================================================================================================================== 00333 // SendAsyncErrorToGateway 00334 // Static -- thread 00335 // Send async error or soft error to gateway 00336 // Do this as thread so that workloop can end 00337 void FEVInterface::sendAsyncErrorToGateway(FEVInterface* fe, 00338 const std::string& errorMessage, 00339 bool isSoftError) try 00340 { 00341 if(isSoftError) 00342 __COUT_ERR__ << ":FE:" << fe->getInterfaceType() << ":" << fe->getInterfaceUID() 00343 << ":" << fe->theConfigurationRecordName_ << ":" 00344 << "Sending FE Async SOFT Running Error... \n" 00345 << errorMessage << __E__; 00346 else 00347 __COUT_ERR__ << ":FE:" << fe->getInterfaceType() << ":" << fe->getInterfaceUID() 00348 << ":" << fe->theConfigurationRecordName_ << ":" 00349 << "Sending FE Async Running Error... \n" 00350 << errorMessage << __E__; 00351 00352 XDAQ_CONST_CALL xdaq::ApplicationDescriptor* gatewaySupervisor = 00353 fe->VStateMachine::parentSupervisor_->allSupervisorInfo_.getGatewayInfo() 00354 .getDescriptor(); 00355 00356 SOAPParameters parameters; 00357 parameters.addParameter("ErrorMessage", errorMessage); 00358 00359 xoap::MessageReference replyMessage = 00360 fe->VStateMachine::parentSupervisor_->SOAPMessenger::sendWithSOAPReply( 00361 gatewaySupervisor, isSoftError ? "AsyncSoftError" : "AsyncError", parameters); 00362 00363 std::stringstream replyMessageSStream; 00364 replyMessageSStream << SOAPUtilities::translate(replyMessage); 00365 __COUT__ << ":FE:" << fe->getInterfaceType() << ":" << fe->getInterfaceUID() << ":" 00366 << fe->theConfigurationRecordName_ << ":" 00367 << "Received... " << replyMessageSStream.str() << std::endl; 00368 00369 if(replyMessageSStream.str().find("Fault") != std::string::npos) 00370 { 00371 __COUT_ERR__ << ":FE:" << fe->getInterfaceType() << ":" << fe->getInterfaceUID() 00372 << ":" << fe->theConfigurationRecordName_ << ":" 00373 << "Failure to indicate fault to Gateway..." << __E__; 00374 throw; 00375 } 00376 } 00377 catch(const xdaq::exception::Exception& e) 00378 { 00379 if(isSoftError) 00380 __COUT__ << "SOAP message failure indicating front-end asynchronous running SOFT " 00381 "error back to Gateway: " 00382 << e.what() << __E__; 00383 else 00384 __COUT__ << "SOAP message failure indicating front-end asynchronous running " 00385 "error back to Gateway: " 00386 << e.what() << __E__; 00387 } 00388 catch(...) 00389 { 00390 if(isSoftError) 00391 __COUT__ << "Unknown error encounter indicating front-end asynchronous running " 00392 "SOFT error back to Gateway." 00393 << __E__; 00394 else 00395 __COUT__ << "Unknown error encounter indicating front-end asynchronous running " 00396 "error back to Gateway." 00397 << __E__; 00398 } // end SendAsyncErrorToGateway() 00399 00400 //======================================================================================================================== 00401 // override WorkLoop::workLoopThread 00402 // return false to stop the workloop from calling the thread again 00403 bool FEVInterface::workLoopThread(toolbox::task::WorkLoop* workLoop) 00404 { 00405 try 00406 { 00407 continueWorkLoop_ = 00408 running(); /* in case users return false, without using continueWorkLoop_*/ 00409 } 00410 catch(...) // 00411 { 00412 // catch all, then rethrow with local variables needed 00413 __FE_SS__; 00414 00415 bool isSoftError = false; 00416 00417 try 00418 { 00419 throw; 00420 } 00421 catch(const __OTS_SOFT_EXCEPTION__& e) 00422 { 00423 ss << "SOFT Error was caught while configuring: " << e.what() << std::endl; 00424 isSoftError = true; 00425 } 00426 catch(const std::runtime_error& e) 00427 { 00428 ss << "Caught an error during running at FE Interface '" 00429 << Configurable::theConfigurationRecordName_ << "': " << e.what() << __E__; 00430 } 00431 catch(...) 00432 { 00433 ss << "Caught an unknown error during running." << __E__; 00434 } 00435 00436 // At this point, an asynchronous error has occurred 00437 // during front-end running... 00438 // Send async error to Gateway 00439 00440 __FE_COUT_ERR__ << ss.str(); 00441 00442 std::thread( 00443 [](FEVInterface* fe, const std::string errorMessage, bool isSoftError) { 00444 FEVInterface::sendAsyncErrorToGateway(fe, errorMessage, isSoftError); 00445 }, 00446 // pass the values 00447 this, 00448 ss.str(), 00449 isSoftError) 00450 .detach(); 00451 00452 return false; 00453 } 00454 00455 return continueWorkLoop_; 00456 } // end workLoopThread() 00457 00458 //======================================================================================================================== 00459 // registerFEMacroFunction 00460 // used by user-defined front-end interface implementations of this 00461 // virtual interface class to register their macro functions. 00462 // 00463 // Front-end Macro Functions are then made accessible through the ots Control System 00464 // web interfaces. The menu consisting of all enabled FEs macros is assembled 00465 // by the FE Supervisor (and its FE Interface Manager). 00466 void FEVInterface::registerFEMacroFunction( 00467 const std::string& feMacroName, 00468 frontEndMacroFunction_t feMacroFunction, 00469 const std::vector<std::string>& namesOfInputArgs, 00470 const std::vector<std::string>& namesOfOutputArgs, 00471 uint8_t requiredUserPermissions, 00472 const std::string& allowedCallingFEs) 00473 { 00474 if(mapOfFEMacroFunctions_.find(feMacroName) != mapOfFEMacroFunctions_.end()) 00475 { 00476 __FE_SS__ << "feMacroName '" << feMacroName << "' already exists! Not allowed." 00477 << __E__; 00478 __FE_COUT_ERR__ << "\n" << ss.str(); 00479 __FE_SS_THROW__; 00480 } 00481 00482 mapOfFEMacroFunctions_.insert(std::pair<std::string, frontEndMacroStruct_t>( 00483 feMacroName, 00484 frontEndMacroStruct_t(feMacroName, 00485 feMacroFunction, 00486 namesOfInputArgs, 00487 namesOfOutputArgs, 00488 requiredUserPermissions, 00489 allowedCallingFEs))); 00490 } 00491 00492 //======================================================================================================================== 00493 // getFEMacroConstArgument 00494 // helper function for getting the value of an argument 00495 // 00496 // Note: static function 00497 const std::string& FEVInterface::getFEMacroConstArgument(frontEndMacroConstArgs_t& args, 00498 const std::string& argName) 00499 { 00500 for(const frontEndMacroArg_t& pair : args) 00501 { 00502 if(pair.first == argName) 00503 { 00504 __COUT__ << "argName : " << pair.second << __E__; 00505 return pair.second; 00506 } 00507 } 00508 __SS__ << "Requested input argument not found with name '" << argName << "'" << __E__; 00509 __SS_THROW__; 00510 } 00511 00512 //======================================================================================================================== 00513 // getFEMacroConstArgumentValue 00514 // helper function for getting the copy of the value of an argument 00515 template<> 00516 std::string getFEMacroConstArgumentValue<std::string>( 00517 FEVInterface::frontEndMacroConstArgs_t& args, const std::string& argName) 00518 { 00519 return FEVInterface::getFEMacroConstArgument(args, argName); 00520 } 00521 00522 //======================================================================================================================== 00523 // getFEMacroArgumentValue 00524 // helper function for getting the copy of the value of an argument 00525 template<> 00526 std::string getFEMacroArgumentValue<std::string>(FEVInterface::frontEndMacroArgs_t& args, 00527 const std::string& argName) 00528 { 00529 return FEVInterface::getFEMacroArgument(args, argName); 00530 } 00531 00532 //======================================================================================================================== 00533 // getFEMacroOutputArgument 00534 // helper function for getting the value of an argument 00535 // 00536 // Note: static function 00537 std::string& FEVInterface::getFEMacroArgument(frontEndMacroArgs_t& args, 00538 const std::string& argName) 00539 { 00540 for(std::pair<const std::string /* output arg name */, 00541 std::string /* arg output value */>& pair : args) 00542 { 00543 if(pair.first == argName) 00544 return pair.second; 00545 } 00546 __SS__ << "Requested argument not found with name '" << argName << "'" << __E__; 00547 __SS_THROW__; 00548 } 00549 00550 //======================================================================================================================== 00551 // runSequenceOfCommands 00552 // runs a sequence of write commands from a linked section of the configuration tree 00553 // based on these fields: 00554 // - WriteAddress, WriteValue, StartingBitPosition, BitFieldSize 00555 void FEVInterface::runSequenceOfCommands(const std::string& treeLinkName) 00556 { 00557 std::map<uint64_t, uint64_t> writeHistory; 00558 uint64_t writeAddress, writeValue, bitMask; 00559 uint8_t bitPosition; 00560 00561 std::string writeBuffer; 00562 std::string readBuffer; 00563 char msg[1000]; 00564 bool ignoreError = true; 00565 00566 // ignore errors getting sequence of commands through tree (since it is optional) 00567 try 00568 { 00569 ConfigurationTree configSeqLink = 00570 theXDAQContextConfigTree_.getNode(theConfigurationPath_) 00571 .getNode(treeLinkName); 00572 00573 // but throw errors if problems executing the sequence of commands 00574 try 00575 { 00576 if(configSeqLink.isDisconnected()) 00577 __FE_COUT__ << "Disconnected configure sequence" << __E__; 00578 else 00579 { 00580 __FE_COUT__ << "Handling configure sequence." << __E__; 00581 auto childrenMap = configSeqLink.getChildrenMap(); 00582 for(const auto& child : childrenMap) 00583 { 00584 // WriteAddress and WriteValue fields 00585 00586 writeAddress = 00587 child.second.getNode("WriteAddress").getValue<uint64_t>(); 00588 writeValue = child.second.getNode("WriteValue").getValue<uint64_t>(); 00589 bitPosition = 00590 child.second.getNode("StartingBitPosition").getValue<uint8_t>(); 00591 bitMask = 00592 (1 << child.second.getNode("BitFieldSize").getValue<uint8_t>()) - 00593 1; 00594 00595 writeValue &= bitMask; 00596 writeValue <<= bitPosition; 00597 bitMask = ~(bitMask << bitPosition); 00598 00599 // place into write history 00600 if(writeHistory.find(writeAddress) == writeHistory.end()) 00601 writeHistory[writeAddress] = 0; // init to 0 00602 00603 writeHistory[writeAddress] &= bitMask; // clear incoming bits 00604 writeHistory[writeAddress] |= writeValue; // add incoming bits 00605 00606 sprintf(msg, 00607 "\t Writing %s: \t %ld(0x%lX) \t %ld(0x%lX)", 00608 child.first.c_str(), 00609 writeAddress, 00610 writeAddress, 00611 writeHistory[writeAddress], 00612 writeHistory[writeAddress]); 00613 00614 __FE_COUT__ << msg << __E__; 00615 00616 universalWrite((char*)&writeAddress, 00617 (char*)&(writeHistory[writeAddress])); 00618 } 00619 } 00620 } 00621 catch(...) 00622 { 00623 ignoreError = false; 00624 throw; 00625 } 00626 } 00627 catch(...) 00628 { 00629 if(!ignoreError) 00630 throw; 00631 // else ignoring error 00632 __FE_COUT__ 00633 << "Unable to access sequence of commands through configuration tree. " 00634 << "Assuming no sequence. " << __E__; 00635 } 00636 } 00637 00638 //======================================================================================================================== 00639 // runFrontEndMacro 00640 // Helper function to run this FEInterface's own front-end macro 00641 // and gets the output arguments back. 00642 // 00643 // Very similar to FEVInterfacesManager::runFEMacro() 00644 // 00645 // Note: that argsOut are populated for caller, can just pass empty vector. 00646 void FEVInterface::runSelfFrontEndMacro( 00647 const std::string& feMacroName, 00648 // not equivalent to __ARGS__ 00649 // left non-const value so caller can modify inputArgs as they are being created 00650 const std::vector<FEVInterface::frontEndMacroArg_t>& argsIn, 00651 std::vector<FEVInterface::frontEndMacroArg_t>& argsOut) 00652 { 00653 // have pointer to virtual FEInterface, find Macro structure 00654 auto FEMacroIt = this->getMapOfFEMacroFunctions().find(feMacroName); 00655 if(FEMacroIt == this->getMapOfFEMacroFunctions().end()) 00656 { 00657 __CFG_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '" 00658 << getInterfaceUID() << "' was not found!" << __E__; 00659 __CFG_COUT_ERR__ << "\n" << ss.str(); 00660 __CFG_SS_THROW__; 00661 } 00662 const FEVInterface::frontEndMacroStruct_t& feMacro = FEMacroIt->second; 00663 00664 // check for input arg name match 00665 for(unsigned int i = 0; i < argsIn.size(); ++i) 00666 if(argsIn[i].first != feMacro.namesOfInputArguments_[i]) 00667 { 00668 __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '" 00669 << getInterfaceUID() << "' was attempted with a mismatch in" 00670 << " a name of an input argument. " << argsIn[i].first 00671 << " was given. " << feMacro.namesOfInputArguments_[i] 00672 << " expected." << __E__; 00673 __CFG_COUT_ERR__ << "\n" << ss.str(); 00674 __CFG_SS_THROW__; 00675 } 00676 00677 // check namesOfInputArguments_ 00678 if(feMacro.namesOfInputArguments_.size() != argsIn.size()) 00679 { 00680 __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '" 00681 << getInterfaceUID() << "' was attempted with a mismatch in" 00682 << " number of input arguments. " << argsIn.size() << " were given. " 00683 << feMacro.namesOfInputArguments_.size() << " expected." << __E__; 00684 __CFG_COUT_ERR__ << "\n" << ss.str(); 00685 __CFG_SS_THROW__; 00686 } 00687 00688 __CFG_COUT__ << "# of input args = " << argsIn.size() << __E__; 00689 for(auto& argIn : argsIn) 00690 __CFG_COUT__ << argIn.first << ": " << argIn.second << __E__; 00691 00692 __CFG_COUT__ << "Launching FE Macro '" << feMacro.feMacroName_ << "' ..." << __E__; 00693 00694 argsOut.clear(); 00695 for(unsigned int i = 0; i < feMacro.namesOfOutputArguments_.size(); ++i) 00696 argsOut.push_back(FEVInterface::frontEndMacroArg_t( 00697 feMacro.namesOfOutputArguments_[i], "DEFAULT")); 00698 00699 // run it! 00700 (this->*(feMacro.macroFunction_))(feMacro, argsIn, argsOut); 00701 00702 __CFG_COUT__ << "FE Macro complete!" << __E__; 00703 00704 __CFG_COUT__ << "# of output args = " << argsOut.size() << __E__; 00705 for(const auto& arg : argsOut) 00706 __CFG_COUT__ << arg.first << ": " << arg.second << __E__; 00707 00708 } // end runSelfFrontEndMacro() 00709 00710 //======================================================================================================================== 00711 // runFrontEndMacro 00712 // run a front-end macro in the target interface plug-in and gets the output arguments 00713 // back 00714 void FEVInterface::runFrontEndMacro( 00715 const std::string& targetInterfaceID, 00716 const std::string& feMacroName, 00717 const std::vector<FEVInterface::frontEndMacroArg_t>& inputArgs, 00718 std::vector<FEVInterface::frontEndMacroArg_t>& outputArgs) const 00719 { 00720 __FE_COUTV__(targetInterfaceID); 00721 __FE_COUTV__(VStateMachine::parentSupervisor_); 00722 00723 std::string inputArgsStr = StringMacros::vectorToString( 00724 inputArgs, ";" /*primaryDelimeter*/, "," /*secondaryDelimeter*/); 00725 00726 __FE_COUTV__(inputArgsStr); 00727 00728 xoap::MessageReference message = 00729 SOAPUtilities::makeSOAPMessageReference("FECommunication"); 00730 00731 SOAPParameters parameters; 00732 parameters.addParameter("type", "feMacro"); 00733 parameters.addParameter("requester", FEVInterface::interfaceUID_); 00734 parameters.addParameter("targetInterfaceID", targetInterfaceID); 00735 parameters.addParameter("feMacroName", feMacroName); 00736 parameters.addParameter("inputArgs", inputArgsStr); 00737 SOAPUtilities::addParameters(message, parameters); 00738 00739 __FE_COUT__ << "Sending FE communication: " << SOAPUtilities::translate(message) 00740 << __E__; 00741 00742 xoap::MessageReference replyMessage = 00743 VStateMachine::parentSupervisor_->SOAPMessenger::sendWithSOAPReply( 00744 VStateMachine::parentSupervisor_->allSupervisorInfo_ 00745 .getAllMacroMakerTypeSupervisorInfo() 00746 .begin() 00747 ->second.getDescriptor(), 00748 message); 00749 00750 __FE_COUT__ << "Response received: " << SOAPUtilities::translate(replyMessage) 00751 << __E__; 00752 00753 SOAPParameters rxParameters; 00754 rxParameters.addParameter("Error"); 00755 SOAPUtilities::receive(replyMessage, rxParameters); 00756 00757 std::string error = rxParameters.getValue("Error"); 00758 00759 if(error != "") 00760 { 00761 // error occurred! 00762 __FE_SS__ << "Error transmitting request to target interface '" 00763 << targetInterfaceID << "' from '" << FEVInterface::interfaceUID_ 00764 << ".' " << error << __E__; 00765 __FE_SS_THROW__; 00766 } 00767 00768 // extract output args 00769 SOAPParameters argsOutParameter; 00770 argsOutParameter.addParameter("outputArgs"); 00771 SOAPUtilities::receive(replyMessage, argsOutParameter); 00772 00773 std::string outputArgsStr = argsOutParameter.getValue("outputArgs"); 00774 std::set<char> pairDelimiter({';'}), nameValueDelimiter({','}); 00775 00776 std::map<std::string, std::string> mapToReturn; 00777 StringMacros::getMapFromString( 00778 outputArgsStr, mapToReturn, pairDelimiter, nameValueDelimiter); 00779 00780 outputArgs.clear(); 00781 for(auto& mapPair : mapToReturn) 00782 outputArgs.push_back(mapPair); 00783 00784 } // end runFrontEndMacro() 00785 00786 //======================================================================================================================== 00787 // receiveFromFrontEnd 00788 // specialized template function for T=std::string 00789 // 00790 // Note: requester can be a wildcard string as defined in StringMacros 00791 void FEVInterface::receiveFromFrontEnd(const std::string& requester, 00792 std::string& retValue, 00793 unsigned int timeoutInSeconds) const 00794 { 00795 __FE_COUTV__(requester); 00796 __FE_COUTV__(parentSupervisor_); 00797 00798 std::string data = "0"; 00799 bool found = false; 00800 while(1) 00801 { 00802 // mutex scope 00803 { 00804 std::lock_guard<std::mutex> lock( 00805 parentInterfaceManager_->frontEndCommunicationReceiveMutex_); 00806 00807 auto receiveBuffersForTargetIt = 00808 parentInterfaceManager_->frontEndCommunicationReceiveBuffer_.find( 00809 FEVInterface::interfaceUID_); 00810 if(receiveBuffersForTargetIt != 00811 parentInterfaceManager_->frontEndCommunicationReceiveBuffer_.end()) 00812 { 00813 __FE_COUT__ << "Number of source buffers found for front-end '" 00814 << FEVInterface::interfaceUID_ 00815 << "': " << receiveBuffersForTargetIt->second.size() << __E__; 00816 00817 for(auto& buffPair : receiveBuffersForTargetIt->second) 00818 __FE_COUTV__(buffPair.first); 00819 00820 // match requester to map of buffers 00821 std::string sourceBufferId = ""; 00822 std::queue<std::string /*value*/>& sourceBuffer = 00823 StringMacros::getWildCardMatchFromMap( 00824 requester, receiveBuffersForTargetIt->second, &sourceBufferId); 00825 00826 __FE_COUT__ << "Found source buffer '" << sourceBufferId << "' with size " 00827 << sourceBuffer.size() << __E__; 00828 00829 if(sourceBuffer.size()) 00830 { 00831 __FE_COUT__ << "Found a value in queue of size " 00832 << sourceBuffer.size() << __E__; 00833 00834 // remove from receive buffer 00835 retValue = sourceBuffer.front(); 00836 sourceBuffer.pop(); 00837 return; 00838 } 00839 else 00840 __FE_COUT__ << "Source buffer empty for '" << requester << "'" 00841 << __E__; 00842 } 00843 00844 // else, not found... 00845 00846 // if out of time, throw error 00847 if(!timeoutInSeconds) 00848 { 00849 __FE_SS__ << "Timeout (" << timeoutInSeconds 00850 << " s) waiting for front-end communication from " << requester 00851 << "." << __E__; 00852 __FE_SS_THROW__; 00853 } 00854 // else, there is still hope 00855 00856 } // end mutex scope 00857 00858 // else try again in a sec 00859 __FE_COUT__ << "Waiting for front-end communication from " << requester << " for " 00860 << timeoutInSeconds << " more seconds..." << __E__; 00861 00862 --timeoutInSeconds; 00863 sleep(1); // wait a sec 00864 } // end timeout loop 00865 00866 // should never get here 00867 } // end receiveFromFrontEnd() 00868 00869 //======================================================================================================================== 00870 // receiveFromFrontEnd 00871 // specialized template function for T=std::string 00872 // Note: if called without template <T> syntax, necessary because types of 00873 // std::basic_string<char> cause compiler problems if no string specific function 00874 std::string FEVInterface::receiveFromFrontEnd(const std::string& requester, 00875 unsigned int timeoutInSeconds) const 00876 { 00877 std::string retValue; 00878 FEVInterface::receiveFromFrontEnd(requester, retValue, timeoutInSeconds); 00879 return retValue; 00880 } // end receiveFromFrontEnd() 00881 00882 //======================================================================================================================== 00883 // macroStruct_t constructor 00884 FEVInterface::macroStruct_t::macroStruct_t(const std::string& macroString) 00885 { 00886 __COUTV__(macroString); 00887 00888 // example macro string: 00889 // {"name":"testPublic","sequence":"0:w:1001:writeVal,1:r:1001:","time":"Sat Feb 0 00890 // 9 2019 10:42:03 GMT-0600 (Central Standard Time)","notes":"","LSBF":"false"}@ 00891 00892 std::vector<std::string> extractVec; 00893 StringMacros::getVectorFromString(macroString, extractVec, {'"'}); 00894 00895 __COUTV__(StringMacros::vectorToString(extractVec, " ||| ")); 00896 00897 enum 00898 { 00899 MACRONAME_NAME_INDEX = 1, 00900 MACRONAME_VALUE_INDEX = 3, 00901 SEQUENCE_NAME_INDEX = 5, 00902 SEQUENCE_VALUE_INDEX = 7, 00903 LSBF_NAME_INDEX = 17, 00904 LSFBF_VALUE_INDEX = 19, 00905 }; 00906 00907 // verify fields in sequence (for sanity) 00908 if(MACRONAME_NAME_INDEX >= extractVec.size() || 00909 extractVec[MACRONAME_NAME_INDEX] != "name") 00910 { 00911 __SS__ << "Invalid sequence, 'name' expected in position " << MACRONAME_NAME_INDEX 00912 << __E__; 00913 __SS_THROW__; 00914 } 00915 if(SEQUENCE_NAME_INDEX >= extractVec.size() || 00916 extractVec[SEQUENCE_NAME_INDEX] != "sequence") 00917 { 00918 __SS__ << "Invalid sequence, 'sequence' expected in position " 00919 << SEQUENCE_NAME_INDEX << __E__; 00920 __SS_THROW__; 00921 } 00922 if(LSBF_NAME_INDEX >= extractVec.size() || extractVec[LSBF_NAME_INDEX] != "LSBF") 00923 { 00924 __SS__ << "Invalid sequence, 'LSBF' expected in position " << LSBF_NAME_INDEX 00925 << __E__; 00926 __SS_THROW__; 00927 } 00928 macroName_ = extractVec[MACRONAME_VALUE_INDEX]; 00929 __COUTV__(macroName_); 00930 lsbf_ = extractVec[LSFBF_VALUE_INDEX] == "false" ? false : true; 00931 __COUTV__(lsbf_); 00932 std::string& sequence = extractVec[SEQUENCE_VALUE_INDEX]; 00933 __COUTV__(sequence); 00934 00935 std::vector<std::string> sequenceCommands; 00936 StringMacros::getVectorFromString(sequence, sequenceCommands, {','}); 00937 00938 __COUTV__(StringMacros::vectorToString(sequenceCommands, " ### ")); 00939 00940 for(auto& command : sequenceCommands) 00941 { 00942 __COUTV__(command); 00943 00944 // Note: the only way to distinguish between variable and data 00945 // is hex characters or not (lower and upper case allowed for hex) 00946 00947 std::vector<std::string> commandPieces; 00948 StringMacros::getVectorFromString(command, commandPieces, {':'}); 00949 00950 __COUTV__(StringMacros::vectorToString(commandPieces, " ### ")); 00951 00952 __COUTV__(commandPieces.size()); 00953 00954 // command format 00955 // index | type | address/sleep[ms] | data 00956 // d is delay (1+2) 00957 // w is write (1+3) 00958 // r is read (1+2/3 with arg) 00959 00960 // extract input arguments, as the variables in address/data fields 00961 // extract output arguments, as the variables in read data fields 00962 00963 if(commandPieces.size() < 3 || commandPieces.size() > 4 || 00964 commandPieces[1].size() != 1) 00965 { 00966 __SS__ << "Invalid command type specified in command string: " << command 00967 << __E__; 00968 __SS_THROW__; 00969 } 00970 00971 //========================== 00972 // Use lambda to identify variable name in field 00973 std::function<bool(const std::string& /*field value*/ 00974 )> 00975 localIsVariable = [/*capture variable*/](const std::string& fieldValue) { 00976 // create local message facility subject 00977 std::string mfSubject_ = "isVar"; 00978 __GEN_COUTV__(fieldValue); 00979 00980 // return false if all hex characters found 00981 for(const auto& c : fieldValue) 00982 if(!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || 00983 (c >= 'A' && c <= 'F'))) 00984 return true; // is variable name! 00985 return false; // else is a valid hex string, so not variable name 00986 00987 }; //end local lambda localIsVariable() 00988 00989 if(commandPieces[1][0] == 'r' && commandPieces.size() == 4) // read type 00990 { 00991 __COUT__ << "Read type found." << __E__; 00992 // 2: address or optional variable name 00993 // 3: optional variable name 00994 00995 operations_.push_back( 00996 std::make_pair(macroStruct_t::OP_TYPE_READ, readOps_.size())); 00997 00998 readOps_.push_back(macroStruct_t::readOp_t()); 00999 readOps_.back().addressIsVar_ = localIsVariable(commandPieces[2]); 01000 readOps_.back().dataIsVar_ = localIsVariable(commandPieces[3]); 01001 01002 if(!readOps_.back().addressIsVar_) 01003 { 01004 if(lsbf_) // flip byte order 01005 { 01006 std::string lsbfData = ""; 01007 01008 // always add leading 0 to guarantee do not miss data 01009 commandPieces[2] = "0" + commandPieces[2]; 01010 for(unsigned int i = 0; i < commandPieces[2].size() / 2; ++i) 01011 { 01012 __COUTV__(commandPieces[2].size() - 2 * (i + 1)); 01013 // add one byte at a time, backwards 01014 lsbfData += 01015 commandPieces[2][commandPieces[2].size() - 2 * (i + 1)]; 01016 lsbfData += 01017 commandPieces[2][commandPieces[2].size() - 2 * (i + 1) + 1]; 01018 __COUTV__(lsbfData); 01019 } 01020 __COUTV__(lsbfData); 01021 StringMacros::getNumber("0x" + lsbfData, readOps_.back().address_); 01022 } 01023 else 01024 StringMacros::getNumber("0x" + commandPieces[2], 01025 readOps_.back().address_); 01026 } 01027 else 01028 { 01029 readOps_.back().addressVarName_ = commandPieces[2]; 01030 __COUTV__(readOps_.back().addressVarName_); 01031 01032 namesOfInputArguments_.emplace(readOps_.back().addressVarName_); 01033 } 01034 01035 if(readOps_.back().dataIsVar_) 01036 { 01037 readOps_.back().dataVarName_ = commandPieces[3]; 01038 __COUTV__(readOps_.back().dataVarName_); 01039 01040 namesOfOutputArguments_.emplace(readOps_.back().dataVarName_); 01041 } 01042 } 01043 else if(commandPieces[1][0] == 'w' && commandPieces.size() == 4) // write type 01044 { 01045 __COUT__ << "Write type found." << __E__; 01046 // 2: address or optional variable name 01047 // 3: data or optional variable name 01048 01049 operations_.push_back( 01050 std::make_pair(macroStruct_t::OP_TYPE_WRITE, writeOps_.size())); 01051 01052 writeOps_.push_back(macroStruct_t::writeOp_t()); 01053 writeOps_.back().addressIsVar_ = localIsVariable(commandPieces[2]); 01054 writeOps_.back().dataIsVar_ = localIsVariable(commandPieces[3]); 01055 01056 if(!writeOps_.back().addressIsVar_) 01057 { 01058 if(lsbf_) // flip byte order 01059 { 01060 std::string lsbfData = ""; 01061 01062 // always add leading 0 to guarantee do not miss data 01063 commandPieces[2] = "0" + commandPieces[2]; 01064 for(unsigned int i = 0; i < commandPieces[2].size() / 2; ++i) 01065 { 01066 __COUTV__(commandPieces[2].size() - 2 * (i + 1)); 01067 // add one byte at a time, backwards 01068 lsbfData += 01069 commandPieces[2][commandPieces[2].size() - 2 * (i + 1)]; 01070 lsbfData += 01071 commandPieces[2][commandPieces[2].size() - 2 * (i + 1) + 1]; 01072 __COUTV__(lsbfData); 01073 } 01074 __COUTV__(lsbfData); 01075 StringMacros::getNumber("0x" + lsbfData, writeOps_.back().address_); 01076 } 01077 else 01078 StringMacros::getNumber("0x" + commandPieces[2], 01079 writeOps_.back().address_); 01080 } 01081 else 01082 { 01083 writeOps_.back().addressVarName_ = commandPieces[2]; 01084 __COUTV__(writeOps_.back().addressVarName_); 01085 01086 namesOfInputArguments_.emplace(writeOps_.back().addressVarName_); 01087 } 01088 01089 if(!writeOps_.back().dataIsVar_) 01090 { 01091 if(lsbf_) // flip byte order 01092 { 01093 std::string lsbfData = ""; 01094 01095 // always add leading 0 to guarantee do not miss data 01096 commandPieces[2] = "0" + commandPieces[3]; 01097 for(unsigned int i = 0; i < commandPieces[3].size() / 2; ++i) 01098 { 01099 __COUTV__(commandPieces[3].size() - 2 * (i + 1)); 01100 // add one byte at a time, backwards 01101 lsbfData += 01102 commandPieces[3][commandPieces[3].size() - 2 * (i + 1)]; 01103 lsbfData += 01104 commandPieces[3][commandPieces[3].size() - 2 * (i + 1) + 1]; 01105 __COUTV__(lsbfData); 01106 } 01107 __COUTV__(lsbfData); 01108 StringMacros::getNumber("0x" + lsbfData, writeOps_.back().data_); 01109 } 01110 else 01111 StringMacros::getNumber("0x" + commandPieces[3], 01112 writeOps_.back().data_); 01113 } 01114 else 01115 { 01116 writeOps_.back().dataVarName_ = commandPieces[3]; 01117 __COUTV__(writeOps_.back().dataVarName_); 01118 01119 namesOfInputArguments_.emplace(writeOps_.back().dataVarName_); 01120 } 01121 } 01122 else if(commandPieces[1][0] == 'd' && commandPieces.size() == 3) // delay type 01123 { 01124 __COUT__ << "Delay type found." << __E__; 01125 // 2: delay[ms] or optional variable name 01126 01127 operations_.push_back( 01128 std::make_pair(macroStruct_t::OP_TYPE_DELAY, delayOps_.size())); 01129 01130 delayOps_.push_back(macroStruct_t::delayOp_t()); 01131 delayOps_.back().delayIsVar_ = localIsVariable(commandPieces[2]); 01132 01133 if(!delayOps_.back().delayIsVar_) 01134 StringMacros::getNumber("0x" + commandPieces[2], delayOps_.back().delay_); 01135 else 01136 { 01137 delayOps_.back().delayVarName_ = commandPieces[2]; 01138 __COUTV__(delayOps_.back().delayVarName_); 01139 01140 namesOfInputArguments_.emplace(delayOps_.back().delayVarName_); 01141 } 01142 } 01143 else // invalid type 01144 { 01145 __SS__ << "Invalid command type '" << commandPieces[1][0] 01146 << "' specified with " << commandPieces.size() << " components." 01147 << __E__; 01148 __SS_THROW__; 01149 } 01150 01151 } // end sequence commands extraction loop 01152 01153 __COUT__ << operations_.size() << " operations extracted: \n\t" << readOps_.size() 01154 << " reads \n\t" << writeOps_.size() << " writes \n\t" << delayOps_.size() 01155 << " delays" << __E__; 01156 01157 __COUT__ << "Input arguments: " << __E__; 01158 for(const auto& inputArg : namesOfInputArguments_) 01159 __COUT__ << "\t" << inputArg << __E__; 01160 01161 __COUT__ << "Output arguments: " << __E__; 01162 for(const auto& outputArg : namesOfOutputArguments_) 01163 __COUT__ << "\t" << outputArg << __E__; 01164 01165 } // end macroStruct_t constructor 01166 01167 //======================================================================================================================== 01168 // runMacro 01169 void FEVInterface::runMacro( 01170 FEVInterface::macroStruct_t& macro, 01171 std::map<std::string /*name*/, uint64_t /*value*/>& variableMap) 01172 { 01173 // Similar to FEVInterface::runSequenceOfCommands() 01174 01175 __FE_COUT__ << "Running Macro '" << macro.macroName_ << "' of " 01176 << macro.operations_.size() << " operations." << __E__; 01177 01178 for(auto& op : macro.operations_) 01179 { 01180 if(op.first == macroStruct_t::OP_TYPE_READ) 01181 { 01182 __FE_COUT__ << "Doing read op..." << __E__; 01183 macroStruct_t::readOp_t& readOp = macro.readOps_[op.second]; 01184 if(readOp.addressIsVar_) 01185 { 01186 __FE_COUTV__(readOp.addressVarName_); 01187 readOp.address_ = variableMap.at(readOp.addressVarName_); 01188 } 01189 01190 uint64_t dataValue = 0; 01191 01192 __FE_COUT__ << std::hex << "Read address: \t 0x" << readOp.address_ << __E__ 01193 << std::dec; 01194 01195 universalRead((char*)&readOp.address_, (char*)&dataValue); 01196 01197 __FE_COUT__ << std::hex << "Read data: \t 0x" << dataValue << __E__ 01198 << std::dec; 01199 01200 if(readOp.dataIsVar_) 01201 { 01202 __FE_COUTV__(readOp.dataVarName_); 01203 variableMap.at(readOp.dataVarName_) = dataValue; 01204 } 01205 01206 } // end read op 01207 else if(op.first == macroStruct_t::OP_TYPE_WRITE) 01208 { 01209 __FE_COUT__ << "Doing write op..." << __E__; 01210 macroStruct_t::writeOp_t& writeOp = macro.writeOps_[op.second]; 01211 if(writeOp.addressIsVar_) 01212 { 01213 __FE_COUTV__(writeOp.addressVarName_); 01214 writeOp.address_ = variableMap.at(writeOp.addressVarName_); 01215 } 01216 if(writeOp.dataIsVar_) 01217 { 01218 __FE_COUTV__(writeOp.dataVarName_); 01219 writeOp.data_ = variableMap.at(writeOp.dataVarName_); 01220 } 01221 01222 __FE_COUT__ << std::hex << "Write address: \t 0x" << writeOp.address_ << __E__ 01223 << std::dec; 01224 __FE_COUT__ << std::hex << "Write data: \t 0x" << writeOp.data_ << __E__ 01225 << std::dec; 01226 01227 universalWrite((char*)&writeOp.address_, (char*)&writeOp.data_); 01228 01229 } // end write op 01230 else if(op.first == macroStruct_t::OP_TYPE_DELAY) 01231 { 01232 __FE_COUT__ << "Doing delay op..." << __E__; 01233 01234 macroStruct_t::delayOp_t& delayOp = macro.delayOps_[op.second]; 01235 if(delayOp.delayIsVar_) 01236 { 01237 __FE_COUTV__(delayOp.delayVarName_); 01238 delayOp.delay_ = variableMap.at(delayOp.delayVarName_); 01239 } 01240 01241 __FE_COUT__ << std::dec << "Delay ms: \t " << delayOp.delay_ << __E__; 01242 01243 usleep(delayOp.delay_ /*ms*/ * 1000); 01244 01245 } // end delay op 01246 else // invalid type 01247 { 01248 __FE_SS__ << "Invalid command type '" << op.first << "!'" << __E__; 01249 __FE_SS_THROW__; 01250 } 01251 01252 } // end operations loop 01253 01254 } // end runMacro