Simple interface for Mbed Cloud Client
Embed:
(wiki syntax)
Show/hide line numbers
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 Tue Jul 12 2022 19:01:37 by 1.7.2