US915 OTAA Join bad sate 原因记录

原因

该问题不是普通射频、网关或 Join 参数问题,也不能简单归类为 “协议栈自带 bug”。更准确地说:

这是 SWL2001 协议栈 US915 / AU915 区域实现中的状态机约束被触发。
真正触发原因是应用层 / 适配层在 OTAA Join 前使用
smtc_real_set_channel_mask() 重放信道掩码的时机不合适。

也就是说,bad sate 的报错位置确实在协议栈内部,属于协议栈 US915 / AU915 区域状态保护逻辑主动触发的 panic;但触发条件并不是 协议栈无条件自身异常,而是 Join 前外部调用时机改变了协议栈期望的 区域状态。因此对外说明时,建议描述为:

这是协议栈内部 US915 / AU915 channel mask 状态保护被触发,
触发原因是入网前恢复 / 设置 channel mask 的时机不符合该协议栈
区域状态机要求。

bad sate panic 来自协议栈内部的 US915 / AU915 after-join snapshot channel mask 保护逻辑。协议栈要求 Join Accept 处理前, first_ch_mask_received 必须保持在入网前允许的状态。

US915 / AU915 的 smtc_real_set_channel_mask() 不是单纯复制掩码。 该接口内部会推进区域私有的 first_ch_mask_received 状态机。 如果在 OTAA Join 之前,由应用层恢复 AT+QCHAN 缓存,或由 Join 选频流程提前调用该接口,就会导致 first_ch_mask_received 在 Join Accept 到来前被提前推进。

当 Join Accept 没有有效 ChMask CFList 时,协议栈会进入本地 after_join_snapshot_channel_mask 推导流程。此时如果 first_ch_mask_received 已经不处于入网前允许的状态,协议栈会触发:

!!! LBM PANIC: region_us_915_init_after_join_snapshot_channel_mask:531 bad sate !!!

因此,本问题的根因是:

入网前信道掩码重放方式错误,提前推进了 US915 / AU915 的
first_ch_mask_received 状态机,从而触发协议栈内部状态保护。

触发条件

该问题通常需要同时满足以下条件:

1. 频段为 US915 或 AU915;
2. 入网前配置或恢复了固定信道掩码,例如 AT+QCHAN;
3. Join 前调用或间接调用了 smtc_real_set_channel_mask();
4. Join Accept 未携带有效 ChMask CFList;
5. 协议栈进入 after-join snapshot channel mask 推导流程。

注意事项

  • bad sate panic 本身来自 SWL2001 协议栈内部保护逻辑。

  • 该保护逻辑被触发,不代表射频链路、网关或 Join 参数一定异常。

  • smtc_real_set_channel_mask() 对 US915 / AU915 有状态副作用, 不适合在 OTAA Join 前用于恢复用户信道掩码。

  • 入网前如需恢复信道掩码,应只同步 Join 选频需要的数据,避免推进 first_ch_mask_received 状态机。

  • LoRaWAN 1.0.4 场景中 Join Accept 通常可能携带 ChMask CFList, 因此不一定触发该问题;但这不代表入网前调用 smtc_real_set_channel_mask() 是安全的。