diff --git a/cpu/cc2538/radio/cc2538_rf_radio_ops.c b/cpu/cc2538/radio/cc2538_rf_radio_ops.c index 85546fc5e8..dcb400567f 100644 --- a/cpu/cc2538/radio/cc2538_rf_radio_ops.c +++ b/cpu/cc2538/radio/cc2538_rf_radio_ops.c @@ -353,8 +353,10 @@ void cc2538_irq_handler(void) cc2538_rf_dev.cb(&cc2538_rf_dev, IEEE802154_RADIO_INDICATION_RX_DONE); } else { + /* Disable RX while the frame has not been processed */ + RFCORE_XREG_RXMASKCLR = 0xFF; /* CRC failed; discard packet */ - RFCORE_SFR_RFST = ISFLUSHRX; + cc2538_rf_dev.cb(&cc2538_rf_dev, IEEE802154_RADIO_INDICATION_CRC_ERROR); } } @@ -396,11 +398,12 @@ static bool _get_cap(ieee802154_dev_t *dev, ieee802154_rf_caps_t cap) (void) dev; switch (cap) { case IEEE802154_CAP_24_GHZ: + case IEEE802154_CAP_AUTO_CSMA: + case IEEE802154_CAP_IRQ_CRC_ERROR: case IEEE802154_CAP_IRQ_TX_DONE: case IEEE802154_CAP_IRQ_CCA_DONE: case IEEE802154_CAP_IRQ_RX_START: case IEEE802154_CAP_IRQ_TX_START: - case IEEE802154_CAP_AUTO_CSMA: return true; default: return false; diff --git a/cpu/nrf52/radio/nrf802154/nrf802154_radio.c b/cpu/nrf52/radio/nrf802154/nrf802154_radio.c index 592c8d5082..fc359df69b 100644 --- a/cpu/nrf52/radio/nrf802154/nrf802154_radio.c +++ b/cpu/nrf52/radio/nrf802154/nrf802154_radio.c @@ -543,7 +543,7 @@ void isr_radio(void) } else { DEBUG("[nrf802154] CRC fail.\n"); - NRF_RADIO->TASKS_START = 1; + dev->cb(dev, IEEE802154_RADIO_INDICATION_CRC_ERROR); } break; case STATE_ACK: @@ -644,6 +644,7 @@ static bool _get_cap(ieee802154_dev_t *dev, ieee802154_rf_caps_t cap) (void) dev; switch (cap) { case IEEE802154_CAP_24_GHZ: + case IEEE802154_CAP_IRQ_CRC_ERROR: case IEEE802154_CAP_IRQ_RX_START: case IEEE802154_CAP_IRQ_TX_START: case IEEE802154_CAP_IRQ_TX_DONE: diff --git a/drivers/include/net/netdev/ieee802154_submac.h b/drivers/include/net/netdev/ieee802154_submac.h index f91f0298e9..a148f788f8 100644 --- a/drivers/include/net/netdev/ieee802154_submac.h +++ b/drivers/include/net/netdev/ieee802154_submac.h @@ -38,8 +38,9 @@ extern "C" { #include "xtimer.h" #define NETDEV_SUBMAC_FLAGS_ACK_TIMEOUT (1 << 0) /**< Flag for ACK Timeout event */ -#define NETDEV_SUBMAC_FLAGS_TX_DONE (1 << 1) /**< Flag for TX Done event */ -#define NETDEV_SUBMAC_FLAGS_RX_DONE (1 << 2) /**< Flag for RX Done event */ +#define NETDEV_SUBMAC_FLAGS_TX_DONE (1 << 1) /**< Flag for TX Done event */ +#define NETDEV_SUBMAC_FLAGS_RX_DONE (1 << 2) /**< Flag for RX Done event */ +#define NETDEV_SUBMAC_FLAGS_CRC_ERROR (1 << 3) /**< Flag for CRC ERROR event */ /** * @brief IEEE 802.15.4 SubMAC netdev descriptor diff --git a/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c b/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c index adc6f053ba..b54b5f8371 100644 --- a/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c +++ b/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c @@ -178,6 +178,10 @@ static void _isr(netdev_t *netdev) if (flags & NETDEV_SUBMAC_FLAGS_RX_DONE) { ieee802154_submac_rx_done_cb(submac); } + + if (flags & NETDEV_SUBMAC_FLAGS_CRC_ERROR) { + ieee802154_submac_crc_error_cb(submac); + } } while (netdev_submac->isr_flags != 0); } @@ -268,6 +272,10 @@ static void _hal_radio_cb(ieee802154_dev_t *dev, ieee802154_trx_ev_t status) break; case IEEE802154_RADIO_INDICATION_RX_DONE: netdev_submac->isr_flags |= NETDEV_SUBMAC_FLAGS_RX_DONE; + break; + case IEEE802154_RADIO_INDICATION_CRC_ERROR: + netdev_submac->isr_flags |= NETDEV_SUBMAC_FLAGS_CRC_ERROR; + break; default: break; } diff --git a/pkg/openwsn/contrib/radio_hal.c b/pkg/openwsn/contrib/radio_hal.c index 28a46dd34c..ae35306740 100644 --- a/pkg/openwsn/contrib/radio_hal.c +++ b/pkg/openwsn/contrib/radio_hal.c @@ -16,6 +16,7 @@ * @author Francisco Molina * @} */ +#include #include #include "leds.h" @@ -40,6 +41,8 @@ openwsn_radio_t openwsn_radio; /* stores the event capture time */ static PORT_TIMER_WIDTH _txrx_event_capture_time = 0; +/* set if frame with valid CRC is received, false otherwise */ +static atomic_bool _valid_crc = true; void _idmanager_addr_override(void) { @@ -89,12 +92,21 @@ static void _hal_radio_cb(ieee802154_dev_t *dev, ieee802154_trx_ev_t status) while (ieee802154_radio_confirm_set_trx_state(openwsn_radio.dev) == -EAGAIN) {} openwsn_radio.endFrame_cb(_txrx_event_capture_time); break; + case IEEE802154_RADIO_INDICATION_CRC_ERROR: + _valid_crc = false; + ieee802154_radio_request_set_trx_state(openwsn_radio.dev, + IEEE802154_TRX_STATE_TRX_OFF); + while (ieee802154_radio_confirm_set_trx_state(openwsn_radio.dev) == -EAGAIN) {} + openwsn_radio.endFrame_cb(_txrx_event_capture_time); + break; case IEEE802154_RADIO_INDICATION_RX_DONE: + _valid_crc = true; + ieee802154_radio_request_set_trx_state(openwsn_radio.dev, + IEEE802154_TRX_STATE_TRX_OFF); + while (ieee802154_radio_confirm_set_trx_state(openwsn_radio.dev) == -EAGAIN) {} openwsn_radio.endFrame_cb(_txrx_event_capture_time); break; case IEEE802154_RADIO_INDICATION_TX_START: - openwsn_radio.startFrame_cb(_txrx_event_capture_time); - break; case IEEE802154_RADIO_INDICATION_RX_START: openwsn_radio.startFrame_cb(_txrx_event_capture_time); break; @@ -312,6 +324,5 @@ void radio_getReceivedFrame(uint8_t *bufRead, /* get rssi, lqi & crc */ *rssi = ieee802154_rssi_to_dbm(rx_info.rssi); *lqi = rx_info.lqi; - /* only valid crc frames are currently accepted */ - *crc = 1; + *crc = _valid_crc ? 1 : 0; } diff --git a/sys/include/net/ieee802154/radio.h b/sys/include/net/ieee802154/radio.h index 44066927a1..721703e871 100644 --- a/sys/include/net/ieee802154/radio.h +++ b/sys/include/net/ieee802154/radio.h @@ -92,6 +92,10 @@ typedef enum { * @brief the device support the IEEE802.15.4 Sub GHz band */ IEEE802154_CAP_SUB_GHZ, + /** + * @brief the device reports reception off frames with invalid CRC. + */ + IEEE802154_CAP_IRQ_CRC_ERROR, /** * @brief the device reports when the transmission is done */ @@ -190,6 +194,18 @@ typedef enum { */ IEEE802154_RADIO_INDICATION_RX_START, + /** + * @brief the transceiver received a frame with an invalid crc. + * + * The transceiver might not stay in @ref IEEE802154_TRX_STATE_RX_ON + * after receiving an invalid CRC. Therefore the upper layer must + * set the transceiver state (@ref ieee802154_radio_ops::request_set_trx_state). + * e.g.: @ref IEEE802154_TRX_STATE_TRX_OFF or @ref IEEE802154_TRX_STATE_TX_ON + * to stop listening or @ref IEEE802154_TRX_STATE_RX_ON to keep + * listening. + */ + IEEE802154_RADIO_INDICATION_CRC_ERROR, + /** * @brief the transceiver sent out a valid SFD * diff --git a/sys/include/net/ieee802154/submac.h b/sys/include/net/ieee802154/submac.h index 1f777d2b50..5548ce9f8c 100644 --- a/sys/include/net/ieee802154/submac.h +++ b/sys/include/net/ieee802154/submac.h @@ -379,6 +379,13 @@ void ieee802154_submac_ack_timeout_fired(ieee802154_submac_t *submac); */ void ieee802154_submac_rx_done_cb(ieee802154_submac_t *submac); +/** + * @brief Indicate the SubMAC that a frame with invalid CRC was received. + * + * @param[in] submac pointer to the SubMAC descriptor + */ +void ieee802154_submac_crc_error_cb(ieee802154_submac_t *submac); + /** * @brief Indicate the SubMAC that the device finished the transmission procedure. * diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index 0193a83c45..352e3da991 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -147,6 +147,14 @@ void ieee802154_submac_ack_timeout_fired(ieee802154_submac_t *submac) } } +void ieee802154_submac_crc_error_cb(ieee802154_submac_t *submac) +{ + ieee802154_dev_t *dev = submac->dev; + /* switch back to RX_ON state */ + ieee802154_radio_request_set_trx_state(dev, IEEE802154_TRX_STATE_RX_ON); + while (ieee802154_radio_confirm_set_trx_state(dev) == -EAGAIN) {} +} + /* All callbacks run in the same context */ void ieee802154_submac_rx_done_cb(ieee802154_submac_t *submac) { diff --git a/tests/ieee802154_hal/main.c b/tests/ieee802154_hal/main.c index 555476b1b3..22dce9ffa0 100644 --- a/tests/ieee802154_hal/main.c +++ b/tests/ieee802154_hal/main.c @@ -102,6 +102,21 @@ static xtimer_t timer_ack = { .callback = _timer_ack_handler, }; +void _crc_error_handler(event_t *event) +{ + (void) event; + puts("Packet with invalid CRC received"); + ieee802154_dev_t* dev = ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID); + /* switch back to RX_ON state */ + ieee802154_radio_request_set_trx_state(dev, IEEE802154_TRX_STATE_RX_ON); + while (ieee802154_radio_confirm_set_trx_state(dev) == -EAGAIN) {} +} + +static event_t _crc_error_event = { + .handler = _crc_error_handler, +}; + + void _rx_done_handler(event_t *event) { (void) event; @@ -139,6 +154,9 @@ static void _hal_radio_cb(ieee802154_dev_t *dev, ieee802154_trx_ev_t status) case IEEE802154_RADIO_INDICATION_RX_DONE: event_post(EVENT_PRIO_HIGHEST, &_rx_done_event); break; + case IEEE802154_RADIO_INDICATION_CRC_ERROR: + event_post(EVENT_PRIO_HIGHEST, &_crc_error_event); + break; default: break; }