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.
Fork of OmniWheels by
ns_timer.c
00001 /* 00002 * Copyright (c) 2014-2015 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "ns_types.h" 00018 #include "ns_list.h" 00019 #include "ns_timer.h" 00020 #include "eventOS_callback_timer.h" 00021 #include "platform/arm_hal_interrupt.h" 00022 #include "platform/arm_hal_timer.h" 00023 #include "nsdynmemLIB.h" 00024 00025 #ifndef NS_EXCLUDE_HIGHRES_TIMER 00026 typedef enum ns_timer_state_e { 00027 NS_TIMER_ACTIVE = 0, // Will run on the next HAL interrupt 00028 NS_TIMER_HOLD, // Will run on a later HAL interrupt 00029 NS_TIMER_RUN_INTERRUPT, // Running on the interrupt we're currently handling 00030 NS_TIMER_STOP // Timer not scheduled ("start" not called since last callback) 00031 } ns_timer_state_e; 00032 00033 typedef struct ns_timer_struct { 00034 int8_t ns_timer_id; 00035 ns_timer_state_e timer_state; 00036 uint16_t slots; 00037 uint16_t remaining_slots; 00038 void (*interrupt_handler)(int8_t, uint16_t); 00039 ns_list_link_t link; 00040 } ns_timer_struct; 00041 00042 static NS_LIST_DEFINE(ns_timer_list, ns_timer_struct, link); 00043 00044 #define NS_TIMER_RUNNING 1 00045 static uint8_t ns_timer_state = 0; 00046 00047 #ifdef ATMEGA256RFR2 00048 #define COMPENSATION 3 00049 #define COMPENSATION_TUNE 1 00050 #else 00051 #define COMPENSATION 0 00052 #define COMPENSATION_TUNE 0 00053 #endif 00054 00055 static void ns_timer_interrupt_handler(void); 00056 static ns_timer_struct *ns_timer_get_pointer_to_timer_struct(int8_t timer_id); 00057 static bool ns_timer_initialized = 0; 00058 00059 int8_t eventOS_callback_timer_register(void (*timer_interrupt_handler)(int8_t, uint16_t)) 00060 { 00061 int8_t retval = -1; 00062 00063 if (!ns_timer_initialized) { 00064 /*Set interrupt handler in HAL driver*/ 00065 platform_timer_set_cb(ns_timer_interrupt_handler); 00066 ns_timer_initialized = 1; 00067 } 00068 00069 /*Find first free timer ID in timer list*/ 00070 /*(Note use of uint8_t to avoid overflow if we reach 0x7F)*/ 00071 for (uint8_t i = 0; i <= INT8_MAX; i++) { 00072 if (!ns_timer_get_pointer_to_timer_struct(i)) { 00073 retval = i; 00074 break; 00075 } 00076 } 00077 00078 if (retval == -1) { 00079 return -1; 00080 } 00081 00082 ns_timer_struct *new_timer = ns_dyn_mem_alloc(sizeof(ns_timer_struct)); 00083 if (!new_timer) { 00084 return -1; 00085 } 00086 00087 /*Initialise new timer*/ 00088 new_timer->ns_timer_id = retval; 00089 new_timer->timer_state = NS_TIMER_STOP; 00090 new_timer->remaining_slots = 0; 00091 new_timer->interrupt_handler = timer_interrupt_handler; 00092 00093 // Critical section sufficient as long as list can't be reordered from 00094 // interrupt, otherwise will need to cover whole routine 00095 platform_enter_critical(); 00096 ns_list_add_to_end(&ns_timer_list, new_timer); 00097 platform_exit_critical(); 00098 00099 /*Return timer ID*/ 00100 return retval; 00101 } 00102 00103 int8_t eventOS_callback_timer_unregister(int8_t ns_timer_id) 00104 { 00105 ns_timer_struct *current_timer; 00106 00107 current_timer = ns_timer_get_pointer_to_timer_struct(ns_timer_id); 00108 if (!current_timer) { 00109 return -1; 00110 } 00111 00112 // Critical section sufficient as long as list can't be reordered from 00113 // interrupt, otherwise will need to cover whole routine 00114 platform_enter_critical(); 00115 ns_list_remove(&ns_timer_list, current_timer); 00116 platform_exit_critical(); 00117 00118 ns_dyn_mem_free(current_timer); 00119 return 0; 00120 } 00121 00122 00123 static int8_t ns_timer_start_pl_timer(uint16_t pl_timer_start_slots) 00124 { 00125 /*Don't start timer with 0 slots*/ 00126 if (!pl_timer_start_slots) { 00127 pl_timer_start_slots = 1; 00128 } 00129 00130 /*Start HAL timer*/ 00131 platform_timer_start(pl_timer_start_slots); 00132 /*Set HAL timer state to running*/ 00133 ns_timer_state |= NS_TIMER_RUNNING; 00134 return 0; 00135 } 00136 00137 int8_t ns_timer_sleep(void) 00138 { 00139 int8_t ret_val = -1; 00140 if (ns_timer_state & NS_TIMER_RUNNING) { 00141 /*Start HAL timer*/ 00142 platform_timer_disable(); 00143 /*Set HAL timer state to running*/ 00144 ns_timer_state &= ~NS_TIMER_RUNNING; 00145 ret_val = 0; 00146 } 00147 return ret_val; 00148 } 00149 00150 static int8_t ns_timer_get_next_running_to(void) 00151 { 00152 uint8_t hold_count = 0; 00153 ns_timer_struct *first_timer = NULL; 00154 00155 /*Find hold-labelled timer with the least remaining slots*/ 00156 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00157 if (current_timer->timer_state == NS_TIMER_HOLD) { 00158 if (!first_timer || current_timer->remaining_slots < first_timer->remaining_slots) { 00159 first_timer = current_timer; 00160 } 00161 /*For optimisation, count the found timers*/ 00162 hold_count++; 00163 } 00164 } 00165 00166 if (!first_timer) { 00167 return 0; 00168 } 00169 00170 /*If hold-labelled timer found, set it active and start the HAL driver*/ 00171 hold_count--; 00172 first_timer->timer_state = NS_TIMER_ACTIVE; 00173 /*Compensate time spent in timer function*/ 00174 if (first_timer->remaining_slots > COMPENSATION) { 00175 first_timer->remaining_slots -= COMPENSATION; 00176 } 00177 /*Start HAL timer*/ 00178 ns_timer_start_pl_timer(first_timer->remaining_slots); 00179 00180 /*Update other hold-labelled timers*/ 00181 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00182 if (hold_count == 0) { // early termination optimisation 00183 break; 00184 } 00185 if (current_timer->timer_state == NS_TIMER_HOLD) { 00186 if (current_timer->remaining_slots == first_timer->remaining_slots) { 00187 current_timer->timer_state = NS_TIMER_ACTIVE; 00188 } else { 00189 current_timer->remaining_slots -= first_timer->remaining_slots; 00190 /*Compensate time spent in timer function*/ 00191 if (current_timer->remaining_slots > COMPENSATION) { 00192 current_timer->remaining_slots -= COMPENSATION; 00193 } 00194 } 00195 hold_count--; 00196 } 00197 } 00198 00199 return 0; 00200 } 00201 00202 00203 static ns_timer_struct *ns_timer_get_pointer_to_timer_struct(int8_t timer_id) 00204 { 00205 /*Find timer with the given ID*/ 00206 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00207 if (current_timer->ns_timer_id == timer_id) { 00208 return current_timer; 00209 } 00210 } 00211 return NULL; 00212 } 00213 00214 int8_t eventOS_callback_timer_start(int8_t ns_timer_id, uint16_t slots) 00215 { 00216 int8_t ret_val = 0; 00217 uint16_t pl_timer_remaining_slots; 00218 ns_timer_struct *timer; 00219 platform_enter_critical(); 00220 00221 /*Find timer to be activated*/ 00222 timer = ns_timer_get_pointer_to_timer_struct(ns_timer_id); 00223 if (!timer) { 00224 ret_val = -1; 00225 goto exit; 00226 } 00227 00228 // XXX this assumes the timer currently isn't running? 00229 // Is event.c relying on this restarting HAL timer after ns_timer_sleep()? 00230 00231 /*If any timers are active*/ 00232 if (ns_timer_state & NS_TIMER_RUNNING) { 00233 /*Get remaining slots of the currently activated timeout*/ 00234 pl_timer_remaining_slots = platform_timer_get_remaining_slots(); 00235 00236 /*New timeout is shorter than currently enabled timeout*/ 00237 if (pl_timer_remaining_slots > slots) { 00238 /*Start HAL timer*/ 00239 ns_timer_start_pl_timer(slots - 0); 00240 00241 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00242 /*Switch active timers to hold*/ 00243 if (current_timer->timer_state == NS_TIMER_ACTIVE) { 00244 current_timer->timer_state = NS_TIMER_HOLD; 00245 current_timer->remaining_slots = 0; 00246 } 00247 /*Update hold-labelled timers*/ 00248 if (current_timer->timer_state == NS_TIMER_HOLD) { 00249 current_timer->remaining_slots += (pl_timer_remaining_slots - slots); 00250 /*Compensate time spent in timer function*/ 00251 if (current_timer->remaining_slots > (COMPENSATION - COMPENSATION_TUNE)) { 00252 current_timer->remaining_slots -= (COMPENSATION - COMPENSATION_TUNE); 00253 } 00254 } 00255 } 00256 /*Mark active and start the timer*/ 00257 timer->timer_state = NS_TIMER_ACTIVE; 00258 timer->slots = slots; 00259 timer->remaining_slots = slots; 00260 } 00261 00262 /*New timeout is longer than currently enabled timeout*/ 00263 else if (pl_timer_remaining_slots < slots) { 00264 /*Mark hold and update remaining slots*/ 00265 timer->timer_state = NS_TIMER_HOLD; 00266 timer->slots = slots; 00267 timer->remaining_slots = (slots - pl_timer_remaining_slots); 00268 } 00269 /*New timeout is equal to currently enabled timeout*/ 00270 else { 00271 /*Mark it active and it will be handled in next interrupt*/ 00272 timer->timer_state = NS_TIMER_ACTIVE; 00273 timer->slots = slots; 00274 timer->remaining_slots = slots; 00275 } 00276 } else { 00277 /*No timers running*/ 00278 timer->timer_state = NS_TIMER_HOLD; 00279 timer->slots = slots; 00280 timer->remaining_slots = slots; 00281 /*Start next timeout*/ 00282 ns_timer_get_next_running_to(); 00283 } 00284 exit: 00285 platform_exit_critical(); 00286 return ret_val; 00287 } 00288 00289 static void ns_timer_interrupt_handler(void) 00290 { 00291 uint8_t i = 0; 00292 00293 platform_enter_critical(); 00294 /*Clear timer running state*/ 00295 ns_timer_state &= ~NS_TIMER_RUNNING; 00296 /*Mark active timers as NS_TIMER_RUN_INTERRUPT, interrupt functions are called at the end of this function*/ 00297 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00298 if (current_timer->timer_state == NS_TIMER_ACTIVE) { 00299 current_timer->timer_state = NS_TIMER_RUN_INTERRUPT; 00300 /*For optimisation, count the found timers*/ 00301 i++; 00302 } 00303 } 00304 00305 /*Start next timeout*/ 00306 ns_timer_get_next_running_to(); 00307 00308 /*Call interrupt functions*/ 00309 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00310 if (i == 0) { 00311 break; 00312 } 00313 if (current_timer->timer_state == NS_TIMER_RUN_INTERRUPT) { 00314 current_timer->timer_state = NS_TIMER_STOP; 00315 current_timer->interrupt_handler(current_timer->ns_timer_id, current_timer->slots); 00316 i--; 00317 } 00318 } 00319 00320 platform_exit_critical(); 00321 } 00322 00323 int8_t eventOS_callback_timer_stop(int8_t ns_timer_id) 00324 { 00325 uint16_t pl_timer_remaining_slots; 00326 bool active_timer_found = false; 00327 ns_timer_struct *current_timer; 00328 ns_timer_struct *first_timer = NULL; 00329 int8_t retval = -1; 00330 00331 platform_enter_critical(); 00332 /*Find timer with given timer ID*/ 00333 current_timer = ns_timer_get_pointer_to_timer_struct(ns_timer_id); 00334 if (!current_timer) { 00335 goto exit; 00336 } 00337 00338 retval = 0; 00339 00340 /*Check if already stopped*/ 00341 if (current_timer->timer_state == NS_TIMER_STOP) { 00342 goto exit; 00343 } 00344 00345 current_timer->timer_state = NS_TIMER_STOP; 00346 current_timer->remaining_slots = 0; 00347 00348 /*Check if some timer is already active*/ 00349 ns_list_foreach(ns_timer_struct, curr_timer, &ns_timer_list) { 00350 if (curr_timer->timer_state == NS_TIMER_ACTIVE) { 00351 active_timer_found = true; 00352 break; 00353 } 00354 } 00355 /*If no active timers found, start one*/ 00356 if (!active_timer_found) { 00357 pl_timer_remaining_slots = platform_timer_get_remaining_slots(); 00358 /*Find hold-labelled timer with the least remaining slots*/ 00359 ns_list_foreach(ns_timer_struct, cur_timer, &ns_timer_list) { 00360 if (cur_timer->timer_state == NS_TIMER_HOLD) { 00361 cur_timer->remaining_slots += pl_timer_remaining_slots; 00362 00363 if (!first_timer || cur_timer->remaining_slots < first_timer->remaining_slots) { 00364 first_timer = cur_timer; 00365 } 00366 } 00367 } 00368 /*If hold-labelled timer found, set it active and start the HAL driver*/ 00369 if (first_timer) { 00370 first_timer->timer_state = NS_TIMER_ACTIVE; 00371 /*Start HAL timer*/ 00372 ns_timer_start_pl_timer(first_timer->remaining_slots); 00373 /*If some of the other hold-labelled timers have the same remaining slots as the timer_tmp, mark them active*/ 00374 ns_list_foreach(ns_timer_struct, cur_timer, &ns_timer_list) { 00375 if (cur_timer->timer_state == NS_TIMER_HOLD) { 00376 if (cur_timer->remaining_slots == first_timer->remaining_slots) { 00377 cur_timer->timer_state = NS_TIMER_ACTIVE; 00378 } else { 00379 cur_timer->remaining_slots -= first_timer->remaining_slots; 00380 } 00381 } 00382 } 00383 } 00384 } 00385 00386 exit: 00387 platform_exit_critical(); 00388 00389 return retval; 00390 } 00391 #endif // NS_EXCLUDE_HIGHRES_TIMER
Generated on Fri Jul 22 2022 04:53:58 by
1.7.2
