2015-04-23 18:36:55 +02:00
|
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2013 Alaeddine Weslati <alaeddine.weslati@inria.fr>
|
|
|
|
|
* Copyright (C) 2015 Freie Universität Berlin
|
2017-06-30 13:53:29 +02:00
|
|
|
|
* 2017 HAW Hamburg
|
2015-04-23 18:36:55 +02:00
|
|
|
|
*
|
|
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
|
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
|
|
|
* directory for more details.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
2015-08-09 21:24:55 +02:00
|
|
|
|
* @ingroup drivers_at86rf2xx
|
2015-04-23 18:36:55 +02:00
|
|
|
|
* @{
|
|
|
|
|
*
|
|
|
|
|
* @file
|
|
|
|
|
* @brief Implementation of public functions for AT86RF2xx drivers
|
|
|
|
|
*
|
|
|
|
|
* @author Alaeddine Weslati <alaeddine.weslati@inria.fr>
|
|
|
|
|
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
|
|
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
|
|
|
|
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
2015-05-10 21:50:41 +02:00
|
|
|
|
* @author Oliver Hahm <oliver.hahm@inria.fr>
|
2017-06-30 13:53:29 +02:00
|
|
|
|
* @author Sebastian Meiling <s@mlng.net>
|
2015-04-23 18:36:55 +02:00
|
|
|
|
* @}
|
|
|
|
|
*/
|
|
|
|
|
|
2021-02-25 21:23:27 +01:00
|
|
|
|
#include "kernel_defines.h"
|
2015-05-10 21:50:41 +02:00
|
|
|
|
#include "byteorder.h"
|
2015-08-07 14:36:04 +02:00
|
|
|
|
#include "net/ieee802154.h"
|
2020-10-02 19:39:43 +02:00
|
|
|
|
#if IS_USED(IEEE802154_SECURITY)
|
|
|
|
|
#include "net/ieee802154_security.h"
|
|
|
|
|
#endif
|
2015-08-10 02:41:08 +02:00
|
|
|
|
#include "net/gnrc.h"
|
2015-08-09 21:24:55 +02:00
|
|
|
|
#include "at86rf2xx_registers.h"
|
|
|
|
|
#include "at86rf2xx_internal.h"
|
|
|
|
|
#include "at86rf2xx_netdev.h"
|
2020-10-02 19:39:43 +02:00
|
|
|
|
#if IS_USED(MODULE_AT86RF2XX_AES_SPI)
|
|
|
|
|
#include "at86rf2xx_aes.h"
|
|
|
|
|
#endif
|
2015-04-23 18:36:55 +02:00
|
|
|
|
|
2020-10-22 11:34:31 +02:00
|
|
|
|
#define ENABLE_DEBUG 0
|
2015-04-23 18:36:55 +02:00
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
2020-10-02 19:39:43 +02:00
|
|
|
|
#if IS_USED(MODULE_AT86RF2XX_AES_SPI) && \
|
|
|
|
|
IS_USED(MODULE_IEEE802154_SECURITY)
|
|
|
|
|
/**
|
|
|
|
|
* @brief Pass the 802.15.4 encryption key to the transceiver hardware
|
|
|
|
|
*
|
|
|
|
|
* @param[in] dev Abstract security device descriptor
|
|
|
|
|
* @param[in] key Encryption key to be used
|
|
|
|
|
* @param[in] key_size Size of the encryption key in bytes
|
|
|
|
|
*/
|
|
|
|
|
static void _at86rf2xx_set_key(ieee802154_sec_dev_t *dev,
|
|
|
|
|
const uint8_t *key, uint8_t key_size)
|
|
|
|
|
{
|
|
|
|
|
(void)key_size;
|
|
|
|
|
at86rf2xx_aes_key_write_encrypt((at86rf2xx_t *)dev->ctx, key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Compute CBC-MAC from IEEE 802.15.4 security context
|
|
|
|
|
*
|
|
|
|
|
* @param[in] dev Abstract security device descriptor
|
|
|
|
|
* @param[out] cipher Buffer to store cipher blocks
|
|
|
|
|
* @param[in] iv Initial vector
|
|
|
|
|
* @param[in] plain Input data blocks
|
|
|
|
|
* @param[in] nblocks Number of blocks
|
|
|
|
|
*/
|
|
|
|
|
static void _at86rf2xx_cbc(const ieee802154_sec_dev_t *dev,
|
|
|
|
|
uint8_t *cipher,
|
|
|
|
|
uint8_t *iv,
|
|
|
|
|
const uint8_t *plain,
|
|
|
|
|
uint8_t nblocks)
|
|
|
|
|
{
|
|
|
|
|
at86rf2xx_aes_cbc_encrypt((at86rf2xx_t *)dev->ctx,
|
|
|
|
|
(aes_block_t *)cipher,
|
|
|
|
|
NULL,
|
|
|
|
|
iv,
|
|
|
|
|
(aes_block_t *)plain,
|
|
|
|
|
nblocks);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Perform ECB encryption
|
|
|
|
|
*
|
|
|
|
|
* @param[in] dev Abstract security device descriptor
|
|
|
|
|
* @param[out] cipher Output cipher blocks
|
|
|
|
|
* @param[in] plain Plain blocks
|
|
|
|
|
* @param[in] nblocks Number of blocks
|
|
|
|
|
*/
|
|
|
|
|
static void _at86rf2xx_ecb(const ieee802154_sec_dev_t *dev,
|
|
|
|
|
uint8_t *cipher,
|
|
|
|
|
const uint8_t *plain,
|
|
|
|
|
uint8_t nblocks)
|
|
|
|
|
{
|
|
|
|
|
at86rf2xx_aes_ecb_encrypt((at86rf2xx_t *)dev->ctx,
|
|
|
|
|
(aes_block_t *)cipher,
|
|
|
|
|
NULL,
|
|
|
|
|
(aes_block_t *)plain,
|
|
|
|
|
nblocks);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* @brief Struct that contains IEEE 802.15.4 security operations
|
|
|
|
|
* which are implemented, using the transceiver´s hardware
|
|
|
|
|
* crypto capabilities
|
|
|
|
|
*/
|
|
|
|
|
static const ieee802154_radio_cipher_ops_t _at86rf2xx_cipher_ops = {
|
|
|
|
|
.set_key = _at86rf2xx_set_key,
|
|
|
|
|
.ecb = _at86rf2xx_ecb,
|
|
|
|
|
.cbc = _at86rf2xx_cbc
|
|
|
|
|
};
|
2021-02-17 20:41:11 +01:00
|
|
|
|
#endif /* IS_USED(MODULE_AT86RF2XX_AES_SPI) && \
|
2020-10-02 19:39:43 +02:00
|
|
|
|
IS_USED(MODULE_IEEE802154_SECURITY) */
|
2015-04-23 18:36:55 +02:00
|
|
|
|
|
2020-07-07 20:15:56 +02:00
|
|
|
|
void at86rf2xx_setup(at86rf2xx_t *dev, const at86rf2xx_params_t *params, uint8_t index)
|
2015-04-23 18:36:55 +02:00
|
|
|
|
{
|
2020-06-16 15:24:35 +02:00
|
|
|
|
netdev_t *netdev = &dev->netdev.netdev;
|
2015-04-23 18:36:55 +02:00
|
|
|
|
|
2016-03-18 10:26:33 +01:00
|
|
|
|
netdev->driver = &at86rf2xx_driver;
|
2018-07-06 14:03:09 +02:00
|
|
|
|
/* State to return after receiving or transmitting */
|
2015-08-09 21:24:55 +02:00
|
|
|
|
dev->idle_state = AT86RF2XX_STATE_TRX_OFF;
|
2017-07-07 12:48:46 +02:00
|
|
|
|
/* radio state is P_ON when first powered-on */
|
|
|
|
|
dev->state = AT86RF2XX_STATE_P_ON;
|
2016-04-07 16:53:34 +02:00
|
|
|
|
dev->pending_tx = 0;
|
2019-10-21 01:07:44 +02:00
|
|
|
|
|
|
|
|
|
#if defined(MODULE_AT86RFA1) || defined(MODULE_AT86RFR2)
|
|
|
|
|
(void) params;
|
|
|
|
|
/* set all interrupts off */
|
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__IRQ_MASK, 0x00);
|
|
|
|
|
#else
|
|
|
|
|
/* initialize device descriptor */
|
|
|
|
|
dev->params = *params;
|
|
|
|
|
#endif
|
2020-07-07 20:15:56 +02:00
|
|
|
|
|
|
|
|
|
netdev_register(netdev, NETDEV_AT86RF2XX, index);
|
2020-06-16 15:24:35 +02:00
|
|
|
|
/* set device address */
|
|
|
|
|
netdev_ieee802154_setup(&dev->netdev);
|
2019-10-21 01:07:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void at86rf2xx_disable_clock_output(at86rf2xx_t *dev)
|
|
|
|
|
{
|
|
|
|
|
#if defined(MODULE_AT86RFA1) || defined(MODULE_AT86RFR2)
|
|
|
|
|
(void) dev;
|
|
|
|
|
#else
|
|
|
|
|
uint8_t tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_0);
|
|
|
|
|
tmp &= ~(AT86RF2XX_TRX_CTRL_0_MASK__CLKM_CTRL);
|
|
|
|
|
tmp &= ~(AT86RF2XX_TRX_CTRL_0_MASK__CLKM_SHA_SEL);
|
|
|
|
|
tmp |= (AT86RF2XX_TRX_CTRL_0_CLKM_CTRL__OFF);
|
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_0, tmp);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void at86rf2xx_enable_smart_idle(at86rf2xx_t *dev)
|
|
|
|
|
{
|
|
|
|
|
#if AT86RF2XX_SMART_IDLE_LISTENING
|
|
|
|
|
uint8_t tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_RPC);
|
|
|
|
|
tmp |= (AT86RF2XX_TRX_RPC_MASK__RX_RPC_EN |
|
|
|
|
|
AT86RF2XX_TRX_RPC_MASK__PDT_RPC_EN |
|
|
|
|
|
AT86RF2XX_TRX_RPC_MASK__PLL_RPC_EN |
|
|
|
|
|
AT86RF2XX_TRX_RPC_MASK__XAH_TX_RPC_EN |
|
|
|
|
|
AT86RF2XX_TRX_RPC_MASK__IPAN_RPC_EN);
|
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_RPC, tmp);
|
|
|
|
|
at86rf2xx_set_rxsensitivity(dev, RSSI_BASE_VAL);
|
|
|
|
|
#else
|
|
|
|
|
(void) dev;
|
|
|
|
|
#endif
|
2015-04-23 18:36:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
|
void at86rf2xx_reset(at86rf2xx_t *dev)
|
2015-04-23 18:36:55 +02:00
|
|
|
|
{
|
2018-07-10 14:28:38 +02:00
|
|
|
|
netdev_ieee802154_reset(&dev->netdev);
|
|
|
|
|
|
2015-07-16 20:54:50 +02:00
|
|
|
|
/* Reset state machine to ensure a known state */
|
2017-07-07 18:11:28 +02:00
|
|
|
|
if (dev->state == AT86RF2XX_STATE_P_ON) {
|
|
|
|
|
at86rf2xx_set_state(dev, AT86RF2XX_STATE_FORCE_TRX_OFF);
|
|
|
|
|
}
|
2015-07-16 20:54:50 +02:00
|
|
|
|
|
2017-01-10 14:53:09 +01:00
|
|
|
|
/* set short and long address */
|
2020-06-16 15:24:35 +02:00
|
|
|
|
at86rf2xx_set_addr_long(dev, (eui64_t *)dev->netdev.long_addr);
|
|
|
|
|
at86rf2xx_set_addr_short(dev, (network_uint16_t *)dev->netdev.short_addr);
|
2017-01-10 14:53:09 +01:00
|
|
|
|
|
2015-04-23 18:36:55 +02:00
|
|
|
|
/* set default channel */
|
2015-08-09 21:24:55 +02:00
|
|
|
|
at86rf2xx_set_chan(dev, AT86RF2XX_DEFAULT_CHANNEL);
|
2015-04-23 18:36:55 +02:00
|
|
|
|
/* set default TX power */
|
2015-08-09 21:24:55 +02:00
|
|
|
|
at86rf2xx_set_txpower(dev, AT86RF2XX_DEFAULT_TXPOWER);
|
2015-04-23 18:36:55 +02:00
|
|
|
|
/* set default options */
|
2018-07-10 14:28:38 +02:00
|
|
|
|
|
2020-04-02 16:48:34 +02:00
|
|
|
|
if (!IS_ACTIVE(AT86RF2XX_BASIC_MODE)) {
|
|
|
|
|
at86rf2xx_set_option(dev, AT86RF2XX_OPT_AUTOACK, true);
|
|
|
|
|
at86rf2xx_set_option(dev, AT86RF2XX_OPT_CSMA, true);
|
|
|
|
|
|
|
|
|
|
static const netopt_enable_t enable = NETOPT_ENABLE;
|
|
|
|
|
netdev_ieee802154_set(&dev->netdev, NETOPT_ACK_REQ,
|
|
|
|
|
&enable, sizeof(enable));
|
|
|
|
|
}
|
2018-10-25 12:06:23 +02:00
|
|
|
|
|
2015-04-23 18:36:55 +02:00
|
|
|
|
/* enable safe mode (protect RX FIFO until reading data starts) */
|
2015-08-09 21:24:55 +02:00
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2,
|
|
|
|
|
AT86RF2XX_TRX_CTRL_2_MASK__RX_SAFE_MODE);
|
2015-08-12 17:08:42 +02:00
|
|
|
|
#ifdef MODULE_AT86RF212B
|
2017-10-05 15:14:41 +02:00
|
|
|
|
at86rf2xx_set_page(dev, AT86RF2XX_DEFAULT_PAGE);
|
2015-04-23 18:36:55 +02:00
|
|
|
|
#endif
|
2015-07-01 16:35:19 +02:00
|
|
|
|
|
2019-10-21 01:07:44 +02:00
|
|
|
|
#if !defined(MODULE_AT86RFA1) && !defined(MODULE_AT86RFR2)
|
2015-07-01 16:35:19 +02:00
|
|
|
|
/* don't populate masked interrupt flags to IRQ_STATUS register */
|
2015-08-09 21:24:55 +02:00
|
|
|
|
uint8_t tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_1);
|
|
|
|
|
tmp &= ~(AT86RF2XX_TRX_CTRL_1_MASK__IRQ_MASK_MODE);
|
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_1, tmp);
|
2019-10-21 01:07:44 +02:00
|
|
|
|
#endif
|
2015-07-01 16:35:19 +02:00
|
|
|
|
|
2018-08-06 22:56:42 +02:00
|
|
|
|
/* configure smart idle listening feature */
|
2019-10-21 01:07:44 +02:00
|
|
|
|
at86rf2xx_enable_smart_idle(dev);
|
2018-08-06 22:56:42 +02:00
|
|
|
|
|
2015-09-16 14:01:17 +02:00
|
|
|
|
/* disable clock output to save power */
|
2019-10-21 01:07:44 +02:00
|
|
|
|
at86rf2xx_disable_clock_output(dev);
|
2015-09-16 14:01:17 +02:00
|
|
|
|
|
2015-04-23 18:36:55 +02:00
|
|
|
|
/* enable interrupts */
|
2015-08-09 21:24:55 +02:00
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__IRQ_MASK,
|
|
|
|
|
AT86RF2XX_IRQ_STATUS_MASK__TRX_END);
|
2020-07-23 19:50:08 +02:00
|
|
|
|
|
|
|
|
|
/* enable TX start interrupt for retry counter */
|
|
|
|
|
#ifdef AT86RF2XX_REG__IRQ_MASK1
|
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__IRQ_MASK1,
|
|
|
|
|
AT86RF2XX_IRQ_STATUS_MASK1__TX_START);
|
|
|
|
|
#endif
|
|
|
|
|
|
2015-07-01 16:35:19 +02:00
|
|
|
|
/* clear interrupt flags */
|
2015-08-09 21:24:55 +02:00
|
|
|
|
at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);
|
2015-07-01 16:35:19 +02:00
|
|
|
|
|
2020-10-02 19:39:43 +02:00
|
|
|
|
#if IS_USED(MODULE_IEEE802154_SECURITY) && \
|
|
|
|
|
IS_USED(MODULE_AT86RF2XX_AES_SPI)
|
|
|
|
|
dev->netdev.sec_ctx.dev.cipher_ops = &_at86rf2xx_cipher_ops;
|
|
|
|
|
dev->netdev.sec_ctx.dev.ctx = dev;
|
|
|
|
|
/* All configurations of the security module, the SRAM content,
|
|
|
|
|
and keys are reset during DEEP_SLEEP or RESET state. */
|
|
|
|
|
at86rf2xx_aes_key_write_encrypt(dev,
|
|
|
|
|
dev->netdev.sec_ctx.cipher.context.context);
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-07-06 14:03:09 +02:00
|
|
|
|
/* State to return after receiving or transmitting */
|
2020-04-02 16:48:34 +02:00
|
|
|
|
dev->idle_state = AT86RF2XX_PHY_STATE_RX;
|
2015-04-23 18:36:55 +02:00
|
|
|
|
/* go into RX state */
|
2020-04-02 16:48:34 +02:00
|
|
|
|
at86rf2xx_set_state(dev, AT86RF2XX_PHY_STATE_RX);
|
2015-04-23 18:36:55 +02:00
|
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
|
DEBUG("at86rf2xx_reset(): reset complete.\n");
|
2015-04-23 18:36:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
|
size_t at86rf2xx_send(at86rf2xx_t *dev, const uint8_t *data, size_t len)
|
2015-04-23 18:36:55 +02:00
|
|
|
|
{
|
|
|
|
|
/* check data length */
|
2015-08-09 21:24:55 +02:00
|
|
|
|
if (len > AT86RF2XX_MAX_PKT_LENGTH) {
|
|
|
|
|
DEBUG("[at86rf2xx] Error: data to send exceeds max packet size\n");
|
2015-04-23 18:36:55 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-08-09 21:24:55 +02:00
|
|
|
|
at86rf2xx_tx_prepare(dev);
|
|
|
|
|
at86rf2xx_tx_load(dev, data, len, 0);
|
|
|
|
|
at86rf2xx_tx_exec(dev);
|
2015-04-23 18:36:55 +02:00
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
|
void at86rf2xx_tx_prepare(at86rf2xx_t *dev)
|
2015-04-23 18:36:55 +02:00
|
|
|
|
{
|
2017-06-29 13:39:14 +02:00
|
|
|
|
uint8_t state;
|
|
|
|
|
|
2016-04-07 16:53:34 +02:00
|
|
|
|
dev->pending_tx++;
|
2020-04-02 16:48:34 +02:00
|
|
|
|
state = at86rf2xx_set_state(dev, AT86RF2XX_PHY_STATE_TX);
|
|
|
|
|
if (state != AT86RF2XX_PHY_STATE_TX) {
|
2017-06-29 13:39:14 +02:00
|
|
|
|
dev->idle_state = state;
|
|
|
|
|
}
|
2016-03-18 10:26:33 +01:00
|
|
|
|
dev->tx_frame_len = IEEE802154_FCS_LEN;
|
2015-04-23 18:36:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
|
size_t at86rf2xx_tx_load(at86rf2xx_t *dev, const uint8_t *data,
|
2015-08-09 21:24:55 +02:00
|
|
|
|
size_t len, size_t offset)
|
2015-04-23 18:36:55 +02:00
|
|
|
|
{
|
2016-03-18 10:26:33 +01:00
|
|
|
|
dev->tx_frame_len += (uint8_t)len;
|
2015-08-09 21:24:55 +02:00
|
|
|
|
at86rf2xx_sram_write(dev, offset + 1, data, len);
|
2015-04-23 18:36:55 +02:00
|
|
|
|
return offset + len;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-23 19:50:08 +02:00
|
|
|
|
void at86rf2xx_tx_exec(at86rf2xx_t *dev)
|
2015-04-23 18:36:55 +02:00
|
|
|
|
{
|
2017-02-15 13:07:34 +01:00
|
|
|
|
netdev_t *netdev = (netdev_t *)dev;
|
2016-03-18 10:26:33 +01:00
|
|
|
|
|
2020-07-23 19:50:08 +02:00
|
|
|
|
#if AT86RF2XX_HAVE_RETRIES
|
|
|
|
|
dev->tx_retries = -1;
|
|
|
|
|
#endif
|
|
|
|
|
|
2015-04-23 18:36:55 +02:00
|
|
|
|
/* write frame length field in FIFO */
|
2016-03-18 10:26:33 +01:00
|
|
|
|
at86rf2xx_sram_write(dev, 0, &(dev->tx_frame_len), 1);
|
2015-04-23 18:36:55 +02:00
|
|
|
|
/* trigger sending of pre-loaded frame */
|
2015-08-09 21:24:55 +02:00
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_STATE,
|
|
|
|
|
AT86RF2XX_TRX_STATE__TX_START);
|
2016-03-18 10:26:33 +01:00
|
|
|
|
if (netdev->event_callback &&
|
2018-07-11 14:10:50 +02:00
|
|
|
|
(dev->flags & AT86RF2XX_OPT_TELL_TX_START)) {
|
2017-02-15 13:07:34 +01:00
|
|
|
|
netdev->event_callback(netdev, NETDEV_EVENT_TX_STARTED);
|
2015-04-23 18:36:55 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-09-04 16:06:55 +02:00
|
|
|
|
|
|
|
|
|
bool at86rf2xx_cca(at86rf2xx_t *dev)
|
|
|
|
|
{
|
|
|
|
|
uint8_t reg;
|
|
|
|
|
uint8_t old_state = at86rf2xx_set_state(dev, AT86RF2XX_STATE_TRX_OFF);
|
|
|
|
|
/* Disable RX path */
|
|
|
|
|
uint8_t rx_syn = at86rf2xx_reg_read(dev, AT86RF2XX_REG__RX_SYN);
|
2018-07-06 13:07:02 +02:00
|
|
|
|
|
2017-09-04 16:06:55 +02:00
|
|
|
|
reg = rx_syn | AT86RF2XX_RX_SYN__RX_PDT_DIS;
|
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__RX_SYN, reg);
|
|
|
|
|
/* Manually triggered CCA is only possible in RX_ON (basic operating mode) */
|
|
|
|
|
at86rf2xx_set_state(dev, AT86RF2XX_STATE_RX_ON);
|
|
|
|
|
/* Perform CCA */
|
|
|
|
|
reg = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_CC_CCA);
|
|
|
|
|
reg |= AT86RF2XX_PHY_CC_CCA_MASK__CCA_REQUEST;
|
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_CC_CCA, reg);
|
|
|
|
|
/* Spin until done (8 symbols + 12 µs = 128 µs + 12 µs for O-QPSK)*/
|
|
|
|
|
do {
|
|
|
|
|
reg = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_STATUS);
|
|
|
|
|
} while ((reg & AT86RF2XX_TRX_STATUS_MASK__CCA_DONE) == 0);
|
|
|
|
|
/* return true if channel is clear */
|
|
|
|
|
bool ret = !!(reg & AT86RF2XX_TRX_STATUS_MASK__CCA_STATUS);
|
|
|
|
|
/* re-enable RX */
|
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__RX_SYN, rx_syn);
|
|
|
|
|
/* Step back to the old state */
|
|
|
|
|
at86rf2xx_set_state(dev, AT86RF2XX_STATE_TRX_OFF);
|
|
|
|
|
at86rf2xx_set_state(dev, old_state);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|