From 1fb418df4cb61c19beab0f7a47f325373faf70ce Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 28 Feb 2020 13:57:49 +0100 Subject: [PATCH] net: ieee802154_radio: Allow to specify TX mode Even though radio driver can report in its capabilities that it does support CSMA CA, there's no way in the driver to select how the frame should be transmitted (with CSMA or without). As layers above radio driver (Thread, Zigbee) can expect that both TX modes are available, we need to extend the API to allow either of these modes. This commits extends the API `tx` function with an extra parameter, `ieee802154_tx_mode`, which informs the driver how the packet should be transmitted. Currently, the following modes are specified: * direct (regular tx, no cca, just how it worked so far), * CCA before transmission, * CSMA CA before transmission, * delayed TX, * delayed TX with CCA Assume that radios that reported CSMA CA capability transmit in CSMA CA mode by default, all others will support direct mode. Signed-off-by: Robert Lubos --- drivers/ieee802154/ieee802154_cc1200.c | 6 +++++ drivers/ieee802154/ieee802154_cc13xx_cc26xx.c | 9 ++++++- drivers/ieee802154/ieee802154_cc2520.c | 6 +++++ drivers/ieee802154/ieee802154_kw41z.c | 9 +++++-- drivers/ieee802154/ieee802154_mcr20a.c | 6 +++++ drivers/ieee802154/ieee802154_nrf5.c | 6 +++++ drivers/ieee802154/ieee802154_rf2xx.c | 6 +++++ drivers/ieee802154/ieee802154_uart_pipe.c | 6 +++++ include/net/ieee802154_radio.h | 26 ++++++++++++++++--- samples/net/wpan_serial/src/main.c | 3 ++- samples/net/wpanusb/src/wpanusb.c | 3 ++- subsys/net/l2/ieee802154/ieee802154.c | 6 +++-- .../l2/ieee802154/ieee802154_radio_aloha.c | 3 ++- .../l2/ieee802154/ieee802154_radio_csma_ca.c | 3 ++- subsys/net/l2/ieee802154/ieee802154_utils.h | 6 +++-- subsys/net/lib/openthread/platform/radio.c | 6 +++-- .../l2/src/ieee802154_fake_driver.c | 1 + 17 files changed, 94 insertions(+), 17 deletions(-) diff --git a/drivers/ieee802154/ieee802154_cc1200.c b/drivers/ieee802154/ieee802154_cc1200.c index 158fe91e683..195a44017d3 100644 --- a/drivers/ieee802154/ieee802154_cc1200.c +++ b/drivers/ieee802154/ieee802154_cc1200.c @@ -592,6 +592,7 @@ static int cc1200_set_txpower(struct device *dev, s16_t dbm) } static int cc1200_tx(struct device *dev, + enum ieee802154_tx_mode mode, struct net_pkt *pkt, struct net_buf *frag) { @@ -600,6 +601,11 @@ static int cc1200_tx(struct device *dev, u8_t len = frag->len; bool status = false; + if (mode != IEEE802154_TX_MODE_DIRECT) { + NET_ERR("TX mode %d not supported", mode); + return -ENOTSUP; + } + LOG_DBG("%p (%u)", frag, len); /* ToDo: diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c index 4cff57b2090..e346d72e19f 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c @@ -188,7 +188,9 @@ static int ieee802154_cc13xx_cc26xx_set_txpower(struct device *dev, s16_t dbm) } /* See IEEE 802.15.4 section 6.2.5.1 and TRM section 25.5.4.3 */ -static int ieee802154_cc13xx_cc26xx_tx(struct device *dev, struct net_pkt *pkt, +static int ieee802154_cc13xx_cc26xx_tx(struct device *dev, + enum ieee802154_tx_mode mode, + struct net_pkt *pkt, struct net_buf *frag) { struct ieee802154_cc13xx_cc26xx_data *drv_data = get_dev_data(dev); @@ -196,6 +198,11 @@ static int ieee802154_cc13xx_cc26xx_tx(struct device *dev, struct net_pkt *pkt, int retry = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES; u32_t status; + if (mode != IEEE802154_TX_MODE_CSMA_CA) { + NET_ERR("TX mode %d not supported", mode); + return -ENOTSUP; + } + drv_data->cmd_ieee_csma.status = IDLE; drv_data->cmd_ieee_csma.randomState = sys_rand32_get(); diff --git a/drivers/ieee802154/ieee802154_cc2520.c b/drivers/ieee802154/ieee802154_cc2520.c index d44fa4e8ead..bd4eef0c093 100644 --- a/drivers/ieee802154/ieee802154_cc2520.c +++ b/drivers/ieee802154/ieee802154_cc2520.c @@ -793,6 +793,7 @@ error: } static int cc2520_tx(struct device *dev, + enum ieee802154_tx_mode mode, struct net_pkt *pkt, struct net_buf *frag) { @@ -802,6 +803,11 @@ static int cc2520_tx(struct device *dev, u8_t retry = 2U; bool status; + if (mode != IEEE802154_TX_MODE_DIRECT) { + NET_ERR("TX mode %d not supported", mode); + return -ENOTSUP; + } + LOG_DBG("%p (%u)", frag, len); if (!write_reg_excflag0(cc2520, EXCFLAG0_RESET_TX_FLAGS) || diff --git a/drivers/ieee802154/ieee802154_kw41z.c b/drivers/ieee802154/ieee802154_kw41z.c index 3bcc332a183..6e39fe337cc 100644 --- a/drivers/ieee802154/ieee802154_kw41z.c +++ b/drivers/ieee802154/ieee802154_kw41z.c @@ -612,8 +612,8 @@ out: net_pkt_unref(ack_pkt); } -static int kw41z_tx(struct device *dev, struct net_pkt *pkt, - struct net_buf *frag) +static int kw41z_tx(struct device *dev, enum ieee802154_tx_mode mode, + struct net_pkt *pkt, struct net_buf *frag) { struct kw41z_context *kw41z = dev->driver_data; u8_t payload_len = frag->len; @@ -621,6 +621,11 @@ static int kw41z_tx(struct device *dev, struct net_pkt *pkt, u8_t xcvseq; int key; + if (mode != IEEE802154_TX_MODE_DIRECT) { + NET_ERR("TX mode %d not supported", mode); + return -ENOTSUP; + } + /* * The transmit requests are preceded by the CCA request. On * completion of the CCA the sequencer should be in the IDLE diff --git a/drivers/ieee802154/ieee802154_mcr20a.c b/drivers/ieee802154/ieee802154_mcr20a.c index a56a9de3916..d7e931375b7 100644 --- a/drivers/ieee802154/ieee802154_mcr20a.c +++ b/drivers/ieee802154/ieee802154_mcr20a.c @@ -1082,6 +1082,7 @@ static inline bool write_txfifo_content(struct mcr20a_context *dev, } static int mcr20a_tx(struct device *dev, + enum ieee802154_tx_mode mode, struct net_pkt *pkt, struct net_buf *frag) { @@ -1090,6 +1091,11 @@ static int mcr20a_tx(struct device *dev, MCR20A_XCVSEQ_TX; int retval; + if (mode != IEEE802154_TX_MODE_DIRECT) { + NET_ERR("TX mode %d not supported", mode); + return -ENOTSUP; + } + k_mutex_lock(&mcr20a->phy_mutex, K_FOREVER); LOG_DBG("%p (%u)", frag, frag->len); diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 313dfe8815d..8e3c11f5903 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -322,6 +322,7 @@ free_nrf_ack: } static int nrf5_tx(struct device *dev, + enum ieee802154_tx_mode mode, struct net_pkt *pkt, struct net_buf *frag) { @@ -329,6 +330,11 @@ static int nrf5_tx(struct device *dev, u8_t payload_len = frag->len; u8_t *payload = frag->data; + if (mode != IEEE802154_TX_MODE_DIRECT) { + NET_ERR("TX mode %d not supported", mode); + return -ENOTSUP; + } + LOG_DBG("%p (%u)", payload, payload_len); nrf5_radio->tx_psdu[0] = payload_len + NRF5_FCS_LENGTH; diff --git a/drivers/ieee802154/ieee802154_rf2xx.c b/drivers/ieee802154/ieee802154_rf2xx.c index 9926aecc89f..eeafb6a464b 100644 --- a/drivers/ieee802154/ieee802154_rf2xx.c +++ b/drivers/ieee802154/ieee802154_rf2xx.c @@ -473,6 +473,7 @@ static void rf2xx_handle_ack(struct rf2xx_context *ctx, struct net_buf *frag) #endif static int rf2xx_tx(struct device *dev, + enum ieee802154_tx_mode mode, struct net_pkt *pkt, struct net_buf *frag) { @@ -481,6 +482,11 @@ static int rf2xx_tx(struct device *dev, struct rf2xx_context *ctx = dev->driver_data; int response = 0; + if (mode != IEEE802154_TX_MODE_CSMA_CA) { + NET_ERR("TX mode %d not supported", mode); + return -ENOTSUP; + } + rf2xx_trx_set_tx_state(dev); rf2xx_iface_reg_read(dev, RF2XX_IRQ_STATUS_REG); diff --git a/drivers/ieee802154/ieee802154_uart_pipe.c b/drivers/ieee802154/ieee802154_uart_pipe.c index e695fa275cd..14da9e13db8 100644 --- a/drivers/ieee802154/ieee802154_uart_pipe.c +++ b/drivers/ieee802154/ieee802154_uart_pipe.c @@ -266,6 +266,7 @@ static int upipe_set_txpower(struct device *dev, s16_t dbm) } static int upipe_tx(struct device *dev, + enum ieee802154_tx_mode mode, struct net_pkt *pkt, struct net_buf *frag) { @@ -274,6 +275,11 @@ static int upipe_tx(struct device *dev, u8_t len = frag->len; u8_t i, data; + if (mode != IEEE802154_TX_MODE_DIRECT) { + NET_ERR("TX mode %d not supported", mode); + return -ENOTSUP; + } + LOG_DBG("%p (%u)", frag, len); if (upipe->stopped) { diff --git a/include/net/ieee802154_radio.h b/include/net/ieee802154_radio.h index f01a178390c..1219a14c58a 100644 --- a/include/net/ieee802154_radio.h +++ b/include/net/ieee802154_radio.h @@ -36,7 +36,8 @@ enum ieee802154_hw_caps { IEEE802154_HW_2_4_GHZ = BIT(4), /* 2.4Ghz radio supported */ IEEE802154_HW_TX_RX_ACK = BIT(5), /* Handles ACK request on TX */ IEEE802154_HW_SUB_GHZ = BIT(6), /* Sub-GHz radio supported */ - IEEE802154_HW_ENERGY_SCAN = BIT(7) /* Energy scan supported */ + IEEE802154_HW_ENERGY_SCAN = BIT(7), /* Energy scan supported */ + IEEE802154_HW_TXTIME = BIT(8), /* TX at specified time supported */ }; enum ieee802154_filter_type { @@ -57,6 +58,24 @@ struct ieee802154_filter { /* @endcond */ }; +/** IEEE802.15.4 Transmission mode. */ +enum ieee802154_tx_mode { + /** Transmit packet immediately, no CCA. */ + IEEE802154_TX_MODE_DIRECT, + + /** Perform CCA before packet transmission. */ + IEEE802154_TX_MODE_CCA, + + /** Perform full CSMA CA procedure before packet transmission. */ + IEEE802154_TX_MODE_CSMA_CA, + + /** Transmit packet in the future, at specified time, no CCA. */ + IEEE802154_TX_MODE_TXTIME, + + /** Transmit packet in the future, perform CCA before transmission. */ + IEEE802154_TX_MODE_TXTIME_CCA, +}; + /** IEEE802.15.4 driver configuration types. */ enum ieee802154_config_type { /** Indicates how radio driver should set Frame Pending bit in ACK @@ -137,9 +156,8 @@ struct ieee802154_radio_api { int (*set_txpower)(struct device *dev, s16_t dbm); /** Transmit a packet fragment */ - int (*tx)(struct device *dev, - struct net_pkt *pkt, - struct net_buf *frag); + int (*tx)(struct device *dev, enum ieee802154_tx_mode mode, + struct net_pkt *pkt, struct net_buf *frag); /** Start the device */ int (*start)(struct device *dev); diff --git a/samples/net/wpan_serial/src/main.c b/samples/net/wpan_serial/src/main.c index 0183f8203f1..d21f43e552b 100644 --- a/samples/net/wpan_serial/src/main.c +++ b/samples/net/wpan_serial/src/main.c @@ -248,7 +248,8 @@ static void process_data(struct net_pkt *pkt) } /* Transmit data through radio */ - ret = radio_api->tx(ieee802154_dev, pkt, buf); + ret = radio_api->tx(ieee802154_dev, IEEE802154_TX_MODE_DIRECT, + pkt, buf); if (ret) { LOG_ERR("Error transmit data"); } diff --git a/samples/net/wpanusb/src/wpanusb.c b/samples/net/wpanusb/src/wpanusb.c index de8688f172f..342c3d674b1 100644 --- a/samples/net/wpanusb/src/wpanusb.c +++ b/samples/net/wpanusb/src/wpanusb.c @@ -260,7 +260,8 @@ static int tx(struct net_pkt *pkt) LOG_DBG("len %d seq %u", buf->len, seq); do { - ret = radio_api->tx(ieee802154_dev, pkt, buf); + ret = radio_api->tx(ieee802154_dev, IEEE802154_TX_MODE_DIRECT, + pkt, buf); } while (ret && retries--); if (ret) { diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index f20bdaf11d3..c6c6f7cb2c5 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -81,7 +81,8 @@ static inline void ieee802154_acknowledge(struct net_if *iface, } if (ieee802154_create_ack_frame(iface, pkt, mpdu->mhr.fs->sequence)) { - ieee802154_tx(iface, pkt, pkt->buffer); + ieee802154_tx(iface, IEEE802154_TX_MODE_DIRECT, + pkt, pkt->buffer); } net_pkt_unref(pkt); @@ -276,7 +277,8 @@ static int ieee802154_send(struct net_if *iface, struct net_pkt *pkt) if (IS_ENABLED(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA) && ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_CSMA) { - ret = ieee802154_tx(iface, pkt, &frame_buf); + ret = ieee802154_tx(iface, IEEE802154_TX_MODE_CSMA_CA, + pkt, &frame_buf); } else { ret = ieee802154_radio_send(iface, pkt, &frame_buf); } diff --git a/subsys/net/l2/ieee802154/ieee802154_radio_aloha.c b/subsys/net/l2/ieee802154/ieee802154_radio_aloha.c index 837b9083bd5..c70a3398c1d 100644 --- a/subsys/net/l2/ieee802154/ieee802154_radio_aloha.c +++ b/subsys/net/l2/ieee802154/ieee802154_radio_aloha.c @@ -30,7 +30,8 @@ static inline int aloha_radio_send(struct net_if *iface, while (retries) { retries--; - ret = ieee802154_tx(iface, pkt, frag); + ret = ieee802154_tx(iface, IEEE802154_TX_MODE_DIRECT, + pkt, frag); if (ret) { continue; } diff --git a/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c b/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c index ed653e8e865..6afe3638a0d 100644 --- a/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c +++ b/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c @@ -57,7 +57,8 @@ loop: } } - ret = ieee802154_tx(iface, pkt, frag); + ret = ieee802154_tx(iface, IEEE802154_TX_MODE_DIRECT, + pkt, frag); if (ret) { continue; } diff --git a/subsys/net/l2/ieee802154/ieee802154_utils.h b/subsys/net/l2/ieee802154/ieee802154_utils.h index bfffe9687ad..e950a9f47f7 100644 --- a/subsys/net/l2/ieee802154/ieee802154_utils.h +++ b/subsys/net/l2/ieee802154/ieee802154_utils.h @@ -64,7 +64,9 @@ static inline int ieee802154_set_tx_power(struct net_if *iface, s16_t dbm) } static inline int ieee802154_tx(struct net_if *iface, - struct net_pkt *pkt, struct net_buf *buf) + enum ieee802154_tx_mode mode, + struct net_pkt *pkt, + struct net_buf *buf) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->driver_api; @@ -73,7 +75,7 @@ static inline int ieee802154_tx(struct net_if *iface, return -ENOENT; } - return radio->tx(net_if_get_device(iface), pkt, buf); + return radio->tx(net_if_get_device(iface), mode, pkt, buf); } static inline int ieee802154_start(struct net_if *iface) diff --git a/subsys/net/lib/openthread/platform/radio.c b/subsys/net/lib/openthread/platform/radio.c index 6752dbeed00..14d209fa0f5 100644 --- a/subsys/net/lib/openthread/platform/radio.c +++ b/subsys/net/lib/openthread/platform/radio.c @@ -190,11 +190,13 @@ void platformRadioProcess(otInstance *aInstance) if (sTransmitFrame.mInfo.mTxInfo.mCsmaCaEnabled) { if (radio_api->cca(radio_dev) || - radio_api->tx(radio_dev, tx_pkt, tx_payload)) { + radio_api->tx(radio_dev, IEEE802154_TX_MODE_DIRECT, + tx_pkt, tx_payload)) { result = OT_ERROR_CHANNEL_ACCESS_FAILURE; } } else { - if (radio_api->tx(radio_dev, tx_pkt, tx_payload)) { + if (radio_api->tx(radio_dev, IEEE802154_TX_MODE_DIRECT, + tx_pkt, tx_payload)) { result = OT_ERROR_CHANNEL_ACCESS_FAILURE; } } diff --git a/tests/net/ieee802154/l2/src/ieee802154_fake_driver.c b/tests/net/ieee802154/l2/src/ieee802154_fake_driver.c index 7307bd02f62..6c9dc47d68f 100644 --- a/tests/net/ieee802154/l2/src/ieee802154_fake_driver.c +++ b/tests/net/ieee802154/l2/src/ieee802154_fake_driver.c @@ -60,6 +60,7 @@ static inline void insert_frag(struct net_pkt *pkt, struct net_buf *frag) } static int fake_tx(struct device *dev, + enum ieee802154_tx_mode mode, struct net_pkt *pkt, struct net_buf *frag) {