25#include <unordered_map>
48namespace fs = std::filesystem;
57const std::unordered_map<CDBType, o2::header::DataDescription>
CDBDescMap{
86 LOGP(info,
"endOfStream");
97 struct membuf : std::streambuf {
98 membuf(
char* base, std::ptrdiff_t
n)
100 this->setg(base, base, base +
n);
105 static constexpr std::string_view CalDetNames =
"ITfraction,ITexpLambda,ThresholdMap,Pedestals,CMkValues";
106 static constexpr int NCalDets = 5;
108 static constexpr std::string_view CRUConfigName =
"CRUdata";
109 static constexpr std::string_view TagInfoName =
"TagInfo";
110 static constexpr std::string_view RunInfoFileName =
"TPCRunInfo.txt";
113 CDBStorage mCDBStorage;
115 FEEConfig mFEEConfig;
116 std::unordered_map<std::string, std::vector<char>> mDataBuffer;
117 std::unordered_map<std::string, long> mDataBufferTimes;
118 std::bitset<NCalDets> mFEEPadDataReceived;
119 bool mCRUConfigReceived =
false;
120 bool mDumpToRootFile =
false;
121 bool mDumpToTextFiles =
false;
122 bool mReadFromRootFile =
false;
123 bool mDontWriteRunInfo =
false;
125 void updateRunInfo(gsl::span<const char> configBuff);
126 void fillFEEPad(std::string_view configFileName, gsl::span<const char> configBuff,
bool update);
127 void fillCRUConfig(gsl::span<const char> configBuff,
bool update);
128 void dumpToTextFile(std::string_view configFileName, gsl::span<const char> configBuff, std::string_view tagNames);
129 bool loadFEEConfig(
int tag);
136 mDumpToTextFiles = ic.
options().
get<
bool>(
"dump-to-text-files");
137 mDumpToRootFile = ic.
options().
get<
bool>(
"dump-to-root-file");
138 mReadFromRootFile = ic.
options().
get<
bool>(
"read-from-root-file");
139 mDontWriteRunInfo = ic.
options().
get<
bool>(
"dont-write-run-info");
141 const auto calDetNamesVec =
Str::tokenize(CalDetNames.data(),
',');
142 assert(NCalDets == calDetNamesVec.size());
144 for (
const auto&
name : calDetNamesVec) {
150 mCDBStorage.
setResponsible(
"Jens Wiechula (jens.wiechula@cern.ch)");
156 auto configBuff = pc.
inputs().
get<gsl::span<char>>(
"inputConfig");
157 auto configFileName = pc.
inputs().
get<std::string>(
"inputConfigFileName");
159 LOG(info) <<
"received input file " << configFileName <<
" of size " << configBuff.size();
162 if (configFileName == RunInfoFileName) {
163 updateRunInfo(configBuff);
165 std::string objName = fs::path(configFileName).stem().c_str();
166 objName = objName.substr(3, objName.size());
168 auto& dataVec = mDataBuffer[objName];
169 auto& objTime = mDataBufferTimes[objName];
170 if (dataVec.size()) {
171 LOGP(warning,
"Another object with name {} was already received before: {}, now: {}, old object will be overwritten", objName, objTime, creation);
174 dataVec.insert(dataVec.begin(), configBuff.begin(), configBuff.end());
177 if (objName == TagInfoName) {
183void DCSConfigDevice::updateRunInfo(gsl::span<const char> configBuff)
185 const std::string line(configBuff.data(), configBuff.size());
187 const std::string_view runInfoConf(
"Run number;SOX;Tag number;Run type");
188 if (
data.size() != 4) {
189 LOGP(error,
"{} has wrong format: {}, expected: {}, not writing RunInformation to CCDB", RunInfoFileName, line, runInfoConf);
192 const auto tagString =
data[2];
197 std::map<std::string, std::string> md;
199 md[
"RunType"] =
data[3];
201 if (headers.find(
"ETag") != headers.end()) {
202 auto etag = headers.at(
"ETag");
203 etag.erase(std::remove(etag.begin(), etag.end(),
'"'), etag.end());
206 LOGP(error,
"No ETag found for Tag {}, not setting Redirect in RunInfo", tagString);
209 const long startValRCT = std::stol(
data[1]);
210 const long endValRCT = startValRCT + 48l * 60l * 60l * 1000l;
211 if (!mDontWriteRunInfo) {
219 std::string mdInfo =
"[";
220 for (
const auto& [
key,
val] : md) {
221 mdInfo += fmt::format(
"{} = {}, ",
key,
val);
230 std::map<std::string, std::string> md = mCDBStorage.
getMetaData();
237 LOGP(info,
"Sending object {} / {} of size {} bytes, valid for {} : {} ",
w.getPath(),
w.getFileName(),
image->size(),
w.getStartValidityTimestamp(),
w.getEndValidityTimestamp());
241 mFEEPadDataReceived.reset();
242 mCRUConfigReceived =
false;
244 if (mDumpToRootFile) {
251void DCSConfigDevice::fillFEEPad(std::string_view configFileName, gsl::span<const char> configBuff,
bool update)
253 auto& calPad = mFEEConfig.
padMaps[configFileName.data()];
255 if (configFileName ==
"ITfraction") {
256 nLines = cru_calib_helpers::fillCalPad<0>(calPad, configBuff);
257 mFEEPadDataReceived.set(0);
258 }
else if (configFileName ==
"ITexpLambda") {
259 nLines = cru_calib_helpers::fillCalPad<0>(calPad, configBuff);
260 mFEEPadDataReceived.set(1);
261 }
else if (configFileName ==
"ThresholdMap") {
262 nLines = cru_calib_helpers::fillCalPad<2>(calPad, configBuff);
263 mFEEPadDataReceived.set(2);
264 }
else if (configFileName ==
"Pedestals") {
265 nLines = cru_calib_helpers::fillCalPad<2>(calPad, configBuff);
266 mFEEPadDataReceived.set(3);
267 }
else if (configFileName ==
"CMkValues") {
268 nLines = cru_calib_helpers::fillCalPad<0>(calPad, configBuff);
269 mFEEPadDataReceived.set(4);
272 if (!update && (nLines != NLinksTotal)) {
273 LOGP(error,
"Full FEEConfig expected, but only {} / {} lines read for object {}", nLines, NLinksTotal, configFileName);
275 LOGP(info,
"updating CalDet object {} for {} links", configFileName, nLines);
279void DCSConfigDevice::fillCRUConfig(gsl::span<const char> configBuff,
bool update)
281 membuf sbuf((
char*)configBuff.data(), configBuff.size());
282 std::istream in(&sbuf);
286 while (std::getline(in, line)) {
287 const auto cru = std::stoi(line.substr(0, line.find_first_of(
' ')));
289 LOGP(error,
"unexpected CRU number {} in line {}", cru, line);
293 const std::string cruData(line.substr(line.find_first_of(
' ') + 1, line.size()));
295 auto& cruConfig = mFEEConfig.
cruConfig[cru];
296 if (cruConfig.setValues(cruData)) {
302 LOGP(error,
"Full FEEConfig expected, but only {} / {} lines read for CRUConfig", nLines, (
int)
CRU::MaxCRU);
304 LOGP(info,
"updating CRUConfig for {} crus", nLines);
306 mCRUConfigReceived =
true;
309void DCSConfigDevice::dumpToTextFile(std::string_view objName, gsl::span<const char> configBuff, std::string_view tagNames)
311 const auto now = std::chrono::system_clock::now();
312 const long timeStart = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()).count();
314 const auto outputFileName = fmt::format(
"TPC{}.{}.{}.txt", objName, tagNames, timeStart);
316 std::ofstream outFile(outputFileName);
317 outFile.write(configBuff.data(), configBuff.size());
323 const auto tagInfos =
readTagInfos(mDataBuffer.at(TagInfoName.data()));
324 std::string tagNames;
326 for (
const auto& tagInfo : tagInfos) {
327 if (tagNames.size()) {
331 LOGP(info,
"Updating TPC FEE config for tag {}", tagInfo.tag);
332 const auto update = loadFEEConfig(tagInfo.tag);
334 for (
const auto& [objName, configBuff] : mDataBuffer) {
335 if (CalDetNames.find(objName) != std::string_view::npos) {
336 fillFEEPad(objName, configBuff, update);
337 }
else if (objName == CRUConfigName) {
338 fillCRUConfig(configBuff, update);
341 if (!update && ((mFEEPadDataReceived.count() != NCalDets) || !mCRUConfigReceived)) {
342 std::string errorMessage;
343 if (mFEEPadDataReceived.count() != NCalDets) {
344 errorMessage = fmt::format(
"not all CalDet objects received: {} ({})", mFEEPadDataReceived.to_string(), CalDetNames);
346 if (!mCRUConfigReceived) {
347 if (errorMessage.size()) {
348 errorMessage +=
" and ";
350 errorMessage +=
"CRUConfig not reveived";
353 LOGP(error,
"Full FEEConfig expected, but {}", errorMessage);
355 updateCCDB(outputs, tagInfo);
358 if (mDumpToTextFiles) {
359 for (
const auto& [objName, configBuff] : mDataBuffer) {
360 dumpToTextFile(objName, configBuff, tagNames);
369 const auto now = std::chrono::system_clock::now();
370 const long timeStart = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
371 const auto outputFileName = fmt::format(
"TPCFEEConfig.{}.{}.root", tag, timeStart);
372 std::unique_ptr<TFile> outFile(TFile::Open(outputFileName.data(),
"recreate"));
373 outFile->WriteObject(&mFEEConfig,
"FEEConfig");
379 membuf sbuf((
char*)configBuff.data(), configBuff.size());
380 std::istream in(&sbuf);
384 while (std::getline(in, line)) {
385 const auto firstComma = line.find_first_of(
',');
388 tag = std::stoi(std::string(line.substr(0, firstComma)));
391 const std::string comment(line.substr(firstComma + 1, line.size()));
392 if ((tag < 0) || comment.empty()) {
393 LOGP(warning,
"Ill formatted line in 'TPC{}.txt': {}, expecting <tag,comment>, skipping", TagInfoName, line);
397 LOGP(warning,
"Tag '{}' not accepted, must be > 0, skipping", tag);
400 infos.emplace_back(tag, comment);
406bool DCSConfigDevice::loadFEEConfig(
int tag)
409 if (mReadFromRootFile) {
411 std::vector<std::string> filenames;
412 for (
const auto&
entry : fs::directory_iterator(
"./")) {
413 const auto fileName =
entry.path().filename().string();
415 if (
entry.is_regular_file() &&
416 fileName.find(
".root") == (fileName.size() - 5) &&
417 fileName.find(fmt::format(
".{}.", tag)) != std::string::npos) {
418 filenames.emplace_back(fileName);
421 if (filenames.size()) {
422 std::sort(filenames.begin(), filenames.end());
423 const auto& lastFile = filenames.back();
424 std::unique_ptr<TFile> inFile(TFile::Open(lastFile.data()));
425 if (inFile->IsOpen() && !inFile->IsZombie()) {
426 inFile->GetObject(
"FEEConfig", feeConfig);
429 LOGP(info,
"Read FEEConfig from file {} for updating", lastFile);
433 std::map<std::string, std::string> headers;
436 LOGP(info,
"Read FEEConfig from ccdb for updating: URL: {}, Validity: {} - {}, Last modfied: {}, ETag: {}", mCCDBApi.
getURL(), headers[
"Valid-From"], headers[
"Valid-Until"], headers[
"Last-Modified"], headers[
"ETag"]);
441 LOGP(warning,
"Could not retrieve FEE config for tag {}, a new entry will be created, full config should be sent", tag);
445 mFEEConfig = *feeConfig;
446 if (mReadFromRootFile) {
455 std::vector<OutputSpec> outputs;
466 {
"dump-to-text-files", VariantType::Bool,
false, {
"Optionally dump received data to text files"}},
467 {
"dump-to-root-file", VariantType::Bool,
false, {
"Optionally write FEEConfig to root file"}},
468 {
"read-from-root-file", VariantType::Bool,
false, {
"For testing purposes: read configuration from local root file instead of ccdb"}},
469 {
"dont-write-run-info", VariantType::Bool,
false, {
"For testing purposes: skip writing RunInformation to ccdb"}},
Simple interface to the CDB manager.
constexpr auto CDBWrapper
constexpr auto CDBPayload
DCS configuration processing.
Utils and constants for calibration and related workflows.
Frontend electronics configuration values.
Definition of the Names Generator class.
static constexpr std::string_view CCDBRunTag
static std::string getCCDBServer()
void init(std::string const &hosts)
std::string const & getURL() const
static std::unique_ptr< std::vector< char > > createObjectImage(const T *obj, CcdbObjectInfo *info=nullptr)
bool isSnapshotMode() const
std::enable_if<!std::is_base_of< o2::conf::ConfigurableParam, T >::value, T * >::type retrieveFromTFileAny(std::string const &path, std::map< std::string, std::string > const &metadata, long timestamp=-1, std::map< std::string, std::string > *headers=nullptr, std::string const &etag="", const std::string &createdNotAfter="", const std::string &createdNotBefore="") const
std::map< std::string, std::string > retrieveHeaders(std::string const &path, std::map< std::string, std::string > const &metadata, long timestamp=-1) const
int storeAsBinaryFile(const char *buffer, size_t size, const std::string &fileName, const std::string &objectType, const std::string &path, const std::map< std::string, std::string > &metadata, long startValidityTimestamp, long endValidityTimestamp, std::vector< char >::size_type maxSize=0) const
static constexpr const char * AdjustableEOV
T get(const char *key) const
ConfigParamRegistry const & options()
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
void setReason(std::string_view reason)
void setIntervention(CDBIntervention const intervention)
void setResponsible(std::string_view responsible)
const auto & getMetaData() const
std::vector< TagInfo > TagInfos
void init(o2::framework::InitContext &ic) final
void stop() final
This is invoked on stop.
void run(o2::framework::ProcessingContext &pc) final
void writeRootFile(int tag)
void endOfStream(o2::framework::EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
DCSConfigDevice()=default
static TagInfos readTagInfos(gsl::span< const char > configBuff)
static constexpr int FECsTotal
GLuint const GLchar * name
GLubyte GLubyte GLubyte GLubyte w
constexpr o2::header::DataOrigin gDataOriginTPC
int adjustOverriddenEOV(CcdbApi &api, const CcdbObjectInfo &infoNew)
set EOV of overriden objects to SOV-1 of overriding one if it is allowed
Defining PrimaryVertex explicitly as messageable.
std::vector< ConfigParamSpec > Options
std::vector< InputSpec > Inputs
Global TPC definitions and constants.
DataProcessorSpec getDCSConfigSpec()
create DCS processor
const std::unordered_map< CDBType, const std::string > CDBTypeMap
Storage name in CCDB for each calibration and parameter type.
@ FEEConfig
use fee config
const std::unordered_map< CDBType, o2::header::DataDescription > CDBDescMap
@ Automatic
Automatic upload.
@ ConfigFEE
FEE configuration map for each tag.
std::string to_string(gsl::span< T, Size > span)
static void prepareCCDBobjectInfo(T &obj, o2::ccdb::CcdbObjectInfo &info, const std::string &path, const std::map< std::string, std::string > &md, long start, long end=-1)
static constexpr o2::header::DataOrigin gDataOriginCDBWrapper
static constexpr o2::header::DataOrigin gDataOriginCDBPayload
TagInfo(int t, std::string_view c)
CalPadMapType padMaps
pad-wise configuration data
std::vector< CRUConfig > cruConfig
CRU configuration values.
Tags
Tag definitions for TPC/Config/FEE.
static std::vector< std::string > tokenize(const std::string &src, char delim, bool trimToken=true, bool skipEmpty=true)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"