diff --git a/firmware/cyd_35r/VERSION.txt b/firmware/cyd_35r/VERSION.txt index 3c0500a..d17f10f 100644 --- a/firmware/cyd_35r/VERSION.txt +++ b/firmware/cyd_35r/VERSION.txt @@ -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 diff --git a/firmware/cyd_35r/firmware.bin b/firmware/cyd_35r/firmware.bin index 75f6920..94961db 100644 Binary files a/firmware/cyd_35r/firmware.bin and b/firmware/cyd_35r/firmware.bin differ diff --git a/include/wifi_prov.h b/include/wifi_prov.h index 0f8daf3..1b33bd3 100644 --- a/include/wifi_prov.h +++ b/include/wifi_prov.h @@ -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。 diff --git a/src/main.cpp b/src/main.cpp index 6eee57f..9253ced 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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); } diff --git a/src/touch.cpp b/src/touch.cpp index bd64e07..fca8f59 100644 --- a/src/touch.cpp +++ b/src/touch.cpp @@ -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", diff --git a/src/wifi_prov.cpp b/src/wifi_prov.cpp index 5e70a99..a388b53 100644 --- a/src/wifi_prov.cpp +++ b/src/wifi_prov.cpp @@ -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; diff --git a/src/wifi_ui.cpp b/src/wifi_ui.cpp index 6ab50c0..13becb1 100644 --- a/src/wifi_ui.cpp +++ b/src/wifi_ui.cpp @@ -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(); } }