From db815aa779e6eaaed537d5300aa5890bb4a0e5ea Mon Sep 17 00:00:00 2001 From: Jose Alamos Date: Tue, 28 Sep 2021 13:15:29 +0200 Subject: [PATCH] ieee802154/hal: migrate to request_op and confirm_op --- cpu/cc2538/radio/cc2538_rf_radio_ops.c | 375 ++++++++--------- cpu/native/include/socket_zep.h | 2 +- cpu/native/socket_zep/socket_zep.c | 83 ++-- cpu/nrf52/radio/nrf802154/nrf802154_radio.c | 251 ++++++------ pkg/openwsn/contrib/radio_hal.c | 52 +-- sys/include/net/ieee802154/radio.h | 431 +++++++++++++------- sys/net/link_layer/ieee802154/submac.c | 84 ++-- tests/ieee802154_hal/main.c | 121 +++--- 8 files changed, 746 insertions(+), 653 deletions(-) diff --git a/cpu/cc2538/radio/cc2538_rf_radio_ops.c b/cpu/cc2538/radio/cc2538_rf_radio_ops.c index c3184bec4f..2190b44f25 100644 --- a/cpu/cc2538/radio/cc2538_rf_radio_ops.c +++ b/cpu/cc2538/radio/cc2538_rf_radio_ops.c @@ -82,114 +82,189 @@ static int _write(ieee802154_dev_t *dev, const iolist_t *iolist) rfcore_poke_tx_fifo(0, pkt_len + CC2538_AUTOCRC_LEN); return 0; } - -static int _confirm_transmit(ieee802154_dev_t *dev, ieee802154_tx_info_t *info) +static int _request_op(ieee802154_dev_t *dev, ieee802154_hal_op_t op, void *ctx) { (void) dev; - + int res = -EBUSY; cc2538_rf_disable_irq(); - int res = -EAGAIN; - if (cc2538_state != CC2538_STATE_CONFIRM_TX) { - goto end; - } - - if (info) { - if (cc2538_csma_ca_retries >= 0 && RFCORE_XREG_CSPZ == 0) { - info->status = TX_STATUS_MEDIUM_BUSY; + switch (op) { + case IEEE802154_HAL_OP_TRANSMIT: + 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 + * controlled by the CPU or the CSP Strobe Processor. + * We set this to 1 in order to indicate that the CSP is not used and + * thus, that the @ref ieee802154_radio_confirm_transmit should + * return 0 immediately after the TXDONE event + */ + RFCORE_XREG_CSPCTRL |= CC2538_CSP_MCU_CTRL_MASK; } else { - info->status = TX_STATUS_SUCCESS; + /* Disable RX Chain for CCA (see CC2538 RM, Section 29.9.5.3) */ + _disable_rx(); + RFCORE_SFR_RFST = ISRXON; + /* Clear last program */ + RFCORE_SFR_RFST = ISCLEAR; + + /* If the RSSI is not yet valid, skip 0 instructions. This creates + * a busy loop until the RSSI is valid. */ + RFCORE_SFR_RFST = SKIP_S_C + | CC2538_CSP_SKIP_N_MASK + | CC2538_CSP_SKIP_COND_RSSI; + + /* Set a label right before the backoff */ + RFCORE_SFR_RFST = LABEL; + + /* Load a random number with "register Y" LSBs into register X. + * This is equivalent to choosing a random number between + * (0, 2^(Y+1)). + * Then, wait "register X" number of backoff units */ + RFCORE_SFR_RFST = RANDXY; + RFCORE_SFR_RFST = WAITX; + + /* If CCA is not valid, skip the next stop instruction. In such case + * the CSP_STOP interrupt will trigger the transmission since the + * channel is clear */ + RFCORE_SFR_RFST = SKIP_S_C + | (1 << CC2538_CSP_SKIP_INST_POS) + | CC2538_CSP_SKIP_N_MASK + | CC2538_CSP_SKIP_COND_CCA; + + RFCORE_SFR_RFST = STOP; + + /* If we are here, the channel was not clear. Decrement the register Z + * (remaining attempts) */ + RFCORE_SFR_RFST = DECZ; + + /* Update the backoff exponent */ + RFCORE_SFR_RFST = INCMAXY | (cc2538_max_be & CC2538_CSP_INCMAXY_MAX_MASK); + + /* If the are CSMA-CA retries left, go back to the defined label */ + RFCORE_SFR_RFST = RPT_C + | CC2538_CSP_SKIP_N_MASK + | CC2538_CSP_SKIP_COND_CSPZ; + + /* Stop the program. The CSP_STOP interrupt will trigger the routine + * to inform the upper layer that CSMA-CA failed. */ + RFCORE_SFR_RFST = STOP; + + RFCORE_XREG_CSPX = 0; /* Holds timer value */ + RFCORE_XREG_CSPY = cc2538_min_be; /* Holds MinBE */ + + assert(cc2538_csma_ca_retries >= 0); + RFCORE_XREG_CSPZ = cc2538_csma_ca_retries + 1; /* Holds CSMA-CA attempts (retries + 1) */ + + RFCORE_XREG_CSPCTRL &= ~CC2538_CSP_MCU_CTRL_MASK; + + /* Execute the program */ + RFCORE_SFR_RFST = ISSTART; } + cc2538_rf_enable_irq(); + break; + case IEEE802154_HAL_OP_SET_RX: + if (cc2538_state != CC2538_STATE_READY) { + goto error; + } + cc2538_state = CC2538_STATE_TRX_TRANSITION; + /* Enable RX Chain */ + _enable_rx(); + RFCORE_SFR_RFST = ISRXON; + RFCORE_SFR_RFIRQF0 &= ~RXPKTDONE; + RFCORE_SFR_RFIRQF0 &= ~SFD; + /* We keep the interrupts disabled until the state transition is + * finished */ + break; + case IEEE802154_HAL_OP_SET_IDLE: { + assert(ctx); + bool force = *((bool*) ctx); + + if (!force && cc2538_state != CC2538_STATE_READY) { + goto error; + } + + cc2538_state = CC2538_STATE_TRX_TRANSITION; + if (RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE != FSM_STATE_IDLE) { + RFCORE_SFR_RFST = ISRFOFF; + } + RFCORE_SFR_RFIRQF0 &= ~RXPKTDONE; + RFCORE_SFR_RFIRQF0 &= ~SFD; + /* We keep the interrupts disabled until the state transition is + * finished */ + break; + } + case IEEE802154_HAL_OP_CCA: + /* Ignore baseband processing */ + _disable_rx(); + RFCORE_SFR_RFIRQF0 &= ~RXPKTDONE; + RFCORE_SFR_RFIRQF0 &= ~SFD; + RFCORE_SFR_RFST = ISRXON; + RFCORE_SFR_RFST = ISCLEAR; + RFCORE_SFR_RFST = STOP; + RFCORE_XREG_CSPCTRL &= ~CC2538_CSP_MCU_CTRL_MASK; + /* Execute the last program */ + RFCORE_SFR_RFST = ISSTART; + cc2538_rf_enable_irq(); + break; + } + + res = 0; + return res; + +error: + cc2538_rf_enable_irq(); + return res; +} + +static int _confirm_op(ieee802154_dev_t *dev, ieee802154_hal_op_t op, void *ctx) +{ + int res = -EAGAIN; + (void) dev; + + switch (op) { + case IEEE802154_HAL_OP_TRANSMIT: + cc2538_rf_disable_irq(); + if (cc2538_state != CC2538_STATE_CONFIRM_TX) { + goto error; + } + + if (ctx) { + ieee802154_tx_info_t *info = ctx; + + if (cc2538_csma_ca_retries >= 0 && RFCORE_XREG_CSPZ == 0) { + info->status = TX_STATUS_MEDIUM_BUSY; + } + else { + info->status = TX_STATUS_SUCCESS; + } + } + break; + case IEEE802154_HAL_OP_SET_RX: + case IEEE802154_HAL_OP_SET_IDLE: + /* IRQ is already disabled here */ + assert(cc2538_state == CC2538_STATE_TRX_TRANSITION); + break; + case IEEE802154_HAL_OP_CCA: + assert(ctx); + cc2538_rf_disable_irq(); + assert(cc2538_state == CC2538_STATE_CCA || cc2538_state == CC2538_STATE_CONFIRM_CCA); + if (cc2538_state != CC2538_STATE_CONFIRM_CCA) { + goto error; + } + + _enable_rx(); + *((bool*) ctx) = cc2538_cca_status; + break; } cc2538_state = CC2538_STATE_READY; res = 0; -end: +error: cc2538_rf_enable_irq(); return res; -} -static int _request_transmit(ieee802154_dev_t *dev) -{ - (void) dev; - - 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 - * controlled by the CPU or the CSP Strobe Processor. - * We set this to 1 in order to indicate that the CSP is not used and - * thus, that the @ref ieee802154_radio_ops::confirm_transmit should - * return 0 immediately after the TXDONE event - */ - RFCORE_XREG_CSPCTRL |= CC2538_CSP_MCU_CTRL_MASK; - } - else { - /* Disable RX Chain for CCA (see CC2538 RM, Section 29.9.5.3) */ - _disable_rx(); - RFCORE_SFR_RFST = ISRXON; - /* Clear last program */ - RFCORE_SFR_RFST = ISCLEAR; - - /* If the RSSI is not yet valid, skip 0 instructions. This creates - * a busy loop until the RSSI is valid. */ - RFCORE_SFR_RFST = SKIP_S_C - | CC2538_CSP_SKIP_N_MASK - | CC2538_CSP_SKIP_COND_RSSI; - - /* Set a label right before the backoff */ - RFCORE_SFR_RFST = LABEL; - - /* Load a random number with "register Y" LSBs into register X. - * This is equivalent to choosing a random number between - * (0, 2^(Y+1)). - * Then, wait "register X" number of backoff units */ - RFCORE_SFR_RFST = RANDXY; - RFCORE_SFR_RFST = WAITX; - - /* If CCA is not valid, skip the next stop instruction. In such case - * the CSP_STOP interrupt will trigger the transmission since the - * channel is clear */ - RFCORE_SFR_RFST = SKIP_S_C - | (1 << CC2538_CSP_SKIP_INST_POS) - | CC2538_CSP_SKIP_N_MASK - | CC2538_CSP_SKIP_COND_CCA; - - RFCORE_SFR_RFST = STOP; - - /* If we are here, the channel was not clear. Decrement the register Z - * (remaining attempts) */ - RFCORE_SFR_RFST = DECZ; - - /* Update the backoff exponent */ - RFCORE_SFR_RFST = INCMAXY | (cc2538_max_be & CC2538_CSP_INCMAXY_MAX_MASK); - - /* If the are CSMA-CA retries left, go back to the defined label */ - RFCORE_SFR_RFST = RPT_C - | CC2538_CSP_SKIP_N_MASK - | CC2538_CSP_SKIP_COND_CSPZ; - - /* Stop the program. The CSP_STOP interrupt will trigger the routine - * to inform the upper layer that CSMA-CA failed. */ - RFCORE_SFR_RFST = STOP; - - RFCORE_XREG_CSPX = 0; /* Holds timer value */ - RFCORE_XREG_CSPY = cc2538_min_be; /* Holds MinBE */ - - assert(cc2538_csma_ca_retries >= 0); - RFCORE_XREG_CSPZ = cc2538_csma_ca_retries + 1; /* Holds CSMA-CA attempts (retries + 1) */ - - RFCORE_XREG_CSPCTRL &= ~CC2538_CSP_MCU_CTRL_MASK; - - /* Execute the program */ - RFCORE_SFR_RFST = ISSTART; - } - cc2538_rf_enable_irq(); - return 0; } static int _len(ieee802154_dev_t *dev) @@ -253,64 +328,12 @@ static int _read(ieee802154_dev_t *dev, void *buf, size_t size, ieee802154_rx_in } end: - /* 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(); - } + /* We don't need to enable RX chain here, since the upper layer already + * made sure the transceiver is in IDLE. We simply flush the RX buffer */ RFCORE_SFR_RFST = ISFLUSHRX; return res; } -static int _confirm_cca(ieee802154_dev_t *dev) -{ - (void) dev; - - int res = -EAGAIN; - cc2538_rf_disable_irq(); - assert(cc2538_state == CC2538_STATE_CCA || cc2538_state == CC2538_STATE_CONFIRM_CCA); - - 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) { - goto end; - } - - cc2538_state = CC2538_STATE_CCA; - - /* Ignore baseband processing */ - _disable_rx(); - - RFCORE_SFR_RFST = ISCLEAR; - RFCORE_SFR_RFST = STOP; - RFCORE_XREG_CSPCTRL &= ~CC2538_CSP_MCU_CTRL_MASK; - - /* Execute the last program */ - RFCORE_SFR_RFST = ISSTART; - -end: - cc2538_rf_enable_irq(); - return res; -} - static int _set_cca_threshold(ieee802154_dev_t *dev, int8_t threshold) { (void) dev; @@ -341,53 +364,6 @@ static int _config_phy(ieee802154_dev_t *dev, const ieee802154_phy_conf_t *conf) return 0; } -static int _confirm_set_trx_state(ieee802154_dev_t *dev) -{ - (void) dev; - assert(cc2538_state == CC2538_STATE_TRX_TRANSITION); - cc2538_state = CC2538_STATE_READY; - cc2538_rf_enable_irq(); - return 0; -} - -static int _request_set_trx_state(ieee802154_dev_t *dev, ieee802154_trx_state_t state) -{ - - (void) dev; - 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; - } - break; - case IEEE802154_TRX_STATE_RX_ON: - /* Enable RX Chain */ - _enable_rx(); - RFCORE_SFR_RFST = ISRXON; - break; - } - - RFCORE_SFR_RFIRQF0 &= ~RXPKTDONE; - RFCORE_SFR_RFIRQF0 &= ~SFD; - -end: - if (res < 0) { - cc2538_rf_enable_irq(); - } - - return res; -} - void cc2538_irq_handler(void) { uint_fast8_t flags_f0 = RFCORE_SFR_RFIRQF0; @@ -647,21 +623,16 @@ static const ieee802154_radio_ops_t cc2538_rf_ops = { | IEEE802154_CAP_IRQ_CCA_DONE | IEEE802154_CAP_IRQ_RX_START | IEEE802154_CAP_IRQ_TX_START - | IEEE802154_CAP_PHY_OQPSK | IEEE802154_CAP_RX_CONTINUOUS, .write = _write, .read = _read, - .request_transmit = _request_transmit, - .confirm_transmit = _confirm_transmit, .len = _len, .off = _off, .request_on = _request_on, .confirm_on = _confirm_on, - .request_set_trx_state = _request_set_trx_state, - .confirm_set_trx_state = _confirm_set_trx_state, - .request_cca = _request_cca, - .confirm_cca = _confirm_cca, + .request_op = _request_op, + .confirm_op = _confirm_op, .set_cca_threshold = _set_cca_threshold, .set_cca_mode = _set_cca_mode, .config_phy = _config_phy, diff --git a/cpu/native/include/socket_zep.h b/cpu/native/include/socket_zep.h index 034056d364..ac2a7edd2a 100644 --- a/cpu/native/include/socket_zep.h +++ b/cpu/native/include/socket_zep.h @@ -105,7 +105,7 @@ typedef struct { */ uint8_t addr_long[IEEE802154_LONG_ADDRESS_LEN]; ieee802154_filter_mode_t filter_mode; /**< frame filter mode */ - ieee802154_trx_state_t state; /**< radio state */ + bool rx; /**< whether the radio is listening for packets */ bool send_hello; /**< send HELLO packet on connect */ } socket_zep_t; diff --git a/cpu/native/socket_zep/socket_zep.c b/cpu/native/socket_zep/socket_zep.c index 47c458a298..37df65bd8f 100644 --- a/cpu/native/socket_zep/socket_zep.c +++ b/cpu/native/socket_zep/socket_zep.c @@ -239,7 +239,7 @@ static void _socket_isr(int fd, void *arg) DEBUG("socket_zep::_socket_isr: bytes on %d\n", fd); - if (zepdev->state == IEEE802154_TRX_STATE_RX_ON) { + if (zepdev->rx) { dev->cb(dev, IEEE802154_RADIO_INDICATION_RX_DONE); } else { /* discard frame */ @@ -319,19 +319,6 @@ static int _set_cca_mode(ieee802154_dev_t *dev, ieee802154_cca_mode_t mode) return 0; } -static int _request_cca(ieee802154_dev_t *dev) -{ - (void) dev; - return 0; -} - -static int _confirm_cca(ieee802154_dev_t *dev) -{ - (void) dev; - assert(false); - return 0; -} - static int _set_cca_threshold(ieee802154_dev_t *dev, int8_t threshold) { (void) dev; @@ -393,19 +380,6 @@ static int _set_frame_filter_mode(ieee802154_dev_t *dev, ieee802154_filter_mode_ return 0; } -static int _request_set_trx_state(ieee802154_dev_t *dev, ieee802154_trx_state_t state) -{ - socket_zep_t *zepdev = dev->priv; - zepdev->state = state; - return 0; -} - -static int _confirm_set_trx_state(ieee802154_dev_t *dev) -{ - (void) dev; - return 0; -} - static int _write(ieee802154_dev_t *dev, const iolist_t *iolist) { socket_zep_t *zepdev = dev->priv; @@ -584,6 +558,53 @@ out: return res; } +static int _request_op(ieee802154_dev_t *dev, ieee802154_hal_op_t op, void *ctx) +{ + socket_zep_t *zepdev = dev->priv; + int res = -ENOTSUP; + (void) ctx; + + switch (op) { + case IEEE802154_HAL_OP_TRANSMIT: + res = _request_transmit(dev); + break; + case IEEE802154_HAL_OP_SET_RX: + zepdev->rx = true; + res = 0; + break; + case IEEE802154_HAL_OP_SET_IDLE: + zepdev->rx = false; + res = 0; + break; + case IEEE802154_HAL_OP_CCA: + res = -ENOTSUP; + break; + } + + return res; +} + + +static int _confirm_op(ieee802154_dev_t *dev, ieee802154_hal_op_t op, void *ctx) +{ + int res = -EAGAIN; + switch (op) { + case IEEE802154_HAL_OP_TRANSMIT: + res = _confirm_transmit(dev, ctx); + break; + case IEEE802154_HAL_OP_SET_RX: + case IEEE802154_HAL_OP_SET_IDLE: + res = 0; + break; + case IEEE802154_HAL_OP_CCA: + /* This shouldn't happen! */ + assert(false); + break; + } + + return res; +} + static const ieee802154_radio_ops_t socket_zep_rf_ops = { .caps = IEEE802154_CAP_24_GHZ | IEEE802154_CAP_AUTO_CSMA @@ -594,16 +615,12 @@ static const ieee802154_radio_ops_t socket_zep_rf_ops = { .write = _write, .read = _read, - .request_transmit = _request_transmit, - .confirm_transmit = _confirm_transmit, + .request_op = _request_op, + .confirm_op = _confirm_op, .len = _len, .off = _off, .request_on = _request_on, .confirm_on = _confirm_on, - .request_set_trx_state = _request_set_trx_state, - .confirm_set_trx_state = _confirm_set_trx_state, - .request_cca = _request_cca, - .confirm_cca = _confirm_cca, .set_cca_threshold = _set_cca_threshold, .set_cca_mode = _set_cca_mode, .config_phy = _config_phy, diff --git a/cpu/nrf52/radio/nrf802154/nrf802154_radio.c b/cpu/nrf52/radio/nrf802154/nrf802154_radio.c index 559c4079ba..b31389b510 100644 --- a/cpu/nrf52/radio/nrf802154/nrf802154_radio.c +++ b/cpu/nrf52/radio/nrf802154/nrf802154_radio.c @@ -49,7 +49,7 @@ * and on TXREADY to TXSTART, without requiring to trigger the task manually. */ #define DEFAULT_SHORTS (RADIO_SHORTS_RXREADY_START_Msk | \ - RADIO_SHORTS_TXREADY_START_Msk); + RADIO_SHORTS_TXREADY_START_Msk) /** * @brief nrf52840 shortcuts for CCA on send @@ -62,7 +62,7 @@ RADIO_SHORTS_CCAIDLE_STOP_Msk | \ RADIO_SHORTS_CCAIDLE_TXEN_Msk | \ RADIO_SHORTS_CCABUSY_DISABLE_Msk | \ - RADIO_SHORTS_TXREADY_START_Msk); + RADIO_SHORTS_TXREADY_START_Msk) #define MAC_TIMER_CHAN_ACK (0U) /**< MAC timer channel for transmitting an ACK frame */ #define MAC_TIMER_CHAN_IFS (1U) /**< MAC timer channel for handling IFS logic */ @@ -174,44 +174,130 @@ static int _write(ieee802154_dev_t *dev, const iolist_t *iolist) return 0; } -static int _confirm_transmit(ieee802154_dev_t *dev, ieee802154_tx_info_t *info) +static void _disable(void) +{ + /* set device into DISABLED state */ + if (NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) { + NRF_RADIO->EVENTS_DISABLED = 0; + NRF_RADIO->TASKS_DISABLE = 1; + DEBUG("[nrf802154] Device state: DISABLED\n"); + } +} + +static void _disable_blocking(void) +{ + _disable(); + + /* This will take in worst case 21 us */ + while (NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) {}; +} + +static int _request_op(ieee802154_dev_t *dev, ieee802154_hal_op_t op, void *ctx) { (void) dev; - if (_state != STATE_IDLE - && _state != STATE_CCA_BUSY && NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) { + int res = -EBUSY; + int state; + + switch (op) { + case IEEE802154_HAL_OP_TRANSMIT: + if (cfg.ifs) { + goto end; + } + NRF_RADIO->SHORTS = cfg.cca_send ? CCA_SHORTS : DEFAULT_SHORTS; + NRF_RADIO->TASKS_TXEN = 1; + state = STATE_TX; + break; + case IEEE802154_HAL_OP_SET_RX: + if (_state != STATE_IDLE && _state != STATE_RX) { + goto end; + } + _disable_blocking(); + state = STATE_RX; + NRF_RADIO->PACKETPTR = (uint32_t) rxbuf; + NRF_RADIO->SHORTS = DEFAULT_SHORTS; + NRF_RADIO->TASKS_RXEN = 1; + break; + case IEEE802154_HAL_OP_SET_IDLE: { + assert(ctx); + bool force = *((bool*) ctx); + if (!force && _state != STATE_IDLE && _state != STATE_RX) { + goto end; + } + _disable_blocking(); + NRF_RADIO->SHORTS = DEFAULT_SHORTS; + NRF_RADIO->PACKETPTR = (uint32_t) txbuf; + state = STATE_IDLE; + break; + } + case IEEE802154_HAL_OP_CCA: + _disable_blocking(); + NRF_RADIO->SHORTS = RADIO_SHORTS_RXREADY_CCASTART_Msk; + NRF_RADIO->TASKS_RXEN = 1; + state = STATE_IDLE; + break; + default: + assert(false); + state = 0; + break; + } + + _state = state; + res = 0; + +end: + return res; +} + +static int _confirm_op(ieee802154_dev_t *dev, ieee802154_hal_op_t op, void *ctx) +{ + (void) dev; + bool eagain; + ieee802154_tx_info_t *info = NULL; + int state = _state; + bool enable_shorts = false; + int radio_state = NRF_RADIO->STATE; + switch (op) { + case IEEE802154_HAL_OP_TRANSMIT: + eagain = (state != STATE_IDLE + && state != STATE_CCA_BUSY && NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled); + + state = STATE_IDLE; + enable_shorts = true; + break; + case IEEE802154_HAL_OP_SET_RX: + eagain = (radio_state == RADIO_STATE_STATE_RxRu); + break; + case IEEE802154_HAL_OP_SET_IDLE: + eagain = (radio_state == RADIO_STATE_STATE_TxDisable || + radio_state == RADIO_STATE_STATE_RxDisable); + break; + case IEEE802154_HAL_OP_CCA: + eagain = (state != STATE_CCA_BUSY && state != STATE_CCA_CLEAR); + assert(ctx); + *((bool*) ctx) = (state == STATE_CCA_CLEAR) ? true : false; + state = STATE_IDLE; + break; + default: + eagain = false; + assert(false); + break; + } + + if (eagain) { return -EAGAIN; } + _state = state; + if (info) { info->status = (_state == STATE_CCA_BUSY) ? TX_STATUS_MEDIUM_BUSY : TX_STATUS_SUCCESS; } - _state = STATE_IDLE; - NRF_RADIO->SHORTS = DEFAULT_SHORTS; - DEBUG("[nrf802154] TX Finished\n"); - - return 0; -} - -static int _request_transmit(ieee802154_dev_t *dev) -{ - (void) dev; - if (cfg.ifs) { - return -EBUSY; + if (enable_shorts) { + NRF_RADIO->SHORTS = DEFAULT_SHORTS; + DEBUG("[nrf802154] TX Finished\n"); } - - _state = STATE_TX; - if (cfg.cca_send) { - DEBUG("[nrf802154] Transmit a frame using CCA\n"); - NRF_RADIO->SHORTS = CCA_SHORTS; - NRF_RADIO->TASKS_RXEN = 1; - } - else { - DEBUG("[nrf802154] Transmit a frame using Direct Transmission\n"); - NRF_RADIO->TASKS_TXEN = 1; - } - return 0; } @@ -256,44 +342,6 @@ static int _read(ieee802154_dev_t *dev, void *buf, size_t max_size, return pktlen; } -static int _confirm_cca(ieee802154_dev_t *dev) -{ - (void) dev; - int res; - - switch (_state) { - case STATE_CCA_CLEAR: - DEBUG("[nrf802154] Channel is clear\n"); - res = true; - break; - case STATE_CCA_BUSY: - DEBUG("[nrf802154] Channel is busy\n"); - res = false; - break; - default: - res = -EAGAIN; - } - - _state = STATE_RX; - return res; -} - -static int _request_cca(ieee802154_dev_t *dev) -{ - (void) dev; - - if (_state != STATE_RX) { - DEBUG("[nrf802154] CCA request fail: EBUSY\n"); - return -EBUSY; - } - - DEBUG("[nrf802154] CCA Requested\n"); - /* Go back to RxIdle state and start CCA */ - NRF_RADIO->TASKS_STOP = 1; - NRF_RADIO->TASKS_CCASTART = 1; - return 0; -} - /** * @brief Convert from dBm to the internal representation, when the * radio operates as a IEEE802.15.4 transceiver. @@ -350,16 +398,6 @@ static void _set_txpower(int16_t txpower) } } -static void _disable(void) -{ - /* set device into DISABLED state */ - if (NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) { - NRF_RADIO->EVENTS_DISABLED = 0; - NRF_RADIO->TASKS_DISABLE = 1; - DEBUG("[nrf802154] Device state: DISABLED\n"); - } -} - static void _set_ifs_timer(bool lifs) { uint8_t timeout; @@ -375,53 +413,6 @@ static void _set_ifs_timer(bool lifs) timer_start(NRF802154_TIMER); } -static int _confirm_set_trx_state(ieee802154_dev_t *dev) -{ - (void) dev; - int radio_state = NRF_RADIO->STATE; - if (radio_state == RADIO_STATE_STATE_TxRu || radio_state == RADIO_STATE_STATE_RxRu || - radio_state == RADIO_STATE_STATE_TxDisable || radio_state == RADIO_STATE_STATE_RxDisable) { - return -EAGAIN; - } - DEBUG("[nrf802154]: State transition finished\n"); - return 0; -} - -static int _request_set_trx_state(ieee802154_dev_t *dev, ieee802154_trx_state_t state) -{ - (void) dev; - - if (_state != STATE_IDLE && _state != STATE_RX) { - DEBUG("[nrf802154]: set_trx_state failed: -EBUSY\n"); - return -EBUSY; - } - - _disable(); - - /* This will take in worst case 21 us */ - while (NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) {}; - - switch (state) { - case IEEE802154_TRX_STATE_TRX_OFF: - _state = STATE_IDLE; - DEBUG("[nrf802154]: Request state to TRX_OFF\n"); - break; - case IEEE802154_TRX_STATE_RX_ON: - NRF_RADIO->PACKETPTR = (uint32_t)rxbuf; - NRF_RADIO->TASKS_RXEN = 1; - _state = STATE_RX; - DEBUG("[nrf802154]: Request state to RX_ON\n"); - break; - case IEEE802154_TRX_STATE_TX_ON: - NRF_RADIO->PACKETPTR = (uint32_t)txbuf; - _state = STATE_IDLE; - DEBUG("[nrf802154]: Request state to TX_ON\n"); - break; - } - - return 0; -} - static void _timer_cb(void *arg, int chan) { (void)arg; @@ -802,16 +793,12 @@ static const ieee802154_radio_ops_t nrf802154_ops = { .write = _write, .read = _read, - .request_transmit = _request_transmit, - .confirm_transmit = _confirm_transmit, - .len = _len, - .off = _off, .request_on = _request_on, .confirm_on = _confirm_on, - .request_set_trx_state = _request_set_trx_state, - .confirm_set_trx_state = _confirm_set_trx_state, - .request_cca = _request_cca, - .confirm_cca = _confirm_cca, + .len = _len, + .off = _off, + .request_op = _request_op, + .confirm_op = _confirm_op, .set_cca_threshold = set_cca_threshold, .set_cca_mode = _set_cca_mode, .config_phy = _config_phy, diff --git a/pkg/openwsn/contrib/radio_hal.c b/pkg/openwsn/contrib/radio_hal.c index b69aeddc38..d91f6ccd7e 100644 --- a/pkg/openwsn/contrib/radio_hal.c +++ b/pkg/openwsn/contrib/radio_hal.c @@ -90,23 +90,20 @@ static void _hal_radio_cb(ieee802154_dev_t *dev, ieee802154_trx_ev_t status) switch (status) { case IEEE802154_RADIO_CONFIRM_TX_DONE: ieee802154_radio_confirm_transmit(openwsn_radio.dev, NULL); - 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) {} + ieee802154_radio_request_set_idle(openwsn_radio.dev, true); + while (ieee802154_radio_confirm_set_idle(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) {} + ieee802154_radio_request_set_idle(openwsn_radio.dev, true); + while (ieee802154_radio_confirm_set_idle(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) {} + ieee802154_radio_request_set_idle(openwsn_radio.dev, true); + while (ieee802154_radio_confirm_set_idle(openwsn_radio.dev) == -EAGAIN) {} openwsn_radio.endFrame_cb(_txrx_event_capture_time); break; case IEEE802154_RADIO_INDICATION_TX_START: @@ -202,9 +199,8 @@ void radio_rfOn(void) /* If the radio is still not in TRX_OFF state, spin */ while (ieee802154_radio_confirm_on(openwsn_radio.dev) == -EAGAIN) {} /* HACK: cc2538 does not implement on() correctly, remove when it does*/ - 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) {} + ieee802154_radio_request_set_idle(openwsn_radio.dev, true); + while (ieee802154_radio_confirm_set_idle(openwsn_radio.dev) == -EAGAIN) {} } void radio_rfOff(void) @@ -212,18 +208,16 @@ void radio_rfOff(void) /* radio_rfOff is called in the middle of a slot and is not always followed by an `radio_rfOn`, so don't call `ieee802154_radio_off` and only send the radio to `TrxOFF` instead */ - int ret = ieee802154_radio_request_set_trx_state(openwsn_radio.dev, - IEEE802154_TRX_STATE_TRX_OFF); + int ret = ieee802154_radio_request_set_idle(openwsn_radio.dev, true); if (ret) { - LOG_ERROR("[openwsn/radio]: request_set_trx_state failed %s\n", + LOG_ERROR("[openwsn/radio]: request_set_idle failed %s\n", __FUNCTION__); } else { debugpins_radio_clr(); leds_radio_off(); - while (ieee802154_radio_confirm_set_trx_state(openwsn_radio.dev) == - -EAGAIN) {} + while (ieee802154_radio_confirm_set_idle(openwsn_radio.dev) == -EAGAIN) {} } } @@ -244,15 +238,14 @@ void radio_loadPacket(uint8_t *packet, uint16_t len) void radio_txEnable(void) { - int ret = ieee802154_radio_request_set_trx_state(openwsn_radio.dev, - IEEE802154_TRX_STATE_TX_ON); + int ret = ieee802154_radio_request_set_idle(openwsn_radio.dev, true); if (ret) { - LOG_ERROR("[openwsn/radio]: request_set_trx_state failed %s\n", + LOG_ERROR("[openwsn/radio]: request_set_idle failed %s\n", __FUNCTION__); } else { - while (ieee802154_radio_confirm_set_trx_state(openwsn_radio.dev) == + while (ieee802154_radio_confirm_set_idle(openwsn_radio.dev) == -EAGAIN) {} debugpins_radio_set(); leds_radio_on(); @@ -264,7 +257,7 @@ void radio_txNow(void) int ret = ieee802154_radio_request_transmit(openwsn_radio.dev); if (ret) { - LOG_ERROR("[openwsn/radio]: request_set_trx_state failed %s\n", + LOG_ERROR("[openwsn/radio]: request_transmit failed %s\n", __FUNCTION__); } else { @@ -280,15 +273,14 @@ void radio_txNow(void) void radio_rxEnable(void) { - int ret = ieee802154_radio_request_set_trx_state(openwsn_radio.dev, - IEEE802154_TRX_STATE_TRX_OFF); + int ret = ieee802154_radio_request_set_idle(openwsn_radio.dev, true); if (ret) { - LOG_ERROR("[openwsn/radio]: request_set_trx_state failed %s\n", + LOG_ERROR("[openwsn/radio]: request_set_idle failed %s\n", __FUNCTION__); } else { - while (ieee802154_radio_confirm_set_trx_state(openwsn_radio.dev) == + while (ieee802154_radio_confirm_set_idle(openwsn_radio.dev) == -EAGAIN) {} debugpins_radio_set(); leds_radio_on(); @@ -297,16 +289,14 @@ void radio_rxEnable(void) void radio_rxNow(void) { - int ret = ieee802154_radio_request_set_trx_state(openwsn_radio.dev, - IEEE802154_TRX_STATE_RX_ON); + int ret = ieee802154_radio_request_set_rx(openwsn_radio.dev); if (ret) { - LOG_ERROR("[openwsn/radio]: request_set_trx_state failed %s\n", + LOG_ERROR("[openwsn/radio]: request_set_rx failed %s\n", __FUNCTION__); } else { - while (ieee802154_radio_confirm_set_trx_state(openwsn_radio.dev) == - -EAGAIN) {} + while (ieee802154_radio_confirm_set_rx(openwsn_radio.dev) == -EAGAIN) {} } } diff --git a/sys/include/net/ieee802154/radio.h b/sys/include/net/ieee802154/radio.h index 5bb05cf7cc..3617df0344 100644 --- a/sys/include/net/ieee802154/radio.h +++ b/sys/include/net/ieee802154/radio.h @@ -33,6 +33,7 @@ extern "C" { #include "byteorder.h" #include "net/eui64.h" #include "net/ieee802154.h" +#include "errno.h" /** * @brief Forward declaration of the radio ops structure. @@ -50,7 +51,7 @@ typedef enum { * * The device supports sending with CSMA-CA and retransmissions. If the * CSMA-CA fails, the device reports a @ref TX_STATUS_MEDIUM_BUSY when - * calling @ref ieee802154_radio_ops::confirm_transmit. In case CSMA-CA + * calling @ref ieee802154_radio_confirm_transmit. In case CSMA-CA * succeeds and the ACK frame is expected, the * device reports a @ref TX_STATUS_SUCCESS if the ACK frame is received * during any retransmission attempt. Otherwise, it reports a @ref @@ -68,7 +69,7 @@ typedef enum { * The device supports performing CSMA-CA before transmitting a frame. If * CSMA-CA procedure succeeds, the device sends the frame and reports a * @ref TX_STATUS_SUCCESS when calling @ref - * ieee802154_radio_ops::confirm_transmit. If it fails, the device reports + * ieee802154_radio_confirm_transmit. If it fails, the device reports * @ref TX_STATUS_MEDIUM_BUSY. */ IEEE802154_CAP_AUTO_CSMA = BIT1, @@ -78,7 +79,7 @@ typedef enum { * The device will automatically attempt to receive and handle the ACK * frame if expected. * If the ACK frame is not received, the device reports @ref - * TX_STATUS_NO_ACK when calling @ref ieee802154_radio_ops::confirm_transmit. + * TX_STATUS_NO_ACK when calling @ref ieee802154_radio_confirm_transmit. * Otherwise, it reports @ref TX_STATUS_SUCCESS. * * The ACK frame is not indicated to the upper layer. @@ -220,24 +221,6 @@ typedef enum { TX_STATUS_MEDIUM_BUSY, } ieee802154_tx_status_t; -/** - * @brief IEEE802.15.4 transceiver states (not to confuse with device states) - */ -typedef enum { - /** - * @brief the transceiver state is off - */ - IEEE802154_TRX_STATE_TRX_OFF, - /** - * @brief the transceiver is ready to receive/receiving frames - */ - IEEE802154_TRX_STATE_RX_ON, - /** - * @brief the transceiver is ready to transmit/transmitting a frame - */ - IEEE802154_TRX_STATE_TX_ON, -} ieee802154_trx_state_t; - /** * @brief IEEE802.15.4 Radio HAL events * @@ -297,7 +280,7 @@ typedef enum { * * This event is present if radio has @ref IEEE802154_CAP_IRQ_TX_DONE cap. * The upper layer should immediately call @ref - * ieee802154_radio_ops::confirm_transmit when on this event. + * ieee802154_radio_confirm_transmit when on this event. */ IEEE802154_RADIO_CONFIRM_TX_DONE, /** @@ -483,6 +466,30 @@ typedef struct { int8_t pow; /**< TX power in dBm */ } ieee802154_phy_conf_t; +/** + * @brief IEEE 802.15.4 radio operations + */ +typedef enum { + /** + * @brief Transmission of a preloaded frame. + */ + IEEE802154_HAL_OP_TRANSMIT, + /** + * @brief Set the transceiver state to RX. + */ + IEEE802154_HAL_OP_SET_RX, + /** + * @brief Set the transceiver state to IDLE (RX off). + */ + IEEE802154_HAL_OP_SET_IDLE, + /** + * @brief Request Clear Channel Assessment + */ + IEEE802154_HAL_OP_CCA, + + /* add more as needed (e.g Energy Scanning, transmit slotted ACK) */ +} ieee802154_hal_op_t; + /** * @brief Radio ops struct declaration */ @@ -509,48 +516,6 @@ struct ieee802154_radio_ops { */ int (*write)(ieee802154_dev_t *dev, const iolist_t *psdu); - /** - * @brief Request the transmission of a preloaded frame - * - * @ref ieee802154_radio_ops::confirm_transmit MUST be used to finish the - * transmission. - * - * @pre the PHY state is @ref IEEE802154_TRX_STATE_TX_ON and the frame - * is already in the framebuffer. - * - * @param[in] dev IEEE802.15.4 device descriptor - * - * @return 0 on success - * @return negative errno on error - */ - int (*request_transmit)(ieee802154_dev_t *dev); - - /** - * @brief Confirmation function for @ref ieee802154_radio_ops::request_transmit. - * - * This function must be called to finish the transmission procedure and - * get the transmission status. This function should be called on @ref - * IEEE802154_RADIO_CONFIRM_TX_DONE. If no interrupt is available, this - * function can be polled. - * - * @pre the device is on - * @pre call to @ref ieee802154_radio_ops::request_transmit was successful. - * - * @post the state is @ref IEEE802154_TRX_STATE_TX_ON. - * - * @param[in] dev IEEE802.15.4 device descriptor - * @param[out] info the TX information. Pass NULL - * if the information is not needed. If the radio supports AutoCCA, the - * status should indicate transmission done or channel busy. If the radio - * supports frame retransmissions, the status should indicate if medium - * was busy, no ACK was received or transmission succeeded. - * - * @return 0 on success - * @return -EAGAIN if the transmission has not finished yet. - * @return negative errno on error - */ - int (*confirm_transmit)(ieee802154_dev_t *dev, ieee802154_tx_info_t *info); - /** * @brief Get the length of the received PSDU frame. * @@ -597,8 +562,7 @@ struct ieee802154_radio_ops { * * When this function returns, the radio shall be off. * - * @post the device is off (and thus, the transceiver state is @ref - * IEEE802154_TRX_STATE_TRX_OFF) + * @post the device is off * * @return 0 on success * @return negative errno on error @@ -625,7 +589,7 @@ struct ieee802154_radio_ops { * * @pre call to @ref ieee802154_radio_ops::request_on was successful. * - * @post the transceiver state is @ref IEEE802154_TRX_STATE_TRX_OFF + * @post the transceiver state is IDLE * During boot or in case the radio doesn't support @ref * IEEE802154_CAP_REG_RETENTION when @ref off was called, the * Physical Information Base will be undefined. Thus, take into @@ -649,74 +613,37 @@ struct ieee802154_radio_ops { int (*confirm_on)(ieee802154_dev_t *dev); /** - * @brief Request a PHY state change + * @brief Request a radio operation. * - * @note @ref ieee802154_radio_ops::confirm_set_trx_state MUST be used to - * finish the state transition. Also, setting the state to - * @ref IEEE802154_TRX_STATE_RX_ON flushes the RX FIFO. - * - * @pre the device is on + * This functions is used to request a radio operation. See @ref + * ieee802154_hal_op_t for a list of available operations. * * @param[in] dev IEEE802.15.4 device descriptor - * @param[in] state the new state + * @param[in] op operation to be executed + * @param[in] ctx operation specific context * - * @return 0 on success - * @return -EBUSY if the transceiver is busy - * @return negative number on error + * @return status of the request + * + * @retval 0 on success + * @retval negative errno on error */ - int (*request_set_trx_state)(ieee802154_dev_t *dev, - ieee802154_trx_state_t state); + int (*request_op)(ieee802154_dev_t *dev, ieee802154_hal_op_t op, void *ctx); /** - * @brief Confirmation function for @ref - * ieee802154_radio_ops::request_set_trx_state + * @brief Confirmation function for @ref ieee802154_radio_ops::request_op * - * @pre call to @ref ieee802154_radio_ops::request_set_trx_state was - * successful. + * This function must be called to finish a given @ref ieee802154_hal_op_t. * * @param[in] dev IEEE802.15.4 device descriptor + * @param[in] op operation to be confirmed + * @param[in] ctx operation specific context * - * @return 0 if the state transition was successful - * @return -EAGAIN if the transition has not finished yet - * @return negative errno on error + * @return status of the request + * + * @retval 0 on success + * @retval negative errno on error */ - int (*confirm_set_trx_state)(ieee802154_dev_t *dev); - - /** - * @brief Request Stand-Alone Clear Channel Assessment - * - * @pre the state is @ref IEEE802154_TRX_STATE_RX_ON - * - * @note @ref ieee802154_radio_ops::confirm_cca MUST be used to - * finish the CCA procedure and get the channel status. - * - * @param[in] dev IEEE802.15.4 device descriptor - * - * @post the state is @ref IEEE802154_TRX_STATE_RX_ON - * - * @return 0 if request was OK - * @return -EAGAIN if the request cannot be performed immediately. - * @return negative errno on error - */ - int (*request_cca)(ieee802154_dev_t *dev); - - /** - * @brief Confirmation function for @ref ieee802154_radio_ops::request_cca - * - * This function must be called to finish the CCA procedure. This - * function should be called on @ref IEEE802154_RADIO_CONFIRM_CCA, - * If no interrupt is available, this function can be polled. - * - * @pre call to @ref ieee802154_radio_ops::request_cca was successful. - * - * @param[in] dev IEEE802.15.4 device descriptor - * - * @return positive number if the channel is clear - * @return 0 if the channel is busy - * @return -EAGAIN if the CCA procedure hasn't finished. - * @return negative errno on error - */ - int (*confirm_cca)(ieee802154_dev_t *dev); + int (*confirm_op)(ieee802154_dev_t *dev, ieee802154_hal_op_t op, void *ctx); /** * @brief Set the threshold for the Energy Detection (first mode of CCA) @@ -757,7 +684,7 @@ struct ieee802154_radio_ops { * function should return -EINVAL * * @pre the device is on - * @pre the transceiver state is @ref IEEE802154_TRX_STATE_TRX_OFF + * @pre the transceiver state is IDLE. * * @param[in] dev IEEE802.15.4 device descriptor * @param[in] conf the PHY configuration @@ -795,7 +722,7 @@ struct ieee802154_radio_ops { * @param[in] retries number of CSMA-CA retries. If @p retries < 0, * retransmissions with CSMA-CA MUST be disabled. * If @p retries == 0, the @ref - * ieee802154_radio_ops::request_transmit function is + * ieee802154_radio_request_transmit function is * equivalent to CCA send. * * @return 0 on success @@ -871,29 +798,58 @@ static inline int ieee802154_radio_write(ieee802154_dev_t *dev, const iolist_t * } /** - * @brief Shortcut to @ref ieee802154_radio_ops::request_transmit + * @brief Transmit a preloaded frame * - * @param[in] dev IEEE802.15.4 device descriptor + * This functions calls ieee802154_radio_ops::request_op with @ref + * IEEE802154_HAL_OP_TRANSMIT and NULL context. * - * @return result of @ref ieee802154_radio_ops::request_transmit + * @pre The upper layer should have called set the transceiver to IDLE (see + * @ref ieee802154_radio_set_idle) and the frame is already in the framebuffer + * (@ref ieee802154_radio_ops_t::write). + * @pre the device is on + * + * @note @ref ieee802154_radio_confirm_transmit MUST be used to + * finish the transmission. + * + * @return result of @ref ieee802154_radio_request_transmit + * + * @retval 0 on success + * @retval negative errno on error */ static inline int ieee802154_radio_request_transmit(ieee802154_dev_t *dev) { - return dev->driver->request_transmit(dev); + return dev->driver->request_op(dev, IEEE802154_HAL_OP_TRANSMIT, NULL); } /** - * @brief Shortcut to @ref ieee802154_radio_ops::confirm_transmit + * @brief Confirmation function for @ref ieee802154_radio_request_transmit + * This function must be called to finish the transmission procedure and + * get the transmission status. This function should be called on @ref + * IEEE802154_RADIO_CONFIRM_TX_DONE. If no interrupt is available, this + * function can be polled. + * + * This functions calls ieee802154_radio_ops::confirm_op with @ref + * IEEE802154_HAL_OP_TRANSMIT and sets the context to @p info. + * + * @pre the device is on + * @pre call to @ref ieee802154_radio_request_transmit was successful. * * @param[in] dev IEEE802.15.4 device descriptor - * @param[out] info the TX information + * @param[out] info the TX information. Pass NULL + * if the information is not needed. If the radio supports AutoCCA, the + * status should indicate transmission done or channel busy. If the radio + * supports frame retransmissions, the status should indicate if medium + * was busy, no ACK was received or transmission succeeded. * - * @return result of @ref ieee802154_radio_ops::confirm_transmit + * @retval whether the transmission finished or not + * + * @return 0 if the transmission finished + * @return -EAGAIN otherwise */ static inline int ieee802154_radio_confirm_transmit(ieee802154_dev_t *dev, ieee802154_tx_info_t *info) { - return dev->driver->confirm_transmit(dev, info); + return dev->driver->confirm_op(dev, IEEE802154_HAL_OP_TRANSMIT, info); } /** @@ -958,7 +914,7 @@ static inline int ieee802154_radio_set_cca_mode(ieee802154_dev_t *dev, /** * @brief Shortcut to @ref ieee802154_radio_ops::config_phy * - * @pre the transceiver state is @ref IEEE802154_TRX_STATE_TRX_OFF + * @pre the transceiver state is IDLE. * * @param[in] dev IEEE802.15.4 device descriptor * @param[in] conf the PHY configuration @@ -994,7 +950,7 @@ static inline int ieee802154_radio_config_src_address_match(ieee802154_dev_t *de * * @param[in] dev IEEE802.15.4 device descriptor * - * @post the transceiver state is @ref IEEE802154_TRX_STATE_TRX_OFF + * @post the transceiver state is IDLE. * * @return result of @ref ieee802154_radio_ops::off */ @@ -1101,53 +1057,226 @@ static inline int ieee802154_radio_confirm_on(ieee802154_dev_t *dev) } /** - * @brief Shortcut to @ref ieee802154_radio_ops::request_set_trx_state + * @brief Request the transceiver state to IDLE. + * + * During IDLE, the radio won't be able to receive frames but it's still + * responsive to other HAL functions. + * + * This functions calls ieee802154_radio_ops::request_op with @ref + * IEEE802154_HAL_OP_SET_IDLE and sets the context to @p force + * + * @pre the device is on + * + * @note @ref ieee802154_radio_confirm_set_idle MUST be used to + * finish the state transition. * * @param[in] dev IEEE802.15.4 device descriptor - * @param[in] state the new state + * @param[in] force whether the state transition should be forced or not. If + * forced, the transceiver aborts any ongoing operation. * - * @return result of @ref ieee802154_radio_ops::request_set_trx_state + * @return status of the request + * + * @retval 0 on success + * @retval negative errno on error */ -static inline int ieee802154_radio_request_set_trx_state(ieee802154_dev_t *dev, - ieee802154_trx_state_t state) +static inline int ieee802154_radio_request_set_idle(ieee802154_dev_t *dev, bool force) { - return dev->driver->request_set_trx_state(dev, state); + return dev->driver->request_op(dev, IEEE802154_HAL_OP_SET_IDLE, &force); } /** - * @brief Shortcut to @ref ieee802154_radio_ops::confirm_set_trx_state + * @brief Confirmation function for @ref ieee802154_radio_request_set_idle + * + * @pre call to @ref ieee802154_radio_request_set_idle was successful. + * @pre the device is on * * @param[in] dev IEEE802.15.4 device descriptor * - * @return result of @ref ieee802154_radio_ops::confirm_set_trx_state + * @return whether the state transition finished or not + * + * @return 0 if the transition finished + * @return -EAGAIN otherwise. */ -static inline int ieee802154_radio_confirm_set_trx_state(ieee802154_dev_t *dev) +static inline int ieee802154_radio_confirm_set_idle(ieee802154_dev_t *dev) { - return dev->driver->confirm_set_trx_state(dev); + return dev->driver->confirm_op(dev, IEEE802154_HAL_OP_SET_IDLE, NULL); } /** - * @brief Shortcut to @ref ieee802154_radio_ops::request_cca + * @brief Request the transceiver state to RX. + * + * During RX, the radio will listen to incoming frames + * + * This functions calls ieee802154_radio_ops::request_op with @ref + * IEEE802154_HAL_OP_SET_RX and NULL context. + * + * @pre the device is on + * + * @note @ref ieee802154_radio_confirm_set_rx MUST be used to + * finish the state transition. * * @param[in] dev IEEE802.15.4 device descriptor * - * @return result of @ref ieee802154_radio_ops::request_cca + * @return status of the request + * + * @retval 0 on success + * @retval negative errno on error + */ +static inline int ieee802154_radio_request_set_rx(ieee802154_dev_t *dev) +{ + return dev->driver->request_op(dev, IEEE802154_HAL_OP_SET_RX, NULL); +} + +/** + * @brief Confirmation function for @ref ieee802154_radio_request_set_rx + * + * @pre call to @ref ieee802154_radio_request_set_rx was successful. + * @pre the device is on + * + * @param[in] dev IEEE802.15.4 device descriptor + * + * @return whether the state transition finished or not + * + * @return 0 if the transition finished + * @return -EAGAIN otherwise. + */ +static inline int ieee802154_radio_confirm_set_rx(ieee802154_dev_t *dev) +{ + return dev->driver->confirm_op(dev, IEEE802154_HAL_OP_SET_RX, NULL); +} + +/** + * @brief Set transceiver state to IDLE (blocking) + * + * This function will internally call @ref ieee802154_radio_request_set_idle + * and poll @ref ieee802154_radio_confirm_set_idle. + * + * @pre the device is on + * + * @param[in] dev IEEE802.15.4 device descriptor + * @param[in] force whether the state transition should be forced or not. If + * forced, the transceiver aborts any ongoing operation. + * + * @return result of the state transition + * + * @retval 0 on success + * @retval negative errno on error + */ +static inline int ieee802154_radio_set_idle(ieee802154_dev_t *dev, bool force) +{ + int res = ieee802154_radio_request_set_idle(dev, force); + if (res < 0) { + return res; + } + while (ieee802154_radio_confirm_set_idle(dev) == -EAGAIN) {} + + return 0; +} + +/** + * @brief Set transceiver state to RX (blocking) + * + * This function will internally call @ref ieee802154_radio_request_set_rx + * and poll @ref ieee802154_radio_confirm_set_rx. + * + * @pre the device is on + * + * @param[in] dev IEEE802.15.4 device descriptor + * + * @return result of the state transition + * + * @retval 0 on success + * @retval negative errno on error + */ +static inline int ieee802154_radio_set_rx(ieee802154_dev_t *dev) +{ + int res = ieee802154_radio_request_set_rx(dev); + if (res < 0) { + return res; + } + while (ieee802154_radio_confirm_set_rx(dev) == -EAGAIN) {} + + return 0; +} + +/** + * @brief Request Stand-Alone Clear Channel Assessment + * + * This functions calls ieee802154_radio_ops::request_op with @ref + * IEEE802154_HAL_OP_CCA and NULL context. + * + * @pre the device is on + * + * @note @ref ieee802154_radio_confirm_cca MUST be used to + * finish the CCA procedure and get the channel status. + * + * @param[in] dev IEEE802.15.4 device descriptor + * + * @return 0 on success + * @return negative errno on error */ static inline int ieee802154_radio_request_cca(ieee802154_dev_t *dev) { - return dev->driver->request_cca(dev); + return dev->driver->request_op(dev, IEEE802154_HAL_OP_CCA, NULL); } /** - * @brief Shortcut to @ref ieee802154_radio_ops::confirm_cca + * @brief Shortcut to @ref ieee802154_radio_confirm_cca + * + * This function must be called to finish the CCA procedure. This + * function should be called on @ref IEEE802154_RADIO_CONFIRM_CCA, + * If no interrupt is available, this function can be polled. + * + * This functions calls ieee802154_radio_ops::request_op with @ref + * IEEE802154_HAL_OP_CCA and sets the context to a boolean where the result + * of the CCA should be store. Setting it to true means the channel is clear. + * + * @pre call to @ref ieee802154_radio_request_cca was successful. + * @pre the device is on * * @param[in] dev IEEE802.15.4 device descriptor * - * @return result of @ref ieee802154_radio_ops::confirm_cca + * @return status of the CCA procedure + * + * @retval positive number if the channel is clear + * @retval 0 if the channel is busy + * @retval -EAGAIN if the CCA procedure hasn't finished. */ static inline int ieee802154_radio_confirm_cca(ieee802154_dev_t *dev) { - return dev->driver->confirm_cca(dev); + bool clear; + int res = dev->driver->confirm_op(dev, IEEE802154_HAL_OP_CCA, &clear); + if (res < 0) { + return res; + } + return clear; +} + +/** + * @brief Perform a Clear Channel Assessment (blocking) + * + * This function will internally call @ref ieee802154_radio_request_cca + * and poll @ref ieee802154_radio_confirm_cca. + * + * @pre the device is on + * + * @param[in] dev IEEE802.15.4 device descriptor + * + * @return status of the CCA + * + * @retval positive number if the channel is clear + * @retval 0 if the channel is busy + * @retval negative errno on error + */ +static inline int ieee802154_radio_cca(ieee802154_dev_t *dev) +{ + int res = ieee802154_radio_request_cca(dev); + if (res < 0) { + return res; + } + while (ieee802154_radio_confirm_cca(dev) == -EAGAIN) {} + + return 0; } /** diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index fc483c0064..9f95b7aad9 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -50,23 +50,6 @@ static char *str_ev[IEEE802154_FSM_EV_NUMOF] = { "REQUEST_SET_IDLE", }; -static inline void _req_set_trx_state_wait_busy(ieee802154_dev_t *dev, - ieee802154_trx_state_t state) -{ - int res; - - /* Some radios will run some house keeping tasks on event suchs as RX_DONE - * (e.g sending ACK frames) or TX_DONE. In such case we need to wait until - * the radio is not busy. - */ - do { - res = ieee802154_radio_request_set_trx_state(dev, state); - } while (res == -EBUSY); - - while (ieee802154_radio_confirm_set_trx_state(dev) == -EAGAIN) {} - assert(res >= 0); -} - static inline bool _does_handle_ack(ieee802154_dev_t *dev) { return ieee802154_radio_has_frame_retrans(dev) || @@ -87,8 +70,16 @@ static bool _has_retrans_left(ieee802154_submac_t *submac) static ieee802154_fsm_state_t _tx_end(ieee802154_submac_t *submac, int status, ieee802154_tx_info_t *info) { + int res; + + /* This is required to prevent unused variable warnings */ + (void) res; + submac->wait_for_ack = false; - _req_set_trx_state_wait_busy(&submac->dev, IEEE802154_TRX_STATE_TRX_OFF); + + res = ieee802154_radio_set_idle(&submac->dev, true); + + assert(res >= 0); submac->cb->tx_done(submac, status, info); return IEEE802154_FSM_STATE_IDLE; } @@ -101,11 +92,17 @@ static void _print_debug(ieee802154_fsm_state_t old, ieee802154_fsm_state_t new, static ieee802154_fsm_state_t _handle_tx_no_ack(ieee802154_submac_t *submac) { + int res; + + /* This is required to prevent unused variable warnings */ + (void) res; + /* In case of ACK Timeout, either trigger retransmissions or end * the TX procedure */ if (_has_retrans_left(submac)) { submac->retrans++; - _req_set_trx_state_wait_busy(&submac->dev, IEEE802154_TRX_STATE_TX_ON); + res = ieee802154_radio_set_idle(&submac->dev, true); + assert(res >= 0); ieee802154_submac_bh_request(submac); return IEEE802154_FSM_STATE_PREPARE; } @@ -120,13 +117,12 @@ static int _handle_fsm_ev_request_tx(ieee802154_submac_t *submac) ieee802154_dev_t *dev = &submac->dev; /* Set state to TX_ON */ - int res = ieee802154_radio_request_set_trx_state(dev, IEEE802154_TRX_STATE_TX_ON); + int res = ieee802154_radio_set_idle(dev, false); if (res < 0) { return res; } else { - while (ieee802154_radio_confirm_set_trx_state(dev) == -EAGAIN) {} /* write frame to radio */ ieee802154_radio_write(dev, submac->psdu); ieee802154_submac_bh_request(submac); @@ -137,6 +133,10 @@ static int _handle_fsm_ev_request_tx(ieee802154_submac_t *submac) static ieee802154_fsm_state_t _fsm_state_rx(ieee802154_submac_t *submac, ieee802154_fsm_ev_t ev) { ieee802154_dev_t *dev = &submac->dev; + int res; + + /* This is required to prevent unused variable warnings */ + (void) res; switch (ev) { case IEEE802154_FSM_EV_REQUEST_TX: @@ -146,8 +146,8 @@ static ieee802154_fsm_state_t _fsm_state_rx(ieee802154_submac_t *submac, ieee802 return IEEE802154_FSM_STATE_PREPARE; case IEEE802154_FSM_EV_RX_DONE: /* Make sure it's not an ACK frame */ + while (ieee802154_radio_set_idle(&submac->dev, false) < 0) {} if (ieee802154_radio_len(&submac->dev) > (int)IEEE802154_MIN_FRAME_LEN) { - _req_set_trx_state_wait_busy(&submac->dev, IEEE802154_TRX_STATE_TRX_OFF); submac->cb->rx_done(submac); return IEEE802154_FSM_STATE_IDLE; } @@ -155,29 +155,28 @@ static ieee802154_fsm_state_t _fsm_state_rx(ieee802154_submac_t *submac, ieee802 ieee802154_radio_read(&submac->dev, NULL, 0, NULL); /* If the radio doesn't support RX Continuous, go to RX */ - if (!ieee802154_radio_has_rx_continuous(&submac->dev)) { - _req_set_trx_state_wait_busy(&submac->dev, IEEE802154_TRX_STATE_RX_ON); - } + res = ieee802154_radio_set_rx(&submac->dev); + assert(res >= 0); /* Keep on current state */ return IEEE802154_FSM_STATE_RX; } case IEEE802154_FSM_EV_CRC_ERROR: + while (ieee802154_radio_set_idle(&submac->dev, false) < 0) {} ieee802154_radio_read(&submac->dev, NULL, 0, NULL); /* If the radio doesn't support RX Continuous, go to RX */ - if (!ieee802154_radio_has_rx_continuous(&submac->dev)) { - _req_set_trx_state_wait_busy(&submac->dev, IEEE802154_TRX_STATE_RX_ON); - } + res = ieee802154_radio_set_rx(&submac->dev); + assert(res >= 0); /* Keep on current state */ return IEEE802154_FSM_STATE_RX; case IEEE802154_FSM_EV_REQUEST_SET_IDLE: /* Try to turn off the transceiver */ - if ((ieee802154_radio_request_set_trx_state(dev, IEEE802154_TRX_STATE_TRX_OFF)) < 0) { + if ((ieee802154_radio_request_set_idle(dev, false)) < 0) { /* Keep on current state */ return IEEE802154_FSM_STATE_RX; } - while (ieee802154_radio_confirm_set_trx_state(dev) == -EAGAIN) {} + while (ieee802154_radio_confirm_set_idle(dev) == -EAGAIN) {} return IEEE802154_FSM_STATE_IDLE; default: @@ -199,11 +198,10 @@ static ieee802154_fsm_state_t _fsm_state_idle(ieee802154_submac_t *submac, ieee8 return IEEE802154_FSM_STATE_PREPARE; case IEEE802154_FSM_EV_REQUEST_SET_RX_ON: /* Try to go turn on the transceiver */ - if ((ieee802154_radio_request_set_trx_state(dev, IEEE802154_TRX_STATE_RX_ON)) < 0) { + if ((ieee802154_radio_set_rx(dev) < 0)) { /* Keep on current state */ return IEEE802154_FSM_STATE_IDLE; } - while (ieee802154_radio_confirm_set_trx_state(dev) == -EAGAIN) {} return IEEE802154_FSM_STATE_RX; case IEEE802154_FSM_EV_RX_DONE: case IEEE802154_FSM_EV_CRC_ERROR: @@ -260,6 +258,10 @@ static ieee802154_fsm_state_t _fsm_state_tx_process_tx_done(ieee802154_submac_t ieee802154_tx_info_t *info) { ieee802154_dev_t *dev = &submac->dev; + int res; + + /* This is required to prevent unused variable warnings */ + (void) res; switch (info->status) { case TX_STATUS_FRAME_PENDING: @@ -276,7 +278,8 @@ static ieee802154_fsm_state_t _fsm_state_tx_process_tx_done(ieee802154_submac_t * and enable the ACK filter */ else { ieee802154_radio_set_frame_filter_mode(dev, IEEE802154_FILTER_ACK_ONLY); - _req_set_trx_state_wait_busy(dev, IEEE802154_TRX_STATE_RX_ON); + res = ieee802154_radio_set_rx(dev); + assert (res >= 0); /* Handle ACK reception */ ieee802154_submac_ack_timer_set(submac, ACK_TIMEOUT_US); @@ -310,13 +313,15 @@ static ieee802154_fsm_state_t _fsm_state_tx_process_tx_done(ieee802154_submac_t static ieee802154_fsm_state_t _fsm_state_tx(ieee802154_submac_t *submac, ieee802154_fsm_ev_t ev) { - int res; ieee802154_tx_info_t info; + int res; + + /* This is required to prevent unused variable warnings */ + (void) res; switch (ev) { case IEEE802154_FSM_EV_TX_DONE: res = ieee802154_radio_confirm_transmit(&submac->dev, &info); - (void)res; assert(res >= 0); return _fsm_state_tx_process_tx_done(submac, &info); case IEEE802154_FSM_EV_RX_DONE: @@ -505,7 +510,7 @@ int ieee802154_submac_init(ieee802154_submac_t *submac, const network_uint16_t * CONFIG_IEEE802154_CCA_THRESH_DEFAULT); assert(res >= 0); - _req_set_trx_state_wait_busy(dev, IEEE802154_TRX_STATE_RX_ON); + while (ieee802154_radio_set_rx(dev) < 0) {} return res; } @@ -529,7 +534,7 @@ int ieee802154_set_phy_conf(ieee802154_submac_t *submac, uint16_t channel_num, /* If the radio is listening, turn it off first */ if (current_state == IEEE802154_FSM_STATE_RX) { - if ((res = ieee802154_radio_request_set_trx_state(dev, IEEE802154_TRX_STATE_TRX_OFF)) < 0) { + if ((res = ieee802154_radio_request_set_idle(dev, false)) < 0) { return res; } } @@ -541,11 +546,12 @@ int ieee802154_set_phy_conf(ieee802154_submac_t *submac, uint16_t channel_num, submac->channel_page = channel_page; submac->tx_pow = tx_pow; } - while (ieee802154_radio_confirm_set_trx_state(dev) == -EAGAIN) {} + while (ieee802154_radio_confirm_set_idle(dev) == -EAGAIN) {} /* Go back to RX if needed */ if (current_state == IEEE802154_FSM_STATE_RX) { - _req_set_trx_state_wait_busy(dev, IEEE802154_TRX_STATE_RX_ON); + res = ieee802154_radio_set_rx(dev); + assert (res >= 0); } return res; diff --git a/tests/ieee802154_hal/main.c b/tests/ieee802154_hal/main.c index 5c32aecac7..bc7e5f95ae 100644 --- a/tests/ieee802154_hal/main.c +++ b/tests/ieee802154_hal/main.c @@ -39,16 +39,24 @@ #define SYMBOL_TIME (16U) /**< 16 us */ #define ACK_TIMEOUT_TIME (40 * SYMBOL_TIME) +#define TX_RX_TURNAROUND (12 * SYMBOL_TIME) + +/* the CC2538 takes 193 us to put the transceiver in RX_ON, which officially + * violates the official TX<->RX turnaround time (192 us for O-QPSK). + * However, the radio is able to pick up the preamble of a frame even if the + * first symbol is lost. We add a tolerance of half a symbol to the + * TX_RX_TURNAROUND in order to be sure the TX<->RX measurement test doesn't + * fail + */ +#define MAX_TX_RX_TURNAROUND (TX_RX_TURNAROUND + (SYMBOL_TIME >> 1)) + #define IEEE802154_LONG_ADDRESS_LEN_STR_MAX \ (sizeof("00:00:00:00:00:00:00:00")) -static inline void _set_trx_state(int state, bool verbose); - static uint8_t buffer[127]; static xtimer_t timer_ack; static mutex_t lock; -static const char *str_states[3]= {"TRX_OFF", "RX", "TX"}; static eui64_t ext_addr; static network_uint16_t short_addr; static uint8_t seq; @@ -105,10 +113,13 @@ void _crc_error_handler(event_t *event) (void) event; puts("Frame with invalid CRC received"); ieee802154_dev_t* dev = &_radio[0]; - if (!ieee802154_radio_has_rx_continuous(dev)) { - /* switch back to RX_ON state */ - _set_trx_state(IEEE802154_TRX_STATE_RX_ON, false); - } + /* Force transition to IDLE before calling the read function */ + ieee802154_radio_set_idle(dev, true); + + /* We are not interested in the content of the frame */ + ieee802154_radio_read(dev, NULL, 0, NULL); + + ieee802154_radio_set_rx(dev); } static event_t _crc_error_event = { @@ -121,6 +132,9 @@ void _rx_done_handler(event_t *event) ieee802154_rx_info_t info; ieee802154_dev_t* dev = &_radio[0]; + /* Force transition to IDLE before calling the read function */ + ieee802154_radio_set_idle(dev, true); + /* Read packet from internal framebuffer * * NOTE: It's possible to call `ieee802154_radio_len` to retrieve the packet @@ -132,10 +146,7 @@ void _rx_done_handler(event_t *event) _print_packet(size, info.lqi, info.rssi); } - if (!ieee802154_radio_has_rx_continuous(dev)) { - /* switch back to RX_ON state */ - _set_trx_state(IEEE802154_TRX_STATE_RX_ON, false); - } + ieee802154_radio_set_rx(dev); } static event_t _rx_done_event = { @@ -172,7 +183,7 @@ static void _tx_finish_handler(event_t *event) if (!ieee802154_radio_has_irq_ack_timeout(&_radio[0]) && !ieee802154_radio_has_frame_retrans(&_radio[0])) { /* This is just to show how the MAC layer would handle ACKs... */ - _set_trx_state(IEEE802154_TRX_STATE_RX_ON, false); + ieee802154_radio_set_rx(&_radio[0]); xtimer_set(&timer_ack, ACK_TIMEOUT_TIME); } @@ -206,17 +217,17 @@ static event_t _tx_finish_ev = { static void _send(iolist_t *pkt) { - /* Request a state change to TX_ON */ - if (ieee802154_radio_request_set_trx_state(&_radio[0], IEEE802154_TRX_STATE_TX_ON) < 0) { + /* Request a state change to IDLE */ + if (ieee802154_radio_request_set_idle(&_radio[0], false) < 0) { puts("Couldn't send frame"); return; } - /* Write the packet to the radio */ + /* Write the packet to the radio while the radio is transitioning to IDLE */ ieee802154_radio_write(&_radio[0], pkt); /* Block until the radio confirms the state change */ - while(ieee802154_radio_confirm_set_trx_state(&_radio[0]) == -EAGAIN); + while(ieee802154_radio_confirm_set_idle(&_radio[0]) == -EAGAIN); /* Set the frame filter to receive ACKs */ ieee802154_radio_set_frame_filter_mode(&_radio[0], IEEE802154_FILTER_ACK_ONLY); @@ -312,7 +323,7 @@ static int _init(void) expect(res >= 0); /* Set the transceiver state to RX_ON in order to receive packets */ - _set_trx_state(IEEE802154_TRX_STATE_RX_ON, false); + ieee802154_radio_set_rx(&_radio[0]); return 0; } @@ -379,56 +390,37 @@ int _cca(int argc, char **argv) return 0; } -static inline void _set_trx_state(int state, bool verbose) -{ - xtimer_ticks32_t a; - int res; - - /* Under certain conditions (internal house-keeping or sending ACK frames - * back) the radio could indicate it's busy. Therefore, busy loop until - * the radio doesn't report BUSY - */ - while((res = ieee802154_radio_request_set_trx_state(&_radio[0], state)) == -EBUSY) {} - - if (verbose) { - a = xtimer_now(); - if(res != 0) { - printf("%i != 0 \n", res); - expect(false); - } - } - - while ((res = ieee802154_radio_confirm_set_trx_state(&_radio[0])) == -EAGAIN) {} - if (verbose) { - if (res != 0) { - printf("%i != 0 \n", res); - expect(false); - } - uint32_t secs = xtimer_usec_from_ticks(xtimer_diff(xtimer_now(), a)); - printf("\tTransition took %" PRIu32 " usecs\n", secs); - } -} - int _test_states(int argc, char **argv) { (void) argc; (void) argv; - for (int i=0; i<3;i++) { - printf("Setting state to: %s\n", str_states[i]); - _set_trx_state(i, true); - for (int j=0; j<3; j++) { - if (i == j) { - continue; - } - printf("%s-> %s\n", str_states[i], str_states[j]); - _set_trx_state(j, true); - printf("%s-> %s\n", str_states[j], str_states[i]); - _set_trx_state(i, true); - } - puts(""); - } + uint32_t usecs; + int res; + xtimer_ticks32_t a; - _set_trx_state(IEEE802154_TRX_STATE_RX_ON, true); + /* Force transition to IDLE */ + res = ieee802154_radio_set_idle(&_radio[0], true); + assert(res == 0); + + printf("Testing TX<->RX transition time: "); + a = xtimer_now(); + res = ieee802154_radio_set_rx(&_radio[0]); + assert(res == 0); + usecs = xtimer_usec_from_ticks(xtimer_diff(xtimer_now(), a)); + printf("%" PRIu32 " us (%s)\n", usecs, usecs > MAX_TX_RX_TURNAROUND + ? "FAIL" + : "PASS"); + + printf("Testing RX<->TX transition time"); + a = xtimer_now(); + res = ieee802154_radio_set_idle(&_radio[0], true); + assert(res == 0); + usecs = xtimer_usec_from_ticks(xtimer_diff(xtimer_now(), a)); + printf("%" PRIu32 " us (%s)\n", usecs, usecs > MAX_TX_RX_TURNAROUND + ? "FAIL" + : "PASS"); + + ieee802154_radio_set_rx(&_radio[0]); return 0; } @@ -518,8 +510,9 @@ int config_phy(int argc, char **argv) puts("Wrong channel configuration (11 <= channel <= 26)."); return 1; } - _set_trx_state(IEEE802154_TRX_STATE_TRX_OFF, false); + ieee802154_dev_t *dev = &_radio[0]; + ieee802154_radio_set_idle(dev, true); ieee802154_phy_conf_t conf = {.phy_mode=phy_mode, .channel=channel, .page=0, .pow=tx_pow}; if (ieee802154_radio_config_phy(dev, &conf) < 0) { puts("Channel or TX power settings not supported"); @@ -529,7 +522,7 @@ int config_phy(int argc, char **argv) res = 0; } - _set_trx_state(IEEE802154_TRX_STATE_RX_ON, false); + ieee802154_radio_set_rx(dev); return res; }