1

Committer:
valeyev
Date:
Tue Mar 13 07:17:50 2018 +0000
Revision:
0:e056ac8fecf8
looking for...

Who changed what in which revision?

UserRevisionLine numberNew contents of line
valeyev 0:e056ac8fecf8 1 /* mbed Microcontroller Library
valeyev 0:e056ac8fecf8 2 * Copyright (c) 2017 ARM Limited
valeyev 0:e056ac8fecf8 3 *
valeyev 0:e056ac8fecf8 4 * Licensed under the Apache License, Version 2.0 (the "License");
valeyev 0:e056ac8fecf8 5 * you may not use this file except in compliance with the License.
valeyev 0:e056ac8fecf8 6 * You may obtain a copy of the License at
valeyev 0:e056ac8fecf8 7 *
valeyev 0:e056ac8fecf8 8 * http://www.apache.org/licenses/LICENSE-2.0
valeyev 0:e056ac8fecf8 9 *
valeyev 0:e056ac8fecf8 10 * Unless required by applicable law or agreed to in writing, software
valeyev 0:e056ac8fecf8 11 * distributed under the License is distributed on an "AS IS" BASIS,
valeyev 0:e056ac8fecf8 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
valeyev 0:e056ac8fecf8 13 * See the License for the specific language governing permissions and
valeyev 0:e056ac8fecf8 14 * limitations under the License.
valeyev 0:e056ac8fecf8 15 */
valeyev 0:e056ac8fecf8 16
valeyev 0:e056ac8fecf8 17 #include "mbed_assert.h"
valeyev 0:e056ac8fecf8 18 #include "mbed_power_mgmt.h"
valeyev 0:e056ac8fecf8 19 #include "mbed_critical.h"
valeyev 0:e056ac8fecf8 20 #include "sleep_api.h"
valeyev 0:e056ac8fecf8 21 #include "mbed_error.h"
valeyev 0:e056ac8fecf8 22 #include "mbed_debug.h"
valeyev 0:e056ac8fecf8 23 #include <limits.h>
valeyev 0:e056ac8fecf8 24 #include <stdio.h>
valeyev 0:e056ac8fecf8 25
valeyev 0:e056ac8fecf8 26 #if DEVICE_SLEEP
valeyev 0:e056ac8fecf8 27
valeyev 0:e056ac8fecf8 28 // deep sleep locking counter. A target is allowed to deep sleep if counter == 0
valeyev 0:e056ac8fecf8 29 static uint16_t deep_sleep_lock = 0U;
valeyev 0:e056ac8fecf8 30
valeyev 0:e056ac8fecf8 31 #ifdef MBED_SLEEP_TRACING_ENABLED
valeyev 0:e056ac8fecf8 32
valeyev 0:e056ac8fecf8 33 // Length of the identifier extracted from the driver name to store for logging.
valeyev 0:e056ac8fecf8 34 #define IDENTIFIER_WIDTH 15
valeyev 0:e056ac8fecf8 35 // Number of drivers that can be stored in the structure
valeyev 0:e056ac8fecf8 36 #define STATISTIC_COUNT 10
valeyev 0:e056ac8fecf8 37
valeyev 0:e056ac8fecf8 38 typedef struct sleep_statistic {
valeyev 0:e056ac8fecf8 39 char identifier[IDENTIFIER_WIDTH];
valeyev 0:e056ac8fecf8 40 uint8_t count;
valeyev 0:e056ac8fecf8 41 } sleep_statistic_t;
valeyev 0:e056ac8fecf8 42
valeyev 0:e056ac8fecf8 43 static sleep_statistic_t sleep_stats[STATISTIC_COUNT];
valeyev 0:e056ac8fecf8 44
valeyev 0:e056ac8fecf8 45 static const char* strip_path(const char* const filename)
valeyev 0:e056ac8fecf8 46 {
valeyev 0:e056ac8fecf8 47 char *output = strrchr(filename, '/');
valeyev 0:e056ac8fecf8 48
valeyev 0:e056ac8fecf8 49 if (output != NULL) {
valeyev 0:e056ac8fecf8 50 return output + 1;
valeyev 0:e056ac8fecf8 51 }
valeyev 0:e056ac8fecf8 52
valeyev 0:e056ac8fecf8 53 output = strrchr(filename, '\\');
valeyev 0:e056ac8fecf8 54
valeyev 0:e056ac8fecf8 55 if (output != NULL) {
valeyev 0:e056ac8fecf8 56 return output + 1;
valeyev 0:e056ac8fecf8 57 }
valeyev 0:e056ac8fecf8 58
valeyev 0:e056ac8fecf8 59 return filename;
valeyev 0:e056ac8fecf8 60 }
valeyev 0:e056ac8fecf8 61
valeyev 0:e056ac8fecf8 62 static sleep_statistic_t* sleep_tracker_find(const char *const filename)
valeyev 0:e056ac8fecf8 63 {
valeyev 0:e056ac8fecf8 64 char temp[IDENTIFIER_WIDTH];
valeyev 0:e056ac8fecf8 65 strncpy(temp, filename, IDENTIFIER_WIDTH);
valeyev 0:e056ac8fecf8 66 temp[IDENTIFIER_WIDTH - 1] = '\0';
valeyev 0:e056ac8fecf8 67
valeyev 0:e056ac8fecf8 68 // Search for the a driver matching the current name and return it's index
valeyev 0:e056ac8fecf8 69 for (int i = 0; i < STATISTIC_COUNT; ++i) {
valeyev 0:e056ac8fecf8 70 if (strcmp(sleep_stats[i].identifier, temp) == 0) {
valeyev 0:e056ac8fecf8 71 return &sleep_stats[i];
valeyev 0:e056ac8fecf8 72 }
valeyev 0:e056ac8fecf8 73 }
valeyev 0:e056ac8fecf8 74
valeyev 0:e056ac8fecf8 75 return NULL;
valeyev 0:e056ac8fecf8 76 }
valeyev 0:e056ac8fecf8 77
valeyev 0:e056ac8fecf8 78 static sleep_statistic_t* sleep_tracker_add(const char* const filename)
valeyev 0:e056ac8fecf8 79 {
valeyev 0:e056ac8fecf8 80 char temp[IDENTIFIER_WIDTH];
valeyev 0:e056ac8fecf8 81 strncpy(temp, filename, IDENTIFIER_WIDTH);
valeyev 0:e056ac8fecf8 82 temp[IDENTIFIER_WIDTH - 1] = '\0';
valeyev 0:e056ac8fecf8 83
valeyev 0:e056ac8fecf8 84 for (int i = 0; i < STATISTIC_COUNT; ++i) {
valeyev 0:e056ac8fecf8 85 if (sleep_stats[i].identifier[0] == '\0') {
valeyev 0:e056ac8fecf8 86 core_util_critical_section_enter();
valeyev 0:e056ac8fecf8 87 strncpy(sleep_stats[i].identifier, temp, sizeof(temp));
valeyev 0:e056ac8fecf8 88 core_util_critical_section_exit();
valeyev 0:e056ac8fecf8 89
valeyev 0:e056ac8fecf8 90 return &sleep_stats[i];
valeyev 0:e056ac8fecf8 91 }
valeyev 0:e056ac8fecf8 92 }
valeyev 0:e056ac8fecf8 93
valeyev 0:e056ac8fecf8 94 debug("No free indexes left to use in mbed sleep tracker.\r\n");
valeyev 0:e056ac8fecf8 95
valeyev 0:e056ac8fecf8 96 return NULL;
valeyev 0:e056ac8fecf8 97 }
valeyev 0:e056ac8fecf8 98
valeyev 0:e056ac8fecf8 99 static void sleep_tracker_print_stats(void)
valeyev 0:e056ac8fecf8 100 {
valeyev 0:e056ac8fecf8 101 debug("Sleep locks held:\r\n");
valeyev 0:e056ac8fecf8 102 for (int i = 0; i < STATISTIC_COUNT; ++i) {
valeyev 0:e056ac8fecf8 103 if (sleep_stats[i].count == 0) {
valeyev 0:e056ac8fecf8 104 continue;
valeyev 0:e056ac8fecf8 105 }
valeyev 0:e056ac8fecf8 106
valeyev 0:e056ac8fecf8 107 if (sleep_stats[i].identifier[0] == '\0') {
valeyev 0:e056ac8fecf8 108 return;
valeyev 0:e056ac8fecf8 109 }
valeyev 0:e056ac8fecf8 110
valeyev 0:e056ac8fecf8 111 debug("[id: %s, count: %u]\r\n", sleep_stats[i].identifier,
valeyev 0:e056ac8fecf8 112 sleep_stats[i].count);
valeyev 0:e056ac8fecf8 113 }
valeyev 0:e056ac8fecf8 114 }
valeyev 0:e056ac8fecf8 115
valeyev 0:e056ac8fecf8 116 void sleep_tracker_lock(const char* const filename, int line)
valeyev 0:e056ac8fecf8 117 {
valeyev 0:e056ac8fecf8 118 const char* const stripped_path = strip_path(filename);
valeyev 0:e056ac8fecf8 119
valeyev 0:e056ac8fecf8 120 sleep_statistic_t* stat = sleep_tracker_find(stripped_path);
valeyev 0:e056ac8fecf8 121
valeyev 0:e056ac8fecf8 122 // Entry for this driver does not exist, create one.
valeyev 0:e056ac8fecf8 123 if (stat == NULL) {
valeyev 0:e056ac8fecf8 124 stat = sleep_tracker_add(stripped_path);
valeyev 0:e056ac8fecf8 125 }
valeyev 0:e056ac8fecf8 126
valeyev 0:e056ac8fecf8 127 core_util_atomic_incr_u8(&stat->count, 1);
valeyev 0:e056ac8fecf8 128
valeyev 0:e056ac8fecf8 129 debug("LOCK: %s, ln: %i, lock count: %u\r\n", stripped_path, line, deep_sleep_lock);
valeyev 0:e056ac8fecf8 130 }
valeyev 0:e056ac8fecf8 131
valeyev 0:e056ac8fecf8 132 void sleep_tracker_unlock(const char* const filename, int line)
valeyev 0:e056ac8fecf8 133 {
valeyev 0:e056ac8fecf8 134 const char* const stripped_path = strip_path(filename);
valeyev 0:e056ac8fecf8 135 sleep_statistic_t* stat = sleep_tracker_find(stripped_path);
valeyev 0:e056ac8fecf8 136
valeyev 0:e056ac8fecf8 137 // Entry for this driver does not exist, something went wrong.
valeyev 0:e056ac8fecf8 138 if (stat == NULL) {
valeyev 0:e056ac8fecf8 139 debug("Unlocking sleep for driver that was not previously locked: %s, ln: %i\r\n", stripped_path, line);
valeyev 0:e056ac8fecf8 140 return;
valeyev 0:e056ac8fecf8 141 }
valeyev 0:e056ac8fecf8 142
valeyev 0:e056ac8fecf8 143 core_util_atomic_decr_u8(&stat->count, 1);
valeyev 0:e056ac8fecf8 144
valeyev 0:e056ac8fecf8 145 debug("UNLOCK: %s, ln: %i, lock count: %u\r\n", stripped_path, line, deep_sleep_lock);
valeyev 0:e056ac8fecf8 146 }
valeyev 0:e056ac8fecf8 147
valeyev 0:e056ac8fecf8 148 #endif // MBED_SLEEP_TRACING_ENABLED
valeyev 0:e056ac8fecf8 149
valeyev 0:e056ac8fecf8 150 void sleep_manager_lock_deep_sleep_internal(void)
valeyev 0:e056ac8fecf8 151 {
valeyev 0:e056ac8fecf8 152 core_util_critical_section_enter();
valeyev 0:e056ac8fecf8 153 if (deep_sleep_lock == USHRT_MAX) {
valeyev 0:e056ac8fecf8 154 core_util_critical_section_exit();
valeyev 0:e056ac8fecf8 155 error("Deep sleep lock would overflow (> USHRT_MAX)");
valeyev 0:e056ac8fecf8 156 }
valeyev 0:e056ac8fecf8 157 core_util_atomic_incr_u16(&deep_sleep_lock, 1);
valeyev 0:e056ac8fecf8 158 core_util_critical_section_exit();
valeyev 0:e056ac8fecf8 159 }
valeyev 0:e056ac8fecf8 160
valeyev 0:e056ac8fecf8 161 void sleep_manager_unlock_deep_sleep_internal(void)
valeyev 0:e056ac8fecf8 162 {
valeyev 0:e056ac8fecf8 163 core_util_critical_section_enter();
valeyev 0:e056ac8fecf8 164 if (deep_sleep_lock == 0) {
valeyev 0:e056ac8fecf8 165 core_util_critical_section_exit();
valeyev 0:e056ac8fecf8 166 error("Deep sleep lock would underflow (< 0)");
valeyev 0:e056ac8fecf8 167 }
valeyev 0:e056ac8fecf8 168 core_util_atomic_decr_u16(&deep_sleep_lock, 1);
valeyev 0:e056ac8fecf8 169 core_util_critical_section_exit();
valeyev 0:e056ac8fecf8 170 }
valeyev 0:e056ac8fecf8 171
valeyev 0:e056ac8fecf8 172 bool sleep_manager_can_deep_sleep(void)
valeyev 0:e056ac8fecf8 173 {
valeyev 0:e056ac8fecf8 174 return deep_sleep_lock == 0 ? true : false;
valeyev 0:e056ac8fecf8 175 }
valeyev 0:e056ac8fecf8 176
valeyev 0:e056ac8fecf8 177 void sleep_manager_sleep_auto(void)
valeyev 0:e056ac8fecf8 178 {
valeyev 0:e056ac8fecf8 179 #ifdef MBED_SLEEP_TRACING_ENABLED
valeyev 0:e056ac8fecf8 180 sleep_tracker_print_stats();
valeyev 0:e056ac8fecf8 181 #endif
valeyev 0:e056ac8fecf8 182 core_util_critical_section_enter();
valeyev 0:e056ac8fecf8 183 // debug profile should keep debuggers attached, no deep sleep allowed
valeyev 0:e056ac8fecf8 184 #ifdef MBED_DEBUG
valeyev 0:e056ac8fecf8 185 hal_sleep();
valeyev 0:e056ac8fecf8 186 #else
valeyev 0:e056ac8fecf8 187 if (sleep_manager_can_deep_sleep()) {
valeyev 0:e056ac8fecf8 188 hal_deepsleep();
valeyev 0:e056ac8fecf8 189 } else {
valeyev 0:e056ac8fecf8 190 hal_sleep();
valeyev 0:e056ac8fecf8 191 }
valeyev 0:e056ac8fecf8 192 #endif
valeyev 0:e056ac8fecf8 193 core_util_critical_section_exit();
valeyev 0:e056ac8fecf8 194 }
valeyev 0:e056ac8fecf8 195
valeyev 0:e056ac8fecf8 196 #else
valeyev 0:e056ac8fecf8 197
valeyev 0:e056ac8fecf8 198 // locking is valid only if DEVICE_SLEEP is defined
valeyev 0:e056ac8fecf8 199 // we provide empty implementation
valeyev 0:e056ac8fecf8 200
valeyev 0:e056ac8fecf8 201 void sleep_manager_lock_deep_sleep_internal(void)
valeyev 0:e056ac8fecf8 202 {
valeyev 0:e056ac8fecf8 203
valeyev 0:e056ac8fecf8 204 }
valeyev 0:e056ac8fecf8 205
valeyev 0:e056ac8fecf8 206 void sleep_manager_unlock_deep_sleep_internal(void)
valeyev 0:e056ac8fecf8 207 {
valeyev 0:e056ac8fecf8 208
valeyev 0:e056ac8fecf8 209 }
valeyev 0:e056ac8fecf8 210
valeyev 0:e056ac8fecf8 211 bool sleep_manager_can_deep_sleep(void)
valeyev 0:e056ac8fecf8 212 {
valeyev 0:e056ac8fecf8 213 // no sleep implemented
valeyev 0:e056ac8fecf8 214 return false;
valeyev 0:e056ac8fecf8 215 }
valeyev 0:e056ac8fecf8 216
valeyev 0:e056ac8fecf8 217 #endif