Simulated product dispenser
Fork of mbed-cloud-workshop-connect-HTS221 by
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 Mbed cloud 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 Tue Jul 12 2022 19:12:13 by 1.7.2