Skip to content

Commit ba69a59

Browse files
authored
Merge pull request adafruit#10271 from dhalbert/wifi-power-management
Wifi power management
2 parents dd81542 + 7d65991 commit ba69a59

File tree

13 files changed

+243
-73
lines changed

13 files changed

+243
-73
lines changed

ports/espressif/common-hal/wifi/Radio.c

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -139,23 +139,44 @@ void common_hal_wifi_radio_set_tx_power(wifi_radio_obj_t *self, const mp_float_t
139139
esp_wifi_set_max_tx_power(tx_power * 4.0f);
140140
}
141141

142-
mp_int_t common_hal_wifi_radio_get_listen_interval(wifi_radio_obj_t *self) {
143-
wifi_config_t *config = &self->sta_config;
144-
return config->sta.listen_interval;
142+
wifi_power_management_t common_hal_wifi_radio_get_power_management(wifi_radio_obj_t *self) {
143+
wifi_ps_type_t ps;
144+
esp_err_t ret = esp_wifi_get_ps(&ps);
145+
if (ret == ESP_OK) {
146+
switch (ps) {
147+
case WIFI_PS_MIN_MODEM:
148+
return POWER_MANAGEMENT_MIN;
149+
case WIFI_PS_MAX_MODEM:
150+
return POWER_MANAGEMENT_MAX;
151+
case WIFI_PS_NONE:
152+
return POWER_MANAGEMENT_NONE;
153+
}
154+
}
155+
return POWER_MANAGEMENT_MIN;
145156
}
146157

147-
void common_hal_wifi_radio_set_listen_interval(wifi_radio_obj_t *self, const mp_int_t listen_interval) {
148-
wifi_config_t *config = &self->sta_config;
149-
config->sta.listen_interval = listen_interval;
150-
if (listen_interval == 1) {
151-
esp_wifi_set_ps(WIFI_PS_MIN_MODEM);
152-
} else if (listen_interval > 1) {
153-
esp_wifi_set_ps(WIFI_PS_MAX_MODEM);
154-
} else {
155-
esp_wifi_set_ps(WIFI_PS_NONE);
156-
}
157158

158-
esp_wifi_set_config(ESP_IF_WIFI_STA, config);
159+
void common_hal_wifi_radio_set_power_management(wifi_radio_obj_t *self, wifi_power_management_t power_management) {
160+
switch (power_management) {
161+
case POWER_MANAGEMENT_MIN:
162+
esp_wifi_set_ps(WIFI_PS_MIN_MODEM);
163+
break;
164+
case POWER_MANAGEMENT_MAX: {
165+
// listen_interval is only used in this case.
166+
wifi_config_t *config = &self->sta_config;
167+
// This is a typical value seen in various examples.
168+
config->sta.listen_interval = 3;
169+
esp_wifi_set_ps(WIFI_PS_MAX_MODEM);
170+
esp_wifi_set_config(ESP_IF_WIFI_STA, config);
171+
}
172+
break;
173+
case POWER_MANAGEMENT_NONE:
174+
esp_wifi_set_ps(WIFI_PS_NONE);
175+
break;
176+
case POWER_MANAGEMENT_UNKNOWN:
177+
// This should be prevented in shared-bindings.
178+
break;
179+
}
159180
}
160181

161182
mp_obj_t common_hal_wifi_radio_get_mac_address_ap(wifi_radio_obj_t *self) {

ports/espressif/mpconfigport.mk

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,6 @@ CIRCUITPY_FULL_BUILD ?= 1
4040
# If SSL is enabled, it's mbedtls
4141
CIRCUITPY_SSL_MBEDTLS = 1
4242

43-
# Wifi Power Save
44-
CIRCUITPY_WIFI_RADIO_SETTABLE_LISTEN_INTERVAL = 1
45-
4643
# Never use our copy of MBEDTLS
4744
CIRCUITPY_HASHLIB_MBEDTLS_ONLY = 0
4845

ports/raspberrypi/bindings/cyw43/__init__.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
#include "lib/cyw43-driver/src/cyw43.h"
1818

19-
static int power_management_value = PM_DISABLED;
19+
static uint32_t power_management_value = CONST_CYW43_DEFAULT_PM;
2020

2121
void cyw43_enter_deep_sleep(void) {
2222
#define WL_REG_ON 23
@@ -43,14 +43,23 @@ MP_DEFINE_CONST_OBJ_TYPE(
4343
print, shared_bindings_microcontroller_pin_print
4444
);
4545

46+
uint32_t cyw43_get_power_management_value() {
47+
return power_management_value;
48+
}
49+
50+
void cyw43_set_power_management_value(uint32_t value) {
51+
power_management_value = value;
52+
bindings_cyw43_wifi_enforce_pm();
53+
}
54+
4655
//| PM_STANDARD: int
47-
//| """The standard power management mode"""
56+
//| """The default power management mode; same as PM_PERFORMANCE"""
4857
//| PM_AGGRESSIVE: int
4958
//| """Aggressive power management mode for optimal power usage at the cost of performance"""
5059
//| PM_PERFORMANCE: int
5160
//| """Performance power management mode where more power is used to increase performance"""
5261
//| PM_DISABLED: int
53-
//| """Disable power management and always use highest power mode. CircuitPython sets this value at reset time, because it provides the best connectivity reliability."""
62+
//| """Disable power management and always use highest power mode."""
5463
//|
5564
//|
5665
//| def set_power_management(value: int) -> None:
@@ -85,8 +94,7 @@ MP_DEFINE_CONST_OBJ_TYPE(
8594
//|
8695
static mp_obj_t cyw43_set_power_management(const mp_obj_t value_in) {
8796
mp_int_t value = mp_obj_get_int(value_in);
88-
power_management_value = value;
89-
bindings_cyw43_wifi_enforce_pm();
97+
cyw43_set_power_management_value(value);
9098
return mp_const_none;
9199
}
92100
static MP_DEFINE_CONST_FUN_OBJ_1(cyw43_set_power_management_obj, cyw43_set_power_management);
@@ -126,10 +134,10 @@ static const mp_rom_map_elem_t cyw43_module_globals_table[] = {
126134
{ MP_ROM_QSTR(MP_QSTR_CywPin), MP_ROM_PTR(&cyw43_pin_type) },
127135
{ MP_ROM_QSTR(MP_QSTR_set_power_management), &cyw43_set_power_management_obj },
128136
{ MP_ROM_QSTR(MP_QSTR_get_power_management), &cyw43_get_power_management_obj },
129-
{ MP_ROM_QSTR(MP_QSTR_PM_STANDARD), MP_ROM_INT(PM_STANDARD) },
130-
{ MP_ROM_QSTR(MP_QSTR_PM_AGGRESSIVE), MP_ROM_INT(PM_AGGRESSIVE) },
131-
{ MP_ROM_QSTR(MP_QSTR_PM_PERFORMANCE), MP_ROM_INT(PM_PERFORMANCE) },
132-
{ MP_ROM_QSTR(MP_QSTR_PM_DISABLED), MP_ROM_INT(PM_DISABLED) },
137+
{ MP_ROM_QSTR(MP_QSTR_PM_STANDARD), MP_ROM_INT(CONST_CYW43_DEFAULT_PM) },
138+
{ MP_ROM_QSTR(MP_QSTR_PM_AGGRESSIVE), MP_ROM_INT(CONST_CYW43_AGGRESSIVE_PM) },
139+
{ MP_ROM_QSTR(MP_QSTR_PM_PERFORMANCE), MP_ROM_INT(CONST_CYW43_PERFORMANCE_PM) },
140+
{ MP_ROM_QSTR(MP_QSTR_PM_DISABLED), MP_ROM_INT(CONST_CYW43_NONE_PM) },
133141
};
134142

135143
static MP_DEFINE_CONST_DICT(cyw43_module_globals, cyw43_module_globals_table);

ports/raspberrypi/bindings/cyw43/__init__.h

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,25 @@ const mcu_pin_obj_t *validate_obj_is_free_pin_including_cyw43(mp_obj_t obj, qstr
1616
const mcu_pin_obj_t *validate_obj_is_free_pin_or_gpio29(mp_obj_t obj, qstr arg_name);
1717
const mcu_pin_obj_t *validate_obj_is_pin_including_cyw43(mp_obj_t obj, qstr arg_name);
1818

19-
#define CONSTANT_CYW43_PM_VALUE(pm_mode, pm2_sleep_ret_ms, li_beacon_period, li_dtim_period, li_assoc) \
19+
// This is equivalent to the code in cyw43.h, except that the values are computed at compile time.
20+
// A `CONST_` prefix has been added to the computation function (expressed as a macro) and the values.
21+
22+
#define CONST_cyw43_pm_value(pm_mode, pm2_sleep_ret_ms, li_beacon_period, li_dtim_period, li_assoc) \
2023
(li_assoc << 20 | /* listen interval sent to ap */ \
2124
li_dtim_period << 16 | \
2225
li_beacon_period << 12 | \
2326
(pm2_sleep_ret_ms / 10) << 4 | /* cyw43_ll_wifi_pm multiplies this by 10 */ \
2427
pm_mode /* CYW43_PM2_POWERSAVE_MODE etc */)
2528

26-
// CYW43_DEFAULT_PM (except a compile-time constant)
27-
#define PM_STANDARD CONSTANT_CYW43_PM_VALUE(CYW43_PM2_POWERSAVE_MODE, 200, 1, 1, 10)
28-
// CYW43_AGGRESSIVE_PM (except a compile-time constant)
29-
#define PM_AGGRESSIVE CONSTANT_CYW43_PM_VALUE(CYW43_PM2_POWERSAVE_MODE, 2000, 1, 1, 10)
30-
// CYW43_PERFORMANCE_PM (except a compile-time constant)
31-
#define PM_PERFORMANCE CONSTANT_CYW43_PM_VALUE(CYW43_PM2_POWERSAVE_MODE, 20, 1, 1, 1)
32-
// The 0xa11140 magic value
33-
#define PM_DISABLED CONSTANT_CYW43_PM_VALUE(CYW43_NO_POWERSAVE_MODE, 200, 1, 1, 10)
29+
#define CONST_CYW43_DEFAULT_PM (CONST_CYW43_PERFORMANCE_PM)
30+
31+
#define CONST_CYW43_NONE_PM (CONST_cyw43_pm_value(CYW43_NO_POWERSAVE_MODE, 10, 0, 0, 0))
32+
33+
#define CONST_CYW43_AGGRESSIVE_PM (CONST_cyw43_pm_value(CYW43_PM1_POWERSAVE_MODE, 10, 0, 0, 0))
34+
35+
#define CONST_CYW43_PERFORMANCE_PM (CONST_cyw43_pm_value(CYW43_PM2_POWERSAVE_MODE, 200, 1, 1, 10))
3436

37+
extern uint32_t cyw43_get_power_management_value(void);
38+
extern void cyw43_set_power_management_value(uint32_t value);
3539
extern void bindings_cyw43_wifi_enforce_pm(void);
3640
void cyw43_enter_deep_sleep(void);

ports/raspberrypi/common-hal/wifi/Radio.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// SPDX-License-Identifier: MIT
66

77
#include "supervisor/port.h"
8+
#include "shared-bindings/wifi/PowerManagement.h"
89
#include "shared-bindings/wifi/Radio.h"
910
#include "shared-bindings/wifi/Network.h"
1011

@@ -107,6 +108,41 @@ void common_hal_wifi_radio_set_tx_power(wifi_radio_obj_t *self, const mp_float_t
107108
cyw43_ioctl(&cyw43_state, CYW43_IOCTL_SET_VAR, 9 + 4, buf, CYW43_ITF_AP);
108109
}
109110

111+
wifi_power_management_t common_hal_wifi_radio_get_power_management(wifi_radio_obj_t *self) {
112+
uint32_t pm_value = cyw43_get_power_management_value();
113+
114+
switch (pm_value) {
115+
case CONST_CYW43_PERFORMANCE_PM:
116+
return POWER_MANAGEMENT_MIN;
117+
case CONST_CYW43_AGGRESSIVE_PM:
118+
return POWER_MANAGEMENT_MAX;
119+
case CONST_CYW43_NONE_PM:
120+
return POWER_MANAGEMENT_NONE;
121+
default:
122+
return POWER_MANAGEMENT_UNKNOWN;
123+
}
124+
}
125+
126+
127+
void common_hal_wifi_radio_set_power_management(wifi_radio_obj_t *self, wifi_power_management_t power_management) {
128+
uint32_t pm_setting = CONST_CYW43_DEFAULT_PM;
129+
switch (power_management) {
130+
case POWER_MANAGEMENT_MIN:
131+
pm_setting = CONST_CYW43_PERFORMANCE_PM;
132+
break;
133+
case POWER_MANAGEMENT_MAX:
134+
pm_setting = CONST_CYW43_AGGRESSIVE_PM;
135+
break;
136+
case POWER_MANAGEMENT_NONE:
137+
pm_setting = CONST_CYW43_NONE_PM;
138+
break;
139+
default:
140+
// Should not get here.
141+
break;
142+
}
143+
cyw43_set_power_management_value(pm_setting);
144+
}
145+
110146
mp_obj_t common_hal_wifi_radio_get_mac_address_ap(wifi_radio_obj_t *self) {
111147
return common_hal_wifi_radio_get_mac_address(self);
112148
}

ports/zephyr-cp/common-hal/wifi/Radio.c

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,44 @@ void common_hal_wifi_radio_set_tx_power(wifi_radio_obj_t *self, const mp_float_t
137137
// esp_wifi_set_max_tx_power(tx_power * 4.0f);
138138
}
139139

140-
mp_int_t common_hal_wifi_radio_get_listen_interval(wifi_radio_obj_t *self) {
141-
// wifi_config_t *config = &self->sta_config;
142-
// return config->sta.listen_interval;
143-
return 0;
140+
wifi_power_management_t common_hal_wifi_radio_get_power_management(wifi_radio_obj_t *self) {
141+
// wifi_ps_type_t ps;
142+
// esp_err_t ret = esp_wifi_get_ps(&ps);
143+
// if (ret == ESP_OK) {
144+
// switch (ps) {
145+
// case WIFI_PS_MIN_MODEM:
146+
// return POWER_MANAGEMENT_MIN;
147+
// case WIFI_PS_MAX_MODEM:
148+
// return POWER_MANAGEMENT_MAX;
149+
// case WIFI_PS_NONE:
150+
// return POWER_MANAGEMENT_NONE;
151+
// }
152+
// }
153+
return POWER_MANAGEMENT_UNKNOWN;
154+
}
155+
156+
157+
void common_hal_wifi_radio_set_power_management(wifi_radio_obj_t *self, wifi_power_management_t power_management) {
158+
// switch (power_management) {
159+
// case POWER_MANAGEMENT_MIN:
160+
// esp_wifi_set_ps(WIFI_PS_MIN_MODEM);
161+
// break;
162+
// case POWER_MANAGEMENT_MAX: {
163+
// // listen_interval is only used in this case.
164+
// wifi_config_t *config = &self->sta_config;
165+
// // This is a typical value seen in various examples.
166+
// config->sta.listen_interval = 3;
167+
// esp_wifi_set_ps(WIFI_PS_MAX_MODEM);
168+
// esp_wifi_set_config(ESP_IF_WIFI_STA, config);
169+
// }
170+
// break;
171+
// case POWER_MANAGEMENT_NONE:
172+
// esp_wifi_set_ps(WIFI_PS_NONE);
173+
// break;
174+
// case POWER_MANAGEMENT_UNKNOWN:
175+
// // This should be prevented in shared-bindings.
176+
// break;
177+
// }
144178
}
145179

146180
void common_hal_wifi_radio_set_listen_interval(wifi_radio_obj_t *self, const mp_int_t listen_interval) {

py/circuitpy_defns.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ $(filter $(SRC_PATTERNS), \
620620
supervisor/StatusBar.c \
621621
wifi/AuthMode.c \
622622
wifi/Packet.c \
623+
wifi/PowerManagement.c \
623624
)
624625

625626
ifeq ($(CIRCUITPY_BLEIO_HCI),1)

py/circuitpy_mpconfig.mk

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -707,9 +707,6 @@ CFLAGS += -DCIRCUITPY_WEB_WORKFLOW=$(CIRCUITPY_WEB_WORKFLOW)
707707
CIRCUITPY_WIFI_RADIO_SETTABLE_MAC_ADDRESS?= 1
708708
CFLAGS += -DCIRCUITPY_WIFI_RADIO_SETTABLE_MAC_ADDRESS=$(CIRCUITPY_WIFI_RADIO_SETTABLE_MAC_ADDRESS)
709709

710-
CIRCUITPY_WIFI_RADIO_SETTABLE_LISTEN_INTERVAL?= 0
711-
CFLAGS += -DCIRCUITPY_WIFI_RADIO_SETTABLE_LISTEN_INTERVAL=$(CIRCUITPY_WIFI_RADIO_SETTABLE_LISTEN_INTERVAL)
712-
713710
# tinyusb port tailored configuration
714711
CIRCUITPY_TUSB_MEM_ALIGN ?= 4
715712
CFLAGS += -DCIRCUITPY_TUSB_MEM_ALIGN=$(CIRCUITPY_TUSB_MEM_ALIGN)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// This file is part of the CircuitPython project: https://circuitpython.org
2+
//
3+
// SPDX-FileCopyrightText: Copyright (c) 2025 Dan Halbert for Adafruit Industries
4+
//
5+
// SPDX-License-Identifier: MIT
6+
7+
#include "py/enum.h"
8+
9+
#include "shared-bindings/wifi/PowerManagement.h"
10+
11+
//| class PowerManagement:
12+
//| """Power-saving options for wifi
13+
//|
14+
//| .. note:: On boards using the CYW43 radio module, the choices below correspond to the
15+
//| power management values defined in the `cyw43` module:
16+
//| `PowerManagement.MIN` is the same as `cyw43.PM_PERFORMANCE`, `PowerManagement.MAX`
17+
//| is the same as `cyw43.PM_AGGRESSIVE`, and `PowerManagement.NONE` is the same as
18+
//| `cyw43.PM_DISABLED`. If a custom value was set with `cyw43.set_power_management()`
19+
//| not corresponding to one of these three values, then `PowerManagement.UNKNOWN` will be returned.
20+
//| """
21+
//|
22+
//| MIN: PowerManagement
23+
//| """Minimum power management (default). The WiFi station wakes up to receive a beacon every DTIM period.
24+
//| The DTIM period is set by the access point."""
25+
//| MAX: PowerManagement
26+
//| """Maximum power management, at the expense of some performance. The WiFi station wakes up less often than `MIN`."""
27+
//| NONE: PowerManagement
28+
//| """No power management: the WiFi station does not sleep."""
29+
//| UNKNOWN: PowerManagement
30+
//| """Power management setting cannot be determined."""
31+
//|
32+
33+
// In order of the enum type.
34+
MAKE_ENUM_VALUE(wifi_power_management_type, power_management, NONE, POWER_MANAGEMENT_NONE);
35+
MAKE_ENUM_VALUE(wifi_power_management_type, power_management, MIN, POWER_MANAGEMENT_MIN);
36+
MAKE_ENUM_VALUE(wifi_power_management_type, power_management, MAX, POWER_MANAGEMENT_MAX);
37+
MAKE_ENUM_VALUE(wifi_power_management_type, power_management, UNKNOWN, POWER_MANAGEMENT_UNKNOWN);
38+
39+
MAKE_ENUM_MAP(wifi_power_management) {
40+
MAKE_ENUM_MAP_ENTRY(power_management, NONE),
41+
MAKE_ENUM_MAP_ENTRY(power_management, MIN),
42+
MAKE_ENUM_MAP_ENTRY(power_management, MAX),
43+
MAKE_ENUM_MAP_ENTRY(power_management, UNKNOWN),
44+
};
45+
46+
static MP_DEFINE_CONST_DICT(wifi_power_management_locals_dict, wifi_power_management_locals_table);
47+
48+
MAKE_PRINTER(wifi, wifi_power_management);
49+
50+
MAKE_ENUM_TYPE(wifi, PowerManagement, wifi_power_management);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// This file is part of the CircuitPython project: https://circuitpython.org
2+
//
3+
// SPDX-FileCopyrightText: Copyright (c) 2025 Dan Halbert for Adafruit Industries
4+
//
5+
// SPDX-License-Identifier: MIT
6+
7+
#pragma once
8+
9+
#include "py/enum.h"
10+
11+
typedef enum {
12+
POWER_MANAGEMENT_NONE = 0,
13+
POWER_MANAGEMENT_MIN = 1,
14+
POWER_MANAGEMENT_MAX = 2,
15+
// Value can't be determined.
16+
POWER_MANAGEMENT_UNKNOWN = 3,
17+
} wifi_power_management_t;
18+
19+
extern const mp_obj_type_t wifi_power_management_type;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy