diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig index 916cc1a9ddba3..a4e4e6d307dbe 100644 --- a/drivers/ieee802154/Kconfig +++ b/drivers/ieee802154/Kconfig @@ -92,6 +92,14 @@ config IEEE802154_CSL_DEBUG help Enable support for CSL debugging by avoiding sleep state in favor of receive state. +config IEEE802154_SELECTIVE_TXCHANNEL + bool "Support for selective TX channel setting" + help + Enable support for selectively setting TX channel for every timed transmission request. + The drivers MAY have the capability IEEE802154_HW_SELECTIVE_TXCHANNEL only if + this Kconfig option is enabled. If the Kconfig option is disabled the drivers + MUST NOT have the capability. + module = IEEE802154_DRIVER module-str = IEEE 802.15.4 driver module-help = Sets log level for IEEE 802.15.4 Device Drivers. diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 613c913868bfd..8b9c9368e6df7 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -255,6 +255,9 @@ static void nrf5_get_capabilities_at_boot(void) ((caps & NRF_802154_CAPABILITY_SECURITY) ? IEEE802154_HW_TX_SEC : 0UL) #if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) | IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA +#endif +#if defined(CONFIG_IEEE802154_SELECTIVE_TXCHANNEL) + | IEEE802154_HW_SELECTIVE_TXCHANNEL #endif ; } @@ -540,7 +543,11 @@ static bool nrf5_tx_at(struct nrf5_802154_data *nrf5_radio, struct net_pkt *pkt, .dynamic_data_is_set = net_pkt_ieee802154_mac_hdr_rdy(pkt), }, .cca = cca, +#if defined(CONFIG_IEEE802154_SELECTIVE_TXCHANNEL) + .channel = net_pkt_ieee802154_txchannel(pkt), +#else .channel = nrf_802154_channel_get(), +#endif .tx_power = { .use_metadata_value = true, .power = nrf5_data.txpwr, diff --git a/include/zephyr/net/ieee802154_pkt.h b/include/zephyr/net/ieee802154_pkt.h index 3270f9942483d..b51db139c60b4 100644 --- a/include/zephyr/net/ieee802154_pkt.h +++ b/include/zephyr/net/ieee802154_pkt.h @@ -59,6 +59,16 @@ struct net_pkt_cb_ieee802154 { */ uint8_t rssi; }; + struct { +#if defined(CONFIG_IEEE802154_SELECTIVE_TXCHANNEL) + /* The channel used for timed transmissions. + * + * Please refer to `ieee802154_radio_api::tx` documentation for + * details. + */ + uint8_t txchannel; +#endif /* CONFIG_IEEE802154_SELECTIVE_TXCHANNEL */ + }; }; /* Flags */ @@ -179,6 +189,18 @@ static inline void net_pkt_set_ieee802154_rssi_dbm(struct net_pkt *pkt, int16_t CODE_UNREACHABLE; } +#if defined(CONFIG_IEEE802154_SELECTIVE_TXCHANNEL) +static inline uint8_t net_pkt_ieee802154_txchannel(struct net_pkt *pkt) +{ + return net_pkt_cb_ieee802154(pkt)->txchannel; +} + +static inline void net_pkt_set_ieee802154_txchannel(struct net_pkt *pkt, uint8_t channel) +{ + net_pkt_cb_ieee802154(pkt)->txchannel = channel; +} +#endif /* CONFIG_IEEE802154_SELECTIVE_TXCHANNEL */ + static inline bool net_pkt_ieee802154_ack_fpb(struct net_pkt *pkt) { return net_pkt_cb_ieee802154(pkt)->ack_fpb; diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index 10a1922f6fa87..f9a557beba0db 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -520,13 +520,26 @@ enum ieee802154_hw_caps { /** RxOnWhenIdle handling supported */ IEEE802154_RX_ON_WHEN_IDLE = BIT(12), + /** Support for timed transmissions on selective channel. + * + * This capability informs that transmissions with modes + * @ref IEEE802154_TX_MODE_TXTIME and @ref IEEE802154_TX_MODE_TXTIME_CCA support + * scheduling of timed transmissions on selective tx channel. + * The driver MAY have this capability only if the Kconfig option + * `CONFIG_IEEE802154_SELECTIVE_TXCHANNEL` is set, otherwise the driver MUST + * NOT have this capability. + * + * Please refer to the `ieee802154_radio_api::tx` documentation for details. + */ + IEEE802154_HW_SELECTIVE_TXCHANNEL = BIT(13), + /* Note: Update also IEEE802154_HW_CAPS_BITS_COMMON_COUNT when changing * the ieee802154_hw_caps type. */ }; /** @brief Number of bits used by ieee802154_hw_caps type. */ -#define IEEE802154_HW_CAPS_BITS_COMMON_COUNT (13) +#define IEEE802154_HW_CAPS_BITS_COMMON_COUNT (14) /** @brief This and higher values are specific to the protocol- or driver-specific extensions. */ #define IEEE802154_HW_CAPS_BITS_PRIV_START IEEE802154_HW_CAPS_BITS_COMMON_COUNT @@ -625,6 +638,8 @@ enum ieee802154_tx_mode { * Transmit packet in the future, at the specified time, no CCA. * * @note requires IEEE802154_HW_TXTIME capability. + * + * @note capability IEEE802154_HW_SELECTIVE_TXCHANNEL may apply. */ IEEE802154_TX_MODE_TXTIME, @@ -635,6 +650,8 @@ enum ieee802154_tx_mode { * * @note Required for Thread 1.2 Coordinated Sampled Listening feature * (see Thread specification 1.2.0, ch. 3.2.6.3). + * + * @note capability IEEE802154_HW_SELECTIVE_TXCHANNEL may apply. */ IEEE802154_TX_MODE_TXTIME_CCA, @@ -1657,6 +1674,23 @@ struct ieee802154_radio_api { * considerable idle waiting time. SHALL return `-ENETDOWN` unless the * interface is "UP". * + * @note The transmission occurs on the radio channel set by the call to + * `set_channel()`. However, if the `CONFIG_IEEE802154_SELECTIVE_TXCHANNEL` + * is set and the driver has the capability `IEEE802154_HW_SELECTIVE_TXCHANNEL` + * then the transmissions requested with `mode` IEEE802154_TX_MODE_TXTIME + * or `IEEE802154_TX_MODE_TXTIME_CCA` SHALL use the radio channel + * returned by `net_pkt_ieee802154_txchannel()` to transmit the packet + * and receive an ACK on that channel if the frame requested it. After + * the operation the driver should return to the channel set previously by + * `set_channel()` call. + * It is responsibility of an upper layer to set the required radio channel + * for the packet by a call to `net_pkt_set_ieee802154_txchannel()`. + * This feature allows CSL transmissions as stated in IEEE 802.15.4-2020 + * chapter 6.12.2.7 CSL over multiple channels. This feature allows to perform + * a switch of the radio channel as late as possible before transmission without + * interrupting possible reception that could occur if separate `set_channel()` + * was called. + * * @param dev pointer to IEEE 802.15.4 driver device * @param mode the transmission mode, some of which require specific * offloading capabilities. diff --git a/include/zephyr/net/ieee802154_radio_openthread.h b/include/zephyr/net/ieee802154_radio_openthread.h index e45bbc6b85b4c..3606c7a2b78be 100644 --- a/include/zephyr/net/ieee802154_radio_openthread.h +++ b/include/zephyr/net/ieee802154_radio_openthread.h @@ -64,6 +64,9 @@ enum ieee802154_openthread_tx_mode { * section 11.3, table 11-2). * * Requires IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA capability. + * + * @note Capability @ref IEEE802154_HW_SELECTIVE_TXCHANNEL applies as for + * @ref IEEE802154_TX_MODE_TXTIME_CCA. */ IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA = IEEE802154_TX_MODE_PRIV_START }; diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index 7e2943e734f80..4f9a52de20d2f 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -379,12 +379,20 @@ void platformRadioInit(void) radio_api->configure(radio_dev, IEEE802154_CONFIG_EVENT_HANDLER, &cfg); } +static void radio_set_channel(uint16_t ch) +{ + channel = ch; + radio_api->set_channel(radio_dev, ch); +} + void transmit_message(struct k_work *tx_job) { int tx_err; ARG_UNUSED(tx_job); + enum ieee802154_hw_caps radio_caps = radio_api->get_capabilities(radio_dev); + /* * The payload is already in tx_payload->data, * but we need to set the length field @@ -394,10 +402,7 @@ void transmit_message(struct k_work *tx_job) */ tx_payload->len = sTransmitFrame.mLength - FCS_SIZE; - channel = sTransmitFrame.mChannel; - - radio_api->set_channel(radio_dev, channel); - radio_api->set_txpower(radio_dev, get_transmit_power_for_channel(channel)); + radio_api->set_txpower(radio_dev, get_transmit_power_for_channel(sTransmitFrame.mChannel)); #if defined(CONFIG_OPENTHREAD_TIME_SYNC) if (sTransmitFrame.mInfo.mTxInfo.mIeInfo->mTimeIeOffset != 0) { @@ -415,17 +420,27 @@ void transmit_message(struct k_work *tx_job) sTransmitFrame.mInfo.mTxInfo.mIsSecurityProcessed); net_pkt_set_ieee802154_mac_hdr_rdy(tx_pkt, sTransmitFrame.mInfo.mTxInfo.mIsHeaderUpdated); - if ((radio_api->get_capabilities(radio_dev) & IEEE802154_HW_TXTIME) && + if ((radio_caps & IEEE802154_HW_TXTIME) && (sTransmitFrame.mInfo.mTxInfo.mTxDelay != 0)) { #if defined(CONFIG_NET_PKT_TXTIME) uint32_t tx_at = sTransmitFrame.mInfo.mTxInfo.mTxDelayBaseTime + sTransmitFrame.mInfo.mTxInfo.mTxDelay; net_pkt_set_timestamp_ns(tx_pkt, convert_32bit_us_wrapped_to_64bit_ns(tx_at)); +#endif +#if defined(CONFIG_IEEE802154_SELECTIVE_TXCHANNEL) + if (radio_caps & IEEE802154_HW_SELECTIVE_TXCHANNEL) { + net_pkt_set_ieee802154_txchannel(tx_pkt, sTransmitFrame.mChannel); + } else { + radio_set_channel(sTransmitFrame.mChannel); + } +#else + radio_set_channel(sTransmitFrame.mChannel); #endif tx_err = radio_api->tx(radio_dev, IEEE802154_TX_MODE_TXTIME_CCA, tx_pkt, tx_payload); } else if (sTransmitFrame.mInfo.mTxInfo.mCsmaCaEnabled) { - if (radio_api->get_capabilities(radio_dev) & IEEE802154_HW_CSMA) { + radio_set_channel(sTransmitFrame.mChannel); + if (radio_caps & IEEE802154_HW_CSMA) { tx_err = radio_api->tx(radio_dev, IEEE802154_TX_MODE_CSMA_CA, tx_pkt, tx_payload); } else { @@ -436,6 +451,7 @@ void transmit_message(struct k_work *tx_job) } } } else { + radio_set_channel(sTransmitFrame.mChannel); tx_err = radio_api->tx(radio_dev, IEEE802154_TX_MODE_DIRECT, tx_pkt, tx_payload); }