1 /* Console example — various system commands
2
3 This example code is in the Public Domain (or CC0 licensed, at your option.)
4
5 Unless required by applicable law or agreed to in writing, this
6 software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7 CONDITIONS OF ANY KIND, either express or implied.
8 */
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <unistd.h>
14 #include "esp_log.h"
15 #include "esp_console.h"
16 #include "esp_system.h"
17 #include "esp_sleep.h"
18 #include "esp_spi_flash.h"
19 #include "driver/rtc_io.h"
20 #include "driver/uart.h"
21 #include "argtable3/argtable3.h"
22 #include "freertos/FreeRTOS.h"
23 #include "freertos/task.h"
24 #include "cmd_system.h"
25 #include "sdkconfig.h"
26
27 #ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS
28 #define WITH_TASKS_INFO 1
29 #endif
30
31 static const char *TAG = "cmd_system";
32
33 static void register_free(void);
34 static void register_heap(void);
35 static void register_version(void);
36 static void register_restart(void);
37 static void register_deep_sleep(void);
38 static void register_light_sleep(void);
39 #if WITH_TASKS_INFO
40 static void register_tasks(void);
41 #endif
42
register_system_common(void)43 void register_system_common(void)
44 {
45 register_free();
46 register_heap();
47 register_version();
48 register_restart();
49 #if WITH_TASKS_INFO
50 register_tasks();
51 #endif
52 }
53
register_system_sleep(void)54 void register_system_sleep(void)
55 {
56 register_deep_sleep();
57 register_light_sleep();
58 }
59
register_system(void)60 void register_system(void)
61 {
62 register_system_common();
63 register_system_sleep();
64 }
65
66 /* 'version' command */
get_version(int argc,char ** argv)67 static int get_version(int argc, char **argv)
68 {
69 esp_chip_info_t info;
70 esp_chip_info(&info);
71 printf("IDF Version:%s\r\n", esp_get_idf_version());
72 printf("Chip info:\r\n");
73 printf("\tmodel:%s\r\n", info.model == CHIP_ESP32 ? "ESP32" : "Unknown");
74 printf("\tcores:%d\r\n", info.cores);
75 printf("\tfeature:%s%s%s%s%d%s\r\n",
76 info.features & CHIP_FEATURE_WIFI_BGN ? "/802.11bgn" : "",
77 info.features & CHIP_FEATURE_BLE ? "/BLE" : "",
78 info.features & CHIP_FEATURE_BT ? "/BT" : "",
79 info.features & CHIP_FEATURE_EMB_FLASH ? "/Embedded-Flash:" : "/External-Flash:",
80 spi_flash_get_chip_size() / (1024 * 1024), " MB");
81 printf("\trevision number:%d\r\n", info.revision);
82 return 0;
83 }
84
register_version(void)85 static void register_version(void)
86 {
87 const esp_console_cmd_t cmd = {
88 .command = "version",
89 .help = "Get version of chip and SDK",
90 .hint = NULL,
91 .func = &get_version,
92 };
93 ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
94 }
95
96 /** 'restart' command restarts the program */
97
restart(int argc,char ** argv)98 static int restart(int argc, char **argv)
99 {
100 ESP_LOGI(TAG, "Restarting");
101 esp_restart();
102 }
103
register_restart(void)104 static void register_restart(void)
105 {
106 const esp_console_cmd_t cmd = {
107 .command = "restart",
108 .help = "Software reset of the chip",
109 .hint = NULL,
110 .func = &restart,
111 };
112 ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
113 }
114
115 /** 'free' command prints available heap memory */
116
free_mem(int argc,char ** argv)117 static int free_mem(int argc, char **argv)
118 {
119 printf("%d\n", esp_get_free_heap_size());
120 return 0;
121 }
122
register_free(void)123 static void register_free(void)
124 {
125 const esp_console_cmd_t cmd = {
126 .command = "free",
127 .help = "Get the current size of free heap memory",
128 .hint = NULL,
129 .func = &free_mem,
130 };
131 ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
132 }
133
134 /* 'heap' command prints minumum heap size */
heap_size(int argc,char ** argv)135 static int heap_size(int argc, char **argv)
136 {
137 uint32_t heap_size = heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT);
138 printf("min heap size: %u\n", heap_size);
139 return 0;
140 }
141
register_heap(void)142 static void register_heap(void)
143 {
144 const esp_console_cmd_t heap_cmd = {
145 .command = "heap",
146 .help = "Get minimum size of free heap memory that was available during program execution",
147 .hint = NULL,
148 .func = &heap_size,
149 };
150 ESP_ERROR_CHECK( esp_console_cmd_register(&heap_cmd) );
151
152 }
153
154 /** 'tasks' command prints the list of tasks and related information */
155 #if WITH_TASKS_INFO
156
tasks_info(int argc,char ** argv)157 static int tasks_info(int argc, char **argv)
158 {
159 const size_t bytes_per_task = 40; /* see vTaskList description */
160 char *task_list_buffer = malloc(uxTaskGetNumberOfTasks() * bytes_per_task);
161 if (task_list_buffer == NULL) {
162 ESP_LOGE(TAG, "failed to allocate buffer for vTaskList output");
163 return 1;
164 }
165 fputs("Task Name\tStatus\tPrio\tHWM\tTask#", stdout);
166 #ifdef CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID
167 fputs("\tAffinity", stdout);
168 #endif
169 fputs("\n", stdout);
170 vTaskList(task_list_buffer);
171 fputs(task_list_buffer, stdout);
172 free(task_list_buffer);
173 return 0;
174 }
175
register_tasks(void)176 static void register_tasks(void)
177 {
178 const esp_console_cmd_t cmd = {
179 .command = "tasks",
180 .help = "Get information about running tasks",
181 .hint = NULL,
182 .func = &tasks_info,
183 };
184 ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
185 }
186
187 #endif // WITH_TASKS_INFO
188
189 /** 'deep_sleep' command puts the chip into deep sleep mode */
190
191 static struct {
192 struct arg_int *wakeup_time;
193 #if SOC_PM_SUPPORT_EXT_WAKEUP
194 struct arg_int *wakeup_gpio_num;
195 struct arg_int *wakeup_gpio_level;
196 #endif
197 struct arg_end *end;
198 } deep_sleep_args;
199
200
deep_sleep(int argc,char ** argv)201 static int deep_sleep(int argc, char **argv)
202 {
203 int nerrors = arg_parse(argc, argv, (void **) &deep_sleep_args);
204 if (nerrors != 0) {
205 arg_print_errors(stderr, deep_sleep_args.end, argv[0]);
206 return 1;
207 }
208 if (deep_sleep_args.wakeup_time->count) {
209 uint64_t timeout = 1000ULL * deep_sleep_args.wakeup_time->ival[0];
210 ESP_LOGI(TAG, "Enabling timer wakeup, timeout=%lluus", timeout);
211 ESP_ERROR_CHECK( esp_sleep_enable_timer_wakeup(timeout) );
212 }
213
214 #if SOC_PM_SUPPORT_EXT_WAKEUP
215 if (deep_sleep_args.wakeup_gpio_num->count) {
216 int io_num = deep_sleep_args.wakeup_gpio_num->ival[0];
217 if (!esp_sleep_is_valid_wakeup_gpio(io_num)) {
218 ESP_LOGE(TAG, "GPIO %d is not an RTC IO", io_num);
219 return 1;
220 }
221 int level = 0;
222 if (deep_sleep_args.wakeup_gpio_level->count) {
223 level = deep_sleep_args.wakeup_gpio_level->ival[0];
224 if (level != 0 && level != 1) {
225 ESP_LOGE(TAG, "Invalid wakeup level: %d", level);
226 return 1;
227 }
228 }
229 ESP_LOGI(TAG, "Enabling wakeup on GPIO%d, wakeup on %s level",
230 io_num, level ? "HIGH" : "LOW");
231
232 ESP_ERROR_CHECK( esp_sleep_enable_ext1_wakeup(1ULL << io_num, level) );
233 ESP_LOGE(TAG, "GPIO wakeup from deep sleep currently unsupported on ESP32-C3");
234 }
235 #endif // SOC_PM_SUPPORT_EXT_WAKEUP
236
237 #if CONFIG_IDF_TARGET_ESP32
238 rtc_gpio_isolate(GPIO_NUM_12);
239 #endif //CONFIG_IDF_TARGET_ESP32
240
241 esp_deep_sleep_start();
242 }
243
register_deep_sleep(void)244 static void register_deep_sleep(void)
245 {
246 int num_args = 1;
247 deep_sleep_args.wakeup_time =
248 arg_int0("t", "time", "<t>", "Wake up time, ms");
249 #if SOC_PM_SUPPORT_EXT_WAKEUP
250 deep_sleep_args.wakeup_gpio_num =
251 arg_int0(NULL, "io", "<n>",
252 "If specified, wakeup using GPIO with given number");
253 deep_sleep_args.wakeup_gpio_level =
254 arg_int0(NULL, "io_level", "<0|1>", "GPIO level to trigger wakeup");
255 num_args += 2;
256 #endif
257 deep_sleep_args.end = arg_end(num_args);
258
259 const esp_console_cmd_t cmd = {
260 .command = "deep_sleep",
261 .help = "Enter deep sleep mode. "
262 #if SOC_PM_SUPPORT_EXT_WAKEUP
263 "Two wakeup modes are supported: timer and GPIO. "
264 #else
265 "Timer wakeup mode is supported. "
266 #endif
267 "If no wakeup option is specified, will sleep indefinitely.",
268 .hint = NULL,
269 .func = &deep_sleep,
270 .argtable = &deep_sleep_args
271 };
272 ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
273 }
274
275 /** 'light_sleep' command puts the chip into light sleep mode */
276
277 static struct {
278 struct arg_int *wakeup_time;
279 struct arg_int *wakeup_gpio_num;
280 struct arg_int *wakeup_gpio_level;
281 struct arg_end *end;
282 } light_sleep_args;
283
light_sleep(int argc,char ** argv)284 static int light_sleep(int argc, char **argv)
285 {
286 int nerrors = arg_parse(argc, argv, (void **) &light_sleep_args);
287 if (nerrors != 0) {
288 arg_print_errors(stderr, light_sleep_args.end, argv[0]);
289 return 1;
290 }
291 esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
292 if (light_sleep_args.wakeup_time->count) {
293 uint64_t timeout = 1000ULL * light_sleep_args.wakeup_time->ival[0];
294 ESP_LOGI(TAG, "Enabling timer wakeup, timeout=%lluus", timeout);
295 ESP_ERROR_CHECK( esp_sleep_enable_timer_wakeup(timeout) );
296 }
297 int io_count = light_sleep_args.wakeup_gpio_num->count;
298 if (io_count != light_sleep_args.wakeup_gpio_level->count) {
299 ESP_LOGE(TAG, "Should have same number of 'io' and 'io_level' arguments");
300 return 1;
301 }
302 for (int i = 0; i < io_count; ++i) {
303 int io_num = light_sleep_args.wakeup_gpio_num->ival[i];
304 int level = light_sleep_args.wakeup_gpio_level->ival[i];
305 if (level != 0 && level != 1) {
306 ESP_LOGE(TAG, "Invalid wakeup level: %d", level);
307 return 1;
308 }
309 ESP_LOGI(TAG, "Enabling wakeup on GPIO%d, wakeup on %s level",
310 io_num, level ? "HIGH" : "LOW");
311
312 ESP_ERROR_CHECK( gpio_wakeup_enable(io_num, level ? GPIO_INTR_HIGH_LEVEL : GPIO_INTR_LOW_LEVEL) );
313 }
314 if (io_count > 0) {
315 ESP_ERROR_CHECK( esp_sleep_enable_gpio_wakeup() );
316 }
317 if (CONFIG_ESP_CONSOLE_UART_NUM >= 0 && CONFIG_ESP_CONSOLE_UART_NUM <= UART_NUM_1) {
318 ESP_LOGI(TAG, "Enabling UART wakeup (press ENTER to exit light sleep)");
319 ESP_ERROR_CHECK( uart_set_wakeup_threshold(CONFIG_ESP_CONSOLE_UART_NUM, 3) );
320 ESP_ERROR_CHECK( esp_sleep_enable_uart_wakeup(CONFIG_ESP_CONSOLE_UART_NUM) );
321 }
322 fflush(stdout);
323 fsync(fileno(stdout));
324 esp_light_sleep_start();
325 esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
326 const char *cause_str;
327 switch (cause) {
328 case ESP_SLEEP_WAKEUP_GPIO:
329 cause_str = "GPIO";
330 break;
331 case ESP_SLEEP_WAKEUP_UART:
332 cause_str = "UART";
333 break;
334 case ESP_SLEEP_WAKEUP_TIMER:
335 cause_str = "timer";
336 break;
337 default:
338 cause_str = "unknown";
339 printf("%d\n", cause);
340 }
341 ESP_LOGI(TAG, "Woke up from: %s", cause_str);
342 return 0;
343 }
344
register_light_sleep(void)345 static void register_light_sleep(void)
346 {
347 light_sleep_args.wakeup_time =
348 arg_int0("t", "time", "<t>", "Wake up time, ms");
349 light_sleep_args.wakeup_gpio_num =
350 arg_intn(NULL, "io", "<n>", 0, 8,
351 "If specified, wakeup using GPIO with given number");
352 light_sleep_args.wakeup_gpio_level =
353 arg_intn(NULL, "io_level", "<0|1>", 0, 8, "GPIO level to trigger wakeup");
354 light_sleep_args.end = arg_end(3);
355
356 const esp_console_cmd_t cmd = {
357 .command = "light_sleep",
358 .help = "Enter light sleep mode. "
359 "Two wakeup modes are supported: timer and GPIO. "
360 "Multiple GPIO pins can be specified using pairs of "
361 "'io' and 'io_level' arguments. "
362 "Will also wake up on UART input.",
363 .hint = NULL,
364 .func = &light_sleep,
365 .argtable = &light_sleep_args
366 };
367 ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
368 }
369