build ok but has warnings
This commit is contained in:
parent
db6d6b20c4
commit
dec314ce6b
|
|
@ -0,0 +1,203 @@
|
||||||
|
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse, os, sys, time, fnmatch
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import List, Dict
|
||||||
|
|
||||||
|
import serial, serial.tools.list_ports as list_ports
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
KNOWN_VIDS = {0x0403, 0x10C4, 0x1A86, 0x067B, 0x303A}
|
||||||
|
|
||||||
|
def run(cmd, cwd=None, check=True):
|
||||||
|
print(">>", " ".join(cmd))
|
||||||
|
p = subprocess.run(cmd, cwd=cwd)
|
||||||
|
if check and p.returncode != 0:
|
||||||
|
raise RuntimeError(f"Command failed ({p.returncode}): {' '.join(cmd)}")
|
||||||
|
return p.returncode
|
||||||
|
|
||||||
|
def detect_chip_type(port: str) -> str:
|
||||||
|
try:
|
||||||
|
out = subprocess.check_output(["esptool.py", "--port", port, "chip_id"], stderr=subprocess.STDOUT, text=True, timeout=6)
|
||||||
|
if "ESP32-S3" in out.upper(): return "ESP32-S3"
|
||||||
|
if "ESP32-S2" in out.upper(): return "ESP32-S2"
|
||||||
|
if "ESP32-C3" in out.upper(): return "ESP32-C3"
|
||||||
|
if "ESP32-C6" in out.upper(): return "ESP32-C6"
|
||||||
|
if "ESP32" in out.upper(): return "ESP32"
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return "Unknown"
|
||||||
|
|
||||||
|
def map_chip_to_idf_target(chip: str) -> str:
|
||||||
|
s = chip.upper()
|
||||||
|
if s.startswith("ESP32-S3"): return "esp32s3"
|
||||||
|
if s.startswith("ESP32-S2"): return "esp32s2"
|
||||||
|
if s.startswith("ESP32-C3"): return "esp32c3"
|
||||||
|
if s.startswith("ESP32-C6"): return "esp32c6"
|
||||||
|
if s.startswith("ESP32-H2"): return "esp32h2"
|
||||||
|
if s.startswith("ESP32"): return "esp32"
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
def list_ports_filtered(patterns: List[str] = None):
|
||||||
|
ports = list_ports.comports()
|
||||||
|
out = []
|
||||||
|
for p in ports:
|
||||||
|
dev = p.device
|
||||||
|
if patterns:
|
||||||
|
if not any(fnmatch.fnmatch(dev, pat) for pat in patterns):
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
if not (dev.startswith("/dev/ttyUSB") or dev.startswith("/dev/ttyACM")):
|
||||||
|
continue
|
||||||
|
vid = getattr(p, "vid", None)
|
||||||
|
if vid is not None and vid not in KNOWN_VIDS:
|
||||||
|
continue
|
||||||
|
out.append(p)
|
||||||
|
return out
|
||||||
|
|
||||||
|
def ensure_target(project_dir: str, target: str):
|
||||||
|
if not target or target == "unknown":
|
||||||
|
raise ValueError("Unknown IDF target; cannot set-target")
|
||||||
|
run(["idf.py", "set-target", target], cwd=project_dir, check=True)
|
||||||
|
|
||||||
|
def flash_device(project_dir: str, port: str, idf_target: str, baud: int = 460800) -> bool:
|
||||||
|
try:
|
||||||
|
ensure_target(project_dir, idf_target)
|
||||||
|
run(["idf.py", "-p", port, "-b", str(baud), "flash"], cwd=project_dir, check=True)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f" Flash failed on {port}: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def toggle_reset(ser):
|
||||||
|
try:
|
||||||
|
ser.dtr = False
|
||||||
|
ser.rts = True
|
||||||
|
time.sleep(0.05)
|
||||||
|
ser.dtr = True
|
||||||
|
ser.rts = False
|
||||||
|
time.sleep(0.05)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def send_wifi_config(port: str, ssid: str, password: str, ip: str, mask: str, gw: str, dhcp: bool, baud: int = 115200, retries: int = 3) -> bool:
|
||||||
|
for attempt in range(1, retries+1):
|
||||||
|
try:
|
||||||
|
print(f" [{port}] opening serial @ {baud} (attempt {attempt}/{retries})")
|
||||||
|
with serial.Serial(port, baudrate=baud, timeout=2) as ser:
|
||||||
|
time.sleep(0.3)
|
||||||
|
toggle_reset(ser)
|
||||||
|
time.sleep(0.8)
|
||||||
|
ser.reset_input_buffer()
|
||||||
|
ser.reset_output_buffer()
|
||||||
|
|
||||||
|
lines = [
|
||||||
|
"CFG\n",
|
||||||
|
f"SSID:{ssid}\n" if ssid else "",
|
||||||
|
f"PASS:{password}\n" if password else "",
|
||||||
|
f"IP:{ip}\n" if ip else "",
|
||||||
|
f"MASK:{mask}\n" if mask else "",
|
||||||
|
f"GW:{gw}\n" if gw else "",
|
||||||
|
f"DHCP:{1 if dhcp else 0}\n",
|
||||||
|
"END\n",
|
||||||
|
]
|
||||||
|
payload = "".join([l for l in lines if l])
|
||||||
|
ser.write(payload.encode("utf-8"))
|
||||||
|
ser.flush()
|
||||||
|
|
||||||
|
t0 = time.time()
|
||||||
|
buf = b""
|
||||||
|
while time.time() - t0 < 3.0:
|
||||||
|
chunk = ser.read(64)
|
||||||
|
if chunk:
|
||||||
|
buf += chunk
|
||||||
|
if b"OK" in buf:
|
||||||
|
print(f" [{port}] config applied: {buf.decode(errors='ignore').strip()}")
|
||||||
|
return True
|
||||||
|
print(f" [{port}] no OK from device, got: {buf.decode(errors='ignore').strip()}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" [{port}] serial error: {e}")
|
||||||
|
time.sleep(0.6)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def main():
|
||||||
|
ap = argparse.ArgumentParser(description="Mass flash ESP32 devices and push Wi‑Fi/IP config over serial.")
|
||||||
|
ap.add_argument("--project", required=True, help="Path to ESP‑IDF project")
|
||||||
|
ap.add_argument("--ssid", required=True, help="Wi‑Fi SSID")
|
||||||
|
ap.add_argument("--password", required=True, help="Wi‑Fi password")
|
||||||
|
ap.add_argument("--start-ip", default="192.168.1.50", help="Base IP (only used if --dhcp=0)")
|
||||||
|
ap.add_argument("--mask", default="255.255.255.0", help="Netmask for static IP")
|
||||||
|
ap.add_argument("--gw", default="192.168.1.1", help="Gateway for static IP")
|
||||||
|
ap.add_argument("--dhcp", type=int, choices=[0,1], default=1, help="1=use DHCP, 0=set static IPs")
|
||||||
|
ap.add_argument("--baud", type=int, default=460800, help="Flashing baud rate")
|
||||||
|
ap.add_argument("--cfg-baud", type=int, default=115200, help="Serial baud for config exchange")
|
||||||
|
ap.add_argument("--ports", help="Comma-separated globs to override port selection, e.g. '/dev/ttyUSB*,/dev/ttyACM*'")
|
||||||
|
ap.add_argument("--dry-run", action="store_true", help="Plan only; do not flash or configure")
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
project_dir = os.path.abspath(args.project)
|
||||||
|
if not os.path.isdir(project_dir):
|
||||||
|
print(f"Project directory not found: {project_dir}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
patterns = [p.strip() for p in args.ports.split(",")] if args.ports else None
|
||||||
|
devices = list_ports_filtered(patterns)
|
||||||
|
if not devices:
|
||||||
|
print("No candidate USB serial ports found.")
|
||||||
|
sys.exit(2)
|
||||||
|
print(f"Found {len(devices)} devices.")
|
||||||
|
|
||||||
|
base = args.start_ip.split(".")
|
||||||
|
try:
|
||||||
|
base = [int(x) for x in base]
|
||||||
|
except Exception:
|
||||||
|
base = [192,168,1,50]
|
||||||
|
|
||||||
|
plan = []
|
||||||
|
for idx, dev in enumerate(devices, 1):
|
||||||
|
port = dev.device
|
||||||
|
chip = detect_chip_type(port)
|
||||||
|
target = map_chip_to_idf_target(chip)
|
||||||
|
ip = f"{base[0]}.{base[1]}.{base[2]}.{base[3] + idx - 1}" if args.dhcp == 0 else None
|
||||||
|
plan.append(dict(idx=idx, port=port, chip=chip, target=target, ip=ip))
|
||||||
|
|
||||||
|
print("\nPlan:")
|
||||||
|
for d in plan:
|
||||||
|
print(f" {d['idx']:2d} {d['port']} {d['chip']} -> target {d['target']} IP:{d['ip'] or 'DHCP'}")
|
||||||
|
|
||||||
|
if args.dry_run:
|
||||||
|
print("\nDry run only.")
|
||||||
|
return
|
||||||
|
|
||||||
|
failed = []
|
||||||
|
for d in plan:
|
||||||
|
if d['target'] == 'unknown':
|
||||||
|
print(f"\nERROR: Unknown IDF target for {d['port']} (chip '{d['chip']}'). Skipping.")
|
||||||
|
failed.append(d['idx'])
|
||||||
|
continue
|
||||||
|
print(f"\nFlashing {d['port']} as {d['target']}...")
|
||||||
|
if not flash_device(project_dir, d['port'], d['target'], baud=args.baud):
|
||||||
|
failed.append(d['idx'])
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"Configuring Wi‑Fi on {d['port']}...")
|
||||||
|
ok = send_wifi_config(
|
||||||
|
d['port'],
|
||||||
|
args.ssid,
|
||||||
|
args.password,
|
||||||
|
d['ip'],
|
||||||
|
args.mask if d['ip'] else None,
|
||||||
|
args.gw if d['ip'] else None,
|
||||||
|
dhcp=(args.dhcp == 1),
|
||||||
|
baud=args.cfg_baud,
|
||||||
|
)
|
||||||
|
if not ok:
|
||||||
|
print(f" WARN: config not acknowledged on {d['port']}")
|
||||||
|
|
||||||
|
if failed:
|
||||||
|
print(f"\nCompleted with flashing failures on: {failed}")
|
||||||
|
sys.exit(3)
|
||||||
|
print("\nAll done.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -1,2 +1,8 @@
|
||||||
idf_component_register(SRCS "main.c" "iperf.c"
|
idf_component_register(
|
||||||
INCLUDE_DIRS ".")
|
SRCS
|
||||||
|
"main.c"
|
||||||
|
"iperf.c"
|
||||||
|
"wifi_cfg.c"
|
||||||
|
INCLUDE_DIRS
|
||||||
|
"."
|
||||||
|
)
|
||||||
|
|
|
||||||
272
main/main.c
272
main/main.c
|
|
@ -1,137 +1,41 @@
|
||||||
|
// main.c — Add support for wifi_cfg and ip address assignment
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "freertos/event_groups.h"
|
#include "freertos/event_groups.h"
|
||||||
|
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include "esp_wifi.h"
|
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_mac.h"
|
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "esp_console.h"
|
#include "esp_console.h"
|
||||||
#include "argtable3/argtable3.h"
|
#include "argtable3/argtable3.h"
|
||||||
|
|
||||||
#include "esp_netif.h"
|
#include "esp_netif.h"
|
||||||
#include "lwip/inet.h"
|
#include "lwip/inet.h"
|
||||||
#include "iperf.h"
|
|
||||||
|
|
||||||
#define WIFI_SSID CONFIG_WIFI_SSID
|
#include "iperf.h"
|
||||||
#define WIFI_PASS CONFIG_WIFI_PASSWORD
|
#include "wifi_cfg.h"
|
||||||
#define WIFI_MAXIMUM_RETRY CONFIG_WIFI_MAXIMUM_RETRY
|
|
||||||
|
|
||||||
static const char *TAG = "main";
|
static const char *TAG = "main";
|
||||||
|
|
||||||
static EventGroupHandle_t s_wifi_event_group;
|
|
||||||
#define WIFI_CONNECTED_BIT BIT0
|
|
||||||
#define WIFI_FAIL_BIT BIT1
|
|
||||||
|
|
||||||
static int s_retry_num = 0;
|
|
||||||
|
|
||||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||||
int32_t event_id, void* event_data)
|
int32_t event_id, void* event_data)
|
||||||
{
|
{
|
||||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||||
esp_wifi_connect();
|
|
||||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) {
|
|
||||||
wifi_event_sta_connected_t* event = (wifi_event_sta_connected_t*) event_data;
|
|
||||||
|
|
||||||
// Get RSSI
|
|
||||||
wifi_ap_record_t ap_info;
|
|
||||||
esp_wifi_sta_get_ap_info(&ap_info);
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Connected to AP SSID:%.*s, BSSID:" MACSTR " Channel:%d RSSI:%d dBm",
|
|
||||||
event->ssid_len, (const char *)event->ssid, MAC2STR(event->bssid), event->channel, ap_info.rssi);
|
|
||||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
|
||||||
if (s_retry_num < WIFI_MAXIMUM_RETRY) {
|
|
||||||
esp_wifi_connect();
|
|
||||||
s_retry_num++;
|
|
||||||
ESP_LOGI(TAG, "retry to connect to the AP");
|
|
||||||
} else {
|
|
||||||
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
|
|
||||||
}
|
|
||||||
ESP_LOGI(TAG,"connect to the AP fail");
|
|
||||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
|
||||||
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
|
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
|
||||||
ESP_LOGI(TAG, "got ip:" IPSTR " gw:" IPSTR " netmask:" IPSTR,
|
ESP_LOGI(TAG, "got ip:" IPSTR " gw:" IPSTR " netmask:" IPSTR,
|
||||||
IP2STR(&event->ip_info.ip),
|
IP2STR(&event->ip_info.ip),
|
||||||
IP2STR(&event->ip_info.gw),
|
IP2STR(&event->ip_info.gw),
|
||||||
IP2STR(&event->ip_info.netmask));
|
IP2STR(&event->ip_info.netmask));
|
||||||
s_retry_num = 0;
|
|
||||||
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void wifi_init_sta(void)
|
|
||||||
{
|
|
||||||
s_wifi_event_group = xEventGroupCreate();
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_netif_init());
|
|
||||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
|
||||||
|
|
||||||
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
|
|
||||||
|
|
||||||
#ifdef CONFIG_USE_STATIC_IP
|
|
||||||
// Configure static IP
|
|
||||||
ESP_LOGI(TAG, "Configuring static IP: %s", CONFIG_STATIC_IP_ADDR);
|
|
||||||
|
|
||||||
esp_netif_dhcpc_stop(sta_netif);
|
|
||||||
|
|
||||||
esp_netif_ip_info_t ip_info;
|
|
||||||
memset(&ip_info, 0, sizeof(esp_netif_ip_info_t));
|
|
||||||
|
|
||||||
ip_info.ip.addr = ipaddr_addr(CONFIG_STATIC_IP_ADDR);
|
|
||||||
ip_info.gw.addr = ipaddr_addr(CONFIG_STATIC_GATEWAY_ADDR);
|
|
||||||
ip_info.netmask.addr = ipaddr_addr(CONFIG_STATIC_NETMASK_ADDR);
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_netif_set_ip_info(sta_netif, &ip_info));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
|
||||||
|
|
||||||
esp_event_handler_instance_t instance_any_id;
|
|
||||||
esp_event_handler_instance_t instance_got_ip;
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
|
|
||||||
ESP_EVENT_ANY_ID,
|
|
||||||
&event_handler,
|
|
||||||
NULL,
|
|
||||||
&instance_any_id));
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
|
|
||||||
IP_EVENT_STA_GOT_IP,
|
|
||||||
&event_handler,
|
|
||||||
NULL,
|
|
||||||
&instance_got_ip));
|
|
||||||
|
|
||||||
wifi_config_t wifi_config = {
|
|
||||||
.sta = {
|
|
||||||
.ssid = WIFI_SSID,
|
|
||||||
.password = WIFI_PASS,
|
|
||||||
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_start() );
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "wifi_init_sta finished.");
|
|
||||||
|
|
||||||
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
|
||||||
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
|
|
||||||
pdFALSE,
|
|
||||||
pdFALSE,
|
|
||||||
portMAX_DELAY);
|
|
||||||
|
|
||||||
if (bits & WIFI_CONNECTED_BIT) {
|
|
||||||
ESP_LOGI(TAG, "WiFi connection successful");
|
|
||||||
} else if (bits & WIFI_FAIL_BIT) {
|
|
||||||
ESP_LOGI(TAG, "Failed to connect to SSID:%s", WIFI_SSID);
|
|
||||||
} else {
|
|
||||||
ESP_LOGE(TAG, "UNEXPECTED EVENT");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Console command structure for iperf */
|
|
||||||
static struct {
|
static struct {
|
||||||
struct arg_str *ip;
|
struct arg_str *ip;
|
||||||
struct arg_lit *server;
|
struct arg_lit *server;
|
||||||
|
|
@ -145,74 +49,6 @@ static struct {
|
||||||
struct arg_end *end;
|
struct arg_end *end;
|
||||||
} iperf_args;
|
} iperf_args;
|
||||||
|
|
||||||
/* Console command structure for wifi config */
|
|
||||||
static struct {
|
|
||||||
struct arg_str *ssid;
|
|
||||||
struct arg_str *password;
|
|
||||||
struct arg_end *end;
|
|
||||||
} wifi_args;
|
|
||||||
|
|
||||||
static int cmd_wifi(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int nerrors = arg_parse(argc, argv, (void **)&wifi_args);
|
|
||||||
if (nerrors != 0) {
|
|
||||||
arg_print_errors(stderr, wifi_args.end, argv[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wifi_args.ssid->count == 0) {
|
|
||||||
ESP_LOGE(TAG, "Please provide SSID with -s option");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
wifi_config_t wifi_config;
|
|
||||||
memset(&wifi_config, 0, sizeof(wifi_config_t));
|
|
||||||
|
|
||||||
// Set SSID
|
|
||||||
strncpy((char *)wifi_config.sta.ssid, wifi_args.ssid->sval[0], sizeof(wifi_config.sta.ssid) - 1);
|
|
||||||
|
|
||||||
// Set password if provided
|
|
||||||
if (wifi_args.password->count > 0) {
|
|
||||||
strncpy((char *)wifi_config.sta.password, wifi_args.password->sval[0], sizeof(wifi_config.sta.password) - 1);
|
|
||||||
wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Updating WiFi configuration...");
|
|
||||||
ESP_LOGI(TAG, "SSID: %s", wifi_config.sta.ssid);
|
|
||||||
|
|
||||||
// Stop WiFi
|
|
||||||
esp_wifi_disconnect();
|
|
||||||
esp_wifi_stop();
|
|
||||||
|
|
||||||
// Update config
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
|
||||||
|
|
||||||
// Restart WiFi
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_start());
|
|
||||||
esp_wifi_connect();
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "WiFi configuration updated. Attempting to connect...");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void register_wifi(void)
|
|
||||||
{
|
|
||||||
wifi_args.ssid = arg_str1("s", "ssid", "<ssid>", "WiFi SSID");
|
|
||||||
wifi_args.password = arg_str0("p", "password", "<password>", "WiFi password");
|
|
||||||
wifi_args.end = arg_end(1);
|
|
||||||
|
|
||||||
const esp_console_cmd_t wifi_cmd = {
|
|
||||||
.command = "wifi",
|
|
||||||
.help = "Configure WiFi credentials (wifi -s <ssid> -p <password>)",
|
|
||||||
.hint = NULL,
|
|
||||||
.func = &cmd_wifi,
|
|
||||||
.argtable = &wifi_args
|
|
||||||
};
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_console_cmd_register(&wifi_cmd));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmd_iperf(int argc, char **argv)
|
static int cmd_iperf(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int nerrors = arg_parse(argc, argv, (void **)&iperf_args);
|
int nerrors = arg_parse(argc, argv, (void **)&iperf_args);
|
||||||
|
|
@ -221,7 +57,6 @@ static int cmd_iperf(int argc, char **argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if needs to abort */
|
|
||||||
if (iperf_args.abort->count != 0) {
|
if (iperf_args.abort->count != 0) {
|
||||||
iperf_stop();
|
iperf_stop();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -230,10 +65,8 @@ static int cmd_iperf(int argc, char **argv)
|
||||||
iperf_cfg_t cfg;
|
iperf_cfg_t cfg;
|
||||||
memset(&cfg, 0, sizeof(cfg));
|
memset(&cfg, 0, sizeof(cfg));
|
||||||
|
|
||||||
/* Set protocol type */
|
|
||||||
cfg.flag |= (iperf_args.udp->count == 0) ? IPERF_FLAG_TCP : IPERF_FLAG_UDP;
|
cfg.flag |= (iperf_args.udp->count == 0) ? IPERF_FLAG_TCP : IPERF_FLAG_UDP;
|
||||||
|
|
||||||
/* Set server/client mode */
|
|
||||||
if (iperf_args.server->count != 0) {
|
if (iperf_args.server->count != 0) {
|
||||||
cfg.flag |= IPERF_FLAG_SERVER;
|
cfg.flag |= IPERF_FLAG_SERVER;
|
||||||
cfg.sport = IPERF_DEFAULT_PORT;
|
cfg.sport = IPERF_DEFAULT_PORT;
|
||||||
|
|
@ -246,7 +79,7 @@ static int cmd_iperf(int argc, char **argv)
|
||||||
if (iperf_args.port->count != 0) {
|
if (iperf_args.port->count != 0) {
|
||||||
cfg.dport = iperf_args.port->ival[0];
|
cfg.dport = iperf_args.port->ival[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iperf_args.ip->count == 0) {
|
if (iperf_args.ip->count == 0) {
|
||||||
ESP_LOGE(TAG, "Please input destination IP address");
|
ESP_LOGE(TAG, "Please input destination IP address");
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -258,84 +91,61 @@ static int cmd_iperf(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set test time */
|
|
||||||
cfg.time = IPERF_DEFAULT_TIME;
|
cfg.time = IPERF_DEFAULT_TIME;
|
||||||
if (iperf_args.time->count != 0) {
|
if (iperf_args.time->count != 0) {
|
||||||
cfg.time = iperf_args.time->ival[0];
|
cfg.time = iperf_args.time->ival[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set bandwidth limit for UDP */
|
|
||||||
cfg.bw_lim = 0;
|
cfg.bw_lim = 0;
|
||||||
if (iperf_args.bw->count != 0) {
|
if (iperf_args.bw->count != 0) {
|
||||||
cfg.bw_lim = iperf_args.bw->ival[0];
|
cfg.bw_lim = iperf_args.bw->ival[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "mode=%s-%s sport=%u, dip=%u.%u.%u.%u:%u, interval=%" PRIu32 ", time=%" PRIu32,
|
if (iperf_args.interval->count != 0) {
|
||||||
(cfg.flag & IPERF_FLAG_TCP) ? "tcp" : "udp",
|
cfg.interval = iperf_args.interval->ival[0];
|
||||||
(cfg.flag & IPERF_FLAG_SERVER) ? "server" : "client",
|
}
|
||||||
cfg.sport,
|
|
||||||
cfg.dip & 0xFF, (cfg.dip >> 8) & 0xFF, (cfg.dip >> 16) & 0xFF, (cfg.dip >> 24) & 0xFF, cfg.dport,
|
|
||||||
cfg.interval, cfg.time);
|
|
||||||
|
|
||||||
iperf_start(&cfg);
|
iperf_start(&cfg);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void register_iperf(void)
|
static void register_iperf(void)
|
||||||
{
|
{
|
||||||
iperf_args.ip = arg_str0("c", "client", "<ip>", "run in client mode, connecting to <host>");
|
iperf_args.ip = arg_str0("c", "client_ip", "<ip>", "Destination IP for client mode");
|
||||||
iperf_args.server = arg_lit0("s", "server", "run in server mode");
|
iperf_args.server = arg_lit0("s", "server", "Run as server");
|
||||||
iperf_args.udp = arg_lit0("u", "udp", "use UDP rather than TCP");
|
iperf_args.udp = arg_lit0("u", "udp", "Use UDP (default TCP)");
|
||||||
iperf_args.port = arg_int0("p", "port", "<port>", "server port to listen on/connect to");
|
iperf_args.client = arg_lit0("c", "client", "Run as client");
|
||||||
iperf_args.interval = arg_int0("i", "interval", "<interval>", "seconds between periodic bandwidth reports");
|
iperf_args.port = arg_int0("p", "port", "<n>", "Port (default 5001)");
|
||||||
iperf_args.time = arg_int0("t", "time", "<time>", "time in seconds to transmit for (default 30 secs)");
|
iperf_args.interval = arg_int0("i", "interval", "<s>", "Report interval");
|
||||||
iperf_args.bw = arg_int0("b", "bandwidth", "<bandwidth>", "bandwidth to send at in Mbits/sec");
|
iperf_args.time = arg_int0("t", "time", "<s>", "Test duration");
|
||||||
iperf_args.abort = arg_lit0("a", "abort", "abort running iperf");
|
iperf_args.bw = arg_int0("b", "bandwidth", "<kbps>", "UDP bandwidth");
|
||||||
iperf_args.end = arg_end(1);
|
iperf_args.abort = arg_lit0(NULL, "abort", "Abort iperf");
|
||||||
|
iperf_args.end = arg_end(2);
|
||||||
|
|
||||||
const esp_console_cmd_t iperf_cmd = {
|
const esp_console_cmd_t cmd = {
|
||||||
.command = "iperf",
|
.command = "iperf",
|
||||||
.help = "iperf command",
|
.help = "iperf traffic test (server/client, TCP/UDP)",
|
||||||
.hint = NULL,
|
.hint = NULL,
|
||||||
.func = &cmd_iperf,
|
.func = &cmd_iperf,
|
||||||
.argtable = &iperf_args
|
.argtable= &iperf_args
|
||||||
};
|
};
|
||||||
|
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
|
||||||
ESP_ERROR_CHECK(esp_console_cmd_register(&iperf_cmd));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void initialize_console(void)
|
|
||||||
{
|
|
||||||
esp_console_repl_t *repl = NULL;
|
|
||||||
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
|
|
||||||
repl_config.prompt = "iperf>";
|
|
||||||
|
|
||||||
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
|
|
||||||
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl));
|
|
||||||
|
|
||||||
register_iperf();
|
|
||||||
register_wifi();
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_console_start_repl(repl));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "ESP32 iperf starting...");
|
ESP_ERROR_CHECK(nvs_flash_init());
|
||||||
|
ESP_ERROR_CHECK(esp_netif_init());
|
||||||
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
|
||||||
// Initialize NVS
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
||||||
esp_err_t ret = nvs_flash_init();
|
IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, NULL));
|
||||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
|
||||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
|
||||||
ret = nvs_flash_init();
|
|
||||||
}
|
|
||||||
ESP_ERROR_CHECK(ret);
|
|
||||||
|
|
||||||
// Initialize WiFi
|
wifi_cfg_init();
|
||||||
wifi_init_sta();
|
wifi_cfg_apply_from_nvs();
|
||||||
|
|
||||||
// Initialize console
|
register_iperf();
|
||||||
initialize_console();
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Ready. Type 'iperf --help' for usage");
|
ESP_LOGI(TAG, "System init complete. Waiting for serial config or console commands.");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,167 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "esp_system.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 "driver/uart.h"
|
||||||
|
#include "esp_vfs_dev.h"
|
||||||
|
#include "driver/usb_serial_jtag.h"
|
||||||
|
|
||||||
|
static const char *TAG = "wifi_cfg";
|
||||||
|
|
||||||
|
static void trim(char *s){
|
||||||
|
int n = strlen(s);
|
||||||
|
while(n>0 && (s[n-1]=='\r' || s[n-1]=='\n' || isspace((unsigned char)s[n-1]))) s[--n]=0;
|
||||||
|
while(*s && isspace((unsigned char)*s)) memmove(s, s+1, strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 bool cfg_dhcp = true;
|
||||||
|
|
||||||
|
static void save_cfg(const char* ssid, const char* pass, const char* ip, const char* mask, const char* gw, bool dhcp){
|
||||||
|
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);
|
||||||
|
nvs_set_u8(h, "dhcp", dhcp ? 1 : 0);
|
||||||
|
nvs_commit(h);
|
||||||
|
nvs_close(h);
|
||||||
|
cfg_dhcp = dhcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 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;
|
||||||
|
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; }
|
||||||
|
|
||||||
|
static esp_netif_t *sta_netif = NULL;
|
||||||
|
|
||||||
|
static void apply_ip_static(const char* ip, const char* mask, const char* gw){
|
||||||
|
if (!sta_netif) 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};
|
||||||
|
bool dhcp = true;
|
||||||
|
if (!load_cfg(ssid,sizeof(ssid), pass,sizeof(pass), ip,sizeof(ip), mask,sizeof(mask), gw,sizeof(gw), &dhcp)){
|
||||||
|
ESP_LOGW(TAG, "No Wi‑Fi config in NVS");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ESP_LOGI(TAG, "Applying Wi‑Fi config: SSID=%s DHCP=%d IP=%s", ssid, dhcp, ip);
|
||||||
|
|
||||||
|
static bool inited = false;
|
||||||
|
if (!inited){
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_init());
|
||||||
|
ESP_ERROR_CHECK(esp_netif_init());
|
||||||
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
sta_netif = esp_netif_create_default_wifi_sta();
|
||||||
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
|
||||||
|
inited = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
wifi_config_t wcfg = {0};
|
||||||
|
strncpy((char*)wcfg.sta.ssid, ssid, sizeof(wcfg.sta.ssid)-1);
|
||||||
|
strncpy((char*)wcfg.sta.password, pass, sizeof(wcfg.sta.password)-1);
|
||||||
|
wcfg.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
|
||||||
|
wcfg.sta.sae_pwe_h2e = WPA3_SAE_PWE_BOTH;
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wcfg) );
|
||||||
|
|
||||||
|
if (!dhcp && ip[0] && mask[0] && gw[0]){
|
||||||
|
apply_ip_static(ip, mask, gw);
|
||||||
|
}else{
|
||||||
|
if (sta_netif) esp_netif_dhcpc_start(sta_netif);
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_start() );
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_connect() );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cfg_listener_task(void *arg){
|
||||||
|
// Install low-level USB-Serial/JTAG driver
|
||||||
|
usb_serial_jtag_driver_config_t dcfg = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT();
|
||||||
|
ESP_ERROR_CHECK(usb_serial_jtag_driver_install(&dcfg));
|
||||||
|
|
||||||
|
// Bind stdio to that driver (deprecated name, but available on IDF v5.3.1)
|
||||||
|
esp_vfs_usb_serial_jtag_use_driver();
|
||||||
|
|
||||||
|
// Now stdio is safe to use
|
||||||
|
setvbuf(stdin, NULL, _IONBF, 0);
|
||||||
|
setvbuf(stdout, NULL, _IONBF, 0);
|
||||||
|
|
||||||
|
char line[160];
|
||||||
|
char ssid[64]={0}, pass[64]={0}, ip[32]={0}, mask[32]={0}, gw[32]={0};
|
||||||
|
bool dhcp = true;
|
||||||
|
bool in_cfg = false;
|
||||||
|
|
||||||
|
while (1){
|
||||||
|
if (!fgets(line, sizeof(line), stdin)){
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(50));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// ... rest unchanged ...
|
||||||
|
trim(line);
|
||||||
|
if (!in_cfg){
|
||||||
|
if (strcmp(line, "CFG")==0){
|
||||||
|
in_cfg = true;
|
||||||
|
ssid[0]=pass[0]=ip[0]=mask[0]=gw[0]=0;
|
||||||
|
dhcp = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strcmp(line, "END")==0){
|
||||||
|
save_cfg(ssid, pass, ip, mask, gw, dhcp);
|
||||||
|
printf("OK\n");
|
||||||
|
wifi_cfg_apply_from_nvs();
|
||||||
|
in_cfg = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strncmp(line, "SSID:",5)==0){ strncpy(ssid, line+5, sizeof(ssid)-1); continue; }
|
||||||
|
if (strncmp(line, "PASS:",5)==0){ strncpy(pass, line+5, sizeof(pass)-1); continue; }
|
||||||
|
if (strncmp(line, "IP:",3)==0){ strncpy(ip, line+3, sizeof(ip)-1); continue; }
|
||||||
|
if (strncmp(line, "MASK:",5)==0){ strncpy(mask, line+5, sizeof(mask)-1); continue; }
|
||||||
|
if (strncmp(line, "GW:",3)==0){ strncpy(gw, line+3, sizeof(gw)-1); continue; }
|
||||||
|
if (strncmp(line, "DHCP:",5)==0){ dhcp = atoi(line+5) ? true:false; continue; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_cfg_init(void){
|
||||||
|
nvs_flash_init();
|
||||||
|
xTaskCreatePinnedToCore(cfg_listener_task, "cfg_listener", 6144, NULL, 5, NULL, tskNO_AFFINITY);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
void wifi_cfg_init(void); // starts serial listener task
|
||||||
|
bool wifi_cfg_apply_from_nvs(void); // reads saved config and connects Wi‑Fi
|
||||||
|
void wifi_cfg_force_dhcp(bool enable); // for testing
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Loading…
Reference in New Issue