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 <robert.lubos@nordicsemi.no>
This commit is contained in:
Robert Lubos 2020-02-28 13:57:49 +01:00 committed by Jukka Rissanen
commit 1fb418df4c
17 changed files with 94 additions and 17 deletions

View file

@ -592,6 +592,7 @@ static int cc1200_set_txpower(struct device *dev, s16_t dbm)
} }
static int cc1200_tx(struct device *dev, static int cc1200_tx(struct device *dev,
enum ieee802154_tx_mode mode,
struct net_pkt *pkt, struct net_pkt *pkt,
struct net_buf *frag) struct net_buf *frag)
{ {
@ -600,6 +601,11 @@ static int cc1200_tx(struct device *dev,
u8_t len = frag->len; u8_t len = frag->len;
bool status = false; 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); LOG_DBG("%p (%u)", frag, len);
/* ToDo: /* ToDo:

View file

@ -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 */ /* 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 net_buf *frag)
{ {
struct ieee802154_cc13xx_cc26xx_data *drv_data = get_dev_data(dev); 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; int retry = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES;
u32_t status; 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.status = IDLE;
drv_data->cmd_ieee_csma.randomState = sys_rand32_get(); drv_data->cmd_ieee_csma.randomState = sys_rand32_get();

View file

@ -793,6 +793,7 @@ error:
} }
static int cc2520_tx(struct device *dev, static int cc2520_tx(struct device *dev,
enum ieee802154_tx_mode mode,
struct net_pkt *pkt, struct net_pkt *pkt,
struct net_buf *frag) struct net_buf *frag)
{ {
@ -802,6 +803,11 @@ static int cc2520_tx(struct device *dev,
u8_t retry = 2U; u8_t retry = 2U;
bool status; bool status;
if (mode != IEEE802154_TX_MODE_DIRECT) {
NET_ERR("TX mode %d not supported", mode);
return -ENOTSUP;
}
LOG_DBG("%p (%u)", frag, len); LOG_DBG("%p (%u)", frag, len);
if (!write_reg_excflag0(cc2520, EXCFLAG0_RESET_TX_FLAGS) || if (!write_reg_excflag0(cc2520, EXCFLAG0_RESET_TX_FLAGS) ||

View file

@ -612,8 +612,8 @@ out:
net_pkt_unref(ack_pkt); net_pkt_unref(ack_pkt);
} }
static int kw41z_tx(struct device *dev, struct net_pkt *pkt, static int kw41z_tx(struct device *dev, enum ieee802154_tx_mode mode,
struct net_buf *frag) struct net_pkt *pkt, struct net_buf *frag)
{ {
struct kw41z_context *kw41z = dev->driver_data; struct kw41z_context *kw41z = dev->driver_data;
u8_t payload_len = frag->len; u8_t payload_len = frag->len;
@ -621,6 +621,11 @@ static int kw41z_tx(struct device *dev, struct net_pkt *pkt,
u8_t xcvseq; u8_t xcvseq;
int key; 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 * The transmit requests are preceded by the CCA request. On
* completion of the CCA the sequencer should be in the IDLE * completion of the CCA the sequencer should be in the IDLE

View file

@ -1082,6 +1082,7 @@ static inline bool write_txfifo_content(struct mcr20a_context *dev,
} }
static int mcr20a_tx(struct device *dev, static int mcr20a_tx(struct device *dev,
enum ieee802154_tx_mode mode,
struct net_pkt *pkt, struct net_pkt *pkt,
struct net_buf *frag) struct net_buf *frag)
{ {
@ -1090,6 +1091,11 @@ static int mcr20a_tx(struct device *dev,
MCR20A_XCVSEQ_TX; MCR20A_XCVSEQ_TX;
int retval; 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); k_mutex_lock(&mcr20a->phy_mutex, K_FOREVER);
LOG_DBG("%p (%u)", frag, frag->len); LOG_DBG("%p (%u)", frag, frag->len);

View file

@ -322,6 +322,7 @@ free_nrf_ack:
} }
static int nrf5_tx(struct device *dev, static int nrf5_tx(struct device *dev,
enum ieee802154_tx_mode mode,
struct net_pkt *pkt, struct net_pkt *pkt,
struct net_buf *frag) struct net_buf *frag)
{ {
@ -329,6 +330,11 @@ static int nrf5_tx(struct device *dev,
u8_t payload_len = frag->len; u8_t payload_len = frag->len;
u8_t *payload = frag->data; 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); LOG_DBG("%p (%u)", payload, payload_len);
nrf5_radio->tx_psdu[0] = payload_len + NRF5_FCS_LENGTH; nrf5_radio->tx_psdu[0] = payload_len + NRF5_FCS_LENGTH;

View file

@ -473,6 +473,7 @@ static void rf2xx_handle_ack(struct rf2xx_context *ctx, struct net_buf *frag)
#endif #endif
static int rf2xx_tx(struct device *dev, static int rf2xx_tx(struct device *dev,
enum ieee802154_tx_mode mode,
struct net_pkt *pkt, struct net_pkt *pkt,
struct net_buf *frag) struct net_buf *frag)
{ {
@ -481,6 +482,11 @@ static int rf2xx_tx(struct device *dev,
struct rf2xx_context *ctx = dev->driver_data; struct rf2xx_context *ctx = dev->driver_data;
int response = 0; 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_trx_set_tx_state(dev);
rf2xx_iface_reg_read(dev, RF2XX_IRQ_STATUS_REG); rf2xx_iface_reg_read(dev, RF2XX_IRQ_STATUS_REG);

View file

@ -266,6 +266,7 @@ static int upipe_set_txpower(struct device *dev, s16_t dbm)
} }
static int upipe_tx(struct device *dev, static int upipe_tx(struct device *dev,
enum ieee802154_tx_mode mode,
struct net_pkt *pkt, struct net_pkt *pkt,
struct net_buf *frag) struct net_buf *frag)
{ {
@ -274,6 +275,11 @@ static int upipe_tx(struct device *dev,
u8_t len = frag->len; u8_t len = frag->len;
u8_t i, data; 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); LOG_DBG("%p (%u)", frag, len);
if (upipe->stopped) { if (upipe->stopped) {

View file

@ -36,7 +36,8 @@ enum ieee802154_hw_caps {
IEEE802154_HW_2_4_GHZ = BIT(4), /* 2.4Ghz radio supported */ 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_TX_RX_ACK = BIT(5), /* Handles ACK request on TX */
IEEE802154_HW_SUB_GHZ = BIT(6), /* Sub-GHz radio supported */ 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 { enum ieee802154_filter_type {
@ -57,6 +58,24 @@ struct ieee802154_filter {
/* @endcond */ /* @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. */ /** IEEE802.15.4 driver configuration types. */
enum ieee802154_config_type { enum ieee802154_config_type {
/** Indicates how radio driver should set Frame Pending bit in ACK /** 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); int (*set_txpower)(struct device *dev, s16_t dbm);
/** Transmit a packet fragment */ /** Transmit a packet fragment */
int (*tx)(struct device *dev, int (*tx)(struct device *dev, enum ieee802154_tx_mode mode,
struct net_pkt *pkt, struct net_pkt *pkt, struct net_buf *frag);
struct net_buf *frag);
/** Start the device */ /** Start the device */
int (*start)(struct device *dev); int (*start)(struct device *dev);

View file

@ -248,7 +248,8 @@ static void process_data(struct net_pkt *pkt)
} }
/* Transmit data through radio */ /* 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) { if (ret) {
LOG_ERR("Error transmit data"); LOG_ERR("Error transmit data");
} }

View file

@ -260,7 +260,8 @@ static int tx(struct net_pkt *pkt)
LOG_DBG("len %d seq %u", buf->len, seq); LOG_DBG("len %d seq %u", buf->len, seq);
do { do {
ret = radio_api->tx(ieee802154_dev, pkt, buf); ret = radio_api->tx(ieee802154_dev, IEEE802154_TX_MODE_DIRECT,
pkt, buf);
} while (ret && retries--); } while (ret && retries--);
if (ret) { if (ret) {

View file

@ -81,7 +81,8 @@ static inline void ieee802154_acknowledge(struct net_if *iface,
} }
if (ieee802154_create_ack_frame(iface, pkt, mpdu->mhr.fs->sequence)) { 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); 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) && if (IS_ENABLED(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA) &&
ieee802154_get_hw_capabilities(iface) & ieee802154_get_hw_capabilities(iface) &
IEEE802154_HW_CSMA) { IEEE802154_HW_CSMA) {
ret = ieee802154_tx(iface, pkt, &frame_buf); ret = ieee802154_tx(iface, IEEE802154_TX_MODE_CSMA_CA,
pkt, &frame_buf);
} else { } else {
ret = ieee802154_radio_send(iface, pkt, &frame_buf); ret = ieee802154_radio_send(iface, pkt, &frame_buf);
} }

View file

@ -30,7 +30,8 @@ static inline int aloha_radio_send(struct net_if *iface,
while (retries) { while (retries) {
retries--; retries--;
ret = ieee802154_tx(iface, pkt, frag); ret = ieee802154_tx(iface, IEEE802154_TX_MODE_DIRECT,
pkt, frag);
if (ret) { if (ret) {
continue; continue;
} }

View file

@ -57,7 +57,8 @@ loop:
} }
} }
ret = ieee802154_tx(iface, pkt, frag); ret = ieee802154_tx(iface, IEEE802154_TX_MODE_DIRECT,
pkt, frag);
if (ret) { if (ret) {
continue; continue;
} }

View file

@ -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, 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 = const struct ieee802154_radio_api *radio =
net_if_get_device(iface)->driver_api; net_if_get_device(iface)->driver_api;
@ -73,7 +75,7 @@ static inline int ieee802154_tx(struct net_if *iface,
return -ENOENT; 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) static inline int ieee802154_start(struct net_if *iface)

View file

@ -190,11 +190,13 @@ void platformRadioProcess(otInstance *aInstance)
if (sTransmitFrame.mInfo.mTxInfo.mCsmaCaEnabled) { if (sTransmitFrame.mInfo.mTxInfo.mCsmaCaEnabled) {
if (radio_api->cca(radio_dev) || 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; result = OT_ERROR_CHANNEL_ACCESS_FAILURE;
} }
} else { } 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; result = OT_ERROR_CHANNEL_ACCESS_FAILURE;
} }
} }

View file

@ -60,6 +60,7 @@ static inline void insert_frag(struct net_pkt *pkt, struct net_buf *frag)
} }
static int fake_tx(struct device *dev, static int fake_tx(struct device *dev,
enum ieee802154_tx_mode mode,
struct net_pkt *pkt, struct net_pkt *pkt,
struct net_buf *frag) struct net_buf *frag)
{ {