Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
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 free->state = ARM_LIB_EVENT_UNQUEUED; 00183 00184 switch (free->allocator) { 00185 case ARM_LIB_EVENT_STARTUP_POOL: 00186 platform_enter_critical(); 00187 ns_list_add_to_start(&free_event_entry, free); 00188 platform_exit_critical(); 00189 break; 00190 case ARM_LIB_EVENT_DYNAMIC: 00191 // Free all dynamically allocated events. 00192 ns_dyn_mem_free(free); 00193 break; 00194 case ARM_LIB_EVENT_TIMER: 00195 // Hand it back to the timer system 00196 timer_sys_event_free(free); 00197 break; 00198 case ARM_LIB_EVENT_USER: 00199 default: 00200 break; 00201 } 00202 } 00203 00204 00205 static arm_event_storage_t *event_core_read(void) 00206 { 00207 platform_enter_critical(); 00208 arm_event_storage_t *event = ns_list_get_first(&event_queue_active); 00209 if (event) { 00210 event->state = ARM_LIB_EVENT_RUNNING; 00211 ns_list_remove(&event_queue_active, event); 00212 } 00213 platform_exit_critical(); 00214 return event; 00215 } 00216 00217 void event_core_write(arm_event_storage_t *event) 00218 { 00219 platform_enter_critical(); 00220 bool added = false; 00221 ns_list_foreach(arm_event_storage_t, event_tmp, &event_queue_active) { 00222 // note enum ordering means we're checking if event_tmp is LOWER priority than event 00223 if (event_tmp->data.priority > event->data.priority) { 00224 ns_list_add_before(&event_queue_active, event_tmp, event); 00225 added = true; 00226 break; 00227 } 00228 } 00229 if (!added) { 00230 ns_list_add_to_end(&event_queue_active, event); 00231 } 00232 event->state = ARM_LIB_EVENT_QUEUED; 00233 00234 /* Wake From Idle */ 00235 platform_exit_critical(); 00236 eventOS_scheduler_signal(); 00237 } 00238 00239 // Requires lock to be held 00240 arm_event_storage_t *eventOS_event_find_by_id_critical(uint8_t tasklet_id, uint8_t event_id) 00241 { 00242 ns_list_foreach(arm_event_storage_t, cur, &event_queue_active) { 00243 if (cur->data.receiver == tasklet_id && cur->data.event_id == event_id) { 00244 return cur; 00245 } 00246 } 00247 00248 return NULL; 00249 } 00250 00251 /** 00252 * 00253 * \brief Initialize Nanostack Core. 00254 * 00255 * Function Initialize Nanostack Core, Socket Interface,Buffer memory and Send Init event to all Tasklett which are Defined. 00256 * 00257 */ 00258 void eventOS_scheduler_init(void) 00259 { 00260 /* Reset Event List variables */ 00261 ns_list_init(&free_event_entry); 00262 ns_list_init(&event_queue_active); 00263 ns_list_init(&arm_core_tasklet_list); 00264 00265 //Add first 10 entries to "free" list 00266 for (unsigned i = 0; i < (sizeof(startup_event_pool) / sizeof(startup_event_pool[0])); i++) { 00267 startup_event_pool[i].allocator = ARM_LIB_EVENT_STARTUP_POOL; 00268 ns_list_add_to_start(&free_event_entry, &startup_event_pool[i]); 00269 } 00270 00271 /* Init Generic timer module */ 00272 timer_sys_init(); //initialize timer 00273 /* Set Tasklett switcher to Idle */ 00274 curr_tasklet = 0; 00275 00276 } 00277 00278 int8_t eventOS_scheduler_get_active_tasklet(void) 00279 { 00280 return curr_tasklet; 00281 } 00282 00283 void eventOS_scheduler_set_active_tasklet(int8_t tasklet) 00284 { 00285 curr_tasklet = tasklet; 00286 } 00287 00288 int eventOS_scheduler_timer_stop(void) 00289 { 00290 timer_sys_disable(); 00291 if (ns_timer_sleep() != 0) { 00292 return 1; 00293 } 00294 return 0; 00295 } 00296 00297 int eventOS_scheduler_timer_synch_after_sleep(uint32_t sleep_ticks) 00298 { 00299 //Update MS to 10ms ticks 00300 sleep_ticks /= 10; 00301 sleep_ticks++; 00302 system_timer_tick_update(sleep_ticks); 00303 if (timer_sys_wakeup() == 0) { 00304 return 0; 00305 } 00306 return -1; 00307 } 00308 00309 /** 00310 * 00311 * \brief Infinite Event Read Loop. 00312 * 00313 * Function Read and handle Cores Event and switch/enable tasklet which are event receiver. WhenEvent queue is empty it goes to sleep 00314 * 00315 */ 00316 bool eventOS_scheduler_dispatch_event(void) 00317 { 00318 curr_tasklet = 0; 00319 00320 arm_event_storage_t *cur_event = event_core_read(); 00321 if (!cur_event) { 00322 return false; 00323 } 00324 00325 curr_tasklet = cur_event->data.receiver; 00326 00327 arm_core_tasklet_t *tasklet = event_tasklet_handler_get(curr_tasklet); 00328 /* Do not bother with check for NULL - tasklets cannot be deleted, 00329 * and user-facing API eventOS_event_send() has already checked the tasklet 00330 * exists, so there is no possible issue there. 00331 * 00332 * For eventOS_event_send_user_allocated(), it would be a non-recoverable 00333 * error to not deliver the message - we have to have a receiver to pass 00334 * ownership to. If the lookup fails, let it crash. We want the send call 00335 * itself to return void to simplify logic. 00336 */ 00337 00338 /* Tasklet Scheduler Call */ 00339 tasklet->func_ptr(&cur_event->data); 00340 event_core_free_push(cur_event); 00341 00342 /* Set Current Tasklet to Idle state */ 00343 curr_tasklet = 0; 00344 00345 return true; 00346 } 00347 00348 void eventOS_scheduler_run_until_idle(void) 00349 { 00350 while (eventOS_scheduler_dispatch_event()); 00351 } 00352 00353 /** 00354 * 00355 * \brief Infinite Event Read Loop. 00356 * 00357 * Function Read and handle Cores Event and switch/enable tasklet which are event receiver. WhenEvent queue is empty it goes to sleep 00358 * 00359 */ 00360 NS_NORETURN void eventOS_scheduler_run(void) 00361 { 00362 while (1) { 00363 if (!eventOS_scheduler_dispatch_event()) { 00364 eventOS_scheduler_idle(); 00365 } 00366 } 00367 } 00368 00369 void eventOS_cancel(arm_event_storage_t *event) 00370 { 00371 if (!event) { 00372 return; 00373 } 00374 00375 platform_enter_critical(); 00376 00377 /* 00378 * Notify timer of cancellation. 00379 */ 00380 if (event->allocator == ARM_LIB_EVENT_TIMER) { 00381 timer_sys_event_cancel_critical(event); 00382 } 00383 00384 /* 00385 * Remove event from the list, 00386 * Only queued can be removed, unqued are either timers or stale pointers 00387 * RUNNING cannot be removed, we are currenly "in" that event. 00388 */ 00389 if (event->state == ARM_LIB_EVENT_QUEUED) { 00390 eventOS_event_cancel_critical(event); 00391 } 00392 00393 /* 00394 * Push back to "free" state 00395 */ 00396 if (event->state != ARM_LIB_EVENT_RUNNING) { 00397 event_core_free_push(event); 00398 } 00399 00400 platform_exit_critical(); 00401 }
Generated on Sun Jul 17 2022 08:25:22 by 1.7.2