Skip to content

Conversation

@lexfrei
Copy link

@lexfrei lexfrei commented Dec 24, 2025

Summary

  • Add set_link_mode() method to OpenThread struct for configuring Thread link mode
  • Exposes otThreadSetLinkMode FFI function through safe Rust API
  • Allows control of rx_on_when_idle, device_type, and network_data flags

Motivation

Matter-over-Thread devices need to receive unsolicited UDP messages (e.g., CASE session establishment) after joining a Thread network. By default, MTD devices have rx_on_when_idle=false, which causes them to miss incoming packets when idle.

This method enables applications to set rx_on_when_idle=true so the device keeps its radio receiver active and can respond to CASE requests from Matter controllers.

Test plan

  • Code compiles (verified with vendor fork in smart-garland project)
  • Method successfully enables rx_on_when_idle mode on ESP32-C6

Add set_link_mode() method to OpenThread struct that allows configuring
the Thread link mode parameters:
- rx_on_when_idle: Keep receiver on when idle (needed for unsolicited messages)
- device_type: Full Thread Device (FTD) vs Minimal Thread Device (MTD)
- network_data: Request full Network Data

This is essential for Matter-over-Thread devices that need to receive
CASE session establishment messages after commissioning.

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
@lexfrei lexfrei marked this pull request as ready for review December 24, 2025 21:19
lexfrei added a commit to lexfrei/rs-matter-embassy that referenced this pull request Dec 24, 2025
Point to lexfrei/openthread#feat/add-set-link-mode which adds
the set_link_mode() method required for rx_on_when_idle support.

Upstream PR: esp-rs/openthread#50

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei added a commit to lexfrei/smart-garland that referenced this pull request Dec 24, 2025
Replace local vendor paths with GitHub fork branches:
- rs-matter-embassy: lexfrei/rs-matter-embassy#feat/enable-rx-on-when-idle
- openthread: lexfrei/openthread#feat/add-set-link-mode

PRs pending upstream:
- esp-rs/openthread#50
- sysgrok/rs-matter-embassy#30

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
lexfrei and others added 2 commits December 26, 2025 03:44
OpenThread calls this callback when the MLE link mode changes.
Previously this callback was not implemented, so radio_conf.rx_when_idle
was never updated, causing the radio to stay in sleep mode even when
rx_on_when_idle was requested.

This is required for Matter-over-Thread commissioning where the device
needs to receive unsolicited CASE session requests from the commissioner.

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
Add OT_RADIO_CAPS_RX_ON_WHEN_IDLE (256) and OT_RADIO_CAPS_CSMA_BACKOFF to
plat_radio_caps() return value. OpenThread requires these capabilities
to be advertised before it will call otPlatRadioSetRxOnWhenIdle callback.

Define OT_RADIO_CAPS_RX_ON_WHEN_IDLE locally since it's missing from
riscv32imac bindgen target.

Without this, set_link_mode(rx_on_when_idle=true) has no effect because
OpenThread never calls the platform callback to update radio config.

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
@lexfrei lexfrei force-pushed the feat/add-set-link-mode branch from f24c801 to 8e42bae Compare December 26, 2025 00:52
The riscv32imac bindings incorrectly defined otRadioCaps as u8, but
OT_RADIO_CAPS_RX_ON_WHEN_IDLE = 256 which doesn't fit in u8.

This caused the capability to be silently truncated to 0, preventing
OpenThread from calling otPlatRadioSetRxOnWhenIdle callback.

Changes:
- Change otRadioCaps from u8 to u16 in riscv32imac bindings
- Add missing OT_RADIO_CAPS_RX_ON_WHEN_IDLE constant (256)
- Use proper import in lib.rs instead of local const
- Fix otPlatRadioGetCaps return type to use otRadioCaps

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
@lexfrei lexfrei force-pushed the feat/add-set-link-mode branch from 5d10928 to acec2a2 Compare December 26, 2025 01:01
lexfrei and others added 3 commits December 26, 2025 04:07
The function declaration was missing from riscv32imac bindings while
present in riscv32imc. Without this, the linker cannot find the symbol
and OpenThread cannot call the callback.

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
OpenThread doesn't call otPlatRadioSetRxOnWhenIdle callback, so the
radio config was never updated when link mode changed. This caused
the ESP radio driver to keep rx_when_idle: false even when the device
should stay awake to receive unsolicited messages.

Now set_link_mode directly updates radio_conf.rx_when_idle to match
the requested link mode, ensuring the ESP radio driver configuration
stays in sync.

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
set_link_mode() is called BEFORE Thread attach in thread.rs. The
previous change to update radio_conf.rx_when_idle directly caused
attach to fail because the ESP radio driver behaves differently
with rx_when_idle=true during the attach process.

Now we check device_role.is_connected() before updating radio_conf,
ensuring rx_when_idle stays false during attach and only gets
enabled after successful connection.

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
@lexfrei lexfrei marked this pull request as draft December 26, 2025 10:03
Previously the SRP callback ignored the error parameter, making it
impossible to diagnose why SRP registration was failing. Now errors
are logged with the error code and host state for debugging.

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
@ivmarkov
Copy link
Collaborator

ivmarkov commented Jan 6, 2026

@lexfrei Can you fix the fmt error? The CI fails because of it.

///
/// The value is a bit-field indicating the capabilities supported by the radio. See `OT_RADIO_CAPS_*` definitions.
pub type otRadioCaps = u8;
pub type otRadioCaps = u16;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is autogenerated, so I wonder from where these changes came, given that I don't see anything related to the OpenThread build configuration that had changed.

Did you change it manually?

pub fn set_link_mode(
&self,
rx_on_when_idle: bool,
device_type: bool,
Copy link
Collaborator

@ivmarkov ivmarkov Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this an enum? device_type = true meaning this is a FTD is confusing. Or - at the very least, perhaps this should be named full_thread_device?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also: what would happen if OpenThread is not compiled with FTD support (which is currently the case) and I pass true?

&self,
rx_on_when_idle: bool,
device_type: bool,
network_data: bool,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here: perhaps receive_full_network_data


fn plat_radio_caps(&mut self) -> otRadioCaps {
let caps = OT_RADIO_CAPS_ACK_TIMEOUT as _;
let caps = (OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF) as _;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't OT_RADIO_CAPS_CSMA_BACKOFF (and all others, for that matter, including OT_RADIO_RX_ON_WHEN_IDLE) be obtained from the Radio driver actually?

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.

2 participants