diff --git a/drivers/at86rf2xx/at86rf2xx_netdev.c b/drivers/at86rf2xx/at86rf2xx_netdev.c index 3786e3b1cded..05a0a598239a 100644 --- a/drivers/at86rf2xx/at86rf2xx_netdev.c +++ b/drivers/at86rf2xx/at86rf2xx_netdev.c @@ -627,6 +627,51 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len) return res; } +static void _isr_send_complete(at86rf2xx_t *dev, uint8_t trac_status) +{ + netdev_t *netdev = &dev->netdev.netdev; +/* Only radios with the XAH_CTRL_2 register support frame retry reporting */ +#if AT86RF2XX_HAVE_RETRIES + dev->tx_retries = (at86rf2xx_reg_read(dev, AT86RF2XX_REG__XAH_CTRL_2) + & AT86RF2XX_XAH_CTRL_2__ARET_FRAME_RETRIES_MASK) >> + AT86RF2XX_XAH_CTRL_2__ARET_FRAME_RETRIES_OFFSET; +#endif + + DEBUG("[at86rf2xx] EVT - TX_END\n"); + + if (netdev->event_callback && (dev->flags & AT86RF2XX_OPT_TELL_TX_END)) { + switch (trac_status) { +#ifdef MODULE_OPENTHREAD + case AT86RF2XX_TRX_STATE__TRAC_SUCCESS: + netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE); + DEBUG("[at86rf2xx] TX SUCCESS\n"); + break; + case AT86RF2XX_TRX_STATE__TRAC_SUCCESS_DATA_PENDING: + netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE_DATA_PENDING); + DEBUG("[at86rf2xx] TX SUCCESS DATA PENDING\n"); + break; +#else + case AT86RF2XX_TRX_STATE__TRAC_SUCCESS: + case AT86RF2XX_TRX_STATE__TRAC_SUCCESS_DATA_PENDING: + netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE); + DEBUG("[at86rf2xx] TX SUCCESS\n"); + break; +#endif + case AT86RF2XX_TRX_STATE__TRAC_NO_ACK: + netdev->event_callback(netdev, NETDEV_EVENT_TX_NOACK); + DEBUG("[at86rf2xx] TX NO_ACK\n"); + break; + case AT86RF2XX_TRX_STATE__TRAC_CHANNEL_ACCESS_FAILURE: + netdev->event_callback(netdev, NETDEV_EVENT_TX_MEDIUM_BUSY); + DEBUG("[at86rf2xx] TX_CHANNEL_ACCESS_FAILURE\n"); + break; + default: + DEBUG("[at86rf2xx] Unhandled TRAC_STATUS: %d\n", + trac_status >> 5); + } + } +} + static void _isr(netdev_t *netdev) { at86rf2xx_t *dev = (at86rf2xx_t *) netdev; @@ -667,54 +712,28 @@ static void _isr(netdev_t *netdev) } netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE); } - else if ((state == AT86RF2XX_STATE_TX_ARET_ON) - || (state == AT86RF2XX_STATE_BUSY_TX_ARET)) { + else if (state == AT86RF2XX_STATE_TX_ARET_ON) { /* check for more pending TX calls and return to idle state if * there are none */ assert(dev->pending_tx != 0); - if ((--dev->pending_tx) == 0) { - at86rf2xx_set_state(dev, dev->idle_state); - DEBUG("[at86rf2xx] return to idle state 0x%x\n", dev->idle_state); - } -/* Only radios with the XAH_CTRL_2 register support frame retry reporting */ -#if AT86RF2XX_HAVE_RETRIES - dev->tx_retries = (at86rf2xx_reg_read(dev, AT86RF2XX_REG__XAH_CTRL_2) - & AT86RF2XX_XAH_CTRL_2__ARET_FRAME_RETRIES_MASK) >> - AT86RF2XX_XAH_CTRL_2__ARET_FRAME_RETRIES_OFFSET; -#endif - - DEBUG("[at86rf2xx] EVT - TX_END\n"); - - if (netdev->event_callback && (dev->flags & AT86RF2XX_OPT_TELL_TX_END)) { - switch (trac_status) { -#ifdef MODULE_OPENTHREAD - case AT86RF2XX_TRX_STATE__TRAC_SUCCESS: - netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE); - DEBUG("[at86rf2xx] TX SUCCESS\n"); - break; - case AT86RF2XX_TRX_STATE__TRAC_SUCCESS_DATA_PENDING: - netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE_DATA_PENDING); - DEBUG("[at86rf2xx] TX SUCCESS DATA PENDING\n"); - break; -#else - case AT86RF2XX_TRX_STATE__TRAC_SUCCESS: - case AT86RF2XX_TRX_STATE__TRAC_SUCCESS_DATA_PENDING: - netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE); - DEBUG("[at86rf2xx] TX SUCCESS\n"); - break; -#endif - case AT86RF2XX_TRX_STATE__TRAC_NO_ACK: - netdev->event_callback(netdev, NETDEV_EVENT_TX_NOACK); - DEBUG("[at86rf2xx] TX NO_ACK\n"); - break; - case AT86RF2XX_TRX_STATE__TRAC_CHANNEL_ACCESS_FAILURE: - netdev->event_callback(netdev, NETDEV_EVENT_TX_MEDIUM_BUSY); - DEBUG("[at86rf2xx] TX_CHANNEL_ACCESS_FAILURE\n"); - break; - default: - DEBUG("[at86rf2xx] Unhandled TRAC_STATUS: %d\n", - trac_status >> 5); - } + /* Radio is idle, any TX transaction is done */ + dev->pending_tx = 0; + at86rf2xx_set_state(dev, dev->idle_state); + DEBUG("[at86rf2xx] return to idle state 0x%x\n", dev->idle_state); + _isr_send_complete(dev, trac_status); + } + /* Only the case when an interrupt was received and the radio is busy + * with a next PDU transmission when _isr is called. + * dev->pending == 1 means a receive and immediately a send happened. + * The receive is discarded as the send already overwrote the internal + * buffer. + * dev->pending == 2 means two transmits occurred and this is the isr for + * the first. + */ + else if (state == AT86RF2XX_STATE_BUSY_TX_ARET) { + if (dev->pending_tx > 1) { + dev->pending_tx--; + _isr_send_complete(dev, trac_status); } } }