Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sys/shell: add pm command for power management #13679

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions makefiles/pseudomodules.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ PSEUDOMODULES += newlib_gnu_source
PSEUDOMODULES += newlib_nano
PSEUDOMODULES += openthread
PSEUDOMODULES += pktqueue
PSEUDOMODULES += pm_cmd
PSEUDOMODULES += posix_headers
PSEUDOMODULES += printf_float
PSEUDOMODULES += prng
Expand Down
5 changes: 5 additions & 0 deletions sys/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,9 @@ ifneq (,$(filter rtt_cmd,$(USEMODULE)))
FEATURES_REQUIRED += periph_rtt
endif

ifneq (,$(filter pm_cmd,$(USEMODULE)))
FEATURES_REQUIRED += periph_pm
FEATURES_OPTIONAL += periph_rtc
endif

include $(RIOTBASE)/sys/test_utils/Makefile.dep
4 changes: 4 additions & 0 deletions sys/shell/commands/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,8 @@ ifneq (,$(filter suit_coap,$(USEMODULE)))
SRC += sc_suit.c
endif

ifneq (,$(filter pm_cmd,$(USEMODULE)))
SRC += sc_pm.c
endif

include $(RIOTBASE)/Makefile.base
235 changes: 235 additions & 0 deletions sys/shell/commands/sc_pm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
/*
* Copyright (C) 2020 Gunar Schorcht
* Copyright (C) 2016-2018 Bas Stottelaar <[email protected]>
*
* 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 implementation for power management
*
* @author Gunar Schorcht <[email protected]>
* @author Bas Stottelaar <[email protected]>
* @author Vincent Dupont <[email protected]>
*
* @}
*/

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>

#include "periph/pm.h"

#ifdef MODULE_PM_LAYERED
#ifdef MODULE_PERIPH_RTC
#include "periph/rtc.h"
#endif /* MODULE_PERIPH_RTC */
#include "pm_layered.h"
#endif /* MODULE_PM_LAYERED */

#ifdef MODULE_PM_LAYERED
static int _pm_cmd_check_mode(int argc, char **argv)
{
if (argc < 2) {
printf("Usage: %s <power mode>\n", argv[0]);
return -1;
}

return 0;
}

static int _pm_cmd_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 _pm_cmd_check_mode_duration(int argc, char **argv)
{
if (argc != 3) {
printf("Usage: %s <power mode> <duration (s)>\n", argv[0]);
return -1;
}

return 0;
}

static int _pm_cmd_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 _pm_cmd_cb_rtc(void *arg)
{
int level = (int)arg;

pm_block(level);
}
#endif /* MODULE_PERIPH_RTC */
#endif /* MODULE_PM_LAYERED */

#ifdef MODULE_PM_LAYERED
static int _pm_cmd_block(int argc, char **argv)
{
if (_pm_cmd_check_mode(argc, argv) != 0) {
return 1;
}

int mode = _pm_cmd_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 _pm_cmd_set(int argc, char **argv)
{
if (_pm_cmd_check_mode(argc, argv) != 0) {
return 1;
}

int mode = _pm_cmd_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 _pm_cmd_unblock(int argc, char **argv)
{
if (_pm_cmd_check_mode(argc, argv) != 0) {
return 1;
}

int mode = _pm_cmd_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 _pm_cmd_unblock_rtc(int argc, char **argv)
{
if (_pm_cmd_check_mode_duration(argc, argv) != 0) {
return 1;
}

int mode = _pm_cmd_parse_mode(argv[1]);
int duration = _pm_cmd_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, _pm_cmd_cb_rtc, (void *)mode);

pm_unblock(mode);

return 0;
}
#endif /* MODULE_PERIPH_RTC */
#endif /* MODULE_PM_LAYERED */

static int _pm_cmd_usage(void)
{
puts("off\t\tturn off");
puts("reboot\t\treboot");
#ifdef MODULE_PM_LAYERED
puts("set\t\tset power mode");
puts("block\t\tblock power mode");
puts("unblock\t\tunblock power mode");
#ifdef MODULE_PERIPH_RTC
puts("unblock_rtc\ttemporary unblock power mode");
#endif /* MODULE_PERIPH_RTC */
#endif /* MODULE_PM_LAYERED */
return 0;
}

int _pm_cmd_handler(int argc, char **argv)
{
if (argc < 2) {
_pm_cmd_usage();
return 1;
}
else if (strncmp(argv[1], "off", 3) == 0) {
pm_off();
}
else if (strncmp(argv[1], "reboot", 6) == 0) {
pm_reboot();
}
#ifdef MODULE_PM_LAYERED
else if ((strncmp(argv[1], "set", 3) == 0) && (argc == 3)) {
return _pm_cmd_set(argc - 1, argv + 1);
}
else if ((strncmp(argv[1], "block", 5) == 0) && (argc == 3)) {
return _pm_cmd_block(argc - 1, argv + 1);
}
#ifdef MODULE_PERIPH_RTC
else if ((strncmp(argv[1], "unblock_rtc", 11) == 0) && (argc == 4)) {
return _pm_cmd_unblock_rtc(argc - 1, argv + 1);
}
#endif /* MODULE_PERIPH_RTC */
else if ((strncmp(argv[1], "unblock", 7) == 0) && (argc == 3)) {
return _pm_cmd_unblock(argc - 1, argv +1);
}
#endif /* MODULE_PM_LAYERED */
else {
printf("unknown command or missing parameters: %s\n\n", argv[1]);
_pm_cmd_usage();
return 1;
}
return 0;
}
7 changes: 7 additions & 0 deletions sys/shell/commands/shell_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ extern int _nimble_netif_handler(int argc, char **argv);
extern int _suit_handler(int argc, char **argv);
#endif

#ifdef MODULE_PM_CMD
extern int _pm_cmd_handler(int argc, char **argv);
#endif

const shell_command_t _shell_command_list[] = {
{"reboot", "Reboot the node", _reboot_handler},
{"version", "Prints current RIOT_VERSION", _version_handler},
Expand Down Expand Up @@ -279,6 +283,9 @@ const shell_command_t _shell_command_list[] = {
#endif
#ifdef MODULE_SUIT_COAP
{ "suit", "Trigger a SUIT firmware update", _suit_handler },
#endif
#ifdef MODULE_PM_CMD
{"pm", "Power management commands", _pm_cmd_handler},
#endif
{NULL, NULL, NULL}
};
3 changes: 2 additions & 1 deletion tests/periph_pm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ 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
FEATURES_OPTIONAL += periph_gpio_irq

USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += pm_cmd

include $(RIOTBASE)/Makefile.include
Loading