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.
EventQueueClassic.h
00001 /* 00002 * Copyright (c) 2016, ARM Limited, All Rights Reserved 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00006 * not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 #ifndef BLE_API_SOURCE_MBEDCLASSICEVENTQUEUE_H_ 00018 #define BLE_API_SOURCE_MBEDCLASSICEVENTQUEUE_H_ 00019 00020 #include <cmsis.h> 00021 #include "PriorityQueue.h" 00022 #include "Ticker.h" 00023 #include "Timer.h" 00024 #include <stdio.h> 00025 #include "Thunk.h" 00026 #include "MakeThunk.h" 00027 #include "EventQueue.h" 00028 00029 #ifdef TARGET_NORDIC 00030 #include "util/NordicCriticalSectionLock.h" 00031 typedef ::util::NordicCriticalSectionLock CriticalSection; 00032 #else 00033 #include <util/CriticalSectionLock.h> 00034 typedef ::mbed::util::CriticalSectionLock CriticalSection; 00035 #endif 00036 00037 namespace eq { 00038 00039 template<std::size_t EventCount> 00040 class EventQueueClassic: public EventQueue { 00041 00042 /// Describe an event. 00043 /// An event is composed of a function f to execute after a a time t. 00044 /// Optionnaly, the event can be periodic and in this case the function f 00045 /// is executed after each period p. 00046 struct Event { 00047 /// construct an event 00048 /// @param f The function to execute when this event occur 00049 /// @param ms_remaining_time remaining time before this event occurence 00050 /// @param ms_repeat_period If the event is periodic, this parameter is the 00051 /// period between to occurence of this event. 00052 Event(const function_t& f, ms_time_t ms_remaining_time, ms_time_t ms_repeat_period = 0) : 00053 _f(f), 00054 _ms_remaining_time(ms_remaining_time), 00055 _ms_repeat_period(ms_repeat_period) { 00056 } 00057 00058 /// call the inner function within an event 00059 void operator()() { 00060 _f(); 00061 } 00062 00063 /// return a reference to the inner function 00064 const function_t& get_function() const { 00065 return _f; 00066 } 00067 00068 /// comparison operator used by the priority queue. 00069 /// comaprare remaining time between two events 00070 friend bool operator<(const Event& lhs, const Event& rhs) { 00071 return lhs._ms_remaining_time < rhs._ms_remaining_time; 00072 } 00073 00074 /// return the time remaining when this event was inserted into the priority queue. 00075 ms_time_t get_ms_remaining_time() const { 00076 return _ms_remaining_time; 00077 } 00078 00079 /// update the remaining time for this event 00080 void set_ms_remaining_time(ms_time_t new_remaining_time) { 00081 _ms_remaining_time = new_remaining_time; 00082 } 00083 00084 /// If an event is periodic, return the time between two occurence 00085 ms_time_t get_ms_repeat_period() const { 00086 return _ms_repeat_period; 00087 } 00088 00089 private: 00090 function_t _f; 00091 ms_time_t _ms_remaining_time; 00092 const ms_time_t _ms_repeat_period; 00093 }; 00094 00095 /// type of the internal queue 00096 typedef PriorityQueue<Event, EventCount> priority_queue_t; 00097 00098 /// iterator for the queue type 00099 typedef typename priority_queue_t::iterator q_iterator_t; 00100 00101 /// node type in the queue 00102 typedef typename priority_queue_t::Node q_node_t; 00103 00104 public: 00105 /// Construct an empty event queue 00106 EventQueueClassic() : 00107 _events_queue(), _ticker(), _timer(), _timed_event_pending(false) { 00108 } 00109 00110 virtual ~EventQueueClassic() { } 00111 00112 virtual bool cancel(event_handle_t event_handle) { 00113 CriticalSection critical_section; 00114 bool success = _events_queue.erase(static_cast<q_node_t*>(event_handle)); 00115 if (success) { 00116 // update the timers and events remaining time 00117 updateTime(); 00118 } 00119 return success; 00120 } 00121 00122 void dispatch() { 00123 while(true) { 00124 function_t f; 00125 // pick a task from the queue/ or leave 00126 { 00127 CriticalSection cs; 00128 q_iterator_t event_it = _events_queue.begin(); 00129 if(event_it != _events_queue.end() && event_it->get_ms_remaining_time() == 0) { 00130 f = event_it->get_function(); 00131 // if the event_it should be repeated, reschedule it 00132 if (event_it->get_ms_repeat_period()) { 00133 reschedule_event(event_it); 00134 } else { 00135 _events_queue.pop(); 00136 } 00137 } else { 00138 break; 00139 } 00140 } 00141 f(); 00142 } 00143 } 00144 00145 private: 00146 00147 void update_ticker(ms_time_t ms_delay) { 00148 _timed_event_pending = true; 00149 _ticker.detach(); 00150 _ticker.attach(this, &EventQueueClassic::updateTime, ((float) ms_delay / 1000)); 00151 } 00152 00153 void update_ticker(q_node_t* ref, ms_time_t ms_delay) { 00154 // look if the node inserted is the first node with a delay 00155 for (q_iterator_t it = _events_queue.begin(); it != _events_queue.end(); ++it) { 00156 if(it->get_ms_remaining_time()) { 00157 if (it.get_node() == ref) { 00158 // update the ticker to ms_delay if the first event 00159 // with a delay is the one inserted 00160 update_ticker(ms_delay); 00161 } 00162 break; 00163 } 00164 } 00165 } 00166 00167 void update_events_remaining_time(ms_time_t elapsed_time) { 00168 bool ticker_updated = false; 00169 00170 for (q_iterator_t it = _events_queue.begin(); 00171 it != _events_queue.end(); ++it) { 00172 ms_time_t remaining_time = it->get_ms_remaining_time(); 00173 if(remaining_time) { 00174 if(remaining_time <= elapsed_time) { 00175 it->set_ms_remaining_time(0); 00176 } else { 00177 it->set_ms_remaining_time(remaining_time - elapsed_time); 00178 if (!ticker_updated) { 00179 update_ticker(it->get_ms_remaining_time()); 00180 _timer.start(); 00181 ticker_updated = true; 00182 } 00183 } 00184 } 00185 } 00186 } 00187 00188 void updateTime() { 00189 CriticalSection critical_section; 00190 ms_time_t elapsed_time = _timer.read_ms(); 00191 _timed_event_pending = false; 00192 _timer.stop(); 00193 _timer.reset(); 00194 _ticker.detach(); 00195 update_events_remaining_time(elapsed_time); 00196 } 00197 00198 void reschedule_event(q_iterator_t& event_it) { 00199 ms_time_t ms_period = event_it->get_ms_repeat_period(); 00200 00201 if (_timed_event_pending == false) { 00202 update_ticker(ms_period); 00203 _timer.start(); 00204 event_it->set_ms_remaining_time(ms_period); 00205 _events_queue.update(event_it); 00206 } else { 00207 int elapsed_time = _timer.read_ms(); 00208 event_it->set_ms_remaining_time(elapsed_time + ms_period); 00209 _events_queue.update(event_it); 00210 update_ticker(event_it.get_node(), ms_period); 00211 } 00212 } 00213 00214 virtual event_handle_t do_post(const function_t& fn, ms_time_t ms_delay = 0, bool repeat = false) { 00215 if(repeat && (ms_delay == 0)) { 00216 return NULL; 00217 } 00218 00219 Event event(fn, ms_delay, repeat ? ms_delay : 0); 00220 00221 CriticalSection critical_section; 00222 if (_events_queue.full()) { 00223 return NULL; 00224 } 00225 00226 // there is no need to update timings if ms_delay == 0 00227 if (!ms_delay) { 00228 return _events_queue.push(event).get_node(); 00229 } 00230 00231 // if there is no pending timed event, just add this one and start timers 00232 if (_timed_event_pending == false) { 00233 update_ticker(ms_delay); 00234 _timer.start(); 00235 return _events_queue.push(event).get_node(); 00236 } 00237 00238 int elapsed_time = _timer.read_ms(); 00239 00240 // update remaining time and post the event 00241 event.set_ms_remaining_time(ms_delay + elapsed_time); 00242 event_handle_t handle = _events_queue.push(event).get_node(); 00243 update_ticker(static_cast<q_node_t*>(handle), ms_delay); 00244 00245 return handle; 00246 } 00247 00248 priority_queue_t _events_queue; 00249 mbed::Ticker _ticker; 00250 mbed::Timer _timer; 00251 bool _timed_event_pending; 00252 }; 00253 00254 } // namespace eq 00255 00256 #endif /* BLE_API_SOURCE_MBEDCLASSICEVENTQUEUE_H_ */
Generated on Thu Jul 14 2022 09:28:18 by
1.7.2