diff --git a/sys/include/pm_layered.h b/sys/include/pm_layered.h index d7fa07e16987..7814b5e32494 100644 --- a/sys/include/pm_layered.h +++ b/sys/include/pm_layered.h @@ -49,6 +49,14 @@ extern "C" { #define PROVIDES_PM_SET_LOWEST #endif +/** + * @brief Power Management mode blocker typedef + */ +typedef union { + uint32_t val_u32; /**< power mode blockers u32 */ + uint8_t val_u8[PM_NUM_MODES]; /**< power mode blockers u8 */ +} pm_blocker_t; + /** * @brief Block a power mode * diff --git a/sys/pm_layered/pm.c b/sys/pm_layered/pm.c index 3f63bfa7b9b7..c14217d60ea3 100644 --- a/sys/pm_layered/pm.c +++ b/sys/pm_layered/pm.c @@ -33,14 +33,6 @@ #define PM_BLOCKER_INITIAL 0x01010101 /* block all by default */ #endif -/** - * @brief Power Management mode typedef - */ -typedef union { - uint32_t val_u32; - uint8_t val_u8[PM_NUM_MODES]; -} pm_blocker_t; - /** * @brief Global variable for keeping track of blocked modes */ diff --git a/sys/shell/commands/Makefile b/sys/shell/commands/Makefile index f2ad26f1aa02..a8403d4aa27c 100644 --- a/sys/shell/commands/Makefile +++ b/sys/shell/commands/Makefile @@ -8,6 +8,9 @@ endif ifneq (,$(filter mci,$(USEMODULE))) SRC += sc_disk.c endif +ifneq (,$(filter periph_pm,$(USEMODULE))) + SRC += sc_pm.c +endif ifneq (,$(filter ps,$(USEMODULE))) SRC += sc_ps.c endif diff --git a/sys/shell/commands/sc_pm.c b/sys/shell/commands/sc_pm.c new file mode 100644 index 000000000000..6834ee8b7e86 --- /dev/null +++ b/sys/shell/commands/sc_pm.c @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2019 Thomas Stilwell + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_shell_commands + * @{ + * + * @file + * @brief Shell command to interact with the PM subsystem + * + * @author Bas Stottelaar + * @author Vincent Dupont + * @author Thomas Stilwell + * + * @} + */ + +#include +#include +#include +#include "periph/pm.h" + +#ifdef MODULE_PM_LAYERED +#include "pm_layered.h" + +extern volatile pm_blocker_t pm_blocker; /* sys/pm_layered/pm.c */ +#endif /* MODULE_PM_LAYERED */ + +static void _print_usage(void) { + puts("Usage:"); +#ifdef MODULE_PM_LAYERED + puts("\tpm show: display current blockers for each power mode"); + puts("\tpm set : manually set power mode (lasts until WFI returns)"); + puts("\tpm block : manually block power mode"); + puts("\tpm unblock : manually unblock power mode"); +#endif /* MODULE_PM_LAYERED */ + puts("\tpm off: call pm_off()"); +} + +#ifdef MODULE_PM_LAYERED +static int check_mode(int argc, char **argv) +{ + if (argc != 3) { + printf("Usage: %s %s \n", argv[0], argv[1]); + return -1; + } + + return 0; +} + +static int parse_mode(char *argv) +{ + uint8_t mode = atoi(argv); + + if (mode >= PM_NUM_MODES) { + printf("Error: power mode not in range 0 - %d.\n", PM_NUM_MODES - 1); + return -1; + } + + return mode; +} + +static int cmd_block(char *arg) +{ + int mode = parse_mode(arg); + if (mode < 0) { + return 1; + } + + printf("Blocking power mode %d.\n", mode); + fflush(stdout); + + pm_block(mode); + + return 0; +} + +static int cmd_set(char *arg) +{ + int mode = parse_mode(arg); + if (mode < 0) { + return 1; + } + + printf("CPU is entering power mode %d.\n", mode); + puts("Now waiting for a wakeup event..."); + fflush(stdout); + + pm_set(mode); + /* execution stops here until anything (like shell input) wakes the CPU */ + + printf("CPU has returned from power mode %d.\n", mode); + + return 0; +} + +static int cmd_unblock(char *arg) +{ + int mode = parse_mode(arg); + + if (mode < 0) { + return 1; + } + + if (pm_blocker.val_u8[mode] == 0) { + printf("Mode %d is already unblocked.\n", mode); + return 1; + } + + printf("Unblocking power mode %d.\n", mode); + fflush(stdout); + + pm_unblock(mode); + + return 0; +} + +static int cmd_show(char *arg) +{ + (void)arg; + uint8_t lowest_allowed_mode = 0; + + for (unsigned i = 0; i < PM_NUM_MODES; i++) { + printf("mode %u blockers: %u \n", i, pm_blocker.val_u8[i]); + if (pm_blocker.val_u8[i]) { + lowest_allowed_mode = i + 1; + } + } + + printf("Lowest allowed mode: %u\n", lowest_allowed_mode); + return 0; +} +#endif /* MODULE_PM_LAYERED */ + +static int cmd_off(char *arg) +{ + (void)arg; + + pm_off(); + + return 0; +} + +int _pm_handler(int argc, char **argv) +{ +#ifdef MODULE_PM_LAYERED + if (!strcmp(argv[1], "show")) { + if (argc != 2) { + puts("usage: pm show: display current blockers for each power mode"); + return 1; + } + + return cmd_show(argv[1]); + } + + if (!strcmp(argv[1], "block")) { + if (check_mode(argc, argv) != 0) { + return 1; + } + + return cmd_block(argv[2]); + } + + if (!strcmp(argv[1], "unblock")) { + if (check_mode(argc, argv) != 0) { + return 1; + } + + return cmd_unblock(argv[2]); + } + + if (!strcmp(argv[1], "set")) { + if (check_mode(argc, argv) != 0) { + return 1; + } + + return cmd_set(argv[2]); + } +#else + (void)argc; +#endif /* MODULE_PM_LAYERED */ + + if (!strcmp(argv[1], "off")) { + return cmd_off(NULL); + } + + _print_usage(); + return 1; +} diff --git a/sys/shell/commands/shell_commands.c b/sys/shell/commands/shell_commands.c index 620c4d1feaeb..084ab13d6d6d 100644 --- a/sys/shell/commands/shell_commands.c +++ b/sys/shell/commands/shell_commands.c @@ -34,6 +34,10 @@ extern int _id_handler(int argc, char **argv); extern int _heap_handler(int argc, char **argv); #endif +#ifdef MODULE_PERIPH_PM +extern int _pm_handler(int argc, char **argv); +#endif + #ifdef MODULE_PS extern int _ps_handler(int argc, char **argv); #endif @@ -180,6 +184,9 @@ const shell_command_t _shell_command_list[] = { #ifdef MODULE_HEAP_CMD {"heap", "Prints heap statistics.", _heap_handler}, #endif +#ifdef MODULE_PERIPH_PM + { "pm", "interact with layered PM subsystem", _pm_handler }, +#endif #ifdef MODULE_PS {"ps", "Prints information about running threads.", _ps_handler}, #endif diff --git a/tests/driver_sx127x/Makefile.ci b/tests/driver_sx127x/Makefile.ci index 3585ad2b49c9..5bb8cf0dcdea 100644 --- a/tests/driver_sx127x/Makefile.ci +++ b/tests/driver_sx127x/Makefile.ci @@ -5,5 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \ arduino-uno \ atmega328p \ nucleo-f031k6 \ + nucleo-f042k6 \ + nucleo-l031k6 \ stm32f030f4-demo \ # diff --git a/tests/gnrc_udp/Makefile.ci b/tests/gnrc_udp/Makefile.ci index 6fa52d6a3373..69ee200e1ee7 100644 --- a/tests/gnrc_udp/Makefile.ci +++ b/tests/gnrc_udp/Makefile.ci @@ -7,6 +7,8 @@ BOARD_INSUFFICIENT_MEMORY := \ arduino-uno \ atmega1284p \ atmega328p \ + blackpill \ + bluepill \ calliope-mini \ chronos \ derfmega128 \ diff --git a/tests/lwip/Makefile.ci b/tests/lwip/Makefile.ci index a8f189bb5501..620aeed99a58 100644 --- a/tests/lwip/Makefile.ci +++ b/tests/lwip/Makefile.ci @@ -11,6 +11,8 @@ BOARD_INSUFFICIENT_MEMORY := \ nucleo-f334r8 \ nucleo-l031k6 \ nucleo-l053r8 \ + saml10-xpro \ + saml11-xpro \ stm32f030f4-demo \ stm32f0discovery \ stm32l0538-disco \ diff --git a/tests/periph_pm/Makefile b/tests/periph_pm/Makefile index 16bb20073bed..f8ca0371e745 100644 --- a/tests/periph_pm/Makefile +++ b/tests/periph_pm/Makefile @@ -8,5 +8,6 @@ FEATURES_OPTIONAL += periph_rtc FEATURES_OPTIONAL += periph_gpio_irq USEMODULE += shell +USEMODULE += shell_commands include $(RIOTBASE)/Makefile.include diff --git a/tests/periph_pm/main.c b/tests/periph_pm/main.c index 63d16f97ef15..caaccf070e0b 100644 --- a/tests/periph_pm/main.c +++ b/tests/periph_pm/main.c @@ -33,6 +33,9 @@ #endif #include "pm_layered.h" #endif + +extern int _pm_handler(int argc, char **argv); + #include "shell.h" #ifndef BTN0_INT_FLANK @@ -40,10 +43,14 @@ #endif #ifdef MODULE_PM_LAYERED -static int check_mode(int argc, char **argv) + +extern volatile pm_blocker_t pm_blocker; /* sys/pm_layered/pm.c */ + +#ifdef MODULE_PERIPH_RTC +static int check_mode_duration(int argc, char **argv) { - if (argc < 2) { - printf("Usage: %s \n", argv[0]); + if (argc != 3) { + printf("Usage: %s \n", argv[0]); return -1; } @@ -62,17 +69,6 @@ static int parse_mode(char *argv) return mode; } -#ifdef MODULE_PERIPH_RTC -static int check_mode_duration(int argc, char **argv) -{ - if (argc != 3) { - printf("Usage: %s \n", argv[0]); - return -1; - } - - return 0; -} - static int parse_duration(char *argv) { int duration = atoi(argv); @@ -91,97 +87,7 @@ static void cb_rtc(void *arg) pm_block(level); } -#endif /* MODULE_PERIPH_RTC */ -#endif /* MODULE_PM_LAYERED */ - -static int cmd_off(int argc, char **argv) -{ - (void) argc; - (void) argv; - - puts("CPU will turn off."); - fflush(stdout); - - pm_off(); - - return 0; -} - -static int cmd_reboot(int argc, char **argv) -{ - (void) argc; - (void) argv; - - puts("CPU will reboot."); - fflush(stdout); - - pm_reboot(); - - return 0; -} - -#ifdef MODULE_PM_LAYERED -static int cmd_block(int argc, char **argv) -{ - if (check_mode(argc, argv) != 0) { - return 1; - } - - int mode = parse_mode(argv[1]); - - if (mode < 0) { - return 1; - } - printf("Blocking power mode %d.\n", mode); - fflush(stdout); - - pm_block(mode); - - return 0; -} - -static int cmd_set(int argc, char **argv) -{ - if (check_mode(argc, argv) != 0) { - return 1; - } - - int mode = parse_mode(argv[1]); - - if (mode < 0) { - return 1; - } - - printf("CPU will enter power mode %d.\n", mode); - fflush(stdout); - - pm_set(mode); - - return 0; -} - -static int cmd_unblock(int argc, char **argv) -{ - if (check_mode(argc, argv) != 0) { - return 1; - } - - int mode = parse_mode(argv[1]); - - if (mode < 0) { - return 1; - } - - printf("Unblocking power mode %d.\n", mode); - fflush(stdout); - - pm_unblock(mode); - - return 0; -} - -#ifdef MODULE_PERIPH_RTC static int cmd_unblock_rtc(int argc, char **argv) { if (check_mode_duration(argc, argv) != 0) { @@ -195,6 +101,11 @@ static int cmd_unblock_rtc(int argc, char **argv) return 1; } + if (pm_blocker.val_u8[mode] == 0) { + printf("Mode %d is already unblocked.\n", mode); + return 1; + } + printf("Unblocking power mode %d for %d seconds.\n", mode, duration); fflush(stdout); @@ -224,15 +135,8 @@ static void btn_cb(void *ctx) * @brief List of shell commands for this example. */ static const shell_command_t shell_commands[] = { - { "off", "turn off", cmd_off }, - { "reboot", "reboot", cmd_reboot }, -#ifdef MODULE_PM_LAYERED - { "block", "block power mode", cmd_block }, - { "set", "set power mode", cmd_set }, - { "unblock", "unblock power mode", cmd_unblock }, -#ifdef MODULE_PERIPH_RTC - { "unblock_rtc", "temporary unblock power mode", cmd_unblock_rtc }, -#endif +#if defined MODULE_PM_LAYERED && defined MODULE_PERIPH_RTC + { "unblock_rtc", "temporarily unblock power mode", cmd_unblock_rtc }, #endif { NULL, NULL, NULL } }; @@ -251,6 +155,13 @@ int main(void) "save more power, but may require an event/interrupt to wake up\n" "the CPU. Reset the CPU if needed.\n", PM_NUM_MODES - 1); + + /* In case the system boots into an unresponsive shell, at least display + * the state of PM blockers so that the user will know which power mode has + * been entered and is presumably responsible for the unresponsive shell. + */ + _pm_handler(2, (char *[]){"pm", "show"}); + #else puts("This application allows you to test the CPU power management.\n" "Layered support is not unavailable for this CPU. Reset the CPU if\n"