BA / Mbed OS BaBoRo1
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 <limits.h>
00024 #include <stdio.h>
00025 
00026 #if DEVICE_SLEEP
00027 
00028 // deep sleep locking counter. A target is allowed to deep sleep if counter == 0
00029 static uint16_t deep_sleep_lock = 0U;
00030 
00031 #ifdef MBED_SLEEP_TRACING_ENABLED
00032 
00033 // Number of drivers that can be stored in the structure
00034 #define STATISTIC_COUNT  10
00035 
00036 typedef struct sleep_statistic {
00037     const char* identifier;
00038     uint8_t count;
00039 } sleep_statistic_t;
00040 
00041 static sleep_statistic_t sleep_stats[STATISTIC_COUNT];
00042 
00043 static sleep_statistic_t* sleep_tracker_find(const char *const filename)
00044 {
00045     for (int i = 0; i < STATISTIC_COUNT; ++i) {
00046         if (sleep_stats[i].identifier == filename) {
00047             return &sleep_stats[i];
00048         }
00049     }
00050 
00051     return NULL;
00052 }
00053 
00054 static sleep_statistic_t* sleep_tracker_add(const char* const filename)
00055 {
00056     for (int i = 0; i < STATISTIC_COUNT; ++i) {
00057         if (sleep_stats[i].identifier == NULL) {
00058             sleep_stats[i].identifier = filename;
00059 
00060             return &sleep_stats[i];
00061         }
00062     }
00063 
00064     debug("No free indexes left to use in mbed sleep tracker.\r\n");
00065 
00066     return NULL;
00067 }
00068 
00069 static void sleep_tracker_print_stats(void)
00070 {
00071     debug("Sleep locks held:\r\n");
00072     for (int i = 0; i < STATISTIC_COUNT; ++i) {
00073         if (sleep_stats[i].count == 0) {
00074             continue;
00075         }
00076 
00077         if (sleep_stats[i].identifier == NULL) {
00078             return;
00079         }
00080 
00081         debug("[id: %s, count: %u]\r\n", sleep_stats[i].identifier,
00082                                          sleep_stats[i].count);
00083     }
00084 }
00085 
00086 void sleep_tracker_lock(const char* const filename, int line)
00087 {
00088     sleep_statistic_t *stat = sleep_tracker_find(filename);
00089 
00090     // Entry for this driver does not exist, create one.
00091     if (stat == NULL) {
00092         stat = sleep_tracker_add(filename);
00093     }
00094 
00095     core_util_atomic_incr_u8(&stat->count, 1);
00096 
00097     debug("LOCK: %s, ln: %i, lock count: %u\r\n", filename, line, deep_sleep_lock);
00098 }
00099 
00100 void sleep_tracker_unlock(const char* const filename, int line)
00101 {
00102     sleep_statistic_t *stat = sleep_tracker_find(filename);
00103 
00104     // Entry for this driver does not exist, something went wrong.
00105     if (stat == NULL) {
00106         debug("Unlocking sleep for driver that was not previously locked: %s, ln: %i\r\n", filename, line);
00107         return;
00108     }
00109 
00110     core_util_atomic_decr_u8(&stat->count, 1);
00111 
00112     debug("UNLOCK: %s, ln: %i, lock count: %u\r\n", filename, line, deep_sleep_lock);
00113 }
00114 
00115 #endif // MBED_SLEEP_TRACING_ENABLED
00116 
00117 void sleep_manager_lock_deep_sleep_internal(void)
00118 {
00119     core_util_critical_section_enter();
00120     if (deep_sleep_lock == USHRT_MAX) {
00121         core_util_critical_section_exit();
00122         error("Deep sleep lock would overflow (> USHRT_MAX)");
00123     }
00124     core_util_atomic_incr_u16(&deep_sleep_lock, 1);
00125     core_util_critical_section_exit();
00126 }
00127 
00128 void sleep_manager_unlock_deep_sleep_internal(void)
00129 {
00130     core_util_critical_section_enter();
00131     if (deep_sleep_lock == 0) {
00132         core_util_critical_section_exit();
00133         error("Deep sleep lock would underflow (< 0)");
00134     }
00135     core_util_atomic_decr_u16(&deep_sleep_lock, 1);
00136     core_util_critical_section_exit();
00137 }
00138 
00139 bool sleep_manager_can_deep_sleep(void)
00140 {
00141     return deep_sleep_lock == 0 ? true : false;
00142 }
00143 
00144 void sleep_manager_sleep_auto(void)
00145 {
00146 #ifdef MBED_SLEEP_TRACING_ENABLED
00147     sleep_tracker_print_stats();
00148 #endif
00149     core_util_critical_section_enter();
00150 // debug profile should keep debuggers attached, no deep sleep allowed
00151 #ifdef MBED_DEBUG
00152     hal_sleep();
00153 #else
00154     if (sleep_manager_can_deep_sleep()) {
00155         hal_deepsleep();
00156     } else {
00157         hal_sleep();
00158     }
00159 #endif
00160     core_util_critical_section_exit();
00161 }
00162 
00163 #else
00164 
00165 // locking is valid only if DEVICE_SLEEP is defined
00166 // we provide empty implementation
00167 
00168 void sleep_manager_lock_deep_sleep_internal(void)
00169 {
00170 
00171 }
00172 
00173 void sleep_manager_unlock_deep_sleep_internal(void)
00174 {
00175 
00176 }
00177 
00178 bool sleep_manager_can_deep_sleep(void)
00179 {
00180     // no sleep implemented
00181     return false;
00182 }
00183 
00184 #endif