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
system_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 #include "ns_types.h" 00017 #include "ns_list.h" 00018 #include "timer_sys.h" 00019 #include "platform/arm_hal_interrupt.h" 00020 #include "platform/arm_hal_timer.h" 00021 #include "nsdynmemLIB.h" 00022 #include "eventOS_event.h" 00023 #include "eventOS_event_timer.h" 00024 #include "event.h" 00025 #include "eventOS_callback_timer.h" 00026 00027 #include "ns_timer.h" 00028 00029 #ifndef ST_MAX 00030 #define ST_MAX 6 00031 #endif 00032 00033 static sys_timer_struct_s startup_sys_timer_pool[ST_MAX]; 00034 00035 #define TIMER_SLOTS_PER_MS 20 00036 NS_STATIC_ASSERT(1000 % EVENTOS_EVENT_TIMER_HZ == 0, "Need whole number of ms per tick") 00037 #define TIMER_SYS_TICK_PERIOD (1000 / EVENTOS_EVENT_TIMER_HZ) // milliseconds 00038 00039 // timer_sys_ticks must be read in critical section to guarantee 00040 // atomicity on 16-bit platforms 00041 static volatile uint32_t timer_sys_ticks; 00042 00043 static NS_LIST_DEFINE(system_timer_free, sys_timer_struct_s, event.link); 00044 static NS_LIST_DEFINE(system_timer_list, sys_timer_struct_s, event.link); 00045 00046 00047 static sys_timer_struct_s *sys_timer_dynamically_allocate(void); 00048 static void timer_sys_interrupt(void); 00049 static void timer_sys_add(sys_timer_struct_s *timer); 00050 00051 #ifndef NS_EVENTLOOP_USE_TICK_TIMER 00052 static int8_t platform_tick_timer_start(uint32_t period_ms); 00053 /* Implement platform tick timer using eventOS timer */ 00054 // platform tick timer callback function 00055 static void (*tick_timer_callback)(void); 00056 static int8_t tick_timer_id = -1; // eventOS timer id for tick timer 00057 00058 // EventOS timer callback function 00059 static void tick_timer_eventOS_callback(int8_t timer_id, uint16_t slots) 00060 { 00061 // Not interested in timer id or slots 00062 (void)slots; 00063 // Call the tick timer callback 00064 if (tick_timer_callback != NULL && timer_id == tick_timer_id) { 00065 platform_tick_timer_start(TIMER_SYS_TICK_PERIOD); 00066 tick_timer_callback(); 00067 } 00068 } 00069 00070 static int8_t platform_tick_timer_register(void (*tick_timer_cb)(void)) 00071 { 00072 tick_timer_callback = tick_timer_cb; 00073 tick_timer_id = eventOS_callback_timer_register(tick_timer_eventOS_callback); 00074 return tick_timer_id; 00075 } 00076 00077 static int8_t platform_tick_timer_start(uint32_t period_ms) 00078 { 00079 return eventOS_callback_timer_start(tick_timer_id, TIMER_SLOTS_PER_MS * period_ms); 00080 } 00081 00082 static int8_t platform_tick_timer_stop(void) 00083 { 00084 return eventOS_callback_timer_stop(tick_timer_id); 00085 } 00086 #endif // !NS_EVENTLOOP_USE_TICK_TIMER 00087 00088 /* 00089 * Initializes timers and starts system timer 00090 */ 00091 void timer_sys_init(void) 00092 { 00093 for (uint8_t i = 0; i < ST_MAX; i++) { 00094 ns_list_add_to_start(&system_timer_free, &startup_sys_timer_pool[i]); 00095 } 00096 00097 platform_tick_timer_register(timer_sys_interrupt); 00098 platform_tick_timer_start(TIMER_SYS_TICK_PERIOD); 00099 } 00100 00101 00102 00103 /*-------------------SYSTEM TIMER FUNCTIONS--------------------------*/ 00104 void timer_sys_disable(void) 00105 { 00106 platform_tick_timer_stop(); 00107 } 00108 00109 /* 00110 * Starts ticking system timer interrupts every 10ms 00111 */ 00112 int8_t timer_sys_wakeup(void) 00113 { 00114 return platform_tick_timer_start(TIMER_SYS_TICK_PERIOD); 00115 } 00116 00117 00118 static void timer_sys_interrupt(void) 00119 { 00120 system_timer_tick_update(1); 00121 } 00122 00123 00124 00125 /* * * * * * * * * */ 00126 00127 static sys_timer_struct_s *sys_timer_dynamically_allocate(void) 00128 { 00129 return ns_dyn_mem_alloc(sizeof(sys_timer_struct_s)); 00130 } 00131 00132 static sys_timer_struct_s *timer_struct_get(void) 00133 { 00134 sys_timer_struct_s *timer; 00135 platform_enter_critical(); 00136 timer = ns_list_get_first(&system_timer_free); 00137 if (timer) { 00138 ns_list_remove(&system_timer_free, timer); 00139 } else { 00140 timer = sys_timer_dynamically_allocate(); 00141 } 00142 platform_exit_critical(); 00143 return timer; 00144 } 00145 00146 void timer_sys_event_free(arm_event_storage_t *event) 00147 { 00148 platform_enter_critical(); 00149 sys_timer_struct_s *timer = NS_CONTAINER_OF(event, sys_timer_struct_s, event); 00150 if (timer->period == 0) { 00151 // Non-periodic - return to free list 00152 ns_list_add_to_start(&system_timer_free, timer); 00153 } else { 00154 // Periodic - check due time of next launch 00155 timer->launch_time += timer->period; 00156 if (TICKS_BEFORE_OR_AT(timer->launch_time, timer_sys_ticks)) { 00157 // next event is overdue - queue event now 00158 eventOS_event_send_timer_allocated(&timer->event); 00159 } else { 00160 // add back to timer queue for the future 00161 timer_sys_add(timer); 00162 } 00163 } 00164 platform_exit_critical(); 00165 } 00166 00167 void timer_sys_event_cancel_critical(struct arm_event_storage *event) 00168 { 00169 sys_timer_struct_s *timer = NS_CONTAINER_OF(event, sys_timer_struct_s, event); 00170 timer->period = 0; 00171 // If its unqueued it is on my timer list, otherwise it is in event-loop. 00172 if (event->state == ARM_LIB_EVENT_UNQUEUED) { 00173 ns_list_remove(&system_timer_list, timer); 00174 } 00175 } 00176 00177 uint32_t eventOS_event_timer_ticks(void) 00178 { 00179 uint32_t ret_val; 00180 // Enter/exit critical is a bit clunky, but necessary on 16-bit platforms, 00181 // which won't be able to do an atomic 32-bit read. 00182 platform_enter_critical(); 00183 ret_val = timer_sys_ticks; 00184 platform_exit_critical(); 00185 return ret_val; 00186 } 00187 00188 /* Called internally with lock held */ 00189 static void timer_sys_add(sys_timer_struct_s *timer) 00190 { 00191 uint32_t at = timer->launch_time; 00192 00193 // Find first timer scheduled to run after us, and insert before it. 00194 // (This means timers scheduled for same time run in order of request) 00195 ns_list_foreach(sys_timer_struct_s, t, &system_timer_list) { 00196 if (TICKS_BEFORE(at, t->launch_time)) { 00197 ns_list_add_before(&system_timer_list, t, timer); 00198 return; 00199 } 00200 } 00201 00202 // Didn't insert before another timer, so must be last. 00203 ns_list_add_to_end(&system_timer_list, timer); 00204 } 00205 00206 /* Called internally with lock held */ 00207 static arm_event_storage_t *eventOS_event_timer_request_at_(const arm_event_t *event, uint32_t at, uint32_t period) 00208 { 00209 // Because we use user-allocated events, they must get delivered to avoid 00210 // a leak. Previously this call queued timers for invalid tasks, then they 00211 // would go undelivered. Now it returns an error. 00212 if (!event_tasklet_handler_id_valid(event->receiver)) { 00213 return NULL; 00214 } 00215 00216 sys_timer_struct_s *timer = timer_struct_get(); 00217 if (!timer) { 00218 return NULL; 00219 } 00220 00221 timer->event.data = *event; 00222 timer->event.allocator = ARM_LIB_EVENT_TIMER; 00223 timer->event.state = ARM_LIB_EVENT_UNQUEUED; 00224 timer->launch_time = at; 00225 timer->period = period; 00226 00227 if (TICKS_BEFORE_OR_AT(at, timer_sys_ticks)) { 00228 eventOS_event_send_timer_allocated(&timer->event); 00229 } else { 00230 timer_sys_add(timer); 00231 } 00232 00233 return &timer->event; 00234 } 00235 00236 arm_event_storage_t *eventOS_event_timer_request_at(const arm_event_t *event, uint32_t at) 00237 { 00238 platform_enter_critical(); 00239 00240 arm_event_storage_t *ret = eventOS_event_timer_request_at_(event, at, 0); 00241 00242 platform_exit_critical(); 00243 00244 return ret; 00245 } 00246 00247 arm_event_storage_t *eventOS_event_timer_request_in(const arm_event_t *event, int32_t in) 00248 { 00249 platform_enter_critical(); 00250 00251 arm_event_storage_t *ret = eventOS_event_timer_request_at_(event, timer_sys_ticks + in, 0); 00252 00253 platform_exit_critical(); 00254 00255 return ret; 00256 00257 } 00258 00259 arm_event_storage_t *eventOS_event_timer_request_every(const arm_event_t *event, int32_t period) 00260 { 00261 if (period <= 0) { 00262 return NULL; 00263 } 00264 00265 platform_enter_critical(); 00266 00267 arm_event_storage_t *ret = eventOS_event_timer_request_at_(event, timer_sys_ticks + period, period); 00268 00269 platform_exit_critical(); 00270 00271 return ret; 00272 00273 } 00274 00275 int8_t eventOS_event_timer_request(uint8_t event_id, uint8_t event_type, int8_t tasklet_id, uint32_t time) 00276 { 00277 const arm_event_t event = { 00278 .event_id = event_id, 00279 .event_type = event_type, 00280 .receiver = tasklet_id, 00281 .sender = 0, 00282 .data_ptr = NULL, 00283 .event_data = 0, 00284 .priority = ARM_LIB_MED_PRIORITY_EVENT, 00285 }; 00286 00287 // Legacy time behaviour preserved 00288 00289 // Note that someone wanting 20ms gets 2 ticks, thanks to this test. 30ms would be 4 ticks. 00290 // And why shouldn't they be able to get a 1-tick callback? 00291 if (time > 2 * TIMER_SYS_TICK_PERIOD) { 00292 time /= TIMER_SYS_TICK_PERIOD; 00293 // XXX Why this? Someone wanting 50ms shouldn't get 6 ticks. Round to nearest, maybe? 00294 time++; 00295 } else { 00296 time = 2; 00297 } 00298 00299 platform_enter_critical(); 00300 arm_event_storage_t *ret = eventOS_event_timer_request_at_(&event, timer_sys_ticks + time, 0); 00301 platform_exit_critical(); 00302 return ret?0:-1; 00303 } 00304 00305 int8_t eventOS_event_timer_cancel(uint8_t event_id, int8_t tasklet_id) 00306 { 00307 platform_enter_critical(); 00308 00309 /* First check pending timers */ 00310 ns_list_foreach(sys_timer_struct_s, cur, &system_timer_list) { 00311 if (cur->event.data.receiver == tasklet_id && cur->event.data.event_id == event_id) { 00312 eventOS_cancel(&cur->event); 00313 goto done; 00314 } 00315 } 00316 00317 /* No pending timer, so check for already-pending event */ 00318 arm_event_storage_t *event = eventOS_event_find_by_id_critical(tasklet_id, event_id); 00319 if (event && event->allocator == ARM_LIB_EVENT_TIMER) { 00320 eventOS_cancel(event); 00321 goto done; 00322 } 00323 00324 /* No match found */ 00325 platform_exit_critical(); 00326 return -1; 00327 00328 done: 00329 platform_exit_critical(); 00330 return 0; 00331 } 00332 00333 uint32_t eventOS_event_timer_shortest_active_timer(void) 00334 { 00335 uint32_t ret_val = 0; 00336 00337 platform_enter_critical(); 00338 sys_timer_struct_s *first = ns_list_get_first(&system_timer_list); 00339 if (first == NULL) { 00340 // Weird API has 0 for "no events" 00341 ret_val = 0; 00342 } else if (TICKS_BEFORE_OR_AT(first->launch_time, timer_sys_ticks)) { 00343 // Which means an immediate/overdue event has to be 1 00344 ret_val = 1; 00345 } else { 00346 ret_val = first->launch_time - timer_sys_ticks; 00347 } 00348 00349 platform_exit_critical(); 00350 return eventOS_event_timer_ticks_to_ms(ret_val); 00351 } 00352 00353 void system_timer_tick_update(uint32_t ticks) 00354 { 00355 platform_enter_critical(); 00356 //Keep runtime time 00357 timer_sys_ticks += ticks; 00358 ns_list_foreach_safe(sys_timer_struct_s, cur, &system_timer_list) { 00359 if (TICKS_BEFORE_OR_AT(cur->launch_time, timer_sys_ticks)) { 00360 // Unthread from our list 00361 ns_list_remove(&system_timer_list, cur); 00362 // Make it an event (can't fail - no allocation) 00363 // event system will call our timer_sys_event_free on event delivery. 00364 eventOS_event_send_timer_allocated(&cur->event); 00365 } else { 00366 // List is ordered, so as soon as we see a later event, we're done. 00367 break; 00368 } 00369 } 00370 00371 platform_exit_critical(); 00372 } 00373
Generated on Fri Jul 22 2022 04:54:01 by
 1.7.2
 1.7.2 
    