ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

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 
00025 #include "platform/arm_hal_interrupt.h"
00026 
00027 
00028 typedef struct arm_core_tasklet_list_s {
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_list_s;
00033 
00034 typedef struct arm_core_event_s {
00035     arm_event_s data;
00036     ns_list_link_t link;
00037 } arm_core_event_s;
00038 
00039 static NS_LIST_DEFINE(arm_core_tasklet_list, arm_core_tasklet_list_s, link);
00040 static NS_LIST_DEFINE(event_queue_active, arm_core_event_s, link);
00041 static NS_LIST_DEFINE(free_event_entry, arm_core_event_s, link);
00042 
00043 /** Curr_tasklet tell to core and platform which task_let is active, Core Update this automatic when switch Tasklet. */
00044 int8_t curr_tasklet = 0;
00045 
00046 
00047 static arm_core_tasklet_list_s *tasklet_dynamically_allocate(void);
00048 static arm_core_event_s *event_dynamically_allocate(void);
00049 static arm_core_event_s *event_core_get(void);
00050 static void event_core_write(arm_core_event_s *event);
00051 
00052 static arm_core_tasklet_list_s *event_tasklet_handler_get(uint8_t tasklet_id)
00053 {
00054     ns_list_foreach(arm_core_tasklet_list_s, cur, &arm_core_tasklet_list) {
00055         if (cur->id == tasklet_id) {
00056             return cur;
00057         }
00058     }
00059     return NULL;
00060 }
00061 
00062 // XXX this can return 0, but 0 seems to mean "none" elsewhere? Or at least
00063 // curr_tasklet is reset to 0 in various places.
00064 static int8_t tasklet_get_free_id(void)
00065 {
00066     /*(Note use of uint8_t to avoid overflow if we reach 0x7F)*/
00067     for (uint8_t i = 0; i <= INT8_MAX; i++) {
00068         if (!event_tasklet_handler_get(i)) {
00069             return i;
00070         }
00071     }
00072     return -1;
00073 }
00074 
00075 
00076 int8_t eventOS_event_handler_create(void (*handler_func_ptr)(arm_event_s *), uint8_t init_event_type)
00077 {
00078     arm_core_event_s *event_tmp;
00079 
00080     // XXX Do we really want to prevent multiple tasklets with same function?
00081     ns_list_foreach(arm_core_tasklet_list_s, cur, &arm_core_tasklet_list) {
00082         if (cur->func_ptr == handler_func_ptr) {
00083             return -1;
00084         }
00085     }
00086 
00087     //Allocate new
00088     arm_core_tasklet_list_s *new = tasklet_dynamically_allocate();
00089     if (!new) {
00090         return -2;
00091     }
00092 
00093     event_tmp = event_core_get();
00094     if (!event_tmp) {
00095         ns_dyn_mem_free(new);
00096         return -2;
00097     }
00098 
00099     //Fill in tasklet; add to list
00100     new->id = tasklet_get_free_id();
00101     new->func_ptr = handler_func_ptr;
00102     ns_list_add_to_end(&arm_core_tasklet_list, new);
00103 
00104     //Queue "init" event for the new task
00105     event_tmp->data.receiver = new->id;
00106     event_tmp->data.sender = 0;
00107     event_tmp->data.event_type = init_event_type;
00108     event_tmp->data.event_data = 0;
00109     event_core_write(event_tmp);
00110 
00111     return new->id;
00112 }
00113 
00114 /**
00115 * \brief Send event to  event scheduler.
00116 *
00117 * \param event pointer to pushed event.
00118 *
00119 * \return 0 Event push OK
00120 * \return -1 Memory allocation Fail
00121 *
00122 */
00123 int8_t eventOS_event_send(arm_event_s *event)
00124 {
00125     int8_t retval = -1;
00126     if (event_tasklet_handler_get(event->receiver)) {
00127         arm_core_event_s *event_tmp = event_core_get();
00128         if (event_tmp) {
00129             event_tmp->data = *event;
00130             event_core_write(event_tmp);
00131             retval = 0;
00132         }
00133     }
00134     return retval;
00135 }
00136 
00137 
00138 static arm_core_event_s *event_dynamically_allocate(void)
00139 {
00140     return ns_dyn_mem_alloc(sizeof(arm_core_event_s));
00141 }
00142 
00143 static arm_core_tasklet_list_s *tasklet_dynamically_allocate(void)
00144 {
00145     return ns_dyn_mem_alloc(sizeof(arm_core_tasklet_list_s));
00146 }
00147 
00148 
00149 arm_core_event_s *event_core_get(void)
00150 {
00151     arm_core_event_s *event;
00152     platform_enter_critical();
00153     event = ns_list_get_first(&free_event_entry);
00154     if (event) {
00155         ns_list_remove(&free_event_entry, event);
00156     } else {
00157         event = event_dynamically_allocate();
00158     }
00159     if (event) {
00160         event->data.data_ptr = NULL;
00161         event->data.priority = ARM_LIB_LOW_PRIORITY_EVENT;
00162     }
00163     platform_exit_critical();
00164     return event;
00165 }
00166 
00167 static void event_core_free_push(arm_core_event_s *free)
00168 {
00169     platform_enter_critical();
00170     ns_list_add_to_start(&free_event_entry, free);
00171     platform_exit_critical();
00172 }
00173 
00174 
00175 static arm_core_event_s *event_core_read(void)
00176 {
00177     arm_core_event_s *event;
00178     platform_enter_critical();
00179     event = ns_list_get_first(&event_queue_active);
00180     if (event) {
00181         ns_list_remove(&event_queue_active, event);
00182     }
00183     platform_exit_critical();
00184     return event;
00185 }
00186 
00187 void event_core_write(arm_core_event_s *event)
00188 {
00189     platform_enter_critical();
00190     bool added = false;
00191     ns_list_foreach(arm_core_event_s, event_tmp, &event_queue_active) {
00192         // note enum ordering means we're checking if event_tmp is LOWER priority than event
00193         if (event_tmp->data.priority > event->data.priority) {
00194             ns_list_add_before(&event_queue_active, event_tmp, event);
00195             added = true;
00196             break;
00197         }
00198     }
00199     if (!added) {
00200         ns_list_add_to_end(&event_queue_active, event);
00201     }
00202 
00203     /* Wake From Idle */
00204     platform_exit_critical();
00205     eventOS_scheduler_signal();
00206 }
00207 
00208 /**
00209  *
00210  * \brief Initialize Nanostack Core.
00211  *
00212  * Function Initialize Nanostack Core, Socket Interface,Buffer memory and Send Init event to all Tasklett which are Defined.
00213  *
00214  */
00215 void eventOS_scheduler_init(void)
00216 {
00217     /* Reset Event List variables */
00218     ns_list_init(&free_event_entry);
00219     ns_list_init(&event_queue_active);
00220     ns_list_init(&arm_core_tasklet_list);
00221 
00222     //Allocate 10 entry
00223     for (uint8_t i = 0; i < 10; i++) {
00224         arm_core_event_s *event = event_dynamically_allocate();
00225         if (event) {
00226             ns_list_add_to_start(&free_event_entry, event);
00227         }
00228     }
00229 
00230     /* Init Generic timer module */
00231     timer_sys_init();               //initialize timer
00232     /* Set Tasklett switcher to Idle */
00233     curr_tasklet = 0;
00234 
00235 }
00236 
00237 
00238 int8_t eventOS_scheduler_get_active_tasklet(void)
00239 {
00240     return  curr_tasklet;
00241 }
00242 
00243 void eventOS_scheduler_set_active_tasklet(int8_t tasklet)
00244 {
00245     curr_tasklet = tasklet;
00246 }
00247 
00248 int eventOS_scheduler_timer_stop(void)
00249 {
00250     timer_sys_disable();
00251     if (ns_timer_sleep() != 0) {
00252         return 1;
00253     }
00254     return 0;
00255 }
00256 
00257 int eventOS_scheduler_timer_synch_after_sleep(uint32_t sleep_ticks)
00258 {
00259     //Update MS to 10ms ticks
00260     sleep_ticks /= 10;
00261     sleep_ticks++;
00262     system_timer_tick_update(sleep_ticks);
00263     if (timer_sys_wakeup() == 0) {
00264         return 0;
00265     }
00266     return -1;
00267 }
00268 
00269 /**
00270  *
00271  * \brief Infinite Event Read Loop.
00272  *
00273  * Function Read and handle Cores Event and switch/enable tasklet which are event receiver. WhenEvent queue is empty it goes to sleep
00274  *
00275  */
00276 bool eventOS_scheduler_dispatch_event(void)
00277 {
00278     arm_core_tasklet_list_s *tasklet;
00279     arm_core_event_s *cur_event;
00280     arm_event_s event;
00281 
00282     curr_tasklet = 0;
00283 
00284     cur_event =  event_core_read();
00285     if (cur_event) {
00286         event = cur_event->data;
00287         event_core_free_push(cur_event);
00288         tasklet = event_tasklet_handler_get(event.receiver);
00289         if (tasklet) {
00290             curr_tasklet = event.receiver;
00291             /* Tasklet Scheduler Call */
00292             tasklet->func_ptr(&event);
00293             /* Set Current Tasklet to Idle state */
00294             curr_tasklet = 0;
00295         }
00296         return true;
00297     } else {
00298         return false;
00299     }
00300 }
00301 
00302 void eventOS_scheduler_run_until_idle(void)
00303 {
00304     while (eventOS_scheduler_dispatch_event());
00305 }
00306 
00307 /**
00308  *
00309  * \brief Infinite Event Read Loop.
00310  *
00311  * Function Read and handle Cores Event and switch/enable tasklet which are event receiver. WhenEvent queue is empty it goes to sleep
00312  *
00313  */
00314 NS_NORETURN void eventOS_scheduler_run(void)
00315 {
00316     while (1) {
00317         if (!eventOS_scheduler_dispatch_event()) {
00318             eventOS_scheduler_idle();
00319         }
00320     }
00321 }