Sarah Marsh / Mbed OS EddystoneBeacon
Committer:
sarahmarshy
Date:
Tue Nov 29 06:29:10 2016 +0000
Revision:
0:1c7da5f83647
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sarahmarshy 0:1c7da5f83647 1 /*
sarahmarshy 0:1c7da5f83647 2 * Copyright (c) 2016, ARM Limited, All Rights Reserved
sarahmarshy 0:1c7da5f83647 3 * SPDX-License-Identifier: Apache-2.0
sarahmarshy 0:1c7da5f83647 4 *
sarahmarshy 0:1c7da5f83647 5 * Licensed under the Apache License, Version 2.0 (the "License"); you may
sarahmarshy 0:1c7da5f83647 6 * not use this file except in compliance with the License.
sarahmarshy 0:1c7da5f83647 7 * You may obtain a copy of the License at
sarahmarshy 0:1c7da5f83647 8 *
sarahmarshy 0:1c7da5f83647 9 * http://www.apache.org/licenses/LICENSE-2.0
sarahmarshy 0:1c7da5f83647 10 *
sarahmarshy 0:1c7da5f83647 11 * Unless required by applicable law or agreed to in writing, software
sarahmarshy 0:1c7da5f83647 12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
sarahmarshy 0:1c7da5f83647 13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
sarahmarshy 0:1c7da5f83647 14 * See the License for the specific language governing permissions and
sarahmarshy 0:1c7da5f83647 15 * limitations under the License.
sarahmarshy 0:1c7da5f83647 16 */
sarahmarshy 0:1c7da5f83647 17 #ifndef BLE_API_SOURCE_MBEDCLASSICEVENTQUEUE_H_
sarahmarshy 0:1c7da5f83647 18 #define BLE_API_SOURCE_MBEDCLASSICEVENTQUEUE_H_
sarahmarshy 0:1c7da5f83647 19
sarahmarshy 0:1c7da5f83647 20 #include <cmsis.h>
sarahmarshy 0:1c7da5f83647 21 #include "PriorityQueue.h"
sarahmarshy 0:1c7da5f83647 22 #include "Ticker.h"
sarahmarshy 0:1c7da5f83647 23 #include "Timer.h"
sarahmarshy 0:1c7da5f83647 24 #include <stdio.h>
sarahmarshy 0:1c7da5f83647 25 #include "Thunk.h"
sarahmarshy 0:1c7da5f83647 26 #include "MakeThunk.h"
sarahmarshy 0:1c7da5f83647 27 #include "EventQueue.h"
sarahmarshy 0:1c7da5f83647 28
sarahmarshy 0:1c7da5f83647 29 #include <util/CriticalSectionLock.h>
sarahmarshy 0:1c7da5f83647 30 typedef ::mbed::util::CriticalSectionLock CriticalSection;
sarahmarshy 0:1c7da5f83647 31
sarahmarshy 0:1c7da5f83647 32 namespace eq {
sarahmarshy 0:1c7da5f83647 33
sarahmarshy 0:1c7da5f83647 34 template<std::size_t EventCount>
sarahmarshy 0:1c7da5f83647 35 class EventQueueClassic: public EventQueue {
sarahmarshy 0:1c7da5f83647 36
sarahmarshy 0:1c7da5f83647 37 /// Describe an event.
sarahmarshy 0:1c7da5f83647 38 /// An event is composed of a function f to execute after a a time t.
sarahmarshy 0:1c7da5f83647 39 /// Optionnaly, the event can be periodic and in this case the function f
sarahmarshy 0:1c7da5f83647 40 /// is executed after each period p.
sarahmarshy 0:1c7da5f83647 41 struct Event {
sarahmarshy 0:1c7da5f83647 42 /// construct an event
sarahmarshy 0:1c7da5f83647 43 /// @param f The function to execute when this event occur
sarahmarshy 0:1c7da5f83647 44 /// @param ms_remaining_time remaining time before this event occurence
sarahmarshy 0:1c7da5f83647 45 /// @param ms_repeat_period If the event is periodic, this parameter is the
sarahmarshy 0:1c7da5f83647 46 /// period between to occurence of this event.
sarahmarshy 0:1c7da5f83647 47 Event(const function_t& f, ms_time_t ms_remaining_time, ms_time_t ms_repeat_period = 0) :
sarahmarshy 0:1c7da5f83647 48 _f(f),
sarahmarshy 0:1c7da5f83647 49 _ms_remaining_time(ms_remaining_time),
sarahmarshy 0:1c7da5f83647 50 _ms_repeat_period(ms_repeat_period) {
sarahmarshy 0:1c7da5f83647 51 }
sarahmarshy 0:1c7da5f83647 52
sarahmarshy 0:1c7da5f83647 53 /// call the inner function within an event
sarahmarshy 0:1c7da5f83647 54 void operator()() {
sarahmarshy 0:1c7da5f83647 55 _f();
sarahmarshy 0:1c7da5f83647 56 }
sarahmarshy 0:1c7da5f83647 57
sarahmarshy 0:1c7da5f83647 58 /// return a reference to the inner function
sarahmarshy 0:1c7da5f83647 59 const function_t& get_function() const {
sarahmarshy 0:1c7da5f83647 60 return _f;
sarahmarshy 0:1c7da5f83647 61 }
sarahmarshy 0:1c7da5f83647 62
sarahmarshy 0:1c7da5f83647 63 /// comparison operator used by the priority queue.
sarahmarshy 0:1c7da5f83647 64 /// comaprare remaining time between two events
sarahmarshy 0:1c7da5f83647 65 friend bool operator<(const Event& lhs, const Event& rhs) {
sarahmarshy 0:1c7da5f83647 66 return lhs._ms_remaining_time < rhs._ms_remaining_time;
sarahmarshy 0:1c7da5f83647 67 }
sarahmarshy 0:1c7da5f83647 68
sarahmarshy 0:1c7da5f83647 69 /// return the time remaining when this event was inserted into the priority queue.
sarahmarshy 0:1c7da5f83647 70 ms_time_t get_ms_remaining_time() const {
sarahmarshy 0:1c7da5f83647 71 return _ms_remaining_time;
sarahmarshy 0:1c7da5f83647 72 }
sarahmarshy 0:1c7da5f83647 73
sarahmarshy 0:1c7da5f83647 74 /// update the remaining time for this event
sarahmarshy 0:1c7da5f83647 75 void set_ms_remaining_time(ms_time_t new_remaining_time) {
sarahmarshy 0:1c7da5f83647 76 _ms_remaining_time = new_remaining_time;
sarahmarshy 0:1c7da5f83647 77 }
sarahmarshy 0:1c7da5f83647 78
sarahmarshy 0:1c7da5f83647 79 /// If an event is periodic, return the time between two occurence
sarahmarshy 0:1c7da5f83647 80 ms_time_t get_ms_repeat_period() const {
sarahmarshy 0:1c7da5f83647 81 return _ms_repeat_period;
sarahmarshy 0:1c7da5f83647 82 }
sarahmarshy 0:1c7da5f83647 83
sarahmarshy 0:1c7da5f83647 84 private:
sarahmarshy 0:1c7da5f83647 85 function_t _f;
sarahmarshy 0:1c7da5f83647 86 ms_time_t _ms_remaining_time;
sarahmarshy 0:1c7da5f83647 87 const ms_time_t _ms_repeat_period;
sarahmarshy 0:1c7da5f83647 88 };
sarahmarshy 0:1c7da5f83647 89
sarahmarshy 0:1c7da5f83647 90 /// type of the internal queue
sarahmarshy 0:1c7da5f83647 91 typedef PriorityQueue<Event, EventCount> priority_queue_t;
sarahmarshy 0:1c7da5f83647 92
sarahmarshy 0:1c7da5f83647 93 /// iterator for the queue type
sarahmarshy 0:1c7da5f83647 94 typedef typename priority_queue_t::iterator q_iterator_t;
sarahmarshy 0:1c7da5f83647 95
sarahmarshy 0:1c7da5f83647 96 /// node type in the queue
sarahmarshy 0:1c7da5f83647 97 typedef typename priority_queue_t::Node q_node_t;
sarahmarshy 0:1c7da5f83647 98
sarahmarshy 0:1c7da5f83647 99 public:
sarahmarshy 0:1c7da5f83647 100 /// Construct an empty event queue
sarahmarshy 0:1c7da5f83647 101 EventQueueClassic() :
sarahmarshy 0:1c7da5f83647 102 _events_queue(), _ticker(), _timer(), _timed_event_pending(false) {
sarahmarshy 0:1c7da5f83647 103 }
sarahmarshy 0:1c7da5f83647 104
sarahmarshy 0:1c7da5f83647 105 virtual ~EventQueueClassic() { }
sarahmarshy 0:1c7da5f83647 106
sarahmarshy 0:1c7da5f83647 107 virtual bool cancel(event_handle_t event_handle) {
sarahmarshy 0:1c7da5f83647 108 CriticalSection critical_section;
sarahmarshy 0:1c7da5f83647 109 bool success = _events_queue.erase(static_cast<q_node_t*>(event_handle));
sarahmarshy 0:1c7da5f83647 110 if (success) {
sarahmarshy 0:1c7da5f83647 111 // update the timers and events remaining time
sarahmarshy 0:1c7da5f83647 112 updateTime();
sarahmarshy 0:1c7da5f83647 113 }
sarahmarshy 0:1c7da5f83647 114 return success;
sarahmarshy 0:1c7da5f83647 115 }
sarahmarshy 0:1c7da5f83647 116
sarahmarshy 0:1c7da5f83647 117 void dispatch() {
sarahmarshy 0:1c7da5f83647 118 while(true) {
sarahmarshy 0:1c7da5f83647 119 function_t f;
sarahmarshy 0:1c7da5f83647 120 // pick a task from the queue/ or leave
sarahmarshy 0:1c7da5f83647 121 {
sarahmarshy 0:1c7da5f83647 122 CriticalSection cs;
sarahmarshy 0:1c7da5f83647 123 q_iterator_t event_it = _events_queue.begin();
sarahmarshy 0:1c7da5f83647 124 if(event_it != _events_queue.end() && event_it->get_ms_remaining_time() == 0) {
sarahmarshy 0:1c7da5f83647 125 f = event_it->get_function();
sarahmarshy 0:1c7da5f83647 126 // if the event_it should be repeated, reschedule it
sarahmarshy 0:1c7da5f83647 127 if (event_it->get_ms_repeat_period()) {
sarahmarshy 0:1c7da5f83647 128 reschedule_event(event_it);
sarahmarshy 0:1c7da5f83647 129 } else {
sarahmarshy 0:1c7da5f83647 130 _events_queue.pop();
sarahmarshy 0:1c7da5f83647 131 }
sarahmarshy 0:1c7da5f83647 132 } else {
sarahmarshy 0:1c7da5f83647 133 break;
sarahmarshy 0:1c7da5f83647 134 }
sarahmarshy 0:1c7da5f83647 135 }
sarahmarshy 0:1c7da5f83647 136 f();
sarahmarshy 0:1c7da5f83647 137 }
sarahmarshy 0:1c7da5f83647 138 }
sarahmarshy 0:1c7da5f83647 139
sarahmarshy 0:1c7da5f83647 140 private:
sarahmarshy 0:1c7da5f83647 141
sarahmarshy 0:1c7da5f83647 142 void update_ticker(ms_time_t ms_delay) {
sarahmarshy 0:1c7da5f83647 143 _timed_event_pending = true;
sarahmarshy 0:1c7da5f83647 144 _ticker.detach();
sarahmarshy 0:1c7da5f83647 145 _ticker.attach(this, &EventQueueClassic::updateTime, ((float) ms_delay / 1000));
sarahmarshy 0:1c7da5f83647 146 }
sarahmarshy 0:1c7da5f83647 147
sarahmarshy 0:1c7da5f83647 148 void update_ticker(q_node_t* ref, ms_time_t ms_delay) {
sarahmarshy 0:1c7da5f83647 149 // look if the node inserted is the first node with a delay
sarahmarshy 0:1c7da5f83647 150 for (q_iterator_t it = _events_queue.begin(); it != _events_queue.end(); ++it) {
sarahmarshy 0:1c7da5f83647 151 if(it->get_ms_remaining_time()) {
sarahmarshy 0:1c7da5f83647 152 if (it.get_node() == ref) {
sarahmarshy 0:1c7da5f83647 153 // update the ticker to ms_delay if the first event
sarahmarshy 0:1c7da5f83647 154 // with a delay is the one inserted
sarahmarshy 0:1c7da5f83647 155 update_ticker(ms_delay);
sarahmarshy 0:1c7da5f83647 156 }
sarahmarshy 0:1c7da5f83647 157 break;
sarahmarshy 0:1c7da5f83647 158 }
sarahmarshy 0:1c7da5f83647 159 }
sarahmarshy 0:1c7da5f83647 160 }
sarahmarshy 0:1c7da5f83647 161
sarahmarshy 0:1c7da5f83647 162 void update_events_remaining_time(ms_time_t elapsed_time) {
sarahmarshy 0:1c7da5f83647 163 bool ticker_updated = false;
sarahmarshy 0:1c7da5f83647 164
sarahmarshy 0:1c7da5f83647 165 for (q_iterator_t it = _events_queue.begin();
sarahmarshy 0:1c7da5f83647 166 it != _events_queue.end(); ++it) {
sarahmarshy 0:1c7da5f83647 167 ms_time_t remaining_time = it->get_ms_remaining_time();
sarahmarshy 0:1c7da5f83647 168 if(remaining_time) {
sarahmarshy 0:1c7da5f83647 169 if(remaining_time <= elapsed_time) {
sarahmarshy 0:1c7da5f83647 170 it->set_ms_remaining_time(0);
sarahmarshy 0:1c7da5f83647 171 } else {
sarahmarshy 0:1c7da5f83647 172 it->set_ms_remaining_time(remaining_time - elapsed_time);
sarahmarshy 0:1c7da5f83647 173 if (!ticker_updated) {
sarahmarshy 0:1c7da5f83647 174 update_ticker(it->get_ms_remaining_time());
sarahmarshy 0:1c7da5f83647 175 _timer.start();
sarahmarshy 0:1c7da5f83647 176 ticker_updated = true;
sarahmarshy 0:1c7da5f83647 177 }
sarahmarshy 0:1c7da5f83647 178 }
sarahmarshy 0:1c7da5f83647 179 }
sarahmarshy 0:1c7da5f83647 180 }
sarahmarshy 0:1c7da5f83647 181 }
sarahmarshy 0:1c7da5f83647 182
sarahmarshy 0:1c7da5f83647 183 void updateTime() {
sarahmarshy 0:1c7da5f83647 184 CriticalSection critical_section;
sarahmarshy 0:1c7da5f83647 185 ms_time_t elapsed_time = _timer.read_ms();
sarahmarshy 0:1c7da5f83647 186 _timed_event_pending = false;
sarahmarshy 0:1c7da5f83647 187 _timer.stop();
sarahmarshy 0:1c7da5f83647 188 _timer.reset();
sarahmarshy 0:1c7da5f83647 189 _ticker.detach();
sarahmarshy 0:1c7da5f83647 190 update_events_remaining_time(elapsed_time);
sarahmarshy 0:1c7da5f83647 191 }
sarahmarshy 0:1c7da5f83647 192
sarahmarshy 0:1c7da5f83647 193 void reschedule_event(q_iterator_t& event_it) {
sarahmarshy 0:1c7da5f83647 194 ms_time_t ms_period = event_it->get_ms_repeat_period();
sarahmarshy 0:1c7da5f83647 195
sarahmarshy 0:1c7da5f83647 196 if (_timed_event_pending == false) {
sarahmarshy 0:1c7da5f83647 197 update_ticker(ms_period);
sarahmarshy 0:1c7da5f83647 198 _timer.start();
sarahmarshy 0:1c7da5f83647 199 event_it->set_ms_remaining_time(ms_period);
sarahmarshy 0:1c7da5f83647 200 _events_queue.update(event_it);
sarahmarshy 0:1c7da5f83647 201 } else {
sarahmarshy 0:1c7da5f83647 202 int elapsed_time = _timer.read_ms();
sarahmarshy 0:1c7da5f83647 203 event_it->set_ms_remaining_time(elapsed_time + ms_period);
sarahmarshy 0:1c7da5f83647 204 _events_queue.update(event_it);
sarahmarshy 0:1c7da5f83647 205 update_ticker(event_it.get_node(), ms_period);
sarahmarshy 0:1c7da5f83647 206 }
sarahmarshy 0:1c7da5f83647 207 }
sarahmarshy 0:1c7da5f83647 208
sarahmarshy 0:1c7da5f83647 209 virtual event_handle_t do_post(const function_t& fn, ms_time_t ms_delay = 0, bool repeat = false) {
sarahmarshy 0:1c7da5f83647 210 if(repeat && (ms_delay == 0)) {
sarahmarshy 0:1c7da5f83647 211 return NULL;
sarahmarshy 0:1c7da5f83647 212 }
sarahmarshy 0:1c7da5f83647 213
sarahmarshy 0:1c7da5f83647 214 Event event(fn, ms_delay, repeat ? ms_delay : 0);
sarahmarshy 0:1c7da5f83647 215
sarahmarshy 0:1c7da5f83647 216 CriticalSection critical_section;
sarahmarshy 0:1c7da5f83647 217 if (_events_queue.full()) {
sarahmarshy 0:1c7da5f83647 218 return NULL;
sarahmarshy 0:1c7da5f83647 219 }
sarahmarshy 0:1c7da5f83647 220
sarahmarshy 0:1c7da5f83647 221 // there is no need to update timings if ms_delay == 0
sarahmarshy 0:1c7da5f83647 222 if (!ms_delay) {
sarahmarshy 0:1c7da5f83647 223 return _events_queue.push(event).get_node();
sarahmarshy 0:1c7da5f83647 224 }
sarahmarshy 0:1c7da5f83647 225
sarahmarshy 0:1c7da5f83647 226 // if there is no pending timed event, just add this one and start timers
sarahmarshy 0:1c7da5f83647 227 if (_timed_event_pending == false) {
sarahmarshy 0:1c7da5f83647 228 update_ticker(ms_delay);
sarahmarshy 0:1c7da5f83647 229 _timer.start();
sarahmarshy 0:1c7da5f83647 230 return _events_queue.push(event).get_node();
sarahmarshy 0:1c7da5f83647 231 }
sarahmarshy 0:1c7da5f83647 232
sarahmarshy 0:1c7da5f83647 233 int elapsed_time = _timer.read_ms();
sarahmarshy 0:1c7da5f83647 234
sarahmarshy 0:1c7da5f83647 235 // update remaining time and post the event
sarahmarshy 0:1c7da5f83647 236 event.set_ms_remaining_time(ms_delay + elapsed_time);
sarahmarshy 0:1c7da5f83647 237 event_handle_t handle = _events_queue.push(event).get_node();
sarahmarshy 0:1c7da5f83647 238 update_ticker(static_cast<q_node_t*>(handle), ms_delay);
sarahmarshy 0:1c7da5f83647 239
sarahmarshy 0:1c7da5f83647 240 return handle;
sarahmarshy 0:1c7da5f83647 241 }
sarahmarshy 0:1c7da5f83647 242
sarahmarshy 0:1c7da5f83647 243 priority_queue_t _events_queue;
sarahmarshy 0:1c7da5f83647 244 mbed::Ticker _ticker;
sarahmarshy 0:1c7da5f83647 245 mbed::Timer _timer;
sarahmarshy 0:1c7da5f83647 246 bool _timed_event_pending;
sarahmarshy 0:1c7da5f83647 247 };
sarahmarshy 0:1c7da5f83647 248
sarahmarshy 0:1c7da5f83647 249 } // namespace eq
sarahmarshy 0:1c7da5f83647 250
sarahmarshy 0:1c7da5f83647 251 #endif /* BLE_API_SOURCE_MBEDCLASSICEVENTQUEUE_H_ */