Skip to content
Snippets Groups Projects
Unverified Commit 468fc9ed authored by zenker's avatar zenker Committed by GitHub
Browse files

improve history module

* Use templated version to add a trigger.

A trigger is needed for Poll type inputs. Still it can not be used for
Devices. Here one has to call addSource manually.

* No need to use a trigger. Fix connections by moving all to history.

Trigger is only needed for DeviceModules. So in case of device addSource
still needs to be used, because no tags are present for devices.

* Add option to specify the directory where history will appear in CS.

* Remove CS tag not needed any more.

* Update documentation.

* Update documentation of logging module.

* Remove CS tag not needed any more.

* Remove parameter not needed. AddSource for ConnectingDeviceModule. Docu.
parent 67b413fd
No related branches found
No related tags found
No related merge requests found
......@@ -8,32 +8,27 @@
* \page loggingdoc Logging module and Logger
* \section loggingintro Introduction to the logging mechanism
* The logging provided here requires to add the LoggingModule to your
Application.
* The module introduces the following input variables, that need to be
connected to the control system:
* Application.
* The module introduces the following input variables:
* - targetStream: Allows to choose where messages send to the logging module
end up:
* end up:
* - 0: cout/cerr+logfile
* - 1: logfile
* - 2: cout/cerr
* - 3: controlsystem only
* - 4: nowhere
* - logFile: Give the logfile name. If the file is not empty logging messages
will be appended. If
* you choose targetStream 0 or 1 and don't set a logFile the Logging module
simply skips the file
* writing.
* will be appended. If you choose targetStream 0 or 1 and don't set a logFile
* the Logging module simply skips the file writing.
* - logLevel: Choose a certain logging level of the Module. Messages send to
the Logging module also include a logging
* level. The Logging module compares both levels and decides if a message is
dropped (e.g. message level is
* DEBUG and Module level is ERROR) or broadcasted.
* the Logging module also include a logging level.
* The Logging module compares both levels and decides if a message is
* dropped (e.g. message level is DEBUG and Module level is ERROR) or broadcasted.
* - maxTailLength: The number of messages published by the Logging module (see
logTail), i.e. to the control system. If set to 0 the number of messages defaults to 20.
* logTail), i.e. to the control system. If set to 0 the number of messages defaults to 20.
* This length has no influence on the targetStreams, that receive all
messages (depending on the logLevel). The
* logLevel also applies to messages that are published by the Logging module
via the logTail
* messages (depending on the logLevel). The logLevel also applies to messages
* that are published by the Logging module via the logTail
*
* Available logging levels are:
* - DEBUG
......@@ -43,15 +38,21 @@
* - SILENT
*
* The only variable that is published by the Logging module is the logTail. It
contains the list of latest messages.
* contains the list of latest messages.
* Messages are separated by a newline character. The number of messages
published in the logTail is set via the
* published in the logTail is set via the
* input variable tailLength. Other than that, messages are written to
cout/cerr and/or a log file as explained above.
* cout/cerr and/or a log file as explained above.
*
* A Logger class is used to send messages to the LoggingModule.
* The foreseen way of using the Logger is to add a Logger to a module that
should send log messages.
* should send log messages.
* The Logger adds two variables that will be available in the control system:
* - alias: It can be set at runtime and will be used as prefix in messages of that particular
* Logger. If it is set empty the name of the owning module is used.
* - message: This is the message send to the LoggingModule. It includes the severity encoded
* as number in the first character of the string followed by the message.
*
*
* The LoggingModule will take care of finding all Loggers.
* Therefore, the LoggingModule needs to be constructed last - after all ApplicationModules
......@@ -71,8 +72,6 @@
* };
* struct myApp : public ChimeraTK::Application{
*
*
* ChimeraTK::ControlSystemModule cs;
*
* TestModule { this, "test", "" };
*
......@@ -82,12 +81,6 @@
* ...
* };
*
*
* void myAPP::defineConnctions(){
* log.findTag("CS").connectTo(cs);
* ...
* }
*
* void TestModule::mainLoop{
* logger.sendMessage("Test",LogLevel::DEBUG);
* ...
......@@ -225,13 +218,6 @@ namespace logging {
ctk::RegisterPath prepareHierarchy(const ctk::RegisterPath& namePrefix);
struct MessageSource {
/*
* Instead of constructing msg variables with name id and connecting it directly to
* to the message variable of the Logger one could have a variable group here that holds
* the variables message and alias. The variable group name is the id and it is moved
* the correct location in the CS in order to achieve an automatic direct connection when
* the CS is build. Use a ctk::HierarchyModifyingGroup to do that.
*/
struct Data : ctk::HierarchyModifyingGroup {
using ctk::HierarchyModifyingGroup::HierarchyModifyingGroup;
ctk::ScalarPushInput<std::string> msg{this, "message", "", "", {"_logging_internal"}};
......@@ -279,13 +265,11 @@ namespace logging {
{"CS", getName()}};
ctk::ScalarPollInput<uint> tailLength{this, "maxTailLength", "",
"Maximum number of messages to be shown in the logging stream tail. 0 is treated as 20.", {"CS", getName()}};
"Maximum number of messages to be shown in the logging stream tail. 0 is treated as 20.", {getName()}};
ctk::ScalarPollInput<uint> logLevel{
this, "logLevel", "", "Current log level used for messages.", {"CS", getName()}};
ctk::ScalarPollInput<uint> logLevel{this, "logLevel", "", "Current log level used for messages.", {getName()}};
ctk::ScalarOutput<std::string> logTail{
this, "logTail", "", "Tail of the logging stream.", {"CS", "PROCESS", getName()}};
ctk::ScalarOutput<std::string> logTail{this, "logTail", "", "Tail of the logging stream.", {"PROCESS", getName()}};
std::unique_ptr<std::ofstream> file; ///< Log file where to write log messages
......
......@@ -28,12 +28,19 @@
* and the element index i is appended to the feeding process variable name. In
* consequence an input array of length i will result in i output history
* arrays. The following tags are added to the history output variable:
* - CS
* - name of the history module
*
* It is also possible to connect a DeviceModule to the ServerHistory module. This
* requires a trigger, which is given as optional parameter to the \c addSource
* method. If the device variables are writable they are of push type. In this case
* The connection of variables with the 'history' tag to the ServerHistory module is
* done automatically.
* \attention Only variables of modules defined before constructing the ServerHistory
* module are considered.
*
* It is also possible to connect a DeviceModule to the ServerHistory module.
* Variables of Devices have no tags and therefor they will not be automatically connected
* to the SereverHistory module. One has to call addSource().
* In addition a trigger in case the variables are not push type. It is given as optional
* parameter to the \c addSource method.
* If the device variables are writable they are of push type. In this case
* the trigger will not be added. One has to use the LogicalNameMapping backend to
* force the device variables to be read only by using the \c forceReadOnly plugin.
* Using the LogicalNameMapping backend also allows to select individual device
......@@ -44,7 +51,7 @@
* \code
* sruct TestModule: public ChimeraTK::ApplicationModule{
* chimeraTK::ScalarOutput<float> measurement{this, "measurement", "" ,
* "measurement variable", {"CS", History"}};
* "measurement variable", {"history"}};
* ...
* };
* struct myApp : public ChimeraTK::Application{
......@@ -54,7 +61,7 @@
*
* ChimeraTK::ControlSystemModule cs;
*
* ChimeraTK::DeviceModule dev{this, "Dummy"};
* ChimeraTK::ConnectingDeviceModule dev{this, "Dummy", "Trigger/tick"};
*
* ChimeraTK::PeriodicTrigger trigger{this, "Trigger", "Trigger used for other modules"};
*
......@@ -64,15 +71,12 @@
* };
*
*
* void myAPP::defineConnctions(){
* // connect a module with variables that are updated by the module, which
* // triggers an update of the history buffer
* history.addSource(test.findTag("History"), "history" + test->getName())
* // will show up in the control system as history/test/measurement
* // add a device. Updating of the history buffer is trigger external by the given trigger
* history.addSource(dev,"device_history",trigger.tick);
*
* history.findTag("CS").connectTo(cs);
* void myAPP::intitialise(){
* // The variable of the TestModule will show up in the control system as history/test/measurement automatically
* (identified by the tag).
* // Add a device. Updating of the history buffer is trigger external by the given trigger
* history.addSource(&dev,"device_history",trigger.tick);
* ChimeraTK::Application::initialise();
* ...
* }
*
......@@ -92,6 +96,7 @@
#include <ChimeraTK/SupportedUserTypes.h>
#include <string>
#include <tuple>
#include <vector>
......@@ -109,7 +114,8 @@ namespace ChimeraTK { namespace history {
bool withTimeStamps;
};
struct ServerHistory : public ApplicationModule {
class ServerHistory : public ApplicationModule {
public:
/**
* Constructor.
* Addition parameters to a normal application module constructor:
......@@ -117,55 +123,56 @@ namespace ChimeraTK { namespace history {
* \param name Module name passed to ApplicationModule constructor.
* \param description Module description passed to ApplicationModule constructor.
* \param historyLength Length of the history buffers.
* \param enableTimeStamps An additional ring buffer per variable will be added that holds the time stamps
* corresponding to the data ring buffer entries.
* \param eliminateHierarchy Flag passed to ApplicationModule constructor.
* \param enableTimeStamps An additional
* ring buffer per variable will be added that holds the time stamps corresponding to the data ring buffer entries.
* \param hierarchyModifier Flag passed to ApplicationModule constructor.
* \param tags Module tags passed to ApplicationModule constructor.
*/
ServerHistory(EntityOwner* owner, const std::string& name, const std::string& description,
size_t historyLength = 1200, bool enableTimeStamps = false, bool eliminateHierarchy = false,
const std::unordered_set<std::string>& tags = {})
: ApplicationModule(owner, name, description, eliminateHierarchy, tags), _historyLength(historyLength),
_enbaleTimeStamps(enableTimeStamps) {}
size_t historyLength = 1200, bool enableTimeStamps = false,
HierarchyModifier hierarchyModifier = HierarchyModifier::none,
const std::unordered_set<std::string>& tags = {});
/** Default constructor, creates a non-working module. Can be used for late
* initialisation. */
ServerHistory() : _historyLength(1200), _enbaleTimeStamps(false) {}
/**
* Add a Module as a source to this History module.
* Ad variables of a device to the ServerHistory. Calls virtualiseFromCatalog to get access to the internal variables.
*
* \param source For all variables of this module ring buffers are created. Use \c findTag in combination
* with a dedicated history tag. In case device modules use the LogicalNameMapping to create
* a virtual device module that holds all variables that should be passed to the history module.
* \param source For all variables of this module ring buffers are created.
* Use the LogicalNameMapping to create a virtual device module that holds all variables that should be
* passed to the history module.
* \param namePrefix This prefix is added to variable names added to the root directory in the process variable
* tree. E.g. a prefix \c history for a variable names data will appear as history/dummy/data
* if dummy is the name of the source module.
* tree. E.g. a prefix \c history for a variable names data will appear as history/dummy/data
* if dummy is the name of the source module.
* \param submodule If only a submodule should be added give the name.
* It does not work do create a submodule of the DeviceModule itself!
* \param trigger This trigger is used for all poll type variable found in the source module.
*
*/
void addSource(const Module& source, const RegisterPath& namePrefix, const VariableNetworkNode& trigger = {});
void addSource(const DeviceModule& source, const RegisterPath& namePrefix, const std::string& submodule = "",
const VariableNetworkNode& trigger = {});
/**
* Overload that calls virtualiseFromCatalog. Parameter see addSource(const Module&...)
*
* \param source See the other addSource() overload.
*
* \param namePrefix See the other addSource() overload.
*
* \param submodule If only a submodule should be added give the name. It does not work do create a submodule of the
* DeviceModule itself!
*
* \param trigger See the other addSource() overload.
* Just gets the device module from the ConnectingDeviceModule before calling the DeviceModule version of addSource.
*/
void addSource(const DeviceModule& source, const RegisterPath& namePrefix, const std::string& submodule = "",
void addSource(ConnectingDeviceModule* source, const RegisterPath& namePrefix, const std::string& submodule = "",
const VariableNetworkNode& trigger = {});
public:
void prepare() override;
void mainLoop() override;
protected:
void findTagAndAppendToModule(VirtualModule& virtualParent, const std::string& tag, bool eliminateAllHierarchies,
bool eliminateFirstHierarchy, bool negate, VirtualModule& root) const override;
private:
void prepareHierarchy(const RegisterPath& namePrefix);
/**
* See public method for documentation.
*/
void addSource(const Module& source, const RegisterPath& namePrefix, const VariableNetworkNode& trigger = {});
template<typename UserType>
VariableNetworkNode getAccessor(const std::string& variableName, const size_t& nElements);
......@@ -197,5 +204,4 @@ namespace ChimeraTK { namespace history {
friend struct AccessorAttacher;
};
}} // namespace ChimeraTK::history
......@@ -33,12 +33,40 @@ namespace ChimeraTK { namespace history {
const std::string& _name;
};
void ServerHistory::addSource(
const Module& source, const RegisterPath& namePrefix, const VariableNetworkNode& trigger) {
// for simplification, first create a VirtualModule containing the correct
// hierarchy structure (obeying eliminate hierarchy etc.)
auto dynamicModel = source.findTag(".*"); /// @todo use virtualise() instead
ServerHistory::ServerHistory(EntityOwner* owner, const std::string& name, const std::string& description,
size_t historyLength, bool enableTimeStamps, HierarchyModifier hierarchyModifier,
const std::unordered_set<std::string>& tags)
: ApplicationModule(owner, name, description, hierarchyModifier, tags), _historyLength(historyLength),
_enbaleTimeStamps(enableTimeStamps) {
auto virtualLogging = getOwner()->findTag("history");
auto list = virtualLogging.getAccessorListRecursive();
size_t accessors = 0;
for(auto it = list.begin(); it != list.end(); ++it) {
// do not add the module itself
if(it->getOwningModule() == this) continue;
try {
// virtualLogging.getQualifiedName() returns the name of the app, e.g. /test and we remove that from the module
// name , e.g. /test/MyModule
auto namePrefix =
it->getOwningModule()->getQualifiedName().substr(virtualLogging.getQualifiedName().length() + 1);
prepareHierarchy(namePrefix);
boost::fusion::for_each(_accessorListMap.table, AccessorAttacher(*it, this, namePrefix / it->getName(), {}));
accessors++;
}
catch(ChimeraTK::logic_error& e) {
std::cerr << "Failed to add history variable: " << it->getQualifiedName() << " Error: " << e.what()
<< std::endl;
}
}
if(accessors == 0) {
throw logic_error("No accessors for ServerHistory found. Did you use the tag 'history' for any variable?");
}
else {
std::cout << "Added " << accessors << " accessors to the ServerHistory Module." << std::endl;
}
}
void ServerHistory::prepareHierarchy(const RegisterPath& namePrefix) {
// create variable group map for namePrefix if needed
if(groupMap.find(namePrefix) == groupMap.end()) {
// search for existing parent (if any)
......@@ -58,6 +86,15 @@ namespace ChimeraTK { namespace history {
groupMap[parentPrefix] = VariableGroup(owner, std::string(name).substr(1), "");
}
}
}
void ServerHistory::addSource(
const Module& source, const RegisterPath& namePrefix, const VariableNetworkNode& trigger) {
// for simplification, first create a VirtualModule containing the correct
// hierarchy structure (obeying eliminate hierarchy etc.)
auto dynamicModel = source.findTag(".*"); /// @todo use virtualise() instead
prepareHierarchy(namePrefix);
// add all accessors on this hierarchy level
for(auto& acc : dynamicModel.getAccessorList()) {
......@@ -79,6 +116,11 @@ namespace ChimeraTK { namespace history {
addSource(mod.submodule(submodule), namePrefix, trigger);
}
void ServerHistory::addSource(ConnectingDeviceModule* source, const RegisterPath& namePrefix,
const std::string& submodule, const VariableNetworkNode& trigger) {
addSource(source->getDeviceModule(), namePrefix, submodule, trigger);
}
template<typename UserType>
VariableNetworkNode ServerHistory::getAccessor(const std::string& variableName, const size_t& nElements) {
// check if variable name already registered
......@@ -97,33 +139,28 @@ namespace ChimeraTK { namespace history {
auto dirName = variableName.substr(0, variableName.find_last_of("/"));
auto baseName = variableName.substr(variableName.find_last_of("/") + 1);
tmpList.emplace_back(std::piecewise_construct,
std::forward_as_tuple(ArrayPushInput<UserType>{
&groupMap[dirName],
baseName + "_in",
"",
0,
"",
}),
std::forward_as_tuple(
ArrayPushInput<UserType>{&groupMap[dirName], baseName + "_in", "", 0, "", {"_history_internal"}}),
std::forward_as_tuple(HistoryEntry<UserType>{_enbaleTimeStamps}));
for(size_t i = 0; i < nElements; i++) {
if(nElements == 1) {
// in case of a scalar history only use the variableName
tmpList.back().second.data.emplace_back(
ArrayOutput<UserType>{&groupMap[dirName], baseName, "", _historyLength, "", {"CS", getName()}});
ArrayOutput<UserType>{&groupMap[dirName], baseName, "", _historyLength, "", {getName()}});
if(_enbaleTimeStamps) {
tmpList.back().second.timeStamp.emplace_back(
ArrayOutput<uint64_t>{&groupMap[dirName], baseName + "_timeStamps",
"Time stamps for entries in the history buffer", _historyLength, "", {"CS", getName()}});
"Time stamps for entries in the history buffer", _historyLength, "", {getName()}});
}
}
else {
// in case of an array history append the index to the variableName
tmpList.back().second.data.emplace_back(ArrayOutput<UserType>{
&groupMap[dirName], baseName + "_" + std::to_string(i), "", _historyLength, "", {"CS", getName()}});
&groupMap[dirName], baseName + "_" + std::to_string(i), "", _historyLength, "", {getName()}});
if(_enbaleTimeStamps) {
tmpList.back().second.timeStamp.emplace_back(
ArrayOutput<uint64_t>{&groupMap[dirName], baseName + "_" + std::to_string(i) + "_timeStamps",
"Time stamps for entries in the history buffer", _historyLength, "", {"CS", getName()}});
"Time stamps for entries in the history buffer", _historyLength, "", {getName()}});
}
}
}
......@@ -175,4 +212,26 @@ namespace ChimeraTK { namespace history {
}
}
void ServerHistory::findTagAndAppendToModule(VirtualModule& virtualParent, const std::string& tag,
bool eliminateAllHierarchies, bool eliminateFirstHierarchy, bool negate, VirtualModule& root) const {
// Change behaviour to exclude the auto-generated inputs which are connected to the data sources. Otherwise those
// variables might get published twice to the control system, if findTag(".*") is used to connect the entire
// application to the control system.
// This is a temporary solution. In future, instead the inputs should be generated at the same place in the
// hierarchy as the source variable, and the connetion should not be made by the module itself. This currently would
// be complicated to implement, since it is difficult to find the correct virtual name for the variables.
struct MyVirtualModule : VirtualModule {
using VirtualModule::VirtualModule;
using VirtualModule::findTagAndAppendToModule;
};
MyVirtualModule tempParent("tempRoot", "", ModuleType::ApplicationModule);
MyVirtualModule tempRoot("tempRoot", "", ModuleType::ApplicationModule);
EntityOwner::findTagAndAppendToModule(
tempParent, "_history_internal", eliminateAllHierarchies, eliminateFirstHierarchy, true, tempRoot);
tempParent.findTagAndAppendToModule(virtualParent, tag, false, true, negate, root);
tempRoot.findTagAndAppendToModule(root, tag, false, true, negate, root);
}
}} // namespace ChimeraTK::history
......@@ -62,14 +62,11 @@ struct testApp : public ChimeraTK::Application {
~testApp() override { shutdown(); }
Dummy<UserType> dummy{this, "Dummy", "Dummy module"};
ChimeraTK::history::ServerHistory hist{this, "ServerHistory", "History of selected process variables.", 20};
ChimeraTK::history::ServerHistory hist{this, "history", "History of selected process variables.", 20};
ChimeraTK::ControlSystemModule cs;
void defineConnections() override {
hist.addSource(dummy.findTag("history"), "history/" + dummy.getName());
hist.findTag("CS").connectTo(cs);
dummy.connectTo(cs);
void initialise() override {
Application::initialise();
dumpConnections();
}
};
......@@ -82,14 +79,11 @@ struct testAppArray : public ChimeraTK::Application {
~testAppArray() override { shutdown(); }
DummyArray<UserType> dummy{this, "Dummy", "Dummy module"};
ChimeraTK::history::ServerHistory hist{this, "ServerHistory", "History of selected process variables.", 20};
ChimeraTK::ControlSystemModule cs;
ChimeraTK::history::ServerHistory hist{this, "history", "History of selected process variables.", 20};
void defineConnections() override {
hist.addSource(dummy.findTag("history"), "history/" + dummy.getName());
hist.findTag("CS").connectTo(cs);
dummy.connectTo(cs);
void initialise() override {
Application::initialise();
dumpConnections();
}
};
......@@ -100,18 +94,16 @@ struct testAppDev : public ChimeraTK::Application {
testAppDev() : Application("test") { ChimeraTK::BackendFactory::getInstance().setDMapFilePath("test.dmap"); }
~testAppDev() override { shutdown(); }
ChimeraTK::history::ServerHistory hist{this, "ServerHistory", "History of selected process variables.", 20};
ChimeraTK::DeviceModule dev{this, "Dummy1Mapped"};
ChimeraTK::ConnectingDeviceModule dev{this, "Dummy1Mapped", "/Dummy/out"};
DummyArray<int> dummy{this, "Dummy", "Dummy module"};
ChimeraTK::ControlSystemModule cs;
ChimeraTK::history::ServerHistory hist{this, "history", "History of selected process variables.", 20, false};
void defineConnections() override {
dummy.connectTo(cs);
hist.addSource(dev, "history", "", dummy.out);
hist.findTag("CS").connectTo(cs);
void initialise() override {
hist.addSource(&dev, "", "", dummy.out);
Application::initialise();
dumpConnections();
}
};
......@@ -119,7 +111,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(testScalarHistory, T, test_types) {
std::cout << "testScalarHistory " << typeid(T).name() << std::endl;
testApp<T> app;
ChimeraTK::TestFacility tf;
auto i = tf.getScalar<T>("in");
auto i = tf.getScalar<T>("Dummy/in");
tf.runApplication();
i = 42.;
i.write();
......@@ -143,7 +135,7 @@ BOOST_AUTO_TEST_CASE(testScalarHistoryString) {
std::cout << "testScalarHistoryString" << std::endl;
testApp<std::string> app;
ChimeraTK::TestFacility tf;
auto i = tf.getScalar<std::string>("in");
auto i = tf.getScalar<std::string>("Dummy/in");
tf.runApplication();
i = "42";
i.write();
......@@ -164,16 +156,16 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(testArrayHistory, T, test_types) {
std::cout << "testArrayHistory " << typeid(T).name() << std::endl;
testAppArray<T> app;
ChimeraTK::TestFacility tf;
auto arr = tf.getArray<T>("in");
auto arr = tf.getArray<T>("Dummy/in");
tf.runApplication();
arr[0] = 42.;
arr[1] = 43.;
arr[2] = 44.;
arr.write();
tf.stepApplication();
BOOST_CHECK_EQUAL(tf.readArray<T>("out")[0], 42.0);
BOOST_CHECK_EQUAL(tf.readArray<T>("out")[1], 43.0);
BOOST_CHECK_EQUAL(tf.readArray<T>("out")[2], 44.0);
BOOST_CHECK_EQUAL(tf.readArray<T>("Dummy/out")[0], 42.0);
BOOST_CHECK_EQUAL(tf.readArray<T>("Dummy/out")[1], 43.0);
BOOST_CHECK_EQUAL(tf.readArray<T>("Dummy/out")[2], 44.0);
std::vector<T> v_ref(20);
for(size_t i = 0; i < 3; i++) {
v_ref.back() = 42.0 + i;
......@@ -201,16 +193,16 @@ BOOST_AUTO_TEST_CASE(testArrayHistoryString) {
std::cout << "testArrayHistoryString" << std::endl;
testAppArray<std::string> app;
ChimeraTK::TestFacility tf;
auto arr = tf.getArray<std::string>("in");
auto arr = tf.getArray<std::string>("Dummy/in");
tf.runApplication();
arr[0] = "42";
arr[1] = "43";
arr[2] = "44";
arr.write();
tf.stepApplication();
BOOST_CHECK_EQUAL(tf.readArray<std::string>("out")[0], "42");
BOOST_CHECK_EQUAL(tf.readArray<std::string>("out")[1], "43");
BOOST_CHECK_EQUAL(tf.readArray<std::string>("out")[2], "44");
BOOST_CHECK_EQUAL(tf.readArray<std::string>("Dummy/out")[0], "42");
BOOST_CHECK_EQUAL(tf.readArray<std::string>("Dummy/out")[1], "43");
BOOST_CHECK_EQUAL(tf.readArray<std::string>("Dummy/out")[2], "44");
std::vector<std::string> v_ref(20);
for(size_t i = 0; i < 3; i++) {
v_ref.back() = std::to_string(42 + i);
......@@ -243,7 +235,7 @@ BOOST_AUTO_TEST_CASE(testDeviceHistory) {
dev.write("/FixedPoint/value", 42);
// Trigger the reading of the device
auto i = tf.getScalar<int>("in");
auto i = tf.getScalar<int>("Dummy/in");
BOOST_CHECK(true);
tf.runApplication();
i = 1.;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment