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 {
231
232 if (successor.accepts(message.get_message_id()))
233 {
234 successor.receive(destination_router_id, message);
235 }
236 }
237 }
238
239 //********************************************
240 virtual void receive(etl::message_router_id_t destination_router_id,
241 etl::shared_message shared_msg) ETL_OVERRIDE
242 {
243 switch (destination_router_id)
244 {
245 //*****************************
246 // Broadcast to all routers.
247 case etl::imessage_router::ALL_MESSAGE_ROUTERS:
248 {
249 router_list_t::iterator irouter = router_list.begin();
250
251 // Broadcast to everyone.
252 while (irouter != router_list.end())
253 {
254 etl::imessage_router& router = **irouter;
255
256 if (router.accepts(shared_msg.get_message().get_message_id()))
257 {
258 router.receive(shared_msg);
259 }
260
261 ++irouter;
262 }
263
264 break;
265 }
266
267 //*****************************
268 // Must be an addressed message.
269 default:
270 {
271 // Find routers with the id.
272 ETL_OR_STD::pair<router_list_t::iterator, router_list_t::iterator> range = etl::equal_range(router_list.begin(),
273 router_list.end(),
274 destination_router_id,
275 compare_router_id());
276
277 // Call all of them.
278 while (range.first != range.second)
279 {
280 if ((*(range.first))->accepts(shared_msg.get_message().get_message_id()))
281 {
282 (*(range.first))->receive(shared_msg);
283 }
284
285 ++range.first;
286 }
287
288 // Do any message buses.
289 // These are always at the end of the list.
290 router_list_t::iterator irouter = etl::lower_bound(router_list.begin(),
291 router_list.end(),
292 etl::imessage_bus::MESSAGE_BUS,
293 compare_router_id());
294
295 while (irouter != router_list.end())
296 {
297 // So pass it on.
298 (*irouter)->receive(destination_router_id, shared_msg);
299
300 ++irouter;
301 }
302
303 break;
304 }
305 }
306
307 if (has_successor())
308 {
309 etl::imessage_router& successor = get_successor();
310
311 if (successor.accepts(shared_msg.get_message().get_message_id()))
312 {
313 successor.receive(destination_router_id, shared_msg);
314 }
315 }
316 }
317
318 using imessage_router::accepts;
319
320 //*******************************************
323 //*******************************************
324 bool accepts(etl::message_id_t) const ETL_OVERRIDE
325 {
326 return true;
327 }
328
329 //*******************************************
330 size_t size() const
331 {
332 return router_list.size();
333 }
334
335 //*******************************************
336 void clear()
337 {
338 router_list.clear();
339 }
340
341 //********************************************
342 ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE
343 {
344 return false;
345 }
346
347 //********************************************
348 bool is_producer() const ETL_OVERRIDE
349 {
350 return true;
351 }
352
353 //********************************************
354 bool is_consumer() const ETL_OVERRIDE
355 {
356 return true;
357 }
358
359 protected:
360
361 //*******************************************
363 //*******************************************
365 : imessage_router(etl::imessage_router::MESSAGE_BUS),
366 router_list(list)
367 {
368 }
369
370 //*******************************************
372 //*******************************************
378
379 private:
380
381 //*******************************************
382 // How to compare routers to router ids.
383 //*******************************************
384 struct compare_router_id
385 {
386 bool operator()(const etl::imessage_router* prouter, etl::message_router_id_t id) const
387 {
388 return prouter->get_message_router_id() < id;
389 }
390
391 bool operator()(etl::message_router_id_t id, const etl::imessage_router* prouter) const
392 {
393 return id < prouter->get_message_router_id();
394 }
395 };
396
397 router_list_t& router_list;
398 };
399
400 //***************************************************************************
402 //***************************************************************************
403 template <uint_least8_t MAX_ROUTERS_>
405 {
406 public:
407
408 //*******************************************
410 //*******************************************
412 : imessage_bus(router_list)
413 {
414 }
415
416 //*******************************************
418 //*******************************************
423
424 private:
425
427 };
428}
429
430#endif
Interface for message bus.
Definition message_bus.h:76
imessage_bus(router_list_t &list, etl::imessage_router &successor)
Constructor.
Definition message_bus.h:373
bool accepts(etl::message_id_t) const ETL_OVERRIDE
Definition message_bus.h:324
bool subscribe(etl::imessage_router &router)
Subscribe to the bus.
Definition message_bus.h:88
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:364
This is the base of all message routers.
Definition message_router_generator.h:121
Definition message.h:69
A templated list implementation that uses a fixed size buffer.
Definition list.h:2030
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:405
message_bus()
Constructor.
Definition message_bus.h:411
message_bus(etl::imessage_router &successor)
Constructor.
Definition message_bus.h:419
Definition shared_message.h:49
Adds successor traits to a class.
Definition successor.h:73
bool has_successor() const
Does this have a successor?
Definition successor.h:184
successor_type & get_successor() const
Definition successor.h:174
successor()
Default constructor.
Definition successor.h:81
#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:414
iterator end()
Definition vector.h:118
bool full() const
Definition vector.h:977
size_type size() const
Definition vector.h:959
iterator erase(iterator i_element)
Definition vector.h:865
iterator insert(const_iterator position, const_reference value)
Definition vector.h:560
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