Lee Kai Xuan / mbed-os

Fork of mbed-os by erkin yucel

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers system_timer.c Source File

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 "ns_timer.h"
00022 #include "nsdynmemLIB.h"
00023 #include "eventOS_event.h"
00024 #include "eventOS_callback_timer.h"
00025 
00026 #ifndef ST_MAX
00027 #define ST_MAX 6
00028 #endif
00029 
00030 typedef struct sys_timer_struct_s {
00031     uint32_t timer_sys_launch_time;
00032     int8_t timer_sys_launch_receiver;
00033     uint8_t timer_sys_launch_message;
00034     uint8_t timer_event_type;
00035 
00036     ns_list_link_t link;
00037 } sys_timer_struct_s;
00038 
00039 #define TIMER_SLOTS_PER_MS          20
00040 #define TIMER_SYS_TICK_PERIOD       10 // milliseconds
00041 
00042 static uint32_t run_time_tick_ticks = 0;
00043 static NS_LIST_DEFINE(system_timer_free, sys_timer_struct_s, link);
00044 static NS_LIST_DEFINE(system_timer_list, sys_timer_struct_s, link);
00045 
00046 
00047 static sys_timer_struct_s *sys_timer_dynamically_allocate(void);
00048 static void timer_sys_interrupt(void);
00049 
00050 #ifndef NS_EVENTLOOP_USE_TICK_TIMER
00051 static int8_t platform_tick_timer_start(uint32_t period_ms);
00052 /* Implement platform tick timer using eventOS timer */
00053 // platform tick timer callback function
00054 static void (*tick_timer_callback)(void);
00055 static int8_t tick_timer_id = -1;   // eventOS timer id for tick timer
00056 
00057 // EventOS timer callback function
00058 static void tick_timer_eventOS_callback(int8_t timer_id, uint16_t slots)
00059 {
00060     // Not interested in timer id or slots
00061     (void)slots;
00062     // Call the tick timer callback
00063     if (tick_timer_callback != NULL && timer_id == tick_timer_id) {
00064         platform_tick_timer_start(TIMER_SYS_TICK_PERIOD);
00065         tick_timer_callback();
00066     }
00067 }
00068 
00069 static int8_t platform_tick_timer_register(void (*tick_timer_cb)(void))
00070 {
00071     tick_timer_callback = tick_timer_cb;
00072     tick_timer_id = eventOS_callback_timer_register(tick_timer_eventOS_callback);
00073     return tick_timer_id;
00074 }
00075 
00076 static int8_t platform_tick_timer_start(uint32_t period_ms)
00077 {
00078     return eventOS_callback_timer_start(tick_timer_id, TIMER_SLOTS_PER_MS * period_ms);
00079 }
00080 
00081 static int8_t platform_tick_timer_stop(void)
00082 {
00083     return eventOS_callback_timer_stop(tick_timer_id);
00084 }
00085 #endif // !NS_EVENTLOOP_USE_TICK_TIMER
00086 
00087 /*
00088  * Initializes timers and starts system timer
00089  */
00090 void timer_sys_init(void)
00091 {
00092     run_time_tick_ticks = 0;
00093 
00094     // Clear old timers
00095     ns_list_foreach_safe(sys_timer_struct_s, temp, &system_timer_list) {
00096         ns_list_remove(&system_timer_list, temp);
00097         ns_dyn_mem_free(temp);
00098     }
00099     // Clear old free timer entrys
00100     ns_list_foreach_safe(sys_timer_struct_s, temp, &system_timer_free) {
00101         ns_list_remove(&system_timer_free, temp);
00102         ns_dyn_mem_free(temp);
00103     }
00104 
00105     for (uint8_t i = 0; i < ST_MAX; i++) {
00106         sys_timer_struct_s *temp = sys_timer_dynamically_allocate();
00107         if (temp) {
00108             ns_list_add_to_start(&system_timer_free, temp);
00109         }
00110     }
00111 
00112     platform_tick_timer_register(timer_sys_interrupt);
00113     platform_tick_timer_start(TIMER_SYS_TICK_PERIOD);
00114 }
00115 
00116 
00117 
00118 /*-------------------SYSTEM TIMER FUNCTIONS--------------------------*/
00119 void timer_sys_disable(void)
00120 {
00121     platform_tick_timer_stop();
00122 }
00123 
00124 /*
00125  * Starts ticking system timer interrupts every 10ms
00126  */
00127 int8_t timer_sys_wakeup(void)
00128 {
00129     return platform_tick_timer_start(TIMER_SYS_TICK_PERIOD);
00130 }
00131 
00132 
00133 static void timer_sys_interrupt(void)
00134 {
00135     system_timer_tick_update(1);
00136 }
00137 
00138 
00139 
00140 /* * * * * * * * * */
00141 
00142 static sys_timer_struct_s *sys_timer_dynamically_allocate(void)
00143 {
00144     return (sys_timer_struct_s*)ns_dyn_mem_alloc(sizeof(sys_timer_struct_s));
00145 }
00146 
00147 static sys_timer_struct_s *timer_struct_get(void)
00148 {
00149     sys_timer_struct_s *timer;
00150     platform_enter_critical();
00151     timer = ns_list_get_first(&system_timer_free);
00152     if (timer) {
00153         ns_list_remove(&system_timer_free, timer);
00154     } else {
00155         timer = sys_timer_dynamically_allocate();
00156     }
00157     platform_exit_critical();
00158     return timer;
00159 }
00160 
00161 uint32_t timer_get_runtime_ticks(void)  // only used in dev_stats_internal.c
00162 {
00163     uint32_t ret_val;
00164     platform_enter_critical();
00165     ret_val = run_time_tick_ticks;
00166     platform_exit_critical();
00167     return ret_val;
00168 }
00169 
00170 
00171 
00172 int8_t eventOS_event_timer_request(uint8_t snmessage, uint8_t event_type, int8_t tasklet_id, uint32_t time)
00173 {
00174     int8_t res = -1;
00175     sys_timer_struct_s *timer = NULL;
00176 
00177     platform_enter_critical();
00178     // Note that someone wanting 20ms gets 2 ticks, thanks to this test. 30ms would be 4 ticks.
00179     // And why shouldn't they be able to get a 1-tick callback?
00180     if (time > 2 * TIMER_SYS_TICK_PERIOD) {
00181         time /= TIMER_SYS_TICK_PERIOD;
00182         // XXX Why this? Someone wanting 50ms shouldn't get 6 ticks. Round to nearest, maybe?
00183         time++;
00184     } else {
00185         time = 2;
00186     }
00187     timer = timer_struct_get();
00188     if (timer) {
00189         timer->timer_sys_launch_message = snmessage;
00190         timer->timer_sys_launch_receiver = tasklet_id;
00191         timer->timer_event_type = event_type;
00192         timer->timer_sys_launch_time = time;
00193         ns_list_add_to_start(&system_timer_list, timer);
00194         res = 0;
00195     }
00196     platform_exit_critical();
00197     return res;
00198 }
00199 
00200 int8_t eventOS_event_timer_cancel(uint8_t snmessage, int8_t tasklet_id)
00201 {
00202     int8_t res = -1;
00203     platform_enter_critical();
00204     ns_list_foreach(sys_timer_struct_s, cur, &system_timer_list) {
00205         if (cur->timer_sys_launch_receiver == tasklet_id && cur->timer_sys_launch_message == snmessage) {
00206             ns_list_remove(&system_timer_list, cur);
00207             ns_list_add_to_start(&system_timer_free, cur);
00208             res = 0;
00209             break;
00210         }
00211     }
00212 
00213     platform_exit_critical();
00214     return res;
00215 }
00216 
00217 
00218 uint32_t eventOS_event_timer_shortest_active_timer(void)
00219 {
00220     uint32_t ret_val = 0;
00221 
00222     platform_enter_critical();
00223     ns_list_foreach(sys_timer_struct_s, cur, &system_timer_list) {
00224         if (ret_val == 0 || cur->timer_sys_launch_time < ret_val) {
00225             ret_val = cur->timer_sys_launch_time;
00226         }
00227     }
00228 
00229     platform_exit_critical();
00230     //Convert ticks to ms
00231     ret_val *= TIMER_SYS_TICK_PERIOD;
00232     return ret_val;
00233 }
00234 
00235 void system_timer_tick_update(uint32_t ticks)
00236 {
00237     platform_enter_critical();
00238     //Keep runtime time
00239     run_time_tick_ticks += ticks;
00240     ns_list_foreach_safe(sys_timer_struct_s, cur, &system_timer_list) {
00241         if (cur->timer_sys_launch_time <= ticks) {
00242             arm_event_s event = {
00243                 .receiver = cur->timer_sys_launch_receiver,
00244                 .sender = 0, /**< Event sender Tasklet ID */
00245                 .data_ptr = NULL,
00246                 .event_type = cur->timer_event_type,
00247                 .event_id = cur->timer_sys_launch_message,
00248                 .event_data = 0,
00249                 .priority = ARM_LIB_MED_PRIORITY_EVENT,
00250             };
00251             eventOS_event_send(&event);
00252             ns_list_remove(&system_timer_list, cur);
00253             ns_list_add_to_start(&system_timer_free, cur);
00254         } else {
00255             cur->timer_sys_launch_time -= ticks;
00256         }
00257     }
00258 
00259     platform_exit_critical();
00260 }
00261