Committer:
leothedragon
Date:
Sun Apr 18 15:20:23 2021 +0000
Revision:
0:25fa8795676b
DS

Who changed what in which revision?

UserRevisionLine numberNew 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 }