Example
Dependencies: FXAS21002 FXOS8700Q
simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/source/m2mtimerpimpl.cpp@0:11cc2b7889af, 2019-11-19 (annotated)
- Committer:
- maygup01
- Date:
- Tue Nov 19 09:49:38 2019 +0000
- Revision:
- 0:11cc2b7889af
Example
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
maygup01 | 0:11cc2b7889af | 1 | /* |
maygup01 | 0:11cc2b7889af | 2 | * Copyright (c) 2015-2016 ARM Limited. All rights reserved. |
maygup01 | 0:11cc2b7889af | 3 | * SPDX-License-Identifier: Apache-2.0 |
maygup01 | 0:11cc2b7889af | 4 | * Licensed under the Apache License, Version 2.0 (the License); you may |
maygup01 | 0:11cc2b7889af | 5 | * not use this file except in compliance with the License. |
maygup01 | 0:11cc2b7889af | 6 | * You may obtain a copy of the License at |
maygup01 | 0:11cc2b7889af | 7 | * |
maygup01 | 0:11cc2b7889af | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
maygup01 | 0:11cc2b7889af | 9 | * |
maygup01 | 0:11cc2b7889af | 10 | * Unless required by applicable law or agreed to in writing, software |
maygup01 | 0:11cc2b7889af | 11 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT |
maygup01 | 0:11cc2b7889af | 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
maygup01 | 0:11cc2b7889af | 13 | * See the License for the specific language governing permissions and |
maygup01 | 0:11cc2b7889af | 14 | * limitations under the License. |
maygup01 | 0:11cc2b7889af | 15 | */ |
maygup01 | 0:11cc2b7889af | 16 | |
maygup01 | 0:11cc2b7889af | 17 | #include "mbed-client-classic/m2mtimerpimpl.h" |
maygup01 | 0:11cc2b7889af | 18 | #include "mbed-client/m2mtimerobserver.h" |
maygup01 | 0:11cc2b7889af | 19 | |
maygup01 | 0:11cc2b7889af | 20 | #include "eventOS_event_timer.h" |
maygup01 | 0:11cc2b7889af | 21 | #include "eventOS_scheduler.h" |
maygup01 | 0:11cc2b7889af | 22 | |
maygup01 | 0:11cc2b7889af | 23 | #include <assert.h> |
maygup01 | 0:11cc2b7889af | 24 | #include <string.h> |
maygup01 | 0:11cc2b7889af | 25 | |
maygup01 | 0:11cc2b7889af | 26 | |
maygup01 | 0:11cc2b7889af | 27 | #define MBED_CLIENT_TIMER_TASKLET_INIT_EVENT 0 // Tasklet init occurs always when generating a tasklet |
maygup01 | 0:11cc2b7889af | 28 | #define MBED_CLIENT_TIMER_EVENT 10 |
maygup01 | 0:11cc2b7889af | 29 | |
maygup01 | 0:11cc2b7889af | 30 | // This is set to _status on constructor, which forces the lazy second phase initialization |
maygup01 | 0:11cc2b7889af | 31 | // to happen once in initialize_tasklet(). Whole scheme is there to avoid overhead or |
maygup01 | 0:11cc2b7889af | 32 | // unwanted serialization on event OS scheduler mutex, as the whole tasklet needs to be initialized |
maygup01 | 0:11cc2b7889af | 33 | // just once for the whole lifecycle of cloud client. |
maygup01 | 0:11cc2b7889af | 34 | #define STATUS_INIT_NOT_DONE_YET 3 |
maygup01 | 0:11cc2b7889af | 35 | |
maygup01 | 0:11cc2b7889af | 36 | |
maygup01 | 0:11cc2b7889af | 37 | int8_t M2MTimerPimpl::_tasklet_id = -1; |
maygup01 | 0:11cc2b7889af | 38 | |
maygup01 | 0:11cc2b7889af | 39 | extern "C" void tasklet_func(arm_event_s *event) |
maygup01 | 0:11cc2b7889af | 40 | { |
maygup01 | 0:11cc2b7889af | 41 | // skip the init event as there will be a timer event after |
maygup01 | 0:11cc2b7889af | 42 | if (event->event_type == MBED_CLIENT_TIMER_EVENT) { |
maygup01 | 0:11cc2b7889af | 43 | |
maygup01 | 0:11cc2b7889af | 44 | M2MTimerPimpl* timer = (M2MTimerPimpl*)event->data_ptr; |
maygup01 | 0:11cc2b7889af | 45 | assert(timer); |
maygup01 | 0:11cc2b7889af | 46 | timer->handle_timer_event(*event); |
maygup01 | 0:11cc2b7889af | 47 | } |
maygup01 | 0:11cc2b7889af | 48 | } |
maygup01 | 0:11cc2b7889af | 49 | |
maygup01 | 0:11cc2b7889af | 50 | void M2MTimerPimpl::handle_timer_event(const arm_event_s &event) |
maygup01 | 0:11cc2b7889af | 51 | { |
maygup01 | 0:11cc2b7889af | 52 | // Clear the reference to timer event which is now received and handled. |
maygup01 | 0:11cc2b7889af | 53 | // This avoids the useless work from canceling a event if the timer is restarted |
maygup01 | 0:11cc2b7889af | 54 | // and also lets the assertions verify the object state correctly. |
maygup01 | 0:11cc2b7889af | 55 | _timer_event = NULL; |
maygup01 | 0:11cc2b7889af | 56 | |
maygup01 | 0:11cc2b7889af | 57 | if (get_still_left_time() > 0) { |
maygup01 | 0:11cc2b7889af | 58 | start_still_left_timer(); |
maygup01 | 0:11cc2b7889af | 59 | } else { |
maygup01 | 0:11cc2b7889af | 60 | timer_expired(); |
maygup01 | 0:11cc2b7889af | 61 | } |
maygup01 | 0:11cc2b7889af | 62 | } |
maygup01 | 0:11cc2b7889af | 63 | |
maygup01 | 0:11cc2b7889af | 64 | M2MTimerPimpl::M2MTimerPimpl(M2MTimerObserver& observer) |
maygup01 | 0:11cc2b7889af | 65 | : _observer(observer), |
maygup01 | 0:11cc2b7889af | 66 | _interval(0), |
maygup01 | 0:11cc2b7889af | 67 | _intermediate_interval(0), |
maygup01 | 0:11cc2b7889af | 68 | _total_interval(0), |
maygup01 | 0:11cc2b7889af | 69 | _still_left(0), |
maygup01 | 0:11cc2b7889af | 70 | _timer_event(NULL), |
maygup01 | 0:11cc2b7889af | 71 | _type(M2MTimerObserver::Notdefined), |
maygup01 | 0:11cc2b7889af | 72 | _status(STATUS_INIT_NOT_DONE_YET), |
maygup01 | 0:11cc2b7889af | 73 | _dtls_type(false), |
maygup01 | 0:11cc2b7889af | 74 | _single_shot(true) |
maygup01 | 0:11cc2b7889af | 75 | { |
maygup01 | 0:11cc2b7889af | 76 | } |
maygup01 | 0:11cc2b7889af | 77 | |
maygup01 | 0:11cc2b7889af | 78 | M2MTimerPimpl::~M2MTimerPimpl() |
maygup01 | 0:11cc2b7889af | 79 | { |
maygup01 | 0:11cc2b7889af | 80 | // cancel the timer request, if any is pending |
maygup01 | 0:11cc2b7889af | 81 | cancel(); |
maygup01 | 0:11cc2b7889af | 82 | |
maygup01 | 0:11cc2b7889af | 83 | // there is no turning back, event os does not have eventOS_event_handler_delete() or similar, |
maygup01 | 0:11cc2b7889af | 84 | // so the tasklet is lost forever. |
maygup01 | 0:11cc2b7889af | 85 | } |
maygup01 | 0:11cc2b7889af | 86 | |
maygup01 | 0:11cc2b7889af | 87 | void M2MTimerPimpl::initialize_tasklet() |
maygup01 | 0:11cc2b7889af | 88 | { |
maygup01 | 0:11cc2b7889af | 89 | // A micro-optimization to avoid operations on mutex on every time the timer is started. |
maygup01 | 0:11cc2b7889af | 90 | // After all, the tasklet needs to be created just once for the lifecyle of whole client. |
maygup01 | 0:11cc2b7889af | 91 | if (_status == STATUS_INIT_NOT_DONE_YET) { |
maygup01 | 0:11cc2b7889af | 92 | |
maygup01 | 0:11cc2b7889af | 93 | eventOS_scheduler_mutex_wait(); |
maygup01 | 0:11cc2b7889af | 94 | |
maygup01 | 0:11cc2b7889af | 95 | if (_tasklet_id < 0) { |
maygup01 | 0:11cc2b7889af | 96 | _tasklet_id = eventOS_event_handler_create(tasklet_func, MBED_CLIENT_TIMER_TASKLET_INIT_EVENT); |
maygup01 | 0:11cc2b7889af | 97 | assert(_tasklet_id >= 0); |
maygup01 | 0:11cc2b7889af | 98 | } |
maygup01 | 0:11cc2b7889af | 99 | |
maygup01 | 0:11cc2b7889af | 100 | _status = 0; |
maygup01 | 0:11cc2b7889af | 101 | |
maygup01 | 0:11cc2b7889af | 102 | eventOS_scheduler_mutex_release(); |
maygup01 | 0:11cc2b7889af | 103 | } |
maygup01 | 0:11cc2b7889af | 104 | } |
maygup01 | 0:11cc2b7889af | 105 | |
maygup01 | 0:11cc2b7889af | 106 | void M2MTimerPimpl::start_timer(uint64_t interval, |
maygup01 | 0:11cc2b7889af | 107 | M2MTimerObserver::Type type, |
maygup01 | 0:11cc2b7889af | 108 | bool single_shot) |
maygup01 | 0:11cc2b7889af | 109 | { |
maygup01 | 0:11cc2b7889af | 110 | initialize_tasklet(); |
maygup01 | 0:11cc2b7889af | 111 | |
maygup01 | 0:11cc2b7889af | 112 | _dtls_type = false; |
maygup01 | 0:11cc2b7889af | 113 | _intermediate_interval = 0; |
maygup01 | 0:11cc2b7889af | 114 | _total_interval = 0; |
maygup01 | 0:11cc2b7889af | 115 | _status = 0; |
maygup01 | 0:11cc2b7889af | 116 | _single_shot = single_shot; |
maygup01 | 0:11cc2b7889af | 117 | _interval = interval; |
maygup01 | 0:11cc2b7889af | 118 | _type = type; |
maygup01 | 0:11cc2b7889af | 119 | _still_left = 0; |
maygup01 | 0:11cc2b7889af | 120 | start(); |
maygup01 | 0:11cc2b7889af | 121 | } |
maygup01 | 0:11cc2b7889af | 122 | |
maygup01 | 0:11cc2b7889af | 123 | void M2MTimerPimpl::start_dtls_timer(uint64_t intermediate_interval, uint64_t total_interval, M2MTimerObserver::Type type) |
maygup01 | 0:11cc2b7889af | 124 | { |
maygup01 | 0:11cc2b7889af | 125 | initialize_tasklet(); |
maygup01 | 0:11cc2b7889af | 126 | |
maygup01 | 0:11cc2b7889af | 127 | _dtls_type = true; |
maygup01 | 0:11cc2b7889af | 128 | _intermediate_interval = intermediate_interval; |
maygup01 | 0:11cc2b7889af | 129 | _total_interval = total_interval; |
maygup01 | 0:11cc2b7889af | 130 | _interval = _intermediate_interval; |
maygup01 | 0:11cc2b7889af | 131 | _status = 0; |
maygup01 | 0:11cc2b7889af | 132 | _single_shot = false; |
maygup01 | 0:11cc2b7889af | 133 | _type = type; |
maygup01 | 0:11cc2b7889af | 134 | start(); |
maygup01 | 0:11cc2b7889af | 135 | } |
maygup01 | 0:11cc2b7889af | 136 | |
maygup01 | 0:11cc2b7889af | 137 | void M2MTimerPimpl::start() |
maygup01 | 0:11cc2b7889af | 138 | { |
maygup01 | 0:11cc2b7889af | 139 | // Cancel ongoing events before creating a new one. |
maygup01 | 0:11cc2b7889af | 140 | // Otherwise it can happen that there are multiple events running at the same time. |
maygup01 | 0:11cc2b7889af | 141 | cancel(); |
maygup01 | 0:11cc2b7889af | 142 | |
maygup01 | 0:11cc2b7889af | 143 | int32_t wait_time; |
maygup01 | 0:11cc2b7889af | 144 | |
maygup01 | 0:11cc2b7889af | 145 | if (_interval > INT32_MAX) { |
maygup01 | 0:11cc2b7889af | 146 | _still_left = _interval - INT32_MAX; |
maygup01 | 0:11cc2b7889af | 147 | wait_time = INT32_MAX; |
maygup01 | 0:11cc2b7889af | 148 | } else { |
maygup01 | 0:11cc2b7889af | 149 | wait_time = _interval; |
maygup01 | 0:11cc2b7889af | 150 | } |
maygup01 | 0:11cc2b7889af | 151 | |
maygup01 | 0:11cc2b7889af | 152 | request_event_in(wait_time); |
maygup01 | 0:11cc2b7889af | 153 | } |
maygup01 | 0:11cc2b7889af | 154 | |
maygup01 | 0:11cc2b7889af | 155 | void M2MTimerPimpl::request_event_in(int32_t delay_ms) |
maygup01 | 0:11cc2b7889af | 156 | { |
maygup01 | 0:11cc2b7889af | 157 | // init struct to zero to avoid hassle when new fields are added to it |
maygup01 | 0:11cc2b7889af | 158 | arm_event_t event = { 0 }; |
maygup01 | 0:11cc2b7889af | 159 | |
maygup01 | 0:11cc2b7889af | 160 | event.receiver = _tasklet_id; |
maygup01 | 0:11cc2b7889af | 161 | event.sender = _tasklet_id; |
maygup01 | 0:11cc2b7889af | 162 | event.event_type = MBED_CLIENT_TIMER_EVENT; |
maygup01 | 0:11cc2b7889af | 163 | event.data_ptr = this; |
maygup01 | 0:11cc2b7889af | 164 | event.priority = ARM_LIB_MED_PRIORITY_EVENT; |
maygup01 | 0:11cc2b7889af | 165 | |
maygup01 | 0:11cc2b7889af | 166 | // check first, that there is no timer event still pending |
maygup01 | 0:11cc2b7889af | 167 | assert(_timer_event == NULL); |
maygup01 | 0:11cc2b7889af | 168 | |
maygup01 | 0:11cc2b7889af | 169 | const uint32_t delay_ticks = eventOS_event_timer_ms_to_ticks(delay_ms); |
maygup01 | 0:11cc2b7889af | 170 | |
maygup01 | 0:11cc2b7889af | 171 | _timer_event = eventOS_event_timer_request_in(&event, delay_ticks); |
maygup01 | 0:11cc2b7889af | 172 | |
maygup01 | 0:11cc2b7889af | 173 | // The timer request may fail only if the system is out of pre-allocated |
maygup01 | 0:11cc2b7889af | 174 | // timers and it can not allocate more. |
maygup01 | 0:11cc2b7889af | 175 | assert(_timer_event != NULL); |
maygup01 | 0:11cc2b7889af | 176 | } |
maygup01 | 0:11cc2b7889af | 177 | |
maygup01 | 0:11cc2b7889af | 178 | void M2MTimerPimpl::cancel() |
maygup01 | 0:11cc2b7889af | 179 | { |
maygup01 | 0:11cc2b7889af | 180 | // NULL event is ok to cancel |
maygup01 | 0:11cc2b7889af | 181 | eventOS_cancel(_timer_event); |
maygup01 | 0:11cc2b7889af | 182 | |
maygup01 | 0:11cc2b7889af | 183 | _timer_event = NULL; |
maygup01 | 0:11cc2b7889af | 184 | } |
maygup01 | 0:11cc2b7889af | 185 | |
maygup01 | 0:11cc2b7889af | 186 | void M2MTimerPimpl::stop_timer() |
maygup01 | 0:11cc2b7889af | 187 | { |
maygup01 | 0:11cc2b7889af | 188 | _interval = 0; |
maygup01 | 0:11cc2b7889af | 189 | _single_shot = true; |
maygup01 | 0:11cc2b7889af | 190 | _still_left = 0; |
maygup01 | 0:11cc2b7889af | 191 | cancel(); |
maygup01 | 0:11cc2b7889af | 192 | } |
maygup01 | 0:11cc2b7889af | 193 | |
maygup01 | 0:11cc2b7889af | 194 | void M2MTimerPimpl::timer_expired() |
maygup01 | 0:11cc2b7889af | 195 | { |
maygup01 | 0:11cc2b7889af | 196 | _status++; |
maygup01 | 0:11cc2b7889af | 197 | |
maygup01 | 0:11cc2b7889af | 198 | // The code is expecting that the expiration has happened 0, 1 or more times, |
maygup01 | 0:11cc2b7889af | 199 | // and we also need to check for overflow as the _status is stored in 2 bits slot. |
maygup01 | 0:11cc2b7889af | 200 | if (_status > 2) { |
maygup01 | 0:11cc2b7889af | 201 | _status = 2; |
maygup01 | 0:11cc2b7889af | 202 | } |
maygup01 | 0:11cc2b7889af | 203 | |
maygup01 | 0:11cc2b7889af | 204 | _observer.timer_expired(_type); |
maygup01 | 0:11cc2b7889af | 205 | |
maygup01 | 0:11cc2b7889af | 206 | if ((!_dtls_type) && (!_single_shot)) { |
maygup01 | 0:11cc2b7889af | 207 | // start next round of periodic timer |
maygup01 | 0:11cc2b7889af | 208 | start(); |
maygup01 | 0:11cc2b7889af | 209 | } else if ((_dtls_type) && (!is_total_interval_passed())) { |
maygup01 | 0:11cc2b7889af | 210 | // if only the intermediate time has passed, we need still wait up to total time |
maygup01 | 0:11cc2b7889af | 211 | _interval = _total_interval - _intermediate_interval; |
maygup01 | 0:11cc2b7889af | 212 | start(); |
maygup01 | 0:11cc2b7889af | 213 | } |
maygup01 | 0:11cc2b7889af | 214 | } |
maygup01 | 0:11cc2b7889af | 215 | |
maygup01 | 0:11cc2b7889af | 216 | bool M2MTimerPimpl::is_intermediate_interval_passed() const |
maygup01 | 0:11cc2b7889af | 217 | { |
maygup01 | 0:11cc2b7889af | 218 | if (_status > 0) { |
maygup01 | 0:11cc2b7889af | 219 | return true; |
maygup01 | 0:11cc2b7889af | 220 | } |
maygup01 | 0:11cc2b7889af | 221 | return false; |
maygup01 | 0:11cc2b7889af | 222 | } |
maygup01 | 0:11cc2b7889af | 223 | |
maygup01 | 0:11cc2b7889af | 224 | bool M2MTimerPimpl::is_total_interval_passed() const |
maygup01 | 0:11cc2b7889af | 225 | { |
maygup01 | 0:11cc2b7889af | 226 | if (_status > 1) { |
maygup01 | 0:11cc2b7889af | 227 | return true; |
maygup01 | 0:11cc2b7889af | 228 | } |
maygup01 | 0:11cc2b7889af | 229 | return false; |
maygup01 | 0:11cc2b7889af | 230 | } |
maygup01 | 0:11cc2b7889af | 231 | |
maygup01 | 0:11cc2b7889af | 232 | uint64_t M2MTimerPimpl::get_still_left_time() const |
maygup01 | 0:11cc2b7889af | 233 | { |
maygup01 | 0:11cc2b7889af | 234 | return _still_left; |
maygup01 | 0:11cc2b7889af | 235 | } |
maygup01 | 0:11cc2b7889af | 236 | |
maygup01 | 0:11cc2b7889af | 237 | void M2MTimerPimpl::start_still_left_timer() |
maygup01 | 0:11cc2b7889af | 238 | { |
maygup01 | 0:11cc2b7889af | 239 | if (_still_left > 0) { |
maygup01 | 0:11cc2b7889af | 240 | |
maygup01 | 0:11cc2b7889af | 241 | int32_t wait_time; |
maygup01 | 0:11cc2b7889af | 242 | |
maygup01 | 0:11cc2b7889af | 243 | if (_still_left > INT32_MAX) { |
maygup01 | 0:11cc2b7889af | 244 | _still_left = _still_left - INT32_MAX; |
maygup01 | 0:11cc2b7889af | 245 | wait_time = INT32_MAX; |
maygup01 | 0:11cc2b7889af | 246 | } else { |
maygup01 | 0:11cc2b7889af | 247 | wait_time = _still_left; |
maygup01 | 0:11cc2b7889af | 248 | _still_left = 0; |
maygup01 | 0:11cc2b7889af | 249 | } |
maygup01 | 0:11cc2b7889af | 250 | |
maygup01 | 0:11cc2b7889af | 251 | request_event_in(wait_time); |
maygup01 | 0:11cc2b7889af | 252 | |
maygup01 | 0:11cc2b7889af | 253 | } else { |
maygup01 | 0:11cc2b7889af | 254 | _observer.timer_expired(_type); |
maygup01 | 0:11cc2b7889af | 255 | if (!_single_shot) { |
maygup01 | 0:11cc2b7889af | 256 | start_timer(_interval, _type, _single_shot); |
maygup01 | 0:11cc2b7889af | 257 | } |
maygup01 | 0:11cc2b7889af | 258 | } |
maygup01 | 0:11cc2b7889af | 259 | } |