Denislam Valeev / Mbed OS Nucleo_rtos_basic
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 // Length of the identifier extracted from the driver name to store for logging.
00034 #define IDENTIFIER_WIDTH 15
00035 // Number of drivers that can be stored in the structure
00036 #define STATISTIC_COUNT  10
00037 
00038 typedef struct sleep_statistic {
00039     char identifier[IDENTIFIER_WIDTH];
00040     uint8_t count;
00041 } sleep_statistic_t;
00042 
00043 static sleep_statistic_t sleep_stats[STATISTIC_COUNT];
00044 
00045 static const char* strip_path(const char* const filename)
00046 {
00047     char *output = strrchr(filename, '/');
00048 
00049     if (output != NULL) {
00050         return output + 1;
00051     }
00052 
00053     output = strrchr(filename, '\\');
00054 
00055     if (output != NULL) {
00056         return output + 1;
00057     }
00058 
00059     return filename;
00060 }
00061 
00062 static sleep_statistic_t* sleep_tracker_find(const char *const filename)
00063 {
00064     char temp[IDENTIFIER_WIDTH];
00065     strncpy(temp, filename, IDENTIFIER_WIDTH);
00066     temp[IDENTIFIER_WIDTH - 1] = '\0';
00067 
00068     // Search for the a driver matching the current name and return it's index
00069     for (int i = 0; i < STATISTIC_COUNT; ++i) {
00070         if (strcmp(sleep_stats[i].identifier, temp) == 0) {
00071             return &sleep_stats[i];
00072         }
00073     }
00074 
00075     return NULL;
00076 }
00077 
00078 static sleep_statistic_t* sleep_tracker_add(const char* const filename)
00079 {
00080     char temp[IDENTIFIER_WIDTH];
00081     strncpy(temp, filename, IDENTIFIER_WIDTH);
00082     temp[IDENTIFIER_WIDTH - 1] = '\0';
00083 
00084     for (int i = 0; i < STATISTIC_COUNT; ++i) {
00085         if (sleep_stats[i].identifier[0] == '\0') {
00086             core_util_critical_section_enter();
00087             strncpy(sleep_stats[i].identifier, temp, sizeof(temp));
00088             core_util_critical_section_exit();
00089 
00090             return &sleep_stats[i];
00091         }
00092     }
00093 
00094     debug("No free indexes left to use in mbed sleep tracker.\r\n");
00095 
00096     return NULL;
00097 }
00098 
00099 static void sleep_tracker_print_stats(void)
00100 {
00101     debug("Sleep locks held:\r\n");
00102     for (int i = 0; i < STATISTIC_COUNT; ++i) {
00103         if (sleep_stats[i].count == 0) {
00104             continue;
00105         }
00106 
00107         if (sleep_stats[i].identifier[0] == '\0') {
00108             return;
00109         }
00110 
00111         debug("[id: %s, count: %u]\r\n", sleep_stats[i].identifier,
00112                                           sleep_stats[i].count);
00113     }
00114 }
00115 
00116 void sleep_tracker_lock(const char* const filename, int line)
00117 {
00118     const char* const stripped_path = strip_path(filename);
00119 
00120     sleep_statistic_t* stat = sleep_tracker_find(stripped_path);
00121 
00122     // Entry for this driver does not exist, create one.
00123     if (stat == NULL) {
00124         stat = sleep_tracker_add(stripped_path);
00125     }
00126 
00127     core_util_atomic_incr_u8(&stat->count, 1);
00128 
00129     debug("LOCK: %s, ln: %i, lock count: %u\r\n", stripped_path, line, deep_sleep_lock);
00130 }
00131 
00132 void sleep_tracker_unlock(const char* const filename, int line)
00133 {
00134     const char* const stripped_path = strip_path(filename);
00135     sleep_statistic_t* stat = sleep_tracker_find(stripped_path);
00136 
00137     // Entry for this driver does not exist, something went wrong.
00138     if (stat == NULL) {
00139         debug("Unlocking sleep for driver that was not previously locked: %s, ln: %i\r\n", stripped_path, line);
00140         return;
00141     }
00142 
00143     core_util_atomic_decr_u8(&stat->count, 1);
00144 
00145     debug("UNLOCK: %s, ln: %i, lock count: %u\r\n", stripped_path, line, deep_sleep_lock);
00146 }
00147 
00148 #endif // MBED_SLEEP_TRACING_ENABLED
00149 
00150 void sleep_manager_lock_deep_sleep_internal(void)
00151 {
00152     core_util_critical_section_enter();
00153     if (deep_sleep_lock == USHRT_MAX) {
00154         core_util_critical_section_exit();
00155         error("Deep sleep lock would overflow (> USHRT_MAX)");
00156     }
00157     core_util_atomic_incr_u16(&deep_sleep_lock, 1);
00158     core_util_critical_section_exit();
00159 }
00160 
00161 void sleep_manager_unlock_deep_sleep_internal(void)
00162 {
00163     core_util_critical_section_enter();
00164     if (deep_sleep_lock == 0) {
00165         core_util_critical_section_exit();
00166         error("Deep sleep lock would underflow (< 0)");
00167     }
00168     core_util_atomic_decr_u16(&deep_sleep_lock, 1);
00169     core_util_critical_section_exit();
00170 }
00171 
00172 bool sleep_manager_can_deep_sleep(void)
00173 {
00174     return deep_sleep_lock == 0 ? true : false;
00175 }
00176 
00177 void sleep_manager_sleep_auto(void)
00178 {
00179 #ifdef MBED_SLEEP_TRACING_ENABLED
00180     sleep_tracker_print_stats();
00181 #endif
00182     core_util_critical_section_enter();
00183 // debug profile should keep debuggers attached, no deep sleep allowed
00184 #ifdef MBED_DEBUG
00185     hal_sleep();
00186 #else
00187     if (sleep_manager_can_deep_sleep()) {
00188         hal_deepsleep();
00189     } else {
00190         hal_sleep();
00191     }
00192 #endif
00193     core_util_critical_section_exit();
00194 }
00195 
00196 #else
00197 
00198 // locking is valid only if DEVICE_SLEEP is defined
00199 // we provide empty implementation
00200 
00201 void sleep_manager_lock_deep_sleep_internal(void)
00202 {
00203 
00204 }
00205 
00206 void sleep_manager_unlock_deep_sleep_internal(void)
00207 {
00208 
00209 }
00210 
00211 bool sleep_manager_can_deep_sleep(void)
00212 {
00213     // no sleep implemented
00214     return false;
00215 }
00216 
00217 #endif