Newer
Older
/*
* FeedingFanOut.h
*
* Created on: Jun 15, 2016
* Author: Martin Hierholzer
*/
#ifndef CHIMERATK_FEEDING_FAN_OUT_H
#define CHIMERATK_FEEDING_FAN_OUT_H
#include <ChimeraTK/NDRegisterAccessor.h>
#include "FanOut.h"
namespace ChimeraTK {
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
/**
* NDRegisterAccessor implementation which distributes values written to this
* accessor out to any number of slaves.
*/
template <typename UserType>
class FeedingFanOut : public FanOut<UserType>,
public ChimeraTK::NDRegisterAccessor<UserType> {
public:
FeedingFanOut(std::string const &name, std::string const &unit,
std::string const &description, size_t numberOfElements,
bool withReturn)
: FanOut<UserType>(
boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>>()),
ChimeraTK::NDRegisterAccessor<UserType>("FeedingFanOut:" + name, unit,
description),
_withReturn(withReturn) {
ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D.resize(1);
ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0].resize(
numberOfElements);
}
/** Add a slave to the FanOut. Only sending end-points of a consuming node may
* be added. */
void
addSlave(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> slave,
VariableNetworkNode &) override {
// check if array shape is compatible, unless the receiver is a trigger
// node, so no data is expected
if (slave->getNumberOfSamples() != 0 &&
(slave->getNumberOfChannels() != 1 ||
slave->getNumberOfSamples() != this->getNumberOfSamples())) {
std::string what = "FeedingFanOut::addSlave(): Trying to add a slave '" +
slave->getName();
what += "' with incompatible array shape! Name of fan out: '" +
this->getName() + "'";
throw ChimeraTK::logic_error(what.c_str());
}
// make sure slave is writeable
if (!slave->isWriteable()) {
throw ChimeraTK::logic_error("FeedingFanOut::addSlave() has been called "
"with a receiving implementation!");
}
// handle return channels
if (_withReturn) {
if (slave->isReadable()) {
if (_hasReturnSlave) {
throw ChimeraTK::logic_error(
"FeedingFanOut: Cannot add multiple slaves with return channel!");
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
_hasReturnSlave = true;
_returnSlave = slave;
}
}
// add the slave
FanOut<UserType>::slaves.push_back(slave);
}
bool isReadable() const override { return _withReturn; }
bool isReadOnly() const override { return false; }
bool isWriteable() const override { return true; }
void doReadTransfer() override {
if (!_withReturn)
throw ChimeraTK::logic_error(
"Read operation called on write-only variable.");
_returnSlave->doReadTransfer();
}
bool doReadTransferNonBlocking() override {
if (!_withReturn)
throw ChimeraTK::logic_error(
"Read operation called on write-only variable.");
return _returnSlave->doReadTransferNonBlocking();
}
bool doReadTransferLatest() override {
if (!_withReturn)
throw ChimeraTK::logic_error(
"Read operation called on write-only variable.");
return _returnSlave->doReadTransferLatest();
}
void doPreRead() override {
if (!_withReturn)
throw ChimeraTK::logic_error(
"Read operation called on write-only variable.");
_returnSlave->accessChannel(0).swap(
ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0]);
_returnSlave->preRead();
}
void doPostRead() override {
if (!_withReturn)
throw ChimeraTK::logic_error(
"Read operation called on write-only variable.");
assert(_hasReturnSlave);
_returnSlave->postRead();
_returnSlave->accessChannel(0).swap(
ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0]);
// distribute return-channel update to the other slaves
for (auto &slave : FanOut<UserType>::slaves) { // send out copies to slaves
if (slave == _returnSlave)
continue;
if (slave->getNumberOfSamples() !=
0) { // do not send copy if no data is expected (e.g. trigger)
slave->accessChannel(0) =
ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0];
}
slave->write(_returnSlave->getVersionNumber());
}
}
ChimeraTK::TransferFuture doReadTransferAsync() override {
if (!_withReturn)
throw ChimeraTK::logic_error(
"Read operation called on write-only variable.");
return {_returnSlave->doReadTransferAsync(), this};
}
void doPreWrite() override {
for (auto &slave : FanOut<UserType>::slaves) { // send out copies to slaves
if (slave->getNumberOfSamples() !=
0) { // do not send copy if no data is expected (e.g. trigger)
if (slave ==
FanOut<UserType>::slaves
.front()) { // in case of first slave, swap instead of copy
slave->accessChannel(0).swap(
ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0]);
} else { // not the first slave: copy the data from the first slave
slave->accessChannel(0) =
FanOut<UserType>::slaves.front()->accessChannel(0);
Martin Christoph Hierholzer
committed
}
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
}
// pre write may only be called on the target accessors after we have filled
// them all, otherwise the first accessor might take us the data away...
for (auto &slave : FanOut<UserType>::slaves) {
slave->preWrite();
}
}
bool doWriteTransfer(ChimeraTK::VersionNumber versionNumber = {}) override {
bool dataLost = false;
for (auto &slave : FanOut<UserType>::slaves) {
bool ret = slave->doWriteTransfer(versionNumber);
if (ret)
dataLost = true;
}
return dataLost;
}
void doPostWrite() override {
for (auto &slave : FanOut<UserType>::slaves) {
slave->postWrite();
}
FanOut<UserType>::slaves.front()->accessChannel(0).swap(
ChimeraTK::NDRegisterAccessor<UserType>::buffer_2D[0]);
}
bool mayReplaceOther(const boost::shared_ptr<const ChimeraTK::TransferElement>
&) const override {
return false; /// @todo implement properly?
}
std::list<boost::shared_ptr<ChimeraTK::TransferElement>>
getInternalElements() override {
return {}; /// @todo implement properly?
}
std::vector<boost::shared_ptr<ChimeraTK::TransferElement>>
getHardwareAccessingElements() override {
return {boost::enable_shared_from_this<ChimeraTK::TransferElement>::
shared_from_this()}; /// @todo implement properly?
}
void replaceTransferElement(
boost::shared_ptr<ChimeraTK::TransferElement>) override {
// You can't replace anything here. Just do nothing.
/// @todo implement properly?
}
AccessModeFlags getAccessModeFlags() const override {
return {AccessMode::wait_for_new_data};
}
VersionNumber getVersionNumber() const override {
return FanOut<UserType>::slaves.front()->getVersionNumber();
}
boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> getReturnSlave() {
return _returnSlave;
}
protected:
/// Flag whether this FeedingFanOut has a return channel. Is specified in the
/// constructor
bool _withReturn;
/// Used if _withReturn is true: flag whether the corresponding slave with the
/// return channel has already been added.
bool _hasReturnSlave{false};
/// The slave with return channel
boost::shared_ptr<ChimeraTK::NDRegisterAccessor<UserType>> _returnSlave;
};
} /* namespace ChimeraTK */
#endif /* CHIMERATK_FEEDING_FAN_OUT_H */