From 4fa0d1f693fe56e23282e1ef5a5027ed533a58c2 Mon Sep 17 00:00:00 2001
From: Rosen Matev <rosen.matev@cern.ch>
Date: Tue, 9 Apr 2024 18:14:37 +0200
Subject: [PATCH] Fix ODIN::CalibrationTypes for Run 3 and usage

---
 Event/DAQEvent/include/Event/ODIN.h | 25 ++++++++++++++++------
 Event/DAQEvent/src/ODIN.cpp         | 32 ++++++++++++++---------------
 2 files changed, 34 insertions(+), 23 deletions(-)

diff --git a/Event/DAQEvent/include/Event/ODIN.h b/Event/DAQEvent/include/Event/ODIN.h
index 80bfdf71b40..f520896309e 100644
--- a/Event/DAQEvent/include/Event/ODIN.h
+++ b/Event/DAQEvent/include/Event/ODIN.h
@@ -139,10 +139,10 @@ namespace LHCb {
 
       /// Calibration types
       enum class CalibrationTypes : std::uint8_t { //
-        A = 0,
-        B = 1,
-        C = 2,
-        D = 3
+        A = 0x1,
+        B = 0x2,
+        C = 0x4,
+        D = 0x8
       };
 
       /// BX Types
@@ -345,11 +345,24 @@ namespace LHCb {
       [[nodiscard]] constexpr ACCEL_TARGET_SPEC auto calibrationType() const {
         return details::get_bits<CalibrationTypeSize, CalibrationTypeOffset>( data );
       }
+      [[nodiscard]] constexpr bool calibrationTypeBit( CalibrationTypes mask ) const {
+        assert( __builtin_popcount( static_cast<std::uint8_t>( mask ) ) == 1 ); // FIXME: C++20 use std::popcount
+                                                                                // instead
+        return calibrationType() & static_cast<std::uint8_t>( mask );
+      }
       constexpr void setCalibrationType( std::uint8_t value ) {
         details::set_bits<CalibrationTypeSize, CalibrationTypeOffset>( data, value );
       }
-      constexpr void setCalibrationType( CalibrationTypes value ) {
-        setCalibrationType( static_cast<std::uint8_t>( value ) );
+      constexpr void setCalibrationTypeBit( CalibrationTypes mask, bool value ) {
+        assert( __builtin_popcount( static_cast<std::uint8_t>( mask ) ) == 1 ); // FIXME: C++20 use std::popcount
+                                                                                // instead
+        std::uint8_t newCalibrationType = calibrationType();
+        if ( value ) {
+          newCalibrationType |= static_cast<std::uint8_t>( mask );
+        } else {
+          newCalibrationType &= ~static_cast<std::uint8_t>( mask );
+        }
+        setCalibrationType( newCalibrationType );
       }
 
       [[nodiscard]] constexpr ACCEL_TARGET_SPEC auto orbitNumber() const {
diff --git a/Event/DAQEvent/src/ODIN.cpp b/Event/DAQEvent/src/ODIN.cpp
index ea6405fb22c..c2b1c221a82 100644
--- a/Event/DAQEvent/src/ODIN.cpp
+++ b/Event/DAQEvent/src/ODIN.cpp
@@ -39,7 +39,8 @@ namespace LHCb::ODINImplementation::v7_standalone {
     odin.setBunchId( get_bits<12, 8 * 32 + 0>( buffer ) );
     odin.setTimeAlignmentEventIndex( get_bits<3, 8 * 32 + 12>( buffer ) );
     odin.setTriggerType( get_bits<3, 8 * 32 + 16>( buffer ) );
-    odin.setCalibrationType( get_bits<2, 8 * 32 + 19>( buffer ) );
+    // calibration type changed from value (x) to bitmask (1 << x)
+    odin.setCalibrationType( 1 << get_bits<2, 8 * 32 + 19>( buffer ) );
     odin.setBunchCrossingType( static_cast<ODIN::BXTypes>( get_bits<2, 8 * 32 + 22>( buffer ) ) );
 
     return odin;
@@ -65,25 +66,22 @@ namespace LHCb::ODINImplementation::v7_standalone {
     set_bits<3, 8 * 32 + 12>( buffer, timeAlignmentEventIndex() );
     assert( triggerType() <= 7 ); // change of width between v6 and v7
     set_bits<3, 8 * 32 + 16>( buffer, triggerType() );
-    assert( calibrationType() <= 3 ); // change of width between v6 and v7
-    set_bits<2, 8 * 32 + 19>( buffer, calibrationType() );
+    // change of width between v6 and v7
+    std::uint8_t calibrationTypeV6 = 0;
+    if ( calibrationTypeBit( CalibrationTypes::A ) ) {
+      calibrationTypeV6 = 0;
+    } else if ( calibrationTypeBit( CalibrationTypes::B ) ) {
+      calibrationTypeV6 = 1;
+    } else if ( calibrationTypeBit( CalibrationTypes::C ) ) {
+      calibrationTypeV6 = 2;
+    } else if ( calibrationTypeBit( CalibrationTypes::D ) ) {
+      calibrationTypeV6 = 3;
+    }
+    set_bits<2, 8 * 32 + 19>( buffer, calibrationTypeV6 );
     set_bits<2, 8 * 32 + 22>( buffer, static_cast<std::uint16_t>( bunchCrossingType() ) );
   }
 
-  std::ostream& operator<<( std::ostream& s, ODIN::CalibrationTypes e ) {
-    switch ( e ) {
-    case LHCb::ODIN::CalibrationTypes::A:
-      return s << "A";
-    case LHCb::ODIN::CalibrationTypes::B:
-      return s << "B";
-    case LHCb::ODIN::CalibrationTypes::C:
-      return s << "C";
-    case LHCb::ODIN::CalibrationTypes::D:
-      return s << "D";
-    default:
-      return s << "ERROR unknown value " << static_cast<int>( e ) << " for enum LHCb::ODIN::CalibrationTypes";
-    }
-  }
+  std::ostream& operator<<( std::ostream& s, ODIN::CalibrationTypes e ) { return s << static_cast<int>( e ); }
 
   std::ostream& operator<<( std::ostream& s, ODIN::BXTypes e ) {
     switch ( e ) {
-- 
GitLab