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