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.
m2mtimerpimpl.cpp
00001 /* 00002 * Copyright (c) 2015-2016 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "mbed-client-classic/m2mtimerpimpl.h" 00018 #include "mbed-client/m2mtimerobserver.h" 00019 00020 #include "eventOS_event_timer.h" 00021 #include "eventOS_scheduler.h" 00022 00023 #include <assert.h> 00024 #include <string.h> 00025 00026 00027 #define MBED_CLIENT_TIMER_TASKLET_INIT_EVENT 0 // Tasklet init occurs always when generating a tasklet 00028 #define MBED_CLIENT_TIMER_EVENT 10 00029 00030 // This is set to _status on constructor, which forces the lazy second phase initialization 00031 // to happen once in initialize_tasklet(). Whole scheme is there to avoid overhead or 00032 // unwanted serialization on event OS scheduler mutex, as the whole tasklet needs to be initialized 00033 // just once for the whole lifecycle of cloud client. 00034 #define STATUS_INIT_NOT_DONE_YET 3 00035 00036 00037 int8_t M2MTimerPimpl::_tasklet_id = -1; 00038 00039 extern "C" void tasklet_func(arm_event_s *event) 00040 { 00041 // skip the init event as there will be a timer event after 00042 if (event->event_type == MBED_CLIENT_TIMER_EVENT) { 00043 00044 M2MTimerPimpl* timer = (M2MTimerPimpl*)event->data_ptr; 00045 assert(timer); 00046 timer->handle_timer_event(*event); 00047 } 00048 } 00049 00050 void M2MTimerPimpl::handle_timer_event(const arm_event_s &event) 00051 { 00052 // Clear the reference to timer event which is now received and handled. 00053 // This avoids the useless work from canceling a event if the timer is restarted 00054 // and also lets the assertions verify the object state correctly. 00055 _timer_event = NULL; 00056 00057 if (get_still_left_time() > 0) { 00058 start_still_left_timer(); 00059 } else { 00060 timer_expired(); 00061 } 00062 } 00063 00064 M2MTimerPimpl::M2MTimerPimpl(M2MTimerObserver& observer) 00065 : _observer(observer), 00066 _interval(0), 00067 _intermediate_interval(0), 00068 _total_interval(0), 00069 _still_left(0), 00070 _timer_event(NULL), 00071 _type(M2MTimerObserver::Notdefined), 00072 _status(STATUS_INIT_NOT_DONE_YET), 00073 _dtls_type(false), 00074 _single_shot(true) 00075 { 00076 } 00077 00078 M2MTimerPimpl::~M2MTimerPimpl() 00079 { 00080 // cancel the timer request, if any is pending 00081 cancel(); 00082 00083 // there is no turning back, event os does not have eventOS_event_handler_delete() or similar, 00084 // so the tasklet is lost forever. 00085 } 00086 00087 void M2MTimerPimpl::initialize_tasklet() 00088 { 00089 // A micro-optimization to avoid operations on mutex on every time the timer is started. 00090 // After all, the tasklet needs to be created just once for the lifecyle of whole client. 00091 if (_status == STATUS_INIT_NOT_DONE_YET) { 00092 00093 eventOS_scheduler_mutex_wait(); 00094 00095 if (_tasklet_id < 0) { 00096 _tasklet_id = eventOS_event_handler_create(tasklet_func, MBED_CLIENT_TIMER_TASKLET_INIT_EVENT); 00097 assert(_tasklet_id >= 0); 00098 } 00099 00100 _status = 0; 00101 00102 eventOS_scheduler_mutex_release(); 00103 } 00104 } 00105 00106 void M2MTimerPimpl::start_timer(uint64_t interval, 00107 M2MTimerObserver::Type type, 00108 bool single_shot) 00109 { 00110 initialize_tasklet(); 00111 00112 _dtls_type = false; 00113 _intermediate_interval = 0; 00114 _total_interval = 0; 00115 _status = 0; 00116 _single_shot = single_shot; 00117 _interval = interval; 00118 _type = type; 00119 _still_left = 0; 00120 start(); 00121 } 00122 00123 void M2MTimerPimpl::start_dtls_timer(uint64_t intermediate_interval, uint64_t total_interval, M2MTimerObserver::Type type) 00124 { 00125 initialize_tasklet(); 00126 00127 _dtls_type = true; 00128 _intermediate_interval = intermediate_interval; 00129 _total_interval = total_interval; 00130 _interval = _intermediate_interval; 00131 _status = 0; 00132 _single_shot = false; 00133 _type = type; 00134 start(); 00135 } 00136 00137 void M2MTimerPimpl::start() 00138 { 00139 // Cancel ongoing events before creating a new one. 00140 // Otherwise it can happen that there are multiple events running at the same time. 00141 cancel(); 00142 00143 int32_t wait_time; 00144 00145 if (_interval > INT32_MAX) { 00146 _still_left = _interval - INT32_MAX; 00147 wait_time = INT32_MAX; 00148 } else { 00149 wait_time = _interval; 00150 } 00151 00152 request_event_in(wait_time); 00153 } 00154 00155 void M2MTimerPimpl::request_event_in(int32_t delay_ms) 00156 { 00157 // init struct to zero to avoid hassle when new fields are added to it 00158 arm_event_t event = { 0 }; 00159 00160 event.receiver = _tasklet_id; 00161 event.sender = _tasklet_id; 00162 event.event_type = MBED_CLIENT_TIMER_EVENT; 00163 event.data_ptr = this; 00164 event.priority = ARM_LIB_MED_PRIORITY_EVENT; 00165 00166 // check first, that there is no timer event still pending 00167 assert(_timer_event == NULL); 00168 00169 const uint32_t delay_ticks = eventOS_event_timer_ms_to_ticks(delay_ms); 00170 00171 _timer_event = eventOS_event_timer_request_in(&event, delay_ticks); 00172 00173 // The timer request may fail only if the system is out of pre-allocated 00174 // timers and it can not allocate more. 00175 assert(_timer_event != NULL); 00176 } 00177 00178 void M2MTimerPimpl::cancel() 00179 { 00180 // NULL event is ok to cancel 00181 eventOS_cancel(_timer_event); 00182 00183 _timer_event = NULL; 00184 } 00185 00186 void M2MTimerPimpl::stop_timer() 00187 { 00188 _interval = 0; 00189 _single_shot = true; 00190 _still_left = 0; 00191 cancel(); 00192 } 00193 00194 void M2MTimerPimpl::timer_expired() 00195 { 00196 _status++; 00197 00198 // The code is expecting that the expiration has happened 0, 1 or more times, 00199 // and we also need to check for overflow as the _status is stored in 2 bits slot. 00200 if (_status > 2) { 00201 _status = 2; 00202 } 00203 00204 _observer.timer_expired(_type); 00205 00206 if ((!_dtls_type) && (!_single_shot)) { 00207 // start next round of periodic timer 00208 start(); 00209 } else if ((_dtls_type) && (!is_total_interval_passed())) { 00210 // if only the intermediate time has passed, we need still wait up to total time 00211 _interval = _total_interval - _intermediate_interval; 00212 start(); 00213 } 00214 } 00215 00216 bool M2MTimerPimpl::is_intermediate_interval_passed() const 00217 { 00218 if (_status > 0) { 00219 return true; 00220 } 00221 return false; 00222 } 00223 00224 bool M2MTimerPimpl::is_total_interval_passed() const 00225 { 00226 if (_status > 1) { 00227 return true; 00228 } 00229 return false; 00230 } 00231 00232 uint64_t M2MTimerPimpl::get_still_left_time() const 00233 { 00234 return _still_left; 00235 } 00236 00237 void M2MTimerPimpl::start_still_left_timer() 00238 { 00239 if (_still_left > 0) { 00240 00241 int32_t wait_time; 00242 00243 if (_still_left > INT32_MAX) { 00244 _still_left = _still_left - INT32_MAX; 00245 wait_time = INT32_MAX; 00246 } else { 00247 wait_time = _still_left; 00248 _still_left = 0; 00249 } 00250 00251 request_event_in(wait_time); 00252 00253 } else { 00254 _observer.timer_expired(_type); 00255 if (!_single_shot) { 00256 start_timer(_interval, _type, _single_shot); 00257 } 00258 } 00259 }
Generated on Mon Aug 29 2022 19:53:40 by
