mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
cc2538_rf: remove RX Busy detection in request_set_trx_state
This PR removes the RX Busy detection because it doesn't seem to be reliable enough to ensure the radio is not locked. Some radios such as nrf802154 don't provide RX Busy detection mechanisms, so this is not uncommon. It's intended that the MAC layer takes care of this (e.g slots, CSMA-CA with retransmissions, etc)
This commit is contained in:
parent
467236dba8
commit
474838ba15
@ -296,6 +296,24 @@ typedef struct {
|
||||
*/
|
||||
void cc2538_rf_hal_setup(ieee802154_dev_t *hal);
|
||||
|
||||
/**
|
||||
* @brief Enable CC2538 RF IRQs.
|
||||
*/
|
||||
static inline void cc2538_rf_enable_irq(void)
|
||||
{
|
||||
RFCORE_XREG_RFIRQM1 = TXDONE | CSP_STOP | TXACKDONE;
|
||||
RFCORE_XREG_RFIRQM0 = RXPKTDONE | SFD;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable CC2538 RF IRQs.
|
||||
*/
|
||||
static inline void cc2538_rf_disable_irq(void)
|
||||
{
|
||||
RFCORE_XREG_RFIRQM1 = 0;
|
||||
RFCORE_XREG_RFIRQM0 = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief IRQ handler for RF events
|
||||
*
|
||||
|
@ -134,8 +134,7 @@ void cc2538_init(void)
|
||||
RFCORE_XREG_FIFOPCTRL = CC2538_RF_MAX_DATA_LEN;
|
||||
|
||||
/* Set default IRQ */
|
||||
RFCORE_XREG_RFIRQM1 = TXDONE | CSP_STOP | TXACKDONE;
|
||||
RFCORE_XREG_RFIRQM0 = RXPKTDONE | FIFOP | SFD;
|
||||
cc2538_rf_enable_irq();
|
||||
|
||||
/* Enable all RF CORE error interrupts */
|
||||
RFCORE_XREG_RFERRM = STROBE_ERR | TXUNDERF | TXOVERF | \
|
||||
|
@ -30,21 +30,39 @@
|
||||
|
||||
#include "net/ieee802154/radio.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
static const ieee802154_radio_ops_t cc2538_rf_ops;
|
||||
|
||||
static ieee802154_dev_t *cc2538_rf_hal;
|
||||
|
||||
static bool cc2538_tx_busy; /**< used to indicate TX chain is busy */
|
||||
static bool cc2538_rx_busy; /**< used to indicate RX chain is busy */
|
||||
typedef enum {
|
||||
CC2538_STATE_READY, /**< The radio is ready to receive requests */
|
||||
CC2538_STATE_TRX_TRANSITION, /**< There's a pending TRX state transition */
|
||||
CC2538_STATE_CONFIRM_TX, /**< Transmission finished and waiting for confirm */
|
||||
CC2538_STATE_TX_BUSY, /**< The radio is busy transmitting */
|
||||
CC2538_STATE_TX_ACK, /**< The radio is currently transmitting an ACK frame */
|
||||
CC2538_STATE_CCA, /**< The radio is doing CCA */
|
||||
CC2538_STATE_CONFIRM_CCA, /**< CCA finished and waiting for confirm */
|
||||
} cc2538_state_t;
|
||||
|
||||
static cc2538_state_t cc2538_state;
|
||||
static uint8_t cc2538_min_be = CONFIG_IEEE802154_DEFAULT_CSMA_CA_MIN_BE;
|
||||
static uint8_t cc2538_max_be = CONFIG_IEEE802154_DEFAULT_CSMA_CA_MAX_BE;
|
||||
static int cc2538_csma_ca_retries = CONFIG_IEEE802154_DEFAULT_CSMA_CA_RETRIES;
|
||||
|
||||
static bool cc2538_cca_status; /**< status of the last CCA request */
|
||||
static bool cc2538_cca; /**< used to check whether the last CCA result
|
||||
corresponds to a CCA request or send with
|
||||
CSMA-CA */
|
||||
|
||||
static void _enable_rx(void)
|
||||
{
|
||||
RFCORE_XREG_FRMCTRL0 &= ~CC2538_FRMCTRL0_RX_MODE_DIS;
|
||||
}
|
||||
|
||||
static void _disable_rx(void)
|
||||
{
|
||||
RFCORE_XREG_FRMCTRL0 |= CC2538_FRMCTRL0_RX_MODE_DIS;
|
||||
}
|
||||
|
||||
static int _write(ieee802154_dev_t *dev, const iolist_t *iolist)
|
||||
{
|
||||
@ -69,8 +87,10 @@ static int _confirm_transmit(ieee802154_dev_t *dev, ieee802154_tx_info_t *info)
|
||||
{
|
||||
(void) dev;
|
||||
|
||||
if (cc2538_tx_busy) {
|
||||
return -EAGAIN;
|
||||
cc2538_rf_disable_irq();
|
||||
int res = -EAGAIN;
|
||||
if (cc2538_state != CC2538_STATE_CONFIRM_TX) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (info) {
|
||||
@ -82,14 +102,22 @@ static int _confirm_transmit(ieee802154_dev_t *dev, ieee802154_tx_info_t *info)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
cc2538_state = CC2538_STATE_READY;
|
||||
res = 0;
|
||||
|
||||
end:
|
||||
cc2538_rf_enable_irq();
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _request_transmit(ieee802154_dev_t *dev)
|
||||
{
|
||||
(void) dev;
|
||||
|
||||
cc2538_tx_busy = true;
|
||||
cc2538_rf_disable_irq();
|
||||
assert(cc2538_state != CC2538_STATE_TX_BUSY);
|
||||
cc2538_state = CC2538_STATE_TX_BUSY;
|
||||
|
||||
if (cc2538_csma_ca_retries < 0) {
|
||||
RFCORE_SFR_RFST = ISTXON;
|
||||
/* The CPU Ctrl mask is used here to indicate whether the radio is being
|
||||
@ -101,10 +129,8 @@ static int _request_transmit(ieee802154_dev_t *dev)
|
||||
RFCORE_XREG_CSPCTRL |= CC2538_CSP_MCU_CTRL_MASK;
|
||||
}
|
||||
else {
|
||||
cc2538_cca = false;
|
||||
|
||||
/* Disable RX Chain for CCA (see CC2538 RM, Section 29.9.5.3) */
|
||||
RFCORE_XREG_FRMCTRL0 |= CC2538_FRMCTRL0_RX_MODE_DIS;
|
||||
_disable_rx();
|
||||
RFCORE_SFR_RFST = ISRXON;
|
||||
/* Clear last program */
|
||||
RFCORE_SFR_RFST = ISCLEAR;
|
||||
@ -162,6 +188,7 @@ static int _request_transmit(ieee802154_dev_t *dev)
|
||||
/* Execute the program */
|
||||
RFCORE_SFR_RFST = ISSTART;
|
||||
}
|
||||
cc2538_rf_enable_irq();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -226,8 +253,12 @@ static int _read(ieee802154_dev_t *dev, void *buf, size_t size, ieee802154_rx_in
|
||||
}
|
||||
|
||||
end:
|
||||
/* Enable RX Chain */
|
||||
RFCORE_XREG_FRMCTRL0 &= ~CC2538_FRMCTRL0_RX_MODE_DIS;
|
||||
/* Don't enable RX chain if the radio is currently doing CCA or during
|
||||
* transmission. */
|
||||
if (cc2538_state != CC2538_STATE_CCA
|
||||
&& cc2538_state != CC2538_STATE_TX_BUSY) {
|
||||
_enable_rx();
|
||||
}
|
||||
RFCORE_SFR_RFST = ISFLUSHRX;
|
||||
return res;
|
||||
}
|
||||
@ -236,22 +267,38 @@ static int _confirm_cca(ieee802154_dev_t *dev)
|
||||
{
|
||||
(void) dev;
|
||||
|
||||
RFCORE_XREG_RFIRQM0 |= RXPKTDONE;
|
||||
int res = -EAGAIN;
|
||||
cc2538_rf_disable_irq();
|
||||
assert(cc2538_state == CC2538_STATE_CCA || cc2538_state == CC2538_STATE_CONFIRM_CCA);
|
||||
|
||||
return cc2538_cca_status;
|
||||
if (cc2538_state != CC2538_STATE_CONFIRM_CCA) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
cc2538_state = CC2538_STATE_READY;
|
||||
_enable_rx();
|
||||
res = cc2538_cca_status;
|
||||
|
||||
end:
|
||||
cc2538_rf_enable_irq();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _request_cca(ieee802154_dev_t *dev)
|
||||
{
|
||||
(void) dev;
|
||||
int res = -EINVAL;
|
||||
cc2538_rf_disable_irq();
|
||||
if (!RFCORE->XREG_FSMSTAT1bits.RX_ACTIVE) {
|
||||
return -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Ignore baseband processing */
|
||||
RFCORE_XREG_RFIRQM0 &= ~RXPKTDONE;
|
||||
cc2538_state = CC2538_STATE_CCA;
|
||||
|
||||
/* Ignore baseband processing */
|
||||
_disable_rx();
|
||||
|
||||
cc2538_cca = true;
|
||||
RFCORE_SFR_RFST = ISCLEAR;
|
||||
RFCORE_SFR_RFST = STOP;
|
||||
RFCORE_XREG_CSPCTRL &= ~CC2538_CSP_MCU_CTRL_MASK;
|
||||
@ -259,7 +306,9 @@ static int _request_cca(ieee802154_dev_t *dev)
|
||||
/* Execute the last program */
|
||||
RFCORE_SFR_RFST = ISSTART;
|
||||
|
||||
return 0;
|
||||
end:
|
||||
cc2538_rf_enable_irq();
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _set_cca_threshold(ieee802154_dev_t *dev, int8_t threshold)
|
||||
@ -295,9 +344,9 @@ static int _config_phy(ieee802154_dev_t *dev, const ieee802154_phy_conf_t *conf)
|
||||
static int _confirm_set_trx_state(ieee802154_dev_t *dev)
|
||||
{
|
||||
(void) dev;
|
||||
if (RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE == FSM_STATE_RX_CALIBRATION) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
assert(cc2538_state == CC2538_STATE_TRX_TRANSITION);
|
||||
cc2538_state = CC2538_STATE_READY;
|
||||
cc2538_rf_enable_irq();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -305,33 +354,38 @@ static int _request_set_trx_state(ieee802154_dev_t *dev, ieee802154_trx_state_t
|
||||
{
|
||||
|
||||
(void) dev;
|
||||
int irq = irq_disable();
|
||||
if (cc2538_tx_busy || cc2538_rx_busy) {
|
||||
irq_restore(irq);
|
||||
return -EBUSY;
|
||||
cc2538_rf_disable_irq();
|
||||
int res = -EBUSY;
|
||||
if (cc2538_state != CC2538_STATE_READY) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
res = 0;
|
||||
cc2538_state = CC2538_STATE_TRX_TRANSITION;
|
||||
|
||||
switch (state) {
|
||||
case IEEE802154_TRX_STATE_TRX_OFF:
|
||||
case IEEE802154_TRX_STATE_TX_ON:
|
||||
if (RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE != FSM_STATE_IDLE) {
|
||||
RFCORE_SFR_RFST = ISRFOFF;
|
||||
}
|
||||
cc2538_rx_busy = false;
|
||||
break;
|
||||
case IEEE802154_TRX_STATE_RX_ON:
|
||||
RFCORE_XREG_RFIRQM0 |= RXPKTDONE;
|
||||
/* Enable RX Chain */
|
||||
RFCORE_XREG_FRMCTRL0 &= ~CC2538_FRMCTRL0_RX_MODE_DIS;
|
||||
_enable_rx();
|
||||
RFCORE_SFR_RFST = ISRXON;
|
||||
break;
|
||||
}
|
||||
|
||||
RFCORE_SFR_RFIRQF0 = 0;
|
||||
RFCORE_SFR_RFIRQF1 = 0;
|
||||
RFCORE_SFR_RFIRQF0 &= ~RXPKTDONE;
|
||||
RFCORE_SFR_RFIRQF0 &= ~SFD;
|
||||
|
||||
irq_restore(irq);
|
||||
return 0;
|
||||
end:
|
||||
if (res < 0) {
|
||||
cc2538_rf_enable_irq();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void cc2538_irq_handler(void)
|
||||
@ -339,79 +393,108 @@ void cc2538_irq_handler(void)
|
||||
uint_fast8_t flags_f0 = RFCORE_SFR_RFIRQF0;
|
||||
uint_fast8_t flags_f1 = RFCORE_SFR_RFIRQF1;
|
||||
|
||||
RFCORE_SFR_RFIRQF0 = 0;
|
||||
RFCORE_SFR_RFIRQF1 = 0;
|
||||
uint8_t handled_f0 = 0;
|
||||
uint8_t handled_f1 = 0;
|
||||
|
||||
if ((flags_f0 & SFD)) {
|
||||
/* If the radio already transmitted, this SFD is the TX_START event */
|
||||
if (cc2538_tx_busy) {
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_INDICATION_TX_START);
|
||||
}
|
||||
/* If the RX chain was not busy, the detected SFD corresponds to a new
|
||||
* incoming frame. Note the automatic ACK frame also triggers this event.
|
||||
* Therefore, we use this variable to distinguish them. */
|
||||
else if (!cc2538_rx_busy){
|
||||
cc2538_rx_busy = true;
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_INDICATION_RX_START);
|
||||
}
|
||||
}
|
||||
assert(cc2538_state != CC2538_STATE_TRX_TRANSITION);
|
||||
|
||||
if (flags_f1 & TXDONE) {
|
||||
handled_f1 |= TXDONE;
|
||||
/* TXDONE marks the end of the TX chain. The radio is not busy anymore */
|
||||
cc2538_tx_busy = false;
|
||||
assert(cc2538_state == CC2538_STATE_TX_BUSY);
|
||||
cc2538_state = CC2538_STATE_CONFIRM_TX;
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_CONFIRM_TX_DONE);
|
||||
}
|
||||
|
||||
/* The RX chain is not busy anymore on TXACKDONE event */
|
||||
if (flags_f1 & TXACKDONE) {
|
||||
handled_f1 |= TXACKDONE;
|
||||
assert(cc2538_state == CC2538_STATE_TX_ACK);
|
||||
cc2538_state = CC2538_STATE_READY;
|
||||
}
|
||||
|
||||
if ((flags_f0 & SFD)) {
|
||||
handled_f0 |= SFD;
|
||||
switch(cc2538_state) {
|
||||
case CC2538_STATE_READY:
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_INDICATION_RX_START);
|
||||
break;
|
||||
case CC2538_STATE_TX_BUSY:
|
||||
/* If the radio already transmitted, this SFD is the TX_START event */
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_INDICATION_TX_START);
|
||||
break;
|
||||
case CC2538_STATE_TX_ACK:
|
||||
/* The detected SFD comes from the transmitted ACK frame. Simply
|
||||
* ignore it */
|
||||
break;
|
||||
default:
|
||||
/* This should never happen */
|
||||
DEBUG("ERROR: cc2538_state: %i\n", cc2538_state);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags_f0 & RXPKTDONE) {
|
||||
handled_f0 |= RXPKTDONE;
|
||||
/* CRC check */
|
||||
uint8_t pkt_len = rfcore_peek_rx_fifo(0);
|
||||
if (rfcore_peek_rx_fifo(pkt_len) & CC2538_CRC_BIT_MASK) {
|
||||
/* Disable RX while the frame has not been processed */
|
||||
RFCORE_XREG_FRMCTRL0 |= CC2538_FRMCTRL0_RX_MODE_DIS;
|
||||
_disable_rx();
|
||||
/* If AUTOACK is disabled or the ACK request bit is not set */
|
||||
if (IS_ACTIVE(CONFIG_IEEE802154_AUTO_ACK_DISABLE) ||
|
||||
(!(rfcore_peek_rx_fifo(1) & IEEE802154_FCF_ACK_REQ))) {
|
||||
/* The radio won't send an ACK. Therefore the RX chain is not
|
||||
* busy anymore
|
||||
*/
|
||||
cc2538_rx_busy = false;
|
||||
cc2538_state = CC2538_STATE_READY;
|
||||
}
|
||||
else {
|
||||
cc2538_state = CC2538_STATE_TX_ACK;
|
||||
}
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_INDICATION_RX_DONE);
|
||||
}
|
||||
else {
|
||||
/* Disable RX while the frame has not been processed */
|
||||
/* CRC failed; discard packet. The RX chain is not busy anymore */
|
||||
cc2538_rx_busy = false;
|
||||
cc2538_state = CC2538_STATE_READY;
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_INDICATION_CRC_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/* The RX chain is not busy anymore on TXACKDONE event */
|
||||
if (flags_f1 & TXACKDONE) {
|
||||
cc2538_rx_busy = false;
|
||||
}
|
||||
|
||||
/* Check if the interrupt was triggered because the CSP finished its routine
|
||||
* (CSMA-CA or CCA request)
|
||||
*/
|
||||
if (flags_f1 & CSP_STOP) {
|
||||
handled_f1 |= CSP_STOP;
|
||||
RFCORE_XREG_CSPCTRL |= CC2538_CSP_MCU_CTRL_MASK;
|
||||
if (!cc2538_cca) {
|
||||
switch (cc2538_state) {
|
||||
case CC2538_STATE_TX_BUSY:
|
||||
if (RFCORE_XREG_CSPZ > 0) {
|
||||
RFCORE_SFR_RFST = ISTXON;
|
||||
}
|
||||
else {
|
||||
/* In case of CCA failure the TX chain is not busy anymore */
|
||||
cc2538_tx_busy = false;
|
||||
cc2538_state = CC2538_STATE_CONFIRM_TX;
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_CONFIRM_TX_DONE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
case CC2538_STATE_CCA:
|
||||
cc2538_cca_status = BOOLEAN(RFCORE->XREG_FSMSTAT1bits.CCA)
|
||||
&& RFCORE->XREG_RSSISTATbits.RSSI_VALID;
|
||||
cc2538_state = CC2538_STATE_CONFIRM_CCA;
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_CONFIRM_CCA);
|
||||
break;
|
||||
default:
|
||||
/* This should never happen */
|
||||
DEBUG("ERROR: cc2538_state: %i\n", cc2538_state);
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RFCORE_SFR_RFIRQF0 &= ~handled_f0;
|
||||
RFCORE_SFR_RFIRQF1 &= ~handled_f1;
|
||||
}
|
||||
|
||||
static int _off(ieee802154_dev_t *dev)
|
||||
|
Loading…
Reference in New Issue
Block a user