Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers event.c Source File

event.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 <string.h>
00017 #include "ns_types.h"
00018 #include "ns_list.h"
00019 #include "eventOS_event.h"
00020 #include "eventOS_scheduler.h"
00021 #include "timer_sys.h"
00022 #include "nsdynmemLIB.h"
00023 #include "ns_timer.h"
00024 #include "event.h"
00025 #include "platform/arm_hal_interrupt.h"
00026 
00027 
00028 typedef struct arm_core_tasklet {
00029     int8_t id; /**< Event handler Tasklet ID */
00030     void (*func_ptr)(arm_event_s *);
00031     ns_list_link_t link;
00032 } arm_core_tasklet_t;
00033 
00034 static NS_LIST_DEFINE(arm_core_tasklet_list, arm_core_tasklet_t, link);
00035 static NS_LIST_DEFINE(event_queue_active, arm_event_storage_t, link);
00036 static NS_LIST_DEFINE(free_event_entry, arm_event_storage_t, link);
00037 
00038 // Statically allocate initial pool of events.
00039 #define STARTUP_EVENT_POOL_SIZE 10
00040 static arm_event_storage_t startup_event_pool[STARTUP_EVENT_POOL_SIZE];
00041 
00042 /** Curr_tasklet tell to core and platform which task_let is active, Core Update this automatic when switch Tasklet. */
00043 int8_t curr_tasklet = 0;
00044 
00045 
00046 static arm_core_tasklet_t *tasklet_dynamically_allocate(void);
00047 static arm_event_storage_t *event_dynamically_allocate(void);
00048 static arm_event_storage_t *event_core_get(void);
00049 static void event_core_write(arm_event_storage_t *event);
00050 
00051 static arm_core_tasklet_t *event_tasklet_handler_get(uint8_t tasklet_id)
00052 {
00053     ns_list_foreach(arm_core_tasklet_t, cur, &arm_core_tasklet_list) {
00054         if (cur->id == tasklet_id) {
00055             return cur;
00056         }
00057     }
00058     return NULL;
00059 }
00060 
00061 bool event_tasklet_handler_id_valid(uint8_t tasklet_id)
00062 {
00063     return event_tasklet_handler_get(tasklet_id);
00064 }
00065 
00066 // XXX this can return 0, but 0 seems to mean "none" elsewhere? Or at least
00067 // curr_tasklet is reset to 0 in various places.
00068 static int8_t tasklet_get_free_id(void)
00069 {
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 (!event_tasklet_handler_get(i)) {
00073             return i;
00074         }
00075     }
00076     return -1;
00077 }
00078 
00079 
00080 int8_t eventOS_event_handler_create(void (*handler_func_ptr)(arm_event_s *), uint8_t init_event_type)
00081 {
00082     arm_event_storage_t *event_tmp;
00083 
00084     // XXX Do we really want to prevent multiple tasklets with same function?
00085     ns_list_foreach(arm_core_tasklet_t, cur, &arm_core_tasklet_list) {
00086         if (cur->func_ptr == handler_func_ptr) {
00087             return -1;
00088         }
00089     }
00090 
00091     //Allocate new
00092     arm_core_tasklet_t *new = tasklet_dynamically_allocate();
00093     if (!new) {
00094         return -2;
00095     }
00096 
00097     event_tmp = event_core_get();
00098     if (!event_tmp) {
00099         ns_dyn_mem_free(new);
00100         return -2;
00101     }
00102 
00103     //Fill in tasklet; add to list
00104     new->id = tasklet_get_free_id();
00105     new->func_ptr = handler_func_ptr;
00106     ns_list_add_to_end(&arm_core_tasklet_list, new);
00107 
00108     //Queue "init" event for the new task
00109     event_tmp->data.receiver = new->id;
00110     event_tmp->data.sender = 0;
00111     event_tmp->data.event_type = init_event_type;
00112     event_tmp->data.event_data = 0;
00113     event_core_write(event_tmp);
00114 
00115     return new->id;
00116 }
00117 
00118 int8_t eventOS_event_send(const arm_event_t *event)
00119 {
00120     if (event_tasklet_handler_get(event->receiver)) {
00121         arm_event_storage_t *event_tmp = event_core_get();
00122         if (event_tmp) {
00123             event_tmp->data = *event;
00124             event_core_write(event_tmp);
00125             return 0;
00126         }
00127     }
00128     return -1;
00129 }
00130 
00131 void eventOS_event_send_user_allocated(arm_event_storage_t *event)
00132 {
00133     event->allocator = ARM_LIB_EVENT_USER;
00134     event_core_write(event);
00135 }
00136 
00137 void eventOS_event_send_timer_allocated(arm_event_storage_t *event)
00138 {
00139     event->allocator = ARM_LIB_EVENT_TIMER;
00140     event_core_write(event);
00141 }
00142 
00143 void eventOS_event_cancel_critical(arm_event_storage_t *event)
00144 {
00145     ns_list_remove(&event_queue_active, event);
00146 }
00147 
00148 static arm_event_storage_t *event_dynamically_allocate(void)
00149 {
00150     arm_event_storage_t *event = ns_dyn_mem_temporary_alloc(sizeof(arm_event_storage_t));
00151     if (event) {
00152         event->allocator = ARM_LIB_EVENT_DYNAMIC;
00153     }
00154     return event;
00155 }
00156 
00157 static arm_core_tasklet_t *tasklet_dynamically_allocate(void)
00158 {
00159     return ns_dyn_mem_alloc(sizeof(arm_core_tasklet_t));
00160 }
00161 
00162 arm_event_storage_t *event_core_get(void)
00163 {
00164     arm_event_storage_t *event;
00165     platform_enter_critical();
00166     event = ns_list_get_first(&free_event_entry);
00167     if (event) {
00168         ns_list_remove(&free_event_entry, event);
00169     } else {
00170         event = event_dynamically_allocate();
00171     }
00172     if (event) {
00173         event->data.data_ptr = NULL;
00174         event->data.priority = ARM_LIB_LOW_PRIORITY_EVENT;
00175     }
00176     platform_exit_critical();
00177     return event;
00178 }
00179 
00180 void event_core_free_push(arm_event_storage_t *free)
00181 {
00182     switch (free->allocator) {
00183         case ARM_LIB_EVENT_STARTUP_POOL:
00184             free->state = ARM_LIB_EVENT_UNQUEUED;
00185             platform_enter_critical();
00186             ns_list_add_to_start(&free_event_entry, free);
00187             platform_exit_critical();
00188             break;
00189         case ARM_LIB_EVENT_DYNAMIC:
00190             // Free all dynamically allocated events.
00191             // No need to set state to UNQUEUED - it's being freed.
00192             ns_dyn_mem_free(free);
00193             break;
00194         case ARM_LIB_EVENT_TIMER:
00195             // Hand it back to the timer system
00196             free->state = ARM_LIB_EVENT_UNQUEUED;
00197             timer_sys_event_free(free);
00198             break;
00199         case ARM_LIB_EVENT_USER:
00200             // No need set state to UNQUEUED - we forget about it.
00201         default:
00202             break;
00203     }
00204 }
00205 
00206 
00207 static arm_event_storage_t *event_core_read(void)
00208 {
00209     platform_enter_critical();
00210     arm_event_storage_t *event = ns_list_get_first(&event_queue_active);
00211     if (event) {
00212         event->state = ARM_LIB_EVENT_RUNNING;
00213         ns_list_remove(&event_queue_active, event);
00214     }
00215     platform_exit_critical();
00216     return event;
00217 }
00218 
00219 void event_core_write(arm_event_storage_t *event)
00220 {
00221     platform_enter_critical();
00222     bool added = false;
00223     ns_list_foreach(arm_event_storage_t, event_tmp, &event_queue_active) {
00224         // note enum ordering means we're checking if event_tmp is LOWER priority than event
00225         if (event_tmp->data.priority > event->data.priority) {
00226             ns_list_add_before(&event_queue_active, event_tmp, event);
00227             added = true;
00228             break;
00229         }
00230     }
00231     if (!added) {
00232         ns_list_add_to_end(&event_queue_active, event);
00233     }
00234     event->state = ARM_LIB_EVENT_QUEUED;
00235 
00236     /* Wake From Idle */
00237     platform_exit_critical();
00238     eventOS_scheduler_signal();
00239 }
00240 
00241 // Requires lock to be held
00242 arm_event_storage_t *eventOS_event_find_by_id_critical(uint8_t tasklet_id, uint8_t event_id)
00243 {
00244     ns_list_foreach(arm_event_storage_t, cur, &event_queue_active) {
00245         if (cur->data.receiver == tasklet_id && cur->data.event_id == event_id) {
00246             return cur;
00247         }
00248     }
00249 
00250     return NULL;
00251 }
00252 
00253 /**
00254  *
00255  * \brief Initialize Nanostack Core.
00256  *
00257  * Function Initialize Nanostack Core, Socket Interface,Buffer memory and Send Init event to all Tasklett which are Defined.
00258  *
00259  */
00260 void eventOS_scheduler_init(void)
00261 {
00262     /* Reset Event List variables */
00263     ns_list_init(&free_event_entry);
00264     ns_list_init(&event_queue_active);
00265     ns_list_init(&arm_core_tasklet_list);
00266 
00267     //Add first 10 entries to "free" list
00268     for (unsigned i = 0; i < (sizeof(startup_event_pool) / sizeof(startup_event_pool[0])); i++) {
00269         startup_event_pool[i].allocator = ARM_LIB_EVENT_STARTUP_POOL;
00270         ns_list_add_to_start(&free_event_entry, &startup_event_pool[i]);
00271     }
00272 
00273     /* Init Generic timer module */
00274     timer_sys_init();               //initialize timer
00275     /* Set Tasklett switcher to Idle */
00276     curr_tasklet = 0;
00277 
00278 }
00279 
00280 int8_t eventOS_scheduler_get_active_tasklet(void)
00281 {
00282     return curr_tasklet;
00283 }
00284 
00285 void eventOS_scheduler_set_active_tasklet(int8_t tasklet)
00286 {
00287     curr_tasklet = tasklet;
00288 }
00289 
00290 int eventOS_scheduler_timer_stop(void)
00291 {
00292     timer_sys_disable();
00293     if (ns_timer_sleep() != 0) {
00294         return 1;
00295     }
00296     return 0;
00297 }
00298 
00299 int eventOS_scheduler_timer_synch_after_sleep(uint32_t sleep_ticks)
00300 {
00301     //Update MS to 10ms ticks
00302     sleep_ticks /= 10;
00303     sleep_ticks++;
00304     system_timer_tick_update(sleep_ticks);
00305     if (timer_sys_wakeup() == 0) {
00306         return 0;
00307     }
00308     return -1;
00309 }
00310 
00311 /**
00312  *
00313  * \brief Infinite Event Read Loop.
00314  *
00315  * Function Read and handle Cores Event and switch/enable tasklet which are event receiver. WhenEvent queue is empty it goes to sleep
00316  *
00317  */
00318 bool eventOS_scheduler_dispatch_event(void)
00319 {
00320     curr_tasklet = 0;
00321 
00322     arm_event_storage_t *cur_event = event_core_read();
00323     if (!cur_event) {
00324         return false;
00325     }
00326 
00327     curr_tasklet = cur_event->data.receiver;
00328 
00329     arm_core_tasklet_t *tasklet = event_tasklet_handler_get(curr_tasklet);
00330     /* Do not bother with check for NULL - tasklets cannot be deleted,
00331      * and user-facing API eventOS_event_send() has already checked the tasklet
00332      * exists, so there is no possible issue there.
00333      *
00334      * For eventOS_event_send_user_allocated(), it would be a non-recoverable
00335      * error to not deliver the message - we have to have a receiver to pass
00336      * ownership to. If the lookup fails, let it crash. We want the send call
00337      * itself to return void to simplify logic.
00338      */
00339 
00340     /* Tasklet Scheduler Call */
00341     tasklet->func_ptr(&cur_event->data);
00342     event_core_free_push(cur_event);
00343 
00344     /* Set Current Tasklet to Idle state */
00345     curr_tasklet = 0;
00346 
00347     return true;
00348 }
00349 
00350 void eventOS_scheduler_run_until_idle(void)
00351 {
00352     while (eventOS_scheduler_dispatch_event());
00353 }
00354 
00355 /**
00356  *
00357  * \brief Infinite Event Read Loop.
00358  *
00359  * Function Read and handle Cores Event and switch/enable tasklet which are event receiver. WhenEvent queue is empty it goes to sleep
00360  *
00361  */
00362 NS_NORETURN void eventOS_scheduler_run(void)
00363 {
00364     while (1) {
00365         if (!eventOS_scheduler_dispatch_event()) {
00366             eventOS_scheduler_idle();
00367         }
00368     }
00369 }
00370 
00371 void eventOS_cancel(arm_event_storage_t *event)
00372 {
00373     if (!event) {
00374         return;
00375     }
00376 
00377     platform_enter_critical();
00378 
00379     /*
00380      * Notify timer of cancellation.
00381      */
00382     if (event->allocator == ARM_LIB_EVENT_TIMER) {
00383         timer_sys_event_cancel_critical(event);
00384     }
00385 
00386     /*
00387      * Remove event from the list,
00388      * Only queued can be removed, unqued are either timers or stale pointers
00389      * RUNNING cannot be removed, we are currenly "in" that event.
00390      */
00391     if (event->state == ARM_LIB_EVENT_QUEUED) {
00392         eventOS_event_cancel_critical(event);
00393     }
00394 
00395     /*
00396      * Push back to "free" state
00397      */
00398     if (event->state != ARM_LIB_EVENT_RUNNING) {
00399         event_core_free_push(event);
00400     }
00401 
00402     platform_exit_critical();
00403 }