Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

at86rf2xx: fix receive before send detection #12728

Merged
merged 2 commits into from
Feb 7, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 64 additions & 45 deletions drivers/at86rf2xx/at86rf2xx_netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}
}
Expand Down