net: wifi_mgmt: Add support for power save configuration
Add support for configuring power-save in Wi-Fi chipsets, supports Legacy, WMM and TWT. Signed-off-by: Krishna T <krishna.t@nordicsemi.no>
This commit is contained in:
parent
3f4597d0c9
commit
d796f23e0e
4 changed files with 579 additions and 1 deletions
|
@ -245,4 +245,75 @@ static inline const char *wifi_link_mode_txt(enum wifi_link_mode link_mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum wifi_ps {
|
||||||
|
WIFI_PS_DISABLED = 0,
|
||||||
|
WIFI_PS_ENABLED,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const wifi_ps2str[] = {
|
||||||
|
[WIFI_PS_DISABLED] = "Power save disabled",
|
||||||
|
[WIFI_PS_ENABLED] = "Power save enabled",
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wifi_ps_mode {
|
||||||
|
WIFI_PS_MODE_LEGACY = 0,
|
||||||
|
/* This has to be configured before connecting to the AP,
|
||||||
|
* as support for ADDTS action frames is not available.
|
||||||
|
*/
|
||||||
|
WIFI_PS_MODE_WMM,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const wifi_ps_mode2str[] = {
|
||||||
|
[WIFI_PS_MODE_LEGACY] = "Legacy power save",
|
||||||
|
[WIFI_PS_MODE_WMM] = "WMM power save",
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wifi_twt_operation {
|
||||||
|
WIFI_TWT_SETUP = 0,
|
||||||
|
WIFI_TWT_TEARDOWN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const wifi_twt_operation2str[] = {
|
||||||
|
[WIFI_TWT_SETUP] = "TWT setup",
|
||||||
|
[WIFI_TWT_TEARDOWN] = "TWT teardown",
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wifi_twt_negotiation_type {
|
||||||
|
WIFI_TWT_INDIVIDUAL = 0,
|
||||||
|
WIFI_TWT_BROADCAST,
|
||||||
|
WIFI_TWT_WAKE_TBTT
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const wifi_twt_negotiation_type2str[] = {
|
||||||
|
[WIFI_TWT_INDIVIDUAL] = "TWT individual negotiation",
|
||||||
|
[WIFI_TWT_BROADCAST] = "TWT broadcast negotiation",
|
||||||
|
[WIFI_TWT_WAKE_TBTT] = "TWT wake TBTT negotiation",
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wifi_twt_setup_cmd {
|
||||||
|
/* TWT Requests */
|
||||||
|
WIFI_TWT_SETUP_CMD_REQUEST = 0,
|
||||||
|
WIFI_TWT_SETUP_CMD_SUGGEST,
|
||||||
|
WIFI_TWT_SETUP_CMD_DEMAND,
|
||||||
|
/* TWT Responses */
|
||||||
|
WIFI_TWT_SETUP_CMD_GROUPING,
|
||||||
|
WIFI_TWT_SETUP_CMD_ACCEPT,
|
||||||
|
WIFI_TWT_SETUP_CMD_ALTERNATE,
|
||||||
|
WIFI_TWT_SETUP_CMD_DICTATE,
|
||||||
|
WIFI_TWT_SETUP_CMD_REJECT,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const wifi_twt_setup_cmd2str[] = {
|
||||||
|
/* TWT Requests */
|
||||||
|
[WIFI_TWT_SETUP_CMD_REQUEST] = "TWT request",
|
||||||
|
[WIFI_TWT_SETUP_CMD_SUGGEST] = "TWT suggest",
|
||||||
|
[WIFI_TWT_SETUP_CMD_DEMAND] = "TWT demand",
|
||||||
|
/* TWT Responses */
|
||||||
|
[WIFI_TWT_SETUP_CMD_GROUPING] = "TWT grouping",
|
||||||
|
[WIFI_TWT_SETUP_CMD_ACCEPT] = "TWT accept",
|
||||||
|
[WIFI_TWT_SETUP_CMD_ALTERNATE] = "TWT alternate",
|
||||||
|
[WIFI_TWT_SETUP_CMD_DICTATE] = "TWT dictate",
|
||||||
|
[WIFI_TWT_SETUP_CMD_REJECT] = "TWT reject",
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* ZEPHYR_INCLUDE_NET_WIFI_H_ */
|
#endif /* ZEPHYR_INCLUDE_NET_WIFI_H_ */
|
||||||
|
|
|
@ -36,6 +36,10 @@ enum net_request_wifi_cmd {
|
||||||
NET_REQUEST_WIFI_CMD_AP_ENABLE,
|
NET_REQUEST_WIFI_CMD_AP_ENABLE,
|
||||||
NET_REQUEST_WIFI_CMD_AP_DISABLE,
|
NET_REQUEST_WIFI_CMD_AP_DISABLE,
|
||||||
NET_REQUEST_WIFI_CMD_IFACE_STATUS,
|
NET_REQUEST_WIFI_CMD_IFACE_STATUS,
|
||||||
|
NET_REQUEST_WIFI_CMD_PS,
|
||||||
|
NET_REQUEST_WIFI_CMD_PS_MODE,
|
||||||
|
NET_REQUEST_WIFI_CMD_TWT,
|
||||||
|
NET_REQUEST_WIFI_CMD_PS_CONFIG,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NET_REQUEST_WIFI_SCAN \
|
#define NET_REQUEST_WIFI_SCAN \
|
||||||
|
@ -68,12 +72,33 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_DISABLE);
|
||||||
|
|
||||||
NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_IFACE_STATUS);
|
NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_IFACE_STATUS);
|
||||||
|
|
||||||
|
#define NET_REQUEST_WIFI_PS \
|
||||||
|
(_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_PS)
|
||||||
|
|
||||||
|
NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_PS);
|
||||||
|
|
||||||
|
#define NET_REQUEST_WIFI_PS_MODE \
|
||||||
|
(_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_PS_MODE)
|
||||||
|
|
||||||
|
NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_PS_MODE);
|
||||||
|
|
||||||
|
#define NET_REQUEST_WIFI_TWT \
|
||||||
|
(_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_TWT)
|
||||||
|
|
||||||
|
NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_TWT);
|
||||||
|
|
||||||
|
#define NET_REQUEST_WIFI_PS_CONFIG \
|
||||||
|
(_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_PS_CONFIG)
|
||||||
|
|
||||||
|
NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_PS_CONFIG);
|
||||||
|
|
||||||
enum net_event_wifi_cmd {
|
enum net_event_wifi_cmd {
|
||||||
NET_EVENT_WIFI_CMD_SCAN_RESULT = 1,
|
NET_EVENT_WIFI_CMD_SCAN_RESULT = 1,
|
||||||
NET_EVENT_WIFI_CMD_SCAN_DONE,
|
NET_EVENT_WIFI_CMD_SCAN_DONE,
|
||||||
NET_EVENT_WIFI_CMD_CONNECT_RESULT,
|
NET_EVENT_WIFI_CMD_CONNECT_RESULT,
|
||||||
NET_EVENT_WIFI_CMD_DISCONNECT_RESULT,
|
NET_EVENT_WIFI_CMD_DISCONNECT_RESULT,
|
||||||
NET_EVENT_WIFI_CMD_IFACE_STATUS,
|
NET_EVENT_WIFI_CMD_IFACE_STATUS,
|
||||||
|
NET_EVENT_WIFI_CMD_TWT,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NET_EVENT_WIFI_SCAN_RESULT \
|
#define NET_EVENT_WIFI_SCAN_RESULT \
|
||||||
|
@ -91,6 +116,8 @@ enum net_event_wifi_cmd {
|
||||||
#define NET_EVENT_WIFI_IFACE_STATUS \
|
#define NET_EVENT_WIFI_IFACE_STATUS \
|
||||||
(_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_IFACE_STATUS)
|
(_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_IFACE_STATUS)
|
||||||
|
|
||||||
|
#define NET_EVENT_WIFI_TWT \
|
||||||
|
(_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_TWT)
|
||||||
|
|
||||||
/* Each result is provided to the net_mgmt_event_callback
|
/* Each result is provided to the net_mgmt_event_callback
|
||||||
* via its info attribute (see net_mgmt.h)
|
* via its info attribute (see net_mgmt.h)
|
||||||
|
@ -144,6 +171,66 @@ struct wifi_iface_status {
|
||||||
int rssi;
|
int rssi;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wifi_ps_params {
|
||||||
|
enum wifi_ps enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wifi_ps_mode_params {
|
||||||
|
enum wifi_ps_mode mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wifi_twt_params {
|
||||||
|
enum wifi_twt_operation operation;
|
||||||
|
enum wifi_twt_negotiation_type negotiation_type;
|
||||||
|
enum wifi_twt_setup_cmd setup_cmd;
|
||||||
|
/* Map requests to responses */
|
||||||
|
uint8_t dialog_token;
|
||||||
|
/* Map setup with teardown */
|
||||||
|
uint8_t flow_id;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
/* Interval = Wake up time + Sleeping time */
|
||||||
|
uint32_t twt_interval_ms;
|
||||||
|
bool responder;
|
||||||
|
bool trigger;
|
||||||
|
bool implicit;
|
||||||
|
bool announce;
|
||||||
|
/* Wake up time */
|
||||||
|
uint8_t twt_wake_interval_ms;
|
||||||
|
} setup;
|
||||||
|
struct {
|
||||||
|
/* Only for Teardown */
|
||||||
|
bool teardown_all;
|
||||||
|
} teardown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Flow ID is only 3 bits */
|
||||||
|
#define WIFI_MAX_TWT_FLOWS 8
|
||||||
|
#define WIFI_MAX_TWT_INTERVAL_MS 0x7FFFFFFF
|
||||||
|
struct wifi_twt_flow_info {
|
||||||
|
/* Interval = Wake up time + Sleeping time */
|
||||||
|
uint32_t twt_interval_ms;
|
||||||
|
/* Map requests to responses */
|
||||||
|
uint8_t dialog_token;
|
||||||
|
/* Map setup with teardown */
|
||||||
|
uint8_t flow_id;
|
||||||
|
enum wifi_twt_negotiation_type negotiation_type;
|
||||||
|
bool responder;
|
||||||
|
bool trigger;
|
||||||
|
bool implicit;
|
||||||
|
bool announce;
|
||||||
|
/* Wake up time */
|
||||||
|
uint8_t twt_wake_interval_ms;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wifi_ps_config {
|
||||||
|
struct wifi_twt_flow_info twt_flows[WIFI_MAX_TWT_FLOWS];
|
||||||
|
bool enabled;
|
||||||
|
enum wifi_ps_mode mode;
|
||||||
|
char num_twt_flows;
|
||||||
|
};
|
||||||
|
|
||||||
#include <zephyr/net/net_if.h>
|
#include <zephyr/net/net_if.h>
|
||||||
|
|
||||||
typedef void (*scan_result_cb_t)(struct net_if *iface, int status,
|
typedef void (*scan_result_cb_t)(struct net_if *iface, int status,
|
||||||
|
@ -177,6 +264,10 @@ struct net_wifi_mgmt_offload {
|
||||||
#ifdef CONFIG_NET_STATISTICS_WIFI
|
#ifdef CONFIG_NET_STATISTICS_WIFI
|
||||||
int (*get_stats)(const struct device *dev, struct net_stats_wifi *stats);
|
int (*get_stats)(const struct device *dev, struct net_stats_wifi *stats);
|
||||||
#endif /* CONFIG_NET_STATISTICS_WIFI */
|
#endif /* CONFIG_NET_STATISTICS_WIFI */
|
||||||
|
int (*set_power_save)(const struct device *dev, struct wifi_ps_params *params);
|
||||||
|
int (*set_power_save_mode)(const struct device *dev, struct wifi_ps_mode_params *params);
|
||||||
|
int (*set_twt)(const struct device *dev, struct wifi_twt_params *params);
|
||||||
|
int (*get_power_save_config)(const struct device *dev, struct wifi_ps_config *config);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Make sure that the network interface API is properly setup inside
|
/* Make sure that the network interface API is properly setup inside
|
||||||
|
@ -188,6 +279,8 @@ void wifi_mgmt_raise_connect_result_event(struct net_if *iface, int status);
|
||||||
void wifi_mgmt_raise_disconnect_result_event(struct net_if *iface, int status);
|
void wifi_mgmt_raise_disconnect_result_event(struct net_if *iface, int status);
|
||||||
void wifi_mgmt_raise_iface_status_event(struct net_if *iface,
|
void wifi_mgmt_raise_iface_status_event(struct net_if *iface,
|
||||||
struct wifi_iface_status *iface_status);
|
struct wifi_iface_status *iface_status);
|
||||||
|
void wifi_mgmt_raise_twt_event(struct net_if *iface,
|
||||||
|
struct wifi_twt_params *twt_params);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -228,3 +228,82 @@ static int wifi_iface_stats(uint32_t mgmt_request, struct net_if *iface,
|
||||||
}
|
}
|
||||||
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_WIFI, wifi_iface_stats);
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_WIFI, wifi_iface_stats);
|
||||||
#endif /* CONFIG_NET_STATISTICS_WIFI */
|
#endif /* CONFIG_NET_STATISTICS_WIFI */
|
||||||
|
|
||||||
|
static int wifi_set_power_save(uint32_t mgmt_request, struct net_if *iface,
|
||||||
|
void *data, size_t len)
|
||||||
|
{
|
||||||
|
const struct device *dev = net_if_get_device(iface);
|
||||||
|
struct net_wifi_mgmt_offload *off_api =
|
||||||
|
(struct net_wifi_mgmt_offload *) dev->api;
|
||||||
|
struct wifi_ps_params *ps_params = data;
|
||||||
|
|
||||||
|
if (off_api == NULL || off_api->set_power_save == NULL) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return off_api->set_power_save(dev, ps_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_PS, wifi_set_power_save);
|
||||||
|
|
||||||
|
static int wifi_get_power_save_config(uint32_t mgmt_request, struct net_if *iface,
|
||||||
|
void *data, size_t len)
|
||||||
|
{
|
||||||
|
const struct device *dev = net_if_get_device(iface);
|
||||||
|
struct net_wifi_mgmt_offload *off_api =
|
||||||
|
(struct net_wifi_mgmt_offload *) dev->api;
|
||||||
|
struct wifi_ps_config *ps_config = data;
|
||||||
|
|
||||||
|
if (off_api == NULL || off_api->get_power_save_config == NULL) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data || len != sizeof(*ps_config)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return off_api->get_power_save_config(dev, ps_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_PS_CONFIG, wifi_get_power_save_config);
|
||||||
|
|
||||||
|
static int wifi_set_power_save_mode(uint32_t mgmt_request, struct net_if *iface,
|
||||||
|
void *data, size_t len)
|
||||||
|
{
|
||||||
|
const struct device *dev = net_if_get_device(iface);
|
||||||
|
struct net_wifi_mgmt_offload *off_api =
|
||||||
|
(struct net_wifi_mgmt_offload *) dev->api;
|
||||||
|
struct wifi_ps_mode_params *ps_mode_params = data;
|
||||||
|
|
||||||
|
if (off_api == NULL || off_api->set_power_save_mode == NULL) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return off_api->set_power_save_mode(dev, ps_mode_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_PS_MODE, wifi_set_power_save_mode);
|
||||||
|
|
||||||
|
static int wifi_set_twt(uint32_t mgmt_request, struct net_if *iface,
|
||||||
|
void *data, size_t len)
|
||||||
|
{
|
||||||
|
const struct device *dev = net_if_get_device(iface);
|
||||||
|
struct net_wifi_mgmt_offload *off_api =
|
||||||
|
(struct net_wifi_mgmt_offload *) dev->api;
|
||||||
|
struct wifi_twt_params *twt_params = data;
|
||||||
|
|
||||||
|
if (off_api == NULL || off_api->set_twt == NULL) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return off_api->set_twt(dev, twt_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_TWT, wifi_set_twt);
|
||||||
|
|
||||||
|
void wifi_mgmt_raise_twt_event(struct net_if *iface, struct wifi_twt_params *twt_params)
|
||||||
|
{
|
||||||
|
net_mgmt_event_notify_with_info(NET_EVENT_WIFI_TWT,
|
||||||
|
iface, twt_params,
|
||||||
|
sizeof(struct wifi_twt_params));
|
||||||
|
}
|
||||||
|
|
|
@ -29,7 +29,8 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF);
|
||||||
#define WIFI_SHELL_MGMT_EVENTS (NET_EVENT_WIFI_SCAN_RESULT | \
|
#define WIFI_SHELL_MGMT_EVENTS (NET_EVENT_WIFI_SCAN_RESULT | \
|
||||||
NET_EVENT_WIFI_SCAN_DONE | \
|
NET_EVENT_WIFI_SCAN_DONE | \
|
||||||
NET_EVENT_WIFI_CONNECT_RESULT | \
|
NET_EVENT_WIFI_CONNECT_RESULT | \
|
||||||
NET_EVENT_WIFI_DISCONNECT_RESULT)
|
NET_EVENT_WIFI_DISCONNECT_RESULT | \
|
||||||
|
NET_EVENT_WIFI_TWT)
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
const struct shell *sh;
|
const struct shell *sh;
|
||||||
|
@ -58,6 +59,24 @@ static struct net_mgmt_event_callback wifi_shell_mgmt_cb;
|
||||||
} \
|
} \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
|
static bool parse_number(const struct shell *sh, long *param, char *str, int min, int max)
|
||||||
|
{
|
||||||
|
char *endptr;
|
||||||
|
char *str_tmp = str;
|
||||||
|
long num = strtol(str_tmp, &endptr, 10);
|
||||||
|
|
||||||
|
if (*endptr != '\0') {
|
||||||
|
print(sh, SHELL_ERROR, "Invalid number: %s", str_tmp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((num) < (min) || (num) > (max)) {
|
||||||
|
print(sh, SHELL_WARNING, "Value out of range: %s, (%d-%d)", str_tmp, min, max);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*param = num;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_wifi_scan_result(struct net_mgmt_event_callback *cb)
|
static void handle_wifi_scan_result(struct net_mgmt_event_callback *cb)
|
||||||
{
|
{
|
||||||
const struct wifi_scan_result *entry =
|
const struct wifi_scan_result *entry =
|
||||||
|
@ -129,6 +148,24 @@ static void handle_wifi_disconnect_result(struct net_mgmt_event_callback *cb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb)
|
||||||
|
{
|
||||||
|
const struct wifi_twt_params *resp =
|
||||||
|
(const struct wifi_twt_params *)cb->info;
|
||||||
|
|
||||||
|
print(context.sh, SHELL_NORMAL, "TWT response: %s for dialog: %d and flow: %d\n",
|
||||||
|
wifi_twt_setup_cmd2str[resp->setup_cmd], resp->dialog_token, resp->flow_id);
|
||||||
|
|
||||||
|
/* If accepted, then no need to print TWT params */
|
||||||
|
if (resp->setup_cmd != WIFI_TWT_SETUP_CMD_ACCEPT) {
|
||||||
|
print(context.sh, SHELL_NORMAL,
|
||||||
|
"TWT parameters: trigger: %s wake_interval_ms: %d, interval_ms: %d\n",
|
||||||
|
resp->setup.trigger ? "trigger" : "no_trigger",
|
||||||
|
resp->setup.twt_wake_interval_ms,
|
||||||
|
resp->setup.twt_interval_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb,
|
static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb,
|
||||||
uint32_t mgmt_event, struct net_if *iface)
|
uint32_t mgmt_event, struct net_if *iface)
|
||||||
{
|
{
|
||||||
|
@ -145,6 +182,9 @@ static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb,
|
||||||
case NET_EVENT_WIFI_DISCONNECT_RESULT:
|
case NET_EVENT_WIFI_DISCONNECT_RESULT:
|
||||||
handle_wifi_disconnect_result(cb);
|
handle_wifi_disconnect_result(cb);
|
||||||
break;
|
break;
|
||||||
|
case NET_EVENT_WIFI_TWT:
|
||||||
|
handle_wifi_twt_event(cb);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -383,6 +423,277 @@ static int cmd_wifi_stats(const struct shell *sh, size_t argc, char *argv[])
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct net_if *iface = net_if_get_default();
|
||||||
|
struct wifi_ps_params params = { 0 };
|
||||||
|
|
||||||
|
context.sh = sh;
|
||||||
|
|
||||||
|
if (argc > 2) {
|
||||||
|
shell_fprintf(sh, SHELL_WARNING, "Invalid number of arguments\n");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc == 1) {
|
||||||
|
struct wifi_ps_config config = { 0 };
|
||||||
|
|
||||||
|
if (net_mgmt(NET_REQUEST_WIFI_PS_CONFIG, iface,
|
||||||
|
&config, sizeof(config))) {
|
||||||
|
shell_fprintf(sh, SHELL_WARNING, "Failed to get PS config\n");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "PS status: %s\n",
|
||||||
|
wifi_ps_mode2str[config.enabled]);
|
||||||
|
if (config.enabled) {
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "PS mode: %s\n",
|
||||||
|
wifi_ps_mode2str[config.mode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.num_twt_flows == 0) {
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "No TWT flows\n");
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < config.num_twt_flows; i++) {
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "TWT Dialog token: %d\n",
|
||||||
|
config.twt_flows[i].dialog_token);
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "TWT flow ID: %d\n",
|
||||||
|
config.twt_flows[i].flow_id);
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "TWT negotiation type: %s\n",
|
||||||
|
wifi_twt_negotiation_type2str[
|
||||||
|
config.twt_flows[i].negotiation_type]);
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "TWT responder: %s\n",
|
||||||
|
config.twt_flows[i].responder ? "true" : "false");
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "TWT implicit: %s\n",
|
||||||
|
config.twt_flows[i].implicit ? "true" : "false");
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "TWT trigger: %s\n",
|
||||||
|
config.twt_flows[i].trigger ? "true" : "false");
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "TWT announce: %s\n",
|
||||||
|
config.twt_flows[i].announce ? "true" : "false");
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "TWT wake interval: %d ms\n",
|
||||||
|
config.twt_flows[i].twt_wake_interval_ms);
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "TWT interval: %d ms\n",
|
||||||
|
config.twt_flows[i].twt_interval_ms);
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "========================\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strncmp(argv[1], "on", 2)) {
|
||||||
|
params.enabled = WIFI_PS_ENABLED;
|
||||||
|
} else if (!strncmp(argv[1], "off", 3)) {
|
||||||
|
params.enabled = WIFI_PS_DISABLED;
|
||||||
|
} else {
|
||||||
|
shell_fprintf(sh, SHELL_WARNING, "Invalid argument\n");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (net_mgmt(NET_REQUEST_WIFI_PS, iface, ¶ms, sizeof(params))) {
|
||||||
|
shell_fprintf(sh, SHELL_WARNING, "Power save %s failed\n",
|
||||||
|
params.enabled ? "enable" : "disable");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "%s\n", wifi_ps2str[params.enabled]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_wifi_ps_mode(const struct shell *sh, size_t argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct net_if *iface = net_if_get_default();
|
||||||
|
struct wifi_ps_mode_params params = { 0 };
|
||||||
|
|
||||||
|
context.sh = sh;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
shell_fprintf(sh, SHELL_WARNING, "Invalid number of arguments\n");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strncmp(argv[1], "legacy", 6)) {
|
||||||
|
params.mode = WIFI_PS_MODE_LEGACY;
|
||||||
|
} else if (!strncmp(argv[1], "wmm", 3)) {
|
||||||
|
params.mode = WIFI_PS_MODE_WMM;
|
||||||
|
} else {
|
||||||
|
shell_fprintf(sh, SHELL_WARNING, "Invalid power save mode\n");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (net_mgmt(NET_REQUEST_WIFI_PS_MODE, iface, ¶ms, sizeof(params))) {
|
||||||
|
shell_fprintf(sh, SHELL_WARNING, "%s failed\n", wifi_ps_mode2str[params.mode]);
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "%s\n", wifi_ps_mode2str[params.mode]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_wifi_twt_setup_quick(const struct shell *sh, size_t argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
struct net_if *iface = net_if_get_default();
|
||||||
|
struct wifi_twt_params params = { 0 };
|
||||||
|
int idx = 1;
|
||||||
|
|
||||||
|
context.sh = sh;
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
shell_fprintf(sh, SHELL_WARNING, "Invalid number of arguments\n");
|
||||||
|
shell_help(sh);
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sensible defaults */
|
||||||
|
params.operation = WIFI_TWT_SETUP;
|
||||||
|
params.negotiation_type = WIFI_TWT_INDIVIDUAL;
|
||||||
|
params.setup_cmd = WIFI_TWT_SETUP_CMD_REQUEST;
|
||||||
|
params.dialog_token = 1;
|
||||||
|
params.flow_id = 1;
|
||||||
|
params.setup.responder = 0;
|
||||||
|
params.setup.implicit = 1;
|
||||||
|
params.setup.trigger = 1;
|
||||||
|
params.setup.announce = 0;
|
||||||
|
|
||||||
|
if (!parse_number(sh, (long *)¶ms.setup.twt_wake_interval_ms, argv[idx++], 1, 255) ||
|
||||||
|
!parse_number(sh, (long *)¶ms.setup.twt_interval_ms, argv[idx++], 1,
|
||||||
|
WIFI_MAX_TWT_INTERVAL_MS))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (net_mgmt(NET_REQUEST_WIFI_TWT, iface, ¶ms, sizeof(params))) {
|
||||||
|
shell_fprintf(sh, SHELL_WARNING, "%s with %s failed\n",
|
||||||
|
wifi_twt_operation2str[params.operation],
|
||||||
|
wifi_twt_negotiation_type2str[params.negotiation_type]);
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s with dg: %d, flow_id: %d requested\n",
|
||||||
|
wifi_twt_operation2str[params.operation],
|
||||||
|
params.dialog_token, params.flow_id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int cmd_wifi_twt_setup(const struct shell *sh, size_t argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
struct net_if *iface = net_if_get_default();
|
||||||
|
struct wifi_twt_params params = { 0 };
|
||||||
|
int idx = 1;
|
||||||
|
long neg_type;
|
||||||
|
long setup_cmd;
|
||||||
|
|
||||||
|
context.sh = sh;
|
||||||
|
|
||||||
|
if (argc != 11) {
|
||||||
|
shell_fprintf(sh, SHELL_WARNING, "Invalid number of arguments\n");
|
||||||
|
shell_help(sh);
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
params.operation = WIFI_TWT_SETUP;
|
||||||
|
|
||||||
|
if (!parse_number(sh, &neg_type, argv[idx++], WIFI_TWT_INDIVIDUAL,
|
||||||
|
WIFI_TWT_WAKE_TBTT) ||
|
||||||
|
!parse_number(sh, &setup_cmd, argv[idx++], WIFI_TWT_SETUP_CMD_REQUEST,
|
||||||
|
WIFI_TWT_SETUP_CMD_DEMAND) ||
|
||||||
|
!parse_number(sh, (long *)¶ms.dialog_token, argv[idx++], 1, 255) ||
|
||||||
|
!parse_number(sh, (long *)¶ms.flow_id, argv[idx++], 1, WIFI_MAX_TWT_FLOWS) ||
|
||||||
|
!parse_number(sh, (long *)¶ms.setup.responder, argv[idx++], 0, 1) ||
|
||||||
|
!parse_number(sh, (long *)¶ms.setup.trigger, argv[idx++], 0, 1) ||
|
||||||
|
!parse_number(sh, (long *)¶ms.setup.implicit, argv[idx++], 0, 1) ||
|
||||||
|
!parse_number(sh, (long *)¶ms.setup.announce, argv[idx++], 0, 1) ||
|
||||||
|
!parse_number(sh, (long *)¶ms.setup.twt_wake_interval_ms, argv[idx++], 1, 255) ||
|
||||||
|
!parse_number(sh, (long *)¶ms.setup.twt_interval_ms, argv[idx++], 1,
|
||||||
|
WIFI_MAX_TWT_INTERVAL_MS))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
params.negotiation_type = neg_type;
|
||||||
|
params.setup_cmd = setup_cmd;
|
||||||
|
|
||||||
|
if (net_mgmt(NET_REQUEST_WIFI_TWT, iface, ¶ms, sizeof(params))) {
|
||||||
|
shell_fprintf(sh, SHELL_WARNING, "%s with %s failed\n",
|
||||||
|
wifi_twt_operation2str[params.operation],
|
||||||
|
wifi_twt_negotiation_type2str[params.negotiation_type]);
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s with dg: %d, flow_id: %d requested\n",
|
||||||
|
wifi_twt_operation2str[params.operation],
|
||||||
|
params.dialog_token, params.flow_id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_wifi_twt_teardown(const struct shell *sh, size_t argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
struct net_if *iface = net_if_get_default();
|
||||||
|
struct wifi_twt_params params = { 0 };
|
||||||
|
long neg_type = 0;
|
||||||
|
long setup_cmd = 0;
|
||||||
|
|
||||||
|
context.sh = sh;
|
||||||
|
int idx = 1;
|
||||||
|
|
||||||
|
if (argc != 5) {
|
||||||
|
shell_fprintf(sh, SHELL_WARNING, "Invalid number of arguments\n");
|
||||||
|
shell_help(sh);
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
params.operation = WIFI_TWT_TEARDOWN;
|
||||||
|
neg_type = params.negotiation_type;
|
||||||
|
setup_cmd = params.setup_cmd;
|
||||||
|
|
||||||
|
if (!parse_number(sh, &neg_type, argv[idx++], WIFI_TWT_INDIVIDUAL,
|
||||||
|
WIFI_TWT_WAKE_TBTT) ||
|
||||||
|
!parse_number(sh, &setup_cmd, argv[idx++], WIFI_TWT_SETUP_CMD_REQUEST,
|
||||||
|
WIFI_TWT_SETUP_CMD_DEMAND) ||
|
||||||
|
!parse_number(sh, (long *)¶ms.dialog_token, argv[idx++], 1, 255) ||
|
||||||
|
!parse_number(sh, (long *)¶ms.flow_id, argv[idx++], 1, WIFI_MAX_TWT_FLOWS))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (net_mgmt(NET_REQUEST_WIFI_TWT, iface, ¶ms, sizeof(params))) {
|
||||||
|
shell_fprintf(sh, SHELL_WARNING, "%s with %s failed\n",
|
||||||
|
wifi_twt_operation2str[params.operation],
|
||||||
|
wifi_twt_negotiation_type2str[params.negotiation_type]);
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s with dg: %d, flow_id: %d requested\n",
|
||||||
|
wifi_twt_operation2str[params.operation],
|
||||||
|
params.dialog_token, params.flow_id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_wifi_twt_teardown_all(const struct shell *sh, size_t argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
struct net_if *iface = net_if_get_default();
|
||||||
|
struct wifi_twt_params params = { 0 };
|
||||||
|
|
||||||
|
context.sh = sh;
|
||||||
|
|
||||||
|
params.operation = WIFI_TWT_TEARDOWN;
|
||||||
|
params.teardown.teardown_all = 1;
|
||||||
|
|
||||||
|
if (net_mgmt(NET_REQUEST_WIFI_TWT, iface, ¶ms, sizeof(params))) {
|
||||||
|
shell_fprintf(sh, SHELL_WARNING, "%s with %s failed\n",
|
||||||
|
wifi_twt_operation2str[params.operation],
|
||||||
|
wifi_twt_negotiation_type2str[params.negotiation_type]);
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s all flows\n",
|
||||||
|
wifi_twt_operation2str[params.operation]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc,
|
static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc,
|
||||||
char *argv[])
|
char *argv[])
|
||||||
|
@ -433,6 +744,26 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap,
|
||||||
SHELL_SUBCMD_SET_END
|
SHELL_SUBCMD_SET_END
|
||||||
);
|
);
|
||||||
|
|
||||||
|
SHELL_STATIC_SUBCMD_SET_CREATE(wifi_twt_ops,
|
||||||
|
SHELL_CMD(quick_setup, NULL, " Start a TWT flow with defaults:\n"
|
||||||
|
"<twt_wake_interval_ms: 1-256ms> <twt_interval_ms: 1ms-2^32ms>\n",
|
||||||
|
cmd_wifi_twt_setup_quick),
|
||||||
|
SHELL_CMD(setup, NULL, " Start a TWT flow:\n"
|
||||||
|
"<negotiation_type, 0: Individual, 1: Broadcast, 2: Wake TBTT>\n"
|
||||||
|
"<setup_cmd: 0: Request, 1: Suggest, 2: Demand>\n"
|
||||||
|
"<dialog_token: 1-255> <flow_id: 1-255> <responder: 0/1> <trigger: 0/1> <implicit:0/1> "
|
||||||
|
"<announce: 0/1> <twt_wake_interval_ms: 1-256ms> <twt_interval_ms: 1ms-2^32ms>\n",
|
||||||
|
cmd_wifi_twt_setup),
|
||||||
|
SHELL_CMD(teardown, NULL, " Teardown a TWT flow:\n"
|
||||||
|
"<negotiation_type, 0: Individual, 1: Broadcast, 2: Wake TBTT>\n"
|
||||||
|
"<setup_cmd: 0: Request, 1: Suggest, 2: Demand>\n"
|
||||||
|
"<dialog_token: 1-255> <flow_id: 1-255>\n",
|
||||||
|
cmd_wifi_twt_teardown),
|
||||||
|
SHELL_CMD(teardown_all, NULL, " Teardown all TWT flows\n",
|
||||||
|
cmd_wifi_twt_teardown_all),
|
||||||
|
SHELL_SUBCMD_SET_END
|
||||||
|
);
|
||||||
|
|
||||||
SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands,
|
SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands,
|
||||||
SHELL_CMD(ap, &wifi_cmd_ap, "Access Point mode commands", NULL),
|
SHELL_CMD(ap, &wifi_cmd_ap, "Access Point mode commands", NULL),
|
||||||
SHELL_CMD(connect, NULL,
|
SHELL_CMD(connect, NULL,
|
||||||
|
@ -447,9 +778,13 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands,
|
||||||
cmd_wifi_connect),
|
cmd_wifi_connect),
|
||||||
SHELL_CMD(disconnect, NULL, "Disconnect from the Wi-Fi AP",
|
SHELL_CMD(disconnect, NULL, "Disconnect from the Wi-Fi AP",
|
||||||
cmd_wifi_disconnect),
|
cmd_wifi_disconnect),
|
||||||
|
SHELL_CMD(ps, NULL, "Configure Wi-Fi power save on/off, no arguments will dump config",
|
||||||
|
cmd_wifi_ps),
|
||||||
|
SHELL_CMD(ps_mode, NULL, "Configure Wi-Fi power save mode legacy/wmm", cmd_wifi_ps_mode),
|
||||||
SHELL_CMD(scan, NULL, "Scan for Wi-Fi APs", cmd_wifi_scan),
|
SHELL_CMD(scan, NULL, "Scan for Wi-Fi APs", cmd_wifi_scan),
|
||||||
SHELL_CMD(statistics, NULL, "Wi-Fi interface statistics", cmd_wifi_stats),
|
SHELL_CMD(statistics, NULL, "Wi-Fi interface statistics", cmd_wifi_stats),
|
||||||
SHELL_CMD(status, NULL, "Status of the Wi-Fi interface", cmd_wifi_status),
|
SHELL_CMD(status, NULL, "Status of the Wi-Fi interface", cmd_wifi_status),
|
||||||
|
SHELL_CMD(twt, &wifi_twt_ops, "Manage TWT flows", NULL),
|
||||||
SHELL_SUBCMD_SET_END
|
SHELL_SUBCMD_SET_END
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue