11// / \file ProgramAliceLowlevelFrontendServer.cxx
22// / \brief Utility that starts the ALICE Lowlevel Frontend (ALF) DIM server
33// /
4+ // / This file contains a bunch of classes that together form the server part of ALF.
5+ // / It is single-threaded, because an earlier multi-threaded implementation ran into strange locking issues with DIM's
6+ // / thread, and it was determined that it would cost less time to rewrite than to debug.
7+ // /
8+ // / The idea is that the DIM thread calls the RPC handler functions of the ProgramAliceLowlevelFrontendServer class.
9+ // / These handlers then, depending on the RPC:
10+ // / a) Execute the request immediately (such as for register reads and writes)
11+ // / b) Put a corresponding command object in a lock-free thread-safe queue (such as for publish start/stop commands),
12+ // / the mCommandQueue. The main thread of ProgramAliceLowlevelFrontendServer periodically takes commands from this
13+ // / queue and handles them.
14+ // /
415// / \author Pascal Boeschoten ([email protected] )516
617#include " Common/Program.h"
@@ -65,8 +76,19 @@ static std::vector<T> lexicalCastVector(const std::vector<U>& items)
6576struct ServiceDescription
6677{
6778 std::string dnsName;
68- std::vector<uintptr_t > addresses;
6979 std::chrono::milliseconds interval;
80+
81+ struct Register
82+ {
83+ std::vector<uintptr_t > addresses;
84+ };
85+
86+ struct Sca
87+ {
88+ std::vector<std::pair<uint32_t , uint32_t >> commandDataPairs;
89+ };
90+
91+ boost::variant<Register, Sca> type;
7092};
7193
7294// / Class that handles adding/removing publishers
@@ -101,7 +123,7 @@ class PublisherRegistry
101123 for (auto & kv: mServices ) {
102124 auto & service = *kv.second ;
103125 if (service.nextUpdate < now) {
104- service.updateRegisterValues (*mChannel .get ());
126+ service.updateValues (*mChannel .get ());
105127 service.advanceUpdateTime ();
106128 if (service.nextUpdate < next) {
107129 next = service.nextUpdate ;
@@ -120,31 +142,62 @@ class PublisherRegistry
120142 {
121143 mDescription = description;
122144 nextUpdate = std::chrono::steady_clock::now ();
123- registerValues.resize (mDescription .addresses .size ());
145+
146+ Visitor::apply (mDescription .type ,
147+ [&](const ServiceDescription::Register& type){
148+ registerValues.resize (type.addresses .size ());
149+
150+ getInfoLogger () << " Starting publisher '" << mDescription .dnsName << " ' with "
151+ << type.addresses .size () << " address(es) at interval "
152+ << mDescription .interval .count () << " ms" << endm;
153+ },
154+ [&](const ServiceDescription::Sca& type){
155+ registerValues.resize (1 ); // SCA publisher only publishes 1 value
156+
157+ getInfoLogger () << " Starting SCA publisher '" << mDescription .dnsName << " ' with "
158+ << type.commandDataPairs .size () << " commands(s) at interval "
159+ << mDescription .interval .count () << " ms" << endm;
160+ }
161+ );
124162
125163 auto format = (b::format (" I:%1%" ) % registerValues.size ()).str ();
126164 dimService = std::make_unique<DimService>(mDescription .dnsName .c_str (), format.c_str (), registerValues.data (),
127165 registerValues.size ());
128-
129- getInfoLogger () << " Starting publisher '" << mDescription .dnsName << " ' with "
130- << mDescription .addresses .size () << " address(es) at interval "
131- << mDescription .interval .count () << " ms" << endm;
132166 }
133167
134168 ~Service ()
135169 {
136170 getInfoLogger () << " Stopping publisher '" << mDescription .dnsName << " '" << endm;
137171 }
138172
139- void updateRegisterValues (RegisterReadWriteInterface & channel)
173+ void updateValues (BarInterface & channel)
140174 {
141175 getInfoLogger () << " Updating '" << mDescription .dnsName << " ':" << endm;
142- for (size_t i = 0 ; i < mDescription .addresses .size (); ++i) {
143- auto index = mDescription .addresses [i] / 4 ;
144- auto value = channel.readRegister (index);
145- getInfoLogger () << " " << mDescription .addresses [i] << " = " << value << endm;
146- registerValues.at (i) = channel.readRegister (index);
147- }
176+
177+ Visitor::apply (mDescription .type ,
178+ [&](const ServiceDescription::Register& type){
179+ for (size_t i = 0 ; i < type.addresses .size (); ++i) {
180+ auto index = type.addresses [i] / 4 ;
181+ auto value = channel.readRegister (index);
182+ getInfoLogger () << " " << type.addresses [i] << " = " << value << endm;
183+ registerValues.at (i) = channel.readRegister (index);
184+ }
185+ },
186+ [&](const ServiceDescription::Sca& type){
187+ auto sca = Sca (channel, channel.getCardType ());
188+
189+ for (size_t i = 0 ; i < type.commandDataPairs .size (); ++i) {
190+ const auto & pair = type.commandDataPairs [i];
191+ sca.write (pair.first , pair.second );
192+ if (i+1 == type.commandDataPairs .size ()) {
193+ // Last one, we do a read. This result is published.
194+ auto result = sca.read ();
195+ registerValues.at (0 ) = channel.readRegister (result.data );
196+ }
197+ }
198+ }
199+ );
200+
148201 dimService->updateService ();
149202 }
150203
@@ -278,6 +331,8 @@ class ProgramAliceLowlevelFrontendServer: public AliceO2::Common::Program
278331 }
279332
280333 publisherRegistry.loop ();
334+
335+ // Dummy service. Temporary.
281336 mTemperature = double ((std::rand () % 100 ) + 400 ) / 10.0 ;
282337 temperatureService.updateService (mTemperature );
283338 }
@@ -338,7 +393,7 @@ class ProgramAliceLowlevelFrontendServer: public AliceO2::Common::Program
338393 auto params = split (parameter, " ;" );
339394
340395 ServiceDescription description;
341- description.addresses = lexicalCastVector<uintptr_t >(split (params.at (1 ), " ," ));
396+ description.type = ServiceDescription::Register{ lexicalCastVector<uintptr_t >(split (params.at (1 ), " ," ))} ;
342397 description.dnsName = params.at (0 );
343398 description.interval = std::chrono::milliseconds (int64_t (b::lexical_cast<double >(params.at (2 )) * 1000.0 ));
344399
@@ -358,13 +413,15 @@ class ProgramAliceLowlevelFrontendServer: public AliceO2::Common::Program
358413 return " " ;
359414 }
360415
416+ // / RPC handler for SCA read commands
361417 static std::string scaRead (const std::string&, ChannelSharedPtr bar2)
362418 {
363419 getInfoLogger () << " SCA_READ" << endm;
364420 auto result = Sca (*bar2, bar2->getCardType ()).read ();
365421 return (b::format (" 0x%x,0x%x" ) % result.command % result.data ).str ();
366422 }
367423
424+ // / RPC handler for SCA write commands
368425 static std::string scaWrite (const std::string& parameter, ChannelSharedPtr bar2)
369426 {
370427 getInfoLogger () << " SCA_WRITE: '" << parameter << " '" << endm;
@@ -375,13 +432,15 @@ class ProgramAliceLowlevelFrontendServer: public AliceO2::Common::Program
375432 return " " ;
376433 }
377434
435+ // / RPC handler for SCA GPIO read commands
378436 static std::string scaGpioRead (const std::string&, ChannelSharedPtr bar2)
379437 {
380438 getInfoLogger () << " SCA_GPIO_READ" << endm;
381439 auto result = Sca (*bar2, bar2->getCardType ()).gpioRead ();
382440 return (b::format (" 0x%x" ) % result.data ).str ();
383441 }
384442
443+ // / RPC handler for SCA GPIO write commands
385444 static std::string scaGpioWrite (const std::string& parameter, ChannelSharedPtr bar2)
386445 {
387446 getInfoLogger () << " SCA_GPIO_WRITE: '" << parameter << " '" << endm;
@@ -390,6 +449,7 @@ class ProgramAliceLowlevelFrontendServer: public AliceO2::Common::Program
390449 return " " ;
391450 }
392451
452+ // / RPC handler for SCA blob write commands (sequence of commands)
393453 static std::string scaBlobWrite (const std::string& parameter, ChannelSharedPtr bar2)
394454 {
395455 getInfoLogger () << " SCA_BLOB_WRITE size=" << parameter.size () << " bytes" << endm;
0 commit comments