diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/CMakeLists.txt b/Trigger/TrigT1/TrigT1CaloByteStream/CMakeLists.txt
index 760ddc40b7766fe96ec8a47e891780908cfb07ed..0995d67f2333316b0fe3dfcb73fd3a6747b1c1dd 100644
--- a/Trigger/TrigT1/TrigT1CaloByteStream/CMakeLists.txt
+++ b/Trigger/TrigT1/TrigT1CaloByteStream/CMakeLists.txt
@@ -16,6 +16,7 @@ atlas_depends_on_subdirs( PUBLIC
                           Control/AthenaKernel
                           Control/SGTools
                           Control/StoreGate
+                          Control/CxxUtils
                           Event/ByteStreamCnvSvcBase
                           Event/ByteStreamData
                           Event/EventInfo
@@ -41,7 +42,7 @@ atlas_add_component( TrigT1CaloByteStream
                      src/xaod/*.cxx
                      src/components/*.cxx
                      INCLUDE_DIRS ${TDAQ-COMMON_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS}
-                     LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES} ${ROOT_LIBRARIES} AsgTools AthContainers xAODTrigL1Calo GaudiKernel AthenaBaseComps AthenaKernel SGTools StoreGateLib SGtests ByteStreamCnvSvcBaseLib ByteStreamData ByteStreamData_test EventInfo ZdcByteStreamLib TrigT1CaloEventLib TrigT1CaloUtilsLib TrigT1Interfaces )
+                     LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES} ${ROOT_LIBRARIES} AsgTools AthContainers xAODTrigL1Calo GaudiKernel AthenaBaseComps AthenaKernel SGTools StoreGateLib SGtests ByteStreamCnvSvcBaseLib ByteStreamData ByteStreamData_test EventInfo ZdcByteStreamLib TrigT1CaloEventLib TrigT1CaloUtilsLib TrigT1Interfaces CxxUtils )
 
 atlas_add_dictionary( TrigT1CaloByteStreamDict
                       TrigT1CaloByteStream/TrigT1CaloByteStreamDict.h
diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/xaod/PpmByteStreamReadV1V2Tool.cxx b/Trigger/TrigT1/TrigT1CaloByteStream/src/xaod/PpmByteStreamReadV1V2Tool.cxx
index c67620762b464d23289a2ab013be95dd64c12b26..d1c21f84a29802b9e148477882bb975b4d87d354 100644
--- a/Trigger/TrigT1/TrigT1CaloByteStream/src/xaod/PpmByteStreamReadV1V2Tool.cxx
+++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/xaod/PpmByteStreamReadV1V2Tool.cxx
@@ -24,6 +24,8 @@
 #include "../L1CaloSrcIdMap.h"
 
 #include "PpmByteStreamReadV1V2Tool.h"
+
+#include "CxxUtils/atomic_fetch_minmax.h"
 // ===========================================================================
 
 namespace {
@@ -64,20 +66,8 @@ PpmByteStreamReadV1V2Tool::PpmByteStreamReadV1V2Tool(const std::string& name /*=
     m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"),
     m_ppmMaps("LVL1::PpmMappingTool/PpmMappingTool"),
     m_robDataProvider("ROBDataProviderSvc", name),
-    m_subDetectorID(0),
-    m_requestedType(),
-    m_ppmIsRetMuon(false),
-    m_ppmIsRetSpare(false),
     m_srcIdMap(nullptr),
-    m_rodSourceId(0),
-    m_robSourceId(0),
-    m_rodRunNumber(0),
-    m_rodVer(0),
-    m_verCode(0),
-    m_ppPointer(0),
-    m_ppMaxBit(0),
-    m_maxSizeSeen(0),
-    m_triggerTowers(nullptr)
+    m_maxSizeSeen(0)
 {
   declareInterface<PpmByteStreamReadV1V2Tool>(this);
   declareProperty("PpmMappingTool", m_ppmMaps,
@@ -99,9 +89,7 @@ StatusCode PpmByteStreamReadV1V2Tool::initialize() {
   CHECK(m_ppmMaps.retrieve());
   CHECK(m_robDataProvider.retrieve());
 
-  ServiceHandle<IIncidentSvc> incidentSvc("IncidentSvc", name());
-  CHECK(incidentSvc.retrieve());
-  incidentSvc->addListener(this, IncidentType::EndEvent);
+  initSourceIDs();
 
   return StatusCode::SUCCESS;
 }
@@ -114,25 +102,16 @@ StatusCode PpmByteStreamReadV1V2Tool::finalize() {
   return StatusCode::SUCCESS;
 }
 
-void PpmByteStreamReadV1V2Tool::handle( const Incident& inc )
-{
-  if ( inc.type() == IncidentType::EndEvent) {
-
-  }
-}
 // Conversion bytestream to trigger towers
 StatusCode PpmByteStreamReadV1V2Tool::convert(
-    const IROBDataProviderSvc::VROBFRAG& robFrags,
-    xAOD::TriggerTowerContainer* const ttCollection) {
-
-  m_triggerTowers = ttCollection;
-
-  if (m_maxSizeSeen > m_triggerTowers->capacity()){
-    m_triggerTowers->reserve (m_maxSizeSeen);
+    State& state,
+    const IROBDataProviderSvc::VROBFRAG& robFrags) const
+{
+  if (m_maxSizeSeen > state.m_triggerTowers->capacity()){
+    state.m_triggerTowers->reserve (m_maxSizeSeen);
   }
 
-  m_subDetectorID = eformat::TDAQ_CALO_PREPROC;
-  m_requestedType = RequestType::PPM;
+  state.m_subDetectorID = eformat::TDAQ_CALO_PREPROC;
 
   ROBIterator rob = robFrags.begin();
   ROBIterator robEnd = robFrags.end();
@@ -140,53 +119,54 @@ StatusCode PpmByteStreamReadV1V2Tool::convert(
   int robCounter = 1;
   for (; rob != robEnd; ++rob, ++robCounter) {
 
-    StatusCode sc = processRobFragment_(rob, RequestType::PPM);
+    StatusCode sc = processRobFragment_(state, rob, RequestType::PPM);
     if (!sc.isSuccess()) {
 
     }
   }
 
-  m_maxSizeSeen = std::max (m_maxSizeSeen, m_triggerTowers->size());
-  m_triggerTowers = nullptr;
+  CxxUtils::atomic_fetch_max (&m_maxSizeSeen, state.m_triggerTowers->size());
   return StatusCode::SUCCESS;
 }
 
 
 StatusCode PpmByteStreamReadV1V2Tool::convert(
-    xAOD::TriggerTowerContainer* const ttCollection) {
+    xAOD::TriggerTowerContainer* const ttCollection) const
+{
   return convert(LVL1::TrigT1CaloDefs::xAODTriggerTowerLocation, ttCollection);
 }
 
 StatusCode PpmByteStreamReadV1V2Tool::convert(const std::string& sgKey,
-    xAOD::TriggerTowerContainer* const ttCollection) {
-
-  m_triggerTowers = ttCollection;
-
-  const std::vector<uint32_t>& vID(ppmSourceIDs(sgKey));
+    xAOD::TriggerTowerContainer* const ttCollection) const
+{
+  State state;
+  state.m_triggerTowers = ttCollection;
+  const std::vector<uint32_t>& vID(ppmSourceIDs(state, sgKey));
   // // get ROB fragments
   IROBDataProviderSvc::VROBFRAG robFrags;
   m_robDataProvider->getROBData(vID, robFrags, "PpmByteStreamxAODReadTool");
   ATH_MSG_DEBUG("Number of ROB fragments:" << robFrags.size());
 
-  CHECK(convert(robFrags, ttCollection));
+  CHECK(convert(state, robFrags));
   return StatusCode::SUCCESS;
 }
 
 // ===========================================================================
 StatusCode PpmByteStreamReadV1V2Tool::processRobFragment_(
-    const ROBIterator& robIter, const RequestType& /*requestedType*/) {
-
+    State& state,
+    const ROBIterator& robIter, const RequestType& /*requestedType*/) const
+{
   auto rob = **robIter;
 
   ATH_MSG_DEBUG(
       "Treating ROB fragment source id #" << MSG::hex << rob.rob_source_id());
 
 
-  m_rodSourceId = rob.rod_source_id();
-  m_robSourceId = rob.source_id();
-  const auto sourceID = (m_rodSourceId >> 16) & 0xff;
-  const auto rodCrate = m_srcIdMap->crate(m_rodSourceId);
-  const auto rodSlink = m_srcIdMap->slink(m_rodSourceId);
+  state.m_rodSourceId = rob.rod_source_id();
+  state.m_robSourceId = rob.source_id();
+  const auto sourceID = (state.m_rodSourceId >> 16) & 0xff;
+  const auto rodCrate = m_srcIdMap->crate(state.m_rodSourceId);
+  const auto rodSlink = m_srcIdMap->slink(state.m_rodSourceId);
   // -------------------------------------------------------------------------
   // Check Rob status
   if (rob.nstatus() > 0) {
@@ -194,7 +174,7 @@ StatusCode PpmByteStreamReadV1V2Tool::processRobFragment_(
     rob.status(robData);
     if (*robData != 0) {
       ATH_MSG_WARNING("ROB status error - skipping fragment");
-      m_errorTool->robError(m_rodSourceId, *robData);
+      m_errorTool->robError(state.m_rodSourceId, *robData);
       return StatusCode::FAILURE;
     }
   }
@@ -214,31 +194,31 @@ StatusCode PpmByteStreamReadV1V2Tool::processRobFragment_(
   // -------------------------------------------------------------------------
 
 
-  m_rodVer = rob.rod_version() & 0xffff;
-  m_verCode = ((m_rodVer & 0xfff) << 4) | 1;
-  m_rodRunNumber = rob.rod_run_no() & 0xffffff;
+  uint16_t rodVer = rob.rod_version() & 0xffff;
+  uint32_t rodRunNumber = rob.rod_run_no() & 0xffffff;
+  state.m_verCode = ((rodVer & 0xfff) << 4) | 1;
 
 
-  if (sourceID != m_subDetectorID) {
-    ATH_MSG_ERROR("Wrong subdetector source id for requested objects: " << m_rodSourceId);
+  if (sourceID != state.m_subDetectorID) {
+    ATH_MSG_ERROR("Wrong subdetector source id for requested objects: " << state.m_rodSourceId);
     return StatusCode::FAILURE;
   }
 
   ATH_MSG_DEBUG("Treating crate " << rodCrate << " slink " << rodSlink);
-  m_caloUserHeader = CaloUserHeader(*payload);
-  if (!m_caloUserHeader.isValid()) {
+  state.m_caloUserHeader = CaloUserHeader(*payload);
+  if (!state.m_caloUserHeader.isValid()) {
     ATH_MSG_ERROR("Invalid or missing user header");
     return StatusCode::FAILURE;
   }
 
   ATH_MSG_DEBUG(
-      "Run number: " << MSG::dec << m_rodRunNumber << endmsg
-          << "Version code: 0x" << MSG::hex << int(m_verCode) << MSG::dec
+      "Run number: " << MSG::dec << rodRunNumber << endmsg
+      << "Version code: 0x" << MSG::hex << int(state.m_verCode) << MSG::dec
           << endmsg << "LUT triggered slice offset:  "
-          << int(m_caloUserHeader.lut()) << endmsg
-          << "FADC triggered slice offset: " << int(m_caloUserHeader.ppFadc())
+          << int(state.m_caloUserHeader.lut()) << endmsg
+          << "FADC triggered slice offset: " << int(state.m_caloUserHeader.ppFadc())
           << endmsg << "FADC baseline lower bound:   "
-          << int(m_caloUserHeader.ppLowerBound()));
+          << int(state.m_caloUserHeader.ppLowerBound()));
 
   int indata = 0;
   uint8_t blockType = 0;
@@ -249,32 +229,32 @@ StatusCode PpmByteStreamReadV1V2Tool::processRobFragment_(
 
     } else if (SubBlockHeader::isSubBlockHeader(*payload)) {
       indata = 0;
-      CHECK(processPpmBlock_());
+      CHECK(processPpmBlock_(state));
 
-      m_ppLuts.clear();
-      m_ppFadcs.clear();
-      m_ppBlock.clear();
+      state.m_ppLuts.clear();
+      state.m_ppFadcs.clear();
+      state.m_ppBlock.clear();
 
       blockType = (*payload >> 28) & 0xf;
 
       if ((blockType & 0xd) == 0xc) {
-        m_subBlockHeader = SubBlockHeader(*payload);
+        state.m_subBlockHeader = SubBlockHeader(*payload);
         ATH_MSG_VERBOSE(
-            "SubBlock version #" << int(m_subBlockHeader.version())
-             << " format #" << int(m_subBlockHeader.format())
-             << " seqNum (compVer) #" << int(m_subBlockHeader.seqNum())
-             << " nslice1 #" << int(m_subBlockHeader.nSlice1())
-             << " nslice2 #" << int(m_subBlockHeader.nSlice2())
+            "SubBlock version #" << int(state.m_subBlockHeader.version())
+             << " format #" << int(state.m_subBlockHeader.format())
+             << " seqNum (compVer) #" << int(state.m_subBlockHeader.seqNum())
+             << " nslice1 #" << int(state.m_subBlockHeader.nSlice1())
+             << " nslice2 #" << int(state.m_subBlockHeader.nSlice2())
         );
         subBlock = blockType & 0xe;
       } else if (blockType == (subBlock | 1)) {
-        processSubBlockStatus_(m_subBlockHeader.crate(), m_subBlockHeader.module(), *payload);
+        processSubBlockStatus_(state, state.m_subBlockHeader.crate(), state.m_subBlockHeader.module(), *payload);
         subBlock = 0;
       }
     } else {
-      switch(m_subDetectorID){
+      switch(state.m_subDetectorID){
       case eformat::TDAQ_CALO_PREPROC:
-          CHECK(processPpmWord_(*payload, indata));
+          CHECK(processPpmWord_(state, *payload, indata));
           break;
       default:
         break;
@@ -282,21 +262,26 @@ StatusCode PpmByteStreamReadV1V2Tool::processRobFragment_(
       indata++;
     }
   }
-  CHECK(processPpmBlock_());
+  CHECK(processPpmBlock_(state));
+  state.m_ppLuts.clear();
+  state.m_ppFadcs.clear();
+  state.m_ppBlock.clear();
   return StatusCode::SUCCESS;
 }
 
-StatusCode PpmByteStreamReadV1V2Tool::processPpmWord_(uint32_t word,
-    int indata) {
-  if ( (m_subBlockHeader.format() == 0)
-      || (m_subBlockHeader.format() >= 2)
-      || (m_verCode >= 0x41)) {
-    m_ppBlock.push_back(word);
-  } else if ((m_verCode == 0x21) || (m_verCode == 0x31)) {
-    return processPpmStandardR3V1_(word, indata);
+StatusCode PpmByteStreamReadV1V2Tool::processPpmWord_(State& state,
+                                                      uint32_t word,
+                                                      int indata) const
+{
+  if ( (state.m_subBlockHeader.format() == 0)
+      || (state.m_subBlockHeader.format() >= 2)
+      || (state.m_verCode >= 0x41)) {
+    state.m_ppBlock.push_back(word);
+  } else if ((state.m_verCode == 0x21) || (state.m_verCode == 0x31)) {
+    return processPpmStandardR3V1_(state, word, indata);
   } else {
     ATH_MSG_ERROR("Unsupported PPM version:format ("
-      << m_verCode << ":" << m_subBlockHeader.format()
+      << state.m_verCode << ":" << state.m_subBlockHeader.format()
       <<") combination");
     return StatusCode::FAILURE;
   }
@@ -304,52 +289,48 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmWord_(uint32_t word,
 }
 
 
-StatusCode PpmByteStreamReadV1V2Tool::processPpmBlock_() {
-  if (m_ppBlock.size() > 0) {
-    m_ppPointer = 0;
-    if (m_subBlockHeader.format() == 0) {
-      StatusCode sc = processPpmNeutral_();
-      m_ppBlock.clear();
+StatusCode PpmByteStreamReadV1V2Tool::processPpmBlock_(State& state) const
+{
+  if (state.m_ppBlock.size() > 0) {
+    if (state.m_subBlockHeader.format() == 0) {
+      StatusCode sc = processPpmNeutral_(state);
       CHECK(sc);
       return sc;
     }
 
-    if (m_verCode == 0x31) {
-      StatusCode sc = processPpmCompressedR3V1_();
-      m_ppBlock.clear();
+    if (state.m_verCode == 0x31) {
+      StatusCode sc = processPpmCompressedR3V1_(state);
       CHECK(sc);
       return sc;
     }
 
-    if (m_verCode == 0x41 || m_verCode == 0x42) {
-      StatusCode sc = processPpmBlockR4V1_();
-      m_ppBlock.clear();
+    if (state.m_verCode == 0x41 || state.m_verCode == 0x42) {
+      StatusCode sc = processPpmBlockR4V1_(state);
       CHECK(sc);
       return sc;
     }
   }
 
-  if (m_ppLuts.size() > 0) {
-    if (m_verCode == 0x21 || m_verCode == 0x31) {
-      StatusCode sc = processPpmBlockR3V1_();
-      m_ppLuts.clear();
-      m_ppFadcs.clear();
+  if (state.m_ppLuts.size() > 0) {
+    if (state.m_verCode == 0x21 || state.m_verCode == 0x31) {
+      StatusCode sc = processPpmBlockR3V1_(state);
       CHECK(sc);
       return sc;
     }
     ATH_MSG_ERROR("Unknown PPM subheader format '"
-      << int(m_subBlockHeader.format())
+      << int(state.m_subBlockHeader.format())
       << "' for rob version '"
-      << MSG::hex << int(m_verCode)
+      << MSG::hex << int(state.m_verCode)
       << MSG::dec << "'" );
     return StatusCode::FAILURE;
   }
   return StatusCode::SUCCESS;
 }
 
-StatusCode PpmByteStreamReadV1V2Tool::processPpmNeutral_() {
-  uint8_t numLut = m_subBlockHeader.nSlice1();
-  uint8_t numFadc = m_subBlockHeader.nSlice2();
+StatusCode PpmByteStreamReadV1V2Tool::processPpmNeutral_(State& state) const
+{
+  uint8_t numLut = state.m_subBlockHeader.nSlice1();
+  uint8_t numFadc = state.m_subBlockHeader.nSlice2();
   uint8_t totSlice = 3 * numLut + numFadc;
 
   uint8_t channel = 0;
@@ -360,7 +341,7 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmNeutral_() {
 
       for ( uint8_t slice = 0 ; slice < totSlice ; ++slice ) {
         for ( uint8_t bit = 0 ; bit < 11 ; ++bit ) {
-          if ( m_ppBlock[slice * 11 + asic * (11 * totSlice) + bit + 1] & (1 << mcm))
+          if ( state.m_ppBlock[slice * 11 + asic * (11 * totSlice) + bit + 1] & (1 << mcm))
               rotated[slice] |= (1 << bit);
           }
       }
@@ -412,8 +393,9 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmNeutral_() {
       }
 
       CHECK(addTriggerTowerV2_(
-        m_subBlockHeader.crate(),
-        m_subBlockHeader.module(),
+        state,
+        state.m_subBlockHeader.crate(),
+        state.m_subBlockHeader.module(),
         channel,
         std::move(lcpVal),
         std::move(lcpBcidVec),
@@ -430,15 +412,15 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmNeutral_() {
   return StatusCode::SUCCESS;
 }
 
-StatusCode PpmByteStreamReadV1V2Tool::processPpmCompressedR3V1_() {
+StatusCode PpmByteStreamReadV1V2Tool::processPpmCompressedR3V1_(State& state) const
+{
+  BitReader br (state.m_ppBlock);
   uint8_t chan = 0;
-  m_ppPointer = 0;
-  m_ppMaxBit = 31 * m_ppBlock.size();
   try{
     while (chan < 64) {
       uint8_t present = 1;
-      if (m_subBlockHeader.format() == 3) {
-        present = getPpmBytestreamField_(1);
+      if (state.m_subBlockHeader.format() == 3) {
+        present = br.getField(1);
       }
 
       if (present == 1) {
@@ -451,42 +433,42 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmCompressedR3V1_() {
         std::vector<uint16_t> adcVal = {0 , 0, 0, 0, 0};
         std::vector<uint8_t> adcExt = {0 , 0, 0, 0, 0};
 
-        uint8_t minHeader = getPpmBytestreamField_(4);
+        uint8_t minHeader = br.getField(4);
         uint8_t minIndex = minHeader % 5;
         if (minHeader < 15) { // Formats 0-5
           if (minHeader < 10) { // Formats 0-1
             fmt = minHeader / 5;
           } else { // Formats 2-5
-            fmt = 2 + getPpmBytestreamField_(2);
-            uint8_t haveLut = getPpmBytestreamField_(1);
+            fmt = 2 + br.getField( 2);
+            uint8_t haveLut = br.getField(1);
             if (fmt == 2) {
               if (haveLut == 1) {
-                lutVal = getPpmBytestreamField_(3);
+                lutVal = br.getField(3);
                 lutPeak = 1; // Even if LutVal==0 it seems
               }
             } else {
-              uint8_t haveExt = getPpmBytestreamField_(1);
+              uint8_t haveExt = br.getField(1);
               if (haveLut == 1) {
-                lutVal = getPpmBytestreamField_(8);
-                lutExt = getPpmBytestreamField_(1);
-                lutSat = getPpmBytestreamField_(1);
-                lutPeak = getPpmBytestreamField_(1);
+                lutVal = br.getField(8);
+                lutExt = br.getField(1);
+                lutSat = br.getField(1);
+                lutPeak = br.getField(1);
               }
 
               if (haveExt == 1){
                 for(uint8_t i = 0; i < 5; ++i) {
-                  adcExt[i] = getPpmBytestreamField_(1);
+                  adcExt[i] = br.getField(1);
                 }
               } else {
                 adcExt[2] = lutExt;
               }
             }
           }
-          adcVal = getPpmAdcSamplesR3_(fmt, minIndex);
+          adcVal = getPpmAdcSamplesR3_(state, br, fmt, minIndex);
         } else {
-          uint8_t haveAdc = getPpmBytestreamField_(1);
+          uint8_t haveAdc = br.getField(1);
           if (haveAdc == 1) {
-            uint16_t val = getPpmBytestreamField_(10);
+            uint16_t val = br.getField(10);
             for(uint8_t i = 0; i < 5; ++i) {
                   adcVal[i] = val;
             }
@@ -495,8 +477,9 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmCompressedR3V1_() {
         // Add Trigger Tower
         //std::vector<uint8_t> luts = {lutVal};
         CHECK(addTriggerTowerV1_(
-          m_subBlockHeader.crate(),
-          m_subBlockHeader.module(),
+          state,
+          state.m_subBlockHeader.crate(),
+          state.m_subBlockHeader.module(),
           chan,
           std::vector<uint8_t> {lutVal},
           std::vector<uint8_t> {uint8_t(lutExt | (lutSat << 1) | (lutPeak << 2))},
@@ -508,14 +491,15 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmCompressedR3V1_() {
     }
   }catch (const std::out_of_range& ex) {
       ATH_MSG_WARNING("Excess Data in Sub-block");
-      m_errorTool->rodError(m_rodSourceId, L1CaloSubBlock::UNPACK_EXCESS_DATA);
+      m_errorTool->rodError(state.m_rodSourceId, L1CaloSubBlock::UNPACK_EXCESS_DATA);
   }
   return StatusCode::SUCCESS;
 }
 
 std::vector<uint16_t> PpmByteStreamReadV1V2Tool::getPpmAdcSamplesR3_(
-  uint8_t format, uint8_t minIndex) {
-
+  State& state,
+  BitReader& br, uint8_t format, uint8_t minIndex) const
+{
   std::vector<uint16_t> adc = {0, 0, 0, 0, 0};
   uint8_t minAdc = 0;
 
@@ -523,19 +507,19 @@ std::vector<uint16_t> PpmByteStreamReadV1V2Tool::getPpmAdcSamplesR3_(
     uint8_t longField = 0;
     uint8_t numBits = 0;
     if (format > 2) {
-      longField = getPpmBytestreamField_(1);
+      longField = br.getField(1);
       numBits = longField == 0? 4: (format * 2);
     } else {
       numBits = i == 0? 4: (format + 2);
     }
 
     if (i == 0) {
-      minAdc = getPpmBytestreamField_(numBits);
+      minAdc = br.getField(numBits);
       if (longField == 0) {
-        minAdc += m_caloUserHeader.ppLowerBound();
+        minAdc += state.m_caloUserHeader.ppLowerBound();
       }
     } else {
-        adc[i] = minAdc + getPpmBytestreamField_(numBits);
+        adc[i] = minAdc + br.getField(numBits);
     }
   }
 
@@ -550,31 +534,33 @@ std::vector<uint16_t> PpmByteStreamReadV1V2Tool::getPpmAdcSamplesR3_(
 
 
 
-StatusCode PpmByteStreamReadV1V2Tool::processPpmStandardR3V1_(uint32_t word,
-    int inData){
+StatusCode PpmByteStreamReadV1V2Tool::processPpmStandardR3V1_(State& state,
+                                                              uint32_t word,
+                                                              int inData) const
+{
 
   StatusCode sc = StatusCode::SUCCESS;
-  if (m_subBlockHeader.seqNum() == 63) { // Error block
+  if (state.m_subBlockHeader.seqNum() == 63) { // Error block
     ATH_MSG_DEBUG("Error PPM subblock");
     //TODO: errorTool
   } else {
-    const uint8_t numAdc = m_subBlockHeader.nSlice2();
-    const uint8_t numLut = m_subBlockHeader.nSlice1();
+    const uint8_t numAdc = state.m_subBlockHeader.nSlice2();
+    const uint8_t numLut = state.m_subBlockHeader.nSlice1();
     const uint8_t nTotal = numAdc + numLut;
     const uint8_t wordsPerBlock = 8; // 16 towers (4 MCMs) / 2 per word
     const uint8_t iBlk =  inData / wordsPerBlock;
-    uint8_t iChan =  m_subBlockHeader.seqNum() + 2 * (inData % wordsPerBlock);
+    uint8_t iChan =  state.m_subBlockHeader.seqNum() + 2 * (inData % wordsPerBlock);
 
     if (iBlk < numLut) { // First all LUT values
       for(uint8_t i = 0; i < 2; ++i) {
         uint16_t subword = (word >> 16 * i) & 0x7ff;
-        m_ppLuts[iChan].push_back(subword);
+        state.m_ppLuts[iChan].push_back(subword);
         iChan++;
       }
     } else if (iBlk < nTotal) { // Next all FADC values
       for(uint8_t i = 0; i < 2; ++i) {
         uint16_t subword = (word >> (16 * i)) & 0x7ff;
-        m_ppFadcs[iChan].push_back(subword);
+        state.m_ppFadcs[iChan].push_back(subword);
         iChan++;
       }
 
@@ -587,31 +573,26 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmStandardR3V1_(uint32_t word,
   return sc;
 }
 
-StatusCode PpmByteStreamReadV1V2Tool::processPpmBlockR4V1_() {
-  if (m_subBlockHeader.format() == 1) {
-    CHECK(processPpmStandardR4V1_());
+StatusCode PpmByteStreamReadV1V2Tool::processPpmBlockR4V1_(State& state) const
+{
+  if (state.m_subBlockHeader.format() == 1) {
+    CHECK(processPpmStandardR4V1_(state));
     return StatusCode::SUCCESS;
-  } else if (m_subBlockHeader.format() >= 2) {
-    CHECK(processPpmCompressedR4V1_());
+  } else if (state.m_subBlockHeader.format() >= 2) {
+    CHECK(processPpmCompressedR4V1_(state));
     return StatusCode::SUCCESS;
   }
   return StatusCode::FAILURE;
 }
 
-StatusCode PpmByteStreamReadV1V2Tool::processPpmCompressedR4V1_() {
-  m_ppPointer = 0;
-  m_ppMaxBit = 31 * m_ppBlock.size();
-
-  uint8_t numAdc = m_subBlockHeader.nSlice2();
-  uint8_t numLut = m_subBlockHeader.nSlice1();
+StatusCode PpmByteStreamReadV1V2Tool::processPpmCompressedR4V1_(State& state) const
+{
+  BitReader br (state.m_ppBlock);
+  uint8_t numAdc = state.m_subBlockHeader.nSlice2();
+  uint8_t numLut = state.m_subBlockHeader.nSlice1();
   int16_t pedCorBase = -20;
 
 
-  // for(size_t i = 0; i < m_ppBlock.size(); ++i) {
-  //   std::bitset<32> x(m_ppBlock[i]);
-  //   std::cout << i << " " << x << std::endl;
-  // }
-
   try{
     for(uint8_t chan = 0; chan < s_channels; ++chan) {
       uint8_t present = 1;
@@ -639,22 +620,22 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmCompressedR4V1_() {
       int8_t encoding = -1;
       int8_t minIndex = -1;
 
-      if (m_subBlockHeader.format() == 3) {
-        present = getPpmBytestreamField_(1);
+      if (state.m_subBlockHeader.format() == 3) {
+        present = br.getField(1);
       }
       if (present == 1) {
-        interpretPpmHeaderR4V1_(numAdc, encoding, minIndex);
+        interpretPpmHeaderR4V1_(br, numAdc, encoding, minIndex);
         CHECK((encoding != -1) && (minIndex != -1));
         // First get the LIT related quantities
         if (encoding < 3) {
           // Get the peal finder bits
           for(uint i=0; i < numLut; ++i) {
-            lcpPeak[i] = getPpmBytestreamField_(1);
+            lcpPeak[i] = br.getField(1);
           }
           // Get Sat80 low bits
           if (encoding > 0) {
             for (uint8_t i = 0; i < numLut; ++i) {
-              ljeLow[i] = getPpmBytestreamField_(1);
+              ljeLow[i] = br.getField(1);
             }
           }
           // Get LutCP and LutJEP values (these are
@@ -662,45 +643,45 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmCompressedR4V1_() {
           if (encoding == 2) {
             for (uint8_t i = 0; i < numLut; ++i) {
               if (lcpPeak[i] == 1) {
-                lcpVal[i] = getPpmBytestreamField_(4);
+                lcpVal[i] = br.getField(4);
               }
             }
             for(uint8_t i = 0; i < numLut; ++i) {
               if (lcpPeak[i] == 1){
-                ljeVal[i] = getPpmBytestreamField_(3);
+                ljeVal[i] = br.getField(3);
               }
             }
           }
         } else if (encoding < 6) {
           // Get LUT presence flag for each LUT slice.
           for(uint8_t i = 0; i < numLut; ++i){
-            haveLut[i] = getPpmBytestreamField_(1);
+            haveLut[i] = br.getField(1);
           }
 
           // Get external BCID bits (if block is present).
-          uint8_t haveExt = getPpmBytestreamField_(1);
+          uint8_t haveExt = br.getField(1);
 
           if (haveExt == 1) {
             for (uint8_t i = 0; i < numAdc; ++i) {
-              adcExt[i] = getPpmBytestreamField_(1);
+              adcExt[i] = br.getField(1);
             }
           }
 
           for(uint8_t i = 0; i < numLut; ++i){
             if (haveLut[i] == 1) {
-              lcpVal[i] = getPpmBytestreamField_(8);
-              lcpExt[i] = getPpmBytestreamField_(1);
-              lcpSat[i] = getPpmBytestreamField_(1);
-              lcpPeak[i] = getPpmBytestreamField_(1);
+              lcpVal[i] = br.getField(8);
+              lcpExt[i] = br.getField(1);
+              lcpSat[i] = br.getField(1);
+              lcpPeak[i] = br.getField(1);
             }
           }
           // Get JEP LUT values and corresponding bits.
           for(uint8_t i = 0; i < numLut; ++i){
             if (haveLut[i] == 1) {
-              ljeVal[i] = getPpmBytestreamField_(8);
-              ljeLow[i] = getPpmBytestreamField_(1);
-              ljeHigh[i] = getPpmBytestreamField_(1);
-              ljeRes[i] = getPpmBytestreamField_(1);
+              ljeVal[i] = br.getField(8);
+              ljeLow[i] = br.getField(1);
+              ljeHigh[i] = br.getField(1);
+              ljeRes[i] = br.getField(1);
             }
           }
 
@@ -708,13 +689,13 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmCompressedR4V1_() {
 
       }
        // Next get the ADC related quantities (all encodings).
-      adcVal = getPpmAdcSamplesR4_(encoding, minIndex);
+      adcVal = getPpmAdcSamplesR4_(state, br, encoding, minIndex);
       // Finally get the pedestal correction.
       if ((encoding < 3) || (encoding == 6)) {
         for (uint8_t i = 0; i < numLut; ++i)
         {
-          pedCor[i] = getPpmBytestreamField_(6) + pedCorBase;
-          if (m_subBlockHeader.compVer() > 0) {
+          pedCor[i] = br.getField(6) + pedCorBase;
+          if (state.m_subBlockHeader.compVer() > 0) {
             pedEn[i] = 1;
           }
         }
@@ -724,9 +705,9 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmCompressedR4V1_() {
         // The correction values is a twos complement signed value.
         for (uint8_t i = 0; i < numLut; ++i)
         {
-          uint16_t val = getPpmBytestreamField_(10);
+          uint16_t val = br.getField(10);
           pedCor[i] = ::pedCorrection(val);
-          pedEn[i] = getPpmBytestreamField_(1);
+          pedEn[i] = br.getField(1);
         }
       }
 
@@ -734,7 +715,8 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmCompressedR4V1_() {
       lcpBcidVec[i] = uint8_t((lcpPeak[i] << 2) | (lcpSat[i] << 1) | lcpExt[i]);
       ljeSat80Vec[i] = uint8_t((ljeRes[i] << 2) | (ljeHigh[i] << 1) | ljeLow[i]);
     }
-    CHECK(addTriggerTowerV2_(m_subBlockHeader.crate(), m_subBlockHeader.module(),
+    CHECK(addTriggerTowerV2_(state,
+                             state.m_subBlockHeader.crate(), state.m_subBlockHeader.module(),
                              chan,
                              std::move(lcpVal), std::move(lcpBcidVec),
                              std::move(ljeVal), std::move(ljeSat80Vec),
@@ -743,26 +725,28 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmCompressedR4V1_() {
     } // for
   } catch (const std::out_of_range& ex) {
       ATH_MSG_WARNING("Excess Data in Sub-block");
-      m_errorTool->rodError(m_rodSourceId, L1CaloSubBlock::UNPACK_EXCESS_DATA);
+      m_errorTool->rodError(state.m_rodSourceId, L1CaloSubBlock::UNPACK_EXCESS_DATA);
   }
   //Check status workd
   return StatusCode::SUCCESS;
 
 }
 
-void PpmByteStreamReadV1V2Tool::interpretPpmHeaderR4V1_(uint8_t numAdc,
-  int8_t& encoding, int8_t& minIndex) {
+void PpmByteStreamReadV1V2Tool::interpretPpmHeaderR4V1_(BitReader& br,
+                                                        uint8_t numAdc,
+  int8_t& encoding, int8_t& minIndex) const
+{
  uint8_t minHeader = 0;
 
   if (numAdc == 5) {
-    minHeader = getPpmBytestreamField_(4);
+    minHeader = br.getField(4);
 
     minIndex = minHeader % 5;
     if (minHeader < 15){ // Encodings 0-5
       if (minHeader < 10) {
         encoding = minHeader / 5;
       } else {
-        encoding = 2 + getPpmBytestreamField_(2);
+        encoding = 2 + br.getField(2);
       }
     } else {
       encoding = 6;
@@ -779,20 +763,20 @@ void PpmByteStreamReadV1V2Tool::interpretPpmHeaderR4V1_(uint8_t numAdc,
 
       if (numBits > 0) {
         uint8_t fieldSize = 1 << numBits;
-        minHeader = getPpmBytestreamField_(numBits);
+        minHeader = br.getField(numBits);
         uint8_t encValue = fieldSize - 1;
         if (minHeader == encValue) { // Encoding 6
           encoding = 6;
           minIndex = 0;
         } else {
-          minHeader += getPpmBytestreamField_(2) << numBits;
+          minHeader += br.getField(2) << numBits;
           minIndex = minHeader % fieldSize;
           encValue = 3 * fieldSize;
 
           if (minHeader < encValue) { // Encodings 0-2
             encoding = minHeader / fieldSize;
           } else {
-            encoding = 3 + getPpmBytestreamField_(2);
+            encoding = 3 + br.getField(2);
           }
         }
       }
@@ -800,57 +784,59 @@ void PpmByteStreamReadV1V2Tool::interpretPpmHeaderR4V1_(uint8_t numAdc,
 }
 
 std::vector<uint16_t> PpmByteStreamReadV1V2Tool::getPpmAdcSamplesR4_(
-  uint8_t encoding, uint8_t minIndex) {
-  uint8_t numAdc = m_subBlockHeader.nSlice2();
+  State& state,
+  BitReader& br,
+  uint8_t encoding, uint8_t minIndex) const
+{
+  uint8_t numAdc = state.m_subBlockHeader.nSlice2();
 
   if (encoding == 6) {
-    uint16_t val = getPpmBytestreamField_(6);
+    uint16_t val = br.getField(6);
     return std::vector<uint16_t>(numAdc, val);
   } else if ( encoding < 3) {
     std::vector<uint16_t> adc(numAdc, 0);
-    uint16_t minAdc = getPpmBytestreamField_(5) + m_caloUserHeader.ppLowerBound();
+    uint16_t minAdc = br.getField(5) + state.m_caloUserHeader.ppLowerBound();
     adc[minIndex] = minAdc;
     for(uint8_t i = 1; i < numAdc; ++i) {
-      adc[i == minIndex? 0: i] = getPpmBytestreamField_(encoding + 2) + minAdc;
+      adc[i == minIndex? 0: i] = br.getField(encoding + 2) + minAdc;
     }
     return adc;
   } else {
     std::vector<uint16_t> adc(numAdc, 0);
-    uint16_t minAdc = getPpmBytestreamField_(1)
-                      ? getPpmBytestreamField_(encoding * 2)
-                      : (getPpmBytestreamField_(5) +
-                          m_caloUserHeader.ppLowerBound());
+    uint16_t minAdc = br.getField(1)
+                      ? br.getField(encoding * 2)
+                      : (br.getField(5) +
+                          state.m_caloUserHeader.ppLowerBound());
 
     adc[minIndex] = minAdc;
     for (uint8_t i = 1; i < numAdc; ++i) {
-      adc[minIndex == i? 0: i] = getPpmBytestreamField_(
-                              getPpmBytestreamField_(1)? encoding * 2: 4
+      adc[minIndex == i? 0: i] = br.getField( 
+                              br.getField(1)? encoding * 2: 4
                             ) + minAdc;
     }
    return adc;
   }
 }
 
-StatusCode PpmByteStreamReadV1V2Tool::processPpmBlockR3V1_() {
-  if (m_subBlockHeader.format() == 1) {
-    CHECK(processPpmStandardR3V1_());
+StatusCode PpmByteStreamReadV1V2Tool::processPpmBlockR3V1_(State& state) const
+{
+  if (state.m_subBlockHeader.format() == 1) {
+    CHECK(processPpmStandardR3V1_(state));
     return StatusCode::SUCCESS;
-  } else if (m_subBlockHeader.format() >= 2) {
+  } else if (state.m_subBlockHeader.format() >= 2) {
     // TODO: convert compressed
     return StatusCode::FAILURE;
   }
   return StatusCode::FAILURE;
 }
 
-StatusCode PpmByteStreamReadV1V2Tool::processPpmStandardR4V1_() {
-  uint8_t numAdc = m_subBlockHeader.nSlice2();
-  uint8_t numLut = m_subBlockHeader.nSlice1();
-  uint8_t crate = m_subBlockHeader.crate();
-  uint8_t module = m_subBlockHeader.module();
-
-
-  m_ppPointer = 0;
-  m_ppMaxBit = 31 * m_ppBlock.size();
+StatusCode PpmByteStreamReadV1V2Tool::processPpmStandardR4V1_(State& state) const
+{
+  BitReader br (state.m_ppBlock);
+  uint8_t numAdc = state.m_subBlockHeader.nSlice2();
+  uint8_t numLut = state.m_subBlockHeader.nSlice1();
+  uint8_t crate = state.m_subBlockHeader.crate();
+  uint8_t module = state.m_subBlockHeader.module();
 
   for (uint8_t chan = 0; chan < 64; ++chan) {
 
@@ -869,31 +855,32 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmStandardR4V1_() {
     std::vector<uint8_t> pedEn;
     try {
       for (int i = 0; i < numLut; ++i) {
-        lcpVal.push_back(getPpmBytestreamField_(8));
-        lcpBcidVec.push_back(getPpmBytestreamField_(3));
+        lcpVal.push_back(br.getField(8));
+        lcpBcidVec.push_back(br.getField(3));
       }
 
       for (int i = 0; i < numLut; ++i) {
-        ljeVal.push_back(getPpmBytestreamField_(8));
-        ljeSat80Vec.push_back(getPpmBytestreamField_(3));
+        ljeVal.push_back(br.getField(8));
+        ljeSat80Vec.push_back(br.getField(3));
       }
 
       for (int i = 0; i < numAdc; ++i) {
-        adcVal.push_back(getPpmBytestreamField_(10));
-        adcExt.push_back(getPpmBytestreamField_(1));
+        adcVal.push_back(br.getField(10));
+        adcExt.push_back(br.getField(1));
       }
 
       for (int i = 0; i < numLut; ++i) {
-        uint16_t pc = getPpmBytestreamField_(10);
+        uint16_t pc = br.getField(10);
         pedCor.push_back(pedCorrection(pc));
-        pedEn.push_back(getPpmBytestreamField_(1));
+        pedEn.push_back(br.getField(1));
       }
     } catch (const std::out_of_range& ex) {
       ATH_MSG_WARNING("Excess Data in Sub-block");
-      m_errorTool->rodError(m_rodSourceId, L1CaloSubBlock::UNPACK_EXCESS_DATA);
+      m_errorTool->rodError(state.m_rodSourceId, L1CaloSubBlock::UNPACK_EXCESS_DATA);
     }
     CHECK(
-        addTriggerTowerV2_(crate, module, chan,
+        addTriggerTowerV2_(state,
+                           crate, module, chan,
                            std::move(lcpVal), std::move(lcpBcidVec),
                            std::move(ljeVal), std::move(ljeSat80Vec),
                            std::move(adcVal), std::move(adcExt),
@@ -903,29 +890,33 @@ StatusCode PpmByteStreamReadV1V2Tool::processPpmStandardR4V1_() {
   return StatusCode::SUCCESS;
 }
 
-StatusCode PpmByteStreamReadV1V2Tool::processPpmStandardR3V1_() {
-    for(auto lut : m_ppLuts) {
+StatusCode PpmByteStreamReadV1V2Tool::processPpmStandardR3V1_(State& state) const
+{
+    for(auto lut : state.m_ppLuts) {
       CHECK(addTriggerTowerV1_(
-        m_subBlockHeader.crate(),
-        m_subBlockHeader.module(),
+        state,
+        state.m_subBlockHeader.crate(),
+        state.m_subBlockHeader.module(),
         lut.first,
         lut.second,
-        m_ppFadcs[lut.first]));
+        state.m_ppFadcs[lut.first]));
     }
     return StatusCode::SUCCESS;
 }
 
-void PpmByteStreamReadV1V2Tool::processSubBlockStatus_(uint8_t crate, uint8_t module, uint32_t payload){
+void PpmByteStreamReadV1V2Tool::processSubBlockStatus_(State& state,
+                                                       uint8_t crate, uint8_t module, uint32_t payload) const
+{
   LVL1::DataError errorBits(0);
   errorBits.set(LVL1::DataError::SubStatusWord, payload);
 
   const uint32_t error = errorBits.error();
-  int curr = m_triggerTowers->size() - 1;
+  int curr = state.m_triggerTowers->size() - 1;
   for(int i=0; i < s_channels; ++i){
     if (curr < 0){
       break;
     }
-    auto tt = (*m_triggerTowers)[curr--];
+    auto tt = (*state.m_triggerTowers)[curr--];
     if (tt->coolId() >> 16 & crateModuleMask(crate, module)){
       tt->setErrorWord(error);
     }else{
@@ -936,6 +927,7 @@ void PpmByteStreamReadV1V2Tool::processSubBlockStatus_(uint8_t crate, uint8_t mo
 
 
 StatusCode PpmByteStreamReadV1V2Tool::addTriggerTowerV2_(
+    State& state,
     uint8_t crate,
     uint8_t module,
     uint8_t channel,
@@ -946,8 +938,8 @@ StatusCode PpmByteStreamReadV1V2Tool::addTriggerTowerV2_(
     std::vector<uint16_t>&& adcVal,
     std::vector<uint8_t>&& adcExt,
     std::vector<int16_t>&& pedCor,
-    std::vector<uint8_t>&& pedEn) {
-
+    std::vector<uint8_t>&& pedEn) const
+{
   uint32_t coolId = ::coolId(crate, module, channel);
 
   int layer = 0;
@@ -956,7 +948,7 @@ StatusCode PpmByteStreamReadV1V2Tool::addTriggerTowerV2_(
 
   bool isData = m_ppmMaps->mapping(crate, module, channel, eta, phi, layer);
 
-  if (!isData && !m_ppmIsRetSpare && !m_ppmIsRetMuon){
+  if (!isData && !state.m_ppmIsRetSpare && !state.m_ppmIsRetMuon){
     return StatusCode::SUCCESS;
   }
 
@@ -968,19 +960,20 @@ StatusCode PpmByteStreamReadV1V2Tool::addTriggerTowerV2_(
   }
 
   xAOD::TriggerTower* tt = new xAOD::TriggerTower();
-  m_triggerTowers->push_back(tt);
+  state.m_triggerTowers->push_back(tt);
 
   tt->initialize(coolId, eta, phi,
                  std::move(lcpVal), std::move(ljeVal),
                  std::move(pedCor), std::move(pedEn),
                  std::move(lcpBcidVec), std::move(adcVal),
                  std::move(adcExt), std::move(ljeSat80Vec),
-                 0, m_caloUserHeader.lut(),
-      m_caloUserHeader.ppFadc());
+                 0, state.m_caloUserHeader.lut(),
+      state.m_caloUserHeader.ppFadc());
   return StatusCode::SUCCESS;
 }
 
 StatusCode PpmByteStreamReadV1V2Tool::addTriggerTowerV1_(
+    State& state,
     uint8_t crate,
     uint8_t module,
     uint8_t channel,
@@ -988,14 +981,15 @@ StatusCode PpmByteStreamReadV1V2Tool::addTriggerTowerV1_(
     std::vector<uint8_t>&& lcpBcidVec,
     std::vector<uint16_t>&& fadc,
     std::vector<uint8_t>&& bcidExt
-  ) {
-
+  ) const
+{
     std::vector<uint8_t> ljeSat80Vec;
 
     std::vector<int16_t> pedCor;
     std::vector<uint8_t> pedEn;
 
-   CHECK(addTriggerTowerV2_(crate, module, channel,
+   CHECK(addTriggerTowerV2_(state,
+                            crate, module, channel,
                             std::move(luts), std::move(lcpBcidVec),
                             std::move(luts) , std::move(ljeSat80Vec),
                             std::move(fadc), std::move(bcidExt),
@@ -1006,13 +1000,14 @@ StatusCode PpmByteStreamReadV1V2Tool::addTriggerTowerV1_(
 }
 
 StatusCode PpmByteStreamReadV1V2Tool::addTriggerTowerV1_(
+    State& state,
     uint8_t crate,
     uint8_t module,
     uint8_t channel,
     const std::vector<uint16_t>& luts,
     const std::vector<uint16_t>& fadc
-  ) {
-
+  ) const
+{
     std::vector<uint8_t> lcpVal;
     std::vector<uint8_t> lcpBcidVec;
 
@@ -1029,7 +1024,8 @@ StatusCode PpmByteStreamReadV1V2Tool::addTriggerTowerV1_(
       adcVal.push_back(BitField::get<uint16_t>(f, 1, 10));
     }
 
-   CHECK(addTriggerTowerV1_(crate, module, channel,
+   CHECK(addTriggerTowerV1_(state,
+                            crate, module, channel,
                             std::move(lcpVal), std::move(lcpBcidVec),
                             std::move(adcVal), std::move(adcExt)));
 
@@ -1039,51 +1035,61 @@ StatusCode PpmByteStreamReadV1V2Tool::addTriggerTowerV1_(
 
 // Return reference to vector with all possible Source Identifiers
 
-const std::vector<uint32_t>& PpmByteStreamReadV1V2Tool::ppmSourceIDs(
-  const std::string& sgKey) {
-
+void PpmByteStreamReadV1V2Tool::initSourceIDs()
+{
   const int crates = 8;
-  m_ppmIsRetMuon = false;
-  m_ppmIsRetSpare =  false;
 
-  if (sgKey.find("Muon") != std::string::npos) {
-    m_ppmIsRetMuon = true;
-  } else if (sgKey.find("Spare") != std::string::npos) {
-    m_ppmIsRetSpare = true;
-  }
-
-  if (m_ppmSourceIDs.empty()) {
-    for (int crate = 0; crate < crates; ++crate) {
-      for (int slink = 0; slink < m_srcIdMap->maxSlinks(); ++slink) {
-        const uint32_t rodId = m_srcIdMap->getRodID(crate, slink, 0,
-            eformat::TDAQ_CALO_PREPROC);
-        const uint32_t robId = m_srcIdMap->getRobID(rodId);
-        m_ppmSourceIDs.push_back(robId);
-        if (crate > 1 && crate < 6) {
-            m_ppmSourceIDsSpare.push_back(robId);
-            if (crate < 4 && slink == 0) {
-              m_ppmSourceIDsMuon.push_back(robId);
-            }
+  m_ppmSourceIDs.clear();
+  m_ppmSourceIDsSpare.clear();
+  m_ppmSourceIDsMuon.clear();
+
+  for (int crate = 0; crate < crates; ++crate) {
+    for (int slink = 0; slink < m_srcIdMap->maxSlinks(); ++slink) {
+      const uint32_t rodId = m_srcIdMap->getRodID(crate, slink, 0,
+                                                  eformat::TDAQ_CALO_PREPROC);
+      const uint32_t robId = m_srcIdMap->getRobID(rodId);
+      m_ppmSourceIDs.push_back(robId);
+      if (crate > 1 && crate < 6) {
+        m_ppmSourceIDsSpare.push_back(robId);
+        if (crate < 4 && slink == 0) {
+          m_ppmSourceIDsMuon.push_back(robId);
         }
       }
     }
   }
+}
+
+
+
+const std::vector<uint32_t>& PpmByteStreamReadV1V2Tool::ppmSourceIDs(
+  State& state,
+  const std::string& sgKey) const
+{
+  state.m_ppmIsRetMuon = false;
+  state.m_ppmIsRetSpare =  false;
+
+  if (sgKey.find("Muon") != std::string::npos) {
+    state.m_ppmIsRetMuon = true;
+  } else if (sgKey.find("Spare") != std::string::npos) {
+    state.m_ppmIsRetSpare = true;
+  }
 
-  if (m_ppmIsRetSpare) {
+  if (state.m_ppmIsRetSpare) {
     return m_ppmSourceIDsSpare;
   }
 
-  if (m_ppmIsRetMuon) {
+  if (state.m_ppmIsRetMuon) {
     return m_ppmSourceIDsMuon;
   }
 
   return m_ppmSourceIDs;
-
 }
 
 
 
-uint32_t PpmByteStreamReadV1V2Tool::getPpmBytestreamField_(const uint8_t numBits) {
+uint32_t PpmByteStreamReadV1V2Tool::BitReader::getField
+  (const uint8_t numBits)
+{
   if ((m_ppPointer + numBits) <= m_ppMaxBit) {
     uint32_t iWord = m_ppPointer / 31;
     uint8_t iBit = m_ppPointer % 31;
diff --git a/Trigger/TrigT1/TrigT1CaloByteStream/src/xaod/PpmByteStreamReadV1V2Tool.h b/Trigger/TrigT1/TrigT1CaloByteStream/src/xaod/PpmByteStreamReadV1V2Tool.h
index 456fc4dcd0f81e631fc7d501b216a40463728194..fd487c98a4bb752ebf612dd69c90e63e3faea0ee 100644
--- a/Trigger/TrigT1/TrigT1CaloByteStream/src/xaod/PpmByteStreamReadV1V2Tool.h
+++ b/Trigger/TrigT1/TrigT1CaloByteStream/src/xaod/PpmByteStreamReadV1V2Tool.h
@@ -13,6 +13,7 @@
 #include <vector>
 #include <unordered_map>
 #include <unordered_set>
+#include <atomic>
 
 
 // ===========================================================================
@@ -54,28 +55,22 @@ class L1CaloErrorByteStreamTool;
  * @author alexander.mazurov@cern.ch
  */
 
-class PpmByteStreamReadV1V2Tool: public asg::AsgTool, virtual public IIncidentListener {
+class PpmByteStreamReadV1V2Tool: public asg::AsgTool
+{
   ASG_TOOL_INTERFACE(PpmByteStreamReadV1V2Tool)
   ASG_TOOL_CLASS0(PpmByteStreamReadV1V2Tool)
 public:
   PpmByteStreamReadV1V2Tool(const std::string& name);
   virtual ~PpmByteStreamReadV1V2Tool() {};
 
-  virtual StatusCode initialize();
-  virtual StatusCode finalize();
-  virtual void handle( const Incident& );
+  virtual StatusCode initialize() override;
+  virtual StatusCode finalize() override;
 
   // =========================================================================
   /// Convert ROB fragments to trigger towers
-  StatusCode convert(
-    const IROBDataProviderSvc::VROBFRAG& robFrags,
-    xAOD::TriggerTowerContainer* const ttCollection
-  );
-  StatusCode convert(xAOD::TriggerTowerContainer* const ttCollection);
-  StatusCode convert(const std::string& sgKey, xAOD::TriggerTowerContainer* const ttCollection);
+  StatusCode convert(xAOD::TriggerTowerContainer* const ttCollection) const;
+  StatusCode convert(const std::string& sgKey, xAOD::TriggerTowerContainer* const ttCollection) const;
   // =========================================================================
-  /// Return reference to vector with all possible Source Identifiers
-  const std::vector<uint32_t>& ppmSourceIDs(const std::string& sgKey);
 
 private:
   enum class RequestType { PPM, CPM, CMX };
@@ -83,32 +78,88 @@ private:
   typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType      ROBPointer;
   typedef OFFLINE_FRAGMENTS_NAMESPACE::PointerType      RODPointer;
 
+  class BitReader
+  {
+  public:
+    BitReader (const std::vector<uint32_t>& ppBlock)
+      : m_ppPointer (0),
+        m_ppMaxBit (31 * ppBlock.size()),
+        m_ppBlock (ppBlock)
+    {
+    }
+
+    uint32_t getField (const uint8_t numBits);
+
+  private:
+    uint32_t m_ppPointer;
+    uint32_t m_ppMaxBit;
+    const std::vector<uint32_t>& m_ppBlock;
+  };
+
+
+  typedef std::map<uint8_t, std::vector<uint16_t>> LutsMap;
+  typedef std::map<uint8_t, std::vector<uint16_t>> FadcsMap;
+
+  struct State
+  {
+    uint32_t m_rodSourceId = 0;
+    uint32_t m_robSourceId = 0;
+    uint8_t m_verCode = 0;
+    uint8_t m_subDetectorID = 0;
+    bool m_ppmIsRetMuon = false;
+    bool m_ppmIsRetSpare = false;
+    CaloUserHeader m_caloUserHeader;
+    SubBlockHeader m_subBlockHeader;
+    xAOD::TriggerTowerContainer* m_triggerTowers;
+    LutsMap m_ppLuts;
+    FadcsMap m_ppFadcs;
+    std::vector<uint32_t> m_ppBlock;
+  };
+
 
 private:
-  StatusCode processRobFragment_(const ROBIterator& robFrag,
-                                 const RequestType& requestedType);
+  StatusCode convert(
+    State& state,
+    const IROBDataProviderSvc::VROBFRAG& robFrags) const;
+
+
+  void initSourceIDs();
+
+  /// Return reference to vector with all possible Source Identifiers
+  const std::vector<uint32_t>& ppmSourceIDs(State& state,
+                                            const std::string& sgKey) const;
+
+  StatusCode processRobFragment_(State& state,
+                                 const ROBIterator& robFrag,
+                                 const RequestType& requestedType) const;
 
   // ==========================================================================
   // PPM
   // ==========================================================================
-  StatusCode processPpmWord_(uint32_t word, int indata);
-  StatusCode processPpmBlock_();
-
-  StatusCode processPpmBlockR4V1_();
-  StatusCode processPpmBlockR3V1_();
-  StatusCode processPpmStandardR4V1_();
-  StatusCode processPpmStandardR3V1_();
-  StatusCode processPpmStandardR3V1_(uint32_t word, int indata);
-  StatusCode processPpmCompressedR3V1_();
-  std::vector<uint16_t> getPpmAdcSamplesR3_(uint8_t format, uint8_t minIndex);
-  StatusCode processPpmCompressedR4V1_();
-  void interpretPpmHeaderR4V1_(uint8_t numAdc, int8_t& encoding,
-                               int8_t& minIndex);
-  std::vector<uint16_t> getPpmAdcSamplesR4_(uint8_t encoding, uint8_t minIndex);
-  StatusCode processPpmNeutral_();
-  uint32_t getPpmBytestreamField_(uint8_t numBits);
+  StatusCode processPpmWord_(State& state,
+                             uint32_t word, int indata) const;
+  StatusCode processPpmBlock_(State& state) const;
+
+  StatusCode processPpmBlockR4V1_(State& state) const;
+  StatusCode processPpmBlockR3V1_(State& state) const;
+  StatusCode processPpmStandardR4V1_(State& state) const;
+  StatusCode processPpmStandardR3V1_(State& state) const;
+  StatusCode processPpmStandardR3V1_(State& state,
+                                     uint32_t word, int indata) const;
+  StatusCode processPpmCompressedR3V1_(State& state) const;
+  std::vector<uint16_t> getPpmAdcSamplesR3_(State& state,
+                                            BitReader& br, uint8_t format, uint8_t minIndex) const;
+  StatusCode processPpmCompressedR4V1_(State& state) const;
+  void interpretPpmHeaderR4V1_(BitReader& br,
+                               uint8_t numAdc, int8_t& encoding,
+                               int8_t& minIndex) const;
+  std::vector<uint16_t> getPpmAdcSamplesR4_(State& state,
+                                            BitReader& br,
+                                            uint8_t encoding, uint8_t minIndex) const;
+  StatusCode processPpmNeutral_(State& state) const;
 
   StatusCode addTriggerTowerV2_(
+    State& state,
     uint8_t crate,
     uint8_t module,
     uint8_t channel,
@@ -121,17 +172,19 @@ private:
     std::vector<uint16_t>&& adcVal,
     std::vector<uint8_t>&& adcExt,
     std::vector<int16_t>&& pedCor,
-    std::vector<uint8_t>&& pedEn);
+    std::vector<uint8_t>&& pedEn) const;
 
   StatusCode addTriggerTowerV1_(
+    State& state,
     uint8_t crate,
     uint8_t module,
     uint8_t channel,
     const std::vector<uint16_t>& luts,
     const std::vector<uint16_t>& fadc
-  );
+  ) const;
 
   StatusCode addTriggerTowerV1_(
+    State& state,
     uint8_t crate,
     uint8_t module,
     uint8_t channel,
@@ -139,9 +192,10 @@ private:
     std::vector<uint8_t>&& lcpBcidVec,
     std::vector<uint16_t>&& fadc,
     std::vector<uint8_t>&& bcidExt
-  );
+  ) const;
 
-  void processSubBlockStatus_(uint8_t crate, uint8_t module, uint32_t word);
+  void processSubBlockStatus_(State& state,
+                              uint8_t crate, uint8_t module, uint32_t word) const;
 
 private:
   ToolHandle<LVL1BS::L1CaloErrorByteStreamTool> m_errorTool;
@@ -151,40 +205,14 @@ private:
   ServiceHandle<IROBDataProviderSvc> m_robDataProvider;
 
 private:
-  CaloUserHeader m_caloUserHeader;
-  SubBlockHeader m_subBlockHeader;
-  // SubBlockStatus m_subBlockStatus;
-
-  uint8_t m_subDetectorID;
-  RequestType m_requestedType;
-
-  std::set<uint32_t> m_coolIds;
   std::vector<uint32_t> m_ppmSourceIDs;
-  bool m_ppmIsRetMuon;
   std::vector<uint32_t> m_ppmSourceIDsMuon;
-  bool m_ppmIsRetSpare;
   std::vector<uint32_t> m_ppmSourceIDsSpare;
-  std::vector<uint32_t> m_cpSourceIDs;
   L1CaloSrcIdMap* m_srcIdMap;
 
-  uint32_t m_rodSourceId;
-  uint32_t m_robSourceId;
-  uint32_t m_rodRunNumber;
-  uint16_t m_rodVer;
-  uint8_t m_verCode;
-
-  // For RUN2
-  std::vector<uint32_t> m_ppBlock;
-  uint32_t m_ppPointer;
-  uint32_t m_ppMaxBit;
-  // For RUN1
-  std::map<uint8_t, std::vector<uint16_t>> m_ppLuts;
-  std::map<uint8_t, std::vector<uint16_t>> m_ppFadcs;
-  size_t m_maxSizeSeen;
-// ==========================================================================
-private:
-  xAOD::TriggerTowerContainer* m_triggerTowers;
+  mutable std::atomic<size_t> m_maxSizeSeen;
 
+// ==========================================================================
 private:
    static const uint8_t s_crates   = 8;
    static const uint8_t s_modules  = 16;