nRF52840 / OpenThread: how to inject custom IEEE 802.15.4 RX frames into the native receive path?

Title: nRF52840 / OpenThread: how to inject custom IEEE 802.15.4 RX frames into the native receive path?

Hi,

I am working on a test setup around nRF52840, OpenThread, and Matter/Thread, and I would like to inject custom IEEE 802.15.4 frames into the normal receive path for testing purposes.

The goal is not just to parse frames externally, but to make the OpenThread stack receive them as if they had been received by the radio driver, preserving the normal buffer ownership, callbacks, metadata, and state machine behavior.

I am trying to understand the intended boundary for this kind of test injection.

Questions:

  1. What is the recommended API/layer for injecting a custom raw IEEE 802.15.4 frame into the nRF 802.15.4/OpenThread receive path?

  2. Is nrf_802154_received_raw() intended to be called by application/test code, or is it strictly an internal driver callback?

  3. If using the nRF 802.15.4 driver, who owns the RX buffer passed to the receive callback, and what is the expected release/free path?

  4. What metadata is required for a valid received frame? For example: RSSI, LQI, timestamp, channel, ACK/security state, or other driver-side fields.

  5. Is there an existing Nordic-supported way to simulate radio RX frames for OpenThread/Matter testing without modifying the OpenThread stack itself?

  6. If direct RX injection is not supported, what is the closest recommended approach for HIL testing or custom packet injection?

I am mainly looking for the correct architectural layer and ownership rules, not a shortcut that bypasses OpenThread behavior.

Target context:

  • nRF52840

  • IEEE 802.15.4 / Thread

  • OpenThread

  • Matter over Thread

  • Zephyr / nRF Connect SDK style environment

Thanks.

Parents
  • Hi,

    There is no Nordic-supported public API to inject synthetic RX frames directly into the nRF 802.15.4 driver receive path on target while keeping it fully "driver-authentic". The intended boundary is callback-based delivery from driver to higher layer, not reverse injection.

    1. We do not have a recommended way of doing this, since it is not supported. However, it could be possible to use the OpenThread radio platform layer for synthetic tests (test backend that feeds otPlatRadioReceiveDone), or use real OTA injection for HIL. In NCS, the normal hardware path is nrf_802154_received_timestamp_raw callback -> radio_nrf5.c -> otPlatRadioReceiveDone.

    2. It is a driver callout callback, not a public "inject frame" API. In driver source, internal nrf_802154_co_received_raw() calls it as part of notification flow.

    3. The RX buffer is driver-owned pool memory (rx_buffer_t pool in nrf_802154_rx_buffer.c) handed to higher layer temporarily. Higher layer must call nrf_802154_buffer_free_raw() when done. In OpenThread backend (radio_nrf5.c), it calls otPlatRadioReceiveDone(...) then frees via nrf_802154_buffer_free_raw(psdu).
    Release path is nrf_802154_buffer_free_raw -> request SWI -> nrf_802154_core_notify_buffer_free.

    4. From nRF driver callback: p_data (PHR + PSDU), power (RSSI), lqi, time (timestamp, may be NRF_802154_NO_TIMESTAMP).
    In radio_nrf5.c, this becomes OpenThread RX metadata: channel, RSSI, LQI, timestamp, mAckedWithFramePending, mAckedWithSecEnhAck (from ACK-start callback state). mAckFrameCounter and mAckKeyId are not populated in this backend path.

    5. No, this is not exposed as a supported API.

    6. We do not have any specific recommended approaches for this. However, you can use a second nRF52840 or RF generator transmitting IEEE 802.15.4 frames over the air, and test the radio backend feeding otPlatRadioReceiveDone.
    Make sure to avoid calling nrf_802154_received_raw() from app/test code directly, it is architecturally the wrong direction and can break ownership/state assumptions.

    Best regards,
    Marte

Reply
  • Hi,

    There is no Nordic-supported public API to inject synthetic RX frames directly into the nRF 802.15.4 driver receive path on target while keeping it fully "driver-authentic". The intended boundary is callback-based delivery from driver to higher layer, not reverse injection.

    1. We do not have a recommended way of doing this, since it is not supported. However, it could be possible to use the OpenThread radio platform layer for synthetic tests (test backend that feeds otPlatRadioReceiveDone), or use real OTA injection for HIL. In NCS, the normal hardware path is nrf_802154_received_timestamp_raw callback -> radio_nrf5.c -> otPlatRadioReceiveDone.

    2. It is a driver callout callback, not a public "inject frame" API. In driver source, internal nrf_802154_co_received_raw() calls it as part of notification flow.

    3. The RX buffer is driver-owned pool memory (rx_buffer_t pool in nrf_802154_rx_buffer.c) handed to higher layer temporarily. Higher layer must call nrf_802154_buffer_free_raw() when done. In OpenThread backend (radio_nrf5.c), it calls otPlatRadioReceiveDone(...) then frees via nrf_802154_buffer_free_raw(psdu).
    Release path is nrf_802154_buffer_free_raw -> request SWI -> nrf_802154_core_notify_buffer_free.

    4. From nRF driver callback: p_data (PHR + PSDU), power (RSSI), lqi, time (timestamp, may be NRF_802154_NO_TIMESTAMP).
    In radio_nrf5.c, this becomes OpenThread RX metadata: channel, RSSI, LQI, timestamp, mAckedWithFramePending, mAckedWithSecEnhAck (from ACK-start callback state). mAckFrameCounter and mAckKeyId are not populated in this backend path.

    5. No, this is not exposed as a supported API.

    6. We do not have any specific recommended approaches for this. However, you can use a second nRF52840 or RF generator transmitting IEEE 802.15.4 frames over the air, and test the radio backend feeding otPlatRadioReceiveDone.
    Make sure to avoid calling nrf_802154_received_raw() from app/test code directly, it is architecturally the wrong direction and can break ownership/state assumptions.

    Best regards,
    Marte

Children
No Data
Related