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.
ecl_timer.c
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 #include <stdint.h> 00030 #include <assert.h> 00031 00032 #include "ecl_timer.h" 00033 00034 //***************************************************************************** 00035 // Internal timer list 00036 //***************************************************************************** 00037 00038 static ecl_timer_id_t head; 00039 static ecl_timer_id_t tail; 00040 static ecl_timer_id_t current; 00041 00042 static struct ecl_timer_config* ptimers; 00043 00044 static void ecl_timer_list_init(struct ecl_timer_config* const ptimers_) 00045 { 00046 ptimers = ptimers_; 00047 head = ECL_TIMER_NO_TIMER; 00048 tail = ECL_TIMER_NO_TIMER; 00049 current = ECL_TIMER_NO_TIMER; 00050 } 00051 00052 //******************************* 00053 static struct ecl_timer_config* ecl_timer_list_front() 00054 { 00055 return &ptimers[head]; 00056 } 00057 00058 //******************************* 00059 static ecl_timer_id_t ecl_timer_list_begin() 00060 { 00061 current = head; 00062 return current; 00063 } 00064 00065 //******************************* 00066 static ecl_timer_id_t ecl_timer_list_next(ecl_timer_id_t last) 00067 { 00068 current = ptimers[last].next; 00069 return current; 00070 } 00071 00072 //******************************* 00073 static int ecl_timer_list_empty() 00074 { 00075 return head == ECL_TIMER_NO_TIMER; 00076 } 00077 00078 //******************************* 00079 // Inserts the timer at the correct delta position 00080 //******************************* 00081 static void ecl_timer_list_insert(ecl_timer_id_t id_) 00082 { 00083 struct ecl_timer_config* ptimer = &ptimers[id_]; 00084 00085 if (head == ECL_TIMER_NO_TIMER) 00086 { 00087 // No entries yet. 00088 head = id_; 00089 tail = id_; 00090 ptimer->previous = ECL_TIMER_NO_TIMER; 00091 ptimer->next = ECL_TIMER_NO_TIMER; 00092 } 00093 else 00094 { 00095 // We already have entries. 00096 ecl_timer_id_t test_id = ecl_timer_list_begin(); 00097 00098 while (test_id != ECL_TIMER_NO_TIMER) 00099 { 00100 struct ecl_timer_config* ptest = &ptimers[test_id]; 00101 00102 // Find the correct place to insert. 00103 if (ptimer->delta <= ptest->delta) 00104 { 00105 if (ptest->id == head) 00106 { 00107 head = ptimer->id; 00108 } 00109 00110 // Insert before ptest-> 00111 ptimer->previous = ptest->previous; 00112 ptest->previous = ptimer->id; 00113 ptimer->next = ptest->id; 00114 00115 // Adjust the next delta to compensate. 00116 ptest->delta -= ptimer->delta; 00117 00118 if (ptimer->previous != ECL_TIMER_NO_TIMER) 00119 { 00120 ptimers[ptimer->previous].next = ptimer->id; 00121 } 00122 break; 00123 } 00124 else 00125 { 00126 ptimer->delta -= ptest->delta; 00127 } 00128 00129 test_id = ecl_timer_list_next(test_id); 00130 } 00131 00132 // Reached the end? 00133 if (test_id == ECL_TIMER_NO_TIMER) 00134 { 00135 // Tag on to the tail. 00136 ptimers[tail].next = ptimer->id; 00137 ptimer->previous = tail; 00138 ptimer->next = ECL_TIMER_NO_TIMER; 00139 tail = ptimer->id; 00140 } 00141 } 00142 } 00143 00144 //******************************* 00145 static void ecl_timer_list_remove(ecl_timer_id_t id_, int has_expired) 00146 { 00147 struct ecl_timer_config* ptimer = &ptimers[id_]; 00148 00149 if (head == id_) 00150 { 00151 head = ptimer->next; 00152 } 00153 else 00154 { 00155 ptimers[ptimer->previous].next = ptimer->next; 00156 } 00157 00158 if (tail == id_) 00159 { 00160 tail = ptimer->previous; 00161 } 00162 else 00163 { 00164 ptimers[ptimer->next].previous = ptimer->previous; 00165 } 00166 00167 if (!has_expired) 00168 { 00169 // Adjust the next delta. 00170 if (ptimer->next != ECL_TIMER_NO_TIMER) 00171 { 00172 ptimers[ptimer->next].delta += ptimer->delta; 00173 } 00174 } 00175 00176 ptimer->previous = ECL_TIMER_NO_TIMER; 00177 ptimer->next = ECL_TIMER_NO_TIMER; 00178 ptimer->delta = ECL_TIMER_INACTIVE; 00179 } 00180 00181 //******************************* 00182 static void ecl_timer_list_clear() 00183 { 00184 ecl_timer_id_t id = ecl_timer_list_begin(); 00185 00186 while (id != ECL_TIMER_NO_TIMER) 00187 { 00188 struct ecl_timer_config* ptimer = &ptimers[id]; 00189 id = ecl_timer_list_next(id); 00190 ptimer->next = ECL_TIMER_NO_TIMER; 00191 } 00192 00193 head = ECL_TIMER_NO_TIMER; 00194 tail = ECL_TIMER_NO_TIMER; 00195 current = ECL_TIMER_NO_TIMER; 00196 } 00197 00198 //***************************************************************************** 00199 // Timer Framework 00200 //***************************************************************************** 00201 00202 //******************************************* 00203 /// Default initialisation. 00204 //******************************************* 00205 void ecl_timer_data_init_default(struct ecl_timer_config* ptimer_data_) 00206 { 00207 assert(ptimer_data_ != 0); 00208 00209 ptimer_data_->pcallback = 0; 00210 ptimer_data_->period = 0; 00211 ptimer_data_->delta = ECL_TIMER_INACTIVE; 00212 ptimer_data_->id = ECL_TIMER_NO_TIMER; 00213 ptimer_data_->previous = ECL_TIMER_NO_TIMER; 00214 ptimer_data_->next = ECL_TIMER_NO_TIMER; 00215 ptimer_data_->repeating = ECL_TIMER_REPEATING; 00216 } 00217 00218 //******************************************* 00219 /// Parameterised initialisation. 00220 //******************************************* 00221 void ecl_timer_data_init(struct ecl_timer_config* ptimer_data_, 00222 ecl_timer_id_t id_, 00223 void (*pcallback_)(), 00224 ecl_timer_time_t period_, 00225 ecl_timer_mode_t repeating_) 00226 { 00227 assert(ptimer_data_ != 0); 00228 assert(pcallback_ != 0); 00229 00230 ptimer_data_->pcallback = pcallback_; 00231 ptimer_data_->period = period_; 00232 ptimer_data_->delta = ECL_TIMER_INACTIVE; 00233 ptimer_data_->id = id_; 00234 ptimer_data_->previous = ECL_TIMER_NO_TIMER; 00235 ptimer_data_->next = ECL_TIMER_NO_TIMER; 00236 ptimer_data_->repeating = repeating_; 00237 } 00238 00239 //******************************************* 00240 /// Returns true if the timer is active. 00241 //******************************************* 00242 ecl_timer_result_t ecl_timer_is_active(struct ecl_timer_config* ptimer_data_) 00243 { 00244 assert(ptimer_data_ != 0); 00245 00246 return (ptimer_data_->delta != ECL_TIMER_INACTIVE) ? ECL_TIMER_PASS : ECL_TIMER_FAIL; 00247 } 00248 00249 //******************************************* 00250 /// Sets the timer to the inactive state. 00251 //******************************************* 00252 void ecl_set_timer_inactive(struct ecl_timer_config* ptimer_data_) 00253 { 00254 assert(ptimer_data_ != 0); 00255 00256 ptimer_data_->delta = ECL_TIMER_INACTIVE; 00257 } 00258 00259 struct ecl_time_config 00260 { 00261 struct ecl_timer_config* ptimers; 00262 uint_least8_t max_timers; 00263 volatile ecl_timer_enable_t enabled; 00264 ECL_TIMER_TIMER_SEMAPHORE process_semaphore; 00265 volatile uint_least8_t registered_timers; 00266 }; 00267 00268 static struct ecl_time_config ecl; 00269 00270 void ecl_timer_init(struct ecl_timer_config* ptimers_, uint_least8_t max_timers_) 00271 { 00272 assert(ptimers_ != 0); 00273 00274 ecl.ptimers = ptimers_; 00275 ecl.max_timers = max_timers_; 00276 ecl.enabled = 0; 00277 ecl.process_semaphore = 0; 00278 ecl.registered_timers = 0; 00279 00280 int i; 00281 for (i = 0; i < max_timers_; ++i) 00282 { 00283 ecl_timer_data_init_default(&ecl.ptimers[i]); 00284 } 00285 00286 ecl_timer_list_init(ecl.ptimers); 00287 } 00288 00289 //******************************************* 00290 /// Register a ptimer-> 00291 //******************************************* 00292 ecl_timer_id_t ecl_timer_register(void (*pcallback_)(), 00293 ecl_timer_time_t period_, 00294 ecl_timer_mode_t repeating_) 00295 { 00296 assert(pcallback_ != 0); 00297 assert(ecl.ptimers != 0); 00298 00299 ecl_timer_id_t id = ECL_TIMER_NO_TIMER; 00300 00301 ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); 00302 00303 int is_space = (ecl.registered_timers < ecl.max_timers); 00304 00305 if (is_space) 00306 { 00307 // Search for the free space. 00308 uint_least8_t i; 00309 for (i = 0; i < ecl.max_timers; ++i) 00310 { 00311 struct ecl_timer_config* ptimer = &ecl.ptimers[i]; 00312 00313 if (ptimer->id == ECL_TIMER_NO_TIMER) 00314 { 00315 // Create in-place. 00316 ecl_timer_data_init(ptimer, i, pcallback_, period_, repeating_); 00317 ++ecl.registered_timers; 00318 id = i; 00319 break; 00320 } 00321 } 00322 } 00323 00324 ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); 00325 00326 return id; 00327 } 00328 00329 //******************************************* 00330 /// Unregister a ptimer-> 00331 //******************************************* 00332 ecl_timer_result_t ecl_timer_unregister(ecl_timer_id_t id_) 00333 { 00334 assert(ecl.ptimers != 0); 00335 00336 ecl_timer_result_t result = ECL_TIMER_FAIL; 00337 00338 if (id_ != ECL_TIMER_NO_TIMER) 00339 { 00340 ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); 00341 00342 struct ecl_timer_config* ptimer = &ecl.ptimers[id_]; 00343 00344 if (ptimer->id != ECL_TIMER_NO_TIMER) 00345 { 00346 if (ecl_timer_is_active(ptimer)) 00347 { 00348 ecl_timer_list_remove(ptimer->id, 0); 00349 00350 // Reset in-place. 00351 ecl_timer_data_init_default(ptimer); 00352 --ecl.registered_timers; 00353 00354 result = ECL_TIMER_PASS; 00355 } 00356 } 00357 00358 ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); 00359 } 00360 00361 return result; 00362 } 00363 00364 //******************************************* 00365 /// Enable/disable the ptimer-> 00366 //******************************************* 00367 void ecl_timer_enable(ecl_timer_enable_t state_) 00368 { 00369 assert(ecl.ptimers != 0); 00370 assert((state_ == ECL_TIMER_ENABLED) || (state_ == ECL_TIMER_DISABLED)); 00371 00372 ecl.enabled = state_; 00373 } 00374 00375 //******************************************* 00376 /// Get the enable/disable state. 00377 //******************************************* 00378 ecl_timer_result_t ecl_timer_is_running() 00379 { 00380 return ecl.enabled; 00381 } 00382 00383 //******************************************* 00384 /// Clears the timer of data. 00385 //******************************************* 00386 void ecl_timer_clear() 00387 { 00388 ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); 00389 00390 ecl_timer_list_clear(); 00391 00392 int i; 00393 for (i = 0; i < ecl.max_timers; ++i) 00394 { 00395 ecl_timer_data_init_default(&ecl.ptimers[i]); 00396 } 00397 00398 ecl.registered_timers = 0; 00399 00400 ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); 00401 } 00402 00403 //******************************************* 00404 // Called by the timer service to indicate the 00405 // amount of time that has elapsed since the last successful call to 'tick'. 00406 // Returns true if the tick was processed, false if not. 00407 //******************************************* 00408 ecl_timer_result_t ecl_timer_tick(uint32_t count) 00409 { 00410 assert(ecl.ptimers != 0); 00411 00412 if (ecl.enabled) 00413 { 00414 if (ECL_TIMER_PROCESSING_ENABLED(ecl.process_semaphore)) 00415 { 00416 // We have something to do? 00417 int has_active = !ecl_timer_list_empty(); 00418 00419 if (has_active) 00420 { 00421 while (has_active && (count >= ecl_timer_list_front()->delta)) 00422 { 00423 struct ecl_timer_config* ptimer = ecl_timer_list_front(); 00424 00425 count -= ptimer->delta; 00426 00427 ecl_timer_list_remove(ptimer->id, 1); 00428 00429 if (ptimer->repeating) 00430 { 00431 // Reinsert the ptimer-> 00432 ptimer->delta = ptimer->period; 00433 ecl_timer_list_insert(ptimer->id); 00434 } 00435 00436 if (ptimer->pcallback != 0) 00437 { 00438 // Call the C callback. 00439 (ptimer->pcallback)(); 00440 } 00441 00442 has_active = !ecl_timer_list_empty(); 00443 } 00444 00445 if (has_active) 00446 { 00447 // Subtract any remainder from the next due timeout. 00448 ecl_timer_list_front()->delta -= count; 00449 } 00450 } 00451 00452 return ECL_TIMER_PASS; 00453 } 00454 } 00455 00456 return ECL_TIMER_FAIL; 00457 } 00458 00459 //******************************************* 00460 /// Starts a timer 00461 //******************************************* 00462 ecl_timer_result_t ecl_timer_start(ecl_timer_id_t id_, ecl_timer_start_t immediate_) 00463 { 00464 assert(ecl.ptimers != 0); 00465 00466 ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); 00467 00468 ecl_timer_result_t result = ECL_TIMER_FAIL; 00469 00470 // Valid timer id? 00471 if (id_ != ECL_TIMER_NO_TIMER) 00472 { 00473 struct ecl_timer_config* ptimer = &ecl.ptimers[id_]; 00474 00475 // Registered timer? 00476 if (ptimer->id != ECL_TIMER_NO_TIMER) 00477 { 00478 // Has a valid period. 00479 if (ptimer->period != ECL_TIMER_INACTIVE) 00480 { 00481 if (ecl_timer_is_active(ptimer)) 00482 { 00483 ecl_timer_list_remove(ptimer->id, 0); 00484 } 00485 00486 ptimer->delta = immediate_ ? 0 : ptimer->period; 00487 ecl_timer_list_insert(ptimer->id); 00488 00489 result = ECL_TIMER_PASS; 00490 } 00491 } 00492 } 00493 00494 ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); 00495 00496 return result; 00497 } 00498 00499 //******************************************* 00500 /// Stops a timer 00501 //******************************************* 00502 ecl_timer_result_t ecl_timer_stop(ecl_timer_id_t id_) 00503 { 00504 assert(ecl.ptimers != 0); 00505 00506 ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); 00507 00508 ecl_timer_result_t result = ECL_TIMER_FAIL; 00509 00510 // Valid timer id? 00511 if (id_ != ECL_TIMER_NO_TIMER) 00512 { 00513 struct ecl_timer_config* ptimer = &ecl.ptimers[id_]; 00514 00515 // Registered timer? 00516 if (ptimer->id != ECL_TIMER_NO_TIMER) 00517 { 00518 if (ecl_timer_is_active(ptimer)) 00519 { 00520 ecl_timer_list_remove(ptimer->id, 0); 00521 result = ECL_TIMER_PASS; 00522 } 00523 } 00524 } 00525 00526 ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); 00527 00528 return result; 00529 } 00530 00531 //******************************************* 00532 /// Sets a timer's period. 00533 //******************************************* 00534 ecl_timer_result_t ecl_timer_set_period(ecl_timer_id_t id_, ecl_timer_time_t period_) 00535 { 00536 assert(ecl.ptimers != 0); 00537 00538 if (ecl_timer_stop(id_)) 00539 { 00540 ecl.ptimers[id_].period = period_; 00541 return ecl_timer_start(id_, 0); 00542 } 00543 00544 return ECL_TIMER_FAIL; 00545 } 00546 00547 //******************************************* 00548 /// Sets a timer's mode. 00549 //******************************************* 00550 ecl_timer_result_t ecl_timer_set_mode(ecl_timer_id_t id_, ecl_timer_mode_t repeating_) 00551 { 00552 assert(ecl.ptimers != 0); 00553 00554 if (ecl_timer_stop(id_)) 00555 { 00556 ecl.ptimers[id_].repeating = repeating_; 00557 return ecl_timer_start(id_, 0); 00558 } 00559 00560 return ECL_TIMER_FAIL; 00561 } 00562 00563 00564 00565 00566
Generated on Tue Jul 12 2022 14:05:40 by
