Mbed Cloud example program for workshop in W27 2018.

Dependencies:   MMA7660 LM75B

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mtimerpimpl.cpp Source File

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 <assert.h>
00018 #include <time.h>
00019 
00020 #include "mbed-client-classic/m2mtimerpimpl.h"
00021 #include "mbed-client/m2mtimerobserver.h"
00022 #include "mbed-client/m2mvector.h"
00023 
00024 #include "eventOS_event.h"
00025 #include "eventOS_event_timer.h"
00026 #include "eventOS_scheduler.h"
00027 #include "ns_hal_init.h"
00028 
00029 #define MBED_CLIENT_TIMER_TASKLET_INIT_EVENT 0 // Tasklet init occurs always when generating a tasklet
00030 #define MBED_CLIENT_TIMER_EVENT 10
00031 
00032 #ifdef MBED_CONF_MBED_CLIENT_EVENT_LOOP_SIZE
00033 #define MBED_CLIENT_EVENT_LOOP_SIZE MBED_CONF_MBED_CLIENT_EVENT_LOOP_SIZE
00034 #else
00035 #define MBED_CLIENT_EVENT_LOOP_SIZE 1024
00036 #endif
00037 
00038 int8_t M2MTimerPimpl::_tasklet_id = -1;
00039 
00040 int8_t M2MTimerPimpl::_next_timer_id = 1;
00041 
00042 static m2m::Vector<M2MTimerPimpl*> timer_impl_list;
00043 
00044 extern "C" void tasklet_func(arm_event_s *event)
00045 {
00046     // skip the init event as there will be a timer event after
00047     if (event->event_type == MBED_CLIENT_TIMER_EVENT) {
00048         bool timer_found = false;
00049         eventOS_scheduler_mutex_wait();
00050         int timer_count = timer_impl_list.size();
00051         for (int index = 0; index < timer_count; index++) {
00052             M2MTimerPimpl* timer = timer_impl_list[index];
00053             if (timer->get_timer_id() == event->event_id) {
00054                 eventOS_scheduler_mutex_release();
00055                 timer_found = true;
00056                 if (timer->get_still_left_time() > 0) {
00057                     timer->start_still_left_timer();
00058                 }else {
00059                     timer->timer_expired();
00060                 }
00061                 break;
00062             }
00063         }
00064         if(!timer_found) {
00065             eventOS_scheduler_mutex_release();
00066         }
00067     }
00068 }
00069 
00070 M2MTimerPimpl::M2MTimerPimpl(M2MTimerObserver& observer)
00071 : _observer(observer),
00072   _single_shot(true),
00073   _interval(0),
00074   _type(M2MTimerObserver::Notdefined),
00075   _intermediate_interval(0),
00076   _total_interval(0),
00077   _still_left(0),
00078   _status(0),
00079   _dtls_type(false)
00080 {
00081     ns_hal_init(NULL, MBED_CLIENT_EVENT_LOOP_SIZE, NULL, NULL);
00082     eventOS_scheduler_mutex_wait();
00083     if (_tasklet_id < 0) {
00084         _tasklet_id = eventOS_event_handler_create(tasklet_func, MBED_CLIENT_TIMER_TASKLET_INIT_EVENT);
00085         assert(_tasklet_id >= 0);
00086     }
00087 
00088     // XXX: this wraps over quite soon
00089     _timer_id = M2MTimerPimpl::_next_timer_id++;
00090     timer_impl_list.push_back(this);
00091     eventOS_scheduler_mutex_release();
00092 }
00093 
00094 M2MTimerPimpl::~M2MTimerPimpl()
00095 {
00096     // cancel the timer request, if any is pending
00097     cancel();
00098 
00099     // there is no turning back, event os does not have eventOS_event_handler_delete() or similar,
00100     // so the tasklet is lost forever. Same goes with timer_impl_list, which leaks now memory.
00101 
00102     // remove the timer from object list
00103     eventOS_scheduler_mutex_wait();
00104     int timer_count = timer_impl_list.size();
00105     for (int index = 0; index < timer_count; index++) {
00106         const M2MTimerPimpl* timer = timer_impl_list[index];
00107         if (timer->get_timer_id() == _timer_id) {
00108             timer_impl_list.erase(index);
00109             break;
00110         }
00111     }
00112     eventOS_scheduler_mutex_release();
00113 }
00114 
00115 void M2MTimerPimpl::start_timer( uint64_t interval,
00116                                  M2MTimerObserver::Type type,
00117                                  bool single_shot)
00118 {
00119     _dtls_type = false;
00120     _intermediate_interval = 0;
00121     _total_interval = 0;
00122     _status = 0;
00123     _single_shot = single_shot;
00124     _interval = interval;
00125     _type = type;
00126     _still_left = 0;
00127     start();
00128 }
00129 
00130 void M2MTimerPimpl::start_dtls_timer(uint64_t intermediate_interval, uint64_t total_interval, M2MTimerObserver::Type type)
00131 {
00132     _dtls_type = true;
00133     _intermediate_interval = intermediate_interval;
00134     _total_interval = total_interval;
00135     _interval = _intermediate_interval;
00136     _status = 0;
00137     _single_shot = false;
00138     _type = type;
00139     start();
00140 }
00141 
00142 void M2MTimerPimpl::start()
00143 {
00144     int status;
00145     if(_interval > INT32_MAX) {
00146         _still_left = _interval - INT32_MAX;
00147         status = eventOS_event_timer_request(_timer_id, MBED_CLIENT_TIMER_EVENT,
00148                                             M2MTimerPimpl::_tasklet_id,
00149                                             INT32_MAX);
00150     }
00151     else {
00152         status = eventOS_event_timer_request(_timer_id, MBED_CLIENT_TIMER_EVENT,
00153                                             M2MTimerPimpl::_tasklet_id,
00154                                             _interval);
00155     }
00156     assert(status == 0);
00157 }
00158 
00159 void M2MTimerPimpl::cancel()
00160 {
00161     eventOS_event_timer_cancel(_timer_id, M2MTimerPimpl::_tasklet_id);
00162 }
00163 
00164 void M2MTimerPimpl::stop_timer()
00165 {
00166     _interval = 0;
00167     _single_shot = true;
00168     _still_left = 0;
00169     cancel();
00170 }
00171 
00172 void M2MTimerPimpl::timer_expired()
00173 {
00174     _status++;
00175     _observer.timer_expired(_type);
00176 
00177     if ((!_dtls_type) && (!_single_shot)) {
00178         // start next round of periodic timer
00179         start();
00180     } else if ((_dtls_type) && (!is_total_interval_passed())) {
00181         // if only the intermediate time has passed, we need still wait up to total time
00182         _interval = _total_interval - _intermediate_interval;
00183         start();
00184     }
00185 }
00186 
00187 bool M2MTimerPimpl::is_intermediate_interval_passed()
00188 {
00189     if (_status > 0) {
00190         return true;
00191     }
00192     return false;
00193 }
00194 
00195 bool M2MTimerPimpl::is_total_interval_passed()
00196 {
00197     if (_status > 1) {
00198         return true;
00199     }
00200     return false;
00201 }
00202 
00203 uint64_t M2MTimerPimpl::get_still_left_time() const
00204 {
00205    return _still_left;
00206 }
00207 
00208 void M2MTimerPimpl::start_still_left_timer()
00209 {
00210     if (_still_left > 0) {
00211         int status;
00212         if( _still_left > INT32_MAX) {
00213             _still_left = _still_left - INT32_MAX;
00214             status = eventOS_event_timer_request(_timer_id, MBED_CLIENT_TIMER_EVENT,
00215                                                 M2MTimerPimpl::_tasklet_id,
00216                                                 INT32_MAX);
00217         }
00218         else {
00219             status = eventOS_event_timer_request(_timer_id, MBED_CLIENT_TIMER_EVENT,
00220                                                 M2MTimerPimpl::_tasklet_id,
00221                                                 _still_left);
00222             _still_left = 0;
00223         }
00224         assert(status == 0);
00225     } else {
00226         _observer.timer_expired(_type);
00227         if(!_single_shot) {
00228             start_timer(_interval, _type, _single_shot);
00229         }
00230     }
00231 }