Example

Dependencies:   FXAS21002 FXOS8700Q

Committer:
maygup01
Date:
Tue Nov 19 09:49:38 2019 +0000
Revision:
0:11cc2b7889af
Example

Who changed what in which revision?

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