From d1261a7ef08cef4271be60fdb1cedbc950f1e1ef Mon Sep 17 00:00:00 2001 From: Josarn Date: Fri, 6 Jul 2018 14:03:09 +0200 Subject: [PATCH] at86rf2xx: correct framebuffer release This PR sets the tranceiver in PLL_ON state to avoid corruption of the data in the frame buffer and sets it back to the last state which the transceiver had before changing into transmit mode after the data is read out. This is done to avoid data corruption when `_recv(...)` is called to retrieve the buffer size and frame buffer protection is released. --- drivers/at86rf2xx/at86rf2xx.c | 3 +++ drivers/at86rf2xx/at86rf2xx_netdev.c | 26 +++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/at86rf2xx/at86rf2xx.c b/drivers/at86rf2xx/at86rf2xx.c index 613dfcb2f8..800616843e 100644 --- a/drivers/at86rf2xx/at86rf2xx.c +++ b/drivers/at86rf2xx/at86rf2xx.c @@ -44,6 +44,7 @@ void at86rf2xx_setup(at86rf2xx_t *dev, const at86rf2xx_params_t *params) netdev->driver = &at86rf2xx_driver; /* initialize device descriptor */ memcpy(&dev->params, params, sizeof(at86rf2xx_params_t)); + /* State to return after receiving or transmitting */ dev->idle_state = AT86RF2XX_STATE_TRX_OFF; /* radio state is P_ON when first powered-on */ dev->state = AT86RF2XX_STATE_P_ON; @@ -123,6 +124,8 @@ void at86rf2xx_reset(at86rf2xx_t *dev) /* clear interrupt flags */ at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS); + /* State to return after receiving or transmitting */ + dev->idle_state = AT86RF2XX_STATE_RX_AACK_ON; /* go into RX state */ at86rf2xx_set_state(dev, AT86RF2XX_STATE_RX_AACK_ON); diff --git a/drivers/at86rf2xx/at86rf2xx_netdev.c b/drivers/at86rf2xx/at86rf2xx_netdev.c index 2623524b78..0fbdc559cb 100644 --- a/drivers/at86rf2xx/at86rf2xx_netdev.c +++ b/drivers/at86rf2xx/at86rf2xx_netdev.c @@ -131,8 +131,11 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) uint8_t phr; size_t pkt_len; - /* frame buffer protection will be unlocked as soon as at86rf2xx_fb_stop() - * is called*/ + /* frame buffer protection will be unlocked as soon as at86rf2xx_fb_stop() is called, + * Set receiver to PLL_ON state to be able to free the SPI bus and avoid loosing data. */ + at86rf2xx_set_state(dev, AT86RF2XX_STATE_PLL_ON); + + /* start frame buffer access */ at86rf2xx_fb_start(dev); /* get the size of the received packet */ @@ -141,14 +144,27 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) /* ignore MSB (refer p.80) and substract length of FCS field */ pkt_len = (phr & 0x7f) - 2; - /* just return length when buf == NULL */ + /* return length when buf == NULL */ if (buf == NULL) { + /* release SPI bus */ at86rf2xx_fb_stop(dev); + + /* drop packet, continue receiving */ + if (len > 0) { + /* set device back in operation state which was used before last transmission. + * e.g RX_AACK_ON */ + at86rf2xx_set_state(dev, dev->idle_state); + } + return pkt_len; } + /* not enough space in buf */ if (pkt_len > len) { at86rf2xx_fb_stop(dev); + /* set device back in operation state which was used before last transmission. + * e.g RX_AACK_ON */ + at86rf2xx_set_state(dev, dev->idle_state); return -ENOBUFS; } #ifdef MODULE_NETSTATS_L2 @@ -202,6 +218,10 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) at86rf2xx_fb_stop(dev); } + /* set device back in operation state which was used before last transmission. + * e.g RX_AACK_ON */ + at86rf2xx_set_state(dev, dev->idle_state); + return pkt_len; }