Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a0acf33
Adding TablePlugin for DB info dump
jicampos Jan 9, 2026
3d703aa
Adding comment
jicampos Jan 15, 2026
751012a
Clangify
jicampos Jan 15, 2026
426e4da
Writing offline tables to file and adding to JSON blob
jicampos Jan 15, 2026
1a9855d
Adding nominal channel map and loopup in CSV dump
jicampos Jan 15, 2026
c7c75e2
Merge branch 'develop' into jcampos/AddChannelStatus
jicampos Jan 15, 2026
019e9e7
Added ChannelMap table logic, removed nominal.txt reads.
giro94 Jan 20, 2026
3d33780
Swapped channel map order to new standard. Fixed some bracket indenta…
giro94 Jan 23, 2026
d0949d3
fix whitespace, clangify
giro94 Jan 23, 2026
0cc0aaf
Merge branch 'develop' into jcampos/AddChannelStatus
rrivera747 Jan 23, 2026
d6f48c9
Initial plan
Copilot Jan 23, 2026
7ef7f2e
Initial plan
Copilot Jan 23, 2026
39c4454
Replace simple return with __SS__ and __SS_THROW__ error handling, ad…
Copilot Jan 23, 2026
eb4ed03
Apply suggestion from @Copilot
rrivera747 Jan 23, 2026
cca443e
Create and use CHANNELS_PER_BOARD constant
Copilot Jan 23, 2026
9fc9a2b
Final update: all feedback addressed
Copilot Jan 23, 2026
58f34f4
Complete CHANNELS_PER_BOARD refactoring
Copilot Jan 23, 2026
b0ccb32
Merge branch 'jcampos/AddChannelStatus' into copilot/sub-pr-49
rrivera747 Jan 23, 2026
cf9a6d9
Merge pull request #51 from Mu2e/copilot/sub-pr-49
rrivera747 Jan 23, 2026
c8fb0f0
Initial plan
Copilot Jan 23, 2026
31621c9
Apply suggestions from code review
rrivera747 Jan 23, 2026
5dd8b4c
Rename colStatus_ to colBoardId_ in ColChannelThreshold struct
Copilot Jan 23, 2026
cd1036d
Update otsdaq-mu2e-calorimeter/TablePlugins/SubsystemCalorimeterParam…
rrivera747 Jan 23, 2026
ec0e7a8
Update otsdaq-mu2e-calorimeter/TablePlugins/SubsystemCalorimeterParam…
rrivera747 Jan 23, 2026
9297f32
Merge branch 'jcampos/AddChannelStatus' into copilot/sub-pr-49-again
rrivera747 Jan 23, 2026
ac0a29d
Merge pull request #52 from Mu2e/copilot/sub-pr-49-again
rrivera747 Jan 23, 2026
bd25651
Update otsdaq-mu2e-calorimeter/TablePlugins/SubsystemCalorimeterParam…
giro94 Jan 26, 2026
a21a6cc
Initial plan
Copilot Jan 26, 2026
36a3f1d
Replace hardcoded 20 with mu2e::CaloConst::_nChPerDIRAC
Copilot Jan 26, 2026
921a82c
Merge pull request #54 from Mu2e/copilot/sub-pr-49
rrivera747 Jan 29, 2026
e9205ca
Merge branch 'jcampos/AddChannelStatus' into copilot/sub-pr-49-yet-again
rrivera747 Jan 29, 2026
07ea18d
Merge pull request #56 from Mu2e/copilot/sub-pr-49-yet-again
rrivera747 Jan 29, 2026
5cc0c5f
Using caloconst constants instead of hardcoded 20 for channels in boa…
giro94 Jan 29, 2026
e941230
Removed unused function
giro94 Jan 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions otsdaq-mu2e-calorimeter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
add_subdirectory(FEInterfaces)
add_subdirectory(Generators)
add_subdirectory(ArtModules)
add_subdirectory(TablePlugins)
12 changes: 12 additions & 0 deletions otsdaq-mu2e-calorimeter/TablePlugins/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

include(otsdaq::table)

cet_build_plugin(SubsystemCalorimeterParametersTable otsdaq::table LIBRARIES REG
otsdaq::SlowControlsTableBase
otsdaq::XDAQContextTable
)



Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line contains trailing whitespace, which may violate project coding standards. Consider removing it.

Suggested change
include(otsdaq::table)
cet_build_plugin(SubsystemCalorimeterParametersTable otsdaq::table LIBRARIES REG
otsdaq::SlowControlsTableBase
otsdaq::XDAQContextTable
)
include(otsdaq::table)
cet_build_plugin(SubsystemCalorimeterParametersTable otsdaq::table LIBRARIES REG
otsdaq::SlowControlsTableBase
otsdaq::XDAQContextTable
)

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line contains trailing whitespace, which may violate project coding standards. Consider removing it.

Suggested change
include(otsdaq::table)
cet_build_plugin(SubsystemCalorimeterParametersTable otsdaq::table LIBRARIES REG
otsdaq::SlowControlsTableBase
otsdaq::XDAQContextTable
)
include(otsdaq::table)
cet_build_plugin(SubsystemCalorimeterParametersTable otsdaq::table LIBRARIES REG
otsdaq::SlowControlsTableBase
otsdaq::XDAQContextTable
)

Copilot uses AI. Check for mistakes.
install_headers()
install_source()
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#ifndef _ots_SubsystemCalorimeterParametersTable_h_
#define _ots_SubsystemCalorimeterParametersTable_h_

#include "otsdaq/ConfigurationInterface/ConfigurationManager.h"
#include "otsdaq/TableCore/TableBase.h"

namespace ots {
class SubsystemCalorimeterParametersTable : public TableBase {
// clang-format off

public:
SubsystemCalorimeterParametersTable (void);
virtual ~SubsystemCalorimeterParametersTable (void);

// Methods
void init (ConfigurationManager* configManager) override;

virtual std::string getStructureAsJSON (const ConfigurationManager* configManager) override;

virtual std::string getChannelMapAndCSVFormat (const ConfigurationManager* configManager, const std::string& OfflineCxxClassName);

virtual std::string getStatusTableInCSVFormat (const ConfigurationManager* configManager, const std::string& OfflineCxxClassName);

void generateOfflineTableMap (const ConfigurationManager* configManager);

void loadNominalChannelMap ();

bool isFirstAppInContext_ = false;

private:

const static std::string PATH_TO_TRIGGER_OFFLINE_DB;
const static std::string CHANNEL_STATUS_TABLE;
const static std::string CHANNEL_MAP_TABLE;
const static uint32_t CHANNELS_PER_BOARD = 20;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we have mu2e::CaloConst::_nChPerDIRAC defined in Offline, if you prefer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot use mu2e::CaloConst::_nChPerDIRAC for the 20


std::map<std::string, std::string> mapOfflineTables_;
std::map<uint16_t, uint16_t> mapChannels_;

// Column names
struct ColParameters // Calorimeter subsystem top level
{
// Incomplete list
std::string const colLinkToFETypeTable = "LinkToChannelStatusTableInfo";
std::string const colLinkToSlowControlsChannelTable_ = "LinkToChannelThresholdTableInfo";
} ColParameters;

struct ColChannelMap // LinkToChannelMapTableInfo
{
std::string const offlineId_ = "offID";
std::string const onlineId_ = "FEEchan";
} ColChannelMap;

struct ColChannelStatus // LinkToChannelStatusTableInfo
{
std::string const colBoardId_ = "BoardID";
std::string const colStatus_ = "Status";
} ColChannelStatus;

struct ColChannelThreshold // LinkToChannelThresholdTableInfo
{
std::string const colStatus_ = "BoardID";
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the ColChannelThreshold struct, the field colStatus_ is named "BoardID" which appears to be a copy-paste error from ColChannelStatus. The field name suggests it should be related to status, but the value is "BoardID". This inconsistency should be resolved - either rename the field or correct the value.

Suggested change
std::string const colStatus_ = "BoardID";
std::string const colStatus_ = "Status";

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot change to colBoardId_ = "BoardID";

std::string const colROCGroupID_ = "Thresholds";
std::string const colROCInterfacePluginName_= "Baseline";
std::string const colLinkToSlowControlsChannelTable_ = "LinkToSlowControlsChannelTable";
} ColChannelThreshold;

// clang-format on
};
} // namespace ots
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#include "otsdaq-mu2e-calorimeter/TablePlugins/SubsystemCalorimeterParametersTable.h"
#include "otsdaq/Macros/TablePluginMacros.h" //for DEFINE_OTS_TABLE

#include "otsdaq/TablePlugins/XDAQContextTable/XDAQContextTable.h"

#include <sys/stat.h> //for mkdir
#include <fstream>
#include <iostream>

using namespace ots;

const std::string SubsystemCalorimeterParametersTable::PATH_TO_TRIGGER_OFFLINE_DB = getenv("PATH_TO_TRIGGER_OFFLINE_DB") ? getenv("PATH_TO_TRIGGER_OFFLINE_DB") : "";
const std::string SubsystemCalorimeterParametersTable::CHANNEL_MAP_TABLE = "SubsystemCalorimeterMapTable";
const std::string SubsystemCalorimeterParametersTable::CHANNEL_STATUS_TABLE = "SubsystemCalorimeterStatusTable";

//==============================================================================
SubsystemCalorimeterParametersTable::SubsystemCalorimeterParametersTable(void) : TableBase("SubsystemCalorimeterParametersTable") {}

//==============================================================================
SubsystemCalorimeterParametersTable::~SubsystemCalorimeterParametersTable(void) {}

//==============================================================================
/// init
/// generate calo specific files needed by the online trigger and save them in the filesystem 'offline' db
void SubsystemCalorimeterParametersTable::init(ConfigurationManager* configManager) {
// use isFirstAppInContext to only run once per context, for example to avoid
// generating files on local disk multiple times.
bool isFirstAppInContext_ = configManager->isOwnerFirstAppInContext();

__COUTV__(isFirstAppInContext_);
if(!isFirstAppInContext_)
return;

__COUTV__(SubsystemCalorimeterParametersTable::PATH_TO_TRIGGER_OFFLINE_DB);
if(SubsystemCalorimeterParametersTable::PATH_TO_TRIGGER_OFFLINE_DB.size() == 0)
return;

__COUT__ << "*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*" << __E__;
__COUT__ << configManager->__SELF_NODE__ << __E__;

generateOfflineTableMap(configManager);

for(const auto& offlineTable : mapOfflineTables_) {
std::string offlineTableFileName = PATH_TO_TRIGGER_OFFLINE_DB + "/" + offlineTable.first + ".txt";

try {
std::ofstream out(offlineTableFileName);
if(!out) {
__COUTT__ << "Failed to open file: " << offlineTableFileName;
return;
}
out << offlineTable.second;
out.close();
} catch(const std::exception& e) {
__COUT__ << "Failed to write offline table " << offlineTable.first << " to file.";
__COUT__ << e.what() << __E__;
}
}

} // end init()

//==============================================================================
void SubsystemCalorimeterParametersTable::generateOfflineTableMap(const ConfigurationManager* configManager) {
mapOfflineTables_.clear();
mapOfflineTables_["CalChannelMap"] = getChannelMapAndCSVFormat(configManager, "CalChannelMap");
__COUTT__ << mapOfflineTables_["CalChannelMap"] << __E__;
mapOfflineTables_["CalChannelStatus"] = getStatusTableInCSVFormat(configManager, "CalChannelStatus");
__COUTT__ << mapOfflineTables_["CalChannelStatus"] << __E__;
} // end generateOfflineTableMap()

//==============================================================================
std::string SubsystemCalorimeterParametersTable::getChannelMapAndCSVFormat(const ConfigurationManager* configManager, const std::string& OfflineCxxClassName) {
mapChannels_.clear();

std::stringstream OfflineTable;
OfflineTable << "TABLE " << OfflineCxxClassName << __E__;
std::vector<std::pair<std::string, ConfigurationTree>> channelMapRecords = configManager->getNode(SubsystemCalorimeterParametersTable::CHANNEL_MAP_TABLE).getChildren();

// start main fe/DTC record loop
for(auto& channelMapPair : channelMapRecords) {
uint16_t onlineID = channelMapPair.second.getNode(ColChannelMap.onlineId_).getValue<uint16_t>();
uint16_t offlineID = channelMapPair.second.getNode(ColChannelMap.offlineId_).getValue<uint16_t>();
mapChannels_[onlineID] = offlineID;

OfflineTable << onlineID << "," << offlineID << "\n";
}
return OfflineTable.str();
} // end getChannelMapAndCSVFormat()

//==============================================================================
std::string SubsystemCalorimeterParametersTable::getStatusTableInCSVFormat(const ConfigurationManager* configManager, const std::string& OfflineCxxClassName) {
std::stringstream OfflineTable;
OfflineTable << "TABLE " << OfflineCxxClassName << __E__;
std::vector<std::pair<std::string, ConfigurationTree>> channelStatusRecords = configManager->getNode(SubsystemCalorimeterParametersTable::CHANNEL_STATUS_TABLE).getChildren();

// start main fe/DTC record loop
for(auto& channelStatusPair : channelStatusRecords) {
uint32_t boardID = channelStatusPair.second.getNode(ColChannelStatus.colBoardId_).getValue<uint32_t>();
ConfigurationTree::BitMap<std::string> bitmap = channelStatusPair.second.getNode(ColChannelStatus.colStatus_).getValueAsBitMap();

// assume data is 1-dimensional
for(uint32_t j = 0; j < bitmap.numberOfColumns(0); j++) {
OfflineTable << mapChannels_.at(boardID * CHANNELS_PER_BOARD + j) << ", ";
OfflineTable << ((bitmap.get(0, j).size() == 0) ? "0" : bitmap.get(0, j));
OfflineTable << ((j + 1 == bitmap.numberOfColumns(0)) ? "" : "\n");
}
}
return OfflineTable.str();
} // end getStatusTableInCSVFormat()

//==============================================================================
// return status structures
std::string SubsystemCalorimeterParametersTable::getStructureAsJSON(const ConfigurationManager* cfgMgr) {
// Don't generate maps if done already in init()
if(mapOfflineTables_.size() == 0)
generateOfflineTableMap(cfgMgr);

std::vector<std::pair<std::string, ConfigurationTree>> channelStatusRecords = cfgMgr->getNode(SubsystemCalorimeterParametersTable::CHANNEL_STATUS_TABLE).getChildren();

std::stringstream outstream;

outstream << "{";

// Write all cat-3 tables converted from MongoDB
outstream << "\t\"cat3\": {" << __E__;
std::map<std::string, std::string>::iterator it;
for(it = mapOfflineTables_.begin(); it != mapOfflineTables_.end(); ++it) {
outstream << "\"" << it->first << "\":" << it->second;
outstream << (std::next(it) == mapOfflineTables_.end() ? "" : ",");
}
outstream << "},";

// Write any desired table in a custom format for user-friendly quick reading
outstream << "\t\"custom\": ";
outstream << "{" << __E__;
outstream << "\t\"Number of rows\": " << channelStatusRecords.size() << "," << __E__;
outstream << "\t[" << __E__;

uint16_t statusPairIdx = 0;
for(auto& channelStatusPair : channelStatusRecords) {
uint16_t boardID = channelStatusPair.second.getNode(ColChannelStatus.colBoardId_).getValue<uint16_t>();
ConfigurationTree::BitMap<std::string> bitmap = channelStatusPair.second.getNode(ColChannelStatus.colStatus_).getValueAsBitMap();
statusPairIdx++;

outstream << "\t\t{" << __E__;
outstream << "\t\t\"BoardID\": " << boardID << "," << __E__;
outstream << "\t\t\"Rows\": " << bitmap.numberOfRows() << "," << __E__;
outstream << "\t\t\"BitMap\": [";

// assume data is 1-dimensional
for(uint32_t j = 0; j < bitmap.numberOfColumns(0); j++) {
outstream << ((bitmap.get(0, j).size() == 0) ? "0" : bitmap.get(0, j));
outstream << ((j + 1 == bitmap.numberOfColumns(0)) ? "" : ", ");
}
outstream << "]" << __E__;
outstream << "\t\t}" << (statusPairIdx == channelStatusRecords.size() ? "" : ",") << __E__;
}

outstream << "\t]" << __E__;
outstream << "}"; // close custom blob
outstream << "}"; // close full blob
return outstream.str();
} // end getStructureAsJSON()

DEFINE_OTS_TABLE(SubsystemCalorimeterParametersTable)