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