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 "vector.h"
35#include "nullptr.h"
36#include "error_handler.h"
37#include "exception.h"
38#include "message_types.h"
39#include "message.h"
40#include "message_router.h"
41
42#include <stdint.h>
43
44namespace etl
45{
46 //***************************************************************************
48 //***************************************************************************
58
59 //***************************************************************************
61 //***************************************************************************
63 {
64 public:
65
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
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 = etl::upper_bound(router_list.begin(),
102 router_list.end(),
103 router.get_message_router_id(),
104 compare_router_id());
105
106 router_list.insert(irouter, &router);
107 }
108 }
109
110 return ok;
111 }
112
113 //*******************************************
115 //*******************************************
116 void unsubscribe(etl::message_router_id_t id)
117 {
118 if (id == etl::imessage_bus::ALL_MESSAGE_ROUTERS)
119 {
120 clear();
121 }
122 else
123 {
124 ETL_OR_STD::pair<router_list_t::iterator, router_list_t::iterator> range = etl::equal_range(router_list.begin(),
125 router_list.end(),
126 id,
127 compare_router_id());
128
129 router_list.erase(range.first, range.second);
130 }
131 }
132
133 //*******************************************
135 {
136 router_list_t::iterator irouter = etl::find(router_list.begin(),
137 router_list.end(),
138 &router);
139
140 if (irouter != router_list.end())
141 {
142 router_list.erase(irouter);
143 }
144 }
145
146 //*******************************************
147 virtual void receive(const etl::imessage& message) ETL_OVERRIDE
148 {
149 receive(etl::imessage_router::ALL_MESSAGE_ROUTERS, message);
150 }
151
152 //*******************************************
153 virtual void receive(etl::shared_message shared_msg) ETL_OVERRIDE
154 {
155 receive(etl::imessage_router::ALL_MESSAGE_ROUTERS, shared_msg);
156 }
157
158 //*******************************************
159 virtual void receive(etl::message_router_id_t destination_router_id,
160 const etl::imessage& message) ETL_OVERRIDE
161 {
162 switch (destination_router_id)
163 {
164 //*****************************
165 // Broadcast to all routers.
166 case etl::imessage_router::ALL_MESSAGE_ROUTERS:
167 {
168 router_list_t::iterator irouter = router_list.begin();
169
170 // Broadcast to everyone.
171 while (irouter != router_list.end())
172 {
173 etl::imessage_router& router = **irouter;
174
175 if (router.accepts(message.get_message_id()))
176 {
177 router.receive(message);
178 }
179
180 ++irouter;
181 }
182
183 break;
184 }
185
186 //*****************************
187 // Must be an addressed message.
188 default:
189 {
190 router_list_t::iterator irouter = router_list.begin();
191
192 // Find routers with the id.
193 ETL_OR_STD::pair<router_list_t::iterator, router_list_t::iterator> range = etl::equal_range(router_list.begin(),
194 router_list.end(),
195 destination_router_id,
196 compare_router_id());
197
198 // Call all of them.
199 while (range.first != range.second)
200 {
201 if ((*(range.first))->accepts(message.get_message_id()))
202 {
203 (*(range.first))->receive(message);
204 }
205
206 ++range.first;
207 }
208
209 // Do any message buses.
210 // These are always at the end of the list.
211 irouter = etl::lower_bound(router_list.begin(),
212 router_list.end(),
213 etl::imessage_bus::MESSAGE_BUS,
214 compare_router_id());
215
216 while (irouter != router_list.end())
217 {
218 // So pass it on.
219 (*irouter)->receive(destination_router_id, message);
220
221 ++irouter;
222 }
223
224 break;
225 }
226 }
227
228 if (has_successor())
229 {
230 if (get_successor().accepts(message.get_message_id()))
231 {
232 get_successor().receive(destination_router_id, message);
233 }
234 }
235 }
236
237 //********************************************
238 virtual void receive(etl::message_router_id_t destination_router_id,
239 etl::shared_message shared_msg) ETL_OVERRIDE
240 {
241 switch (destination_router_id)
242 {
243 //*****************************
244 // Broadcast to all routers.
245 case etl::imessage_router::ALL_MESSAGE_ROUTERS:
246 {
247 router_list_t::iterator irouter = router_list.begin();
248
249 // Broadcast to everyone.
250 while (irouter != router_list.end())
251 {
252 etl::imessage_router& router = **irouter;
253
254 if (router.accepts(shared_msg.get_message().get_message_id()))
255 {
256 router.receive(shared_msg);
257 }
258
259 ++irouter;
260 }
261
262 break;
263 }
264
265 //*****************************
266 // Must be an addressed message.
267 default:
268 {
269 // Find routers with the id.
270 ETL_OR_STD::pair<router_list_t::iterator, router_list_t::iterator> range = etl::equal_range(router_list.begin(),
271 router_list.end(),
272 destination_router_id,
273 compare_router_id());
274
275 // Call all of them.
276 while (range.first != range.second)
277 {
278 if ((*(range.first))->accepts(shared_msg.get_message().get_message_id()))
279 {
280 (*(range.first))->receive(shared_msg);
281 }
282
283 ++range.first;
284 }
285
286 // Do any message buses.
287 // These are always at the end of the list.
288 router_list_t::iterator irouter = etl::lower_bound(router_list.begin(),
289 router_list.end(),
290 etl::imessage_bus::MESSAGE_BUS,
291 compare_router_id());
292
293 while (irouter != router_list.end())
294 {
295 // So pass it on.
296 (*irouter)->receive(destination_router_id, shared_msg);
297
298 ++irouter;
299 }
300
301 break;
302 }
303 }
304
305 if (has_successor())
306 {
307 if (get_successor().accepts(shared_msg.get_message().get_message_id()))
308 {
309 get_successor().receive(destination_router_id, shared_msg);
310 }
311 }
312 }
313
314 using imessage_router::accepts;
315
316 //*******************************************
319 //*******************************************
320 bool accepts(etl::message_id_t id) const ETL_OVERRIDE
321 {
322 // Check the list of subscribed routers.
323 router_list_t::iterator irouter = router_list.begin();
324
325 while (irouter != router_list.end())
326 {
328
329 if (router.accepts(id))
330 {
331 return true;
332 }
333
334 ++irouter;
335 }
336
337 // Check any successor.
338 if (has_successor())
339 {
340 if (get_successor().accepts(id))
341 {
342 return true;
343 }
344 }
345
346 return false;
347 }
348
349 //*******************************************
350 size_t size() const
351 {
352 return router_list.size();
353 }
354
355 //*******************************************
356 void clear()
357 {
358 router_list.clear();
359 }
360
361 //********************************************
362 ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE
363 {
364 return false;
365 }
366
367 //********************************************
368 bool is_producer() const ETL_OVERRIDE
369 {
370 return true;
371 }
372
373 //********************************************
374 bool is_consumer() const ETL_OVERRIDE
375 {
376 return true;
377 }
378
379 protected:
380
381 //*******************************************
383 //*******************************************
385 : imessage_router(etl::imessage_router::MESSAGE_BUS),
386 router_list(list)
387 {
388 }
389
390 //*******************************************
392 //*******************************************
398
399 private:
400
401 //*******************************************
402 // How to compare routers to router ids.
403 //*******************************************
404 struct compare_router_id
405 {
406 bool operator()(const etl::imessage_router* prouter, etl::message_router_id_t id) const
407 {
408 return prouter->get_message_router_id() < id;
409 }
410
411 bool operator()(etl::message_router_id_t id, const etl::imessage_router* prouter) const
412 {
413 return id < prouter->get_message_router_id();
414 }
415 };
416
417 router_list_t& router_list;
418 };
419
420 //***************************************************************************
422 //***************************************************************************
423 template <uint_least8_t MAX_ROUTERS_>
425 {
426 public:
427
428 //*******************************************
430 //*******************************************
432 : imessage_bus(router_list)
433 {
434 }
435
436 //*******************************************
438 //*******************************************
443
444 private:
445
447 };
448}
449
450#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:393
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:320
void unsubscribe(etl::message_router_id_t id)
Unsubscribe from the bus.
Definition message_bus.h:116
imessage_bus(router_list_t &list)
Constructor.
Definition message_bus.h:384
This is the base of all message routers.
Definition message_router_generator.h:123
Definition message.h:73
A templated list implementation that uses a fixed size buffer.
Definition list.h:2073
Base exception class for message bus.
Definition message_bus.h:50
Too many subscribers.
Definition message_bus.h:63
The message bus.
Definition message_bus.h:425
message_bus()
Constructor.
Definition message_bus.h:431
message_bus(etl::imessage_router &successor_)
Constructor.
Definition message_bus.h:439
Definition shared_message.h:49
bool has_successor() const
Does this have a successor?
Definition successor.h:184
successor_type & get_successor() const
Definition successor.h:174
#define ETL_ASSERT(b, e)
Definition error_handler.h:316
Definition exception.h:47
iterator begin()
Definition vector.h:100
void clear()
Clears the vector.
Definition vector.h:417
iterator end()
Definition vector.h:118
bool full() const
Definition vector.h:996
size_type size() const
Definition vector.h:978
iterator erase(iterator i_element)
Definition vector.h:884
iterator insert(const_iterator position, const_reference value)
Definition vector.h:579
bitset_ext
Definition absolute.h:38
uint_least8_t message_id_t
Allow alternative type for message id.
Definition message_types.h:40
pair holds two objects of arbitrary type
Definition utility.h:164