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+ 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+
33218class 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
312596int 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