Embedded Template Library  1.0
message_bus.h
1 /******************************************************************************
2 The MIT License(MIT)
3 
4 Embedded Template Library.
5 https://github.com/ETLCPP/etl
6 https://www.etlcpp.com
7 
8 Copyright(c) 2017 jwellbelove
9 
10 Permission is hereby granted, free of charge, to any person obtaining a copy
11 of this software and associated documentation files(the "Software"), to deal
12 in the Software without restriction, including without limitation the rights
13 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
14 copies of the Software, and to permit persons to whom the Software is
15 furnished to do so, subject to the following conditions :
16 
17 The above copyright notice and this permission notice shall be included in all
18 copies or substantial portions of the Software.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
23 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 SOFTWARE.
27 ******************************************************************************/
28 
29 #ifndef ETL_MESSAGE_BUS_
30 #define ETL_MESSAGE_BUS_
31 
32 #include <stdint.h>
33 #include "algorithm.h"
34 
35 #include "platform.h"
36 #include "algorithm.h"
37 #include "vector.h"
38 #include "nullptr.h"
39 #include "error_handler.h"
40 #include "exception.h"
41 #include "message_types.h"
42 #include "message.h"
43 #include "message_router.h"
44 
45 #undef ETL_FILE
46 #define ETL_FILE "39"
47 
48 namespace etl
49 {
50  //***************************************************************************
52  //***************************************************************************
54  {
55  public:
56 
57  message_bus_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
58  : etl::exception(reason_, file_name_, line_number_)
59  {
60  }
61  };
62 
63  //***************************************************************************
65  //***************************************************************************
67  {
68  public:
69 
70  message_bus_too_many_subscribers(string_type file_name_, numeric_type line_number_)
71  : message_bus_exception(ETL_ERROR_TEXT("message bus:too many subscribers", ETL_FILE"A"), file_name_, line_number_)
72  {
73  }
74  };
75 
76  //***************************************************************************
78  //***************************************************************************
80  {
81  private:
82 
84 
85  public:
86 
87  using etl::imessage_router::receive;
88 
89  //*******************************************
91  //*******************************************
93  {
94  bool ok = true;
95 
96  // There's no point adding routers that don't consume messages.
97  if (router.is_consumer())
98  {
99  ok = !router_list.full();
100 
102 
103  if (ok)
104  {
105  router_list_t::iterator irouter = etl::upper_bound(router_list.begin(),
106  router_list.end(),
107  router.get_message_router_id(),
108  compare_router_id());
109 
110  router_list.insert(irouter, &router);
111  }
112  }
113 
114  return ok;
115  }
116 
117  //*******************************************
119  //*******************************************
120  void unsubscribe(etl::message_router_id_t id)
121  {
122  if (id == etl::imessage_bus::ALL_MESSAGE_ROUTERS)
123  {
124  clear();
125  }
126  else
127  {
128  ETL_OR_STD::pair<router_list_t::iterator, router_list_t::iterator> range = etl::equal_range(router_list.begin(),
129  router_list.end(),
130  id,
131  compare_router_id());
132 
133  router_list.erase(range.first, range.second);
134  }
135  }
136 
137  //*******************************************
138  void unsubscribe(etl::imessage_router& router)
139  {
140  router_list_t::iterator irouter = etl::find(router_list.begin(),
141  router_list.end(),
142  &router);
143 
144  if (irouter != router_list.end())
145  {
146  router_list.erase(irouter);
147  }
148  }
149 
150  //*******************************************
151  void receive(const etl::imessage& message) ETL_OVERRIDE
152  {
154  receive(nmr, etl::imessage_router::ALL_MESSAGE_ROUTERS, message);
155  }
156 
157  //*******************************************
158  void receive(etl::message_router_id_t destination_router_id,
159  const etl::imessage& message)
160  {
162  receive(nmr, destination_router_id, message);
163  }
164 
165  //*******************************************
166  void receive(etl::imessage_router& source,
167  const etl::imessage& message) ETL_OVERRIDE
168  {
169  receive(source, etl::imessage_router::ALL_MESSAGE_ROUTERS, message);
170  }
171 
172  //*******************************************
173  void receive(etl::imessage_router& source,
174  etl::message_router_id_t destination_router_id,
175  const etl::imessage& message) ETL_OVERRIDE
176  {
177  switch (destination_router_id)
178  {
179  //*****************************
180  // Broadcast to all routers.
181  case etl::imessage_router::ALL_MESSAGE_ROUTERS:
182  {
183  router_list_t::iterator irouter = router_list.begin();
184 
185  // Broadcast to everyone.
186  while (irouter != router_list.end())
187  {
188  etl::imessage_router& router = **irouter;
189 
190  if (router.accepts(message.message_id))
191  {
192  router.receive(source, message);
193  }
194 
195  ++irouter;
196  }
197 
198  break;
199  }
200 
201  //*****************************
202  // Must be an addressed message.
203  default:
204  {
205  router_list_t::iterator irouter = router_list.begin();
206 
207  // Find routers with the id.
208  ETL_OR_STD::pair<router_list_t::iterator, router_list_t::iterator> range = etl::equal_range(router_list.begin(),
209  router_list.end(),
210  destination_router_id,
211  compare_router_id());
212 
213  // Call all of them.
214  while (range.first != range.second)
215  {
216  if ((*(range.first))->accepts(message.message_id))
217  {
218  (*(range.first))->receive(source, message);
219  }
220 
221  ++range.first;
222  }
223 
224  // Do any message buses.
225  // These are always at the end of the list.
226  irouter = etl::lower_bound(router_list.begin(),
227  router_list.end(),
228  etl::imessage_bus::MESSAGE_BUS,
229  compare_router_id());
230 
231  while (irouter != router_list.end())
232  {
233  // So pass it on.
234  (*irouter)->receive(source, destination_router_id, message);
235 
236  ++irouter;
237  }
238 
239  break;
240  }
241  }
242  }
243 
244  using imessage_router::accepts;
245 
246  //*******************************************
249  //*******************************************
250  bool accepts(etl::message_id_t) const ETL_OVERRIDE
251  {
252  return true;
253  }
254 
255  //*******************************************
256  size_t size() const
257  {
258  return router_list.size();
259  }
260 
261  //*******************************************
262  void clear()
263  {
264  return router_list.clear();
265  }
266 
267  //********************************************
268  ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE
269  {
270  return false;
271  }
272 
273  //********************************************
274  bool is_producer() const ETL_OVERRIDE
275  {
276  return true;
277  }
278 
279  //********************************************
280  bool is_consumer() const ETL_OVERRIDE
281  {
282  return true;
283  }
284 
285  protected:
286 
287  //*******************************************
289  //*******************************************
291  : imessage_router(etl::imessage_router::MESSAGE_BUS),
292  router_list(list)
293  {
294  }
295 
296  private:
297 
298  //*******************************************
299  // How to compare routers to router ids.
300  //*******************************************
301  struct compare_router_id
302  {
303  bool operator()(const etl::imessage_router* prouter, etl::message_router_id_t id) const
304  {
305  return prouter->get_message_router_id() < id;
306  }
307 
308  bool operator()(etl::message_router_id_t id, const etl::imessage_router* prouter) const
309  {
310  return id < prouter->get_message_router_id();
311  }
312  };
313 
314  router_list_t& router_list;
315  };
316 
317  //***************************************************************************
319  //***************************************************************************
320  template <uint_least8_t MAX_ROUTERS_>
322  {
323  public:
324 
325  //*******************************************
327  //*******************************************
329  : imessage_bus(router_list)
330  {
331  }
332 
333  private:
334 
336  };
337 
338  //***************************************************************************
340  //***************************************************************************
341  inline static void send_message(etl::imessage_bus& bus,
342  const etl::imessage& message)
343  {
344  bus.receive(message);
345  }
346 
347  //***************************************************************************
349  //***************************************************************************
350  inline static void send_message(etl::imessage_bus& bus,
351  etl::message_router_id_t id,
352  const etl::imessage& message)
353  {
354  bus.receive(id, message);
355  }
356 
357  //***************************************************************************
359  //***************************************************************************
360  inline static void send_message(etl::imessage_router& source,
361  etl::imessage_bus& bus,
362  const etl::imessage& message)
363  {
364  bus.receive(source, message);
365  }
366 
367  //***************************************************************************
369  //***************************************************************************
370  inline static void send_message(etl::imessage_router& source,
371  etl::imessage_bus& bus,
372  etl::message_router_id_t id,
373  const etl::imessage& message)
374  {
375  bus.receive(source, id, message);
376  }
377 }
378 
379 #undef ETL_FILE
380 
381 #endif
Interface for message bus.
Definition: message_bus.h:80
bool accepts(etl::message_id_t) const ETL_OVERRIDE
Definition: message_bus.h:250
bool subscribe(etl::imessage_router &router)
Subscribe to the bus.
Definition: message_bus.h:92
void unsubscribe(etl::message_router_id_t id)
Unsubscribe from the bus.
Definition: message_bus.h:120
imessage_bus(router_list_t &list)
Constructor.
Definition: message_bus.h:290
This is the base of all message routers.
Definition: message_router_generator.h:114
Definition: message.h:68
A templated list implementation that uses a fixed size buffer.
Definition: list.h:2029
Base exception class for message bus.
Definition: message_bus.h:54
Too many subscribers.
Definition: message_bus.h:67
The message bus.
Definition: message_bus.h:322
message_bus()
Constructor.
Definition: message_bus.h:328
This router can be used as a sink for messages or a 'null source' router.
Definition: message_router_generator.h:194
#define ETL_ASSERT(b, e)
Definition: error_handler.h:290
Definition: exception.h:47
iterator begin()
Definition: vector.h:108
iterator insert(iterator position, const_reference value)
Definition: vector.h:531
void clear()
Clears the vector.
Definition: vector.h:398
iterator end()
Definition: vector.h:126
bool full() const
Definition: vector.h:914
size_type size() const
Definition: vector.h:896
iterator erase(iterator i_element)
Definition: vector.h:820
Definition: vector.h:80
Definition: absolute.h:37
uint_least8_t message_id_t
Allow alternative type for message id.
Definition: message_types.h:40