Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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 }
Generated on Tue Jul 12 2022 13:54:19 by
1.7.2