From 610cf8666ae2cb5b25444e22e24d9a22b76ea948 Mon Sep 17 00:00:00 2001
From: Eric Torrence <eric.torrence@cern.ch>
Date: Thu, 10 Feb 2022 14:05:58 -0800
Subject: [PATCH] Add cable mapping DB for waveform digitizer

---
 .../WaveByteStream/CMakeLists.txt             |   8 +-
 .../python/WaveByteStreamConfig.py            |  51 +------
 .../src/RawWaveformDecoderTool.cxx            | 126 +++-------------
 .../src/RawWaveformDecoderTool.h              |  52 +------
 .../WaveByteStream/src/WaveByteStreamCnv.cxx  |   9 +-
 .../WaveByteStream/src/WaveByteStreamCnv.h    |   3 +-
 .../WaveformConditionsTools/CMakeLists.txt    |  27 ++++
 .../ATLAS_CHECK_THREAD_SAFETY                 |   1 +
 .../IWaveformCableMappingTool.h               |  44 ++++++
 .../python/WaveformCableMappingConfig.py      |  27 ++++
 .../src/WaveformCableMappingTool.cxx          | 139 ++++++++++++++++++
 .../src/WaveformCableMappingTool.h            |  75 ++++++++++
 .../WaveformConditionsTools_entries.cxx       |   3 +
 13 files changed, 353 insertions(+), 212 deletions(-)
 create mode 100644 Waveform/WaveformConditions/WaveformConditionsTools/CMakeLists.txt
 create mode 100644 Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/ATLAS_CHECK_THREAD_SAFETY
 create mode 100644 Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformCableMappingTool.h
 create mode 100644 Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformCableMappingConfig.py
 create mode 100644 Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx
 create mode 100644 Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.h
 create mode 100644 Waveform/WaveformConditions/WaveformConditionsTools/src/components/WaveformConditionsTools_entries.cxx

diff --git a/Waveform/WaveEventCnv/WaveByteStream/CMakeLists.txt b/Waveform/WaveEventCnv/WaveByteStream/CMakeLists.txt
index bdf35c03..36d36958 100644
--- a/Waveform/WaveEventCnv/WaveByteStream/CMakeLists.txt
+++ b/Waveform/WaveEventCnv/WaveByteStream/CMakeLists.txt
@@ -4,16 +4,10 @@
 atlas_subdir( WaveByteStream )
 
 # Component(s) in the package:
-#atlas_add_library( WaveByteStreamLib
-#                   WaveByteStream/*.h 
-#                   PUBLIC_HEADERS WaveByteStream
-#                   LINK_LIBRARIES   StoreGateLib 
-#		            )
-
 atlas_add_component( WaveByteStream
                      src/*.cxx
                      src/components/*.cxx
-                     LINK_LIBRARIES Identifier ScintIdentifier FaserCaloIdentifier AthenaKernel GaudiKernel FaserByteStreamCnvSvcBaseLib FaserEventStorageLib WaveRawEvent
+                     LINK_LIBRARIES AthenaKernel GaudiKernel FaserByteStreamCnvSvcBaseLib FaserEventStorageLib WaveRawEvent WaveformConditionsToolsLib
                      PRIVATE_LINK_LIBRARIES AthenaBaseComps )
 
 atlas_install_python_modules( python/*.py )
diff --git a/Waveform/WaveEventCnv/WaveByteStream/python/WaveByteStreamConfig.py b/Waveform/WaveEventCnv/WaveByteStream/python/WaveByteStreamConfig.py
index 840a4d0f..b3e1e730 100644
--- a/Waveform/WaveEventCnv/WaveByteStream/python/WaveByteStreamConfig.py
+++ b/Waveform/WaveEventCnv/WaveByteStream/python/WaveByteStreamConfig.py
@@ -1,54 +1,9 @@
 # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 
-from AthenaConfiguration.ComponentFactory import CompFactory
 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from WaveformConditionsTools.WaveformCableMappingConfig import WaveformCableMappingCfg
 
 def WaveByteStreamCfg(configFlags, **kwargs):
-
-    acc = ComponentAccumulator()
-
-    # Decide which waveform mapping to instantiate from Geo tag
-    
-    if configFlags.Input.isMC:
-        # Nothing to do for MC
-        print("WaveByteStreamConfig.WaveByteStreamCfg - Called for isMC True, nothing to do...")
-        return acc
-        
-    print("WaveByteStreamConfig.WaveByteStreamCfg - Found FaserVersion: ", configFlags.GeoModel.FaserVersion,)
-
-    # Channels are ordered front->back, bottom->top, right->left
-    if configFlags.GeoModel.FaserVersion == "FASER-TB00":
-        print(" - setting up testbeam detector")
-
-        waveform_tool = CompFactory.RawWaveformDecoderTool("RawWaveformDecoderTool")
-        waveform_tool.CaloChannels = [5, 3, 1, 4, 2, 0]
-        waveform_tool.VetoChannels = []
-        waveform_tool.TriggerChannels = [8, 9]
-        waveform_tool.PreshowerChannels = [6, 7]
-        acc.addPublicTool(waveform_tool)
-        
-    elif configFlags.GeoModel.FaserVersion == "FASER-01":
-        print(" - setting up TI12 detector")
-
-        waveform_tool = CompFactory.RawWaveformDecoderTool("RawWaveformDecoderTool")
-        waveform_tool.CaloChannels = [1, 0, 3, 2]
-        waveform_tool.VetoChannels = [4, 5, 6, 7]
-        waveform_tool.TriggerChannels = [9, 8, 11, 10]
-        waveform_tool.PreshowerChannels = [12, 13]
-        acc.addPublicTool(waveform_tool)
-
-    elif configFlags.GeoModel.FaserVersion == "FASER-02":
-        print(" - setting up TI12 with IFT detector")
-
-        # Need to fix this!
-        waveform_tool = CompFactory.RawWaveformDecoderTool("RawWaveformDecoderTool")
-        waveform_tool.CaloChannels = [1, 0, 3, 2]
-        waveform_tool.VetoChannels = [4, 5, 6, 7]
-        waveform_tool.TriggerChannels = [9, 8, 11, 10]
-        waveform_tool.PreshowerChannels = [12, 13]
-        acc.addPublicTool(waveform_tool)
-
-    else:
-        print(" - unknown version: user must set up Waveform channel mapping by hand!")
-
+    acc = WaveformCableMappingCfg(configFlags, **kwargs)
     return acc
+        
diff --git a/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.cxx b/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.cxx
index ec7a6641..f3a9f999 100644
--- a/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.cxx
+++ b/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.cxx
@@ -19,20 +19,6 @@ RawWaveformDecoderTool::RawWaveformDecoderTool(const std::string& type,
   : AthAlgTool(type, name, parent)
 {
   declareInterface<RawWaveformDecoderTool>(this);
-
-  // These must be configured by job options
-  declareProperty("CaloChannels", m_caloChannels);
-  declareProperty("VetoChannels", m_vetoChannels);
-  declareProperty("TriggerChannels", m_triggerChannels);
-  declareProperty("PreshowerChannels", m_preshowerChannels);
-
-  // Test channels is provided for conveniene, not normally used
-  declareProperty("TestChannels", m_testChannels);
-
-  // Clock should always be in channel 15
-  declareProperty("ClockChannels", m_clockChannels);
-  m_clockChannels.push_back(15);
-
 }
 
 RawWaveformDecoderTool::~RawWaveformDecoderTool()
@@ -43,82 +29,6 @@ StatusCode
 RawWaveformDecoderTool::initialize() 
 {
   ATH_MSG_DEBUG("RawWaveformDecoderTool::initialize()");
-
-  // Set up helpers
-  ATH_CHECK(detStore()->retrieve(m_ecalID, "EcalID"));
-  ATH_CHECK(detStore()->retrieve(m_vetoID, "VetoID"));
-  ATH_CHECK(detStore()->retrieve(m_triggerID, "TriggerID"));
-  ATH_CHECK(detStore()->retrieve(m_preshowerID, "PreshowerID"));
-
-  // Take each channel list and create identifiers
-
-  // Loop through digitizer channel lists creating Identifiers
-  m_identifierMap.clear();
-
-  // First, calorimeter.  Can either be 4 or 6 channels
-  // Bottom row first from left to right, then top row
-  int index=0;
-  int module=0;
-  int row=0;
-  int pmt=0;
-
-  int max_modules = m_caloChannels.size() / 2;
-  for (auto const& chan : m_caloChannels) {
-    row = index / max_modules;
-    module = index % max_modules;
-    index++;
-    // Only store in map if digitizer channel is valid
-    if (chan < 0) continue;
-    m_identifierMap[chan] = m_ecalID->pmt_id(row, module, pmt);
-    ATH_MSG_DEBUG("Mapped digitizer channel " << chan << " to calo ID: " << m_identifierMap[chan]);
-  }
-
-  // Next, veto detector.  Have station and plate here.
-  int station=0;
-  int plate=0;
-  pmt=0; 
-  index=0;
-
-  int max_stations=m_vetoChannels.size() / 2;
-  for (auto const& chan : m_vetoChannels) {
-    station = index / max_stations;
-    plate = index % max_stations;
-    index++;
-    // Only store in map if digitizer channel is valid
-    if (chan < 0) continue;
-    m_identifierMap[chan] = m_vetoID->pmt_id(station, plate, pmt);
-    ATH_MSG_DEBUG("Mapped digitizer channel " << chan << " to veto ID: " << m_identifierMap[chan]);
-  }
-
-  // Next, trigger detector.  Have pmt and plate.
-  pmt=0;
-  station=0;
-  index=0;
-  int max_plates=m_triggerChannels.size() / 2;
-  for (auto const& chan : m_triggerChannels) {
-    plate = index / max_plates;
-    pmt = index % max_plates;
-    index++;
-    // Only store in map if digitizer channel is valid
-    if (chan < 0) continue;
-    m_identifierMap[chan] = m_triggerID->pmt_id(station, plate, pmt);
-    ATH_MSG_DEBUG("Mapped dititizer channel " << chan << " to trigger ID: " << m_identifierMap[chan]);
-  }
-
-  // Finally, preshower detector.
-  pmt=0;
-  station=0;
-  plate=0;
-  index=0;
-  for (auto const& chan : m_preshowerChannels) {
-    plate = index;
-    index++;
-    // Only store in map if digitizer channel is valid
-    if (chan < 0) continue;
-    m_identifierMap[chan] = m_preshowerID->pmt_id(station, plate, pmt);
-    ATH_MSG_DEBUG("Mapped digitizer channel " << chan << " to preshower ID: " << m_identifierMap[chan]);
-  }
-
   return StatusCode::SUCCESS;
 }
 
@@ -131,8 +41,10 @@ RawWaveformDecoderTool::finalize()
 
 StatusCode
 RawWaveformDecoderTool::convert(const DAQFormats::EventFull* re, 
-				  RawWaveformContainer* container,
-				  const std::string key)
+				RawWaveformContainer* container,
+				const std::string key,
+				WaveformCableMap cable_map
+)
 {
   ATH_MSG_DEBUG("RawWaveformDecoderTool::convert("+key+")");
 
@@ -172,26 +84,32 @@ RawWaveformDecoderTool::convert(const DAQFormats::EventFull* re,
     ATH_MSG_DEBUG("Found valid digitizer fragment");
   }
 
-  std::vector<int>* channelList;
-
+  // Detector type to match in first element of cable map
+  std::string det_type;
   if (key == std::string("CaloWaveforms")) {
-    channelList = &m_caloChannels;
+    det_type = std::string("calo");
   } else if (key == std::string("VetoWaveforms")) {
-    channelList = &m_vetoChannels;
+    det_type = std::string("veto");
   } else if (key == std::string("TriggerWaveforms")) {
-    channelList = &m_triggerChannels;
+    det_type = std::string("trigger");
   } else if (key == std::string("PreshowerWaveforms")) {
-    channelList = &m_preshowerChannels;
-  } else if (key == std::string("TestWaveforms")) {
-    channelList = &m_testChannels;
+    det_type = std::string("preshower");
   } else if (key == std::string("ClockWaveforms")) {
-    channelList = &m_clockChannels;
+    det_type = std::string("clock");
   } else {
     ATH_MSG_ERROR("Unknown key " << key);
     return StatusCode::FAILURE;
   }
 
-  for (int channel: *channelList) {
+  // Loop over 16 digitizer channels
+  std::vector<int> channelList(16);
+  std::iota (std::begin(channelList), std::end(channelList), 0);
+
+  for (int channel: channelList) {
+
+    // Only look at channels we care about
+    if (det_type != cable_map[channel].first) continue;
+
     ATH_MSG_DEBUG("Converting channel "+std::to_string(channel)+" for "+key);
 
     // Check if this has data
@@ -223,8 +141,8 @@ RawWaveformDecoderTool::convert(const DAQFormats::EventFull* re,
     }
 
     // Set ID if one exists (clock, for instance, doesn't have an identifier)
-    if (m_identifierMap.count(channel) == 1) {
-      wfm->setIdentifier(m_identifierMap[channel]);
+    if (cable_map[channel].second != -1) { // Identifier doesn't have operator>=
+      wfm->setIdentifier(cable_map[channel].second);
     }
 
     container->push_back(wfm);    
diff --git a/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.h b/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.h
index e2852f13..1609d3eb 100644
--- a/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.h
+++ b/Waveform/WaveEventCnv/WaveByteStream/src/RawWaveformDecoderTool.h
@@ -13,11 +13,7 @@
 #include "EventFormats/DAQFormats.hpp"
 #include "WaveRawEvent/RawWaveformContainer.h"
 
-#include "Identifier/Identifier.h"
-#include "FaserCaloIdentifier/EcalID.h"
-#include "ScintIdentifier/VetoID.h"
-#include "ScintIdentifier/TriggerID.h"
-#include "ScintIdentifier/PreshowerID.h"
+#include "WaveformConditionsTools/IWaveformCableMappingTool.h"
 
 // This class provides conversion between bytestream and Waveform objects
 
@@ -34,53 +30,9 @@ class RawWaveformDecoderTool : public AthAlgTool {
   virtual StatusCode initialize();
   virtual StatusCode finalize();
 
-  StatusCode convert(const DAQFormats::EventFull* re, RawWaveformContainer* wfm, std::string key);
+  StatusCode convert(const DAQFormats::EventFull* re, RawWaveformContainer* wfm, std::string key, WaveformCableMap cable_map);
 
 private:
-  // List of channels to include in each container
-  // List order must correspond to offline channel order
-  // All L/R designations refer to looking at the detector from
-  // the beam direction.
-  //
-  // In general, the ordering is layer (longitudinal), row (vertical), module (horizontal)
-  // Layers increase with longitudianl position downstream
-  // Rows increase from bottom to top
-  // Modules increase from right to left
-  //
-  // For all lists, use invalid channel (-1) to indicate detectors
-  // missing in sequence (i.e. 3 of 4 veto counters)
-  // 
-  // TI12 detector:
-  // Calorimeter order:
-  //   bottom right, bottom left, top right, top left
-  // Veto 
-  //   front to back.  
-  // Trigger
-  //   bottom right PMT, bottom left PMT, top right PMT, top left PMT
-  // Preshower
-  //   front to back
-  //   
-  // 2021 Testbeam detector:
-  // Calo order:
-  //   bottom right, bottom center, bottom left, top R, top C, top L
-  // All others are just in order front to back 
-
-  std::vector<int> m_caloChannels;
-  std::vector<int> m_vetoChannels;
-  std::vector<int> m_triggerChannels;
-  std::vector<int> m_preshowerChannels;
-  std::vector<int> m_testChannels;
-  std::vector<int> m_clockChannels;
-
-  // Identifiers keyed by digitizer channel
-  std::map<unsigned int, Identifier> m_identifierMap;
-
-  // ID helpers
-  const EcalID* m_ecalID{nullptr};
-  const VetoID* m_vetoID{nullptr};
-  const TriggerID* m_triggerID{nullptr};
-  const PreshowerID* m_preshowerID{nullptr};
-
 };
 
 #endif  /* WAVEBYTESTREAM_FASERTRIGGERDECODERTOOL_H */
diff --git a/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.cxx b/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.cxx
index 189d94c5..b40fc3bd 100644
--- a/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.cxx
+++ b/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.cxx
@@ -26,6 +26,7 @@ WaveByteStreamCnv::WaveByteStreamCnv(ISvcLocator* svcloc)
   , AthMessaging(svcloc != nullptr ? msgSvc() : nullptr, "WaveByteStreamCnv")
   , m_name("WaveByteStreamCnv")
   , m_tool("RawWaveformDecoderTool")
+  , m_mappingTool("WaveformCableMappingTool")
   , m_rdpSvc("FaserROBDataProviderSvc", m_name)
 {
   ATH_MSG_DEBUG(m_name+"::initialize() called");
@@ -47,6 +48,7 @@ StatusCode WaveByteStreamCnv::initialize()
   CHECK(Converter::initialize());
   CHECK(m_rdpSvc.retrieve());
   CHECK(m_tool.retrieve());
+  CHECK(m_mappingTool.retrieve());
 
   return StatusCode::SUCCESS;
 }
@@ -90,9 +92,12 @@ StatusCode WaveByteStreamCnv::createObj(IOpaqueAddress* pAddr, DataObject*& pObj
 
   RawWaveformContainer* wfmCont = new RawWaveformContainer;
 
-  // Convert selected channels
+  // Get mapping tool
+  auto mapping = m_mappingTool->getCableMapping();
+  ATH_MSG_DEBUG("Cable mapping contains " << mapping.size() << " entries");
 
-  CHECK( m_tool->convert(re, wfmCont, key) );
+  // Convert selected channels
+  CHECK( m_tool->convert(re, wfmCont, key, mapping) );
   
   pObj = SG::asStorable(wfmCont);
 
diff --git a/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.h b/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.h
index 043ebef5..ce373326 100644
--- a/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.h
+++ b/Waveform/WaveEventCnv/WaveByteStream/src/WaveByteStreamCnv.h
@@ -14,6 +14,7 @@
 
 #include "AthenaBaseComps/AthMessaging.h"
 #include "FaserByteStreamCnvSvcBase/FaserByteStreamAddress.h"
+#include "WaveformConditionsTools/IWaveformCableMappingTool.h"
 
 class RawWaveformDecoderTool;
 class IFaserROBDataProviderSvc;
@@ -39,8 +40,8 @@ public:
 private:
   std::string m_name;
   ToolHandle<RawWaveformDecoderTool> m_tool;
+  ToolHandle<IWaveformCableMappingTool> m_mappingTool;
   ServiceHandle<IFaserROBDataProviderSvc> m_rdpSvc;
-
 };
 
 #endif  /* WAVEBYTESTREAM_WAVEBYTESTREAMCNV_H */
diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/CMakeLists.txt b/Waveform/WaveformConditions/WaveformConditionsTools/CMakeLists.txt
new file mode 100644
index 00000000..f1d7bbb4
--- /dev/null
+++ b/Waveform/WaveformConditions/WaveformConditionsTools/CMakeLists.txt
@@ -0,0 +1,27 @@
+###############################################################################
+# Package: WaveformConditionsTools
+################################################################################
+
+# Declare the package name:
+atlas_subdir( WaveformConditionsTools )
+
+# External dependencies:
+find_package( CLHEP )
+find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread )
+
+# Component(s) in the package:
+atlas_add_component ( WaveformConditionsTools
+                      src/components/*.cxx
+                      INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS}
+                      LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaKernel WaveformConditionsToolsLib Identifier ScintIdentifier FaserCaloIdentifier GaudiKernel AthenaBaseComps AthenaPoolUtilities StoreGateLib xAODEventInfo )
+
+
+atlas_add_library( WaveformConditionsToolsLib
+                  src/*.cxx
+                  PUBLIC_HEADERS WaveformConditionsTools
+                  INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS}
+                  LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} AthenaKernel Identifier ScintIdentifier FaserCaloIdentifier  GaudiKernel AthenaBaseComps AthenaPoolUtilities StoreGateLib xAODEventInfo )
+
+# Install files from the package:
+atlas_install_python_modules( python/*.py )
+
diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/ATLAS_CHECK_THREAD_SAFETY b/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/ATLAS_CHECK_THREAD_SAFETY
new file mode 100644
index 00000000..f80fa38a
--- /dev/null
+++ b/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/ATLAS_CHECK_THREAD_SAFETY
@@ -0,0 +1 @@
+Waveform/WaveformConditions/WaveformConditionsTools
diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformCableMappingTool.h b/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformCableMappingTool.h
new file mode 100644
index 00000000..8886506e
--- /dev/null
+++ b/Waveform/WaveformConditions/WaveformConditionsTools/WaveformConditionsTools/IWaveformCableMappingTool.h
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FAsER collaborations
+*/
+
+/** @file ISCT_CableMappingTool.h Interface file for SCT_CableMappingTool.
+ */
+
+// Multiple inclusion protection
+#ifndef IWAVEFORMCABLEMAPPINGTOOL
+#define IWAVEFORMCABLEMAPPINGTOOL
+
+//STL includes
+#include <map>
+
+//Gaudi Includes
+#include "GaudiKernel/IAlgTool.h"
+#include "GaudiKernel/EventContext.h"
+
+#include "Identifier/Identifier.h"
+
+// Cable map indexed by digitizer channel number
+// Contains detector type "calo", "trigger", "veto", "preshower" and identifier 
+typedef std::map<int, std::pair<std::string, Identifier> > WaveformCableMap;
+
+class IWaveformCableMappingTool: virtual public IAlgTool {
+
+ public:
+  
+  //----------Public Member Functions----------//
+  // Structors
+  virtual ~IWaveformCableMappingTool() = default; //!< Destructor
+
+  /// Creates the InterfaceID and interfaceID() method
+  DeclareInterfaceID(IWaveformCableMappingTool, 1, 0);
+
+  // Methods to return cable-mapping data 
+  // Key is digitizer channel, pair is <type, identifier>
+  virtual WaveformCableMap getCableMapping(const EventContext& ctx) const = 0;
+  virtual WaveformCableMap getCableMapping(void) const = 0;
+
+};
+
+//---------------------------------------------------------------------- 
+#endif // WAVEFORMCABLEMAPPINGTOOL
diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformCableMappingConfig.py b/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformCableMappingConfig.py
new file mode 100644
index 00000000..bf90fb5d
--- /dev/null
+++ b/Waveform/WaveformConditions/WaveformConditionsTools/python/WaveformCableMappingConfig.py
@@ -0,0 +1,27 @@
+""" Define methods to configure WaveformCableMapping
+
+Copyright (C) 2022 CERN for the benefit of the FASER collaboration
+"""
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+from IOVDbSvc.IOVDbSvcConfig import addFolders
+WaveformCableMappingTool=CompFactory.WaveformCableMappingTool
+
+def WaveformCableMappingToolCfg(flags, name="WaveformCableMappingTool", **kwargs):
+    """ Return a configured WaveformCableMappingTool"""
+    return WaveformCableMappingTool(name, **kwargs)
+
+def WaveformCableMappingCfg(flags, **kwargs):
+    """ Return configured ComponentAccumulator and tool for Waveform CableMapping 
+
+    WaveformCableMappingTool may be provided in kwargs
+    """
+
+    acc = ComponentAccumulator()
+    # tool = kwargs.get("WaveformCableMappingTool", WaveformCableMappingTool(flags))
+    # Probably need to figure this out!
+    dbInstance = kwargs.get("dbInstance", "TDAQ_OFL")
+    dbFolder = kwargs.get("dbFolder", "/WAVE/DAQ/CableMapping")
+    acc.merge(addFolders(flags, dbFolder, dbInstance, className="CondAttrListCollection"))
+    return acc
+
diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx
new file mode 100644
index 00000000..a846fe8d
--- /dev/null
+++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.cxx
@@ -0,0 +1,139 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and FASER collaborations
+*/
+
+/** @file WaveformCableMappingTool.cxx Implementation file for WaveformCableMappingTool.
+    @author Eric Torrence (05/02/22)
+    Based on FaserSCT_CableMappingTool
+*/
+
+#include "WaveformCableMappingTool.h"
+
+//----------------------------------------------------------------------
+WaveformCableMappingTool::WaveformCableMappingTool (const std::string& type, const std::string& name, const IInterface* parent) :
+  base_class(type, name, parent)
+{
+}
+
+//----------------------------------------------------------------------
+StatusCode 
+WaveformCableMappingTool::initialize() {
+  // Read Cond Handle Key
+
+  ATH_MSG_DEBUG("WaveformCableMappingTool::initialize()");
+
+  ATH_CHECK(m_readKey.initialize());
+
+  // Set up helpers
+  ATH_CHECK(detStore()->retrieve(m_ecalID, "EcalID"));
+  ATH_CHECK(detStore()->retrieve(m_vetoID, "VetoID"));
+  ATH_CHECK(detStore()->retrieve(m_triggerID, "TriggerID"));
+  ATH_CHECK(detStore()->retrieve(m_preshowerID, "PreshowerID"));
+
+  return StatusCode::SUCCESS;
+}
+
+//----------------------------------------------------------------------
+StatusCode
+WaveformCableMappingTool::finalize() {
+  // Print where you are
+  return StatusCode::SUCCESS;
+}
+
+//----------------------------------------------------------------------
+WaveformCableMap
+WaveformCableMappingTool::getCableMapping(const EventContext& ctx) const {
+  // Print where you are
+  ATH_MSG_DEBUG("in getCableMapping()");
+  WaveformCableMap mappingData;
+
+  // Read Cond Handle
+  SG::ReadCondHandle<CondAttrListCollection> readHandle{m_readKey, ctx};
+  const CondAttrListCollection* readCdo{*readHandle}; 
+  if (readCdo==nullptr) {
+    ATH_MSG_FATAL("Null pointer to the read conditions object");
+    return mappingData;
+  }
+  // Get the validitiy range
+  EventIDRange rangeW;
+  if (not readHandle.range(rangeW)) {
+    ATH_MSG_FATAL("Failed to retrieve validity range for " << readHandle.key());
+    return mappingData;
+  }
+  ATH_MSG_DEBUG("Size of CondAttrListCollection " << readHandle.fullKey() << " readCdo->size()= " << readCdo->size());
+  ATH_MSG_DEBUG("Range of input is " << rangeW);
+  
+  // Read mapping info
+  /*
+  std::string typeParam{"type"};
+  std::string stationParam{"station"};
+  std::string plateParam{"plate"};
+  std::string rowParam{"row"};
+  std::string moduleParam{"module"};
+  std::string pmtParam{"pmt"};
+  */
+  CondAttrListCollection::const_iterator attrList{readCdo->begin()};
+  CondAttrListCollection::const_iterator end{readCdo->end()};
+  // CondAttrListCollection doesn't support C++11 type loops, no generic 'begin'
+  for (; attrList!=end; ++attrList) {
+    // A CondAttrListCollection is a map of ChanNum and AttributeList
+    CondAttrListCollection::ChanNum channelNumber{attrList->first};
+    const CondAttrListCollection::AttributeList &payload{attrList->second};
+    if (payload.exists("type") and not payload["type"].isNull()) {
+
+      std::string det_type{payload["type"].data<std::string>()};
+
+      int stationVal{payload["station"].data<int>()};
+      int plateVal  {payload["plate"].data<int>()};
+      int rowVal    {payload["row"].data<int>()};
+      int moduleVal {payload["module"].data<int>()};
+      int pmtVal    {payload["pmt"].data<int>()};
+      Identifier identifier;
+
+      // Ugh, cant use switch statement with strings
+      // Must do this using an if ladder
+      if (det_type == "calo") {
+	identifier = m_ecalID->pmt_id(rowVal, moduleVal, pmtVal);
+      }
+      else if (det_type == "veto") {
+	identifier = m_vetoID->pmt_id(stationVal, plateVal, pmtVal);
+      }
+      else if (det_type == "trigger") {
+	identifier = m_triggerID->pmt_id(stationVal, plateVal, pmtVal);
+      }
+      else if (det_type == "preshower") {
+	identifier = m_preshowerID->pmt_id(stationVal, plateVal, pmtVal);
+      }
+      else if (det_type == "clock") {
+	// No valid identifiers for these
+	identifier = -1;
+      }
+      else if (det_type == "none") {
+	identifier = -1;
+      }
+      else {
+	ATH_MSG_WARNING("Detector type " << det_type << " not known for channel " << channelNumber << "!");
+	det_type = std::string("none");
+	identifier = -1;
+      }
+
+      ATH_MSG_DEBUG("Mapped digitizer channel " << channelNumber << " to " << det_type<< " ID: " << identifier);
+
+      mappingData.emplace(std::make_pair(channelNumber, std::make_pair(det_type, identifier)));
+
+    }
+
+  } // End of loop over attributes
+
+
+  return mappingData;
+} 
+
+WaveformCableMap
+WaveformCableMappingTool::getCableMapping(void) const {
+  const EventContext& ctx{Gaudi::Hive::currentContext()};
+  return getCableMapping(ctx);
+}
+
+
+
diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.h b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.h
new file mode 100644
index 00000000..19e6e6d9
--- /dev/null
+++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/WaveformCableMappingTool.h
@@ -0,0 +1,75 @@
+// -*- C++ -*-
+
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS and CERN collaborations
+*/
+
+/** @file WaveformCableMappingTool.h Header file for WaveformCableMappingTool.
+    @author Eric Torrence, 05/02/22
+    Based on FaserSCT_CableMappingTool
+*/
+
+// Multiple inclusion protection
+#ifndef WAVEFORM_CABLE_MAPPING_TOOL
+#define WAVEFORM_CABLE_MAPPING_TOOL
+
+// Include interface class
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "WaveformConditionsTools/IWaveformCableMappingTool.h"
+
+// Identifiers
+#include "Identifier/Identifier.h"
+#include "FaserCaloIdentifier/EcalID.h"
+#include "ScintIdentifier/VetoID.h"
+#include "ScintIdentifier/TriggerID.h"
+#include "ScintIdentifier/PreshowerID.h"
+
+// Include Athena stuff
+#include "AthenaPoolUtilities/CondAttrListCollection.h"
+#include "StoreGate/ReadCondHandleKey.h"
+
+#include "GaudiKernel/ICondSvc.h"
+#include "Gaudi/Property.h"
+
+// Include Gaudi classes
+#include "GaudiKernel/EventContext.h"
+
+/** This class contains a Tool that reads Waveform cable mapping data and makes it available to 
+    other algorithms. The current implementation reads the data from a COOL database. 
+*/
+
+class WaveformCableMappingTool: public extends<AthAlgTool, IWaveformCableMappingTool> {
+
+ public:
+  //----------Public Member Functions----------//
+  // Structors
+  WaveformCableMappingTool(const std::string& type, const std::string& name, const IInterface* parent); //!< Constructor
+  virtual ~WaveformCableMappingTool() = default; //!< Destructor
+
+  // Standard Gaudi functions
+  virtual StatusCode initialize() override; //!< Gaudi initialiser
+  virtual StatusCode finalize() override; //!< Gaudi finaliser
+
+  // Methods to return calibration data
+  // Map indexed by digitizer channel number
+  // Returns detector type "calo", "trigger", "veto", "preshower" and identifier 
+  virtual WaveformCableMap getCableMapping(const EventContext& ctx) const override;
+  virtual WaveformCableMap getCableMapping(void) const override;
+
+ private:
+  // Read Cond Handle
+  SG::ReadCondHandleKey<CondAttrListCollection> m_readKey{this, "ReadKey", "/WAVE/DAQ/CableMapping", "Key of input cabling folder"};
+
+  ServiceHandle<ICondSvc> m_condSvc{this, "CondSvc", "CondSvc"};
+
+  // ID helpers
+  const EcalID* m_ecalID{nullptr};
+  const VetoID* m_vetoID{nullptr};
+  const TriggerID* m_triggerID{nullptr};
+  const PreshowerID* m_preshowerID{nullptr};
+
+
+};
+
+//---------------------------------------------------------------------- 
+#endif // WAVEFORM_CABLE_MAPPING_TOOL
diff --git a/Waveform/WaveformConditions/WaveformConditionsTools/src/components/WaveformConditionsTools_entries.cxx b/Waveform/WaveformConditions/WaveformConditionsTools/src/components/WaveformConditionsTools_entries.cxx
new file mode 100644
index 00000000..1f6a41ac
--- /dev/null
+++ b/Waveform/WaveformConditions/WaveformConditionsTools/src/components/WaveformConditionsTools_entries.cxx
@@ -0,0 +1,3 @@
+#include "../WaveformCableMappingTool.h"
+
+DECLARE_COMPONENT( WaveformCableMappingTool )
-- 
GitLab