1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 05:12:57 +01:00

ieee802154/hal: migrate to request_op and confirm_op

This commit is contained in:
Jose Alamos 2021-09-28 13:15:29 +02:00
parent f33b3ad10d
commit db815aa779
No known key found for this signature in database
GPG Key ID: F483EB800EF89DD9
8 changed files with 746 additions and 653 deletions

View File

@ -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,

View File

@ -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;

View File

@ -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,

View File

@ -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,

View File

@ -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) {}
}
}

View File

@ -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;
}
/**

View File

@ -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;

View File

@ -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;
}