mbed os with nrf51 internal bandgap enabled to read battery level
Dependents: BLE_file_test BLE_Blink ExternalEncoder
features/FEATURE_COMMON_PAL/sal-stack-nanostack-eventloop/source/event.c@0:f269e3021894, 2016-10-23 (annotated)
- Committer:
- elessair
- Date:
- Sun Oct 23 15:10:02 2016 +0000
- Revision:
- 0:f269e3021894
Initial commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
elessair | 0:f269e3021894 | 1 | /* |
elessair | 0:f269e3021894 | 2 | * Copyright (c) 2014-2015 ARM Limited. All rights reserved. |
elessair | 0:f269e3021894 | 3 | * SPDX-License-Identifier: Apache-2.0 |
elessair | 0:f269e3021894 | 4 | * Licensed under the Apache License, Version 2.0 (the License); you may |
elessair | 0:f269e3021894 | 5 | * not use this file except in compliance with the License. |
elessair | 0:f269e3021894 | 6 | * You may obtain a copy of the License at |
elessair | 0:f269e3021894 | 7 | * |
elessair | 0:f269e3021894 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
elessair | 0:f269e3021894 | 9 | * |
elessair | 0:f269e3021894 | 10 | * Unless required by applicable law or agreed to in writing, software |
elessair | 0:f269e3021894 | 11 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT |
elessair | 0:f269e3021894 | 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
elessair | 0:f269e3021894 | 13 | * See the License for the specific language governing permissions and |
elessair | 0:f269e3021894 | 14 | * limitations under the License. |
elessair | 0:f269e3021894 | 15 | */ |
elessair | 0:f269e3021894 | 16 | #include <string.h> |
elessair | 0:f269e3021894 | 17 | #include "ns_types.h" |
elessair | 0:f269e3021894 | 18 | #include "ns_list.h" |
elessair | 0:f269e3021894 | 19 | #include "eventOS_event.h" |
elessair | 0:f269e3021894 | 20 | #include "eventOS_scheduler.h" |
elessair | 0:f269e3021894 | 21 | #include "timer_sys.h" |
elessair | 0:f269e3021894 | 22 | #include "nsdynmemLIB.h" |
elessair | 0:f269e3021894 | 23 | #include "ns_timer.h" |
elessair | 0:f269e3021894 | 24 | |
elessair | 0:f269e3021894 | 25 | #include "platform/arm_hal_interrupt.h" |
elessair | 0:f269e3021894 | 26 | |
elessair | 0:f269e3021894 | 27 | |
elessair | 0:f269e3021894 | 28 | typedef struct arm_core_tasklet_list_s { |
elessair | 0:f269e3021894 | 29 | int8_t id; /**< Event handler Tasklet ID */ |
elessair | 0:f269e3021894 | 30 | void (*func_ptr)(arm_event_s *); |
elessair | 0:f269e3021894 | 31 | ns_list_link_t link; |
elessair | 0:f269e3021894 | 32 | } arm_core_tasklet_list_s; |
elessair | 0:f269e3021894 | 33 | |
elessair | 0:f269e3021894 | 34 | typedef struct arm_core_event_s { |
elessair | 0:f269e3021894 | 35 | arm_event_s data; |
elessair | 0:f269e3021894 | 36 | ns_list_link_t link; |
elessair | 0:f269e3021894 | 37 | } arm_core_event_s; |
elessair | 0:f269e3021894 | 38 | |
elessair | 0:f269e3021894 | 39 | static NS_LIST_DEFINE(arm_core_tasklet_list, arm_core_tasklet_list_s, link); |
elessair | 0:f269e3021894 | 40 | static NS_LIST_DEFINE(event_queue_active, arm_core_event_s, link); |
elessair | 0:f269e3021894 | 41 | static NS_LIST_DEFINE(free_event_entry, arm_core_event_s, link); |
elessair | 0:f269e3021894 | 42 | |
elessair | 0:f269e3021894 | 43 | /** Curr_tasklet tell to core and platform which task_let is active, Core Update this automatic when switch Tasklet. */ |
elessair | 0:f269e3021894 | 44 | int8_t curr_tasklet = 0; |
elessair | 0:f269e3021894 | 45 | |
elessair | 0:f269e3021894 | 46 | |
elessair | 0:f269e3021894 | 47 | static arm_core_tasklet_list_s *tasklet_dynamically_allocate(void); |
elessair | 0:f269e3021894 | 48 | static arm_core_event_s *event_dynamically_allocate(void); |
elessair | 0:f269e3021894 | 49 | static arm_core_event_s *event_core_get(void); |
elessair | 0:f269e3021894 | 50 | static void event_core_write(arm_core_event_s *event); |
elessair | 0:f269e3021894 | 51 | |
elessair | 0:f269e3021894 | 52 | static arm_core_tasklet_list_s *event_tasklet_handler_get(uint8_t tasklet_id) |
elessair | 0:f269e3021894 | 53 | { |
elessair | 0:f269e3021894 | 54 | ns_list_foreach(arm_core_tasklet_list_s, cur, &arm_core_tasklet_list) { |
elessair | 0:f269e3021894 | 55 | if (cur->id == tasklet_id) { |
elessair | 0:f269e3021894 | 56 | return cur; |
elessair | 0:f269e3021894 | 57 | } |
elessair | 0:f269e3021894 | 58 | } |
elessair | 0:f269e3021894 | 59 | return NULL; |
elessair | 0:f269e3021894 | 60 | } |
elessair | 0:f269e3021894 | 61 | |
elessair | 0:f269e3021894 | 62 | // XXX this can return 0, but 0 seems to mean "none" elsewhere? Or at least |
elessair | 0:f269e3021894 | 63 | // curr_tasklet is reset to 0 in various places. |
elessair | 0:f269e3021894 | 64 | static int8_t tasklet_get_free_id(void) |
elessair | 0:f269e3021894 | 65 | { |
elessair | 0:f269e3021894 | 66 | /*(Note use of uint8_t to avoid overflow if we reach 0x7F)*/ |
elessair | 0:f269e3021894 | 67 | for (uint8_t i = 0; i <= INT8_MAX; i++) { |
elessair | 0:f269e3021894 | 68 | if (!event_tasklet_handler_get(i)) { |
elessair | 0:f269e3021894 | 69 | return i; |
elessair | 0:f269e3021894 | 70 | } |
elessair | 0:f269e3021894 | 71 | } |
elessair | 0:f269e3021894 | 72 | return -1; |
elessair | 0:f269e3021894 | 73 | } |
elessair | 0:f269e3021894 | 74 | |
elessair | 0:f269e3021894 | 75 | |
elessair | 0:f269e3021894 | 76 | int8_t eventOS_event_handler_create(void (*handler_func_ptr)(arm_event_s *), uint8_t init_event_type) |
elessair | 0:f269e3021894 | 77 | { |
elessair | 0:f269e3021894 | 78 | arm_core_event_s *event_tmp; |
elessair | 0:f269e3021894 | 79 | |
elessair | 0:f269e3021894 | 80 | // XXX Do we really want to prevent multiple tasklets with same function? |
elessair | 0:f269e3021894 | 81 | ns_list_foreach(arm_core_tasklet_list_s, cur, &arm_core_tasklet_list) { |
elessair | 0:f269e3021894 | 82 | if (cur->func_ptr == handler_func_ptr) { |
elessair | 0:f269e3021894 | 83 | return -1; |
elessair | 0:f269e3021894 | 84 | } |
elessair | 0:f269e3021894 | 85 | } |
elessair | 0:f269e3021894 | 86 | |
elessair | 0:f269e3021894 | 87 | //Allocate new |
elessair | 0:f269e3021894 | 88 | arm_core_tasklet_list_s *new = tasklet_dynamically_allocate(); |
elessair | 0:f269e3021894 | 89 | if (!new) { |
elessair | 0:f269e3021894 | 90 | return -2; |
elessair | 0:f269e3021894 | 91 | } |
elessair | 0:f269e3021894 | 92 | |
elessair | 0:f269e3021894 | 93 | event_tmp = event_core_get(); |
elessair | 0:f269e3021894 | 94 | if (!event_tmp) { |
elessair | 0:f269e3021894 | 95 | ns_dyn_mem_free(new); |
elessair | 0:f269e3021894 | 96 | return -2; |
elessair | 0:f269e3021894 | 97 | } |
elessair | 0:f269e3021894 | 98 | |
elessair | 0:f269e3021894 | 99 | //Fill in tasklet; add to list |
elessair | 0:f269e3021894 | 100 | new->id = tasklet_get_free_id(); |
elessair | 0:f269e3021894 | 101 | new->func_ptr = handler_func_ptr; |
elessair | 0:f269e3021894 | 102 | ns_list_add_to_end(&arm_core_tasklet_list, new); |
elessair | 0:f269e3021894 | 103 | |
elessair | 0:f269e3021894 | 104 | //Queue "init" event for the new task |
elessair | 0:f269e3021894 | 105 | event_tmp->data.receiver = new->id; |
elessair | 0:f269e3021894 | 106 | event_tmp->data.sender = 0; |
elessair | 0:f269e3021894 | 107 | event_tmp->data.event_type = init_event_type; |
elessair | 0:f269e3021894 | 108 | event_tmp->data.event_data = 0; |
elessair | 0:f269e3021894 | 109 | event_core_write(event_tmp); |
elessair | 0:f269e3021894 | 110 | |
elessair | 0:f269e3021894 | 111 | return new->id; |
elessair | 0:f269e3021894 | 112 | } |
elessair | 0:f269e3021894 | 113 | |
elessair | 0:f269e3021894 | 114 | /** |
elessair | 0:f269e3021894 | 115 | * \brief Send event to event scheduler. |
elessair | 0:f269e3021894 | 116 | * |
elessair | 0:f269e3021894 | 117 | * \param event pointer to pushed event. |
elessair | 0:f269e3021894 | 118 | * |
elessair | 0:f269e3021894 | 119 | * \return 0 Event push OK |
elessair | 0:f269e3021894 | 120 | * \return -1 Memory allocation Fail |
elessair | 0:f269e3021894 | 121 | * |
elessair | 0:f269e3021894 | 122 | */ |
elessair | 0:f269e3021894 | 123 | int8_t eventOS_event_send(arm_event_s *event) |
elessair | 0:f269e3021894 | 124 | { |
elessair | 0:f269e3021894 | 125 | int8_t retval = -1; |
elessair | 0:f269e3021894 | 126 | if (event_tasklet_handler_get(event->receiver)) { |
elessair | 0:f269e3021894 | 127 | arm_core_event_s *event_tmp = event_core_get(); |
elessair | 0:f269e3021894 | 128 | if (event_tmp) { |
elessair | 0:f269e3021894 | 129 | event_tmp->data = *event; |
elessair | 0:f269e3021894 | 130 | event_core_write(event_tmp); |
elessair | 0:f269e3021894 | 131 | retval = 0; |
elessair | 0:f269e3021894 | 132 | } |
elessair | 0:f269e3021894 | 133 | } |
elessair | 0:f269e3021894 | 134 | return retval; |
elessair | 0:f269e3021894 | 135 | } |
elessair | 0:f269e3021894 | 136 | |
elessair | 0:f269e3021894 | 137 | |
elessair | 0:f269e3021894 | 138 | static arm_core_event_s *event_dynamically_allocate(void) |
elessair | 0:f269e3021894 | 139 | { |
elessair | 0:f269e3021894 | 140 | return ns_dyn_mem_alloc(sizeof(arm_core_event_s)); |
elessair | 0:f269e3021894 | 141 | } |
elessair | 0:f269e3021894 | 142 | |
elessair | 0:f269e3021894 | 143 | static arm_core_tasklet_list_s *tasklet_dynamically_allocate(void) |
elessair | 0:f269e3021894 | 144 | { |
elessair | 0:f269e3021894 | 145 | return ns_dyn_mem_alloc(sizeof(arm_core_tasklet_list_s)); |
elessair | 0:f269e3021894 | 146 | } |
elessair | 0:f269e3021894 | 147 | |
elessair | 0:f269e3021894 | 148 | |
elessair | 0:f269e3021894 | 149 | arm_core_event_s *event_core_get(void) |
elessair | 0:f269e3021894 | 150 | { |
elessair | 0:f269e3021894 | 151 | arm_core_event_s *event; |
elessair | 0:f269e3021894 | 152 | platform_enter_critical(); |
elessair | 0:f269e3021894 | 153 | event = ns_list_get_first(&free_event_entry); |
elessair | 0:f269e3021894 | 154 | if (event) { |
elessair | 0:f269e3021894 | 155 | ns_list_remove(&free_event_entry, event); |
elessair | 0:f269e3021894 | 156 | } else { |
elessair | 0:f269e3021894 | 157 | event = event_dynamically_allocate(); |
elessair | 0:f269e3021894 | 158 | } |
elessair | 0:f269e3021894 | 159 | if (event) { |
elessair | 0:f269e3021894 | 160 | event->data.data_ptr = NULL; |
elessair | 0:f269e3021894 | 161 | event->data.priority = ARM_LIB_LOW_PRIORITY_EVENT; |
elessair | 0:f269e3021894 | 162 | } |
elessair | 0:f269e3021894 | 163 | platform_exit_critical(); |
elessair | 0:f269e3021894 | 164 | return event; |
elessair | 0:f269e3021894 | 165 | } |
elessair | 0:f269e3021894 | 166 | |
elessair | 0:f269e3021894 | 167 | static void event_core_free_push(arm_core_event_s *free) |
elessair | 0:f269e3021894 | 168 | { |
elessair | 0:f269e3021894 | 169 | platform_enter_critical(); |
elessair | 0:f269e3021894 | 170 | ns_list_add_to_start(&free_event_entry, free); |
elessair | 0:f269e3021894 | 171 | platform_exit_critical(); |
elessair | 0:f269e3021894 | 172 | } |
elessair | 0:f269e3021894 | 173 | |
elessair | 0:f269e3021894 | 174 | |
elessair | 0:f269e3021894 | 175 | static arm_core_event_s *event_core_read(void) |
elessair | 0:f269e3021894 | 176 | { |
elessair | 0:f269e3021894 | 177 | arm_core_event_s *event; |
elessair | 0:f269e3021894 | 178 | platform_enter_critical(); |
elessair | 0:f269e3021894 | 179 | event = ns_list_get_first(&event_queue_active); |
elessair | 0:f269e3021894 | 180 | if (event) { |
elessair | 0:f269e3021894 | 181 | ns_list_remove(&event_queue_active, event); |
elessair | 0:f269e3021894 | 182 | } |
elessair | 0:f269e3021894 | 183 | platform_exit_critical(); |
elessair | 0:f269e3021894 | 184 | return event; |
elessair | 0:f269e3021894 | 185 | } |
elessair | 0:f269e3021894 | 186 | |
elessair | 0:f269e3021894 | 187 | void event_core_write(arm_core_event_s *event) |
elessair | 0:f269e3021894 | 188 | { |
elessair | 0:f269e3021894 | 189 | platform_enter_critical(); |
elessair | 0:f269e3021894 | 190 | bool added = false; |
elessair | 0:f269e3021894 | 191 | ns_list_foreach(arm_core_event_s, event_tmp, &event_queue_active) { |
elessair | 0:f269e3021894 | 192 | // note enum ordering means we're checking if event_tmp is LOWER priority than event |
elessair | 0:f269e3021894 | 193 | if (event_tmp->data.priority > event->data.priority) { |
elessair | 0:f269e3021894 | 194 | ns_list_add_before(&event_queue_active, event_tmp, event); |
elessair | 0:f269e3021894 | 195 | added = true; |
elessair | 0:f269e3021894 | 196 | break; |
elessair | 0:f269e3021894 | 197 | } |
elessair | 0:f269e3021894 | 198 | } |
elessair | 0:f269e3021894 | 199 | if (!added) { |
elessair | 0:f269e3021894 | 200 | ns_list_add_to_end(&event_queue_active, event); |
elessair | 0:f269e3021894 | 201 | } |
elessair | 0:f269e3021894 | 202 | |
elessair | 0:f269e3021894 | 203 | /* Wake From Idle */ |
elessair | 0:f269e3021894 | 204 | platform_exit_critical(); |
elessair | 0:f269e3021894 | 205 | eventOS_scheduler_signal(); |
elessair | 0:f269e3021894 | 206 | } |
elessair | 0:f269e3021894 | 207 | |
elessair | 0:f269e3021894 | 208 | /** |
elessair | 0:f269e3021894 | 209 | * |
elessair | 0:f269e3021894 | 210 | * \brief Initialize Nanostack Core. |
elessair | 0:f269e3021894 | 211 | * |
elessair | 0:f269e3021894 | 212 | * Function Initialize Nanostack Core, Socket Interface,Buffer memory and Send Init event to all Tasklett which are Defined. |
elessair | 0:f269e3021894 | 213 | * |
elessair | 0:f269e3021894 | 214 | */ |
elessair | 0:f269e3021894 | 215 | void eventOS_scheduler_init(void) |
elessair | 0:f269e3021894 | 216 | { |
elessair | 0:f269e3021894 | 217 | /* Reset Event List variables */ |
elessair | 0:f269e3021894 | 218 | ns_list_init(&free_event_entry); |
elessair | 0:f269e3021894 | 219 | ns_list_init(&event_queue_active); |
elessair | 0:f269e3021894 | 220 | ns_list_init(&arm_core_tasklet_list); |
elessair | 0:f269e3021894 | 221 | |
elessair | 0:f269e3021894 | 222 | //Allocate 10 entry |
elessair | 0:f269e3021894 | 223 | for (uint8_t i = 0; i < 10; i++) { |
elessair | 0:f269e3021894 | 224 | arm_core_event_s *event = event_dynamically_allocate(); |
elessair | 0:f269e3021894 | 225 | if (event) { |
elessair | 0:f269e3021894 | 226 | ns_list_add_to_start(&free_event_entry, event); |
elessair | 0:f269e3021894 | 227 | } |
elessair | 0:f269e3021894 | 228 | } |
elessair | 0:f269e3021894 | 229 | |
elessair | 0:f269e3021894 | 230 | /* Init Generic timer module */ |
elessair | 0:f269e3021894 | 231 | timer_sys_init(); //initialize timer |
elessair | 0:f269e3021894 | 232 | /* Set Tasklett switcher to Idle */ |
elessair | 0:f269e3021894 | 233 | curr_tasklet = 0; |
elessair | 0:f269e3021894 | 234 | |
elessair | 0:f269e3021894 | 235 | } |
elessair | 0:f269e3021894 | 236 | |
elessair | 0:f269e3021894 | 237 | |
elessair | 0:f269e3021894 | 238 | int8_t eventOS_scheduler_get_active_tasklet(void) |
elessair | 0:f269e3021894 | 239 | { |
elessair | 0:f269e3021894 | 240 | return curr_tasklet; |
elessair | 0:f269e3021894 | 241 | } |
elessair | 0:f269e3021894 | 242 | |
elessair | 0:f269e3021894 | 243 | void eventOS_scheduler_set_active_tasklet(int8_t tasklet) |
elessair | 0:f269e3021894 | 244 | { |
elessair | 0:f269e3021894 | 245 | curr_tasklet = tasklet; |
elessair | 0:f269e3021894 | 246 | } |
elessair | 0:f269e3021894 | 247 | |
elessair | 0:f269e3021894 | 248 | int eventOS_scheduler_timer_stop(void) |
elessair | 0:f269e3021894 | 249 | { |
elessair | 0:f269e3021894 | 250 | timer_sys_disable(); |
elessair | 0:f269e3021894 | 251 | if (ns_timer_sleep() != 0) { |
elessair | 0:f269e3021894 | 252 | return 1; |
elessair | 0:f269e3021894 | 253 | } |
elessair | 0:f269e3021894 | 254 | return 0; |
elessair | 0:f269e3021894 | 255 | } |
elessair | 0:f269e3021894 | 256 | |
elessair | 0:f269e3021894 | 257 | int eventOS_scheduler_timer_synch_after_sleep(uint32_t sleep_ticks) |
elessair | 0:f269e3021894 | 258 | { |
elessair | 0:f269e3021894 | 259 | //Update MS to 10ms ticks |
elessair | 0:f269e3021894 | 260 | sleep_ticks /= 10; |
elessair | 0:f269e3021894 | 261 | sleep_ticks++; |
elessair | 0:f269e3021894 | 262 | system_timer_tick_update(sleep_ticks); |
elessair | 0:f269e3021894 | 263 | if (timer_sys_wakeup() == 0) { |
elessair | 0:f269e3021894 | 264 | return 0; |
elessair | 0:f269e3021894 | 265 | } |
elessair | 0:f269e3021894 | 266 | return -1; |
elessair | 0:f269e3021894 | 267 | } |
elessair | 0:f269e3021894 | 268 | |
elessair | 0:f269e3021894 | 269 | /** |
elessair | 0:f269e3021894 | 270 | * |
elessair | 0:f269e3021894 | 271 | * \brief Infinite Event Read Loop. |
elessair | 0:f269e3021894 | 272 | * |
elessair | 0:f269e3021894 | 273 | * Function Read and handle Cores Event and switch/enable tasklet which are event receiver. WhenEvent queue is empty it goes to sleep |
elessair | 0:f269e3021894 | 274 | * |
elessair | 0:f269e3021894 | 275 | */ |
elessair | 0:f269e3021894 | 276 | bool eventOS_scheduler_dispatch_event(void) |
elessair | 0:f269e3021894 | 277 | { |
elessair | 0:f269e3021894 | 278 | arm_core_tasklet_list_s *tasklet; |
elessair | 0:f269e3021894 | 279 | arm_core_event_s *cur_event; |
elessair | 0:f269e3021894 | 280 | arm_event_s event; |
elessair | 0:f269e3021894 | 281 | |
elessair | 0:f269e3021894 | 282 | curr_tasklet = 0; |
elessair | 0:f269e3021894 | 283 | |
elessair | 0:f269e3021894 | 284 | cur_event = event_core_read(); |
elessair | 0:f269e3021894 | 285 | if (cur_event) { |
elessair | 0:f269e3021894 | 286 | event = cur_event->data; |
elessair | 0:f269e3021894 | 287 | event_core_free_push(cur_event); |
elessair | 0:f269e3021894 | 288 | tasklet = event_tasklet_handler_get(event.receiver); |
elessair | 0:f269e3021894 | 289 | if (tasklet) { |
elessair | 0:f269e3021894 | 290 | curr_tasklet = event.receiver; |
elessair | 0:f269e3021894 | 291 | /* Tasklet Scheduler Call */ |
elessair | 0:f269e3021894 | 292 | tasklet->func_ptr(&event); |
elessair | 0:f269e3021894 | 293 | /* Set Current Tasklet to Idle state */ |
elessair | 0:f269e3021894 | 294 | curr_tasklet = 0; |
elessair | 0:f269e3021894 | 295 | } |
elessair | 0:f269e3021894 | 296 | return true; |
elessair | 0:f269e3021894 | 297 | } else { |
elessair | 0:f269e3021894 | 298 | return false; |
elessair | 0:f269e3021894 | 299 | } |
elessair | 0:f269e3021894 | 300 | } |
elessair | 0:f269e3021894 | 301 | |
elessair | 0:f269e3021894 | 302 | void eventOS_scheduler_run_until_idle(void) |
elessair | 0:f269e3021894 | 303 | { |
elessair | 0:f269e3021894 | 304 | while (eventOS_scheduler_dispatch_event()); |
elessair | 0:f269e3021894 | 305 | } |
elessair | 0:f269e3021894 | 306 | |
elessair | 0:f269e3021894 | 307 | /** |
elessair | 0:f269e3021894 | 308 | * |
elessair | 0:f269e3021894 | 309 | * \brief Infinite Event Read Loop. |
elessair | 0:f269e3021894 | 310 | * |
elessair | 0:f269e3021894 | 311 | * Function Read and handle Cores Event and switch/enable tasklet which are event receiver. WhenEvent queue is empty it goes to sleep |
elessair | 0:f269e3021894 | 312 | * |
elessair | 0:f269e3021894 | 313 | */ |
elessair | 0:f269e3021894 | 314 | NS_NORETURN void eventOS_scheduler_run(void) |
elessair | 0:f269e3021894 | 315 | { |
elessair | 0:f269e3021894 | 316 | while (1) { |
elessair | 0:f269e3021894 | 317 | if (!eventOS_scheduler_dispatch_event()) { |
elessair | 0:f269e3021894 | 318 | eventOS_scheduler_idle(); |
elessair | 0:f269e3021894 | 319 | } |
elessair | 0:f269e3021894 | 320 | } |
elessair | 0:f269e3021894 | 321 | } |