0
0
Fork 0

feat(wifi) configurable mode: AP,APSTA,Smart APSTA and stop/start AP/STA command

This commit is contained in:
kerms 2024-07-12 12:16:35 +08:00
parent d9b9731f82
commit 7d4d3484f5
9 changed files with 393 additions and 28 deletions

View File

@ -6,12 +6,14 @@
#define WIFI_MODULE_ID 1
typedef enum wifi_api_json_cmd_t {
UNKNOWN = 0,
WIFI_API_JSON_STA_GET_AP_INFO,
WIFI_API_JSON_CONNECT,
WIFI_API_JSON_GET_SCAN,
WIFI_API_JSON_DISCONNECT,
WIFI_API_JSON_AP_GET_INFO,
UNKNOWN = 0,
WIFI_API_JSON_STA_GET_AP_INFO = 1,
WIFI_API_JSON_CONNECT = 2,
WIFI_API_JSON_GET_SCAN = 3,
WIFI_API_JSON_DISCONNECT = 4,
WIFI_API_JSON_AP_GET_INFO = 5,
WIFI_API_JSON_GET_MODE = 6, /* req:{ }, ret:{mode, [delay_off], [delay_on]} */
WIFI_API_JSON_SET_MODE = 7, /* req:{mode, [delay_off], [delay_on]} */
} wifi_api_json_cmd_t;
typedef struct wifi_api_ap_info_t {
@ -23,6 +25,22 @@ typedef struct wifi_api_ap_info_t {
signed char rssi;
} wifi_api_ap_info_t;
typedef enum wifi_apsta_mode_e {
/* permanent */
WIFI_AP_AUTO_STA_ON = 0,
WIFI_AP_STA_OFF = 4, /* 100 */
WIFI_AP_OFF_STA_ON = 5, /* 101 */
WIFI_AP_ON_STA_OFF = 6, /* 110 */
WIFI_AP_STA_ON = 7, /* 111 */
/* temporary */
WIFI_AP_STOP = 8,
WIFI_AP_START = 9,
WIFI_STA_STOP = 10,
WIFI_STA_START = 11,
} wifi_apsta_mode_e;
void wifi_api_sta_get_ap_info(wifi_api_ap_info_t *ap_info);
void wifi_api_ap_get_info(wifi_api_ap_info_t *ap_info);

View File

@ -1,6 +1,7 @@
#include "api_json_module.h"
#include "wifi_api.h"
#include "wifi_json_utils.h"
#include "wifi_manager.h"
#include <stdio.h>
#include <esp_log.h>
@ -17,6 +18,10 @@ static int wifi_api_json_disconnect(api_json_req_t *req);
static int wifi_api_json_ap_get_info(api_json_req_t *req);
static int wifi_api_json_set_mode(api_json_req_t *req);
static int wifi_api_json_get_mode(api_json_req_t *req);
/* the upper caller call cb() with void *, this let us use custom function arg */
static int async_helper_cb(void *arg)
{
@ -50,6 +55,10 @@ static int on_json_req(uint16_t cmd, api_json_req_t *req, api_json_module_async_
return wifi_api_json_disconnect(req);
case WIFI_API_JSON_AP_GET_INFO:
return wifi_api_json_ap_get_info(req);
case WIFI_API_JSON_GET_MODE:
return wifi_api_json_get_mode(req);
case WIFI_API_JSON_SET_MODE:
return wifi_api_json_set_mode(req);
}
ESP_LOGI(TAG, "cmd %d not executed\n", cmd);
@ -112,6 +121,61 @@ int wifi_api_json_connect(api_json_req_t *req)
return wifi_api_json_sta_get_ap_info(req);
};
int wifi_api_json_set_mode(api_json_req_t *req)
{
int value;
int err;
err = wifi_api_json_utils_get_int(req->in, "mode", &value);
if (err) {
req->out = wifi_api_json_create_err_rsp(req->in, "'mode' attribute missing");
ESP_LOGE(TAG, "ap stop: %s", esp_err_to_name(err));
return API_JSON_OK;
}
wifi_apsta_mode_e mode = value;
wifi_mode_t status;
err = wifi_manager_change_mode(mode);
if (err) {
req->out = wifi_api_json_create_err_rsp(req->in, "Change mode Failed");
ESP_LOGE(TAG, "ap stop: %s", esp_err_to_name(err));
return API_JSON_OK;
}
if (mode == WIFI_AP_AUTO_STA_ON) {
int ap_on_delay;
int ap_off_delay;
err = wifi_api_json_utils_get_int(req->in, "ap_on_delay", &ap_on_delay);
err |= wifi_api_json_utils_get_int(req->in, "ap_off_delay", &ap_off_delay);
if (err == 0) {
wifi_manager_set_ap_auto_delay(&ap_on_delay, &ap_off_delay);
req->out = wifi_api_json_serialize_ap_auto(mode, ap_on_delay, ap_off_delay);
return API_JSON_OK;
}
}
return API_JSON_OK;
}
int wifi_api_json_get_mode(api_json_req_t *req)
{
wifi_apsta_mode_e mode;
wifi_mode_t status;
int ap_on_delay, ap_off_delay;
wifi_manager_get_mode(&mode, &status);
if (mode == WIFI_AP_AUTO_STA_ON) {
wifi_manager_get_ap_auto_delay(&ap_on_delay, &ap_off_delay);
} else {
ap_on_delay = -1;
ap_off_delay = -1;
}
req->out = wifi_api_json_serialize_get_mode(mode, status, ap_on_delay, ap_off_delay);
return API_JSON_OK;
}
int wifi_api_json_disconnect(api_json_req_t *req)
{
return wifi_api_disconnect();

View File

@ -54,12 +54,59 @@ cJSON *wifi_api_json_serialize_scan_list(wifi_api_ap_info_t *aps_info, uint16_t
return root;
}
cJSON *wifi_api_json_serialize_ap_auto(wifi_apsta_mode_e mode, int ap_on_delay, int ap_off_delay)
{
cJSON *root;
root = cJSON_CreateObject();
wifi_api_json_set_header(root, WIFI_API_JSON_GET_SCAN);
cJSON_AddNumberToObject(root, "mode", mode);
cJSON_AddNumberToObject(root, "ap_on_delay", ap_on_delay);
cJSON_AddNumberToObject(root, "ap_off_delay", ap_off_delay);
return root;
}
cJSON *wifi_api_json_create_err_rsp(cJSON *req, const char *msg)
{
cJSON *root;
root = cJSON_Duplicate(req, 1);
cJSON_AddStringToObject(root, "msg", msg);
cJSON_AddStringToObject(root, "err", msg);
return root;
}
int wifi_api_json_utils_get_int(cJSON *req, const char *name, int *out_value)
{
cJSON *item = cJSON_GetObjectItemCaseSensitive(req, name);
if (!cJSON_IsNumber(item)) {
return 1;
}
*out_value = item->valueint;
return 0;
}
cJSON *wifi_api_json_serialize_get_mode(wifi_apsta_mode_e mode, int status, int ap_on_delay, int ap_off_delay)
{
cJSON *root;
root = cJSON_CreateObject();
wifi_api_json_set_header(root, WIFI_API_JSON_GET_MODE);
cJSON_AddNumberToObject(root, "mode", mode);
cJSON_AddNumberToObject(root, "status", status);
if (ap_on_delay >= 0 && ap_off_delay >= 0) {
cJSON_AddNumberToObject(root, "ap_on_delay", ap_on_delay);
cJSON_AddNumberToObject(root, "ap_off_delay", ap_off_delay);
}
return root;
}
cJSON *wifi_api_json_add_int_item(cJSON *root, const char *name, int item)
{
cJSON_AddNumberToObject(root, name, item);
return root;
}

View File

@ -5,8 +5,13 @@
cJSON *wifi_api_json_serialize_ap_info(wifi_api_ap_info_t *ap_info, wifi_api_json_cmd_t cmd);
cJSON *wifi_api_json_serialize_scan_list(wifi_api_ap_info_t *aps_info, uint16_t count);
cJSON *wifi_api_json_serialize_ap_auto(wifi_apsta_mode_e mode, int ap_on_delay, int ap_off_delay);
cJSON *wifi_api_json_serialize_get_mode(wifi_apsta_mode_e mode, int status, int ap_on_delay, int ap_off_delay);
cJSON *wifi_api_json_create_err_rsp(cJSON *req, const char *msg);
cJSON *wifi_api_json_add_int_item(cJSON *root, const char *name, int item);
int wifi_api_json_utils_get_int(cJSON *req, const char *name, int *out_value);
#endif //WIFI_JSON_UTILS_H_GUARD

View File

@ -20,6 +20,7 @@
#include <soc/ledc_periph.h>
#include "ssdp.h"
#include "wifi_api.h"
#define TAG __FILENAME__
@ -40,10 +41,20 @@ typedef struct wifi_ctx_t {
uint8_t need_unlock; /* used when trigger connection from wifi_manager instead of wifi_api */
} conn;
};
uint8_t is_endless_connect:1;
uint8_t auto_reconnect:1;
uint8_t do_fast_connect:1; /* 0 delay connect on boot or just disconnected, else 5 seconds delay from each connection try */
uint8_t reserved:5;
struct {
uint8_t is_endless_connect: 1;
uint8_t auto_reconnect: 1;
uint8_t do_fast_connect: 1; /* 0 delay connect on boot or just disconnected, else 5 seconds delay from each connection try */
uint8_t is_sta_connected: 1;
uint8_t reserved: 4;
};
TaskHandle_t delayed_stopAP_task;
TaskHandle_t delayed_startAP_task;
uint32_t try_connect_count;
wifi_apsta_mode_e permanent_mode;
wifi_mode_t mode;
int ap_on_delay_tick;
int ap_off_delay_tick;
} wifi_ctx_t;
static esp_netif_t *ap_netif;
@ -54,6 +65,9 @@ static wifi_ctx_t ctx;
static void set_sta_cred(const char *ssid, const char *password);
static void disconn_handler(void);
static int set_default_sta_cred(void);
static int set_wifi_mode(wifi_apsta_mode_e mode);
static void handle_wifi_connected();
static void wifi_led_init();
static void wifi_led_set_blink();
@ -79,15 +93,24 @@ void wifi_manager_init(void)
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, ESP_EVENT_ANY_ID, &ip_event_handler, NULL, NULL));
ctx.is_sta_connected = false;
ctx.permanent_mode = WIFI_AP_AUTO_STA_ON;
ctx.mode = WIFI_MODE_APSTA;
ctx.ap_on_delay_tick = pdMS_TO_TICKS(5000);
ctx.ap_off_delay_tick = pdMS_TO_TICKS(10000);
ctx.delayed_stopAP_task = NULL;
ctx.delayed_startAP_task = NULL;
ctx.try_connect_count = 0;
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
ESP_ERROR_CHECK(esp_wifi_set_mode(ctx.mode));
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
{
wifi_config_t ap_config = {0};
strncpy((char *) ap_config.ap.ssid, WIFI_DEFAULT_AP_SSID, 32);
strncpy((char *) ap_config.ap.password, WIFI_DEFAULT_AP_PASS, 64);
strncpy((char *)ap_config.ap.ssid, WIFI_DEFAULT_AP_SSID, 32);
strncpy((char *)ap_config.ap.password, WIFI_DEFAULT_AP_PASS, 64);
ap_config.ap.authmode = WIFI_AUTH_WPA2_WPA3_PSK;
ap_config.ap.max_connection = 4;
ap_config.ap.channel = 6;
@ -183,7 +206,7 @@ static void wifi_led_set_blink()
static void wifi_led_set_on()
{
#if WIFI_LED_ENABLE
ledc_set_duty_and_update(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, (1 << 14)-1, 0);
ledc_set_duty_and_update(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, (1 << 14) - 1, 0);
#endif
}
@ -335,6 +358,7 @@ int wifi_manager_connect(const char *ssid, const char *password)
/* connection success: overwrite last connected credential */
wifi_led_set_on();
handle_wifi_connected();
wifi_credential_t credential;
memcpy(credential.ssid, ssid, 32);
memcpy(credential.password, password, 64);
@ -345,6 +369,90 @@ int wifi_manager_connect(const char *ssid, const char *password)
return 0;
}
int wifi_manager_change_mode(wifi_apsta_mode_e mode)
{
int err;
if (ctx.permanent_mode == mode) {
return 0;
}
err = xSemaphoreTake(ctx.lock, pdMS_TO_TICKS(2000));
if (err != pdTRUE) {
ESP_LOGE(TAG, "set mode take lock");
return 1;
}
if (ctx.delayed_stopAP_task) {
xTaskNotifyGive(ctx.delayed_stopAP_task);
}
if (ctx.delayed_startAP_task) {
xTaskNotifyGive(ctx.delayed_startAP_task);
}
err = set_wifi_mode(mode);
xSemaphoreGive(ctx.lock);
if (err)
return err;
return wifi_data_save_wifi_mode(mode);
}
int set_wifi_mode(wifi_apsta_mode_e mode)
{
uint32_t new_mode = ctx.mode;
printf("change mode: %d\n", mode);
switch (mode) {
default:
return 1;
case WIFI_AP_AUTO_STA_ON:
if (ctx.is_sta_connected) {
new_mode = WIFI_MODE_STA;
} else {
new_mode = WIFI_MODE_APSTA;
}
ctx.permanent_mode = mode;
break;
case WIFI_AP_STA_OFF:
case WIFI_AP_ON_STA_OFF:
case WIFI_AP_OFF_STA_ON:
case WIFI_AP_STA_ON:
ctx.permanent_mode = mode;
new_mode = mode & (~WIFI_AP_STA_OFF);
break;
case WIFI_AP_STOP:
new_mode &= ~WIFI_MODE_AP;
break;
case WIFI_AP_START:
new_mode |= WIFI_MODE_AP;
break;
case WIFI_STA_STOP:
new_mode &= ~WIFI_MODE_STA;
break;
case WIFI_STA_START:
new_mode |= WIFI_MODE_STA;
break;
}
printf("set mode to %lx\n", new_mode);
if (new_mode == ctx.mode) {
return 0;
}
int err = esp_wifi_set_mode(new_mode);
if (err) {
printf("set mode ret err %x\n", err);
return err;
}
/* AP -> APSTA */
if (!(ctx.mode & WIFI_MODE_STA) && (new_mode & WIFI_MODE_STA)) {
printf("set mode reco\n");
disconn_handler();
}
ctx.mode = new_mode;
printf("set mode ret %x\n", err);
return err;
}
static void set_sta_cred(const char *ssid, const char *password)
{
wifi_config_t wifi_config = {
@ -353,12 +461,78 @@ static void set_sta_cred(const char *ssid, const char *password)
.sort_method = WIFI_CONNECT_AP_BY_SIGNAL,
},
};
memcpy((char *) wifi_config.sta.ssid, ssid, 32);
memcpy((char *) wifi_config.sta.password, password, 64);
memcpy((char *)wifi_config.sta.ssid, ssid, 32);
memcpy((char *)wifi_config.sta.password, password, 64);
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
}
static void delayed_set_ap_stop(void *arg)
{
uint32_t ret = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(10000));
xSemaphoreTake(ctx.lock, pdMS_TO_TICKS(10000));
/* timeout: connected to STA without disconnection for 10 sec: close AP */
if (ret == 0) {
set_wifi_mode(WIFI_AP_STOP);
ctx.try_connect_count = 0;
}
ctx.delayed_stopAP_task = NULL;
xSemaphoreGive(ctx.lock);
vTaskDelete(NULL);
}
static void delayed_set_ap_start(void *arg)
{
uint32_t ret = 0;
if (!(ctx.try_connect_count > 5)) {
ret = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(10000));
}
xSemaphoreTake(ctx.lock, pdMS_TO_TICKS(10000));
/* timeout: connected to STA without disconnection for 10 sec: close AP */
/* or consecutive connect/disconnect */
if (ret == 0 && ctx.permanent_mode == WIFI_AP_AUTO_STA_ON) {
set_wifi_mode(WIFI_AP_START);
ctx.try_connect_count = 0;
}
ctx.delayed_startAP_task = NULL;
xSemaphoreGive(ctx.lock);
vTaskDelete(NULL);
}
static void handle_wifi_connected()
{
ctx.is_sta_connected = true;
if (ctx.delayed_startAP_task) {
printf("clear start ap task");
xTaskNotifyGive(ctx.delayed_startAP_task);
}
if (ctx.permanent_mode != WIFI_AP_AUTO_STA_ON) {
return;
}
printf("stop ap task");
xTaskCreate(delayed_set_ap_stop, "stop ap", 4096,
NULL, tskIDLE_PRIORITY + 1, &ctx.delayed_stopAP_task);
}
static void handle_wifi_disconnected()
{
ctx.is_sta_connected = false;
if (ctx.delayed_stopAP_task) {
printf("clear stop ap task");
xTaskNotifyGive(ctx.delayed_stopAP_task);
}
if (ctx.permanent_mode != WIFI_AP_AUTO_STA_ON) {
return;
}
printf("start ap task");
ctx.try_connect_count++;
xTaskCreate(delayed_set_ap_start, "start ap", 4096,
NULL, tskIDLE_PRIORITY + 1, &ctx.delayed_startAP_task);
}
static void reconnection_task(void *arg)
{
int err;
@ -383,7 +557,9 @@ static void reconnection_task(void *arg)
if (ctx.conn.event || ctx.auto_reconnect == 0) {
/* reconnection successful or stop reconnect */
if (ctx.conn.event) {
/* sta connected */
wifi_led_set_on();
handle_wifi_connected();
}
break;
}
@ -411,6 +587,7 @@ static void disconn_handler(void)
* 3. this device is ejected by AP
* */
wifi_led_set_blink();
handle_wifi_disconnected();
if (ctx.auto_reconnect == 0) {
return;
}
@ -434,3 +611,24 @@ int wifi_manager_disconnect(void)
ctx.auto_reconnect = 0;
return esp_wifi_disconnect();
}
int wifi_manager_get_ap_auto_delay(int *ap_on_delay, int *ap_off_delay)
{
*ap_on_delay = pdTICKS_TO_MS(ctx.ap_on_delay_tick);
*ap_off_delay = pdTICKS_TO_MS(ctx.ap_off_delay_tick);
return 0;
}
int wifi_manager_set_ap_auto_delay(int *ap_on_delay, int *ap_off_delay)
{
ctx.ap_on_delay_tick = pdMS_TO_TICKS(*ap_on_delay);
ctx.ap_on_delay_tick = pdMS_TO_TICKS(*ap_off_delay);
return wifi_manager_get_ap_auto_delay(ap_on_delay, ap_off_delay);
}
int wifi_manager_get_mode(wifi_apsta_mode_e *mode, wifi_mode_t *status)
{
*mode = ctx.permanent_mode;
*status = ctx.mode;
return 0;
}

View File

@ -2,6 +2,7 @@
#define WIFI_MANAGER_H_GUARD
#include <esp_wifi_types.h>
#include "wifi_api.h"
void wifi_manager_init();
@ -13,6 +14,10 @@ typedef void (*wifi_manager_scan_done_cb)(uint16_t ap_found, wifi_ap_record_t *r
int wifi_manager_get_scan_list(uint16_t *number, wifi_ap_record_t *aps);
int wifi_manager_connect(const char *ssid, const char *password);
int wifi_manager_disconnect(void);
int wifi_manager_change_mode(wifi_apsta_mode_e mode);
int wifi_manager_get_mode(wifi_apsta_mode_e *mode, wifi_mode_t *status);
int wifi_manager_get_ap_auto_delay(int *ap_on_delay, int *ap_off_delay);
int wifi_manager_set_ap_auto_delay(int *ap_on_delay, int *ap_off_delay);

View File

@ -1,6 +1,7 @@
#include "wifi_storage.h"
#include "wifi_storage_priv.h"
#include "wt_nvs.h"
#include "wifi_api.h"
#include <stdio.h>
@ -75,3 +76,24 @@ int wifi_save_ap_credential(wifi_credential_t *ap_credential)
wt_nvs_close(handle);
return WT_NVS_OK;
}
int wifi_data_save_wifi_mode(wifi_apsta_mode_e mode)
{
nvs_handle_t handle;
int err;
uint8_t mode_u8 = mode;
err = wt_nvs_open(WIFI_NVS_NAMESPACE, &handle);
if (err) {
return err;
}
err = wt_nvs_set(handle, KEY_WIFI_APSTA_MODE, &mode_u8, sizeof(mode_u8));
if (err) {
return err;
}
wt_nvs_close(handle);
return WT_NVS_OK;
}

View File

@ -2,6 +2,7 @@
#define WIFI_STORAGE_H_GUARD
#include <stdint-gcc.h>
#include "wifi_api.h"
typedef struct nvs_wifi_credential_t {
char ssid[32];
@ -12,4 +13,6 @@ int wifi_data_get_last_conn_cred(wifi_credential_t *ap_credential);
int wifi_save_ap_credential(wifi_credential_t *ap_credential);
int wifi_data_save_wifi_mode(wifi_apsta_mode_e mode);
#endif //WIFI_STORAGE_H_GUARD

View File

@ -11,19 +11,22 @@ typedef struct w_cache_t {
typedef enum wt_wifi_key_enum {
KEY_WIFI_RESERVED = 0x000,
/* WIFI */
KEY_WIFI_AP_SSID,
KEY_WIFI_AP_PASSWORD,
KEY_WIFI_AP_SSID = 0x1,
KEY_WIFI_AP_PASSWORD = 0x02,
/* TODO: should have 1 for each AP */
KEY_WIFI_STA_USE_STATIC, /* bit[0:31]=[IP, MASK, GATEWAY, DNS] */
KEY_WIFI_STA_STATIC_IP, /* 4B */
KEY_WIFI_STA_STATIC_MASK, /* 4B */
KEY_WIFI_STA_STATIC_GATEWAY, /* 4B */
KEY_WIFI_STA_STATIC_DNS, /* 4B */
/* TODO: should have 1 for each AP */
KEY_WIFI_STA_USE_STATIC = 0x03, /* bit[0:31]=[IP, MASK, GATEWAY, DNS] */
KEY_WIFI_STA_STATIC_IP = 0x04, /* 4B */
KEY_WIFI_STA_STATIC_MASK = 0x05, /* 4B */
KEY_WIFI_STA_STATIC_GATEWAY = 0x06, /* 4B */
KEY_WIFI_STA_STATIC_DNS = 0x07, /* 4B */
/* AP's information */
KEY_WIFI_STA_LAST_AP_CRED, /*!< ssid[32] + password[64] */
KEY_WIFI_STA_AP_BITMAP,
/* STA information */
KEY_WIFI_STA_LAST_AP_CRED = 0x08, /*!< ssid[32] + password[64] */
KEY_WIFI_STA_AP_BITMAP = 0x09, /* 32 bit */
KEY_UNUSED_100 = 0x0100,
KEY_WIFI_APSTA_MODE = 0x0101, /* 1B */
} wt_wifi_key;
#endif //WIFI_STORAGE_PRIV_H_GUARD