ESP32/components/wifi_cfg/wifi_cfg.c

303 lines
12 KiB
C

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdatomic.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "esp_netif.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_check.h"
#include "wifi_cfg.h"
#include "cmd_transport.h" // Now uses the transport component
#include "csi_manager.h" // For CSI enable/disable
static const char *TAG = "wifi_cfg";
static esp_netif_t *sta_netif = NULL;
static bool cfg_dhcp = true;
// --- Helper Functions (Preserved) ---
static esp_err_t nvs_set_str2(nvs_handle_t h, const char *key, const char *val){
return val ? nvs_set_str(h, key, val) : nvs_erase_key(h, key);
}
static void save_cfg(const char* ssid, const char* pass, const char* ip, const char* mask, const char* gw, bool dhcp, const char* band, const char* bw, const char* powersave, const char* mode, uint8_t mon_ch){
nvs_handle_t h;
if (nvs_open("netcfg", NVS_READWRITE, &h) != ESP_OK) return;
if (ssid) nvs_set_str2(h, "ssid", ssid);
if (pass) nvs_set_str2(h, "pass", pass);
if (ip) nvs_set_str2(h, "ip", ip);
if (mask) nvs_set_str2(h, "mask", mask);
if (gw) nvs_set_str2(h, "gw", gw);
if (band) nvs_set_str2(h, "band", band);
if (bw) nvs_set_str2(h, "bw", bw);
if (powersave) nvs_set_str2(h, "powersave", powersave);
if (mode) nvs_set_str2(h, "mode", mode);
nvs_set_u8(h, "mon_ch", mon_ch);
nvs_set_u8(h, "dhcp", dhcp ? 1 : 0);
nvs_commit(h);
nvs_close(h);
cfg_dhcp = dhcp;
ESP_LOGI(TAG, "Config saved to NVS: SSID=%s Mode=%s MonCh=%d", ssid?ssid:"", mode?mode:"STA", mon_ch);
}
static bool load_cfg(char* ssid, size_t ssz, char* pass, size_t psz,
char* ip, size_t isz, char* mask, size_t msz, char* gw, size_t gsz,
char* band, size_t bsz, char* bw, size_t bwsz, char* powersave, size_t pssz,
char* mode, size_t modesz, uint8_t* mon_ch, bool* dhcp){
nvs_handle_t h;
if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) return false;
size_t len;
esp_err_t e;
if ((e = nvs_get_str(h, "ssid", NULL, &len)) != ESP_OK){ nvs_close(h); return false; }
if (len >= ssz){ nvs_close(h); return false; }
nvs_get_str(h, "ssid", ssid, &len);
len = psz; e = nvs_get_str(h, "pass", pass, &len); if (e!=ESP_OK) pass[0]=0;
len = isz; e = nvs_get_str(h, "ip", ip, &len); if (e!=ESP_OK) ip[0]=0;
len = msz; e = nvs_get_str(h, "mask", mask, &len); if (e!=ESP_OK) mask[0]=0;
len = gsz; e = nvs_get_str(h, "gw", gw, &len); if (e!=ESP_OK) gw[0]=0;
len = bsz; e = nvs_get_str(h, "band", band, &len); if (e!=ESP_OK) strcpy(band, "2.4G");
len = bwsz; e = nvs_get_str(h, "bw", bw, &len); if (e!=ESP_OK) strcpy(bw, "HT20");
len = pssz; e = nvs_get_str(h, "powersave", powersave, &len); if (e!=ESP_OK) strcpy(powersave, "NONE");
len = modesz; e = nvs_get_str(h, "mode", mode, &len); if (e!=ESP_OK) strcpy(mode, "STA");
uint8_t ch=36; nvs_get_u8(h, "mon_ch", &ch); *mon_ch = ch;
uint8_t d=1; nvs_get_u8(h, "dhcp", &d); *dhcp = (d!=0);
nvs_close(h);
return true;
}
void wifi_cfg_force_dhcp(bool enable){ cfg_dhcp = enable; }
bool wifi_cfg_get_mode(char *mode, uint8_t *mon_ch) {
if (!mode || !mon_ch) return false;
nvs_handle_t h;
if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) {
strcpy(mode, "STA"); *mon_ch = 36; return false;
}
size_t len = 16;
if (nvs_get_str(h, "mode", mode, &len) != ESP_OK) strcpy(mode, "STA");
uint8_t ch = 36;
nvs_get_u8(h, "mon_ch", &ch);
*mon_ch = ch;
nvs_close(h);
return true;
}
static atomic_bool s_net_stack_ready = false;
static esp_err_t ensure_net_stack_once(void) {
bool expected = false;
if (atomic_compare_exchange_strong(&s_net_stack_ready, &expected, true)) {
ESP_RETURN_ON_ERROR(esp_netif_init(), TAG, "esp_netif_init");
esp_err_t err = esp_event_loop_create_default();
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
ESP_RETURN_ON_ERROR(err, TAG, "event loop create");
}
}
return ESP_OK;
}
static atomic_bool s_wifi_inited = false;
esp_err_t wifi_ensure_inited(void) {
bool expected = false;
if (!atomic_compare_exchange_strong(&s_wifi_inited, &expected, true)) return ESP_OK;
ESP_RETURN_ON_ERROR(ensure_net_stack_once(), TAG, "net stack");
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_err_t err = esp_wifi_init(&cfg);
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
atomic_store(&s_wifi_inited, false);
ESP_RETURN_ON_ERROR(err, TAG, "esp_wifi_init");
}
return ESP_OK;
}
static void apply_ip_static(const char* ip, const char* mask, const char* gw){
if (!sta_netif) return;
if (!ip || !ip[0] || !mask || !mask[0] || !gw || !gw[0]) return;
esp_netif_ip_info_t info = {0};
esp_netif_dhcpc_stop(sta_netif);
info.ip.addr = esp_ip4addr_aton(ip);
info.netmask.addr = esp_ip4addr_aton(mask);
info.gw.addr = esp_ip4addr_aton(gw);
ESP_ERROR_CHECK( esp_netif_set_ip_info(sta_netif, &info) );
}
bool wifi_cfg_apply_from_nvs(void) {
char ssid[64]={0}, pass[64]={0}, ip[32]={0}, mask[32]={0}, gw[32]={0};
char band[16]={0}, bw[16]={0}, powersave[16]={0}, mode[16]={0};
uint8_t mon_ch = 36; bool dhcp = true;
if (!load_cfg(ssid,sizeof(ssid), pass,sizeof(pass), ip,sizeof(ip), mask,sizeof(mask), gw,sizeof(gw),
band,sizeof(band), bw,sizeof(bw), powersave,sizeof(powersave), mode,sizeof(mode), &mon_ch, &dhcp)){
return false;
}
if (ssid[0] == '\0') return false;
static bool inited = false;
if (!inited){
nvs_flash_init();
ensure_net_stack_once();
if (sta_netif == NULL) sta_netif = esp_netif_create_default_wifi_sta();
wifi_ensure_inited();
inited = true;
}
wifi_config_t wcfg = {0};
// Note: strlcpy takes the FULL buffer size and handles the -1 internally
strlcpy((char*)wcfg.sta.ssid, ssid, sizeof(wcfg.sta.ssid));
strlcpy((char*)wcfg.sta.password, pass, sizeof(wcfg.sta.password));
wcfg.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
wcfg.sta.sae_pwe_h2e = WPA3_SAE_PWE_BOTH;
wcfg.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
if (strcmp(band, "5G") == 0) wcfg.sta.channel = 0;
else wcfg.sta.channel = 0;
esp_wifi_set_mode(WIFI_MODE_STA);
// Protocol selection based on target
#if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6
wifi_protocols_t protocols = {
.ghz_2g = WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N,
.ghz_5g = WIFI_PROTOCOL_11A | WIFI_PROTOCOL_11N | WIFI_PROTOCOL_11AC | WIFI_PROTOCOL_11AX,
};
esp_wifi_set_protocols(WIFI_IF_STA, &protocols);
#else
esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
#endif
esp_wifi_set_config(WIFI_IF_STA, &wcfg);
if (!dhcp && ip[0]) apply_ip_static(ip, mask, gw);
else if (sta_netif) esp_netif_dhcpc_start(sta_netif);
// Bandwidth selection
#if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6
wifi_bandwidths_t bandwidths = {.ghz_2g = WIFI_BW_HT20, .ghz_5g = WIFI_BW_HT20};
if (strcmp(bw, "VHT80") == 0) { bandwidths.ghz_2g = WIFI_BW_HT40; bandwidths.ghz_5g = WIFI_BW80; }
else if (strcmp(bw, "HT40") == 0) { bandwidths.ghz_2g = WIFI_BW_HT40; bandwidths.ghz_5g = WIFI_BW_HT40; }
esp_wifi_set_bandwidths(WIFI_IF_STA, &bandwidths);
#else
wifi_bandwidth_t bandwidth = WIFI_BW_HT20;
if (strcmp(bw, "HT40") == 0) bandwidth = WIFI_BW_HT40;
esp_wifi_set_bandwidth(WIFI_IF_STA, bandwidth);
#endif
esp_wifi_start();
// Power Save
wifi_ps_type_t ps_mode = WIFI_PS_NONE;
if (strcmp(powersave, "MIN") == 0) ps_mode = WIFI_PS_MIN_MODEM;
else if (strcmp(powersave, "MAX") == 0) ps_mode = WIFI_PS_MAX_MODEM;
esp_wifi_set_ps(ps_mode);
esp_wifi_connect();
return true;
}
// --- Command Listener Logic ---
static void on_cfg_line(const char *line, char *ssid, char *pass, char *ip, char *mask, char *gw, char *band, char *bw, char *powersave, char *mode, uint8_t *mon_ch, bool *dhcp, bool *csi_enable){
if (strncmp(line, "SSID:",5)==0){ strncpy(ssid, line+5, 63); ssid[63]=0; return; }
if (strncmp(line, "PASS:",5)==0){ strncpy(pass, line+5, 63); pass[63]=0; return; }
if (strncmp(line, "IP:",3)==0){ strncpy(ip, line+3, 31); ip[31]=0; return; }
if (strncmp(line, "MASK:",5)==0){ strncpy(mask, line+5, 31); mask[31]=0; return; }
if (strncmp(line, "GW:",3)==0){ strncpy(gw, line+3, 31); gw[31]=0; return; }
if (strncmp(line, "BAND:",5)==0){ strncpy(band, line+5, 15); band[15]=0; return; }
if (strncmp(line, "BW:",3)==0){ strncpy(bw, line+3, 15); bw[15]=0; return; }
if (strncmp(line, "POWERSAVE:",10)==0){ strncpy(powersave, line+10, 15); powersave[15]=0; return; }
if (strncmp(line, "MODE:",5)==0){ strncpy(mode, line+5, 15); mode[15]=0; return; }
if (strncmp(line, "MON_CH:",7)==0){ *mon_ch = atoi(line+7); return; }
if (strncmp(line, "DHCP:",5)==0){ *dhcp = atoi(line+5) ? true:false; return; }
if (strncmp(line, "CSI:",4)==0){ *csi_enable = atoi(line+4) ? true:false; return; }
}
static bool wifi_cfg_cmd_handler(const char *line, cmd_reply_func_t reply_func, void *reply_ctx) {
static bool in_cfg = false;
static char ssid[64]={0}, pass[64]={0}, ip[32]={0}, mask[32]={0}, gw[32]={0};
static char band[16]={0}, bw[16]={0}, powersave[16]={0}, mode[16]={0};
static uint8_t mon_ch = 36;
static bool dhcp = true;
static bool csi_enable = false;
if (!in_cfg) {
if (strcmp(line, "CFG") == 0) {
in_cfg = true;
// Reset buffers
ssid[0]=0; pass[0]=0; ip[0]=0; mask[0]=0; gw[0]=0;
band[0]=0; bw[0]=0; powersave[0]=0; mode[0]=0;
mon_ch = 36; dhcp = true; csi_enable = false;
return true; // Handled
}
return false; // Not handled
}
// Inside CFG block
if (strcmp(line, "END") == 0) {
// Apply Defaults
if (!band[0]) strcpy(band, "2.4G");
if (!bw[0]) strcpy(bw, "HT20");
if (!powersave[0]) strcpy(powersave, "NONE");
if (!mode[0]) strcpy(mode, "STA");
save_cfg(ssid, pass, ip, mask, gw, dhcp, band, bw, powersave, mode, mon_ch);
// Save CSI enable state
esp_err_t err = csi_mgr_save_enable_state(csi_enable);
if (err == ESP_OK) {
printf("CSI enable state saved: %s\n", csi_enable ? "ENABLED" : "DISABLED");
} else {
printf("Failed to save CSI state: %s\n", esp_err_to_name(err));
}
if (reply_func) reply_func("OK\n", reply_ctx);
wifi_cfg_apply_from_nvs();
in_cfg = false;
return true;
}
on_cfg_line(line, ssid, pass, ip, mask, gw, band, bw, powersave, mode, &mon_ch, &dhcp, &csi_enable);
return true;
}
void wifi_cfg_init(void){
nvs_flash_init();
// Init the shared transport (starts UART/USB tasks)
cmd_transport_init();
// Register our callback to catch "CFG" blocks
cmd_transport_register_listener(wifi_cfg_cmd_handler);
}
wifi_ps_type_t wifi_cfg_get_power_save_mode(void) {
char powersave[16] = {0};
nvs_handle_t h;
if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) return WIFI_PS_NONE;
size_t len = sizeof(powersave);
nvs_get_str(h, "powersave", powersave, &len);
nvs_close(h);
if (strcmp(powersave, "MIN") == 0) return WIFI_PS_MIN_MODEM;
if (strcmp(powersave, "MAX") == 0) return WIFI_PS_MAX_MODEM;
return WIFI_PS_NONE;
}
bool wifi_cfg_get_bandwidth(char *buf, size_t buf_size) {
if (!buf || buf_size < 1) return false;
nvs_handle_t h;
if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) {
strncpy(buf, "Unknown", buf_size); return false;
}
size_t len = buf_size;
esp_err_t err = nvs_get_str(h, "bw", buf, &len);
nvs_close(h);
return (err == ESP_OK);
}