Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
message_timer.h
00001 /****************************************************************************** 00002 The MIT License(MIT) 00003 00004 Embedded Template Library. 00005 https://github.com/ETLCPP/etl 00006 https://www.etlcpp.com 00007 00008 Copyright(c) 2017 jwellbelove 00009 00010 Permission is hereby granted, free of charge, to any person obtaining a copy 00011 of this software and associated documentation files(the "Software"), to deal 00012 in the Software without restriction, including without limitation the rights 00013 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 00014 copies of the Software, and to permit persons to whom the Software is 00015 furnished to do so, subject to the following conditions : 00016 00017 The above copyright notice and this permission notice shall be included in all 00018 copies or substantial portions of the Software. 00019 00020 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00021 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00022 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 00023 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00024 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00025 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00026 SOFTWARE. 00027 ******************************************************************************/ 00028 00029 #ifndef __ETL_MESSAGE_TIMER__ 00030 #define __ETL_MESSAGE_TIMER__ 00031 00032 #include <stdint.h> 00033 #include <algorithm> 00034 00035 #include "platform.h " 00036 #include "nullptr.h " 00037 #include "message_types.h" 00038 #include "message.h" 00039 #include "message_router.h" 00040 #include "message_bus.h" 00041 #include "static_assert.h" 00042 #include "timer.h" 00043 #include "atomic.h" 00044 00045 #undef ETL_FILE 00046 #define ETL_FILE "41" 00047 00048 namespace etl 00049 { 00050 //************************************************************************* 00051 /// The configuration of a timer. 00052 struct message_timer_data 00053 { 00054 //******************************************* 00055 message_timer_data() 00056 : p_message(std::nullptr), 00057 p_router(std::nullptr), 00058 period(0), 00059 delta(etl::timer::state::INACTIVE), 00060 destination_router_id(etl::imessage_bus::ALL_MESSAGE_ROUTERS), 00061 id(etl::timer::id::NO_TIMER), 00062 previous(etl::timer::id::NO_TIMER), 00063 next(etl::timer::id::NO_TIMER), 00064 repeating(true) 00065 { 00066 } 00067 00068 //******************************************* 00069 message_timer_data(etl::timer::id::type id_, 00070 const etl::imessage& message_, 00071 etl::imessage_router& irouter_, 00072 uint32_t period_, 00073 bool repeating_, 00074 etl::message_router_id_t destination_router_id_) 00075 : p_message(&message_), 00076 p_router(&irouter_), 00077 period(period_), 00078 delta(etl::timer::state::INACTIVE), 00079 id(id_), 00080 previous(etl::timer::id::NO_TIMER), 00081 next(etl::timer::id::NO_TIMER), 00082 repeating(repeating_) 00083 { 00084 if (irouter_.is_bus()) 00085 { 00086 destination_router_id = destination_router_id_; 00087 } 00088 else 00089 { 00090 destination_router_id = etl::imessage_bus::ALL_MESSAGE_ROUTERS; 00091 } 00092 } 00093 00094 //******************************************* 00095 /// Returns true if the timer is active. 00096 //******************************************* 00097 bool is_active() const 00098 { 00099 return delta != etl::timer::state::INACTIVE; 00100 } 00101 00102 //******************************************* 00103 /// Sets the timer to the inactive state. 00104 //******************************************* 00105 void set_inactive() 00106 { 00107 delta = etl::timer::state::INACTIVE; 00108 } 00109 00110 const etl::imessage* p_message; 00111 etl::imessage_router* p_router; 00112 uint32_t period; 00113 uint32_t delta; 00114 etl::message_router_id_t destination_router_id; 00115 etl::timer::id::type id; 00116 uint_least8_t previous; 00117 uint_least8_t next; 00118 bool repeating; 00119 00120 private: 00121 00122 // Disabled. 00123 message_timer_data(const message_timer_data& other); 00124 message_timer_data& operator =(const message_timer_data& other); 00125 }; 00126 00127 namespace __private_message_timer__ 00128 { 00129 //************************************************************************* 00130 /// A specialised intrusive linked list for timer data. 00131 //************************************************************************* 00132 class list 00133 { 00134 public: 00135 00136 //******************************* 00137 list(etl::message_timer_data* ptimers_) 00138 : head(etl::timer::id::NO_TIMER), 00139 tail(etl::timer::id::NO_TIMER), 00140 current(etl::timer::id::NO_TIMER), 00141 ptimers(ptimers_) 00142 { 00143 } 00144 00145 //******************************* 00146 bool empty() const 00147 { 00148 return head == etl::timer::id::NO_TIMER; 00149 } 00150 00151 //******************************* 00152 // Inserts the timer at the correct delta position 00153 //******************************* 00154 void insert(etl::timer::id::type id_) 00155 { 00156 etl::message_timer_data& timer = ptimers[id_]; 00157 00158 if (head == etl::timer::id::NO_TIMER) 00159 { 00160 // No entries yet. 00161 head = id_; 00162 tail = id_; 00163 timer.previous = etl::timer::id::NO_TIMER; 00164 timer.next = etl::timer::id::NO_TIMER; 00165 } 00166 else 00167 { 00168 // We already have entries. 00169 etl::timer::id::type test_id = begin(); 00170 00171 while (test_id != etl::timer::id::NO_TIMER) 00172 { 00173 etl::message_timer_data& test = ptimers[test_id]; 00174 00175 // Find the correct place to insert. 00176 if (timer.delta <= test.delta) 00177 { 00178 if (test.id == head) 00179 { 00180 head = timer.id; 00181 } 00182 00183 // Insert before test. 00184 timer.previous = test.previous; 00185 test.previous = timer.id; 00186 timer.next = test.id; 00187 00188 // Adjust the next delta to compensate. 00189 test.delta -= timer.delta; 00190 00191 if (timer.previous != etl::timer::id::NO_TIMER) 00192 { 00193 ptimers[timer.previous].next = timer.id; 00194 } 00195 break; 00196 } 00197 else 00198 { 00199 timer.delta -= test.delta; 00200 } 00201 00202 test_id = next(test_id); 00203 } 00204 00205 // Reached the end? 00206 if (test_id == etl::timer::id::NO_TIMER) 00207 { 00208 // Tag on to the tail. 00209 ptimers[tail].next = timer.id; 00210 timer.previous = tail; 00211 timer.next = etl::timer::id::NO_TIMER; 00212 tail = timer.id; 00213 } 00214 } 00215 } 00216 00217 //******************************* 00218 void remove(etl::timer::id::type id_, bool has_expired) 00219 { 00220 etl::message_timer_data& timer = ptimers[id_]; 00221 00222 if (head == id_) 00223 { 00224 head = timer.next; 00225 } 00226 else 00227 { 00228 ptimers[timer.previous].next = timer.next; 00229 } 00230 00231 if (tail == id_) 00232 { 00233 tail = timer.previous; 00234 } 00235 else 00236 { 00237 ptimers[timer.next].previous = timer.previous; 00238 } 00239 00240 if (!has_expired) 00241 { 00242 // Adjust the next delta. 00243 if (timer.next != etl::timer::id::NO_TIMER) 00244 { 00245 ptimers[timer.next].delta += timer.delta; 00246 } 00247 } 00248 00249 timer.previous = etl::timer::id::NO_TIMER; 00250 timer.next = etl::timer::id::NO_TIMER; 00251 timer.delta = etl::timer::state::INACTIVE; 00252 } 00253 00254 //******************************* 00255 etl::message_timer_data& front() 00256 { 00257 return ptimers[head]; 00258 } 00259 00260 //******************************* 00261 etl::timer::id::type begin() 00262 { 00263 current = head; 00264 return current; 00265 } 00266 00267 //******************************* 00268 etl::timer::id::type previous(etl::timer::id::type last) 00269 { 00270 current = ptimers[last].previous; 00271 return current; 00272 } 00273 00274 //******************************* 00275 etl::timer::id::type next(etl::timer::id::type last) 00276 { 00277 current = ptimers[last].next; 00278 return current; 00279 } 00280 00281 //******************************* 00282 void clear() 00283 { 00284 etl::timer::id::type id = begin(); 00285 00286 while (id != etl::timer::id::NO_TIMER) 00287 { 00288 etl::message_timer_data& timer = ptimers[id]; 00289 id = next(id); 00290 timer.next = etl::timer::id::NO_TIMER; 00291 } 00292 00293 head = etl::timer::id::NO_TIMER; 00294 tail = etl::timer::id::NO_TIMER; 00295 current = etl::timer::id::NO_TIMER; 00296 } 00297 00298 private: 00299 00300 etl::timer::id::type head; 00301 etl::timer::id::type tail; 00302 etl::timer::id::type current; 00303 00304 etl::message_timer_data* const ptimers; 00305 }; 00306 } 00307 00308 //*************************************************************************** 00309 /// Interface for message timer 00310 //*************************************************************************** 00311 class imessage_timer 00312 { 00313 public: 00314 00315 //******************************************* 00316 /// Register a timer. 00317 //******************************************* 00318 etl::timer::id::type register_timer(const etl::imessage& message_, 00319 etl::imessage_router& router_, 00320 uint32_t period_, 00321 bool repeating_, 00322 etl::message_router_id_t destination_router_id_ = etl::imessage_router::ALL_MESSAGE_ROUTERS) 00323 { 00324 etl::timer::id::type id = etl::timer::id::NO_TIMER; 00325 00326 disable_timer_updates(); 00327 00328 bool is_space = (registered_timers < MAX_TIMERS); 00329 00330 if (is_space) 00331 { 00332 // There's no point adding null message routers. 00333 if (!router_.is_null_router()) 00334 { 00335 // Search for the free space. 00336 for (uint_least8_t i = 0; i < MAX_TIMERS; ++i) 00337 { 00338 etl::message_timer_data& timer = timer_array[i]; 00339 00340 if (timer.id == etl::timer::id::NO_TIMER) 00341 { 00342 // Create in-place. 00343 new (&timer) message_timer_data(i, message_, router_, period_, repeating_, destination_router_id_); 00344 ++registered_timers; 00345 id = i; 00346 break; 00347 } 00348 } 00349 } 00350 } 00351 00352 enable_timer_updates(); 00353 00354 return id; 00355 } 00356 00357 //******************************************* 00358 /// Unregister a timer. 00359 //******************************************* 00360 bool unregister_timer(etl::timer::id::type id_) 00361 { 00362 bool result = false; 00363 00364 if (id_ != etl::timer::id::NO_TIMER) 00365 { 00366 disable_timer_updates(); 00367 00368 etl::message_timer_data& timer = timer_array[id_]; 00369 00370 if (timer.id != etl::timer::id::NO_TIMER) 00371 { 00372 if (timer.is_active()) 00373 { 00374 active_list.remove(timer.id, true); 00375 00376 // Reset in-place. 00377 new (&timer) message_timer_data(); 00378 --registered_timers; 00379 00380 result = true; 00381 } 00382 } 00383 00384 enable_timer_updates(); 00385 } 00386 00387 return result; 00388 } 00389 00390 //******************************************* 00391 /// Enable/disable the timer. 00392 //******************************************* 00393 void enable(bool state_) 00394 { 00395 enabled = state_; 00396 } 00397 00398 //******************************************* 00399 /// Get the enable/disable state. 00400 //******************************************* 00401 bool is_running() const 00402 { 00403 return enabled; 00404 } 00405 00406 //******************************************* 00407 /// Clears the timer of data. 00408 //******************************************* 00409 void clear() 00410 { 00411 disable_timer_updates(); 00412 00413 active_list.clear(); 00414 00415 for (int i = 0; i < MAX_TIMERS; ++i) 00416 { 00417 new (&timer_array[i]) message_timer_data(); 00418 } 00419 00420 registered_timers = 0; 00421 00422 enable_timer_updates(); 00423 } 00424 00425 //******************************************* 00426 // Called by the timer service to indicate the 00427 // amount of time that has elapsed since the last successful call to 'tick'. 00428 // Returns true if the tick was processed, 00429 // false if not. 00430 //******************************************* 00431 bool tick(uint32_t count) 00432 { 00433 if (enabled) 00434 { 00435 if (process_semaphore.load() == 0) 00436 { 00437 // We have something to do? 00438 bool has_active = !active_list.empty(); 00439 00440 if (has_active) 00441 { 00442 while (has_active && (count >= active_list.front().delta)) 00443 { 00444 etl::message_timer_data& timer = active_list.front(); 00445 00446 count -= timer.delta; 00447 00448 active_list.remove(timer.id, true); 00449 00450 if (timer.repeating) 00451 { 00452 timer.delta = timer.period; 00453 active_list.insert(timer.id); 00454 } 00455 00456 if (timer.p_router != std::nullptr) 00457 { 00458 if (timer.p_router->is_bus()) 00459 { 00460 // Send to a message bus. 00461 etl::imessage_bus& bus = static_cast<etl::imessage_bus&>(*(timer.p_router)); 00462 bus.receive(timer.destination_router_id, *(timer.p_message)); 00463 } 00464 else 00465 { 00466 // Send to a router. 00467 timer.p_router->receive(*(timer.p_message)); 00468 } 00469 } 00470 00471 has_active = !active_list.empty(); 00472 } 00473 00474 if (has_active) 00475 { 00476 // Subtract any remainder from the next due timeout. 00477 active_list.front().delta -= count; 00478 } 00479 } 00480 00481 return true; 00482 } 00483 } 00484 00485 return false; 00486 } 00487 00488 //******************************************* 00489 /// Starts a timer. 00490 //******************************************* 00491 bool start(etl::timer::id::type id_, bool immediate_ = false) 00492 { 00493 bool result = false; 00494 00495 disable_timer_updates(); 00496 00497 // Valid timer id? 00498 if (id_ != etl::timer::id::NO_TIMER) 00499 { 00500 etl::message_timer_data& timer = timer_array[id_]; 00501 00502 // Registered timer? 00503 if (timer.id != etl::timer::id::NO_TIMER) 00504 { 00505 // Has a valid period. 00506 if (timer.period != etl::timer::state::INACTIVE) 00507 { 00508 if (timer.is_active()) 00509 { 00510 active_list.remove(timer.id, false); 00511 } 00512 00513 timer.delta = immediate_ ? 0 : timer.period; 00514 active_list.insert(timer.id); 00515 00516 result = true; 00517 } 00518 } 00519 } 00520 00521 enable_timer_updates(); 00522 00523 return result; 00524 } 00525 00526 //******************************************* 00527 /// Stops a timer. 00528 //******************************************* 00529 bool stop(etl::timer::id::type id_) 00530 { 00531 bool result = false; 00532 00533 disable_timer_updates(); 00534 00535 // Valid timer id? 00536 if (id_ != etl::timer::id::NO_TIMER) 00537 { 00538 etl::message_timer_data& timer = timer_array[id_]; 00539 00540 // Registered timer? 00541 if (timer.id != etl::timer::id::NO_TIMER) 00542 { 00543 if (timer.is_active()) 00544 { 00545 active_list.remove(timer.id, false); 00546 result = true; 00547 } 00548 } 00549 } 00550 00551 enable_timer_updates(); 00552 00553 return result; 00554 } 00555 00556 //******************************************* 00557 /// Sets a timer's period. 00558 //******************************************* 00559 bool set_period(etl::timer::id::type id_, uint32_t period_) 00560 { 00561 if (stop(id_)) 00562 { 00563 timer_array[id_].period = period_; 00564 return start(id_); 00565 } 00566 00567 return false; 00568 } 00569 00570 //******************************************* 00571 /// Sets a timer's mode. 00572 //******************************************* 00573 bool set_mode(etl::timer::id::type id_, bool repeating_) 00574 { 00575 if (stop(id_)) 00576 { 00577 timer_array[id_].repeating = repeating_; 00578 return start(id_); 00579 } 00580 00581 return false; 00582 } 00583 00584 protected: 00585 00586 //******************************************* 00587 /// Constructor. 00588 //******************************************* 00589 imessage_timer(message_timer_data* const timer_array_, const uint_least8_t MAX_TIMERS_) 00590 : timer_array(timer_array_), 00591 active_list(timer_array_), 00592 enabled(false), 00593 process_semaphore(0), 00594 registered_timers(0), 00595 MAX_TIMERS(MAX_TIMERS_) 00596 { 00597 } 00598 00599 private: 00600 00601 //******************************************* 00602 /// Enable timer callback events. 00603 //******************************************* 00604 void enable_timer_updates() 00605 { 00606 --process_semaphore; 00607 } 00608 00609 //******************************************* 00610 /// Disable timer callback events. 00611 //******************************************* 00612 void disable_timer_updates() 00613 { 00614 ++process_semaphore; 00615 } 00616 00617 // The array of timer data structures. 00618 message_timer_data* const timer_array; 00619 00620 // The list of active timers. 00621 __private_message_timer__::list active_list; 00622 00623 volatile bool enabled; 00624 volatile etl::timer_semaphore_t process_semaphore; 00625 volatile uint_least8_t registered_timers; 00626 00627 public: 00628 00629 const uint_least8_t MAX_TIMERS; 00630 }; 00631 00632 //*************************************************************************** 00633 /// The message timer 00634 //*************************************************************************** 00635 template <uint_least8_t MAX_TIMERS_> 00636 class message_timer : public etl::imessage_timer 00637 { 00638 public: 00639 00640 STATIC_ASSERT(MAX_TIMERS_ <= 254, "No more than 254 timers are allowed"); 00641 00642 //******************************************* 00643 /// Constructor. 00644 //******************************************* 00645 message_timer() 00646 : imessage_timer(timer_array, MAX_TIMERS_) 00647 { 00648 } 00649 00650 private: 00651 00652 message_timer_data timer_array[MAX_TIMERS_]; 00653 }; 00654 } 00655 00656 #undef ETL_FILE 00657 00658 #endif 00659
Generated on Tue Jul 12 2022 14:05:42 by
