572 lines
15 KiB
C
Executable File
572 lines
15 KiB
C
Executable File
/*
|
|
* Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
|
|
* its contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "common/framework/platform_init.h"
|
|
#include <stdio.h>
|
|
#include "kernel/os/os.h"
|
|
|
|
#include "driver/chip/hal_clock.h"
|
|
#include "board_config.h"
|
|
|
|
#include "driver/chip/hal_prcm.h"
|
|
#include "driver/chip/hal_gpio.h"
|
|
#include "driver/chip/hal_wakeup.h"
|
|
|
|
#include "pm/pm.h"
|
|
|
|
#include "common/framework/net_ctrl.h"
|
|
#include "net/wlan/wlan_ext_req.h"
|
|
#include "net/wlan/wlan_defs.h"
|
|
|
|
/* set dtim*/
|
|
#define WLAN_LOW_POWER_LISTEN_INTERVAL 8
|
|
/* set beacon freq offset time*/
|
|
#define WLAN_LOW_POWER_BCN_FREQ_OFFS_TIME (40 * WLAN_LOW_POWER_LISTEN_INTERVAL)
|
|
|
|
char *sta_ssid = "wlan_low_power";
|
|
char *sta_psk = "12345678";
|
|
uint8_t wlp_ap_connected;
|
|
void wlp_net_ctrl_msg_proc(uint32_t event, uint32_t data, void *arg)
|
|
{
|
|
uint16_t type = EVENT_SUBTYPE(event);
|
|
|
|
switch (type) {
|
|
case NET_CTRL_MSG_WLAN_CONNECTED:
|
|
wlp_ap_connected = 1;
|
|
break;
|
|
case NET_CTRL_MSG_WLAN_DISCONNECTED:
|
|
wlp_ap_connected = 0;
|
|
break;
|
|
case NET_CTRL_MSG_WLAN_SCAN_SUCCESS:
|
|
break;
|
|
case NET_CTRL_MSG_WLAN_SCAN_FAILED:
|
|
break;
|
|
case NET_CTRL_MSG_WLAN_4WAY_HANDSHAKE_FAILED:
|
|
wlp_ap_connected = 0;
|
|
break;
|
|
case NET_CTRL_MSG_WLAN_CONNECT_FAILED:
|
|
wlp_ap_connected = 0;
|
|
break;
|
|
case NET_CTRL_MSG_WLAN_CONNECTION_LOSS:
|
|
wlp_ap_connected = 0;
|
|
break;
|
|
case NET_CTRL_MSG_NETWORK_UP:
|
|
break;
|
|
case NET_CTRL_MSG_NETWORK_DOWN:
|
|
wlp_ap_connected = 0;
|
|
break;
|
|
default:
|
|
printf("unknown msg (%u, %u)\n", type, data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
int wlp_net_ctrl_init(void)
|
|
{
|
|
observer_base *ob = sys_callback_observer_create(CTRL_MSG_TYPE_NETWORK,
|
|
NET_CTRL_MSG_ALL,
|
|
wlp_net_ctrl_msg_proc,
|
|
NULL);
|
|
if (ob == NULL)
|
|
return -1;
|
|
if (sys_ctrl_attach(ob) != 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void wlp_connect_ap(void)
|
|
{
|
|
/* create net ctrl for wlan low power examle */
|
|
wlp_net_ctrl_init();
|
|
|
|
/* switch to sta mode */
|
|
net_switch_mode(WLAN_MODE_STA);
|
|
|
|
/* set ssid and password to wlan */
|
|
wlan_sta_set((uint8_t *)sta_ssid, strlen(sta_ssid), (uint8_t *)sta_psk);
|
|
|
|
/* start scan and connect to ap automatically */
|
|
wlan_sta_enable();
|
|
|
|
return;
|
|
}
|
|
|
|
void wlp_set_wlan_to_active_mode(void)
|
|
{
|
|
int ret;
|
|
uint32_t ps_mode, ps_ip, ps_cp;
|
|
wlan_ext_ps_cfg_t ps_cfg;
|
|
|
|
ps_mode = 0;
|
|
ps_ip = 0;
|
|
ps_cp = 0;
|
|
|
|
memset(&ps_cfg, 0, sizeof(wlan_ext_ps_cfg_t));
|
|
ps_cfg.ps_mode = ps_mode;
|
|
ps_cfg.ps_idle_period = ps_ip;
|
|
ps_cfg.ps_change_period = ps_cp;
|
|
ret = wlan_ext_request(wlan_netif_get(WLAN_MODE_NONE),
|
|
WLAN_EXT_CMD_SET_PS_CFG, (uint32_t)&ps_cfg);
|
|
|
|
if (ret == -2) {
|
|
printf("%s: invalid arg\n", __func__);
|
|
return;
|
|
} else if (ret == -1) {
|
|
printf("%s: exec failed\n", __func__);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void wlp_set_beacon_window(void)
|
|
{
|
|
int ret;
|
|
int bcn_win;
|
|
|
|
bcn_win = 2300;
|
|
|
|
ret = wlan_ext_request(wlan_netif_get(WLAN_MODE_NONE),
|
|
WLAN_EXT_CMD_SET_BCN_WIN_US, bcn_win);
|
|
|
|
if (ret == -2) {
|
|
printf("%s: invalid arg\n", __func__);
|
|
return;
|
|
} else if (ret == -1) {
|
|
printf("%s: exec failed\n", __func__);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void wlp_count_ap_beacon_delay(void)
|
|
{
|
|
int ret, i;
|
|
unsigned int sum_cnt = 0;
|
|
int sum_avg = 0;
|
|
wlan_ext_bcn_status_t bcn_status;
|
|
struct netif *nif = wlan_netif_get(WLAN_MODE_NONE);
|
|
char dly_info[][20] = {
|
|
"(<0 )",
|
|
"(<500us )",
|
|
"(<1000us )",
|
|
"(<2000us )",
|
|
"(<4000us )",
|
|
"(<8000us )",
|
|
"(<16000us)",
|
|
"(>16000us)",
|
|
};
|
|
|
|
/* get counters for reset */
|
|
memset(&bcn_status, 0, sizeof(wlan_ext_bcn_status_t));
|
|
ret = wlan_ext_request(nif, WLAN_EXT_CMD_GET_BCN_STATUS,
|
|
(uint32_t)&bcn_status);
|
|
|
|
/* wait 10s for stats */
|
|
OS_Sleep(10);
|
|
|
|
/* get counters */
|
|
memset(&bcn_status, 0, sizeof(wlan_ext_bcn_status_t));
|
|
ret = wlan_ext_request(nif, WLAN_EXT_CMD_GET_BCN_STATUS,
|
|
(uint32_t)&bcn_status);
|
|
if (ret == -2) {
|
|
printf("%s: invalid arg\n", __func__);
|
|
return;
|
|
} else if (ret == -1) {
|
|
printf("%s: exec failed\n", __func__);
|
|
return;
|
|
}
|
|
|
|
printf("\nAPP AP Beacon Delay Stat Info=================\n");
|
|
for (i = 0; i < 8; i++) {
|
|
printf("cnt %d %s: %d\n",
|
|
i, dly_info[i],
|
|
bcn_status.bcn_delay_cnt[i]);
|
|
sum_cnt += bcn_status.bcn_delay_cnt[i];
|
|
}
|
|
|
|
if (sum_cnt)
|
|
sum_avg = bcn_status.bcn_delay_sum / sum_cnt;
|
|
|
|
printf("beacon duration: %d, rxed beacon: %d, missed beacon: %d\n",
|
|
bcn_status.bcn_duration,
|
|
bcn_status.bcn_rx_cnt,
|
|
bcn_status.bcn_miss_cnt);
|
|
printf("beacon delay stat: max %d us, avg %d us, sum %d us, cnt %d\n",
|
|
bcn_status.bcn_delay_max,
|
|
sum_avg, bcn_status.bcn_delay_sum, sum_cnt);
|
|
printf("APP AP Beacon Delay Stat Info=================\n");
|
|
|
|
return;
|
|
}
|
|
|
|
void wlp_set_dtim_period(void)
|
|
{
|
|
int ret;
|
|
uint32_t period;
|
|
|
|
period = 1;
|
|
|
|
ret = wlan_ext_request(wlan_netif_get(WLAN_MODE_NONE),
|
|
WLAN_EXT_CMD_SET_PM_DTIM, period);
|
|
|
|
if (ret == -2) {
|
|
printf("%s: invalid arg\n", __func__);
|
|
return;
|
|
} else if (ret == -1) {
|
|
printf("%s: exec failed\n", __func__);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void wlp_set_listen_interval(void)
|
|
{
|
|
int ret;
|
|
uint32_t listen_interval;
|
|
|
|
listen_interval = WLAN_LOW_POWER_LISTEN_INTERVAL;
|
|
|
|
ret = wlan_ext_request(wlan_netif_get(WLAN_MODE_NONE),
|
|
WLAN_EXT_CMD_SET_LISTEN_INTERVAL, listen_interval);
|
|
|
|
if (ret == -2) {
|
|
printf("%s: invalid arg\n", __func__);
|
|
return;
|
|
} else if (ret == -1) {
|
|
printf("%s: exec failed\n", __func__);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void wlp_set_bcn_freq_offs_time(void)
|
|
{
|
|
int ret;
|
|
int bcn_freq_offs_time;
|
|
|
|
bcn_freq_offs_time = WLAN_LOW_POWER_BCN_FREQ_OFFS_TIME;
|
|
|
|
ret = wlan_ext_request(wlan_netif_get(WLAN_MODE_NONE),
|
|
WLAN_EXT_CMD_SET_BCN_FREQ_OFFS_TIME, bcn_freq_offs_time);
|
|
|
|
if (ret == -2) {
|
|
printf("%s: invalid arg\n", __func__);
|
|
return;
|
|
} else if (ret == -1) {
|
|
printf("%s: exec failed\n", __func__);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void wlp_set_tx_null_period(void)
|
|
{
|
|
int ret;
|
|
int period;
|
|
|
|
period = 48;
|
|
|
|
ret = wlan_ext_request(wlan_netif_get(WLAN_MODE_NONE),
|
|
WLAN_EXT_CMD_SET_PM_TX_NULL_PERIOD, period);
|
|
|
|
if (ret == -2) {
|
|
printf("%s: invalid arg\n", __func__);
|
|
return;
|
|
} else if (ret == -1) {
|
|
printf("%s: exec failed\n", __func__);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void wlp_set_ps_mode_with_little_change_time(void)
|
|
{
|
|
int ret;
|
|
uint32_t ps_mode, ps_ip, ps_cp;
|
|
wlan_ext_ps_cfg_t ps_cfg;
|
|
|
|
ps_mode = 1;
|
|
ps_ip = 10;
|
|
ps_cp = 10;
|
|
|
|
memset(&ps_cfg, 0, sizeof(wlan_ext_ps_cfg_t));
|
|
ps_cfg.ps_mode = ps_mode;
|
|
ps_cfg.ps_idle_period = ps_ip;
|
|
ps_cfg.ps_change_period = ps_cp;
|
|
ret = wlan_ext_request(wlan_netif_get(WLAN_MODE_NONE),
|
|
WLAN_EXT_CMD_SET_PS_CFG, (uint32_t)&ps_cfg);
|
|
|
|
if (ret == -2) {
|
|
printf("%s: invalid arg\n", __func__);
|
|
return;
|
|
} else if (ret == -1) {
|
|
printf("%s: exec failed\n", __func__);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void wlp_set_bcn_rx_11b_only(void)
|
|
{
|
|
int ret;
|
|
uint32_t bcn_rx_11b_only_en;
|
|
|
|
bcn_rx_11b_only_en = 1;
|
|
|
|
ret = wlan_ext_request(wlan_netif_get(WLAN_MODE_NONE),
|
|
WLAN_EXT_CMD_SET_BCN_RX_11B_ONLY, (uint32_t)bcn_rx_11b_only_en);
|
|
|
|
if (ret == -2) {
|
|
printf("%s: invalid arg\n", __func__);
|
|
return;
|
|
} else if (ret == -1) {
|
|
printf("%s: exec failed\n", __func__);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void wlp_set_bcn_win_cfg(void)
|
|
{
|
|
int ret;
|
|
wlan_ext_bcn_win_param_set_t param;
|
|
|
|
param.BeaconWindowAdjStartNum = 1;
|
|
param.BeaconWindowAdjStopNum = 5;
|
|
param.BeaconWindowAdjAmpUs = 1000;
|
|
param.BeaconWindowMaxStartNum = 5;
|
|
ret = wlan_ext_request(wlan_netif_get(WLAN_MODE_NONE),
|
|
WLAN_EXT_CMD_SET_BCN_WIN_CFG, (int)(¶m));
|
|
|
|
if (ret == -2) {
|
|
printf("%s: invalid arg\n", __func__);
|
|
return;
|
|
} else if (ret == -1) {
|
|
printf("%s: exec failed\n", __func__);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void wlp_set_pre_rx_bcn(void)
|
|
{
|
|
int ret;
|
|
wlan_ext_pre_rx_bcn_t param;
|
|
|
|
param.enable = 1;
|
|
param.flags = 0;
|
|
param.stop_num = 0;
|
|
|
|
ret = wlan_ext_request(wlan_netif_get(WLAN_MODE_NONE),
|
|
WLAN_EXT_CMD_SET_PRE_RX_BCN, (uint32_t)¶m);
|
|
|
|
if (ret == -2) {
|
|
printf("%s: invalid arg\n", __func__);
|
|
return;
|
|
} else if (ret == -1) {
|
|
printf("%s: exec failed\n", __func__);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void wlp_goto_standby(void)
|
|
{
|
|
HAL_Wakeup_SetTimer_Sec(240);
|
|
|
|
pm_enter_mode(PM_MODE_STANDBY);
|
|
|
|
return;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
platform_init();
|
|
|
|
/* wlan low power example info */
|
|
printf("wlan low power example base on XR806 demo board.\n\n");
|
|
printf("\trecommend to read readme.md and\n"
|
|
"\tXRADIO_Wlan_Low_Power_Developer_Guide-CN.doc for more information.\n");
|
|
printf("\trecommend to use DC current Analyzer(e.g. N6705B) which connecting V_BAT\n"
|
|
"\tin XR806 demo borad to measure power.\n\n");
|
|
|
|
OS_Sleep(2);
|
|
/* use low cpu frequency */
|
|
printf("use low cpu freq:\n\n");
|
|
|
|
printf("\tcpu freq is %d Hz, recommended value is 160MHz or lower.\n",
|
|
HAL_GetCPUClock());
|
|
|
|
printf("\tmodify BOARD_CPU_CLK_FACTOR in board_config.h to set cpu freq.\n");
|
|
|
|
printf("\n");
|
|
|
|
OS_Sleep(2);
|
|
/* use external low frequency XTAL */
|
|
printf("use accurate external low frequency XTAL:\n\n");
|
|
|
|
printf("\tBOARD_LOSC_EXTERNAL is %d, recommended value is 1\n",
|
|
BOARD_LOSC_EXTERNAL);
|
|
|
|
printf("\tmodify BOARD_LOSC_EXTERNAL in board_config.h to use ext LF XTAL.\n");
|
|
|
|
printf("\n");
|
|
|
|
OS_Sleep(2);
|
|
|
|
/* use DC-DC mode */
|
|
printf("use DC-DC mode\n\n");
|
|
|
|
OS_Sleep(2);
|
|
|
|
/* connect AP */
|
|
printf("connect ap:\n\n");
|
|
wlp_connect_ap();
|
|
|
|
/* wait to be connected */
|
|
while (wlp_ap_connected == 0) {
|
|
printf("\n\tthis example need ap(2.4GHz band), please set your ap in wpa2:\n"
|
|
"\t\tssid: %s, password: %s\n", sta_ssid, sta_psk);
|
|
printf("\tor use this cmd to connect your ap with your own ssid and password:\n"
|
|
"\t\t\"net sta config your_ssid your_password\"\n\n");
|
|
OS_Sleep(10);
|
|
}
|
|
|
|
OS_Sleep(2);
|
|
/* count ap beacon delay */
|
|
printf("\ncount ap beacon delay:\n\n");
|
|
|
|
printf("\tfirst, set wlan to be active mode.\n");
|
|
wlp_set_wlan_to_active_mode();
|
|
|
|
printf("\tsecond, get ap beacon delay stats in 10s or more as you wanted.\n");
|
|
wlp_count_ap_beacon_delay();
|
|
|
|
OS_Sleep(2);
|
|
/* set beacon window */
|
|
printf("\nset beacon window:\n\n");
|
|
|
|
printf("\treduce this value will save wait time when missing beacon,\n"
|
|
"\tbut will increase the probability of beacon loss\n\n");
|
|
|
|
printf("\tthis value is based on ap beacon delay, this example use 2300us.\n");
|
|
wlp_set_beacon_window();
|
|
|
|
OS_Sleep(2);
|
|
/* set dtim period and listen interval */
|
|
printf("\nset dtim period and listen interval:\n\n");
|
|
printf("\tincrease dtim period or listen interval will reduce wlan wakeup time\n");
|
|
printf("\tthe unit of increase dtim period and listen interval is beacon period.\n");
|
|
printf("\tdtim period determine the min value of wlan wakeup period when mcu in standby mode\n");
|
|
printf("\tlisten interval determine the max value of wlan wakeup period when mcu in standby mode\n");
|
|
printf("\tif listen interval is 0, wlan wakeup period will equal to dtim period\n\n");
|
|
|
|
printf("\tset dtim period to 1 and set listen interval to %d in this example.\n", WLAN_LOW_POWER_LISTEN_INTERVAL);
|
|
wlp_set_dtim_period();
|
|
wlp_set_listen_interval();
|
|
|
|
OS_Sleep(2);
|
|
/* set beacon freq offset time */
|
|
printf("\nset beacon freq offset time:\n\n");
|
|
printf("\tset the wlan power up time when recieve beacon\n");
|
|
printf("\tthis value is based on listen interval.\n");
|
|
printf("\tif beacon freq offset time is too short, sta may loss beacon frames.\n\n");
|
|
|
|
printf("\tset beacon freq offset time to %d in this example.\n", WLAN_LOW_POWER_BCN_FREQ_OFFS_TIME);
|
|
wlp_set_bcn_freq_offs_time();
|
|
|
|
OS_Sleep(2);
|
|
/* set tx null period */
|
|
printf("\nset tx null period:\n\n");
|
|
printf("\tincrease tx null period will reduce wlan tx time\n");
|
|
printf("\tthis value is based on ap endurance.\n");
|
|
printf("\tif tx null period is too long, ap will kick off this sta.\n\n");
|
|
|
|
printf("\tset tx null period to 48s in this example.\n");
|
|
wlp_set_tx_null_period();
|
|
|
|
OS_Sleep(2);
|
|
/* set ps mode with little change time */
|
|
printf("\nset ps mode with little change time:\n\n");
|
|
printf("\treduce ps idle period and change period will reduce ps mode change time.\n\n");
|
|
printf("\tset ps idle period and change period to 10ms in this example\n");
|
|
wlp_set_ps_mode_with_little_change_time();
|
|
|
|
OS_Sleep(2);
|
|
/* set beacon rx 11b mode only */
|
|
printf("\nset beacon rx 11b mode only:\n\n");
|
|
printf("\tAP usually send beacon by 11b mode, set this cmd to reduce listening power.\n\n");
|
|
printf("\tif AP send beacon by other mode, do not set this cmd\n");
|
|
wlp_set_bcn_rx_11b_only();
|
|
|
|
OS_Sleep(2);
|
|
/* set bcn win config */
|
|
printf("\nset beacon win config:\n\n");
|
|
printf("\tset BSS lost beacon counter, increase beacon window when beacon missed.\n\n");
|
|
wlp_set_bcn_win_cfg();
|
|
|
|
OS_Sleep(2);
|
|
/* set pre rx bcn config */
|
|
printf("\nset pre rx beacon:\n\n");
|
|
printf("\tset pre RX mode for beacon recieving.\n\n");
|
|
wlp_set_pre_rx_bcn();
|
|
|
|
OS_Sleep(2);
|
|
/* set mcu into standby mode */
|
|
printf("\nset mcu into standby mode:\n\n");
|
|
printf("\tin this mode, use DC current Analyzer to measure the power.\n\n");
|
|
|
|
printf("\tset wakeup timer and goto standby, will wakeup after 240s.\n\n");
|
|
printf("\tplease measure power now.\n\n\n");
|
|
wlp_goto_standby();
|
|
|
|
OS_Sleep(2);
|
|
/* wakeup now */
|
|
printf("\nwakeup now.\n\n");
|
|
|
|
OS_Sleep(2);
|
|
/* pm cmd info */
|
|
printf("\npm cmd info:\n\n");
|
|
printf("\tuse cmd \"pm wk_timer 240\" to set wakeup timer\n");
|
|
printf("\tuse cmd \"pm standby\" to goto standby mode again.\n\n");
|
|
|
|
return 0;
|
|
}
|