Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

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 "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