Skip to content

src/cyw43_ctrl: Add roaming and interference-mitigation config via ioctl helpers#151

Open
mitchellcairns wants to merge 1 commit into
georgerobotics:mainfrom
HandHeldLegend:api_expansion
Open

src/cyw43_ctrl: Add roaming and interference-mitigation config via ioctl helpers#151
mitchellcairns wants to merge 1 commit into
georgerobotics:mainfrom
HandHeldLegend:api_expansion

Conversation

@mitchellcairns

Copy link
Copy Markdown

Follow-up to the discussion on #146. This reworks the WiFi roaming (and
interference-mitigation) configuration to be implemented entirely in terms of
cyw43_ioctl(), per @dpgeorge's feedback, instead of adding dedicated
low-level cyw43_ll_* functions for each setting.

The goal is to expose the handful of roaming/interference ioctls that are
critical for tuning link stability, while keeping the embedded footprint
minimal: only two small generic helpers cost binary space; everything
feature-specific is static inline (or a tiny iovar wrapper) and is only
instantiated when actually used.

Background / motivation

Roaming is enabled by default with no way to configure it. When a STA's RSSI
drops below the (hidden) roam trigger, the firmware starts background roam
scans, which causes dropped packets and severe throughput degradation on a
point-to-point link. See:

Disabling roaming (or tuning the trigger/delta/scan-period) fully resolves
these issues, but until now there was no API and no visibility
that this was even the cause.

Implemented

New generic helpers (the only functions that add code size):

  • cyw43_ioctl_set_u32(self, cmd, val, iface)

  • cyw43_ioctl_get_u32(self, cmd, *out_val, iface)

    Thin wrappers around cyw43_ioctl() for the common case of a 4-byte ioctl
    value. Argument order matches cyw43_ioctl() (iface last).

New CYW43_IOCTL_xxx constants (encoded as (WLC_cmd << 1) | is_set, matching
the existing CYW43_IOCTL_* defines):

  • GET/SET_ROAM_TRIGGER, GET/SET_ROAM_DELTA, GET/SET_ROAM_SCAN_PERIOD
  • GET/SET_INTERFERENCE_MODE

…ctl helpers

Expose the roaming and interference-mitigation ioctls needed to tune
link stability, implemented entirely in terms of cyw43_ioctl() rather
than adding dedicated low-level (cyw43_ll_*) functions for each setting,
per maintainer feedback on PR georgerobotics#146. Only the two generic u32 helpers
cost binary space; the feature-specific wrappers are static inline and
the named-iovar helpers are the only additional functions.

Roaming is enabled by default with no way to configure it. When a STA's
RSSI drops below the (hidden) roam trigger the firmware starts background
roam scans, which causes dropped packets and severe throughput
degradation on a point-to-point link (see georgerobotics#111
and raspberrypi/pico-sdk#2835).

Add public helpers:

  - cyw43_ioctl_set_u32(self, cmd, val, iface)
  - cyw43_ioctl_get_u32(self, cmd, *out_val, iface)
    Wrap cyw43_ioctl() for the common case of a 4-byte ioctl value.
    Argument order matches cyw43_ioctl() (iface last).

Add CYW43_IOCTL_xxx constants, encoded as (WLC_cmd << 1) | is_set to
match the existing CYW43_IOCTL_ defines:

  - GET/SET_ROAM_TRIGGER, GET/SET_ROAM_DELTA, GET/SET_ROAM_SCAN_PERIOD
  - GET/SET_INTERFERENCE_MODE

Add the configuration API:

  - cyw43_wifi_set_roam_params() / cyw43_wifi_get_roam_params()
    static inline, built on the u32 ioctl helpers.
  - cyw43_wifi_set_interference_mode() / cyw43_wifi_get_interference_mode()
    static inline, built on the u32 ioctl helpers, with CYW43_IFMODE_*
    mode constants.
  - cyw43_wifi_set_roam_enabled() / cyw43_wifi_get_roam_enabled()
    toggle/read the "roam_off" iovar via WLC_SET_VAR / WLC_GET_VAR.

The default roaming behaviour is left unchanged.
@peterharperuk

Copy link
Copy Markdown
Collaborator

Have you done much testing with this? I'm wondering what values for the roaming and interference mode you've found make a difference?

@mitchellcairns

Copy link
Copy Markdown
Author

Have you done much testing with this? I'm wondering what values for the roaming and interference mode you've found make a difference?

In my configurations I've disabled both roaming/interference as the roaming mode only serves to cause data rate issues. The default value is rather aggressive.

In my other testing, using some debug logging to track the signal level in dBm, the roaming value set aligns with what is set using the helpers.

Note that this change does not alter the default configuration set, it only exposes these helpers so that developers can utilize them with built in, documented options.

@mihneaco

mihneaco commented Jul 8, 2026

Copy link
Copy Markdown

Had this exact issue on a RC car + controller pair — 2 Pico2W (RP2350),
one AP + one STA, talking via UDP. ~10 s after radio-up, usable range
collapsed from >6m to <1m. The link still worked relatively fine at close range with random latency spikes, and a
full deinit/init of the wifi stack reset it for another ~10 s. Spent one week pulling
my hair suspecting EMI from the motors or other hardware related issues before finding this.

Can confirm cyw43_wifi_set_interference_mode(&cyw43_state, CYW43_IFMODE_NONE)
from the commit attached to this PR completely fixes the range collapse. Checked with both cyw43_wifi_set_roam_enabled(false) and cyw43_wifi_set_interference_mode(CYW43_IFMODE_NONE) and cyw43_wifi_set_interference_mode alone was enough for my range issue but cyw43_wifi_set_roam_enabled(false) probably helps in the long run - will have to test.

For anyone using pico-sdk: cyw43_wifi_set_interference_mode and cyw43_wifi_set_roam_enabled took effect only after cyw43_arch_enable_ap_mode() / cyw43_arch_enable_sta_mode(). Calling them immediately after
cyw43_arch_init() didn't seem to apply them, most likely values get overwritten during AP/STA bringup.

mihneaco added a commit to mihneaco/picorccar that referenced this pull request Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants