Skip to content

Commit 16417f1

Browse files
authored
Merge pull request #393 from sy-c/master
v0.39.0 added roc-config option to generate roc-status report
2 parents 039ce0e + c01dffa commit 16417f1

File tree

3 files changed

+293
-1
lines changed

3 files changed

+293
-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: 289 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,201 @@
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+
43+
auto card = RocPciDevice(cardId).getCardDescriptor();
44+
auto cardType = card.cardType;
45+
46+
std::ostringstream table;
47+
std::string formatHeader;
48+
std::string formatRow;
49+
std::string header;
50+
std::string lineFat;
51+
std::string lineThin;
52+
const char* linkMask = "0-11";
53+
54+
if (cardType == CardType::type::Crorc) {
55+
formatHeader = " %-9s %-8s %-19s\n";
56+
formatRow = " %-9s %-8s %-19.1f\n";
57+
header = (boost::format(formatHeader) % "Link ID" % "Status" % "Optical power(uW)").str();
58+
lineFat = std::string(header.length(), '=') + '\n';
59+
lineThin = std::string(header.length(), '-') + '\n';
60+
61+
auto params = Parameters::makeParameters(cardId, 0); // status available on BAR0
62+
params.setLinkMask(Parameters::linkMaskFromString(linkMask));
63+
auto bar0 = ChannelFactory().getBar(params);
64+
auto crorcBar0 = std::dynamic_pointer_cast<CrorcBar>(bar0);
65+
66+
Crorc::ReportInfo reportInfo = crorcBar0->report();
67+
std::string qsfpEnabled = reportInfo.qsfpEnabled ? "Enabled" : "Disabled";
68+
std::string offset = reportInfo.dynamicOffset ? "Dynamic" : "Fixed";
69+
std::string timeFrameDetectionEnabled = reportInfo.timeFrameDetectionEnabled ? "Enabled" : "Disabled";
70+
71+
if (card.serialId.getSerial() == 0x7fffffff || card.serialId.getSerial() == 0x0) {
72+
table << "Bad serial reported, bad card state" << std::endl;
73+
} else {
74+
75+
table << "-----------------------------" << std::endl;
76+
table << "QSFP " << qsfpEnabled << std::endl;
77+
table << offset << " offset" << std::endl;
78+
table << "-----------------------------" << std::endl;
79+
table << "Time Frame Detection " << timeFrameDetectionEnabled << std::endl;
80+
table << "Time Frame Length: " << reportInfo.timeFrameLength << std::endl;
81+
table << "-----------------------------" << std::endl;
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+
Cru::OnuStatus onuStatus = cruBar2->reportOnuStatus(0);
135+
136+
std::string onuUpstreamStatus = Cru::LinkStatusToString(onuStatus.stickyStatus.upstreamStatus);
137+
std::string onuDownstreamStatus = Cru::LinkStatusToString(onuStatus.stickyStatus.downstreamStatus);
138+
uint32_t onuStickyValue = onuStatus.stickyStatus.stickyValue;
139+
uint32_t onuStickyValuePrev = onuStatus.stickyStatus.stickyValuePrev;
140+
141+
std::string ponQualityStatusStr;
142+
ponQualityStatusStr = onuStatus.ponQualityStatus ? "good" : "bad";
143+
144+
table << "=============================" << std::endl;
145+
table << "ONU downstream status: " << onuDownstreamStatus << std::endl;
146+
table << "ONU upstream status: " << onuUpstreamStatus << std::endl;
147+
table << "ONU sticky value: 0x" << std::hex << onuStickyValue << std::endl;
148+
table << "ONU sticky value (was): 0x" << std::hex << onuStickyValuePrev << std::endl;
149+
table << "ONU address: " << onuStatus.onuAddress << std::endl;
150+
table << "-----------------------------" << std::endl;
151+
table << "ONU RX40 locked: " << onuStatus.rx40Locked << std::endl;
152+
table << "ONU phase good: " << onuStatus.phaseGood << std::endl;
153+
table << "ONU RX locked: " << onuStatus.rxLocked << std::endl;
154+
table << "ONU operational: " << onuStatus.operational << std::endl;
155+
table << "ONU MGT TX ready: " << onuStatus.mgtTxReady << std::endl;
156+
table << "ONU MGT RX ready: " << onuStatus.mgtRxReady << std::endl;
157+
table << "ONU MGT TX PLL locked: " << onuStatus.mgtTxPllLocked << std::endl;
158+
table << "ONU MGT RX PLL locked: " << onuStatus.mgtRxPllLocked << std::endl;
159+
table << "PON quality: 0x" << std::hex << onuStatus.ponQuality << std::endl;
160+
table << "PON quality status: " << ponQualityStatusStr << std::endl;
161+
table << "PON RX power (dBm): " << onuStatus.ponRxPower << std::endl;
162+
163+
table << lineFat << header << lineThin;
164+
165+
/* PARAMETERS PER LINK */
166+
for (const auto& el : reportInfo.linkMap) {
167+
auto link = el.second;
168+
int globalId = el.first; // Use the "new" link mapping
169+
std::string gbtTxMode = GbtMode::toString(link.gbtTxMode);
170+
std::string gbtRxMode = GbtMode::toString(link.gbtRxMode);
171+
std::string gbtTxRxMode = gbtTxMode + "/" + gbtRxMode;
172+
std::string loopback = (link.loopback == false ? "None" : "Enabled");
173+
174+
std::string downstreamData;
175+
if (reportInfo.downstreamData == Cru::DATA_CTP) {
176+
downstreamData = "CTP";
177+
} else if (reportInfo.downstreamData == Cru::DATA_PATTERN) {
178+
downstreamData = "PATTERN";
179+
} else if (reportInfo.downstreamData == Cru::DATA_MIDTRG) {
180+
downstreamData = "MIDTRG";
181+
}
182+
183+
std::string gbtMux = GbtMux::toString(link.gbtMux);
184+
if (gbtMux == "TTC") {
185+
gbtMux += ":" + downstreamData;
186+
}
187+
188+
std::string datapathMode = DatapathMode::toString(link.datapathMode);
189+
190+
std::string enabled = (link.enabled) ? "Enabled" : "Disabled";
191+
192+
float rxFreq = link.rxFreq;
193+
float txFreq = link.txFreq;
194+
195+
std::string linkStatus;
196+
if (link.stickyBit == Cru::LinkStatus::Up) {
197+
linkStatus = "UP";
198+
} else if (link.stickyBit == Cru::LinkStatus::UpWasDown) {
199+
linkStatus = "UP (was DOWN)";
200+
} else if (link.stickyBit == Cru::LinkStatus::Down) {
201+
linkStatus = "DOWN";
202+
}
203+
204+
float opticalPower = link.opticalPower;
205+
std::string systemId = Utilities::toHexString(link.systemId);
206+
std::string feeId = Utilities::toHexString(link.feeId);
207+
auto format = boost::format(formatRow) % globalId % gbtTxRxMode % loopback % gbtMux % datapathMode % enabled % rxFreq % txFreq % linkStatus % opticalPower % systemId % feeId;
208+
table << format;
209+
}
210+
lineFat = std::string(header.length(), '=') + '\n';
211+
table << lineFat;
212+
}
213+
214+
return table.str();
215+
}
216+
33217
class ProgramConfig : public Program
34218
{
35219
public:
@@ -128,13 +312,110 @@ class ProgramConfig : public Program
128312
options.add_options()("fee-id",
129313
po::value<std::string>(&mOptions.feeId),
130314
"Sets the FEE ID");
315+
options.add_options()("status-report",
316+
po::value<std::string>(&mOptions.statusReport),
317+
"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.");
131318
Options::addOptionCardId(options);
132319
}
133320

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

137-
Logger::setFacility("ReadoutCard/config");
418+
Logger::setFacility(ilFacility);
138419

139420
// Configure all cards found - Normally used during boot
140421
if (mOptions.configAll) {
@@ -153,6 +434,7 @@ class ProgramConfig : public Program
153434
try {
154435
FirmwareChecker().checkFirmwareCompatibility(params);
155436
CardConfigurator(card.pciAddress, mOptions.configUri, mOptions.forceConfig);
437+
reportStatus(card.pciAddress);
156438
} catch (const std::runtime_error& e) {
157439
Logger::get() << e.what() << LogErrorOps_(4600) << endm;
158440
} catch (const Exception& e) {
@@ -248,6 +530,7 @@ class ProgramConfig : public Program
248530

249531
try {
250532
CardConfigurator(params, mOptions.forceConfig);
533+
reportStatus(cardId);
251534
} catch (const std::runtime_error& e) {
252535
Logger::get() << e.what() << LogErrorOps_(4600) << endm;
253536
throw;
@@ -263,6 +546,7 @@ class ProgramConfig : public Program
263546

264547
try {
265548
CardConfigurator(cardId, mOptions.configUri, mOptions.forceConfig);
549+
reportStatus(cardId);
266550
} catch (const std::runtime_error& e) {
267551
Logger::get() << e.what() << LogErrorOps_(4600) << endm;
268552
throw;
@@ -302,6 +586,7 @@ class ProgramConfig : public Program
302586
bool noGbt = false;
303587
std::string systemId = "0x0";
304588
std::string feeId = "0x0";
589+
std::string statusReport = ""; // when set, output roc status to file
305590
/*std::string systemId = "0x1ff"; // TODO: Default values that can be used to check if params have been specified
306591
std::string feeId = "0x1f";*/
307592
} mOptions;
@@ -311,6 +596,9 @@ class ProgramConfig : public Program
311596

312597
int main(int argc, char** argv)
313598
{
599+
for (int i = 0; i < argc; i++) {
600+
cmd += argv[i] + std::string(" ");
601+
}
314602
// true here enables InfoLogger output by default
315603
// see the Program constructor
316604
return ProgramConfig(true).execute(argc, argv);

0 commit comments

Comments
 (0)