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");
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.
char error[CURL_ERROR_SIZE]
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 ITS Vertex explicitly as messageable.
std::vector< InputSpec > Inputs
int32_t const char int32_t line
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"