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