Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_sleep_manager.c Source File

mbed_sleep_manager.c

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may 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,
00012  * WITHOUT 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_assert.h"
00018 #include "mbed_power_mgmt.h"
00019 #include "mbed_critical.h"
00020 #include "sleep_api.h"
00021 #include "mbed_error.h"
00022 #include "mbed_debug.h"
00023 #include "mbed_stats.h"
00024 #include "lp_ticker_api.h"
00025 #include <limits.h>
00026 #include <stdio.h>
00027 #include "mbed_stats.h"
00028 
00029 
00030 #if DEVICE_SLEEP
00031 
00032 // deep sleep locking counter. A target is allowed to deep sleep if counter == 0
00033 static uint16_t deep_sleep_lock = 0U;
00034 static us_timestamp_t sleep_time = 0;
00035 static us_timestamp_t deep_sleep_time = 0;
00036 
00037 #if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LPTICKER)
00038 static ticker_data_t *sleep_ticker = NULL;
00039 #endif
00040 
00041 static inline us_timestamp_t read_us(void)
00042 {
00043 #if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LPTICKER)
00044     if (NULL == sleep_ticker) {
00045         sleep_ticker = (ticker_data_t *)get_lp_ticker_data();
00046     }
00047     return ticker_read_us(sleep_ticker);
00048 #else
00049     return 0;
00050 #endif
00051 }
00052 
00053 us_timestamp_t mbed_time_idle(void)
00054 {
00055     return (sleep_time + deep_sleep_time);
00056 }
00057 
00058 us_timestamp_t mbed_uptime(void)
00059 {
00060     return read_us();
00061 }
00062 
00063 us_timestamp_t mbed_time_sleep(void)
00064 {
00065     return sleep_time;
00066 }
00067 
00068 us_timestamp_t mbed_time_deepsleep(void)
00069 {
00070     return deep_sleep_time;
00071 }
00072 
00073 #ifdef MBED_SLEEP_TRACING_ENABLED
00074 
00075 // Number of drivers that can be stored in the structure
00076 #define STATISTIC_COUNT  10
00077 
00078 typedef struct sleep_statistic {
00079     const char *identifier;
00080     uint8_t count;
00081 } sleep_statistic_t;
00082 
00083 static sleep_statistic_t sleep_stats[STATISTIC_COUNT];
00084 
00085 static sleep_statistic_t* sleep_tracker_find(const char *const filename)
00086 {
00087     for (int i = 0; i < STATISTIC_COUNT; ++i) {
00088         if (sleep_stats[i].identifier == filename) {
00089             return &sleep_stats[i];
00090         }
00091     }
00092 
00093     return NULL;
00094 }
00095 
00096 static sleep_statistic_t* sleep_tracker_add(const char* const filename)
00097 {
00098     for (int i = 0; i < STATISTIC_COUNT; ++i) {
00099         if (sleep_stats[i].identifier == NULL) {
00100             sleep_stats[i].identifier = filename;
00101 
00102             return &sleep_stats[i];
00103         }
00104     }
00105 
00106     debug("No free indexes left to use in mbed sleep tracker.\r\n");
00107 
00108     return NULL;
00109 }
00110 
00111 static void sleep_tracker_print_stats(void)
00112 {
00113     debug("Sleep locks held:\r\n");
00114     for (int i = 0; i < STATISTIC_COUNT; ++i) {
00115         if (sleep_stats[i].count == 0) {
00116             continue;
00117         }
00118 
00119         if (sleep_stats[i].identifier == NULL) {
00120             return;
00121         }
00122 
00123         debug("[id: %s, count: %u]\r\n", sleep_stats[i].identifier,
00124                                          sleep_stats[i].count);
00125     }
00126 }
00127 
00128 void sleep_tracker_lock(const char *const filename, int line)
00129 {
00130     sleep_statistic_t *stat = sleep_tracker_find(filename);
00131 
00132     // Entry for this driver does not exist, create one.
00133     if (stat == NULL) {
00134         stat = sleep_tracker_add(filename);
00135     }
00136 
00137     core_util_atomic_incr_u8(&stat->count, 1);
00138 
00139     debug("LOCK: %s, ln: %i, lock count: %u\r\n", filename, line, deep_sleep_lock);
00140 }
00141 
00142 void sleep_tracker_unlock(const char* const filename, int line)
00143 {
00144     sleep_statistic_t *stat = sleep_tracker_find(filename);
00145 
00146     // Entry for this driver does not exist, something went wrong.
00147     if (stat == NULL) {
00148         debug("Unlocking sleep for driver that was not previously locked: %s, ln: %i\r\n", filename, line);
00149         return;
00150     }
00151 
00152     core_util_atomic_decr_u8(&stat->count, 1);
00153 
00154     debug("UNLOCK: %s, ln: %i, lock count: %u\r\n", filename, line, deep_sleep_lock);
00155 }
00156 
00157 #endif // MBED_SLEEP_TRACING_ENABLED
00158 
00159 void sleep_manager_lock_deep_sleep_internal(void)
00160 {
00161     core_util_critical_section_enter();
00162     if (deep_sleep_lock == USHRT_MAX) {
00163         core_util_critical_section_exit();
00164         MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_OVERFLOW), "DeepSleepLock overflow (> USHRT_MAX)", deep_sleep_lock);
00165     }
00166     core_util_atomic_incr_u16(&deep_sleep_lock, 1);
00167     core_util_critical_section_exit();
00168 }
00169 
00170 void sleep_manager_unlock_deep_sleep_internal(void)
00171 {
00172     core_util_critical_section_enter();
00173     if (deep_sleep_lock == 0) {
00174         core_util_critical_section_exit();
00175         MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_UNDERFLOW), "DeepSleepLock underflow (< 0)", deep_sleep_lock);
00176     }
00177     core_util_atomic_decr_u16(&deep_sleep_lock, 1);
00178     core_util_critical_section_exit();
00179 }
00180 
00181 bool sleep_manager_can_deep_sleep(void)
00182 {
00183     return deep_sleep_lock == 0 ? true : false;
00184 }
00185 
00186 void sleep_manager_sleep_auto(void)
00187 {
00188 #ifdef MBED_SLEEP_TRACING_ENABLED
00189     sleep_tracker_print_stats();
00190 #endif
00191     core_util_critical_section_enter();
00192     us_timestamp_t start = read_us();
00193     bool deep = false;
00194 
00195 // debug profile should keep debuggers attached, no deep sleep allowed
00196 #ifdef MBED_DEBUG
00197     hal_sleep();
00198 #else
00199     if (sleep_manager_can_deep_sleep()) {
00200         deep = true;
00201         hal_deepsleep();
00202     } else {
00203         hal_sleep();
00204     }
00205 #endif
00206 
00207     us_timestamp_t end = read_us();
00208     if (true == deep) {
00209         deep_sleep_time += end - start;
00210     } else {
00211         sleep_time += end - start;
00212     }
00213     core_util_critical_section_exit();
00214 }
00215 
00216 #else
00217 
00218 // locking is valid only if DEVICE_SLEEP is defined
00219 // we provide empty implementation
00220 
00221 void sleep_manager_lock_deep_sleep_internal(void)
00222 {
00223 
00224 }
00225 
00226 void sleep_manager_unlock_deep_sleep_internal(void)
00227 {
00228 
00229 }
00230 
00231 bool sleep_manager_can_deep_sleep(void)
00232 {
00233     // no sleep implemented
00234     return false;
00235 }
00236 
00237 #endif