From 74d496f99fc21593607c0c353b31af83916298ef Mon Sep 17 00:00:00 2001 From: Bas Stottelaar Date: Sun, 22 Jan 2017 12:02:29 +0100 Subject: [PATCH] tests: periph_pm: add peripheral test. --- tests/periph_pm/Makefile | 11 ++ tests/periph_pm/README.md | 14 +++ tests/periph_pm/main.c | 248 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 tests/periph_pm/Makefile create mode 100644 tests/periph_pm/README.md create mode 100644 tests/periph_pm/main.c diff --git a/tests/periph_pm/Makefile b/tests/periph_pm/Makefile new file mode 100644 index 0000000000..78d9538197 --- /dev/null +++ b/tests/periph_pm/Makefile @@ -0,0 +1,11 @@ +BOARD ?= slstk3401a +include ../Makefile.tests_common + +# method `fflush()` is not defined for MSP-430 (#6445 will fix this) +BOARD_BLACKLIST := chronos msb-430h msb-430 telosb wsn430-v1_3b wsn430-v1_4 z1 + +FEATURES_OPTIONAL += periph_rtc + +USEMODULE += shell + +include $(RIOTBASE)/Makefile.include diff --git a/tests/periph_pm/README.md b/tests/periph_pm/README.md new file mode 100644 index 0000000000..6079847ea9 --- /dev/null +++ b/tests/periph_pm/README.md @@ -0,0 +1,14 @@ +Expected result +=============== +You should be presented with the RIOT shell, providing you with commands to test the power +management implementation by forcing the CPU to set a certain power mode. An external power +measurement device is needed to observe the effect. + +Some power modes may require a certain event to wake up. Reset the CPU if needed. + +If a RTC peripheral is available, an additional command to temporarily unblock a power mode is +available (provided that the CPU can wake-up from given power mode). + +Background +========== +Test the functionality of the platform's power management implementation. diff --git a/tests/periph_pm/main.c b/tests/periph_pm/main.c new file mode 100644 index 0000000000..4fe74b3bfa --- /dev/null +++ b/tests/periph_pm/main.c @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2016-2018 Bas Stottelaar + * + * 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 tests + * @{ + * + * @file + * @brief Power management peripheral test. + * + * @author Bas Stottelaar + * @author Vincent Dupont + * + * @} + */ + +#include +#include + +#include "periph/pm.h" +#ifdef MODULE_PM_LAYERED +#ifdef MODULE_PERIPH_RTC +#include "periph/rtc.h" +#endif +#include "pm_layered.h" +#endif +#include "shell.h" + +#ifdef MODULE_PM_LAYERED +static int check_mode(int argc, char **argv) +{ + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + 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; +} + +#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); + + if (duration < 0) { + puts("Error: duration must be a positive number."); + return -1; + } + + return duration; +} + +static void cb_rtc(void *arg) +{ + int level = (int)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) { + return 1; + } + + int mode = parse_mode(argv[1]); + int duration = parse_duration(argv[2]); + + if (mode < 0 || duration < 0) { + return 1; + } + + printf("Unblocking power mode %d for %d seconds.\n", mode, duration); + fflush(stdout); + + struct tm time; + + rtc_get_time(&time); + time.tm_sec += duration; + mktime(&time); + rtc_set_alarm(&time, cb_rtc, (void *)mode); + + pm_unblock(mode); + + return 0; +} +#endif /* MODULE_PERIPH_RTC */ +#endif /* MODULE_PM_LAYERED */ + +/** + * @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 +#endif + { NULL, NULL, NULL } +}; + +/** + * @brief Application entry point. + */ +int main(void) +{ + char line_buf[SHELL_DEFAULT_BUFSIZE]; + + /* print test application information */ +#ifdef MODULE_PM_LAYERED + printf("This application allows you to test the CPU power management.\n" + "The available power modes are 0 - %d. Lower-numbered power modes\n" + "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); +#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" + "needed."); +#endif + + /* run the shell and wait for the user to enter a mode */ + shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); + + return 0; +}