diff --git a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/share/MTCalibPeb.py b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/share/MTCalibPeb.py
index dd5a507f2dc25c45d3844601e4fca370bf978f4d..5ce18abe2e3458cd434ffccd8f04a57bbf1e7e3b 100644
--- a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/share/MTCalibPeb.py
+++ b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/share/MTCalibPeb.py
@@ -55,9 +55,25 @@ hypo.HypoOutputDecisions = "MTCalibPebDecisions"
 
 hypoTool1 = MTCalibPebHypoTool("HLT_MTCalibPeb1")
 hypoTool1.RandomAcceptRate = 0.75
+hypoTool1.BurnTimePerCycleMillisec = 100
+hypoTool1.NumBurnCycles = 3
 
 hypoTool2 = MTCalibPebHypoTool("HLT_MTCalibPeb2")
 hypoTool2.RandomAcceptRate = 0.25
+hypoTool2.BurnTimePerCycleMillisec = 200
+hypoTool2.NumBurnCycles = 10
+hypoTool2.TimeBetweenROBReqMillisec = 100
+hypoTool2.ROBAccessDict = {
+ "01 :ADD: Preload  ": [ 0x42002a, 0x42002b ],    # robs for 1st preload
+ "02 :ADD: Preload  ": [ 0x42002e, 0x42002f ],    # robs for 2nd preload
+ "03 :GET: Retrieve ": [ 0x42002e, 0x420060 ],    # robs for 1st retrieval
+ "04 :ADD: Preload  ": [ 0x420060 ],              # robs for 3rd preload
+ "05 :ADD: Preload  ": [ 0x420064 ],              # robs for 4th preload
+ "06 :ADD: Preload  ": [ 0x42002e, 0x420060 ],    # robs for 5th preload
+ "07 :GET: Retrieve ": [ 0x420060 ],              # robs for 2nd retrieval
+ "08 :GET: Retrieve ": [ 0x420064 ],              # robs for 3rd retrieval
+ "09 :COL: Ev.Build ": [ 0x0 ]                    # event building
+} # This is just an example with a few ROBs (LAr in this case) for testing the ROBDataProvider
 
 hypo.HypoTools = [hypoTool1, hypoTool2]
 
@@ -77,6 +93,10 @@ stmaker.ChainDecisions = "HLTFinalDecisions"
 stmaker.ChainToStream = {}
 stmaker.ChainToStream["HLT_MTCalibPeb1"] = "DataScouting_05_Jets"
 stmaker.ChainToStream["HLT_MTCalibPeb2"] = "Main"
+stmaker.StreamSubDets = {}
+stmaker.StreamSubDets["Main"] = [0x41, 0x42]
+stmaker.StreamRobs = {}
+stmaker.StreamRobs["Main"] = [0x42002e, 0x420060, 0x420064]
 
 # Tool adding HLT bits to HLT result
 bitsmaker = TriggerBitsMakerTool()
diff --git a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoAlg.cxx b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoAlg.cxx
index b752081e438684b3a5989abd57b45d15152b9e40..9d8a72ff20bed2c2c18768c200f7a797f2b52c16 100644
--- a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoAlg.cxx
+++ b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoAlg.cxx
@@ -28,6 +28,7 @@ MTCalibPebHypoAlg::~MTCalibPebHypoAlg() {}
 // =============================================================================
 StatusCode MTCalibPebHypoAlg::initialize() {
   ATH_MSG_INFO("Initialising " << name());
+  ATH_CHECK(m_hypoTools.retrieve());
   return StatusCode::SUCCESS;
 }
 
@@ -36,6 +37,7 @@ StatusCode MTCalibPebHypoAlg::initialize() {
 // =============================================================================
 StatusCode MTCalibPebHypoAlg::finalize() {
   ATH_MSG_INFO("Finalising " << name());
+  ATH_CHECK(m_hypoTools.release());
   return StatusCode::SUCCESS;
 }
 
@@ -50,12 +52,11 @@ StatusCode MTCalibPebHypoAlg::execute_r(const EventContext& eventContext) const
   auto aux = std::make_unique<DecisionAuxContainer>();
   decisions->setStore(aux.get());
 
-  // Prepare input for hypo tools
-  std::vector<MTCalibPebHypoTool::Input> toolInput;
-
   // Create new decision
   Decision* newd = newDecisionIn(decisions.get()); // DecisionContainer decisions owns the pointer
-  toolInput.emplace_back(newd);
+
+  // Prepare input for hypo tools
+  MTCalibPebHypoTool::Input toolInput(newd, eventContext);
 
   // Call the hypo tools
   for (const auto& tool: m_hypoTools) {
diff --git a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.cxx b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.cxx
index ecb5371e2935cce1bb6e680defa9bb7576be6c78..8f2dee375d82cc47f4222d4bf9117eaa1927c67b 100644
--- a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.cxx
+++ b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.cxx
@@ -2,15 +2,54 @@
   Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
 */
 
+// Trigger includes
 #include "MTCalibPebHypoTool.h"
+
+// Athena includes
+#include "AthenaKernel/Timeout.h"
+
+// System includes
 #include <random>
+#include <thread>
+#include <sstream>
 
 // Local implementation-specific helper methods
 namespace {
+  /// Returns a reference to static thread-local random number generator
+  std::mt19937& threadLocalGenerator() {
+    static thread_local std::random_device rd; // used only to ensure different seeds for mt19937
+    static thread_local std::mt19937 generator(rd());
+    return generator;
+  }
+  /// Basic random real number generation
+  template<typename T> T randomRealNumber(const T min, const T max) {
+    std::uniform_real_distribution<T> distribution(min, max);
+    return distribution(threadLocalGenerator());
+  }
+  /// Basic random integer generation
+  template<typename T> T randomInteger(const T min, const T max) {
+    std::uniform_int_distribution<T> distribution(min, max);
+    return distribution(threadLocalGenerator());
+  }
+  /// Random bool with a given true rate
   bool randomAccept(const double acceptRate) {
-      static thread_local std::mt19937 generator;
-      std::uniform_real_distribution<double> distribution(0.0, 1.0);
-      return (distribution(generator) < acceptRate);
+      return (randomRealNumber(0.0, 1.0) < acceptRate);
+  }
+  /// ROBFragments vector print helper
+  std::ostream& operator<<(std::ostream& str, const IROBDataProviderSvc::VROBFRAG& robFragments) {
+    for (const IROBDataProviderSvc::ROBF* robf : robFragments) {
+      str << "---> ROB ID = 0x" << std::hex << robf->rob_source_id() << std::dec << std::endl
+          << "     ROD ID = 0x" << std::hex << robf->rod_source_id() << std::dec << std::endl
+          << "     ROD Level-1 ID = " << robf->rod_lvl1_id() << std::endl;
+    }
+    return str;
+  }
+  /// ROB ID vector print helper
+  std::string robIdVecToString(const std::vector<uint32_t>& robIdVec) {
+    std::ostringstream str;
+    for (const uint32_t robId : robIdVec)
+      str << "0x" << std::hex << robId << std::dec << " ";
+    return str.str();
   }
 }
 
@@ -19,6 +58,7 @@ namespace {
 // =============================================================================
 MTCalibPebHypoTool::MTCalibPebHypoTool(const std::string& type, const std::string& name, const IInterface* parent)
 : AthAlgTool(type,name,parent),
+  m_robDataProviderSvc("ROBDataProviderSvc", name),
   m_decisionId (HLT::Identifier::fromToolName(name)) {}
 
 // =============================================================================
@@ -31,21 +71,86 @@ MTCalibPebHypoTool::~MTCalibPebHypoTool() {}
 // =============================================================================
 StatusCode MTCalibPebHypoTool::initialize() {
   ATH_MSG_INFO("Initialising " << name());
+  ATH_CHECK(m_robDataProviderSvc.retrieve());
   return StatusCode::SUCCESS;
 }
 
 // =============================================================================
-StatusCode MTCalibPebHypoTool::decide(const std::vector<MTCalibPebHypoTool::Input>& inputs) const {
+// Implementation of AthAlgTool::finalize
+// =============================================================================
+StatusCode MTCalibPebHypoTool::finalize() {
+  ATH_MSG_INFO("Finalising " << name());
+  ATH_CHECK(m_robDataProviderSvc.release());
+  return StatusCode::SUCCESS;
+}
 
-  bool accept = randomAccept(m_acceptRate);
-  for (auto& in : inputs) {
-    if (accept) {
-      ATH_MSG_DEBUG("Decision " << m_decisionId << " is accept");
-      TrigCompositeUtils::addDecisionID(m_decisionId, in.decision);
+// =============================================================================
+StatusCode MTCalibPebHypoTool::decide(const MTCalibPebHypoTool::Input& input) const {
+
+  // ---------------------------------------------------------------------------
+  // Burn CPU time
+  // ---------------------------------------------------------------------------
+  for (unsigned int iCycle = 0; iCycle < m_numBurnCycles; ++iCycle) {
+    if (Athena::Timeout::instance(input.eventContext).reached()) {
+      if (m_failOnTimeout) {
+        ATH_MSG_ERROR("Timeout reached in CPU time burning cycle # " << iCycle+1 << " and FailOnTimeout is true");
+        return StatusCode::FAILURE;
+      }
+      ATH_MSG_INFO("Timeout reached in CPU time burning cycle # " << iCycle+1);
+      break;
+    }
+    unsigned int burnTime = m_burnTimeRandomly
+                            ? randomInteger<unsigned int>(0, m_burnTimePerCycleMillisec)
+                            : m_burnTimePerCycleMillisec.value();
+    ATH_MSG_VERBOSE("CPU time burning cycle # " << iCycle+1 << ", burn time [ms] = " << burnTime);
+    std::this_thread::sleep_for(std::chrono::milliseconds(burnTime));
+  }
+
+  // ---------------------------------------------------------------------------
+  // Prefetch or retrieve ROBs
+  // ---------------------------------------------------------------------------
+  for (const auto& p : m_robAccessDict) {
+    // Check for timeout
+    if (Athena::Timeout::instance(input.eventContext).reached()) {
+      ATH_MSG_INFO("Timeout reached in ROB retrieval loop");
+      break;
+    }
+    const std::string& instruction = p.first;
+    const std::vector<uint32_t>& robs = p.second;
+    if (instruction.find(":ADD:")!=std::string::npos) {
+      // Prefetch ROBs
+      ATH_MSG_DEBUG("Preloading ROBs: " << robIdVecToString(robs));
+      m_robDataProviderSvc->addROBData(input.eventContext, robs, name()+"-ADD");
     }
-    else {
-      ATH_MSG_DEBUG("Decision " << m_decisionId << " is reject");
+    if (instruction.find(":GET:")!=std::string::npos) {
+      // Retrieve ROBs
+      ATH_MSG_DEBUG("Retrieving ROBs: " << robIdVecToString(robs));
+      // VROBFRAG = std::vector<const eformat::ROBFragment<const uint32_t*>* >
+      IROBDataProviderSvc::VROBFRAG robFragments;
+      m_robDataProviderSvc->getROBData(input.eventContext, robs, robFragments, name()+"-GET");
+      ATH_MSG_DEBUG("Number of ROBs retrieved: " << robFragments.size());
+      if (!robFragments.empty())
+        ATH_MSG_DEBUG("List of ROBs found: " << std::endl << robFragments);
     }
+    if (instruction.find(":COL:")!=std::string::npos) {
+      // Event building
+      ATH_MSG_DEBUG("Requesting full event ROBs");
+      int nrobs = m_robDataProviderSvc->collectCompleteEventData(input.eventContext, name()+"-COL");
+      ATH_MSG_DEBUG("Number of ROBs retrieved: " << nrobs);
+    }
+    std::this_thread::sleep_for(std::chrono::milliseconds(m_timeBetweenRobReqMillisec));
+  }
+
+  // ---------------------------------------------------------------------------
+  // Random accept decision
+  // ---------------------------------------------------------------------------
+  bool accept = randomAccept(m_acceptRate);
+  if (accept) {
+    ATH_MSG_DEBUG("Decision " << m_decisionId << " is accept");
+    TrigCompositeUtils::addDecisionID(m_decisionId, input.decision);
+  }
+  else {
+    ATH_MSG_DEBUG("Decision " << m_decisionId << " is reject");
   }
 
   return StatusCode::SUCCESS;
diff --git a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.h b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.h
index 2fa92ae597464e897bc082e5c19ecff6e3c5a337..a511a354cd568f4143eb8b3904b7fee0c4a32ad8 100644
--- a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.h
+++ b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/src/MTCalibPebHypoTool.h
@@ -6,18 +6,19 @@
 #define TRIGEXPARTIALEB_MTCALIBPEBHYPOTOOL_H
 
 // Trigger includes
+#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h"
 #include "DecisionHandling/HLTIdentifier.h"
 #include "DecisionHandling/TrigCompositeUtils.h"
 
 // Athena includes
 #include "AthenaBaseComps/AthAlgTool.h"
 
+// Gaudi includes
+#include "Gaudi/Parsers/Factory.h" // needed to declare less common Property types
+
 // TDAQ includes
 #include "eformat/StreamTag.h"
 
-// System includes
-#include <random>
-
 /** @class MTCalibPebHypoTool
  *  @brief Base class for tools used by MTCalibPebHypoAlg
  **/
@@ -30,26 +31,55 @@ public:
 
   // ------------------------- AthAlgTool methods ------------------------------
   virtual StatusCode initialize() override;
+  virtual StatusCode finalize() override;
 
   // ------------------------- Public types ------------------------------------
   struct Input {
-    Input(TrigCompositeUtils::Decision* d)
-    : decision(d) {}
+    Input(TrigCompositeUtils::Decision* d, const EventContext& ctx)
+    : decision(d), eventContext(ctx) {}
     TrigCompositeUtils::Decision* decision;
+    const EventContext& eventContext;
   };
 
   // ------------------------- Specific methods of this class ------------------
   /// Decides whether to accept the event
-  StatusCode decide(const std::vector<Input>& inputs) const;
+  StatusCode decide(const Input& input) const;
 
 private:
   // ------------------------- Properties --------------------------------------
   Gaudi::Property<double> m_acceptRate {
-    this,
-    "RandomAcceptRate",
-    -1,
+    this, "RandomAcceptRate", -1,
     "Rate of random accepts, <=0 is never, >=1 is always"
   };
+  Gaudi::Property<unsigned int> m_burnTimePerCycleMillisec {
+    this, "BurnTimePerCycleMillisec", 0,
+    "Burn time per cycle in milliseconds"
+  };
+  Gaudi::Property<unsigned int> m_numBurnCycles {
+    this, "NumBurnCycles", 0,
+    "Number of time burning cycles"
+  };
+  Gaudi::Property<bool> m_burnTimeRandomly {
+    this, "BurnTimeRandomly", true,
+    "If true, burn time per cycle is a random value from uniform distribution between 0 and the given value"
+  };
+  Gaudi::Property<bool> m_failOnTimeout {
+    this, "FailOnTimeout", true,
+    "If true, the execution will return StatusCode::FAILURE when Athena timeout is detected"
+  };
+  Gaudi::Property<std::map<std::string,std::vector<uint32_t> > > m_robAccessDict {
+    this, "ROBAccessDict", {},
+    "List of prefetch/retrieve operations with given ROB IDs."
+    "The string key has to contain :ADD: (prefetch), :GET: (retrieve), or :COL: (full event building)."
+    "The value is a vector of corresponding ROB IDs."
+  };
+  Gaudi::Property<unsigned int> m_timeBetweenRobReqMillisec {
+    this, "TimeBetweenROBReqMillisec", 0,
+    "Delay in milliseconds between subsequent ROB request operations from ROBAccessDict"
+  };
+
+  // ------------------------- Service or tool handles -------------------------
+  ServiceHandle<IROBDataProviderSvc> m_robDataProviderSvc;
 
   // ------------------------- Other private members ---------------------------
   /// The decision id of the tool instance
diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.cxx b/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.cxx
index 9227980a99949bb92189aab4bd34aa3ed0e80955..65b2f51448895e8a70ccdb6485434b333305b323 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.cxx
+++ b/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.cxx
@@ -10,14 +10,28 @@ StreamTagMakerTool::StreamTagMakerTool( const std::string& type, const std::stri
 
 StreamTagMakerTool::~StreamTagMakerTool() {}
 
-StatusCode StreamTagMakerTool::initialize() {  
-  // decode mapping
+StatusCode StreamTagMakerTool::initialize() {
   ATH_CHECK( m_finalChainDecisions.initialize() );
+  // decode mapping - temporary solution for testing
   for ( auto& chainAndStream: m_chainToStreamProperty ) {
-    struct { std::string chain, stream; } conf { chainAndStream.first, chainAndStream.second };    
+    struct { std::string chain, stream; } conf { chainAndStream.first, chainAndStream.second };
     ATH_MSG_DEBUG( "Chain " << conf.chain << " accepts events to stream " << conf.stream );
-    m_mapping[ HLT::Identifier( conf.chain ) ] = eformat::helper::StreamTag( conf.stream, "physics", true );
-    
+    // find subdets
+    std::set<eformat::SubDetector> dets;
+    const auto itSubDetMap = m_streamSubDets.value().find(conf.stream);
+    if (itSubDetMap != m_streamSubDets.value().cend()) {
+      for (const uint32_t detid : itSubDetMap->second)
+        dets.insert(static_cast<eformat::SubDetector>(detid & 0xFF)); // cast from uint32_t
+    }
+    // find robs
+    std::set<uint32_t> robs;
+    const auto itRobsMap = m_streamRobs.value().find(conf.stream);
+    if (itRobsMap != m_streamRobs.value().cend()) {
+      for (const uint32_t robid : itRobsMap->second)
+        robs.insert(robid);
+    }
+    // create the stream tag
+    m_mapping[ HLT::Identifier( conf.chain ) ] = eformat::helper::StreamTag( conf.stream, "physics", true, robs, dets );
   }
 
   return StatusCode::SUCCESS;
@@ -29,14 +43,14 @@ StatusCode StreamTagMakerTool::finalize() {
 
 
 StatusCode StreamTagMakerTool::fill( HLT::HLTResultMT& resultToFill ) const {
-  // obtain chain decisions, 
+  // obtain chain decisions,
   auto chainsHandle = SG::makeHandle( m_finalChainDecisions );
 
   // for each accepted chain lookup the map of chainID -> ST
   for ( TrigCompositeUtils::DecisionID chain: TrigCompositeUtils::decisionIDs( chainsHandle->at( 0 )) ) {
     auto mappingIter = m_mapping.find( chain );
     // each chain has to have stream
-    if( mappingIter == m_mapping.end() ) { 
+    if( mappingIter == m_mapping.end() ) {
       ATH_MSG_ERROR("Each chain has to have stream associated whereas the " << HLT::Identifier( chain ) << " does not" );
       return StatusCode::FAILURE;
     }
@@ -44,5 +58,5 @@ StatusCode StreamTagMakerTool::fill( HLT::HLTResultMT& resultToFill ) const {
   }
 
   ATH_MSG_DEBUG("Number of streams for event " <<  resultToFill.getStreamTags().size() );
-  return StatusCode::SUCCESS;  
+  return StatusCode::SUCCESS;
 }
diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.h b/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.h
index d3e42b474bb1753f983b6d3719429c587550173c..3debf49a80cdb107ce3a2a05787137b081a7d303 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.h
+++ b/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.h
@@ -10,6 +10,7 @@
 #include "AthenaBaseComps/AthAlgTool.h"
 #include "TrigOutputHandling/HLTResultMTMakerTool.h"
 #include "DecisionHandling/TrigCompositeUtils.h"
+#include "Gaudi/Parsers/Factory.h" // needed to declare less common Property types
 #include "eformat/StreamTag.h"
 
 /**
@@ -29,7 +30,9 @@ public:
 private:
   SG::ReadHandleKey<TrigCompositeUtils::DecisionContainer> m_finalChainDecisions { this, "ChainDecisions", "UNDEFINED", "Container with final chain decisions"  }; 
 
-  Gaudi::Property<std::map<std::string, std::string>> m_chainToStreamProperty { this, "ChainToStream", {}, "Mapping from the chain name to string name, (temporary solution, will be replaced)"};
+  Gaudi::Property<std::map<std::string, std::string>> m_chainToStreamProperty { this, "ChainToStream", {}, "Mapping from the chain name to string name (temporary solution, will be replaced)"};
+  Gaudi::Property<std::map<std::string, std::vector<uint32_t>>> m_streamSubDets { this, "StreamSubDets", {}, "Mapping from the stream name to subdetector IDs (temporary solution, will be replaced)"};
+  Gaudi::Property<std::map<std::string, std::vector<uint32_t>>> m_streamRobs { this, "StreamRobs", {}, "Mapping from the stream name to ROB IDs (temporary solution, will be replaced)"};
 
   typedef std::map< TrigCompositeUtils::DecisionID, eformat::helper::StreamTag> ChainToStreamMap;
   ChainToStreamMap m_mapping;