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.
Fork of mbed-dev by
hal/mbed_ticker_api.c@182:a56a73fd2a6f, 2018-03-20 (annotated)
- Committer:
- AnnaBridge
- Date:
- Tue Mar 20 16:56:18 2018 +0000
- Revision:
- 182:a56a73fd2a6f
- Parent:
- 181:57724642e740
- Child:
- 186:707f6e361f3e
mbed-dev library. Release version 160
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
<> | 149:156823d33999 | 1 | /* mbed Microcontroller Library |
<> | 149:156823d33999 | 2 | * Copyright (c) 2015 ARM Limited |
<> | 149:156823d33999 | 3 | * |
<> | 149:156823d33999 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
<> | 149:156823d33999 | 5 | * you may not use this file except in compliance with the License. |
<> | 149:156823d33999 | 6 | * You may obtain a copy of the License at |
<> | 149:156823d33999 | 7 | * |
<> | 149:156823d33999 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
<> | 149:156823d33999 | 9 | * |
<> | 149:156823d33999 | 10 | * Unless required by applicable law or agreed to in writing, software |
<> | 149:156823d33999 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
<> | 149:156823d33999 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
<> | 149:156823d33999 | 13 | * See the License for the specific language governing permissions and |
<> | 149:156823d33999 | 14 | * limitations under the License. |
<> | 149:156823d33999 | 15 | */ |
AnnaBridge | 167:e84263d55307 | 16 | #include <stdio.h> |
<> | 149:156823d33999 | 17 | #include <stddef.h> |
<> | 149:156823d33999 | 18 | #include "hal/ticker_api.h" |
<> | 160:d5399cc887bb | 19 | #include "platform/mbed_critical.h" |
Anna Bridge |
180:96ed750bd169 | 20 | #include "mbed_assert.h" |
<> | 149:156823d33999 | 21 | |
AnnaBridge | 167:e84263d55307 | 22 | static void schedule_interrupt(const ticker_data_t *const ticker); |
AnnaBridge | 167:e84263d55307 | 23 | static void update_present_time(const ticker_data_t *const ticker); |
AnnaBridge | 167:e84263d55307 | 24 | |
AnnaBridge | 167:e84263d55307 | 25 | /* |
AnnaBridge | 167:e84263d55307 | 26 | * Initialize a ticker instance. |
AnnaBridge | 167:e84263d55307 | 27 | */ |
AnnaBridge | 167:e84263d55307 | 28 | static void initialize(const ticker_data_t *ticker) |
AnnaBridge | 167:e84263d55307 | 29 | { |
AnnaBridge | 167:e84263d55307 | 30 | // return if the queue has already been initialized, in that case the |
AnnaBridge | 167:e84263d55307 | 31 | // interface used by the queue is already initialized. |
AnnaBridge | 167:e84263d55307 | 32 | if (ticker->queue->initialized) { |
AnnaBridge | 167:e84263d55307 | 33 | return; |
AnnaBridge | 167:e84263d55307 | 34 | } |
<> | 149:156823d33999 | 35 | |
AnnaBridge | 167:e84263d55307 | 36 | ticker->interface->init(); |
Anna Bridge |
180:96ed750bd169 | 37 | |
Anna Bridge |
180:96ed750bd169 | 38 | const ticker_info_t *info = ticker->interface->get_info(); |
Anna Bridge |
180:96ed750bd169 | 39 | uint32_t frequency = info->frequency; |
Anna Bridge |
180:96ed750bd169 | 40 | if (info->frequency == 0) { |
Anna Bridge |
180:96ed750bd169 | 41 | MBED_ASSERT(0); |
Anna Bridge |
180:96ed750bd169 | 42 | frequency = 1000000; |
Anna Bridge |
180:96ed750bd169 | 43 | } |
Anna Bridge |
180:96ed750bd169 | 44 | |
Anna Bridge |
180:96ed750bd169 | 45 | uint32_t bits = info->bits; |
Anna Bridge |
180:96ed750bd169 | 46 | if ((info->bits > 32) || (info->bits < 4)) { |
Anna Bridge |
180:96ed750bd169 | 47 | MBED_ASSERT(0); |
Anna Bridge |
180:96ed750bd169 | 48 | bits = 32; |
Anna Bridge |
180:96ed750bd169 | 49 | } |
Anna Bridge |
180:96ed750bd169 | 50 | uint32_t max_delta = 0x7 << (bits - 4); // 7/16th |
Anna Bridge |
180:96ed750bd169 | 51 | uint64_t max_delta_us = |
Anna Bridge |
180:96ed750bd169 | 52 | ((uint64_t)max_delta * 1000000 + frequency - 1) / frequency; |
Anna Bridge |
180:96ed750bd169 | 53 | |
AnnaBridge | 167:e84263d55307 | 54 | ticker->queue->event_handler = NULL; |
AnnaBridge | 167:e84263d55307 | 55 | ticker->queue->head = NULL; |
Anna Bridge |
180:96ed750bd169 | 56 | ticker->queue->tick_last_read = ticker->interface->read(); |
Anna Bridge |
180:96ed750bd169 | 57 | ticker->queue->tick_remainder = 0; |
Anna Bridge |
180:96ed750bd169 | 58 | ticker->queue->frequency = frequency; |
Anna Bridge |
180:96ed750bd169 | 59 | ticker->queue->bitmask = ((uint64_t)1 << bits) - 1; |
Anna Bridge |
180:96ed750bd169 | 60 | ticker->queue->max_delta = max_delta; |
Anna Bridge |
180:96ed750bd169 | 61 | ticker->queue->max_delta_us = max_delta_us; |
AnnaBridge | 167:e84263d55307 | 62 | ticker->queue->present_time = 0; |
AnnaBridge | 167:e84263d55307 | 63 | ticker->queue->initialized = true; |
AnnaBridge | 167:e84263d55307 | 64 | |
AnnaBridge | 167:e84263d55307 | 65 | update_present_time(ticker); |
AnnaBridge | 167:e84263d55307 | 66 | schedule_interrupt(ticker); |
AnnaBridge | 167:e84263d55307 | 67 | } |
AnnaBridge | 167:e84263d55307 | 68 | |
AnnaBridge | 167:e84263d55307 | 69 | /** |
AnnaBridge | 167:e84263d55307 | 70 | * Set the event handler function of a ticker instance. |
AnnaBridge | 167:e84263d55307 | 71 | */ |
AnnaBridge | 167:e84263d55307 | 72 | static void set_handler(const ticker_data_t *const ticker, ticker_event_handler handler) |
AnnaBridge | 167:e84263d55307 | 73 | { |
AnnaBridge | 167:e84263d55307 | 74 | ticker->queue->event_handler = handler; |
<> | 149:156823d33999 | 75 | } |
<> | 149:156823d33999 | 76 | |
AnnaBridge | 167:e84263d55307 | 77 | /* |
AnnaBridge | 167:e84263d55307 | 78 | * Convert a 32 bit timestamp into a 64 bit timestamp. |
AnnaBridge | 167:e84263d55307 | 79 | * |
AnnaBridge | 167:e84263d55307 | 80 | * A 64 bit timestamp is used as the point of time of reference while the |
AnnaBridge | 167:e84263d55307 | 81 | * timestamp to convert is relative to this point of time. |
AnnaBridge | 167:e84263d55307 | 82 | * |
AnnaBridge | 167:e84263d55307 | 83 | * The lower 32 bits of the timestamp returned will be equal to the timestamp to |
AnnaBridge | 167:e84263d55307 | 84 | * convert. |
AnnaBridge | 167:e84263d55307 | 85 | * |
AnnaBridge | 167:e84263d55307 | 86 | * If the timestamp to convert is less than the lower 32 bits of the time |
AnnaBridge | 167:e84263d55307 | 87 | * reference then the timestamp to convert is seen as an overflowed value and |
AnnaBridge | 167:e84263d55307 | 88 | * the upper 32 bit of the timestamp returned will be equal to the upper 32 bit |
AnnaBridge | 167:e84263d55307 | 89 | * of the reference point + 1. |
AnnaBridge | 167:e84263d55307 | 90 | * Otherwise, the upper 32 bit returned will be equal to the upper 32 bit of the |
AnnaBridge | 167:e84263d55307 | 91 | * reference point. |
AnnaBridge | 167:e84263d55307 | 92 | * |
AnnaBridge | 167:e84263d55307 | 93 | * @param ref: The 64 bit timestamp of reference. |
AnnaBridge | 167:e84263d55307 | 94 | * @param timestamp: The timestamp to convert. |
AnnaBridge | 167:e84263d55307 | 95 | */ |
AnnaBridge | 167:e84263d55307 | 96 | static us_timestamp_t convert_timestamp(us_timestamp_t ref, timestamp_t timestamp) |
AnnaBridge | 167:e84263d55307 | 97 | { |
AnnaBridge | 167:e84263d55307 | 98 | bool overflow = timestamp < ((timestamp_t) ref) ? true : false; |
AnnaBridge | 167:e84263d55307 | 99 | |
AnnaBridge | 167:e84263d55307 | 100 | us_timestamp_t result = (ref & ~((us_timestamp_t)UINT32_MAX)) | timestamp; |
AnnaBridge | 167:e84263d55307 | 101 | if (overflow) { |
AnnaBridge | 167:e84263d55307 | 102 | result += (1ULL<<32); |
AnnaBridge | 167:e84263d55307 | 103 | } |
AnnaBridge | 167:e84263d55307 | 104 | |
AnnaBridge | 167:e84263d55307 | 105 | return result; |
AnnaBridge | 167:e84263d55307 | 106 | } |
AnnaBridge | 167:e84263d55307 | 107 | |
AnnaBridge | 167:e84263d55307 | 108 | /** |
AnnaBridge | 167:e84263d55307 | 109 | * Update the present timestamp value of a ticker. |
AnnaBridge | 167:e84263d55307 | 110 | */ |
AnnaBridge | 167:e84263d55307 | 111 | static void update_present_time(const ticker_data_t *const ticker) |
Anna Bridge |
180:96ed750bd169 | 112 | { |
Anna Bridge |
180:96ed750bd169 | 113 | ticker_event_queue_t *queue = ticker->queue; |
Anna Bridge |
180:96ed750bd169 | 114 | uint32_t ticker_time = ticker->interface->read(); |
Anna Bridge |
180:96ed750bd169 | 115 | if (ticker_time == ticker->queue->tick_last_read) { |
Anna Bridge |
180:96ed750bd169 | 116 | // No work to do |
Anna Bridge |
180:96ed750bd169 | 117 | return; |
Anna Bridge |
180:96ed750bd169 | 118 | } |
Anna Bridge |
180:96ed750bd169 | 119 | |
Anna Bridge |
180:96ed750bd169 | 120 | uint64_t elapsed_ticks = (ticker_time - queue->tick_last_read) & queue->bitmask; |
Anna Bridge |
180:96ed750bd169 | 121 | queue->tick_last_read = ticker_time; |
Anna Bridge |
180:96ed750bd169 | 122 | |
Anna Bridge |
180:96ed750bd169 | 123 | uint64_t elapsed_us; |
Anna Bridge |
180:96ed750bd169 | 124 | if (1000000 == queue->frequency) { |
Anna Bridge |
180:96ed750bd169 | 125 | // Optimized for 1MHz |
Anna Bridge |
180:96ed750bd169 | 126 | |
Anna Bridge |
180:96ed750bd169 | 127 | elapsed_us = elapsed_ticks; |
Anna Bridge |
180:96ed750bd169 | 128 | } else if (32768 == queue->frequency) { |
Anna Bridge |
180:96ed750bd169 | 129 | // Optimized for 32KHz |
Anna Bridge |
180:96ed750bd169 | 130 | |
Anna Bridge |
180:96ed750bd169 | 131 | uint64_t us_x_ticks = elapsed_ticks * 1000000; |
Anna Bridge |
180:96ed750bd169 | 132 | elapsed_us = us_x_ticks >> 15; |
Anna Bridge |
180:96ed750bd169 | 133 | |
Anna Bridge |
180:96ed750bd169 | 134 | // Update remainder |
Anna Bridge |
180:96ed750bd169 | 135 | queue->tick_remainder += us_x_ticks - (elapsed_us << 15); |
Anna Bridge |
180:96ed750bd169 | 136 | if (queue->tick_remainder >= queue->frequency) { |
Anna Bridge |
180:96ed750bd169 | 137 | elapsed_us += 1; |
Anna Bridge |
180:96ed750bd169 | 138 | queue->tick_remainder -= queue->frequency; |
Anna Bridge |
180:96ed750bd169 | 139 | } |
Anna Bridge |
180:96ed750bd169 | 140 | } else { |
Anna Bridge |
180:96ed750bd169 | 141 | // General case |
Anna Bridge |
180:96ed750bd169 | 142 | |
Anna Bridge |
180:96ed750bd169 | 143 | uint64_t us_x_ticks = elapsed_ticks * 1000000; |
Anna Bridge |
180:96ed750bd169 | 144 | elapsed_us = us_x_ticks / queue->frequency; |
Anna Bridge |
180:96ed750bd169 | 145 | |
Anna Bridge |
180:96ed750bd169 | 146 | // Update remainder |
Anna Bridge |
180:96ed750bd169 | 147 | queue->tick_remainder += us_x_ticks - elapsed_us * queue->frequency; |
Anna Bridge |
180:96ed750bd169 | 148 | if (queue->tick_remainder >= queue->frequency) { |
Anna Bridge |
180:96ed750bd169 | 149 | elapsed_us += 1; |
Anna Bridge |
180:96ed750bd169 | 150 | queue->tick_remainder -= queue->frequency; |
Anna Bridge |
180:96ed750bd169 | 151 | } |
Anna Bridge |
180:96ed750bd169 | 152 | } |
Anna Bridge |
180:96ed750bd169 | 153 | |
Anna Bridge |
180:96ed750bd169 | 154 | // Update current time |
Anna Bridge |
180:96ed750bd169 | 155 | queue->present_time += elapsed_us; |
Anna Bridge |
180:96ed750bd169 | 156 | } |
Anna Bridge |
180:96ed750bd169 | 157 | |
Anna Bridge |
180:96ed750bd169 | 158 | /** |
Anna Bridge |
180:96ed750bd169 | 159 | * Given the absolute timestamp compute the hal tick timestamp. |
Anna Bridge |
180:96ed750bd169 | 160 | */ |
Anna Bridge |
180:96ed750bd169 | 161 | static timestamp_t compute_tick(const ticker_data_t *const ticker, us_timestamp_t timestamp) |
Anna Bridge |
180:96ed750bd169 | 162 | { |
Anna Bridge |
180:96ed750bd169 | 163 | ticker_event_queue_t *queue = ticker->queue; |
Anna Bridge |
180:96ed750bd169 | 164 | us_timestamp_t delta_us = timestamp - queue->present_time; |
Anna Bridge |
180:96ed750bd169 | 165 | |
Anna Bridge |
180:96ed750bd169 | 166 | timestamp_t delta = ticker->queue->max_delta; |
Anna Bridge |
180:96ed750bd169 | 167 | if (delta_us <= ticker->queue->max_delta_us) { |
Anna Bridge |
180:96ed750bd169 | 168 | // Checking max_delta_us ensures the operation will not overflow |
Anna Bridge |
180:96ed750bd169 | 169 | |
Anna Bridge |
180:96ed750bd169 | 170 | if (1000000 == queue->frequency) { |
Anna Bridge |
180:96ed750bd169 | 171 | // Optimized for 1MHz |
Anna Bridge |
180:96ed750bd169 | 172 | |
Anna Bridge |
180:96ed750bd169 | 173 | delta = delta_us; |
Anna Bridge |
180:96ed750bd169 | 174 | if (delta > ticker->queue->max_delta) { |
Anna Bridge |
180:96ed750bd169 | 175 | delta = ticker->queue->max_delta; |
Anna Bridge |
180:96ed750bd169 | 176 | } |
Anna Bridge |
180:96ed750bd169 | 177 | } else if (32768 == queue->frequency) { |
Anna Bridge |
180:96ed750bd169 | 178 | // Optimized for 32KHz |
Anna Bridge |
180:96ed750bd169 | 179 | |
Anna Bridge |
180:96ed750bd169 | 180 | delta = (delta_us << 15) / 1000000; |
Anna Bridge |
180:96ed750bd169 | 181 | if (delta > ticker->queue->max_delta) { |
Anna Bridge |
180:96ed750bd169 | 182 | delta = ticker->queue->max_delta; |
Anna Bridge |
180:96ed750bd169 | 183 | } |
Anna Bridge |
180:96ed750bd169 | 184 | } else { |
Anna Bridge |
180:96ed750bd169 | 185 | // General case |
Anna Bridge |
180:96ed750bd169 | 186 | |
Anna Bridge |
180:96ed750bd169 | 187 | delta = delta_us * queue->frequency / 1000000; |
Anna Bridge |
180:96ed750bd169 | 188 | if (delta > ticker->queue->max_delta) { |
Anna Bridge |
180:96ed750bd169 | 189 | delta = ticker->queue->max_delta; |
Anna Bridge |
180:96ed750bd169 | 190 | } |
Anna Bridge |
180:96ed750bd169 | 191 | } |
Anna Bridge |
180:96ed750bd169 | 192 | } |
Anna Bridge |
180:96ed750bd169 | 193 | return (queue->tick_last_read + delta) & queue->bitmask; |
Anna Bridge |
180:96ed750bd169 | 194 | } |
Anna Bridge |
180:96ed750bd169 | 195 | |
Anna Bridge |
180:96ed750bd169 | 196 | /** |
Anna Bridge |
180:96ed750bd169 | 197 | * Return 1 if the tick has incremented to or past match_tick, otherwise 0. |
Anna Bridge |
180:96ed750bd169 | 198 | */ |
Anna Bridge |
180:96ed750bd169 | 199 | int _ticker_match_interval_passed(timestamp_t prev_tick, timestamp_t cur_tick, timestamp_t match_tick) |
Anna Bridge |
180:96ed750bd169 | 200 | { |
Anna Bridge |
180:96ed750bd169 | 201 | if (match_tick > prev_tick) { |
Anna Bridge |
180:96ed750bd169 | 202 | return (cur_tick >= match_tick) || (cur_tick < prev_tick); |
Anna Bridge |
180:96ed750bd169 | 203 | } else { |
Anna Bridge |
180:96ed750bd169 | 204 | return (cur_tick < prev_tick) && (cur_tick >= match_tick); |
Anna Bridge |
180:96ed750bd169 | 205 | } |
AnnaBridge | 167:e84263d55307 | 206 | } |
AnnaBridge | 167:e84263d55307 | 207 | |
AnnaBridge | 167:e84263d55307 | 208 | /** |
AnnaBridge | 167:e84263d55307 | 209 | * Compute the time when the interrupt has to be triggered and schedule it. |
AnnaBridge | 167:e84263d55307 | 210 | * |
AnnaBridge | 167:e84263d55307 | 211 | * If there is no event in the queue or the next event to execute is in more |
Anna Bridge |
180:96ed750bd169 | 212 | * than ticker.queue.max_delta ticks from now then the ticker irq will be |
Anna Bridge |
180:96ed750bd169 | 213 | * scheduled in ticker.queue.max_delta ticks. Otherwise the irq will be |
Anna Bridge |
180:96ed750bd169 | 214 | * scheduled to happen when the running counter reach the timestamp of the |
Anna Bridge |
180:96ed750bd169 | 215 | * first event in the queue. |
AnnaBridge | 167:e84263d55307 | 216 | * |
AnnaBridge | 167:e84263d55307 | 217 | * @note If there is no event in the queue then the interrupt is scheduled to |
Anna Bridge |
180:96ed750bd169 | 218 | * in ticker.queue.max_delta. This is necessary to keep track |
AnnaBridge | 167:e84263d55307 | 219 | * of the timer overflow. |
AnnaBridge | 167:e84263d55307 | 220 | */ |
AnnaBridge | 167:e84263d55307 | 221 | static void schedule_interrupt(const ticker_data_t *const ticker) |
AnnaBridge | 167:e84263d55307 | 222 | { |
Anna Bridge |
180:96ed750bd169 | 223 | ticker_event_queue_t *queue = ticker->queue; |
AnnaBridge | 167:e84263d55307 | 224 | update_present_time(ticker); |
AnnaBridge | 167:e84263d55307 | 225 | |
AnnaBridge | 167:e84263d55307 | 226 | if (ticker->queue->head) { |
AnnaBridge | 167:e84263d55307 | 227 | us_timestamp_t present = ticker->queue->present_time; |
Anna Bridge |
180:96ed750bd169 | 228 | us_timestamp_t match_time = ticker->queue->head->timestamp; |
AnnaBridge | 167:e84263d55307 | 229 | |
AnnaBridge | 167:e84263d55307 | 230 | // if the event at the head of the queue is in the past then schedule |
AnnaBridge | 167:e84263d55307 | 231 | // it immediately. |
Anna Bridge |
180:96ed750bd169 | 232 | if (match_time <= present) { |
AnnaBridge | 174:b96e65c34a4d | 233 | ticker->interface->fire_interrupt(); |
AnnaBridge | 174:b96e65c34a4d | 234 | return; |
AnnaBridge | 167:e84263d55307 | 235 | } |
Anna Bridge |
180:96ed750bd169 | 236 | |
Anna Bridge |
180:96ed750bd169 | 237 | timestamp_t match_tick = compute_tick(ticker, match_time); |
AnnaBridge | 182:a56a73fd2a6f | 238 | // The time has been checked to be future, but it could still round |
AnnaBridge | 182:a56a73fd2a6f | 239 | // to the last tick as a result of us to ticks conversion |
AnnaBridge | 182:a56a73fd2a6f | 240 | if (match_tick == queue->tick_last_read) { |
AnnaBridge | 182:a56a73fd2a6f | 241 | // Match time has already expired so fire immediately |
AnnaBridge | 182:a56a73fd2a6f | 242 | ticker->interface->fire_interrupt(); |
AnnaBridge | 182:a56a73fd2a6f | 243 | return; |
AnnaBridge | 182:a56a73fd2a6f | 244 | } |
AnnaBridge | 182:a56a73fd2a6f | 245 | |
Anna Bridge |
180:96ed750bd169 | 246 | ticker->interface->set_interrupt(match_tick); |
Anna Bridge |
180:96ed750bd169 | 247 | timestamp_t cur_tick = ticker->interface->read(); |
AnnaBridge | 167:e84263d55307 | 248 | |
Anna Bridge |
180:96ed750bd169 | 249 | if (_ticker_match_interval_passed(queue->tick_last_read, cur_tick, match_tick)) { |
Anna Bridge |
180:96ed750bd169 | 250 | ticker->interface->fire_interrupt(); |
Anna Bridge |
180:96ed750bd169 | 251 | } |
Anna Bridge |
180:96ed750bd169 | 252 | } else { |
Anna Bridge |
180:96ed750bd169 | 253 | uint32_t match_tick = |
Anna Bridge |
180:96ed750bd169 | 254 | (queue->tick_last_read + queue->max_delta) & queue->bitmask; |
Anna Bridge |
180:96ed750bd169 | 255 | ticker->interface->set_interrupt(match_tick); |
AnnaBridge | 174:b96e65c34a4d | 256 | } |
AnnaBridge | 167:e84263d55307 | 257 | } |
AnnaBridge | 167:e84263d55307 | 258 | |
AnnaBridge | 167:e84263d55307 | 259 | void ticker_set_handler(const ticker_data_t *const ticker, ticker_event_handler handler) |
AnnaBridge | 167:e84263d55307 | 260 | { |
AnnaBridge | 167:e84263d55307 | 261 | initialize(ticker); |
AnnaBridge | 181:57724642e740 | 262 | |
AnnaBridge | 181:57724642e740 | 263 | core_util_critical_section_enter(); |
AnnaBridge | 167:e84263d55307 | 264 | set_handler(ticker, handler); |
AnnaBridge | 181:57724642e740 | 265 | core_util_critical_section_exit(); |
AnnaBridge | 167:e84263d55307 | 266 | } |
AnnaBridge | 167:e84263d55307 | 267 | |
AnnaBridge | 167:e84263d55307 | 268 | void ticker_irq_handler(const ticker_data_t *const ticker) |
AnnaBridge | 167:e84263d55307 | 269 | { |
AnnaBridge | 181:57724642e740 | 270 | core_util_critical_section_enter(); |
AnnaBridge | 181:57724642e740 | 271 | |
AnnaBridge | 167:e84263d55307 | 272 | ticker->interface->clear_interrupt(); |
<> | 149:156823d33999 | 273 | |
<> | 149:156823d33999 | 274 | /* Go through all the pending TimerEvents */ |
<> | 149:156823d33999 | 275 | while (1) { |
AnnaBridge | 167:e84263d55307 | 276 | if (ticker->queue->head == NULL) { |
AnnaBridge | 167:e84263d55307 | 277 | break; |
<> | 149:156823d33999 | 278 | } |
<> | 149:156823d33999 | 279 | |
AnnaBridge | 167:e84263d55307 | 280 | // update the current timestamp used by the queue |
AnnaBridge | 167:e84263d55307 | 281 | update_present_time(ticker); |
AnnaBridge | 167:e84263d55307 | 282 | |
AnnaBridge | 167:e84263d55307 | 283 | if (ticker->queue->head->timestamp <= ticker->queue->present_time) { |
<> | 149:156823d33999 | 284 | // This event was in the past: |
<> | 149:156823d33999 | 285 | // point to the following one and execute its handler |
AnnaBridge | 167:e84263d55307 | 286 | ticker_event_t *p = ticker->queue->head; |
AnnaBridge | 167:e84263d55307 | 287 | ticker->queue->head = ticker->queue->head->next; |
AnnaBridge | 167:e84263d55307 | 288 | if (ticker->queue->event_handler != NULL) { |
AnnaBridge | 167:e84263d55307 | 289 | (*ticker->queue->event_handler)(p->id); // NOTE: the handler can set new events |
<> | 149:156823d33999 | 290 | } |
<> | 149:156823d33999 | 291 | /* Note: We continue back to examining the head because calling the |
<> | 149:156823d33999 | 292 | * event handler may have altered the chain of pending events. */ |
<> | 149:156823d33999 | 293 | } else { |
AnnaBridge | 167:e84263d55307 | 294 | break; |
AnnaBridge | 167:e84263d55307 | 295 | } |
<> | 149:156823d33999 | 296 | } |
AnnaBridge | 167:e84263d55307 | 297 | |
AnnaBridge | 167:e84263d55307 | 298 | schedule_interrupt(ticker); |
AnnaBridge | 181:57724642e740 | 299 | |
AnnaBridge | 181:57724642e740 | 300 | core_util_critical_section_exit(); |
<> | 149:156823d33999 | 301 | } |
<> | 149:156823d33999 | 302 | |
AnnaBridge | 167:e84263d55307 | 303 | void ticker_insert_event(const ticker_data_t *const ticker, ticker_event_t *obj, timestamp_t timestamp, uint32_t id) |
AnnaBridge | 167:e84263d55307 | 304 | { |
<> | 149:156823d33999 | 305 | core_util_critical_section_enter(); |
<> | 149:156823d33999 | 306 | |
AnnaBridge | 167:e84263d55307 | 307 | // update the current timestamp |
AnnaBridge | 167:e84263d55307 | 308 | update_present_time(ticker); |
AnnaBridge | 167:e84263d55307 | 309 | us_timestamp_t absolute_timestamp = convert_timestamp( |
AnnaBridge | 167:e84263d55307 | 310 | ticker->queue->present_time, |
AnnaBridge | 167:e84263d55307 | 311 | timestamp |
AnnaBridge | 167:e84263d55307 | 312 | ); |
AnnaBridge | 167:e84263d55307 | 313 | |
AnnaBridge | 167:e84263d55307 | 314 | // defer to ticker_insert_event_us |
AnnaBridge | 167:e84263d55307 | 315 | ticker_insert_event_us( |
AnnaBridge | 167:e84263d55307 | 316 | ticker, |
AnnaBridge | 167:e84263d55307 | 317 | obj, absolute_timestamp, id |
AnnaBridge | 167:e84263d55307 | 318 | ); |
AnnaBridge | 181:57724642e740 | 319 | |
AnnaBridge | 181:57724642e740 | 320 | core_util_critical_section_exit(); |
AnnaBridge | 167:e84263d55307 | 321 | } |
AnnaBridge | 167:e84263d55307 | 322 | |
AnnaBridge | 167:e84263d55307 | 323 | void ticker_insert_event_us(const ticker_data_t *const ticker, ticker_event_t *obj, us_timestamp_t timestamp, uint32_t id) |
AnnaBridge | 167:e84263d55307 | 324 | { |
AnnaBridge | 167:e84263d55307 | 325 | core_util_critical_section_enter(); |
AnnaBridge | 167:e84263d55307 | 326 | |
AnnaBridge | 167:e84263d55307 | 327 | // update the current timestamp |
AnnaBridge | 167:e84263d55307 | 328 | update_present_time(ticker); |
AnnaBridge | 167:e84263d55307 | 329 | |
<> | 149:156823d33999 | 330 | // initialise our data |
<> | 149:156823d33999 | 331 | obj->timestamp = timestamp; |
<> | 149:156823d33999 | 332 | obj->id = id; |
<> | 149:156823d33999 | 333 | |
<> | 149:156823d33999 | 334 | /* Go through the list until we either reach the end, or find |
<> | 149:156823d33999 | 335 | an element this should come before (which is possibly the |
<> | 149:156823d33999 | 336 | head). */ |
AnnaBridge | 167:e84263d55307 | 337 | ticker_event_t *prev = NULL, *p = ticker->queue->head; |
<> | 149:156823d33999 | 338 | while (p != NULL) { |
<> | 149:156823d33999 | 339 | /* check if we come before p */ |
AnnaBridge | 167:e84263d55307 | 340 | if (timestamp < p->timestamp) { |
<> | 149:156823d33999 | 341 | break; |
<> | 149:156823d33999 | 342 | } |
<> | 149:156823d33999 | 343 | /* go to the next element */ |
<> | 149:156823d33999 | 344 | prev = p; |
<> | 149:156823d33999 | 345 | p = p->next; |
<> | 149:156823d33999 | 346 | } |
<> | 162:e13f6fdb2ac4 | 347 | |
<> | 162:e13f6fdb2ac4 | 348 | /* if we're at the end p will be NULL, which is correct */ |
<> | 162:e13f6fdb2ac4 | 349 | obj->next = p; |
<> | 162:e13f6fdb2ac4 | 350 | |
<> | 149:156823d33999 | 351 | /* if prev is NULL we're at the head */ |
<> | 149:156823d33999 | 352 | if (prev == NULL) { |
AnnaBridge | 167:e84263d55307 | 353 | ticker->queue->head = obj; |
<> | 149:156823d33999 | 354 | } else { |
<> | 149:156823d33999 | 355 | prev->next = obj; |
<> | 149:156823d33999 | 356 | } |
<> | 149:156823d33999 | 357 | |
AnnaBridge | 167:e84263d55307 | 358 | schedule_interrupt(ticker); |
AnnaBridge | 167:e84263d55307 | 359 | |
<> | 149:156823d33999 | 360 | core_util_critical_section_exit(); |
AnnaBridge | 181:57724642e740 | 361 | |
<> | 149:156823d33999 | 362 | } |
<> | 149:156823d33999 | 363 | |
AnnaBridge | 167:e84263d55307 | 364 | void ticker_remove_event(const ticker_data_t *const ticker, ticker_event_t *obj) |
AnnaBridge | 167:e84263d55307 | 365 | { |
<> | 149:156823d33999 | 366 | core_util_critical_section_enter(); |
<> | 149:156823d33999 | 367 | |
<> | 149:156823d33999 | 368 | // remove this object from the list |
AnnaBridge | 167:e84263d55307 | 369 | if (ticker->queue->head == obj) { |
<> | 149:156823d33999 | 370 | // first in the list, so just drop me |
AnnaBridge | 167:e84263d55307 | 371 | ticker->queue->head = obj->next; |
AnnaBridge | 167:e84263d55307 | 372 | schedule_interrupt(ticker); |
<> | 149:156823d33999 | 373 | } else { |
<> | 149:156823d33999 | 374 | // find the object before me, then drop me |
AnnaBridge | 167:e84263d55307 | 375 | ticker_event_t* p = ticker->queue->head; |
<> | 149:156823d33999 | 376 | while (p != NULL) { |
<> | 149:156823d33999 | 377 | if (p->next == obj) { |
<> | 149:156823d33999 | 378 | p->next = obj->next; |
<> | 149:156823d33999 | 379 | break; |
<> | 149:156823d33999 | 380 | } |
<> | 149:156823d33999 | 381 | p = p->next; |
<> | 149:156823d33999 | 382 | } |
<> | 149:156823d33999 | 383 | } |
<> | 149:156823d33999 | 384 | |
<> | 149:156823d33999 | 385 | core_util_critical_section_exit(); |
<> | 149:156823d33999 | 386 | } |
<> | 149:156823d33999 | 387 | |
AnnaBridge | 167:e84263d55307 | 388 | timestamp_t ticker_read(const ticker_data_t *const ticker) |
<> | 149:156823d33999 | 389 | { |
AnnaBridge | 167:e84263d55307 | 390 | return ticker_read_us(ticker); |
AnnaBridge | 167:e84263d55307 | 391 | } |
AnnaBridge | 167:e84263d55307 | 392 | |
AnnaBridge | 167:e84263d55307 | 393 | us_timestamp_t ticker_read_us(const ticker_data_t *const ticker) |
AnnaBridge | 167:e84263d55307 | 394 | { |
AnnaBridge | 175:af195413fb11 | 395 | initialize(ticker); |
AnnaBridge | 181:57724642e740 | 396 | |
AnnaBridge | 181:57724642e740 | 397 | core_util_critical_section_enter(); |
AnnaBridge | 167:e84263d55307 | 398 | update_present_time(ticker); |
AnnaBridge | 181:57724642e740 | 399 | core_util_critical_section_exit(); |
AnnaBridge | 181:57724642e740 | 400 | |
AnnaBridge | 167:e84263d55307 | 401 | return ticker->queue->present_time; |
<> | 149:156823d33999 | 402 | } |
<> | 149:156823d33999 | 403 | |
<> | 149:156823d33999 | 404 | int ticker_get_next_timestamp(const ticker_data_t *const data, timestamp_t *timestamp) |
<> | 149:156823d33999 | 405 | { |
<> | 149:156823d33999 | 406 | int ret = 0; |
<> | 149:156823d33999 | 407 | |
<> | 149:156823d33999 | 408 | /* if head is NULL, there are no pending events */ |
<> | 149:156823d33999 | 409 | core_util_critical_section_enter(); |
<> | 149:156823d33999 | 410 | if (data->queue->head != NULL) { |
<> | 149:156823d33999 | 411 | *timestamp = data->queue->head->timestamp; |
<> | 149:156823d33999 | 412 | ret = 1; |
<> | 149:156823d33999 | 413 | } |
<> | 149:156823d33999 | 414 | core_util_critical_section_exit(); |
<> | 149:156823d33999 | 415 | |
<> | 149:156823d33999 | 416 | return ret; |
<> | 149:156823d33999 | 417 | } |