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;
2933using namespace o2 ::roc::CommandLineUtilities;
3034using namespace o2 ::roc;
3135namespace 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+
33217class 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
312597int 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