From b43b6264112dc3dc75aab24b05b7ac3e1a09f334 Mon Sep 17 00:00:00 2001
From: P-A Loizeau <p.-a.loizeau@gsi.de>
Date: Fri, 29 Nov 2024 18:31:09 +0100
Subject: [PATCH] Bugfix and Improve TS and MS Printout formaters

- Fix missing own header include for CbmFormatTsPrintout in the source file
- Replace std::endl with plain newline
- Add method to print a microslice descriptor help (dump description)
- Catch more low probablility error/crash cases (TS with no comp, Comps with no MS, ...)
- Add possibility to dump the MS for only a selected System ID type (default = all as before)
- Add possibility to dump only the first M microslices in each component for each TS (default = all as before)
---
 .../flestools/CbmFormatMsHeaderPrintout.cxx   |  37 ++++--
 .../flestools/CbmFormatMsHeaderPrintout.h     |   2 +
 .../utils/flestools/CbmFormatTsPrintout.cxx   | 108 +++++++++++-------
 .../utils/flestools/CbmFormatTsPrintout.h     |   7 +-
 4 files changed, 101 insertions(+), 53 deletions(-)

diff --git a/core/base/utils/flestools/CbmFormatMsHeaderPrintout.cxx b/core/base/utils/flestools/CbmFormatMsHeaderPrintout.cxx
index 153af59dee..2ce7081a1f 100644
--- a/core/base/utils/flestools/CbmFormatMsHeaderPrintout.cxx
+++ b/core/base/utils/flestools/CbmFormatMsHeaderPrintout.cxx
@@ -7,26 +7,41 @@
 std::string FormatMsHeaderPrintout(const fles::MicrosliceDescriptor& msDescriptor)
 {
   std::stringstream ss;
-  ss << "hi hv eqid flag si sv idx/start        crc      size     offset" << std::endl
+  ss << "hi hv eqid flag si sv idx/start        crc      size     offset"
+     << "\n"
      << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned int>(msDescriptor.hdr_id) << " "
      << std::setw(2) << static_cast<unsigned int>(msDescriptor.hdr_ver) << " " << std::setw(4) << msDescriptor.eq_id
      << " " << std::setw(4) << msDescriptor.flags << " " << std::setw(2)
      << static_cast<unsigned int>(msDescriptor.sys_id) << " " << std::setw(2)
      << static_cast<unsigned int>(msDescriptor.sys_ver) << " " << std::setw(16) << msDescriptor.idx << " "
      << std::setw(8) << msDescriptor.crc << " " << std::setw(8) << msDescriptor.size << " " << std::setw(16)
-     << msDescriptor.offset << std::dec << std::setfill(' ');
+     << msDescriptor.offset;
+  return ss.str();
+}
+
+std::string FormatMsHeaderHelp()
+{
+  std::stringstream ss;
+  ss << " Description of the microslice header format:\n"
+     << "==> hdr_id = Header format identifier (0xDD)                             \n"
+     << "|  ==> hdr_ver = Header format version (0x01)                            \n"
+     << "|  |   ==> eq_id = Equipment identifier                                  \n"
+     << "|  |   |    ==> flags = Status and error flags                           \n"
+     << "|  |   |    |   ==> sys_id = Subsystem identifier                        \n"
+     << "|  |   |    |   |  ==> sys_ver = Subsystem format/version                \n"
+     << "|  |   |    |   |  |      ==> idx = Microslice index / start time        \n"
+     << "|  |   |    |   |  |      |                                              \n"
+     << "hi hv eqid flag si sv idx/start        crc      size     offset          \n"
+     << "dd 01 3001 0000 30 03 180c1f234b1b6000 00000000 00000008 0000000000000080\n"
+     << "                                        |        |         |             \n"
+     << "        crc = CRC-32C of data content <==        |         |             \n"
+     << "              (Castagnoli polynomial)            |         |             \n"
+     << "                   size = Content size (bytes) <==         |             \n"
+     << "                 offset = Offset in event buffer (bytes) <==             \n";
   return ss.str();
 }
 
 std::ostream& operator<<(std::ostream& os, const fles::MicrosliceDescriptor& msDescriptor)
 {
-  char cPrevFill = os.fill('0');
-  return os << "hi hv eqid flag si sv idx/start        crc      size     offset" << std::endl
-            << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned int>(msDescriptor.hdr_id) << " "
-            << std::setw(2) << static_cast<unsigned int>(msDescriptor.hdr_ver) << " " << std::setw(4)
-            << msDescriptor.eq_id << " " << std::setw(4) << msDescriptor.flags << " " << std::setw(2)
-            << static_cast<unsigned int>(msDescriptor.sys_id) << " " << std::setw(2)
-            << static_cast<unsigned int>(msDescriptor.sys_ver) << " " << std::setw(16) << msDescriptor.idx << " "
-            << std::setw(8) << msDescriptor.crc << " " << std::setw(8) << msDescriptor.size << " " << std::setw(16)
-            << msDescriptor.offset << std::dec << std::setfill(cPrevFill);
+  return os << FormatMsHeaderPrintout(msDescriptor);
 }
diff --git a/core/base/utils/flestools/CbmFormatMsHeaderPrintout.h b/core/base/utils/flestools/CbmFormatMsHeaderPrintout.h
index 66cedb8699..0f750005ff 100644
--- a/core/base/utils/flestools/CbmFormatMsHeaderPrintout.h
+++ b/core/base/utils/flestools/CbmFormatMsHeaderPrintout.h
@@ -32,6 +32,8 @@
 
 std::string FormatMsHeaderPrintout(const fles::MicrosliceDescriptor& msDescriptor);
 
+std::string FormatMsHeaderHelp();
+
 std::ostream& operator<<(std::ostream& os, const fles::MicrosliceDescriptor& msDescriptor);
 
 #endif  // CbmFormatMsHeaderPrintout_H
diff --git a/core/base/utils/flestools/CbmFormatTsPrintout.cxx b/core/base/utils/flestools/CbmFormatTsPrintout.cxx
index e0da34c5fc..4fc696399c 100644
--- a/core/base/utils/flestools/CbmFormatTsPrintout.cxx
+++ b/core/base/utils/flestools/CbmFormatTsPrintout.cxx
@@ -2,6 +2,8 @@
    SPDX-License-Identifier: GPL-3.0-only
    Authors: Pierre-Alain Loizeau [committer] */
 
+#include "CbmFormatTsPrintout.h"
+
 #include "CbmFormatMsBufferPrintout.h"
 #include "CbmFormatMsHeaderPrintout.h"
 
@@ -46,72 +48,96 @@ std::string FormatTsHeaderPrintout(const fles::Timeslice& ts)
     else {
       ss << std::setw(3) << min_overlap;
     }  // else of if( min_overlap != max_overlap )
-    ss << " overlap) = " << std::setw(9) << total_num_microslices << std::endl;
+    ss << " overlap) = " << std::setw(9) << total_num_microslices << "\n";
     ss
       << "\tmicroslice size min/avg/max: " << std::setw(6) << min_microslice_size << " / " << std::fixed
       << std::setprecision(0) << std::setw(6)
       << (static_cast<double>(total_microslice_size) / total_num_microslices)
       //         << std::defaultfloat // commented out as not included in GCC 4.9.2 => restore defaults, probably not needed
       << std::setprecision(6)  // restore defaults, probably not needed
-      << " / " << std::setw(6) << max_microslice_size << " bytes" << std::endl;
+      << " / " << std::setw(6) << max_microslice_size << " bytes"
+      << "\n";
   }  // if( 0 != nbComps )
+  else {
+    ss << " = " << std::setw(9) << total_num_microslices << "\n";
+  }
 
   return ss.str();
 }
 
-std::string FormatTsPrintout(const fles::Timeslice& ts)
+std::string FormatTsContentPrintout(const fles::Timeslice& ts, std::underlying_type_t<fles::Subsystem> selSysId,
+                                    size_t nbMsPerComp)
 {
   std::stringstream ss;
-  ss << FormatTsHeaderPrintout(ts);
 
   size_t nbComps = ts.num_components();
   if (0 != nbComps) {
     size_t nbMicroslicesCore    = ts.num_core_microslices();
     size_t nbMicroslicesOverlap = ts.num_microslices(0) - ts.num_core_microslices();
-
-    for (size_t compIdx = 0; compIdx < nbComps; ++compIdx) {
-      ss << "Core Microslices for component " << std::setw(3) << compIdx << std::endl;
-      for (size_t msIdx = 0; msIdx < nbMicroslicesCore; ++msIdx) {
-        ss << ts.descriptor(compIdx, msIdx) << std::endl;
-        ss << FormatMsBufferPrintout(ts, compIdx, msIdx);
-        ss << "----------------------------------------------" << std::endl;
-      }  // for( size_t msIdx = 0; msIdx < nbMicroslicesCore; ++msIdx )
-      ss << "Overlap Microslices for component " << std::setw(3) << compIdx << std::endl;
-      for (size_t msIdx = 0; msIdx < nbMicroslicesOverlap; ++msIdx) {
-        ss << ts.descriptor(compIdx, msIdx + nbMicroslicesCore) << std::endl;
-        ss << FormatMsBufferPrintout(ts, compIdx, msIdx + nbMicroslicesCore);
-        ss << "----------------------------------------------" << std::endl;
-      }  // for( size_t msIdx = 0; msIdx < nbMicroslicesOverlap; ++msIdx )
-    }    // for( size_t comp = 0; comp < nbComps; ++comp )
+    size_t nbCoreMsToLoop       = nbMicroslicesCore;
+    size_t nbOverMsToLoop       = nbMicroslicesOverlap;
+    if (nbMsPerComp < nbMicroslicesCore) {
+      nbCoreMsToLoop = nbMsPerComp;
+      nbOverMsToLoop = 0;
+    }  // if (nbMsPerComp < nbMicroslicesCore)
+    else if (nbMsPerComp < nbMicroslicesCore + nbMicroslicesOverlap) {
+      nbOverMsToLoop = nbMicroslicesOverlap - (nbMsPerComp - nbMicroslicesCore);
+    }  // else if (nbMsPerComp < nbMicroslicesCore + nbMicroslicesOverlap)
+
+    if (0 < nbMicroslicesCore) {
+      for (size_t compIdx = 0; compIdx < nbComps; ++compIdx) {
+        if (0 < nbMicroslicesCore && 0x00 != selSysId && ts.descriptor(compIdx, 0).sys_id != selSysId) {
+          // FIXME: define "reserved/undefined" system ID somewhere (best in flesnet microslice descriptor header)
+          continue;
+        }  // if (0 < nbMicroslicesCore && 0x00 != selSysId && ts.descriptor(compIdx, 0).sys_id != selSysId)
+        // FIXME: Need safe accessor with range check for the cast, to be done in flesnet side
+        ss << "Component " << std::setw(3) << compIdx << ", Subsystem "
+           << fles::to_string(static_cast<fles::Subsystem>(ts.descriptor(compIdx, 0).sys_id)) << "\n";
+        if (0 < nbCoreMsToLoop) {
+          ss << "Core Microslices for component " << std::setw(3) << compIdx << " ("
+             << fles::to_string(static_cast<fles::Subsystem>(ts.descriptor(compIdx, 0).sys_id)) << ")"
+             << "\n";
+          for (size_t msIdx = 0; msIdx < nbCoreMsToLoop; ++msIdx) {
+            ss << ts.descriptor(compIdx, msIdx) << "\n";
+            ss << FormatMsBufferPrintout(ts, compIdx, msIdx);
+            ss << "----------------------------------------------"
+               << "\n";
+          }  // for( size_t msIdx = 0; msIdx < nbOverMsToLoop; ++msIdx )
+        }    // if (0 < nbCoreMsToLoop )
+        if (0 < nbOverMsToLoop) {
+          ss << "Overlap Microslices for component " << std::setw(3) << compIdx << " ("
+             << fles::to_string(static_cast<fles::Subsystem>(ts.descriptor(compIdx, 0).sys_id)) << ")"
+             << "\n";
+          for (size_t msIdx = 0; msIdx < nbOverMsToLoop; ++msIdx) {
+            ss << ts.descriptor(compIdx, msIdx + nbMicroslicesCore) << "\n";
+            ss << FormatMsBufferPrintout(ts, compIdx, msIdx + nbMicroslicesCore);
+            ss << "----------------------------------------------"
+               << "\n";
+          }  // for( size_t msIdx = 0; msIdx < nbOverMsToLoop; ++msIdx )
+        }    // if (0 < nbOverMsToLoop )
+        ss << "++++++++++++++++++++++++++++++++++++++++++++++"
+           << "\n";
+      }  // for( size_t comp = 0; comp < nbComps; ++comp )
+    }    // if (0 < nbMicroslicesCore) )
   }      // if( 0 != nbComps )
-  ss << "**********************************************" << std::endl;
+  ss << "**********************************************"
+     << "\n";
+
+  return ss.str();
+}
 
+std::string FormatTsPrintout(const fles::Timeslice& ts, std::underlying_type_t<fles::Subsystem> selSysId,
+                             size_t nbMsPerComp)
+{
+  std::stringstream ss;
+  ss << FormatTsHeaderPrintout(ts);
+  ss << FormatTsContentPrintout(ts, selSysId, nbMsPerComp);
   return ss.str();
 }
 
 std::ostream& operator<<(std::ostream& os, const fles::Timeslice& ts)
 {
   os << FormatTsHeaderPrintout(ts);
-
-  size_t nbComps              = ts.num_components();
-  size_t nbMicroslicesCore    = ts.num_core_microslices();
-  size_t nbMicroslicesOverlap = ts.num_microslices(0) - ts.num_core_microslices();
-
-  for (size_t compIdx = 0; compIdx < nbComps; ++compIdx) {
-    os << "Core Microslices for component " << std::setw(3) << compIdx << std::endl;
-    for (size_t msIdx = 0; msIdx < nbMicroslicesCore; ++msIdx) {
-      os << ts.descriptor(compIdx, msIdx) << std::endl;
-      os << FormatMsBufferPrintout(ts, compIdx, msIdx);
-      os << "----------------------------------------------" << std::endl;
-    }  // for( size_t msIdx = 0; msIdx < nbMicroslicesCore; ++msIdx )
-    os << "Overlap Microslices for component " << std::setw(3) << compIdx << std::endl;
-    for (size_t msIdx = 0; msIdx < nbMicroslicesOverlap; ++msIdx) {
-      os << ts.descriptor(compIdx, msIdx + nbMicroslicesCore) << std::endl;
-      os << FormatMsBufferPrintout(ts, compIdx, msIdx + nbMicroslicesCore);
-      os << "----------------------------------------------" << std::endl;
-    }  // for( size_t msIdx = 0; msIdx < nbMicroslicesOverlap; ++msIdx )
-  }    // for( size_t comp = 0; comp < nbComps; ++comp )
-  os << "**********************************************" << std::endl;
-
+  os << FormatTsContentPrintout(ts);
   return os;
 }
diff --git a/core/base/utils/flestools/CbmFormatTsPrintout.h b/core/base/utils/flestools/CbmFormatTsPrintout.h
index 8ae3e34e4d..33c947266d 100644
--- a/core/base/utils/flestools/CbmFormatTsPrintout.h
+++ b/core/base/utils/flestools/CbmFormatTsPrintout.h
@@ -14,6 +14,7 @@
 
 #include "Timeslice.hpp"
 
+#include <cstdint>  // For SIZE_MAX
 #include <iomanip>
 #include <iostream>
 #include <sstream>
@@ -24,7 +25,11 @@
 
 std::string FormatTsHeaderPrintout(const fles::Timeslice& ts);
 
-std::string FormatTsPrintout(const fles::Timeslice& ts);
+std::string FormatTsContentPrintout(const fles::Timeslice& ts, std::underlying_type_t<fles::Subsystem> selSysId = 0x00,
+                                    size_t nbMsPerComp = SIZE_MAX);
+
+std::string FormatTsPrintout(const fles::Timeslice& ts, std::underlying_type_t<fles::Subsystem> SelSysId = 0x00,
+                             size_t nbMsPerComp = SIZE_MAX);
 
 std::ostream& operator<<(std::ostream& os, const fles::Timeslice& ts);
 
-- 
GitLab