fix 3.5 backlight and GT911 for cyd_35r.
TFT_BL was wrongly GPIO21 (GT911 INT); use GPIO27, DRAW_BUF_DIV=20, and export firmware/cyd_35r. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
403
src/wifi_prov.cpp
Normal file
403
src/wifi_prov.cpp
Normal file
@@ -0,0 +1,403 @@
|
||||
#include "wifi_prov.h"
|
||||
|
||||
#include <DNSServer.h>
|
||||
#include <Preferences.h>
|
||||
#include <WebServer.h>
|
||||
#include <cstring>
|
||||
|
||||
static constexpr const char *NVS_NS = "wifi_prov";
|
||||
static constexpr const char *NVS_SSID = "ssid";
|
||||
static constexpr const char *NVS_PASS = "pass";
|
||||
|
||||
static Preferences g_prefs;
|
||||
static WifiProvState g_state = WIFI_PROV_IDLE;
|
||||
static WifiProvStateCb g_cb = nullptr;
|
||||
static void *g_cb_user = nullptr;
|
||||
|
||||
static char g_ssid[WIFI_PROV_SSID_MAX + 1] = {};
|
||||
static char g_pass[WIFI_PROV_PASS_MAX + 1] = {};
|
||||
static bool g_has_creds = false;
|
||||
|
||||
static uint32_t g_connect_started_ms = 0;
|
||||
static uint32_t g_last_reconnect_ms = 0;
|
||||
static bool g_want_connect = false;
|
||||
|
||||
static DNSServer *g_dns = nullptr;
|
||||
static WebServer *g_http = nullptr;
|
||||
static bool g_portal = false;
|
||||
static char g_ap_ssid[33] = WIFI_PROV_AP_SSID;
|
||||
|
||||
static void set_state(WifiProvState s) {
|
||||
if (g_state == s) {
|
||||
return;
|
||||
}
|
||||
g_state = s;
|
||||
if (g_cb) {
|
||||
g_cb(s, g_cb_user);
|
||||
}
|
||||
}
|
||||
|
||||
static void load_creds() {
|
||||
g_has_creds = false;
|
||||
g_ssid[0] = '\0';
|
||||
g_pass[0] = '\0';
|
||||
if (!g_prefs.begin(NVS_NS, true)) {
|
||||
return;
|
||||
}
|
||||
String ssid = g_prefs.getString(NVS_SSID, "");
|
||||
String pass = g_prefs.getString(NVS_PASS, "");
|
||||
g_prefs.end();
|
||||
if (ssid.length() == 0 || ssid.length() > WIFI_PROV_SSID_MAX) {
|
||||
return;
|
||||
}
|
||||
strncpy(g_ssid, ssid.c_str(), WIFI_PROV_SSID_MAX);
|
||||
g_ssid[WIFI_PROV_SSID_MAX] = '\0';
|
||||
strncpy(g_pass, pass.c_str(), WIFI_PROV_PASS_MAX);
|
||||
g_pass[WIFI_PROV_PASS_MAX] = '\0';
|
||||
g_has_creds = true;
|
||||
}
|
||||
|
||||
static void begin_sta_connect(const char *ssid, const char *password) {
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.setAutoReconnect(true);
|
||||
WiFi.persistent(false);
|
||||
WiFi.disconnect(false, true);
|
||||
delay(50);
|
||||
WiFi.begin(ssid, password);
|
||||
g_want_connect = true;
|
||||
g_connect_started_ms = millis();
|
||||
g_last_reconnect_ms = millis();
|
||||
set_state(WIFI_PROV_CONNECTING);
|
||||
Serial.printf("[wifi] connecting to \"%s\"...\n", ssid);
|
||||
}
|
||||
|
||||
static String html_escape(const String &s) {
|
||||
String o;
|
||||
o.reserve(s.length());
|
||||
for (size_t i = 0; i < s.length(); ++i) {
|
||||
const char c = s[i];
|
||||
if (c == '&') {
|
||||
o += "&";
|
||||
} else if (c == '<') {
|
||||
o += "<";
|
||||
} else if (c == '>') {
|
||||
o += ">";
|
||||
} else if (c == '"') {
|
||||
o += """;
|
||||
} else {
|
||||
o += c;
|
||||
}
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
static String portal_page() {
|
||||
WifiScanItem items[WIFI_PROV_MAX_SCAN];
|
||||
const int n = wifi_prov_scan(items, WIFI_PROV_MAX_SCAN);
|
||||
|
||||
String html;
|
||||
html.reserve(2048);
|
||||
html += F("<!DOCTYPE html><html><head><meta charset=utf-8>"
|
||||
"<meta name=viewport content=\"width=device-width,initial-scale=1\">"
|
||||
"<title>CYD WiFi</title>"
|
||||
"<style>"
|
||||
"body{font-family:system-ui,sans-serif;margin:16px;background:#0f1419;color:#eaf0f6}"
|
||||
"h1{font-size:1.25rem}label{display:block;margin:.6rem 0 .2rem;color:#9ab}"
|
||||
"input,select,button{width:100%;box-sizing:border-box;padding:.7rem;border-radius:8px;"
|
||||
"border:1px solid #334;background:#1a2330;color:#eaf0f6;font-size:1rem}"
|
||||
"button{margin-top:1rem;background:#1a6aa8;border:none;font-weight:600}"
|
||||
".hint{color:#7a8b9c;font-size:.85rem;margin-top:1rem}"
|
||||
"</style></head><body>"
|
||||
"<h1>WiFi Setup</h1>"
|
||||
"<form method=POST action=/save>"
|
||||
"<label>Network</label><select name=ssid>");
|
||||
|
||||
if (n <= 0) {
|
||||
html += F("<option value=\"\">(no networks — type below)</option>");
|
||||
} else {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
html += F("<option value=\"");
|
||||
html += html_escape(String(items[i].ssid));
|
||||
html += F("\">");
|
||||
html += html_escape(String(items[i].ssid));
|
||||
html += F(" (");
|
||||
html += String(items[i].rssi);
|
||||
html += F(" dBm)</option>");
|
||||
}
|
||||
}
|
||||
|
||||
html += F("</select>"
|
||||
"<label>Or SSID</label><input name=ssid_manual placeholder=\"manual SSID\">"
|
||||
"<label>Password</label><input name=pass type=password placeholder=\"WiFi password\">"
|
||||
"<button type=submit>Save & Connect</button>"
|
||||
"</form>"
|
||||
"<p class=hint>AP: ");
|
||||
html += html_escape(String(g_ap_ssid));
|
||||
html += F(" · http://192.168.4.1/</p></body></html>");
|
||||
return html;
|
||||
}
|
||||
|
||||
static void handle_root() {
|
||||
g_http->send(200, "text/html", portal_page());
|
||||
}
|
||||
|
||||
static void handle_save() {
|
||||
String ssid = g_http->arg("ssid_manual");
|
||||
ssid.trim();
|
||||
if (ssid.length() == 0) {
|
||||
ssid = g_http->arg("ssid");
|
||||
ssid.trim();
|
||||
}
|
||||
String pass = g_http->arg("pass");
|
||||
|
||||
g_http->send(200, "text/html",
|
||||
F("<!DOCTYPE html><html><body style=\"font-family:sans-serif;background:#0f1419;"
|
||||
"color:#eaf0f6;padding:24px\"><h2>Connecting...</h2>"
|
||||
"<p>You can close this page. Device will leave setup AP.</p></body></html>"));
|
||||
|
||||
if (ssid.length() > 0) {
|
||||
delay(200);
|
||||
wifi_prov_portal_stop();
|
||||
wifi_prov_connect_to(ssid.c_str(), pass.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_captive() {
|
||||
g_http->sendHeader("Location", "http://192.168.4.1/", true);
|
||||
g_http->send(302, "text/plain", "");
|
||||
}
|
||||
|
||||
static void handle_not_found() {
|
||||
handle_captive();
|
||||
}
|
||||
|
||||
void wifi_prov_set_state_cb(WifiProvStateCb cb, void *user) {
|
||||
g_cb = cb;
|
||||
g_cb_user = user;
|
||||
}
|
||||
|
||||
bool wifi_prov_begin() {
|
||||
load_creds();
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.setAutoReconnect(true);
|
||||
WiFi.persistent(false);
|
||||
|
||||
if (g_has_creds) {
|
||||
begin_sta_connect(g_ssid, g_pass);
|
||||
} else {
|
||||
set_state(WIFI_PROV_IDLE);
|
||||
Serial.println("[wifi] no credentials");
|
||||
}
|
||||
return g_has_creds;
|
||||
}
|
||||
|
||||
bool wifi_prov_has_credentials() { return g_has_creds; }
|
||||
|
||||
bool wifi_prov_is_connected() {
|
||||
return WiFi.status() == WL_CONNECTED;
|
||||
}
|
||||
|
||||
WifiProvState wifi_prov_state() { return g_state; }
|
||||
|
||||
String wifi_prov_ssid() {
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
return WiFi.SSID();
|
||||
}
|
||||
return String(g_ssid);
|
||||
}
|
||||
|
||||
String wifi_prov_ip() {
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
return String();
|
||||
}
|
||||
return WiFi.localIP().toString();
|
||||
}
|
||||
|
||||
int8_t wifi_prov_rssi() {
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
return 0;
|
||||
}
|
||||
return (int8_t)WiFi.RSSI();
|
||||
}
|
||||
|
||||
void wifi_prov_save(const char *ssid, const char *password) {
|
||||
if (!ssid || !ssid[0]) {
|
||||
return;
|
||||
}
|
||||
strncpy(g_ssid, ssid, WIFI_PROV_SSID_MAX);
|
||||
g_ssid[WIFI_PROV_SSID_MAX] = '\0';
|
||||
if (password) {
|
||||
strncpy(g_pass, password, WIFI_PROV_PASS_MAX);
|
||||
} else {
|
||||
g_pass[0] = '\0';
|
||||
}
|
||||
g_pass[WIFI_PROV_PASS_MAX] = '\0';
|
||||
g_has_creds = true;
|
||||
|
||||
if (g_prefs.begin(NVS_NS, false)) {
|
||||
g_prefs.putString(NVS_SSID, g_ssid);
|
||||
g_prefs.putString(NVS_PASS, g_pass);
|
||||
g_prefs.end();
|
||||
}
|
||||
Serial.printf("[wifi] saved \"%s\"\n", g_ssid);
|
||||
}
|
||||
|
||||
void wifi_prov_clear() {
|
||||
g_ssid[0] = '\0';
|
||||
g_pass[0] = '\0';
|
||||
g_has_creds = false;
|
||||
g_want_connect = false;
|
||||
if (g_prefs.begin(NVS_NS, false)) {
|
||||
g_prefs.clear();
|
||||
g_prefs.end();
|
||||
}
|
||||
WiFi.disconnect(true, true);
|
||||
set_state(WIFI_PROV_IDLE);
|
||||
Serial.println("[wifi] credentials cleared");
|
||||
}
|
||||
|
||||
void wifi_prov_connect_saved() {
|
||||
if (!g_has_creds) {
|
||||
set_state(WIFI_PROV_FAILED);
|
||||
return;
|
||||
}
|
||||
begin_sta_connect(g_ssid, g_pass);
|
||||
}
|
||||
|
||||
void wifi_prov_connect_to(const char *ssid, const char *password) {
|
||||
wifi_prov_save(ssid, password ? password : "");
|
||||
begin_sta_connect(g_ssid, g_pass);
|
||||
}
|
||||
|
||||
int wifi_prov_scan(WifiScanItem *out, int max_items) {
|
||||
if (!out || max_items <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (max_items > WIFI_PROV_MAX_SCAN) {
|
||||
max_items = WIFI_PROV_MAX_SCAN;
|
||||
}
|
||||
|
||||
// SoftAP 时用 APSTA,否则扫描会关掉 AP
|
||||
if (g_portal) {
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
} else {
|
||||
WiFi.mode(WIFI_STA);
|
||||
}
|
||||
|
||||
const int found = WiFi.scanNetworks(/*async=*/false, /*hidden=*/true);
|
||||
if (found <= 0) {
|
||||
WiFi.scanDelete();
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int n = found < max_items ? found : max_items;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
String s = WiFi.SSID(i);
|
||||
strncpy(out[i].ssid, s.c_str(), WIFI_PROV_SSID_MAX);
|
||||
out[i].ssid[WIFI_PROV_SSID_MAX] = '\0';
|
||||
out[i].rssi = WiFi.RSSI(i);
|
||||
out[i].auth = WiFi.encryptionType(i);
|
||||
}
|
||||
WiFi.scanDelete();
|
||||
return n;
|
||||
}
|
||||
|
||||
void wifi_prov_portal_start(const char *ap_ssid) {
|
||||
if (g_portal) {
|
||||
return;
|
||||
}
|
||||
if (ap_ssid && ap_ssid[0]) {
|
||||
strncpy(g_ap_ssid, ap_ssid, sizeof(g_ap_ssid) - 1);
|
||||
g_ap_ssid[sizeof(g_ap_ssid) - 1] = '\0';
|
||||
}
|
||||
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
WiFi.softAP(g_ap_ssid);
|
||||
delay(100);
|
||||
|
||||
g_dns = new DNSServer();
|
||||
g_http = new WebServer(80);
|
||||
g_dns->start(53, "*", WiFi.softAPIP());
|
||||
|
||||
g_http->on("/", HTTP_GET, handle_root);
|
||||
g_http->on("/save", HTTP_POST, handle_save);
|
||||
g_http->on("/generate_204", HTTP_GET, handle_captive);
|
||||
g_http->on("/gen_204", HTTP_GET, handle_captive);
|
||||
g_http->on("/hotspot-detect.html", HTTP_GET, handle_root);
|
||||
g_http->on("/connecttest.txt", HTTP_GET, handle_captive);
|
||||
g_http->on("/ncsi.txt", HTTP_GET, handle_captive);
|
||||
g_http->onNotFound(handle_not_found);
|
||||
g_http->begin();
|
||||
|
||||
g_portal = true;
|
||||
set_state(WIFI_PROV_PORTAL);
|
||||
Serial.printf("[wifi] portal AP \"%s\" @ %s\n", g_ap_ssid,
|
||||
WiFi.softAPIP().toString().c_str());
|
||||
}
|
||||
|
||||
void wifi_prov_portal_stop() {
|
||||
if (!g_portal) {
|
||||
return;
|
||||
}
|
||||
if (g_http) {
|
||||
g_http->stop();
|
||||
delete g_http;
|
||||
g_http = nullptr;
|
||||
}
|
||||
if (g_dns) {
|
||||
g_dns->stop();
|
||||
delete g_dns;
|
||||
g_dns = nullptr;
|
||||
}
|
||||
WiFi.softAPdisconnect(true);
|
||||
g_portal = false;
|
||||
Serial.println("[wifi] portal stopped");
|
||||
}
|
||||
|
||||
bool wifi_prov_portal_active() { return g_portal; }
|
||||
|
||||
void wifi_prov_loop() {
|
||||
if (g_portal && g_dns && g_http) {
|
||||
g_dns->processNextRequest();
|
||||
g_http->handleClient();
|
||||
}
|
||||
|
||||
const wl_status_t st = WiFi.status();
|
||||
const uint32_t now = millis();
|
||||
|
||||
if (g_want_connect || g_state == WIFI_PROV_CONNECTING) {
|
||||
if (st == WL_CONNECTED) {
|
||||
g_want_connect = false;
|
||||
if (g_portal) {
|
||||
wifi_prov_portal_stop();
|
||||
}
|
||||
set_state(WIFI_PROV_CONNECTED);
|
||||
Serial.printf("[wifi] connected %s ip=%s rssi=%d\n", WiFi.SSID().c_str(),
|
||||
WiFi.localIP().toString().c_str(), WiFi.RSSI());
|
||||
return;
|
||||
}
|
||||
|
||||
if (now - g_connect_started_ms >= WIFI_PROV_CONNECT_TIMEOUT_MS ||
|
||||
st == WL_CONNECT_FAILED || st == WL_NO_SSID_AVAIL) {
|
||||
g_want_connect = false;
|
||||
set_state(WIFI_PROV_FAILED);
|
||||
Serial.println("[wifi] connect failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 已配置且非门户:断线后周期性重连
|
||||
if (g_has_creds && !g_portal && g_state == WIFI_PROV_CONNECTED &&
|
||||
st != WL_CONNECTED) {
|
||||
set_state(WIFI_PROV_CONNECTING);
|
||||
g_want_connect = true;
|
||||
g_connect_started_ms = now;
|
||||
}
|
||||
|
||||
if (g_has_creds && !g_portal && st != WL_CONNECTED &&
|
||||
g_state != WIFI_PROV_CONNECTING &&
|
||||
now - g_last_reconnect_ms >= WIFI_PROV_RECONNECT_MS) {
|
||||
g_last_reconnect_ms = now;
|
||||
begin_sta_connect(g_ssid, g_pass);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user