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:
parent
f33b3ad10d
commit
db815aa779
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user