Fawkes API  Fawkes Development Version
blackboard_manager.h
1 
2 /***************************************************************************
3  * Protoboard plugin template
4  * - Header for the blackboard manager
5  *
6  * Copyright 2019 Victor MatarĂ©
7  ****************************************************************************/
8 
9 /* This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Library General Public License for more details.
18  *
19  * Read the full text in the LICENSE.GPL file in the doc directory.
20  */
21 
22 #ifndef BLACKBOARD_MANAGER_H
23 #define BLACKBOARD_MANAGER_H
24 
25 #include "protoboard_types.h"
26 #include "protobuf_thread.h"
27 
28 #include <aspect/blackboard.h>
29 #include <aspect/blocked_timing.h>
30 #include <aspect/clock.h>
31 #include <aspect/configurable.h>
32 #include <aspect/logging.h>
33 #include <blackboard/utils/on_message_waker.h>
34 #include <core/threading/thread.h>
35 #include <interfaces/ProtobufPeerInterface.h>
36 
37 #include <boost/fusion/include/any.hpp>
38 #include <boost/fusion/include/for_each.hpp>
39 #include <boost/fusion/include/std_tuple.hpp>
40 #include <type_traits>
41 #include <unordered_map>
42 #include <vector>
43 
44 namespace protoboard {
45 
46 /** Map a blackboard interface type to a blackboard interface ID.
47  * Must be implemented by the user. Will be called for every type used with
48  * an @a bb_iface_manager.
49  * @return The interface name (ID) that should be used for the given @tparam type */
50 template <class IfaceT>
51 std::string iface_id_for_type();
52 
53 /** Must be implemented by the user.
54  * @return a vector of paths where ProtoBuf should look for message definitions */
55 std::vector<std::string> proto_dirs();
56 
57 /**
58  * Container for an opened interface of type @tparam IfaceT.
59  * @tparam MessageTypeList must be a @a type_list of the message types that should be
60  * handled on @tparam IfaceT.
61  */
62 template <class IfaceT, class MessageTypeList>
64 {
65 public:
66  /// Constructor. Not responsible for actual initialization.
67  bb_iface_manager() : interface_(nullptr), blackboard_(nullptr), waker_(nullptr)
68  {
69  }
70 
71  /** Open an interface of the given type with the ID supplied by @a iface_id_for_type and
72  * register to wake the given thread when any of the given types arrives.
73  * @param blackboard The blackboard to use
74  * @param thread The thread to wake */
75  void
76  init(fawkes::BlackBoard *blackboard, fawkes::Thread *thread)
77  {
78  blackboard_ = blackboard;
79  interface_ = blackboard_->open_for_writing<IfaceT>(iface_id_for_type<IfaceT>().c_str());
80 
81  // TODO: This rather unspecific waker just triggers a loop(), so we need to go over all the interfaces
82  // each time and check where there's a message in the queue. This should be converted to a
83  // BlackBoardInterfaceListener, which calls a specific method and passes in the affected interface
84  // right away. That should allow significant simplification of all this template hackery.
85  waker_ = new fawkes::BlackBoardOnMessageWaker(blackboard, interface_, thread);
86  }
87 
88  /// Cleanup.
89  void
91  {
92  delete waker_;
93  if (blackboard_ && interface_)
94  blackboard_->close(interface_);
95  }
96 
97  /// @return The managed interface
98  IfaceT *
99  interface() const
100  {
101  return interface_;
102  }
103 
104 private:
105  IfaceT * interface_;
106  fawkes::BlackBoard * blackboard_;
108 };
109 
110 /**
111  * Abstract superclass for sending out ProtoBuf messages
112  */
114 {
115 public:
116  /** Constructor.
117  * @param bb_mgr The BlackboardManager that uses this */
119 
120  /// Destructor
121  virtual ~AbstractProtobufSender();
122 
123  /** Go through all interface managers, empty all blackboard message queues and send out
124  * ProtoBuf messages accordingly.
125  */
126  virtual void process_sending_interfaces() = 0;
127 
128  /// Deferred initialization, coincides with the main thread.
129  virtual void init() = 0;
130  /// Deferred cleanup, concides with the main thread.
131  virtual void finalize() = 0;
132 
133 protected:
134  /// Pointer to the main thread that uses this
136 
137  /**
138  * Functor that iterates over all message types that should be handled on a given interface type
139  * and calls the approate handlers for each message type in turn.
140  */
142  {
143  /// Pointer to the main thread
145 
146  /** Handle a specific blackboard message type on a given interface manager
147  * @tparam IfaceT the interface type handled by the interface manager
148  * @tparam MessageT the current
149  * @param iface_mgr a bb_iface_manager for a specific message type
150  */
151  template <class IfaceT, class MessageT>
152  void operator()(const bb_iface_manager<IfaceT, type_list<MessageT>> &iface_mgr) const;
153 
154  /** Iterate through all given message types on a certain interface and
155  * handle them individually
156  * @tparam IfaceT the interface type
157  * @tparam MessageT1 First message type in the list
158  * @tparam MessageTs Remaining message types
159  * @param iface_mgr a bb_iface_manager with a list of message type to go through
160  */
161  template <class IfaceT, class MessageT1, class... MessageTs>
162  void
163  operator()(const bb_iface_manager<IfaceT, type_list<MessageT1, MessageTs...>> &iface_mgr) const;
164  };
165 };
166 
167 /**
168  * Sends out ProtoBuf messages for all given interface managers
169  * @tparam IfaceManagerTs a set of @a bb_iface_manager instantiations
170  */
171 template <class... IfaceManagerTs>
173 {
174 public:
175  /** Constructor
176  * @param bb_mgr A pointer to the main thread */
178 
179  virtual void init() override;
180  virtual void finalize() override;
181 
182  virtual void
184  {
185  boost::fusion::for_each(bb_sending_interfaces_, handle_messages{this->bb_manager});
186  }
187 
188 private:
189  std::tuple<IfaceManagerTs...> bb_sending_interfaces_;
190 };
191 
192 /**
193  * The main thread that is woken each time a message arrives on any of the interfaces
194  * watched by a @a bb_iface_manager.
195  */
197  public fawkes::LoggingAspect,
200  public fawkes::ClockAspect
201 {
202 public:
203  /** Main thread constructor
204  * @param msg_handler A pointer to the thread that receives incoming ProtoBuf messages */
205  BlackboardManager(ProtobufThead *msg_handler);
206 
207  /** Helper for other classes to get access to the blackboard
208  * @return Pointer to the blackboard used by this thread */
210 
211  /** The ProtoBuf sender must be initialized after construction to beak a dependency loop
212  * @param sender The initialized ProtobufSender */
214 
215 protected:
216  virtual void init() override;
217  virtual void finalize() override;
218  virtual void loop() override;
219 
220  /** Act on a given message on a given blackboard interface. Must be implemented by the user.
221  * @tparam the blackboard interface type
222  * @tparam the blackboard message type
223  * @param iface a pointer to the concrete interface
224  * @param msg a pointer to the concrete message that came in on that interface */
225  template <class InterfaceT, class MessageT>
226  void handle_message(InterfaceT *iface, MessageT *msg);
227 
228 private:
229  friend AbstractProtobufSender;
230 
231  ProtobufThead * message_handler_;
232  fawkes::ProtobufPeerInterface * peer_iface_;
233  pb_conversion_map bb_receiving_interfaces_;
234  fawkes::BlackBoardOnMessageWaker * on_message_waker_;
235  unsigned int next_peer_idx_;
236  std::unique_ptr<AbstractProtobufSender> pb_sender_;
237 
238  void add_peer(fawkes::ProtobufPeerInterface *iface, long peer_id);
239 
240  template <class MessageT, class InterfaceT>
241  void handle_message_type(InterfaceT *iface);
242 
243  template <class InterfaceT>
244  struct on_interface
245  {
246  InterfaceT * iface;
247  BlackboardManager *manager;
248 
249  on_interface(InterfaceT *iface, BlackboardManager *manager) : iface(iface), manager(manager)
250  {
251  }
252 
253  template <class MessageT>
254  void
255  handle_msg_types()
256  {
257  manager->handle_message_type<MessageT>(iface);
258  }
259 
260  // This template is disabled if MessageTs is {} to resolve ambiguity
261  template <class MessageT1, class... MessageTs>
262  typename std::enable_if<(sizeof...(MessageTs) > 0)>::type
263  handle_msg_types()
264  {
265  handle_msg_types<MessageT1>();
266  handle_msg_types<MessageTs...>();
267  }
268  };
269 };
270 
271 template <class... IfaceManagerTs>
273 : AbstractProtobufSender(bb_mgr)
274 {
275 }
276 
277 template <class... IfaceManagerTs>
278 void
280 {
281  boost::fusion::for_each(bb_sending_interfaces_, [this](auto &iface_mgr) {
282  iface_mgr.init(this->bb_manager->get_blackboard(), this->bb_manager);
283  });
284 }
285 
286 template <class... IfaceManagerTs>
287 void
289 {
290  boost::fusion::for_each(bb_sending_interfaces_,
291  [this](auto &iface_mgr) { iface_mgr.finalize(); });
292 }
293 
294 template <class IfaceT, class MessageT>
295 void
297  const bb_iface_manager<IfaceT, type_list<MessageT>> &pair) const
298 {
299  manager->handle_message_type<MessageT>(pair.interface());
300 }
301 
302 template <class IfaceT, class MessageT1, class... MessageTs>
303 void
305  const bb_iface_manager<IfaceT, type_list<MessageT1, MessageTs...>> &iface_mgr) const
306 {
307  BlackboardManager::on_interface<IfaceT>{iface_mgr.interface(), manager}
308  .template handle_msg_types<MessageTs...>();
309 
310  manager->handle_message_type<MessageT1>(iface_mgr.interface());
311 }
312 
313 template <class MessageT, class InterfaceT>
314 void
315 BlackboardManager::handle_message_type(InterfaceT *iface)
316 {
317  if (!iface->msgq_empty()) {
318  while (MessageT *msg = iface->msgq_first_safe(msg)) {
319  try {
320  handle_message(iface, msg);
321  iface->write();
322  } catch (std::exception &e) {
323  logger->log_error(
324  name(), "Exception handling %s on %s: %s", msg->type(), iface->uid(), e.what());
325  }
326  iface->msgq_pop();
327  }
328  }
329 }
330 
331 } // namespace protoboard
332 
333 #endif // BLACKBOARD_MANAGER_H
protoboard::AbstractProtobufSender::handle_messages::operator()
void operator()(const bb_iface_manager< IfaceT, type_list< MessageT >> &iface_mgr) const
Handle a specific blackboard message type on a given interface manager.
Definition: blackboard_manager.h:296
fawkes::MultiLogger::log_error
virtual void log_error(const char *component, const char *format,...)
Log error message.
Definition: multi.cpp:237
protoboard::ProtobufThead
Receive incoming ProtoBuf messages and pass them on to the BlackboardManager for publication to the a...
Definition: protobuf_thread.h:55
protoboard::BlackboardManager::init
virtual void init() override
Initialize the thread.
Definition: blackboard_manager.cpp:58
protoboard::BlackboardManager::loop
virtual void loop() override
Code to execute in the thread.
Definition: blackboard_manager.cpp:79
protoboard::AbstractProtobufSender::handle_messages
Functor that iterates over all message types that should be handled on a given interface type and cal...
Definition: blackboard_manager.h:142
protoboard::AbstractProtobufSender::AbstractProtobufSender
AbstractProtobufSender(BlackboardManager *bb_mgr)
Constructor.
Definition: blackboard_manager.cpp:33
protoboard::bb_iface_manager::finalize
void finalize()
Cleanup.
Definition: blackboard_manager.h:90
fawkes::BlackBoard
The BlackBoard abstract class.
Definition: blackboard.h:46
protoboard::BlackboardManager::set_protobuf_sender
void set_protobuf_sender(AbstractProtobufSender *sender)
The ProtoBuf sender must be initialized after construction to beak a dependency loop.
Definition: blackboard_manager.cpp:52
protoboard::AbstractProtobufSender
Abstract superclass for sending out ProtoBuf messages.
Definition: blackboard_manager.h:114
protoboard::AbstractProtobufSender::handle_messages::manager
BlackboardManager * manager
Pointer to the main thread.
Definition: blackboard_manager.h:144
protoboard::ProtobufSender::init
virtual void init() override
Deferred initialization, coincides with the main thread.
Definition: blackboard_manager.h:279
protoboard::BlackboardManager
The main thread that is woken each time a message arrives on any of the interfaces watched by a bb_if...
Definition: blackboard_manager.h:201
protoboard::bb_iface_manager::bb_iface_manager
bb_iface_manager()
Constructor. Not responsible for actual initialization.
Definition: blackboard_manager.h:67
fawkes::ProtobufPeerInterface
ProtobufPeerInterface Fawkes BlackBoard Interface.
Definition: ProtobufPeerInterface.h:34
protoboard::bb_iface_manager::init
void init(fawkes::BlackBoard *blackboard, fawkes::Thread *thread)
Open an interface of the given type with the ID supplied by iface_id_for_type and register to wake th...
Definition: blackboard_manager.h:76
protoboard::bb_iface_manager
Container for an opened interface of type.
Definition: blackboard_manager.h:64
fawkes::BlackBoard::close
virtual void close(Interface *interface)=0
Close interface.
protoboard::bb_iface_manager::interface
IfaceT * interface() const
Definition: blackboard_manager.h:99
protoboard::AbstractProtobufSender::finalize
virtual void finalize()=0
Deferred cleanup, concides with the main thread.
protoboard::ProtobufSender::finalize
virtual void finalize() override
Deferred cleanup, concides with the main thread.
Definition: blackboard_manager.h:288
protoboard::BlackboardManager::get_blackboard
fawkes::BlackBoard * get_blackboard()
Helper for other classes to get access to the blackboard.
Definition: blackboard_manager.cpp:115
fawkes::BlackBoardAspect
Thread aspect to access to BlackBoard.
Definition: blackboard.h:34
protoboard::BlackboardManager::finalize
virtual void finalize() override
Finalize the thread.
Definition: blackboard_manager.cpp:70
fawkes::LoggingAspect
Thread aspect to log output.
Definition: logging.h:33
protoboard::AbstractProtobufSender::~AbstractProtobufSender
virtual ~AbstractProtobufSender()
Destructor.
Definition: blackboard_manager.cpp:37
protoboard::AbstractProtobufSender::process_sending_interfaces
virtual void process_sending_interfaces()=0
Go through all interface managers, empty all blackboard message queues and send out ProtoBuf messages...
protoboard::BlackboardManager::handle_message
void handle_message(InterfaceT *iface, MessageT *msg)
Act on a given message on a given blackboard interface.
fawkes::Thread
Thread class encapsulation of pthreads.
Definition: thread.h:46
fawkes::BlackBoardOnMessageWaker
Wake threads on receiving a blackboard message.
Definition: on_message_waker.h:36
fawkes::ConfigurableAspect
Thread aspect to access configuration data.
Definition: configurable.h:33
protoboard::BlackboardManager::BlackboardManager
BlackboardManager(ProtobufThead *msg_handler)
Main thread constructor.
Definition: blackboard_manager.cpp:41
protoboard::ProtobufSender::ProtobufSender
ProtobufSender(BlackboardManager *bb_mgr)
Constructor.
Definition: blackboard_manager.h:272
protoboard::AbstractProtobufSender::init
virtual void init()=0
Deferred initialization, coincides with the main thread.
fawkes::BlackBoard::open_for_writing
virtual Interface * open_for_writing(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for writing.
fawkes::ClockAspect
Thread aspect that allows to obtain the current time from the clock.
Definition: clock.h:34
protoboard::ProtobufSender
Sends out ProtoBuf messages for all given interface managers.
Definition: blackboard_manager.h:173
protoboard::type_list
Helper structure to wrap a list of types into a single type.
Definition: protoboard_types.h:40
protoboard::AbstractProtobufSender::bb_manager
BlackboardManager * bb_manager
Pointer to the main thread that uses this.
Definition: blackboard_manager.h:135
protoboard::ProtobufSender::process_sending_interfaces
virtual void process_sending_interfaces() override
Go through all interface managers, empty all blackboard message queues and send out ProtoBuf messages...
Definition: blackboard_manager.h:183