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 "nullptr.h"
40#include "vector.h"
41
42#include <stdint.h>
43
44namespace etl
45{
46 //***************************************************************************
48 //***************************************************************************
49 class message_bus_exception : public etl::exception
50 {
51 public:
52
53 message_bus_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
54 : etl::exception(reason_, file_name_, line_number_)
55 {
56 }
57 };
58
59 //***************************************************************************
61 //***************************************************************************
62 class message_bus_too_many_subscribers : public etl::message_bus_exception
63 {
64 public:
65
66 message_bus_too_many_subscribers(string_type file_name_, numeric_type line_number_)
67 : message_bus_exception(ETL_ERROR_TEXT("message bus:too many subscribers", ETL_MESSAGE_BUS_FILE_ID"A"), file_name_, line_number_)
68 {
69 }
70 };
71
72 //***************************************************************************
74 //***************************************************************************
76 {
77 private:
78
79 typedef etl::ivector<etl::imessage_router*> router_list_t;
80
81 public:
82
83 using etl::imessage_router::receive;
84
85 //*******************************************
87 //*******************************************
89 {
90 bool ok = true;
91
92 // There's no point adding routers that don't consume messages.
93 if (router.is_consumer())
94 {
95 ok = !router_list.full();
96
98
99 if (ok)
100 {
101 router_list_t::iterator irouter =
102 etl::upper_bound(router_list.begin(), router_list.end(), router.get_message_router_id(), compare_router_id());
103
104 router_list.insert(irouter, &router);
105 }
106 }
107
108 return ok;
109 }
110
111 //*******************************************
113 //*******************************************
114 void unsubscribe(etl::message_router_id_t id)
115 {
116 if (id == etl::imessage_bus::ALL_MESSAGE_ROUTERS)
117 {
118 clear();
119 }
120 else
121 {
122 ETL_OR_STD::pair<router_list_t::iterator, router_list_t::iterator> range =
123 etl::equal_range(router_list.begin(), router_list.end(), id, compare_router_id());
124
125 router_list.erase(range.first, range.second);
126 }
127 }
128
129 //*******************************************
131 {
132 router_list_t::iterator irouter = etl::find(router_list.begin(), router_list.end(), &router);
133
134 if (irouter != router_list.end())
135 {
136 router_list.erase(irouter);
137 }
138 }
139
140 //*******************************************
141 virtual void receive(const etl::imessage& message) ETL_OVERRIDE
142 {
143 receive(etl::imessage_router::ALL_MESSAGE_ROUTERS, message);
144 }
145
146 //*******************************************
147 virtual void receive(etl::shared_message shared_msg) ETL_OVERRIDE
148 {
149 receive(etl::imessage_router::ALL_MESSAGE_ROUTERS, shared_msg);
150 }
151
152 //*******************************************
153 virtual void receive(etl::message_router_id_t destination_router_id, const etl::imessage& message) ETL_OVERRIDE
154 {
155 switch (destination_router_id)
156 {
157 //*****************************
158 // Broadcast to all routers.
159 case etl::imessage_router::ALL_MESSAGE_ROUTERS:
160 {
161 router_list_t::iterator irouter = router_list.begin();
162
163 // Broadcast to everyone.
164 while (irouter != router_list.end())
165 {
166 etl::imessage_router& router = **irouter;
167
168 if (router.accepts(message.get_message_id()))
169 {
170 router.receive(message);
171 }
172
173 ++irouter;
174 }
175
176 break;
177 }
178
179 //*****************************
180 // Must be an addressed message.
181 default:
182 {
183 router_list_t::iterator irouter = router_list.begin();
184
185 // Find routers with the id.
186 ETL_OR_STD::pair<router_list_t::iterator, router_list_t::iterator> range =
187 etl::equal_range(router_list.begin(), router_list.end(), destination_router_id, compare_router_id());
188
189 // Call all of them.
190 while (range.first != range.second)
191 {
192 if ((*(range.first))->accepts(message.get_message_id()))
193 {
194 (*(range.first))->receive(message);
195 }
196
197 ++range.first;
198 }
199
200 // Do any message buses.
201 // These are always at the end of the list.
202 irouter = etl::lower_bound(router_list.begin(), router_list.end(), etl::imessage_bus::MESSAGE_BUS, compare_router_id());
203
204 while (irouter != router_list.end())
205 {
206 // So pass it on.
207 (*irouter)->receive(destination_router_id, message);
208
209 ++irouter;
210 }
211
212 break;
213 }
214 }
215
216 if (has_successor())
217 {
218 if (get_successor().accepts(message.get_message_id()))
219 {
220 get_successor().receive(destination_router_id, message);
221 }
222 }
223 }
224
225 //********************************************
226 virtual void receive(etl::message_router_id_t destination_router_id, etl::shared_message shared_msg) ETL_OVERRIDE
227 {
228 switch (destination_router_id)
229 {
230 //*****************************
231 // Broadcast to all routers.
232 case etl::imessage_router::ALL_MESSAGE_ROUTERS:
233 {
234 router_list_t::iterator irouter = router_list.begin();
235
236 // Broadcast to everyone.
237 while (irouter != router_list.end())
238 {
239 etl::imessage_router& router = **irouter;
240
241 if (router.accepts(shared_msg.get_message().get_message_id()))
242 {
243 router.receive(shared_msg);
244 }
245
246 ++irouter;
247 }
248
249 break;
250 }
251
252 //*****************************
253 // Must be an addressed message.
254 default:
255 {
256 // Find routers with the id.
257 ETL_OR_STD::pair<router_list_t::iterator, router_list_t::iterator> range =
258 etl::equal_range(router_list.begin(), router_list.end(), destination_router_id, compare_router_id());
259
260 // Call all of them.
261 while (range.first != range.second)
262 {
263 if ((*(range.first))->accepts(shared_msg.get_message().get_message_id()))
264 {
265 (*(range.first))->receive(shared_msg);
266 }
267
268 ++range.first;
269 }
270
271 // Do any message buses.
272 // These are always at the end of the list.
273 router_list_t::iterator irouter =
274 etl::lower_bound(router_list.begin(), router_list.end(), etl::imessage_bus::MESSAGE_BUS, compare_router_id());
275
276 while (irouter != router_list.end())
277 {
278 // So pass it on.
279 (*irouter)->receive(destination_router_id, shared_msg);
280
281 ++irouter;
282 }
283
284 break;
285 }
286 }
287
288 if (has_successor())
289 {
290 if (get_successor().accepts(shared_msg.get_message().get_message_id()))
291 {
292 get_successor().receive(destination_router_id, shared_msg);
293 }
294 }
295 }
296
297 using imessage_router::accepts;
298
299 //*******************************************
302 //*******************************************
303 bool accepts(etl::message_id_t id) const ETL_OVERRIDE
304 {
305 // Check the list of subscribed routers.
306 router_list_t::iterator irouter = router_list.begin();
307
308 while (irouter != router_list.end())
309 {
310 etl::imessage_router& router = **irouter;
311
312 if (router.accepts(id))
313 {
314 return true;
315 }
316
317 ++irouter;
318 }
319
320 // Check any successor.
321 if (has_successor())
322 {
323 if (get_successor().accepts(id))
324 {
325 return true;
326 }
327 }
328
329 return false;
330 }
331
332 //*******************************************
333 size_t size() const
334 {
335 return router_list.size();
336 }
337
338 //*******************************************
339 void clear()
340 {
341 router_list.clear();
342 }
343
344 //********************************************
345 ETL_DEPRECATED
346 bool is_null_router() const ETL_OVERRIDE
347 {
348 return false;
349 }
350
351 //********************************************
352 bool is_producer() const ETL_OVERRIDE
353 {
354 return true;
355 }
356
357 //********************************************
358 bool is_consumer() const ETL_OVERRIDE
359 {
360 return true;
361 }
362
363 protected:
364
365 //*******************************************
367 //*******************************************
368 imessage_bus(router_list_t& list)
369 : imessage_router(etl::imessage_router::MESSAGE_BUS)
370 , router_list(list)
371 {
372 }
373
374 //*******************************************
376 //*******************************************
377 imessage_bus(router_list_t& router_list_, etl::imessage_router& successor_)
378 : imessage_router(etl::imessage_router::MESSAGE_BUS, successor_)
379 , router_list(router_list_)
380 {
381 }
382
383 private:
384
385 //*******************************************
386 // How to compare routers to router ids.
387 //*******************************************
388 struct compare_router_id
389 {
390 bool operator()(const etl::imessage_router* prouter, etl::message_router_id_t id) const
391 {
392 return prouter->get_message_router_id() < id;
393 }
394
395 bool operator()(etl::message_router_id_t id, const etl::imessage_router* prouter) const
396 {
397 return id < prouter->get_message_router_id();
398 }
399 };
400
401 router_list_t& router_list;
402 };
403
404 //***************************************************************************
406 //***************************************************************************
407 template <uint_least8_t MAX_ROUTERS_>
409 {
410 public:
411
412 //*******************************************
414 //*******************************************
416 : imessage_bus(router_list)
417 {
418 }
419
420 //*******************************************
422 //*******************************************
424 : imessage_bus(router_list, successor_)
425 {
426 }
427
428 private:
429
431 };
432} // namespace etl
433
434#endif
Interface for message bus.
Definition message_bus.h:76
imessage_bus(router_list_t &router_list_, etl::imessage_router &successor_)
Constructor.
Definition message_bus.h:377
bool subscribe(etl::imessage_router &router)
Subscribe to the bus.
Definition message_bus.h:88
bool accepts(etl::message_id_t id) const ETL_OVERRIDE
Definition message_bus.h:303
void unsubscribe(etl::message_router_id_t id)
Unsubscribe from the bus.
Definition message_bus.h:114
imessage_bus(router_list_t &list)
Constructor.
Definition message_bus.h:368
This is the base of all message routers.
Definition message_router.h:138
A templated list implementation that uses a fixed size buffer.
Definition list.h:2066
Base exception class for message bus.
Definition message_bus.h:50
Too many subscribers.
Definition message_bus.h:63
message_bus()
Constructor.
Definition message_bus.h:415
message_bus(etl::imessage_router &successor_)
Constructor.
Definition message_bus.h:423
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
iterator begin()
Definition vector.h:99
void clear()
Clears the vector.
Definition vector.h:429
iterator end()
Definition vector.h:117
size_type size() const
Definition vector.h:1040
iterator erase(iterator i_element)
Definition vector.h:911
Definition vector.h:71
Definition vector.h:1277
bitset_ext
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:1192