Newer
Older
Martin Christoph Hierholzer
committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
* Application.cc
*
* Created on: Jun 10, 2016
* Author: Martin Hierholzer
*/
#include <string>
#include <thread>
#include <boost/fusion/container/map.hpp>
#include "Application.h"
#include "ApplicationModule.h"
#include "PublishedAccessor.h"
#include "Accessor.h"
using namespace ChimeraTK;
Application *Application::instance = nullptr;
std::mutex Application::instance_mutex;
/*********************************************************************************************************************/
Application::Application() {
std::lock_guard<std::mutex> lock(instance_mutex);
if(instance != nullptr) {
throw std::string("Multiple instances of ChimeraTK::Application cannot be created."); // @todo TODO throw proper exception
}
instance = this;
}
/*********************************************************************************************************************/
void Application::run() {
initialise();
makeConnections();
for(auto module : moduleList) {
module->run();
}
}
/*********************************************************************************************************************/
void Application::connectAccessors(AccessorBase &a, AccessorBase &b) {
if(a.isOutput() && !b.isOutput()) {
connectionMap[&a].push_back(&b);
}
else if(b.isOutput() && !a.isOutput()) {
connectionMap[&b].push_back(&a);
}
else {
throw std::string("Cannot connect accessors with equal direction."); // @todo TODO throw proper exception
}
// @todo TODO check if the input accessor is already in the list of another output accessor
}
/*********************************************************************************************************************/
template<typename UserType>
void Application::publishAccessor(Accessor<UserType> &a, const std::string& name) {
// @todo TODO check if already published and throw an error
// turn around the direction: the PublishedAccessor represents the control-system-side part!
VariableDirection direction;
if(a.getDirection() == VariableDirection::input) {
direction = VariableDirection::output;
}
else {
direction = VariableDirection::input;
}
// first create a PublishedAccessor to represent the control-system-side part, and store it to the list
boost::shared_ptr<AccessorBase> b;
b.reset( new PublishedAccessor<UserType>(name, direction, a.getUnit()) );
publicationList.push_back(b);
// now connect the accessor with the PublishedAccessor
connectAccessors(a, *b);
}
namespace {
// TODO @todo this is copy&paste from SupportedUserTypes.h of DeviceAccess, but with string and 64-bit ints removed
template< template<typename> class TemplateClass >
class TemplateUserTypeMap {
public:
boost::fusion::map<
boost::fusion::pair<int8_t, TemplateClass<int8_t> >,
boost::fusion::pair<uint8_t, TemplateClass<uint8_t> >,
boost::fusion::pair<int16_t, TemplateClass<int16_t> >,
boost::fusion::pair<uint16_t, TemplateClass<uint16_t> >,
boost::fusion::pair<int32_t, TemplateClass<int32_t> >,
boost::fusion::pair<uint32_t, TemplateClass<uint32_t> >,
boost::fusion::pair<float, TemplateClass<float> >,
boost::fusion::pair<double, TemplateClass<double> >
> table;
};
template<typename UserType>
class Application_publishAccessor_instantiator {
public:
Application_publishAccessor_instantiator() : pointerToMember(&Application::publishAccessor<UserType>) {
}
void (Application::*pointerToMember)(Accessor<UserType>&, const std::string&);
};
TemplateUserTypeMap<Application_publishAccessor_instantiator> x;
}
/*********************************************************************************************************************/
void Application::makeConnections() {
// make connections between accessors
for(auto conn : connectionMap) {
// make connection in single target case
if(conn.second.size() == 1 ) {
if(!conn.second.front()->isInitialised()) {
auto pv = conn.first->createProcessVariable();
conn.second.front()->useProcessVariable(pv);
}
else {
auto pv = conn.second.front()->createProcessVariable();
conn.first->useProcessVariable(pv);
}
}
else {
throw std::string("Connecting to multiple inputs is not yet implemented."); // @todo TODO implement
}
}
}
/*********************************************************************************************************************/