Silabs: fix endless-join wedge, keep orphaned end devices rejoining, arm the watchdog (#458) - #477
Open
barbalexs wants to merge 6 commits into
Open
Silabs: fix endless-join wedge, keep orphaned end devices rejoining, arm the watchdog (#458)#477barbalexs wants to merge 6 commits into
barbalexs wants to merge 6 commits into
Conversation
- Map JOINED_NETWORK_NO_PARENT/S2S to JOINED and LEAVING_NETWORK to busy: starting network steering in these states never delivers the completion callback, wedging the device in a fake joining state until power cycle. - Trust the steering-in-progress flag only when steering_start returns OK, add a 240s safety timeout that force-stops a steering round whose callback never arrived. - Clear the flag on NETWORK_UP. - Re-kick end-device-support rejoin with 30s..5min backoff while orphaned: the SDK gives up for good after REJOIN_ATTEMPTS_MAX attempts. - Steering retry backoff 5..60s in app_task instead of a retry every superloop pass: continuous scanning overwhelms parasitic no-neutral supplies. - Send device announce until it actually succeeds. - Bound cluster/attribute registration to the fixed buffers instead of silently overrunning them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SL_LEGACY_HAL_DISABLE_WATCHDOG=1 is the SDK default, so the WDOG was never enabled and a hung device stayed hung until mains power cycle. The zigbee stack/app-framework ticks already call halResetWatchdog; the WDOG is frozen in EM2, so sleepy end devices get no spurious resets. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…f-by-one A zeroed poll-control NVM record passed validation and left a sleepy end device with no wake schedule. Endpoints are numbered 1..10 but the per-endpoint dispatch tables held 10 entries, so endpoint 10 wrote out of bounds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
Author
|
Note on the red The two pre-existing offenders are fixed separately in #478, so this PR should go green once that lands (or once it is rebased on a fixed |
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.
Fixes the "Silabs device blinks forever and only a power cycle helps" failure (#458), plus the reason a hung Silabs device never recovers at all. Diagnosed and hardware-tested on two SONOFF ZBMINIL2 (EFR32MG22, no-neutral sleepy end devices) that kept dying in the field.
Root causes found
hal_zigbee_start_network_steering()setnetwork_steering_in_progress = truebefore callingsl_zigbee_af_network_steering_start()and ignored its return. Several SDK paths return an error and never deliversl_zigbee_af_network_steering_complete_cb— most importantly, whensl_zigbee_af_network_state() != SL_ZIGBEE_NO_NETWORKthe plugin (network-steering-v2 withOPTIMIZE_SCANS) just broadcasts permit_join and returns without entering its state machine. The flag then staystruefor the rest of the boot: status reads "JOINING" forever, no retry ever happens, permit_join from the coordinator does nothing because the device isn't scanning. Only a power cycle clears it.hal_zigbee_get_network_status()mapped onlyJOINED_NETWORKandJOINING_NETWORK;SL_ZIGBEE_JOINED_NETWORK_NO_PARENT(a sleepy end device that lost its parent — the everyday case) andLEAVING_NETWORK(button factory reset) fell intoNOT_JOINED, soapp_taskstarted steering in exactly the states where the callback never comes → trigger for (1).SL_ZIGBEE_AF_REJOIN_ATTEMPTS_MAX = 4attempts, i.e. any outage longer than ~40 s orphans the device permanently.SL_LEGACY_HAL_DISABLE_WATCHDOGdefaults to1in the SDK, so the WDOG was never armed on Silabs (Telink builds have one since v1.1.1). A hung device stayed hung until mains power cycle. The refresh calls already exist in the zigbee stack/app-framework ticks — they were just compiled to no-ops.The Telink HAL already guards all of this (checks the steering result, clears the flag on every failure path, rejoins with backoff); the Silabs port had dropped those protections.
Changes
JOINED_NETWORK_NO_PARENT/S2S states to JOINED (rejoin is the SDK's job) andLEAVING_NETWORKto busy; onlyNO_NETWORKtriggers steering.steering_startreturnsSL_STATUS_OK; add a 240 s safety timeout that callssl_zigbee_af_network_steering_stop()if the completion callback never arrives (also recovers the plugin's own stranded state machine, e.g. the silent early-return inscanResultsHandler).SL_STATUS_NETWORK_UP.sl_zigbee_af_start_move_cb()with 30 s → 5 min exponential backoff, so devices always come back yet stay cheap on parasitic no-neutral supplies.app_tasknow back off 5 s → 60 s instead of re-scanning every superloop pass (closes the existing TODO; continuous scanning overwhelms no-neutral supplies — we believe this is what killed our weakest-supplied unit).SL_LEGACY_HAL_DISABLE_WATCHDOG: 0). The WDOG is frozen in EM2 (em2Run = falsedefault), so sleepy end devices get no spurious resets.hal_zigbee_init, widen the*_by_endpoint[10]dispatch tables to 11 (endpoints are numbered 1..10, so endpoint 10 wrote out of bounds).Testing
On a bench-powered ZBMINIL2 (EndDevice build):
Note: no overlap with #470 — that PR flips the debug-UART energy-mode flag (relevant for DEBUG builds; release builds already swap in
iostream_dummy), this one doesn't touch that file and addresses the join/recovery logic.🤖 Generated with Claude Code