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.
callback_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_CALLBACK_TIMER__ 00030 #define __ETL_CALLBACK_TIMER__ 00031 00032 #include <stdint.h> 00033 #include <algorithm> 00034 00035 #include "platform.h " 00036 #include "nullptr.h " 00037 #include "function.h " 00038 #include "static_assert.h" 00039 #include "timer.h" 00040 #include "atomic.h" 00041 00042 #undef ETL_FILE 00043 #define ETL_FILE "42" 00044 00045 namespace etl 00046 { 00047 //************************************************************************* 00048 /// The configuration of a timer. 00049 struct callback_timer_data 00050 { 00051 //******************************************* 00052 callback_timer_data() 00053 : p_callback(std::nullptr), 00054 period(0), 00055 delta(etl::timer::state::INACTIVE), 00056 id(etl::timer::id::NO_TIMER), 00057 previous(etl::timer::id::NO_TIMER), 00058 next(etl::timer::id::NO_TIMER), 00059 repeating(true), 00060 has_c_callback(true) 00061 { 00062 } 00063 00064 //******************************************* 00065 /// C function callback 00066 //******************************************* 00067 callback_timer_data(etl::timer::id::type id_, 00068 void (*p_callback_)(), 00069 uint32_t period_, 00070 bool repeating_) 00071 : p_callback(reinterpret_cast<void*>(p_callback_)), 00072 period(period_), 00073 delta(etl::timer::state::INACTIVE), 00074 id(id_), 00075 previous(etl::timer::id::NO_TIMER), 00076 next(etl::timer::id::NO_TIMER), 00077 repeating(repeating_), 00078 has_c_callback(true) 00079 { 00080 } 00081 00082 //******************************************* 00083 /// ETL function callback 00084 //******************************************* 00085 callback_timer_data(etl::timer::id::type id_, 00086 etl::ifunction<void>& callback_, 00087 uint32_t period_, 00088 bool repeating_) 00089 : p_callback(reinterpret_cast<void*>(&callback_)), 00090 period(period_), 00091 delta(etl::timer::state::INACTIVE), 00092 id(id_), 00093 previous(etl::timer::id::NO_TIMER), 00094 next(etl::timer::id::NO_TIMER), 00095 repeating(repeating_), 00096 has_c_callback(false) 00097 { 00098 } 00099 00100 //******************************************* 00101 /// Returns true if the timer is active. 00102 //******************************************* 00103 bool is_active() const 00104 { 00105 return delta != etl::timer::state::INACTIVE; 00106 } 00107 00108 //******************************************* 00109 /// Sets the timer to the inactive state. 00110 //******************************************* 00111 void set_inactive() 00112 { 00113 delta = etl::timer::state::INACTIVE; 00114 } 00115 00116 void* p_callback; 00117 uint32_t period; 00118 uint32_t delta; 00119 etl::timer::id::type id; 00120 uint_least8_t previous; 00121 uint_least8_t next; 00122 bool repeating; 00123 bool has_c_callback; 00124 00125 private: 00126 00127 // Disabled. 00128 callback_timer_data(const callback_timer_data& other); 00129 callback_timer_data& operator =(const callback_timer_data& other); 00130 }; 00131 00132 namespace __private_callback_timer__ 00133 { 00134 //************************************************************************* 00135 /// A specialised intrusive linked list for timer data. 00136 //************************************************************************* 00137 class list 00138 { 00139 public: 00140 00141 //******************************* 00142 list(etl::callback_timer_data* ptimers_) 00143 : head(etl::timer::id::NO_TIMER), 00144 tail(etl::timer::id::NO_TIMER), 00145 current(etl::timer::id::NO_TIMER), 00146 ptimers(ptimers_) 00147 { 00148 } 00149 00150 //******************************* 00151 bool empty() const 00152 { 00153 return head == etl::timer::id::NO_TIMER; 00154 } 00155 00156 //******************************* 00157 // Inserts the timer at the correct delta position 00158 //******************************* 00159 void insert(etl::timer::id::type id_) 00160 { 00161 etl::callback_timer_data& timer = ptimers[id_]; 00162 00163 if (head == etl::timer::id::NO_TIMER) 00164 { 00165 // No entries yet. 00166 head = id_; 00167 tail = id_; 00168 timer.previous = etl::timer::id::NO_TIMER; 00169 timer.next = etl::timer::id::NO_TIMER; 00170 } 00171 else 00172 { 00173 // We already have entries. 00174 etl::timer::id::type test_id = begin(); 00175 00176 while (test_id != etl::timer::id::NO_TIMER) 00177 { 00178 etl::callback_timer_data& test = ptimers[test_id]; 00179 00180 // Find the correct place to insert. 00181 if (timer.delta <= test.delta) 00182 { 00183 if (test.id == head) 00184 { 00185 head = timer.id; 00186 } 00187 00188 // Insert before test. 00189 timer.previous = test.previous; 00190 test.previous = timer.id; 00191 timer.next = test.id; 00192 00193 // Adjust the next delta to compensate. 00194 test.delta -= timer.delta; 00195 00196 if (timer.previous != etl::timer::id::NO_TIMER) 00197 { 00198 ptimers[timer.previous].next = timer.id; 00199 } 00200 break; 00201 } 00202 else 00203 { 00204 timer.delta -= test.delta; 00205 } 00206 00207 test_id = next(test_id); 00208 } 00209 00210 // Reached the end? 00211 if (test_id == etl::timer::id::NO_TIMER) 00212 { 00213 // Tag on to the tail. 00214 ptimers[tail].next = timer.id; 00215 timer.previous = tail; 00216 timer.next = etl::timer::id::NO_TIMER; 00217 tail = timer.id; 00218 } 00219 } 00220 } 00221 00222 //******************************* 00223 void remove(etl::timer::id::type id_, bool has_expired) 00224 { 00225 etl::callback_timer_data& timer = ptimers[id_]; 00226 00227 if (head == id_) 00228 { 00229 head = timer.next; 00230 } 00231 else 00232 { 00233 ptimers[timer.previous].next = timer.next; 00234 } 00235 00236 if (tail == id_) 00237 { 00238 tail = timer.previous; 00239 } 00240 else 00241 { 00242 ptimers[timer.next].previous = timer.previous; 00243 } 00244 00245 if (!has_expired) 00246 { 00247 // Adjust the next delta. 00248 if (timer.next != etl::timer::id::NO_TIMER) 00249 { 00250 ptimers[timer.next].delta += timer.delta; 00251 } 00252 } 00253 00254 timer.previous = etl::timer::id::NO_TIMER; 00255 timer.next = etl::timer::id::NO_TIMER; 00256 timer.delta = etl::timer::state::INACTIVE; 00257 } 00258 00259 //******************************* 00260 etl::callback_timer_data& front() 00261 { 00262 return ptimers[head]; 00263 } 00264 00265 //******************************* 00266 etl::timer::id::type begin() 00267 { 00268 current = head; 00269 return current; 00270 } 00271 00272 //******************************* 00273 etl::timer::id::type previous(etl::timer::id::type last) 00274 { 00275 current = ptimers[last].previous; 00276 return current; 00277 } 00278 00279 //******************************* 00280 etl::timer::id::type next(etl::timer::id::type last) 00281 { 00282 current = ptimers[last].next; 00283 return current; 00284 } 00285 00286 //******************************* 00287 void clear() 00288 { 00289 etl::timer::id::type id = begin(); 00290 00291 while (id != etl::timer::id::NO_TIMER) 00292 { 00293 etl::callback_timer_data& timer = ptimers[id]; 00294 id = next(id); 00295 timer.next = etl::timer::id::NO_TIMER; 00296 } 00297 00298 head = etl::timer::id::NO_TIMER; 00299 tail = etl::timer::id::NO_TIMER; 00300 current = etl::timer::id::NO_TIMER; 00301 } 00302 00303 private: 00304 00305 etl::timer::id::type head; 00306 etl::timer::id::type tail; 00307 etl::timer::id::type current; 00308 00309 etl::callback_timer_data* const ptimers; 00310 }; 00311 } 00312 00313 //*************************************************************************** 00314 /// Interface for callback timer 00315 //*************************************************************************** 00316 class icallback_timer 00317 { 00318 public: 00319 00320 //******************************************* 00321 /// Register a timer. 00322 //******************************************* 00323 etl::timer::id::type register_timer(void (*p_callback_)(), 00324 uint32_t period_, 00325 bool repeating_) 00326 { 00327 etl::timer::id::type id = etl::timer::id::NO_TIMER; 00328 00329 disable_timer_updates(); 00330 00331 bool is_space = (registered_timers < MAX_TIMERS); 00332 00333 if (is_space) 00334 { 00335 // Search for the free space. 00336 for (uint_least8_t i = 0; i < MAX_TIMERS; ++i) 00337 { 00338 etl::callback_timer_data& timer = timer_array[i]; 00339 00340 if (timer.id == etl::timer::id::NO_TIMER) 00341 { 00342 // Create in-place. 00343 new (&timer) callback_timer_data(i, p_callback_, period_, repeating_); 00344 ++registered_timers; 00345 id = i; 00346 break; 00347 } 00348 } 00349 } 00350 00351 enable_timer_updates(); 00352 00353 return id; 00354 } 00355 00356 //******************************************* 00357 /// Register a timer. 00358 //******************************************* 00359 etl::timer::id::type register_timer(etl::ifunction<void>& callback_, 00360 uint32_t period_, 00361 bool repeating_) 00362 { 00363 etl::timer::id::type id = etl::timer::id::NO_TIMER; 00364 00365 disable_timer_updates(); 00366 00367 bool is_space = (registered_timers < MAX_TIMERS); 00368 00369 if (is_space) 00370 { 00371 // Search for the free space. 00372 for (uint_least8_t i = 0; i < MAX_TIMERS; ++i) 00373 { 00374 etl::callback_timer_data& timer = timer_array[i]; 00375 00376 if (timer.id == etl::timer::id::NO_TIMER) 00377 { 00378 // Create in-place. 00379 new (&timer) callback_timer_data(i, callback_, period_, repeating_); 00380 ++registered_timers; 00381 id = i; 00382 break; 00383 } 00384 } 00385 } 00386 00387 enable_timer_updates(); 00388 00389 return id; 00390 } 00391 00392 //******************************************* 00393 /// Unregister a timer. 00394 //******************************************* 00395 bool unregister_timer(etl::timer::id::type id_) 00396 { 00397 bool result = false; 00398 00399 if (id_ != etl::timer::id::NO_TIMER) 00400 { 00401 disable_timer_updates(); 00402 00403 etl::callback_timer_data& timer = timer_array[id_]; 00404 00405 if (timer.id != etl::timer::id::NO_TIMER) 00406 { 00407 if (timer.is_active()) 00408 { 00409 active_list.remove(timer.id, false); 00410 00411 // Reset in-place. 00412 new (&timer) callback_timer_data(); 00413 --registered_timers; 00414 00415 result = true; 00416 } 00417 } 00418 00419 enable_timer_updates(); 00420 } 00421 00422 return result; 00423 } 00424 00425 //******************************************* 00426 /// Enable/disable the timer. 00427 //******************************************* 00428 void enable(bool state_) 00429 { 00430 enabled = state_; 00431 } 00432 00433 //******************************************* 00434 /// Get the enable/disable state. 00435 //******************************************* 00436 bool is_running() const 00437 { 00438 return enabled; 00439 } 00440 00441 //******************************************* 00442 /// Clears the timer of data. 00443 //******************************************* 00444 void clear() 00445 { 00446 disable_timer_updates(); 00447 00448 active_list.clear(); 00449 00450 for (int i = 0; i < MAX_TIMERS; ++i) 00451 { 00452 new (&timer_array[i]) callback_timer_data(); 00453 } 00454 00455 registered_timers = 0; 00456 00457 enable_timer_updates(); 00458 } 00459 00460 //******************************************* 00461 // Called by the timer service to indicate the 00462 // amount of time that has elapsed since the last successful call to 'tick'. 00463 // Returns true if the tick was processed, 00464 // false if not. 00465 //******************************************* 00466 bool tick(uint32_t count) 00467 { 00468 if (enabled) 00469 { 00470 if (process_semaphore.load() == 0) 00471 { 00472 // We have something to do? 00473 bool has_active = !active_list.empty(); 00474 00475 if (has_active) 00476 { 00477 while (has_active && (count >= active_list.front().delta)) 00478 { 00479 etl::callback_timer_data& timer = active_list.front(); 00480 00481 count -= timer.delta; 00482 00483 active_list.remove(timer.id, true); 00484 00485 if (timer.repeating) 00486 { 00487 // Reinsert the timer. 00488 timer.delta = timer.period; 00489 active_list.insert(timer.id); 00490 } 00491 00492 if (timer.p_callback != std::nullptr) 00493 { 00494 if (timer.has_c_callback) 00495 { 00496 // Call the C callback. 00497 reinterpret_cast<void(*)()>(timer.p_callback)(); 00498 } 00499 else 00500 { 00501 // Call the function wrapper callback. 00502 (*reinterpret_cast<etl::ifunction<void>*>(timer.p_callback))(); 00503 } 00504 } 00505 00506 has_active = !active_list.empty(); 00507 } 00508 00509 if (has_active) 00510 { 00511 // Subtract any remainder from the next due timeout. 00512 active_list.front().delta -= count; 00513 } 00514 } 00515 00516 return true; 00517 } 00518 } 00519 00520 return false; 00521 } 00522 00523 //******************************************* 00524 /// Starts a timer. 00525 //******************************************* 00526 bool start(etl::timer::id::type id_, bool immediate_ = false) 00527 { 00528 disable_timer_updates(); 00529 00530 bool result = false; 00531 00532 // Valid timer id? 00533 if (id_ != etl::timer::id::NO_TIMER) 00534 { 00535 etl::callback_timer_data& timer = timer_array[id_]; 00536 00537 // Registered timer? 00538 if (timer.id != etl::timer::id::NO_TIMER) 00539 { 00540 // Has a valid period. 00541 if (timer.period != etl::timer::state::INACTIVE) 00542 { 00543 if (timer.is_active()) 00544 { 00545 active_list.remove(timer.id, false); 00546 } 00547 00548 timer.delta = immediate_ ? 0 : timer.period; 00549 active_list.insert(timer.id); 00550 00551 result = true; 00552 } 00553 } 00554 } 00555 00556 enable_timer_updates(); 00557 00558 return result; 00559 } 00560 00561 //******************************************* 00562 /// Stops a timer. 00563 //******************************************* 00564 bool stop(etl::timer::id::type id_) 00565 { 00566 disable_timer_updates(); 00567 00568 bool result = false; 00569 00570 // Valid timer id? 00571 if (id_ != etl::timer::id::NO_TIMER) 00572 { 00573 etl::callback_timer_data& timer = timer_array[id_]; 00574 00575 // Registered timer? 00576 if (timer.id != etl::timer::id::NO_TIMER) 00577 { 00578 if (timer.is_active()) 00579 { 00580 active_list.remove(timer.id, false); 00581 result = true; 00582 } 00583 } 00584 } 00585 00586 enable_timer_updates(); 00587 00588 return result; 00589 } 00590 00591 //******************************************* 00592 /// Sets a timer's period. 00593 //******************************************* 00594 bool set_period(etl::timer::id::type id_, uint32_t period_) 00595 { 00596 if (stop(id_)) 00597 { 00598 timer_array[id_].period = period_; 00599 return start(id_); 00600 } 00601 00602 return false; 00603 } 00604 00605 //******************************************* 00606 /// Sets a timer's mode. 00607 //******************************************* 00608 bool set_mode(etl::timer::id::type id_, bool repeating_) 00609 { 00610 if (stop(id_)) 00611 { 00612 timer_array[id_].repeating = repeating_; 00613 return start(id_); 00614 } 00615 00616 return false; 00617 } 00618 00619 protected: 00620 00621 //******************************************* 00622 /// Constructor. 00623 //******************************************* 00624 icallback_timer(callback_timer_data* const timer_array_, const uint_least8_t MAX_TIMERS_) 00625 : timer_array(timer_array_), 00626 active_list(timer_array_), 00627 enabled(false), 00628 process_semaphore(0), 00629 registered_timers(0), 00630 MAX_TIMERS(MAX_TIMERS_) 00631 { 00632 } 00633 00634 private: 00635 00636 //******************************************* 00637 /// Enable timer callback events. 00638 //******************************************* 00639 void enable_timer_updates() 00640 { 00641 --process_semaphore; 00642 } 00643 00644 //******************************************* 00645 /// Disable timer callback events. 00646 //******************************************* 00647 void disable_timer_updates() 00648 { 00649 ++process_semaphore; 00650 } 00651 00652 // The array of timer data structures. 00653 callback_timer_data* const timer_array; 00654 00655 // The list of active timers. 00656 __private_callback_timer__::list active_list; 00657 00658 volatile bool enabled; 00659 volatile etl::timer_semaphore_t process_semaphore; 00660 volatile uint_least8_t registered_timers; 00661 00662 public: 00663 00664 const uint_least8_t MAX_TIMERS; 00665 }; 00666 00667 //*************************************************************************** 00668 /// The callback timer 00669 //*************************************************************************** 00670 template <const uint_least8_t MAX_TIMERS_> 00671 class callback_timer : public etl::icallback_timer 00672 { 00673 public: 00674 00675 STATIC_ASSERT(MAX_TIMERS_ <= 254, "No more than 254 timers are allowed"); 00676 00677 //******************************************* 00678 /// Constructor. 00679 //******************************************* 00680 callback_timer() 00681 : icallback_timer(timer_array, MAX_TIMERS_) 00682 { 00683 } 00684 00685 private: 00686 00687 callback_timer_data timer_array[MAX_TIMERS_]; 00688 }; 00689 } 00690 00691 #undef ETL_FILE 00692 00693 #endif 00694
Generated on Tue Jul 12 2022 14:05:39 by
