FairMQ  1.4.14
C++ Message Queuing Library and Framework
DDS.h
1 /********************************************************************************
2  * Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
3  * *
4  * This software is distributed under the terms of the *
5  * GNU Lesser General Public Licence (LGPL) version 3, *
6  * copied verbatim in the file "LICENSE" *
7  ********************************************************************************/
8 
9 #ifndef FAIR_MQ_PLUGINS_DDS
10 #define FAIR_MQ_PLUGINS_DDS
11 
12 #include <fairmq/Plugin.h>
13 #include <fairmq/StateQueue.h>
14 #include <fairmq/Version.h>
15 #include <fairmq/sdk/commands/Commands.h>
16 
17 #include <dds/dds.h>
18 
19 #include <boost/asio/executor.hpp>
20 #include <boost/asio/executor_work_guard.hpp>
21 #include <boost/asio/io_context.hpp>
22 
23 #include <cassert>
24 #include <chrono>
25 #include <condition_variable>
26 #include <mutex>
27 #include <string>
28 #include <atomic>
29 #include <thread>
30 #include <map>
31 #include <unordered_map>
32 #include <utility> // pair
33 #include <vector>
34 
35 namespace fair
36 {
37 namespace mq
38 {
39 namespace plugins
40 {
41 
42 struct DDSConfig
43 {
44  // container of sub channel addresses
45  unsigned int fNumSubChannels;
46  // dds values for the channel
47  std::map<uint64_t, std::string> fDDSValues;
48 };
49 
51 {
53  : fDDSCustomCmd(fService)
54  , fDDSKeyValue(fService)
55  {
56  LOG(debug) << "$DDS_TASK_PATH: " << dds::env_prop<dds::task_path>();
57  LOG(debug) << "$DDS_GROUP_NAME: " << dds::env_prop<dds::group_name>();
58  LOG(debug) << "$DDS_COLLECTION_NAME: " << dds::env_prop<dds::collection_name>();
59  LOG(debug) << "$DDS_TASK_NAME: " << dds::env_prop<dds::task_name>();
60  LOG(debug) << "$DDS_TASK_INDEX: " << dds::env_prop<dds::task_index>();
61  LOG(debug) << "$DDS_COLLECTION_INDEX: " << dds::env_prop<dds::collection_index>();
62  LOG(debug) << "$DDS_TASK_ID: " << dds::env_prop<dds::task_id>();
63  LOG(debug) << "$DDS_LOCATION: " << dds::env_prop<dds::dds_location>();
64  std::string dds_session_id(dds::env_prop<dds::dds_session_id>());
65  LOG(debug) << "$DDS_SESSION_ID: " << dds_session_id;
66 
67  // subscribe for DDS service errors.
68  fService.subscribeOnError([](const dds::intercom_api::EErrorCode errorCode, const std::string& errorMsg) {
69  LOG(error) << "DDS Error received: error code: " << errorCode << ", error message: " << errorMsg;
70  });
71 
72  // fDDSCustomCmd.subscribe([](const std::string& cmd, const std::string& cond, uint64_t senderId) {
73  // LOG(debug) << "cmd: " << cmd << ", cond: " << cond << ", senderId: " << senderId;
74  // });
75  assert(!dds_session_id.empty());
76  }
77 
78  auto Start() -> void {
79  fService.start(dds::env_prop<dds::dds_session_id>());
80  }
81 
82  ~DDSSubscription() {
83  fDDSKeyValue.unsubscribe();
84  fDDSCustomCmd.unsubscribe();
85  }
86 
87  template<typename... Args>
88  auto SubscribeCustomCmd(Args&&... args) -> void
89  {
90  fDDSCustomCmd.subscribe(std::forward<Args>(args)...);
91  }
92 
93  template<typename... Args>
94  auto SubscribeKeyValue(Args&&... args) -> void
95  {
96  fDDSKeyValue.subscribe(std::forward<Args>(args)...);
97  }
98 
99  template<typename... Args>
100  auto Send(Args&&... args) -> void
101  {
102  fDDSCustomCmd.send(std::forward<Args>(args)...);
103  }
104 
105  template<typename... Args>
106  auto PutValue(Args&&... args) -> void
107  {
108  fDDSKeyValue.putValue(std::forward<Args>(args)...);
109  }
110 
111  private:
112  dds::intercom_api::CIntercomService fService;
113  dds::intercom_api::CCustomCmd fDDSCustomCmd;
114  dds::intercom_api::CKeyValue fDDSKeyValue;
115 };
116 
117 struct IofN
118 {
119  IofN(int i, int n)
120  : fI(i)
121  , fN(n)
122  {}
123 
124  unsigned int fI;
125  unsigned int fN;
126  std::vector<std::string> fEntries;
127 };
128 
129 class DDS : public Plugin
130 {
131  public:
132  DDS(const std::string& name, const Plugin::Version version, const std::string& maintainer, const std::string& homepage, PluginServices* pluginServices);
133 
134  ~DDS();
135 
136  private:
137  auto WaitForExitingAck() -> void;
138  auto StartWorkerThread() -> void;
139 
140  auto FillChannelContainers() -> void;
141  auto EmptyChannelContainers() -> void;
142 
143  auto SubscribeForConnectingChannels() -> void;
144  auto PublishBoundChannels() -> void;
145  auto SubscribeForCustomCommands() -> void;
146  auto HandleCmd(const std::string& id, sdk::cmd::Cmd& cmd, const std::string& cond, uint64_t senderId) -> void;
147 
148  DDSSubscription fDDS;
149  size_t fDDSTaskId;
150 
151  std::unordered_map<std::string, std::vector<std::string>> fBindingChans;
152  std::unordered_map<std::string, DDSConfig> fConnectingChans;
153 
154  std::unordered_map<std::string, int> fI;
155  std::unordered_map<std::string, IofN> fIofN;
156 
157  std::thread fControllerThread;
158  DeviceState fCurrentState, fLastState;
159 
160  std::atomic<bool> fDeviceTerminationRequested;
161 
162  std::unordered_map<uint64_t, std::pair<std::chrono::steady_clock::time_point, int64_t>> fStateChangeSubscribers;
163  uint64_t fLastExternalController;
164  bool fExitingAckedByLastExternalController;
165  std::condition_variable fExitingAcked;
166  std::mutex fStateChangeSubscriberMutex;
167 
168  bool fUpdatesAllowed;
169  std::mutex fUpdateMutex;
170  std::condition_variable fUpdateCondition;
171 
172  std::thread fWorkerThread;
173  boost::asio::io_context fWorkerQueue;
174  boost::asio::executor_work_guard<boost::asio::executor> fWorkGuard;
175 };
176 
177 Plugin::ProgOptions DDSProgramOptions()
178 {
179  boost::program_options::options_description options{"DDS Plugin"};
180  options.add_options()
181  ("dds-i", boost::program_options::value<std::vector<std::string>>()->multitoken()->composing(), "Task index for chosing connection target (single channel n to m). When all values come via same update.")
182  ("dds-i-n", boost::program_options::value<std::vector<std::string>>()->multitoken()->composing(), "Task index for chosing connection target (one out of n values to take). When values come as independent updates.")
183  ("wait-for-exiting-ack-timeout", boost::program_options::value<unsigned int>()->default_value(1000), "Wait timeout for EXITING state-change acknowledgement by external controller in milliseconds.");
184 
185  return options;
186 }
187 
188 REGISTER_FAIRMQ_PLUGIN(
189  DDS, // Class name
190  dds, // Plugin name (string, lower case chars only)
191  (Plugin::Version{FAIRMQ_VERSION_MAJOR,
192  FAIRMQ_VERSION_MINOR,
193  FAIRMQ_VERSION_PATCH}), // Version
194  "FairRootGroup <fairroot@gsi.de>", // Maintainer
195  "https://github.com/FairRootGroup/FairMQ", // Homepage
196  DDSProgramOptions // custom program options for the plugin
197 )
198 
199 } /* namespace plugins */
200 } /* namespace mq */
201 } /* namespace fair */
202 
203 #endif /* FAIR_MQ_PLUGINS_DDS */
Facilitates communication between devices and plugins.
Definition: PluginServices.h:40
Definition: DDS.h:129
Definition: DDS.h:42
Definition: DDS.h:117
Base class for FairMQ plugins.
Definition: Plugin.h:39
Definition: Commands.h:62
Tools for interfacing containers to the transport via polymorphic allocators.
Definition: DeviceRunner.h:23
Definition: Version.h:22

privacy