joey shelton / LED_Demo

Dependencies:   MAX44000 PWM_Tone_Library nexpaq_mdk

Fork of LED_Demo by Maxim nexpaq

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     ns_timer_init();
00232     timer_sys_init();               //initialize timer
00233     /* Set Tasklett switcher to Idle */
00234     curr_tasklet = 0;
00235 
00236 }
00237 
00238 
00239 int8_t eventOS_scheduler_get_active_tasklet(void)
00240 {
00241     return  curr_tasklet;
00242 }
00243 
00244 void eventOS_scheduler_set_active_tasklet(int8_t tasklet)
00245 {
00246     curr_tasklet = tasklet;
00247 }
00248 
00249 int eventOS_scheduler_timer_stop(void)
00250 {
00251     timer_sys_disable();
00252     if (ns_timer_sleep() != 0) {
00253         return 1;
00254     }
00255     return 0;
00256 }
00257 
00258 int eventOS_scheduler_timer_synch_after_sleep(uint32_t sleep_ticks)
00259 {
00260     //Update MS to 10ms ticks
00261     sleep_ticks /= 10;
00262     sleep_ticks++;
00263     system_timer_tick_update(sleep_ticks);
00264     if (timer_sys_wakeup() == 0) {
00265         return 0;
00266     }
00267     return -1;
00268 }
00269 
00270 /**
00271  *
00272  * \brief Infinite Event Read Loop.
00273  *
00274  * Function Read and handle Cores Event and switch/enable tasklet which are event receiver. WhenEvent queue is empty it goes to sleep
00275  *
00276  */
00277 bool eventOS_scheduler_dispatch_event(void)
00278 {
00279     arm_core_tasklet_list_s *tasklet;
00280     arm_core_event_s *cur_event;
00281     arm_event_s event;
00282 
00283     curr_tasklet = 0;
00284 
00285     cur_event =  event_core_read();
00286     if (cur_event) {
00287         event = cur_event->data;
00288         event_core_free_push(cur_event);
00289         tasklet = event_tasklet_handler_get(event.receiver);
00290         if (tasklet) {
00291             curr_tasklet = event.receiver;
00292             /* Tasklet Scheduler Call */
00293             tasklet->func_ptr(&event);
00294             /* Set Current Tasklet to Idle state */
00295             curr_tasklet = 0;
00296         }
00297         return true;
00298     } else {
00299         return false;
00300     }
00301 }
00302 
00303 void eventOS_scheduler_run_until_idle(void)
00304 {
00305     while (eventOS_scheduler_dispatch_event());
00306 }
00307 
00308 /**
00309  *
00310  * \brief Infinite Event Read Loop.
00311  *
00312  * Function Read and handle Cores Event and switch/enable tasklet which are event receiver. WhenEvent queue is empty it goes to sleep
00313  *
00314  */
00315 NS_NORETURN void eventOS_scheduler_run(void)
00316 {
00317     while (1) {
00318         if (!eventOS_scheduler_dispatch_event()) {
00319             eventOS_scheduler_idle();
00320         }
00321     }
00322 }