Skip to content

Commit 3eac7b8

Browse files
Added SCA publish RPC
1 parent ced775b commit 3eac7b8

File tree

1 file changed

+75
-15
lines changed

1 file changed

+75
-15
lines changed

src/CommandLineUtilities/AliceLowlevelFrontend/ProgramAliceLowlevelFrontendServer.cxx

Lines changed: 75 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
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)
6576
struct 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

Comments
 (0)