1414// /
1515// / \author Pascal Boeschoten ([email protected] )1616
17+ #define __STDC_WANT_LIB_EXT1__ 1
18+ #include < string>
19+
1720#include " Common/Program.h"
1821#include " CommandLineUtilities/Common.h"
1922#include < chrono>
@@ -103,6 +106,16 @@ static std::vector<T> lexicalCastVector(const std::vector<U>& items)
103106 return result;
104107}
105108
109+ size_t strlenMax (char * string, size_t max)
110+ {
111+ for (size_t i = 0 ; i < max; ++i) {
112+ if (string[i] == ' \0 ' ) {
113+ return i;
114+ }
115+ };
116+ return max;
117+ }
118+
106119struct LinkInfo
107120{
108121 int serial;
@@ -141,8 +154,8 @@ struct Service
141154
142155 ServiceDescription description;
143156 std::chrono::steady_clock::time_point nextUpdate;
144- std::vector<uint32_t > registerValues;
145157 std::unique_ptr<DimService> dimService;
158+ std::vector<char > buffer; // /< Needed for DIM
146159};
147160
148161// / Thread-safe queue for commands
@@ -337,25 +350,24 @@ class ProgramAliceLowlevelFrontendServer: public AliceO2::Common::Program
337350 service->nextUpdate = std::chrono::steady_clock::now ();
338351 Visitor::apply (service->description .type ,
339352 [&](const ServiceDescription::Register& type){
340- service-> registerValues . resize (type. addresses . size ());
341-
353+ // Estimate max needed size. I'm not sure DIM can handle reallocations of this buffer, so we avoid that...
354+ service-> buffer . resize (type. addresses . size ()* 20 + 512 );
342355 getLogger () << " Starting register publisher '" << service->description .dnsName << " ' with "
343356 << type.addresses .size () << " address(es) at interval "
344357 << service->description .interval .count () << " ms" << endm;
345358 },
346359 [&](const ServiceDescription::ScaSequence& type){
347- service-> registerValues . resize (type. commandDataPairs . size () * 2 ); // Two result 32-bit integers per pair
348-
360+ // Estimate max needed size. I'm not sure DIM can handle reallocations of this buffer, so we avoid that...
361+ service-> buffer . resize (type. commandDataPairs . size ()* 20 + 512 );
349362 getLogger () << " Starting SCA publisher '" << service->description .dnsName << " ' with "
350363 << type.commandDataPairs .size () << " commands(s) at interval "
351364 << service->description .interval .count () << " ms" << endm;
352365 }
353366 );
354367
355- auto format = (b::format (" I:%1%" ) % service->registerValues .size ()).str ();
356- service->dimService = std::make_unique<DimService>(service->description .dnsName .c_str (), format.c_str (),
357- service->registerValues .data (), service->registerValues .size ());
358-
368+ std::fill (service->buffer .begin (), service->buffer .end (), ' \0 ' );
369+ service->dimService = std::make_unique<DimService>(service->description .dnsName .c_str (), " C" ,
370+ service->buffer .data (), strlenMax (service->buffer .data (), service->buffer .size ()));
359371 mServices .insert (std::make_pair (serviceDescription.dnsName , std::move (service)));
360372 }
361373
@@ -371,37 +383,30 @@ class ProgramAliceLowlevelFrontendServer: public AliceO2::Common::Program
371383 {
372384 getLogger () << " Updating '" << service.description .dnsName << " '" << endm;
373385
386+ std::string result;
387+
374388 Visitor::apply (service.description .type ,
375389 [&](const ServiceDescription::Register& type){
390+ std::stringstream ss;
376391 auto & bar0 = *(mBars .at (service.description .linkInfo .serial ).at (0 ));
377392 for (size_t i = 0 ; i < type.addresses .size (); ++i) {
378393 auto index = type.addresses [i] / 4 ;
379394 auto value = bar0.readRegister (index);
380- service. registerValues . at (i) = value;
395+ ss << std::hex << value << ' \n ' ;
381396 }
397+ result = ss.str ();
382398 },
383399 [&](const ServiceDescription::ScaSequence& type){
384400 auto & bar2 = *(mBars .at (service.description .linkInfo .serial ).at (2 ));
385- std::fill (service.registerValues .begin (), service.registerValues .end (), 0 ); // Reset array in case of aborts
386401 auto sca = Sca (bar2, bar2.getCardType (), service.description .linkInfo .link );
387- for (size_t i = 0 ; i < type.commandDataPairs .size (); ++i) {
388- try {
389- const auto & pair = type.commandDataPairs [i];
390- sca.write (pair);
391- auto result = sca.read ();
392- service.registerValues [i*2 ] = result.command ;
393- service.registerValues [i*2 + 1 ] = result.data ;
394- } catch (const ScaException &e) {
395- // If an SCA error occurs, we stop executing the sequence of commands and set the error value
396- service.registerValues [i*2 ] = 0xffffffff ;
397- service.registerValues [i*2 + 1 ] = 0xffffffff ;
398- break ;
399- }
400- }
402+ result = writeScaSequence (type.commandDataPairs , sca, service.description .linkInfo );
401403 }
402404 );
403405
404- service.dimService ->updateService ();
406+ // Reset and copy into the persistent buffer because I don't trust DIM with the non-persistent std::string
407+ std::fill (service.buffer .begin (), service.buffer .end (), ' \0 ' );
408+ std::copy (result.begin (), result.end (), service.buffer .begin ());
409+ service.dimService ->updateService (service.buffer .data (), result.size () + 1 );
405410 }
406411
407412 // / Checks if the address is in range
@@ -456,6 +461,31 @@ class ProgramAliceLowlevelFrontendServer: public AliceO2::Common::Program
456461 return commandData;
457462 };
458463
464+ // / Writes an SCA sequence and returns a string of the read results separated by newline
465+ static std::string writeScaSequence (const std::vector<Sca::CommandData>& commandDataPairs, Sca& sca,
466+ LinkInfo linkInfo)
467+ {
468+ std::stringstream resultBuffer;
469+ for (const auto & commandData : commandDataPairs) {
470+ try {
471+ sca.write (commandData);
472+ auto result = sca.read ();
473+ getLogger () << (b::format (" cmd=0x%x data=0x%x result=0x%x" ) % commandData.command % commandData.data %
474+ result.data ).str () << endm;
475+ resultBuffer << std::hex << result.data << ' \n ' ;
476+ } catch (const ScaException &e) {
477+ // If an SCA error occurs, we stop executing the sequence of commands and return the results as far as we got
478+ // them, plus the error message.
479+ getLogger () << InfoLogger::InfoLogger::Error
480+ << (b::format (" SCA_SEQUENCE cmd=0x%x data=0x%x serial=%d link=%d error='%s'" ) % commandData.command
481+ % commandData.data % linkInfo.serial % linkInfo.link % e.what ()).str () << endm;
482+ resultBuffer << e.what ();
483+ break ;
484+ }
485+ }
486+ return resultBuffer.str ();
487+ }
488+
459489 // / RPC handler for register reads
460490 static std::string registerRead (const std::string& parameter, BarSharedPtr channel)
461491 {
@@ -627,29 +657,8 @@ class ProgramAliceLowlevelFrontendServer: public AliceO2::Common::Program
627657 // We split on \n to get the pairs of SCA command and SCA data
628658 auto lines = split (parameter, argumentSeparator ());
629659 auto commandDataPairs = linesToCommandDataVector (lines.begin (), lines.end ());
630-
631- std::stringstream resultBuffer;
632660 auto sca = Sca (*bar2, bar2->getCardType (), linkInfo.link );
633-
634- for (const auto & commandData : commandDataPairs) {
635- try {
636- sca.write (commandData);
637- auto result = sca.read ();
638- getLogger () << (b::format (" cmd=0x%x data=0x%x result=0x%x" ) % commandData.command % commandData.data %
639- result.data ).str () << endm;
640- resultBuffer << std::hex << result.data << ' \n ' ;
641- } catch (const ScaException &e) {
642- // If an SCA error occurs, we stop executing the sequence of commands and return the results as far as we got
643- // them, plus the error message.
644- getLogger () << InfoLogger::InfoLogger::Error
645- << (b::format (" SCA_SEQUENCE cmd=0x%x data=0x%x serial=%d link=%d error='%s'" ) % commandData.command
646- % commandData.data % linkInfo.serial % linkInfo.link % e.what ()).str () << endm;
647- resultBuffer << e.what ();
648- break ;
649- }
650- }
651-
652- return resultBuffer.str ();
661+ return writeScaSequence (commandDataPairs, sca, linkInfo);
653662 }
654663
655664 // / Command queue for passing commands from DIM RPC calls (which are in separate threads) to the main program loop
0 commit comments