fix 3.5 touch freeze: async WiFi scan and GT911 reset.

Scan no longer blocks LVGL; always hw-reset GT911; larger buttons and click areas.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-25 20:01:37 +08:00
parent 9cbbb296b7
commit d9773a8b97
7 changed files with 129 additions and 42 deletions

View File

@@ -1,5 +1,5 @@
name: CYD wifitest (cyd_35r)
git: ba09f4f
git: 9cbbb29
date: 2026-10-25
board: ESP32-3248S035 (ST7796)
flash_size: 4MB
@@ -11,5 +11,5 @@ offsets:
sha256:
bootloader.bin 3D234A7471F67B013686DABD4DEE7C1FA915C9928463616A94BC9297ACF1ABF8
boot_app0.bin F94C5D786A7A8FAB06AC5D10E33BF37711A6697636DC037559EA19CC410A17F0
firmware.bin 8632B39F60FF68A0ABD39C49071FF91889F5446D0EC93F7ADF59CDA48AB6D438
firmware.bin DDB6B8EB5091F9C201A1696CEC05BA68E93A512EE7388C66EC7207850B74FC85
partitions.bin 148B959CBFF1C38AA8E1D5C0BA9D612C54997B945E56A63F41223EEF650653A1

Binary file not shown.

View File

@@ -67,9 +67,14 @@ void wifi_prov_connect_saved();
/** 连接指定网络并在成功后写入 NVS */
void wifi_prov_connect_to(const char *ssid, const char *password);
/** 同步扫描,结果写入 out[],返回条数(≤ WIFI_PROV_MAX_SCAN) */
/** 同步扫描(会阻塞数秒;门户 HTML 可用)。屏上 UI 请用异步接口。 */
int wifi_prov_scan(WifiScanItem *out, int max_items);
/** 异步扫描:start 后每 loop 调 poll;完成时写入 out 并返回条数,进行中返回 -1。 */
bool wifi_prov_scan_start();
bool wifi_prov_scan_busy();
int wifi_prov_scan_poll(WifiScanItem *out, int max_items);
/**
* SoftAP + 简易 Captive Portal(手机连 CYD-Setup → http://192.168.4.1)
* 与屏上配网可并行;配网成功后会自动 stop。

View File

@@ -42,9 +42,9 @@ void setup() {
}
void loop() {
wifi_prov_loop();
wifi_ui_tick();
lv_timer_handler();
lv_tick_inc(5);
wifi_prov_loop();
wifi_ui_tick();
delay(5);
}

View File

@@ -101,15 +101,15 @@ void touch_init() {
Wire.setTimeOut(50);
#endif
/* Always hw-reset: probe-only leaves some boards with stuck buffer / bad INT. */
Serial.println("GT911 hw reset 0x5D");
gt_hw_reset(false);
if (!gt_find_addr()) {
Serial.println("GT911 not found — hw reset 0x5D");
gt_hw_reset(false);
if (!gt_find_addr()) {
Serial.println("GT911 not found — hw reset 0x14");
gt_hw_reset(true);
gt_find_addr();
}
Serial.println("GT911 not found — hw reset 0x14");
gt_hw_reset(true);
gt_find_addr();
}
gt_write8(GT_POINT_INFO, 0);
Serial.printf("GT911 probe 0x5D=%s 0x14=%s using=0x%02X\n",
gt_probe(0x5D) ? "OK" : "no", gt_probe(0x14) ? "OK" : "no",

View File

@@ -26,6 +26,7 @@ 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 bool g_scan_async = false;
static void set_state(WifiProvState s) {
if (g_state == s) {
@@ -269,27 +270,11 @@ void wifi_prov_connect_to(const char *ssid, const char *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);
static int fill_scan_results(WifiScanItem *out, int max_items, int found) {
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);
@@ -302,6 +287,76 @@ int wifi_prov_scan(WifiScanItem *out, int max_items) {
return n;
}
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;
}
if (g_scan_async) {
WiFi.scanDelete();
g_scan_async = false;
}
if (g_portal) {
WiFi.mode(WIFI_AP_STA);
} else {
WiFi.mode(WIFI_STA);
}
const int found = WiFi.scanNetworks(/*async=*/false, /*hidden=*/true);
return fill_scan_results(out, max_items, found);
}
bool wifi_prov_scan_start() {
if (g_scan_async) {
return true;
}
if (g_portal) {
WiFi.mode(WIFI_AP_STA);
} else {
WiFi.mode(WIFI_STA);
}
/* async — does not block LVGL loop */
const int16_t rc = WiFi.scanNetworks(/*async=*/true, /*hidden=*/true);
if (rc == WIFI_SCAN_FAILED) {
Serial.println("[wifi] scan start failed");
return false;
}
g_scan_async = true;
Serial.println("[wifi] scan async started");
return true;
}
bool wifi_prov_scan_busy() { return g_scan_async; }
int wifi_prov_scan_poll(WifiScanItem *out, int max_items) {
if (!g_scan_async) {
return 0;
}
if (!out || max_items <= 0) {
return 0;
}
if (max_items > WIFI_PROV_MAX_SCAN) {
max_items = WIFI_PROV_MAX_SCAN;
}
const int16_t found = WiFi.scanComplete();
if (found == WIFI_SCAN_RUNNING) {
return -1;
}
g_scan_async = false;
if (found == WIFI_SCAN_FAILED) {
WiFi.scanDelete();
Serial.println("[wifi] scan failed");
return 0;
}
const int n = fill_scan_results(out, max_items, found);
Serial.printf("[wifi] scan done n=%d\n", n);
return n;
}
void wifi_prov_portal_start(const char *ap_ssid) {
if (g_portal) {
return;

View File

@@ -41,7 +41,9 @@ static int g_item_n = 0;
static char g_pick_ssid[WIFI_PROV_SSID_MAX + 1] = {};
static bool g_on_setup = false;
static bool g_pass_visible = false;
static bool g_scan_pending = false;
static WifiProvState g_last_shown = WIFI_PROV_IDLE;
static uint32_t g_last_status_ms = 0;
static void style_btn(lv_obj_t *btn, uint32_t bg) {
lv_obj_set_style_radius(btn, 8, 0);
@@ -50,6 +52,8 @@ static void style_btn(lv_obj_t *btn, uint32_t bg) {
lv_obj_set_style_shadow_width(btn, 0, 0);
lv_obj_set_style_border_width(btn, 0, 0);
lv_obj_set_style_pad_all(btn, 0, 0);
lv_obj_add_flag(btn, LV_OBJ_FLAG_CLICKABLE);
lv_obj_set_ext_click_area(btn, 12);
}
static lv_obj_t *make_btn(lv_obj_t *parent, const char *text, uint32_t bg,
@@ -62,6 +66,8 @@ static lv_obj_t *make_btn(lv_obj_t *parent, const char *text, uint32_t bg,
lv_obj_set_style_text_color(lab, lv_color_hex(COL_INK), 0);
lv_obj_set_style_text_font(lab, &lv_font_montserrat_14, 0);
lv_obj_center(lab);
/* Label must not steal clicks from the button. */
lv_obj_clear_flag(lab, LV_OBJ_FLAG_CLICKABLE);
if (cb) {
lv_obj_add_event_cb(btn, cb, LV_EVENT_CLICKED, nullptr);
}
@@ -210,6 +216,7 @@ static void rebuild_list() {
lv_obj_set_style_text_color(jl, lv_color_hex(COL_INK), 0);
lv_obj_set_style_text_font(jl, &lv_font_montserrat_14, 0);
lv_obj_center(jl);
lv_obj_clear_flag(jl, LV_OBJ_FLAG_CLICKABLE);
}
lv_obj_add_event_cb(join, on_row_join, LV_EVENT_CLICKED,
(void *)(intptr_t)i);
@@ -217,22 +224,27 @@ static void rebuild_list() {
}
static void do_scan() {
if (g_scan_pending || wifi_prov_scan_busy()) {
set_setup_status("Scanning...");
return;
}
set_setup_status("Scanning...");
lv_timer_handler();
g_item_n = wifi_prov_scan(g_items, WIFI_PROV_MAX_SCAN);
rebuild_list();
char buf[40];
snprintf(buf, sizeof(buf), "Found %d", g_item_n);
set_setup_status(buf);
if (!wifi_prov_scan_start()) {
set_setup_status("Scan failed");
return;
}
g_scan_pending = true;
}
static void on_scan(lv_event_t *e) {
LV_UNUSED(e);
Serial.println("[ui] Scan clicked");
do_scan();
}
static void on_portal(lv_event_t *e) {
LV_UNUSED(e);
Serial.println("[ui] Phone AP clicked");
wifi_prov_portal_start();
set_setup_status("Phone: join CYD-Setup");
}
@@ -382,7 +394,7 @@ static void build_setup() {
lv_obj_align(lbl_setup_status, LV_ALIGN_TOP_RIGHT, UX(-10), UY(10));
lv_obj_t *bar = lv_obj_create(scr_setup);
lv_obj_set_size(bar, UI_HOR_RES - UW(16), UH(36));
lv_obj_set_size(bar, UI_HOR_RES - UW(16), UH(48));
lv_obj_align(bar, LV_ALIGN_TOP_MID, UX(0), UY(34));
lv_obj_set_style_bg_opa(bar, LV_OPA_TRANSP, 0);
lv_obj_set_style_border_width(bar, 0, 0);
@@ -392,17 +404,18 @@ static void build_setup() {
LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_pad_column(bar, UW(8), 0);
lv_obj_clear_flag(bar, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_add_flag(bar, LV_OBJ_FLAG_CLICKABLE);
make_btn(bar, "Scan", COL_BTN_ACC, on_scan, UW(72), UH(32));
make_btn(bar, "Phone AP", COL_BTN, on_portal, UW(96), UH(32));
make_btn(bar, "Scan", COL_BTN_ACC, on_scan, UW(90), UH(42));
make_btn(bar, "Phone AP", COL_BTN, on_portal, UW(110), UH(42));
make_btn(bar, "Status", COL_BTN, [](lv_event_t *e) {
LV_UNUSED(e);
wifi_ui_show_status();
}, UW(72), UH(32));
}, UW(90), UH(42));
list_wifi = lv_obj_create(scr_setup);
lv_obj_set_size(list_wifi, UI_HOR_RES - UW(16), UI_VER_RES - UH(80));
lv_obj_align(list_wifi, LV_ALIGN_TOP_MID, UX(0), UY(74));
lv_obj_set_size(list_wifi, UI_HOR_RES - UW(16), UI_VER_RES - UH(92));
lv_obj_align(list_wifi, LV_ALIGN_TOP_MID, UX(0), UY(86));
lv_obj_set_style_bg_color(list_wifi, lv_color_hex(COL_LINE), 0);
lv_obj_set_style_border_width(list_wifi, 0, 0);
lv_obj_set_style_radius(list_wifi, 8, 0);
@@ -515,6 +528,18 @@ void wifi_ui_show_status() {
bool wifi_ui_is_setup() { return g_on_setup; }
void wifi_ui_tick() {
if (g_scan_pending) {
const int n = wifi_prov_scan_poll(g_items, WIFI_PROV_MAX_SCAN);
if (n >= 0) {
g_scan_pending = false;
g_item_n = n;
rebuild_list();
char buf[40];
snprintf(buf, sizeof(buf), "Found %d", g_item_n);
set_setup_status(buf);
}
}
const WifiProvState st = wifi_prov_state();
if (st != g_last_shown) {
@@ -530,7 +555,9 @@ void wifi_ui_tick() {
}
}
if (!g_on_setup) {
/* Throttle status refresh — every 5ms was wasteful and could feel sticky. */
if (!g_on_setup && (millis() - g_last_status_ms >= 500)) {
g_last_status_ms = millis();
refresh_status_labels();
}
}