mbed-os5 only for TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Committer:
kenjiArai
Date:
Tue Dec 17 23:23:45 2019 +0000
Revision:
0:5b88d5760320
Child:
1:9db0e321a9f4
mbed-os5 only for TYBLE16

Who changed what in which revision?

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