Move config & control DDS functionality into plugins.

This commit is contained in:
Alexey Rybalchenko
2016-10-19 16:20:40 +02:00
parent 16fd63cd5b
commit da3010b20c
22 changed files with 868 additions and 567 deletions

View File

@@ -0,0 +1,45 @@
################################################################################
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence version 3 (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
set(INCLUDE_DIRECTORIES
${CMAKE_SOURCE_DIR}/fairmq
${CMAKE_SOURCE_DIR}/fairmq/plugins/config
)
set(SYSTEM_INCLUDE_DIRECTORIES
${SYSTEM_INCLUDE_DIRECTORIES}
${Boost_INCLUDE_DIR}
${DDS_INCLUDE_DIR}
)
include_directories(${INCLUDE_DIRECTORIES})
include_directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES})
set(LINK_DIRECTORIES
${LINK_DIRECTORIES}
${Boost_LIBRARY_DIRS}
)
link_directories(${LINK_DIRECTORIES})
set(SRCS
"FairMQDDSConfigPlugin.cxx"
)
set(LIBRARY_NAME FairMQDDSConfigPlugin)
set(DEPENDENCIES
${DEPENDENCIES}
FairMQ
pthread
${DDS_INTERCOM_LIBRARY_SHARED}
${DDS_PROTOCOL_LIBRARY_SHARED}
${DDS_USER_DEFAULTS_LIBRARY_SHARED}
)
GENERATE_LIBRARY()

View File

@@ -0,0 +1,186 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include "dds_intercom.h"
#include "FairMQConfigPlugin.h"
#include "FairMQLogger.h"
#include "FairMQDevice.h"
#include "FairMQChannel.h"
#include <vector>
#include <map>
#include <string>
#include <exception>
#include <unordered_map>
using namespace std;
using namespace dds::intercom_api;
// container to hold channel config and corresponding dds key values
struct DDSConfig
{
DDSConfig()
: subChannels()
, ddsValues()
{}
// container of sub channels, e.g. 'i' in data[i]
vector<FairMQChannel*> subChannels;
// dds values for the channel
unordered_map<string, string> ddsValues;
};
class FairMQConfigPluginDDS
{
public:
static FairMQConfigPluginDDS* GetInstance()
{
if (fInstance == NULL)
{
fInstance = new FairMQConfigPluginDDS();
}
return fInstance;
}
static void ResetInstance()
{
try
{
delete fInstance;
fInstance = NULL;
}
catch (exception& e)
{
LOG(ERROR) << "Error: " << e.what() << endl;
return;
}
}
void Init(FairMQDevice& device)
{
for (auto& mi : device.fChannels)
{
if ((mi.second).at(0).GetMethod() == "bind")
{
for (auto& vi : mi.second)
{
fBindingChans.push_back(&vi);
}
}
else if ((mi.second).at(0).GetMethod() == "connect")
{
// try some trickery with forwarding emplacing values into map
fConnectingChans.emplace(piecewise_construct, forward_as_tuple(mi.first), forward_as_tuple());
LOG(DEBUG) << "preparing to connect: " << (mi.second).at(0).GetChannelPrefix() << " with " << mi.second.size() << " sockets.";
for (auto& vi : mi.second)
{
fConnectingChans.at(mi.first).subChannels.push_back(&vi);
}
}
else
{
LOG(ERROR) << "Cannot update address configuration. Socket method (bind/connect) not specified.";
return;
}
}
if (fConnectingChans.size() > 0)
{
LOG(DEBUG) << "Subscribing for DDS properties.";
fDDSKeyValue.subscribe([&] (const string& propertyId, const string& key, const string& value)
{
LOG(DEBUG) << "Received update for " << propertyId << ": key=" << key << " value=" << value;
fConnectingChans.at(propertyId).ddsValues.insert(make_pair<string, string>(key.c_str(), value.c_str()));
// update channels and remove them from unfinished container
for (auto mi = fConnectingChans.begin(); mi != fConnectingChans.end(); /* no increment */)
{
if (mi->second.subChannels.size() == mi->second.ddsValues.size())
{
auto it = mi->second.ddsValues.begin();
for (unsigned int i = 0; i < mi->second.subChannels.size(); ++i)
{
mi->second.subChannels.at(i)->UpdateAddress(it->second);
++it;
}
// when multiple subChannels are used, their order on every device should be the same, irregardless of arrival order from DDS.
device.SortChannel(mi->first);
fConnectingChans.erase(mi++);
}
else
{
++mi;
}
}
});
}
}
void Run(FairMQDevice& device)
{
// start DDS intercom service
fService.start();
// publish bound addresses via DDS at keys corresponding to the channel prefixes, e.g. 'data' in data[i]
for (const auto& i : fBindingChans)
{
LOG(DEBUG) << "Publishing " << i->GetChannelPrefix() << " address to DDS under '" << i->GetChannelPrefix() << "' property name.";
fDDSKeyValue.putValue(i->GetChannelPrefix(), i->GetAddress());
}
}
private:
FairMQConfigPluginDDS()
: fService()
, fDDSKeyValue(fService)
, fBindingChans()
, fConnectingChans()
{
fService.subscribeOnError([](EErrorCode errorCode, const string& msg) {
LOG(ERROR) << "DDS key-value error code: " << errorCode << ", message: " << msg;
});
}
static FairMQConfigPluginDDS* fInstance;
CIntercomService fService;
CKeyValue fDDSKeyValue;
// container for binding channels
vector<FairMQChannel*> fBindingChans;
// container for connecting channels
map<string, DDSConfig> fConnectingChans;
};
FairMQConfigPluginDDS* FairMQConfigPluginDDS::fInstance = NULL;
void initConfig(FairMQDevice& device)
{
FairMQConfigPluginDDS::GetInstance()->Init(device);
}
/// Handles channels addresses of the device with configuration from DDS
/// Addresses of binding channels are published via DDS using channels names as keys
/// Addresses of connecting channels are collected from DDS using channels names as keys
/// \param device Reference to FairMQDevice whose channels to handle
void handleInitialConfig(FairMQDevice& device)
{
FairMQConfigPluginDDS::GetInstance()->Run(device);
}
void stopConfig()
{
LOG(DEBUG) << "[FairMQConfigPluginDDS]: " << "Resetting instance.";
FairMQConfigPluginDDS::ResetInstance();
LOG(DEBUG) << "[FairMQConfigPluginDDS]: " << "Instance has been reset.";
}
FairMQConfigPlugin fairmqConfigPlugin = { initConfig, handleInitialConfig, stopConfig };

View File

@@ -0,0 +1,7 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/

View File

@@ -0,0 +1,65 @@
################################################################################
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence version 3 (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
set(INCLUDE_DIRECTORIES
${CMAKE_SOURCE_DIR}/fairmq
${CMAKE_SOURCE_DIR}/fairmq/plugins/control
)
set(SYSTEM_INCLUDE_DIRECTORIES
${SYSTEM_INCLUDE_DIRECTORIES}
${Boost_INCLUDE_DIR}
${DDS_INCLUDE_DIR}
)
include_directories(${INCLUDE_DIRECTORIES})
include_directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES})
set(LINK_DIRECTORIES
${LINK_DIRECTORIES}
${Boost_LIBRARY_DIRS}
)
link_directories(${LINK_DIRECTORIES})
set(SRCS
"FairMQDDSControlPlugin.cxx"
)
set(LIBRARY_NAME FairMQDDSControlPlugin)
set(DEPENDENCIES
${DEPENDENCIES}
FairMQ
pthread
${DDS_INTERCOM_LIBRARY_SHARED}
${DDS_PROTOCOL_LIBRARY_SHARED}
${DDS_USER_DEFAULTS_LIBRARY_SHARED}
)
GENERATE_LIBRARY()
set(Exe_Names
fairmq-dds-command-ui
)
set(Exe_Source
../../run/runDDSCommandUI.cxx
)
list(LENGTH Exe_Names _length)
math(EXPR _length ${_length}-1)
foreach(_file RANGE 0 ${_length})
list(GET Exe_Names ${_file} _name)
list(GET Exe_Source ${_file} _src)
set(EXE_NAME ${_name})
set(SRCS ${_src})
set(DEPENDENCIES FairMQ pthread ${DDS_INTERCOM_LIBRARY_SHARED} ${DDS_PROTOCOL_LIBRARY_SHARED} ${DDS_USER_DEFAULTS_LIBRARY_SHARED})
GENERATE_EXECUTABLE()
endforeach(_file RANGE 0 ${_length})

View File

@@ -0,0 +1,163 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include "dds_intercom.h"
#include "FairMQControlPlugin.h"
#include "FairMQLogger.h"
#include "FairMQDevice.h"
#include <string>
#include <exception>
#include <condition_variable>
#include <mutex>
#include <chrono>
using namespace std;
using namespace dds::intercom_api;
class FairMQControlPluginDDS
{
public:
static FairMQControlPluginDDS* GetInstance()
{
if (fInstance == NULL)
{
fInstance = new FairMQControlPluginDDS();
}
return fInstance;
}
static void ResetInstance()
{
try
{
delete fInstance;
fInstance = NULL;
}
catch (exception& e)
{
LOG(ERROR) << "Error: " << e.what() << endl;
return;
}
}
void Init(FairMQDevice& device)
{
string id = device.GetProperty(FairMQDevice::Id, "");
string pid(to_string(getpid()));
try
{
fDDSCustomCmd.subscribe([id, pid, &device, this](const string& cmd, const string& cond, uint64_t senderId)
{
LOG(INFO) << "Received command: " << cmd;
if (cmd == "check-state")
{
fDDSCustomCmd.send(id + ": " + device.GetCurrentStateName() + " (pid: " + pid + ")", to_string(senderId));
}
else if (fEvents.find(cmd) != fEvents.end())
{
fDDSCustomCmd.send(id + ": attempting to " + cmd, to_string(senderId));
device.ChangeState(cmd);
}
else if (cmd == "END")
{
fDDSCustomCmd.send(id + ": attempting to " + cmd, to_string(senderId));
device.ChangeState(cmd);
fDDSCustomCmd.send(id + ": " + device.GetCurrentStateName(), to_string(senderId));
if (device.GetCurrentStateName() == "EXITING")
{
unique_lock<mutex> lock(fMtx);
fStopCondition.notify_one();
}
}
else
{
LOG(WARN) << "Unknown command: " << cmd;
LOG(WARN) << "Origin: " << senderId;
LOG(WARN) << "Destination: " << cond;
}
});
}
catch (exception& e)
{
LOG(ERROR) << "Error: " << e.what() << endl;
return;
}
}
void Run(FairMQDevice& device)
{
try
{
fService.start();
LOG(INFO) << "Listening for commands from DDS...";
unique_lock<mutex> lock(fMtx);
while (!device.Terminated())
{
fStopCondition.wait_for(lock, chrono::seconds(1));
}
LOG(DEBUG) << "Stopping DDS control plugin";
}
catch (exception& e)
{
LOG(ERROR) << "Error: " << e.what() << endl;
return;
}
}
private:
FairMQControlPluginDDS()
: fService()
, fDDSCustomCmd(fService)
, fMtx()
, fStopCondition()
, fEvents({ "INIT_DEVICE", "INIT_TASK", "PAUSE", "RUN", "STOP", "RESET_TASK", "RESET_DEVICE" })
{
fService.subscribeOnError([](const EErrorCode errorCode, const string& errorMsg) {
LOG(ERROR) << "Error received: error code: " << errorCode << ", error message: " << errorMsg << endl;
});
}
static FairMQControlPluginDDS* fInstance;
CIntercomService fService;
CCustomCmd fDDSCustomCmd;
mutex fMtx;
condition_variable fStopCondition;
const set<string> fEvents;
};
FairMQControlPluginDDS* FairMQControlPluginDDS::fInstance = NULL;
void initControl(FairMQDevice& device)
{
FairMQControlPluginDDS::GetInstance()->Init(device);
}
/// Controls device state via DDS custom commands interface
/// \param device Reference to FairMQDevice whose state to control
void handleStateChanges(FairMQDevice& device)
{
FairMQControlPluginDDS::GetInstance()->Run(device);
}
void stopControl()
{
LOG(DEBUG) << "[FairMQControlPluginDDS]: " << "Resetting instance.";
FairMQControlPluginDDS::ResetInstance();
LOG(DEBUG) << "[FairMQControlPluginDDS]: " << "Instance has been reset.";
}
FairMQControlPlugin fairmqControlPlugin = { initControl, handleStateChanges, stopControl };

View File

@@ -0,0 +1,7 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/