ChimeraTK-ApplicationCore 04.06.00
Loading...
Searching...
No Matches
TriggerFanOut.cc
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
4#include "TriggerFanOut.h"
5
6#include "DeviceManager.h"
7
8#include <utility>
9
10namespace ChimeraTK {
11
12 /********************************************************************************************************************/
13
15 boost::shared_ptr<ChimeraTK::TransferElement> externalTriggerImpl, DeviceManager& deviceModule)
16 : _externalTrigger(std::move(externalTriggerImpl)), _deviceModule(deviceModule) {}
17
18 /********************************************************************************************************************/
19
21 try {
22 deactivate();
23 }
24 catch(ChimeraTK::logic_error& e) {
25 std::cerr << e.what() << std::endl;
26 std::exit(1);
27 }
28 }
29
30 /********************************************************************************************************************/
31
33 assert(!_thread.joinable());
34 _thread = boost::thread([this] { this->run(); });
35 }
36
37 /********************************************************************************************************************/
38
40 try {
41 if(_thread.joinable()) {
42 _thread.interrupt();
43 _externalTrigger->interrupt();
44 _thread.join();
45 }
46 assert(!_thread.joinable());
47 }
48 catch(boost::thread_resource_error&) {
49 assert(false);
50 }
51 }
52
53 /********************************************************************************************************************/
54
55 namespace {
56 struct SendDataToConsumers {
57 SendDataToConsumers(VersionNumber theVersion, DataValidity initialTriggerValidity)
58 : version(theVersion), triggerValidity(initialTriggerValidity) {}
59
60 template<typename PAIR>
61 void operator()(PAIR& pair) const {
62 auto theMap = pair.second; // map of feeder to FeedingFanOut (i.e. part of
63 // the fanOutMap)
64
65 // iterate over all feeder/FeedingFanOut pairs
66 for(auto& network : theMap) {
67 auto feeder = network.first;
68 auto fanOut = network.second;
69 fanOut->setDataValidity((triggerValidity == DataValidity::ok && feeder->dataValidity() == DataValidity::ok) ?
70 DataValidity::ok :
71 DataValidity::faulty);
72 fanOut->accessChannel(0).swap(feeder->accessChannel(0));
73 // don't use write destructively. In case of an exception we still need the data for the next read (see
74 // Exception Handling spec B.2.2.6)
75 bool dataLoss = fanOut->write(version);
76 if(dataLoss) {
78 }
79 // swap the data back to the feeder so we have a valid copy there.
80 fanOut->accessChannel(0).swap(feeder->accessChannel(0));
81 }
82 }
83
84 VersionNumber version;
85 DataValidity triggerValidity;
86 };
87 } // namespace
88
89 /********************************************************************************************************************/
90
93 Application::getInstance().getTestableMode().lock("start", true);
95
96 ChimeraTK::VersionNumber version = Application::getInstance().getStartVersion();
97
98 // Wait for the initial value of the trigger. There always will be one, and if we don't read it here we would
99 // trigger the loop twice.
100 _externalTrigger->read();
101 version = _externalTrigger->getVersionNumber();
102
103 // Wait until the device has been initialised for the first time. This means it
104 // has been opened, and the check in TransferGroup::read() will not throw a logic_error
105 // We don't have to store the lock. Just need it as a synchronisation point.
106 // But we have to increase the testable mode counter because we don't want to fall out of testable mode at this
107 // point already.
108 if(Application::getInstance().getTestableMode().isEnabled()) {
109 ++Application::getInstance().getTestableMode()._deviceInitialisationCounter;
110 }
111 Application::getInstance().getTestableMode().unlock("WaitInitialValueLock");
113 Application::getInstance().getTestableMode().lock("Enter while loop", true);
114 if(Application::getInstance().getTestableMode().isEnabled()) {
115 --Application::getInstance().getTestableMode()._deviceInitialisationCounter;
116 }
117
118 while(true) {
119 _transferGroup.read();
120 // send the version number to the consumers
121 boost::fusion::for_each(_fanOutMap.table, SendDataToConsumers(version, _externalTrigger->dataValidity()));
122
123 // wait for external trigger
124 boost::this_thread::interruption_point();
125 _externalTrigger->read();
126 boost::this_thread::interruption_point();
127 version = _externalTrigger->getVersionNumber();
128 }
129 }
130
131 /********************************************************************************************************************/
132
133} // namespace ChimeraTK
VersionNumber version
DataValidity triggerValidity
detail::TestableMode & getTestableMode()
Get the TestableMode control object of this application.
static void registerThread(const std::string &name)
Register the thread in the application system and give it a name.
static Application & getInstance()
Obtain instance of the application.
VersionNumber getStartVersion() const
Return the start version.
static void incrementDataLossCounter(const std::string &name)
Increment counter for how many write() operations have overwritten unread data.
Implements access to a ChimeraTK::Device.
void waitForInitialValues()
Wait for initial values coming from the device.
std::atomic< bool > _testableModeReached
Flag used by the testable mode to identify whether a thread within the EntityOwner has reached the po...
boost::shared_ptr< ChimeraTK::TransferElement > _externalTrigger
TransferElement acting as our trigger.
DeviceManager & _deviceModule
The DeviceModule of the feeder.
boost::thread _thread
Thread handling the synchronisation, if needed.
void activate() override
Activate synchronisation thread if needed.
TemplateUserTypeMap< FanOutMap > _fanOutMap
TriggerFanOut(boost::shared_ptr< ChimeraTK::TransferElement > externalTriggerImpl, DeviceManager &deviceModule)
void deactivate() final
Deactivate synchronisation thread if running.
ChimeraTK::TransferGroup _transferGroup
TransferGroup containing all feeders NDRegisterAccessors.
void run()
Synchronise feeder and the consumers.
InvalidityTracer application module.