Repository navigation
fix(ble): drop the forced station switch before the ap scan - #762
Merged
Merged
Conversation
Querying the wifi list switched the radio to station mode first. On BK based platforms that stops the softap and tears down the ongoing ap netcfg. The scan does not need the switch. (cherry picked from commit 0e26266)
KOKO-cyco
force-pushed
the
fix/ble-drop-sta-switch
branch
from
October 22, 2026 02:47
71305e5 to
982fd3f
Compare
shiliu-yang
approved these changes
Oct 26, 2026
maidang-xing
added a commit
that referenced
this pull request
Oct 27, 2026
…tests/docs (#782) * feat(ai-components): language-neutral alert tones + guided WeChat UI fixes (#713) * ai_components/assets: add language-neutral alert tones as local alert pack Replace the localized voice prompts with short synthesized tones when ENABLE_AI_ALERT_TONE is enabled (now the default): - add 4 semantic tones (success / wait / fail / wake) as MP3 C arrays, generated from assets/media/tone_*.mp3 - map all local alert types onto the 4 tones in media_src.h - compile out the zh/en speech packs while tones are enabled, keeping the sources in tree so voice prompts come back by disabling the option The language option still drives on-screen text; only alert playback changes. Set ENABLE_AI_ALERT_TONE=n to restore the speech packs. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(ai-ui): cache storage license in guided wechat state read guided_wechat_state_read() runs from the 1 Hz UI refresh timer and called tuya_authorize_read() on every invocation, re-reading uuid/authkey from KV flash once per second and logging "Authorization read succeeds." at the same rate. The storage license never changes at runtime (no code path writes it after boot and the UI offers no authorization reset), so read it once and serve the cached pointers. The pointers target the authorize module persistent buffers, which stay valid for the firmware lifetime. Co-Authored-By: Claude Code <noreply@anthropic.com> * feat(ai-ui): show SoftAP hotspot name on guided network page While pairing runs, BLE and AP netcfg operate in parallel. Surface the live AP hotspot name under the guide QR so an app-less phone can join the hotspot and reach the captive setup page. - ap_netcfg: store hotspot ssid/ip when the SoftAP starts and expose a read-only getter - guided wechat state: carry ap_ssid/ap_ip in the device state snapshot - guided wechat UI: one muted hint line under the QR ("配网热点:<ssid>" / "Setup hotspot: <ssid>"), only while pairing is live and the hotspot is up Co-Authored-By: Claude Code <noreply@anthropic.com> --------- Co-authored-by: Claude Code <noreply@anthropic.com> * Fix/ai http ca use after free (#719) * fix(ai-http): keep iotdns CA alive until the TLS handshake parses it http_session_send() freed the CA buffer returned by tuya_iotdns_query_domain_certs() right after TUYA_TRANSPORTER_SET_TLS_CONFIG, but the TLS layer only keeps the pointer: tuya_tls_config_set() memcpy-s the config struct, not the certificate data, and mbedtls_x509_crt_parse() does not run until tuya_transporter_connect(). The freed DER block is typically reused by the allocations inside connect (socket, mbedtls contexts), so mbedtls reads garbage and fails with MBEDTLS_ERR_X509_INVALID_FORMAT (-0x2180) -- the outer SEQUENCE tag is no longer 0x30. TLS connections to CDN hosts then fail, e.g. the US-region *.cdn5th.com TTS download, while CN region often survives because the block happens to stay intact. Free cacert after connect returns instead, and reject an empty CA up front the way http_session.c already does. * fix(http-manager): add handler to read response body from HTTP session * chore(platform): bump SIWX917 platform commit (#727) Co-authored-by: guanshan.xu <guanshan.xu@tuya.com> Co-authored-by: Claude Code <noreply@anthropic.com> * fix(p2p): bound sscanf field widths in tuya_sdp.c to prevent stack overflow (#726) tuya_p2p_rtc_sdp_decode() parsed attacker-controlled SDP attributes with unbounded "%s" conversions into fixed-size stack buffers (wms_name, wms_id, msid, track_id, m1-m3, str_pt, str_attr, ssrc, ssrc_rtx). A malicious P2P peer could send overlong tokens in SDP lines such as "a=msid-semantic:" and overflow these buffers, corrupting the stack and potentially achieving remote code execution. Add maximum field widths (size - 1) to every %s conversion so input is safely truncated to the destination buffer size. Verified with an AddressSanitizer PoC that the original code crashes with a stack-buffer-overflow (WRITE of 201 bytes into char[65]) while the patched code parses the same malicious SDP cleanly. * Fix/esp32c2 tls memory (#729) * chore(platform): pin ESP32 platform to 6117745 (esp32c2 support) * feat(board): add esp32c2 boards (ESP32-C2, ESP32C2_DEVKITM_1) - ESP32-C2: generic module board (UART0 20/19, 26MHz-crystal modules) - ESP32C2_DEVKITM_1: Espressif DevKitM-1, BOOT button on GPIO9, WS2812 RGB LED on GPIO8, both registered in board_com_api - saved board configs for the led/button examples * feat(board): default bluetooth off on esp32c2 and drop dead symbol - esp32c2 has only 132KB heap; WiFi + BLE controller do not fit together, so ENABLE_BLUETOOTH now defaults off when CHIP_CHOICE is esp32c2 (still manually enableable); add the missing prompt, following the LINUX platform precedent - remove ENABLE_ESP_DISPLAY: unprompted, default n, zero references; the DISPLAY_NAME it wrapped is owned by src/peripherals/display/Kconfig * feat(board): add WS2812 SPI LED driver for chips without RMT esp32c2 has no RMT peripheral, so the existing ws1280 driver cannot link there (esp_driver_rmt registers nothing). tdd_led_esp_ws1280_spi encodes each 1.25us WS2812 bit as 10 SPI bits @ 8MHz with a 64-byte zero tail for latch reset; requires DMA since polling mode is capped by the 64-byte FIFO. The RMT driver is excluded from esp32c2 builds. * build(platform): pin ESP32 platform revision * fix(tls): handle idle transporter reads * feat(switch-demo): monitor heap after cloud connect * chore(board): remove ESP32C2 devkit config * style(board): trim trailing whitespace * fix(ai): validate media header length before parsing (#734) Signed-off-by: jaeyeong lee <lee@jaeyeong.cc> * feat(display): add SSD2677 hardware SPI driver (#735) * feat(display): support SSD2677 partial refresh and picture demo (#740) * fix(ble): bound peer-controlled lengths on the BLE command path (#742) The BLE receive path sized buffers and copy lengths from fields the peer supplies and validated none of them, so an unauthenticated peer in range of an advertising device could reach memory corruption, a NULL dereference or an unauthenticated factory reset with a single GATT write. Two patterns account for almost all of it: a length computed as `a - b` in unsigned arithmetic without first establishing `a >= b`, and an allocation and a copy sized by different peer-supplied fields. Add the missing bound at each site: - bound the reassembly varints, and the copy, by the received length and the allocation - bound the transparent-channel allocation and copy, and reject a declared length below the channel header or above one frame - validate the sub-packet size the peer requests against a floor and a ceiling, and allocate the replacement before releasing the live buffer - require a per-opcode minimum length before dispatch, and NULL-guard the paths that consume a decoded packet - NUL-terminate the payload handed to cJSON_Parse - require a completed pairing exchange before the commands that destroy device state, and reject keyless frames on an activated device - check the schema datapoint type before reading its enum table - initialise the netcfg response buffer One reported finding is latent and is deliberately left unchanged: with the current field set it produces no out-of-bounds access, and no peer input can change how much is written. Every fix is a check on an existing path: no function is restructured, no interface changes and no frame shape that was accepted before is now rejected, apart from inputs that previously produced a wrapped length, a NULL dereference or an out-of-bounds access. Build-verified for ESP32-S3 and T5AI. * fix(l511g): restore chatbot build and audio playback (#751) * Codex/l511g chatbot audio fix (#753) * fix(l511g): restore chatbot build and audio playback * feat(opus): integrate configurable fixed-point source codec * fix(l511g): enable Opus upload and reserve encoder stack * feat(examples): add Opus encoding benchmark and validation tools * feat(linux): register RDK X5 and update the platform pin (#750) * feat(linux): register RDK X5 and pin merged cross-build support Add the RDK_X5 Linux board selection, minimal board registration, default configuration and build instructions. Follow the existing Ubuntu board template and keep shared peripheral implementations and numbering intact. Pin TuyaOpen-ubuntu to 83e9183e4988b6878cfbe251e7df57c68b124c93, which merged the host cross-compilation support in platform PR #41. Validation: SDK preflight, clean Windows-to-AArch64 switch_demo build, and X5 runtime binding restoration, MQTT connection and time synchronization. Checked configuration selection for Ubuntu, Raspberry_Pi, DshanPi_A1, TaishanPi_3 and RDK_X5; other boards were not built or hardware tested. New C/H files passed the repository format and header checker. * style(linux): trim X5 board template comments * refactor(linux): reuse shared Linux config for RDK X5 * fix(platform): update T5AI commit reference to the latest version (#754) * feat(ble): add WiFi hotspot list query over the transparent channel (#748) * feat(ble): add WiFi hotspot list query over the transparent channel The app can now ask the device for the surrounding WiFi hotspots over the BLE large data transparent channel (0x801E, subcmd 0x0003) and get a JSON list back on 0x801F, so the netcfg UI can show the scan result before the user picks a network. The list is built in ble_wifi_list.c: tal_wifi_all_ap_scan() the APs, sort them by RSSI, cap the count, and emit {"ssid","rssi","sec"} entries. The scan blocks for up to 5s, so the handler only copies the request and runs the work on WORKQ_SYSTEM. Two fixes in ble_channel.c were needed to carry a payload this large: __response_to_app_by_subpack() only ever sent the first subpacket and kept its progress in a global that ble_channle_ack() never reset, so a response longer than one subpacket was truncated and a retransmit could not restart. It now loops over the whole buffer with local progress, and ble_channle_ack() validates its arguments and releases the buffer when the send is done. ble_mgr.c advertises the capability in both places the app looks for it: ADV_FLAG_WIFI_LIST in the scan response flag byte and CombosFlag bit0 in the device info response. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(ble): send every subpacket of a large response ble_packet_resp() wrapped the HAL send in TUYA_CALL_ERR_GOTO(), whose body assigns rt unconditionally. A successful send therefore overwrote the OPRT_SVC_BT_API_TRSMITR_CONTINUE returned by the frame encoder with OPRT_OK, so the while (rt == OPRT_SVC_BT_API_TRSMITR_CONTINUE) loop never ran a second time and only the first subpacket went out. With the app-negotiated pkg_len of 243 the 401-byte WiFi hotspot list needs two subpackets (243 + 161). The app received a truncated JSON and fell back to "scan failed, please enter the SSID manually". Co-Authored-By: Claude Code <noreply@anthropic.com> * feat(ble): let the wifi list query be disabled and reuse a recent scan Every hotspot list request ran its own tal_wifi_all_ap_scan(), which blocks for seconds, and there was no way to turn the capability off on a product that does not want it. Cache the result for 60s so the netcfg UI and the backup network fallback share one scan, force the station mode before scanning, and add ble_wifi_list_enable()/ble_wifi_list_is_enable() so the capability can be switched at runtime. The flag drives ADV_FLAG_WIFI_LIST through tuya_ble_adv_update(), whose declaration moves from a local extern in ble_netcfg.c into ble_mgr.h, and tuya_ble_deinit() releases the cache. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(ble): bound the channel payload handed to cJSON ble_channel_process() dropped the payload length on the floor and handed the channel callback a bare pointer, so both JSON parsers had to rely on the byte after the payload being a NUL that nothing wrote. A legitimate {"cnt":10} request is enough to read past the buffer: cJSON_Parse() calls strlen() on it. Pass the length through ble_channel_fn_t and parse with cJSON_ParseWithLength() in ble_wifi_list.c and ble_netcfg.c. The transparent-channel path already knows the reassembled length, and the non-subpacket path has the raw length, so nothing has to guess. Also reject a payload shorter than the two type bytes instead of reading them, and note on the callback that the buffer is not NUL terminated. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(ble): guard the send path against a deinitialized manager The wifi list scan runs on WORKQ_SYSTEM and tuya_ble_deinit() neither cancels nor waits for it, so a task that finishes after the manager is freed reaches tuya_ble_send_packet() with s_ble_mgr already NULL and dereferences it. Bail out early instead, the way tuya_ble_deinit() and tal_ble_event_callback() already do. This only removes the crash. The task still runs to completion and its response is silently dropped. Co-Authored-By: Claude Code <noreply@anthropic.com> --------- Co-authored-by: guanshan.xu <guanshan.xu@tuya.com> Co-authored-by: Claude Code <noreply@anthropic.com> * fix(boards): register generic ESP32 boards in CMake (#756) * fix(boards): register generic ESP32-S3 board in CMake * fix(boards): add remaining generic ESP32 board CMake files * Yj/add l511c (#757) * feat(board): add L511C_Y6E board support * feat(platform): register L511C platform * refactor(platform): normalize L511C_Y6E platform identity * refactor(platform): normalize L511G_Y7PM platform identity * docs(boards): remove L511 module README files * fix(ai_ui): add null screen checks in UI init functions (#758) * fix(ai_ui): add null screen checks in UI init functions * fix(cli_flash): guard Windows subprocess decode for CP936 On Windows, tyutool and external tools may output ANSI/OEM bytes (e.g. GBK/CP936). Use errors='replace' and system preferred encoding in _do_flash_pipe to prevent UnicodeDecodeError during flash. * fix(cli_flash): robust multi-encoding decode and safe print on Windows - Support hybrid decoding: try UTF-8 first, fallback to system preferred encoding (e.g. CP936/GBK on Windows), and fallback to replace. - Prevent UnicodeEncodeError when printing \ufffd replacement chars to strict GBK stdout on Windows by reconfiguring stdout errors='replace' and fallback safe printing. - Add unit tests in test_cli_flash.py covering stream decoding, safe printing, and pipe execution. * Codex/l511c y7pm (#770) * feat(platform): add L511C_Y7PM SDK porting bridge * feat(boards): register L511C_Y7PM platform and board * feat(switch_demo): add L511C_Y7PM preset and bring-up guide * fix(switch_demo): use board defaults for L511C_Y7PM * fix(platform): keep L511C_Y7PM adaptation in platform repository * build(platform): pin L511C_Y7PM TuyaOpen adaptation * chore(switch_demo): restore README baseline whitespace * feat(peripherals): add SSD2677 rotation and guard button reads Rotate logical MONO frames at 0/90/180/270 degrees in the SSD2677 driver and skip failed button samples. * build(platform): update L511C_Y6E and L511G_Y7PM pins * fix(display): allow platform GPIO numbers beyond common enum range * Revert "Codex/l511c y7pm (#770)" (#775) This reverts commit 3c6fc15. * fix(lan): bound the UDP discovery frame length against the received data (#771) __udp_serv_is_in_packet_vaild() takes the 32-bit length field of an unauthenticated LAN discovery datagram (FRM_TYPE_APP_UDP_BOARDCAST, validated with the fixed app_key2) and uses it as an offset to the frame tail without checking it against recv_datalen. A datagram that passes the 50 byte minimum with length = 0x7FFFFFFF makes the tail memcmp read about 2 GiB past the 512 byte receive buffer, and a frame whose head and tail checks pass is handed to lpv35_frame_parse() with ilen = 22 + length, so the AES-GCM decrypt reads length bytes out of the same buffer. The TCP (lan_tcp_client_sock_read) and AP (ap_netcfg) paths already reject frame_len > received bytes; do the same here. The check subtracts from recv_datalen, and the function has already rejected recv_datalen < LPV35_FRAME_MINI_SIZE (50 > 22), so it cannot wrap. Reproduced at logic level under AddressSanitizer with the function copied verbatim from this tree and a 512 byte heap receive buffer: the unpatched code segfaults in the tail memcmp for length = 0x7FFFFFFF, the patched code rejects it, and well formed frames, frames with trailing padding and the 50 byte minimum frame are still accepted. Refs: #759 * Codex/l511c y7pm (#776) * feat(platform): add L511C_Y7PM SDK porting bridge * feat(boards): register L511C_Y7PM platform and board * feat(switch_demo): add L511C_Y7PM preset and bring-up guide * fix(switch_demo): use board defaults for L511C_Y7PM * fix(platform): keep L511C_Y7PM adaptation in platform repository * build(platform): pin L511C_Y7PM TuyaOpen adaptation * chore(switch_demo): restore README baseline whitespace * feat(peripherals): add SSD2677 rotation and guard button reads Rotate logical MONO frames at 0/90/180/270 degrees in the SSD2677 driver and skip failed button samples. * build(platform): update L511C_Y6E and L511G_Y7PM pins * fix(display): allow platform GPIO numbers beyond common enum range * build(l511c-y7pm): update platform revision for SPI and GPIO support * feat(ble): advertise the wifi list capability and answer netcfg status queries (#764) * feat(ble): answer netcfg status queries and rescan on every list request * feat(ble): advertise the wifi list capability Set the vendor adv flag bit and the dev info combos flag bits for the wifi list, netcfg status, log and ap name so the app issues the list and status queries while provisioning. (cherry picked from commit 29b68a2) --------- Co-authored-by: guanshan.xu <guanshan.xu@tuya.com> * fix(ble): drop the forced station switch before the ap scan (#762) Querying the wifi list switched the radio to station mode first. On BK based platforms that stops the softap and tears down the ongoing ap netcfg. The scan does not need the switch. (cherry picked from commit 0e26266) Co-authored-by: guanshan.xu <guanshan.xu@tuya.com> * feat(ble): gate the WiFi list query behind a Kconfig option (#778) * feat(ble): make the WiFi list capability configurable The query runs a blocking all-AP scan. Boards whose WiFi driver cannot scan while connected (no APSTA) cannot serve it, so add ENABLE_BT_WIFI_LIST under ENABLE_BT_SERVICE to pick the default state. It defaults to off; a platform opts in from its OS_SERVICE_Kconfig once validated. * feat(boards): opt T5AI and ESP32 into the BLE WiFi list Both can scan while connected, so select ENABLE_BT_WIFI_LIST. On ESP32 it is conditional on ENABLE_BLUETOOTH, which stays off on esp32c2. --------- Co-authored-by: guanshan.xu <guanshan.xu@tuya.com> * chore: remove redundant platform tests and docs to sync tests and docs with master - Remove obsolete tests/platform/ test suite and tests/__init__.py to match master's test layout - Remove docs/jieli_ac791x_ac792x_project_guide.md and docs/jieli_power_management_design.md - Eliminate all remaining references to AC7916A and local drive paths --------- Signed-off-by: jaeyeong lee <lee@jaeyeong.cc> Co-authored-by: jianning-liu <jianning.liu@tuya.com> Co-authored-by: Claude Code <noreply@anthropic.com> Co-authored-by: YangJie <yangjie6759@163.com> Co-authored-by: KOKO-cyco <354146137@qq.com> Co-authored-by: guanshan.xu <guanshan.xu@tuya.com> Co-authored-by: yingtao450 <144092910+yingtao450@users.noreply.github.com> Co-authored-by: Fin <101492831+Finder16@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
tal_wifi_all_ap_scan() no longer forces WWM_STATION first. Switching the radio tore down the soft AP the device was serving for provisioning; platforms that need it (ESP32) now switch to APSTA inside the TKL scan.
Stacked on #744.