Skip to content

Commit 91678dc

Browse files
committed
added roc-config option to generate roc-status report
1 parent 039ce0e commit 91678dc

File tree

3 files changed

+292
-1
lines changed

3 files changed

+292
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ Error codes in the range 4000-4999 are assigned to ReadoutCard. These are furthe
694694
| 4800 - 4899 | Full Range |
695695
| ----------- | ------------ |
696696
| 4800 - 4804 | CTP emulator |
697+
| 4805 | roc status |
697698
698699
### Unassigned
699700
| Range |

doc/releaseNotes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ This file describes the main feature changes for released versions of ReadoutCar
66
- Added release notes as part of source code.
77
- Added library version number. Can be retrieved at runtime with o2::roc::getReadoutCardVersion().
88
- Fixed bug in DMA reset. Old data from previous run could stay in the pipeline if previous process was stopped abruptly.
9+
10+
## v0.39.0 - 07/10/2022
11+
- Added option --status-report to roc-config, in order to dump roc-status (similar) output to given file name. Can be stdout, infologger, or a file name. The file name can be preceded with + for appending the file. Name can contain special escape sequences %t (timestamp) %T (date/time) or %i (card ID). Infologger reports are set with error code 4805.

src/CommandLineUtilities/ProgramConfig.cxx

Lines changed: 288 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,202 @@
1919
#include "CommandLineUtilities/Options.h"
2020
#include "CommandLineUtilities/Program.h"
2121
#include "Cru/CruBar.h"
22+
#include "Crorc/CrorcBar.h"
2223
#include "ReadoutCard/CardConfigurator.h"
2324
#include "ReadoutCard/ChannelFactory.h"
2425
#include "ReadoutCard/Exception.h"
2526
#include "ReadoutCard/FirmwareChecker.h"
2627
#include "ReadoutCard/Logger.h"
2728
#include "RocPciDevice.h"
29+
#include <InfoLogger/InfoLogger.hxx>
30+
#include <boost/format.hpp>
2831

32+
using namespace AliceO2::InfoLogger;
2933
using namespace o2::roc::CommandLineUtilities;
3034
using namespace o2::roc;
3135
namespace po = boost::program_options;
3236

37+
std::string cmd; // program command invoked
38+
39+
/// Get a status report of given card
40+
std::string getStatusReport(Parameters::CardIdType cardId) {
41+
42+
auto card = RocPciDevice(cardId).getCardDescriptor();
43+
auto cardType = card.cardType;
44+
45+
std::ostringstream table;
46+
std::string formatHeader;
47+
std::string formatRow;
48+
std::string header;
49+
std::string lineFat;
50+
std::string lineThin;
51+
const char *linkMask = "0-11";
52+
53+
if (cardType == CardType::type::Crorc) {
54+
formatHeader = " %-9s %-8s %-19s\n";
55+
formatRow = " %-9s %-8s %-19.1f\n";
56+
header = (boost::format(formatHeader) % "Link ID" % "Status" % "Optical power(uW)").str();
57+
lineFat = std::string(header.length(), '=') + '\n';
58+
lineThin = std::string(header.length(), '-') + '\n';
59+
60+
auto params = Parameters::makeParameters(cardId, 0); //status available on BAR0
61+
params.setLinkMask(Parameters::linkMaskFromString(linkMask));
62+
auto bar0 = ChannelFactory().getBar(params);
63+
auto crorcBar0 = std::dynamic_pointer_cast<CrorcBar>(bar0);
64+
65+
Crorc::ReportInfo reportInfo = crorcBar0->report();
66+
std::string qsfpEnabled = reportInfo.qsfpEnabled ? "Enabled" : "Disabled";
67+
std::string offset = reportInfo.dynamicOffset ? "Dynamic" : "Fixed";
68+
std::string timeFrameDetectionEnabled = reportInfo.timeFrameDetectionEnabled ? "Enabled" : "Disabled";
69+
70+
if (card.serialId.getSerial() == 0x7fffffff || card.serialId.getSerial() == 0x0) {
71+
table << "Bad serial reported, bad card state" << std::endl;
72+
} else {
73+
74+
table << "-----------------------------" << std::endl;
75+
table << "QSFP " << qsfpEnabled << std::endl;
76+
table << offset << " offset" << std::endl;
77+
table << "-----------------------------" << std::endl;
78+
table << "Time Frame Detection " << timeFrameDetectionEnabled << std::endl;
79+
table << "Time Frame Length: " << reportInfo.timeFrameLength << std::endl;
80+
table << "-----------------------------" << std::endl;
81+
82+
83+
table << lineFat << header << lineThin;
84+
85+
/* PARAMETERS PER LINK */
86+
for (const auto& el : reportInfo.linkMap) {
87+
auto link = el.second;
88+
int id = el.first;
89+
90+
std::string linkStatus = link.status == Crorc::LinkStatus::Up ? "UP" : "DOWN";
91+
float opticalPower = link.opticalPower;
92+
93+
auto format = boost::format(formatRow) % id % linkStatus % opticalPower;
94+
table << format;
95+
}
96+
}
97+
lineFat = std::string(header.length(), '=') + '\n';
98+
table << lineFat;
99+
100+
} else if (cardType == CardType::type::Cru) {
101+
formatHeader = " %-9s %-16s %-10s %-14s %-15s %-10s %-14s %-14s %-8s %-19s %-11s %-7s\n";
102+
formatRow = " %-9s %-16s %-10s %-14s %-15s %-10s %-14.2f %-14.2f %-8s %-19.1f %-11s %-7s\n";
103+
header = (boost::format(formatHeader) % "Link ID" % "GBT Mode Tx/Rx" % "Loopback" % "GBT MUX" % "Datapath Mode" % "Datapath" % "RX freq(MHz)" % "TX freq(MHz)" % "Status" % "Optical power(uW)" % "System ID" % "FEE ID").str();
104+
lineFat = std::string(header.length(), '=') + '\n';
105+
lineThin = std::string(header.length(), '-') + '\n';
106+
107+
auto params = Parameters::makeParameters(cardId, 2); //status available on BAR2
108+
params.setLinkMask(Parameters::linkMaskFromString(linkMask));
109+
auto bar2 = ChannelFactory().getBar(params);
110+
auto cruBar2 = std::dynamic_pointer_cast<CruBar>(bar2);
111+
112+
Cru::ReportInfo reportInfo = cruBar2->report();
113+
114+
std::string clock = (reportInfo.ttcClock == 0 ? "TTC" : "Local");
115+
std::string offset = (reportInfo.dynamicOffset ? "Dynamic" : "Fixed");
116+
std::string userLogic = (reportInfo.userLogicEnabled ? "Enabled" : "Disabled");
117+
std::string runStats = (reportInfo.runStatsEnabled ? "Enabled" : "Disabled");
118+
std::string userAndCommonLogic = (reportInfo.userAndCommonLogicEnabled ? "Enabled" : "Disabled");
119+
120+
table << "-----------------------------" << std::endl;
121+
table << "CRU ID: " << reportInfo.cruId << std::endl;
122+
table << clock << " clock | ";
123+
table << offset << " offset" << std::endl;
124+
table << "Timeframe length: " << (int)reportInfo.timeFrameLength << std::endl;
125+
if (reportInfo.userLogicEnabled && reportInfo.userAndCommonLogicEnabled) {
126+
table << "User and Common Logic enabled" << std::endl;
127+
} else if (reportInfo.userLogicEnabled) {
128+
table << "User Logic enabled" << std::endl;
129+
}
130+
if (reportInfo.runStatsEnabled) {
131+
table << "Run statistics enabled" << std::endl;
132+
}
133+
134+
135+
Cru::OnuStatus onuStatus = cruBar2->reportOnuStatus(0);
136+
137+
std::string onuUpstreamStatus = Cru::LinkStatusToString(onuStatus.stickyStatus.upstreamStatus);
138+
std::string onuDownstreamStatus = Cru::LinkStatusToString(onuStatus.stickyStatus.downstreamStatus);
139+
uint32_t onuStickyValue = onuStatus.stickyStatus.stickyValue;
140+
uint32_t onuStickyValuePrev = onuStatus.stickyStatus.stickyValuePrev;
141+
142+
std::string ponQualityStatusStr;
143+
ponQualityStatusStr = onuStatus.ponQualityStatus ? "good" : "bad";
144+
145+
table << "=============================" << std::endl;
146+
table << "ONU downstream status: " << onuDownstreamStatus << std::endl;
147+
table << "ONU upstream status: " << onuUpstreamStatus << std::endl;
148+
table << "ONU sticky value: 0x" << std::hex << onuStickyValue << std::endl;
149+
table << "ONU sticky value (was): 0x" << std::hex << onuStickyValuePrev << std::endl;
150+
table << "ONU address: " << onuStatus.onuAddress << std::endl;
151+
table << "-----------------------------" << std::endl;
152+
table << "ONU RX40 locked: " << onuStatus.rx40Locked << std::endl;
153+
table << "ONU phase good: " << onuStatus.phaseGood << std::endl;
154+
table << "ONU RX locked: " << onuStatus.rxLocked << std::endl;
155+
table << "ONU operational: " << onuStatus.operational << std::endl;
156+
table << "ONU MGT TX ready: " << onuStatus.mgtTxReady << std::endl;
157+
table << "ONU MGT RX ready: " << onuStatus.mgtRxReady << std::endl;
158+
table << "ONU MGT TX PLL locked: " << onuStatus.mgtTxPllLocked << std::endl;
159+
table << "ONU MGT RX PLL locked: " << onuStatus.mgtRxPllLocked << std::endl;
160+
table << "PON quality: 0x" << std::hex << onuStatus.ponQuality << std::endl;
161+
table << "PON quality status: " << ponQualityStatusStr << std::endl;
162+
table << "PON RX power (dBm): " << onuStatus.ponRxPower << std::endl;
163+
164+
table << lineFat << header << lineThin;
165+
166+
/* PARAMETERS PER LINK */
167+
for (const auto& el : reportInfo.linkMap) {
168+
auto link = el.second;
169+
int globalId = el.first; //Use the "new" link mapping
170+
std::string gbtTxMode = GbtMode::toString(link.gbtTxMode);
171+
std::string gbtRxMode = GbtMode::toString(link.gbtRxMode);
172+
std::string gbtTxRxMode = gbtTxMode + "/" + gbtRxMode;
173+
std::string loopback = (link.loopback == false ? "None" : "Enabled");
174+
175+
std::string downstreamData;
176+
if (reportInfo.downstreamData == Cru::DATA_CTP) {
177+
downstreamData = "CTP";
178+
} else if (reportInfo.downstreamData == Cru::DATA_PATTERN) {
179+
downstreamData = "PATTERN";
180+
} else if (reportInfo.downstreamData == Cru::DATA_MIDTRG) {
181+
downstreamData = "MIDTRG";
182+
}
183+
184+
std::string gbtMux = GbtMux::toString(link.gbtMux);
185+
if (gbtMux == "TTC") {
186+
gbtMux += ":" + downstreamData;
187+
}
188+
189+
std::string datapathMode = DatapathMode::toString(link.datapathMode);
190+
191+
std::string enabled = (link.enabled) ? "Enabled" : "Disabled";
192+
193+
float rxFreq = link.rxFreq;
194+
float txFreq = link.txFreq;
195+
196+
std::string linkStatus;
197+
if (link.stickyBit == Cru::LinkStatus::Up) {
198+
linkStatus = "UP";
199+
} else if (link.stickyBit == Cru::LinkStatus::UpWasDown) {
200+
linkStatus = "UP (was DOWN)";
201+
} else if (link.stickyBit == Cru::LinkStatus::Down) {
202+
linkStatus = "DOWN";
203+
}
204+
205+
float opticalPower = link.opticalPower;
206+
std::string systemId = Utilities::toHexString(link.systemId);
207+
std::string feeId = Utilities::toHexString(link.feeId);
208+
auto format = boost::format(formatRow) % globalId % gbtTxRxMode % loopback % gbtMux % datapathMode % enabled % rxFreq % txFreq % linkStatus % opticalPower % systemId % feeId;
209+
table << format;
210+
}
211+
lineFat = std::string(header.length(), '=') + '\n';
212+
table << lineFat;
213+
}
214+
215+
return table.str();
216+
}
217+
33218
class ProgramConfig : public Program
34219
{
35220
public:
@@ -128,13 +313,108 @@ class ProgramConfig : public Program
128313
options.add_options()("fee-id",
129314
po::value<std::string>(&mOptions.feeId),
130315
"Sets the FEE ID");
316+
options.add_options()("status-report",
317+
po::value<std::string>(&mOptions.statusReport),
318+
"Sets file where to output card status (similar to roc-status). Can be stdout, infologger, or a file name. The file name can be preceded with + for appending the file. Name can contain special escape sequences %t (timestamp) %T (date/time) or %i (card ID). Infologger reports are set with error code 4805.");
131319
Options::addOptionCardId(options);
132320
}
133321

322+
static std::string cardIdToString(const Parameters::CardIdType &cardId) {
323+
if ( auto *id = boost::get<o2::roc::PciAddress>( &cardId ) ) {
324+
return id->toString();
325+
} else if ( auto *id = boost::get<o2::roc::PciSequenceNumber>( &cardId ) ) {
326+
return id->toString();
327+
} else if ( auto *id = boost::get<o2::roc::SerialId>( &cardId ) ) {
328+
return id->toString();
329+
}
330+
return "";
331+
}
332+
333+
virtual void reportStatus(Parameters::CardIdType cardId) {
334+
if (mOptions.statusReport != "") {
335+
336+
// create report
337+
std::string report;
338+
339+
// time now
340+
std::time_t t = std::time(nullptr);
341+
std::tm tm = *std::localtime(&t);
342+
std::stringstream buffer;
343+
buffer << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
344+
345+
report += "roc-config execution report\n";
346+
report += "Card: " + cardIdToString(cardId) + "\n";
347+
report += "Time completed: " + buffer.str() + "\n";
348+
report += "Command: " + cmd + "\n";
349+
350+
// do as in roc-status
351+
report += "Status: \n" + getStatusReport(cardId);
352+
353+
// parse filename
354+
std::string fileName;
355+
int parseError = 0;
356+
const char* fileMode = "w";
357+
for (std::string::iterator it = mOptions.statusReport.begin(); it != mOptions.statusReport.end(); ++it) {
358+
if (*it == '%') {
359+
// escape characters
360+
++it;
361+
if (it != fileName.end()) {
362+
if (*it == 't') {
363+
fileName += std::to_string(std::time(nullptr));
364+
} else if (*it == 'T') {
365+
std::stringstream buffer;
366+
buffer << std::put_time(&tm, "%Y_%m_%d__%H_%M_%S");
367+
fileName += buffer.str();
368+
} else if (*it == 'i') {
369+
fileName += cardIdToString(cardId);
370+
}
371+
} else {
372+
parseError++;
373+
}
374+
} else if ((it == mOptions.statusReport.begin()) && (*it == '+')) {
375+
fileMode = "a";
376+
} else {
377+
// normal char - copy it
378+
fileName += *it;
379+
}
380+
if (parseError) {
381+
break;
382+
}
383+
}
384+
385+
// write report
386+
if (fileName == "stdout") {
387+
printf("\n%s\n", report.c_str());
388+
} else if (fileName == "infologger") {
389+
InfoLogger theLog;
390+
InfoLoggerContext theLogContext;
391+
theLogContext.setField(InfoLoggerContext::FieldName::Facility, ilFacility);
392+
theLog.setContext(theLogContext);
393+
std::string line;
394+
std::stringstream ss;
395+
ss << report;
396+
while(std::getline(ss, line)) {
397+
theLog << LogInfoSupport_(4805) << line << InfoLogger::endm;
398+
}
399+
} else {
400+
FILE *fp = fopen(fileName.c_str(), fileMode);
401+
if (fp == nullptr) {
402+
BOOST_THROW_EXCEPTION(Exception() << ErrorInfo::Message("Failed to open report file " + fileName + " : " + strerror(errno)));
403+
} else {
404+
fprintf(fp, "%s\n", report.c_str());
405+
fclose(fp);
406+
}
407+
}
408+
}
409+
return;
410+
}
411+
412+
const char *ilFacility = "ReadoutCard/config";
413+
134414
virtual void run(const boost::program_options::variables_map& map)
135415
{
136416

137-
Logger::setFacility("ReadoutCard/config");
417+
Logger::setFacility(ilFacility);
138418

139419
// Configure all cards found - Normally used during boot
140420
if (mOptions.configAll) {
@@ -153,6 +433,7 @@ class ProgramConfig : public Program
153433
try {
154434
FirmwareChecker().checkFirmwareCompatibility(params);
155435
CardConfigurator(card.pciAddress, mOptions.configUri, mOptions.forceConfig);
436+
reportStatus(card.pciAddress);
156437
} catch (const std::runtime_error& e) {
157438
Logger::get() << e.what() << LogErrorOps_(4600) << endm;
158439
} catch (const Exception& e) {
@@ -248,6 +529,7 @@ class ProgramConfig : public Program
248529

249530
try {
250531
CardConfigurator(params, mOptions.forceConfig);
532+
reportStatus(cardId);
251533
} catch (const std::runtime_error& e) {
252534
Logger::get() << e.what() << LogErrorOps_(4600) << endm;
253535
throw;
@@ -263,6 +545,7 @@ class ProgramConfig : public Program
263545

264546
try {
265547
CardConfigurator(cardId, mOptions.configUri, mOptions.forceConfig);
548+
reportStatus(cardId);
266549
} catch (const std::runtime_error& e) {
267550
Logger::get() << e.what() << LogErrorOps_(4600) << endm;
268551
throw;
@@ -302,6 +585,7 @@ class ProgramConfig : public Program
302585
bool noGbt = false;
303586
std::string systemId = "0x0";
304587
std::string feeId = "0x0";
588+
std::string statusReport = ""; // when set, output roc status to file
305589
/*std::string systemId = "0x1ff"; // TODO: Default values that can be used to check if params have been specified
306590
std::string feeId = "0x1f";*/
307591
} mOptions;
@@ -311,6 +595,9 @@ class ProgramConfig : public Program
311595

312596
int main(int argc, char** argv)
313597
{
598+
for (int i=0; i<argc; i++) {
599+
cmd += argv[i] + std::string(" ");
600+
}
314601
// true here enables InfoLogger output by default
315602
// see the Program constructor
316603
return ProgramConfig(true).execute(argc, argv);

0 commit comments

Comments
 (0)