1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #18988 from jia200x/pr/at86rf2xx/isolate_netdev

drivers/at86rf2xx: isolate netdev logic
This commit is contained in:
benpicco 2022-12-07 13:50:37 +01:00 committed by GitHub
commit 2e50d5e448
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 309 additions and 437 deletions

View File

@ -7964,6 +7964,7 @@ drivers/include/at86rf215\.h:[0-9]+: warning: Member at86rf215_clko_cur_t \(enum
drivers/include/at86rf215\.h:[0-9]+: warning: Member at86rf215_clko_freq_t \(enumeration\) of group drivers_at86rf215 is not documented\.
drivers/include/at86rf215\.h:[0-9]+: warning: Member at86rf215_state_t \(enumeration\) of group drivers_at86rf215 is not documented\.
drivers/include/at86rf2xx\.h:[0-9]+: warning: Member AT86RF2XX_DEFAULT_CHANNEL \(macro definition\) of group drivers_at86rf2xx is not documented\.
drivers/include/at86rf2xx\.h:[0-9]+: warning: Member AT86RF2XX_DEFAULT_PAGE \(macro definition\) of group drivers_at86rf2xx is not documented\.
drivers/include/at86rf2xx\.h:[0-9]+: warning: Member AT86RF2XX_MAX_CHANNEL \(macro definition\) of group drivers_at86rf2xx is not documented\.
drivers/include/at86rf2xx\.h:[0-9]+: warning: Member AT86RF2XX_MIN_CHANNEL \(macro definition\) of group drivers_at86rf2xx is not documented\.
drivers/include/bh1900nux\.h:[0-9]+: warning: Member BH1900NUX_REG_ADDR \(macro definition\) of group drivers_bh1900nux is not documented\.

View File

@ -27,13 +27,9 @@
#include "kernel_defines.h"
#include "byteorder.h"
#include "net/ieee802154.h"
#if IS_USED(IEEE802154_SECURITY)
#include "net/ieee802154_security.h"
#endif
#include "net/gnrc.h"
#include "at86rf2xx_registers.h"
#include "at86rf2xx_internal.h"
#include "at86rf2xx_netdev.h"
#if IS_USED(MODULE_AT86RF2XX_AES_SPI)
#include "at86rf2xx_aes.h"
#endif
@ -41,103 +37,6 @@
#define ENABLE_DEBUG 0
#include "debug.h"
#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
};
#endif /* IS_USED(MODULE_AT86RF2XX_AES_SPI) && \
IS_USED(MODULE_IEEE802154_SECURITY) */
void at86rf2xx_setup(at86rf2xx_t *dev, const at86rf2xx_params_t *params, uint8_t index)
{
netdev_t *netdev = &dev->netdev.netdev;
netdev->driver = &at86rf2xx_driver;
/* State to return after receiving or transmitting */
dev->idle_state = AT86RF2XX_STATE_TRX_OFF;
/* radio state is P_ON when first powered-on */
dev->state = AT86RF2XX_STATE_P_ON;
dev->pending_tx = 0;
#if AT86RF2XX_IS_PERIPH
(void) params;
/* set all interrupts off */
at86rf2xx_reg_write(dev, AT86RF2XX_REG__IRQ_MASK, 0x00);
#else
/* initialize device descriptor */
dev->params = *params;
#endif
netdev_register(netdev, NETDEV_AT86RF2XX, index);
/* set device address */
netdev_ieee802154_setup(&dev->netdev);
}
static void at86rf2xx_disable_clock_output(at86rf2xx_t *dev)
{
#if AT86RF2XX_IS_PERIPH
@ -177,38 +76,25 @@ void at86rf2xx_disable_smart_idle(at86rf2xx_t *dev)
void at86rf2xx_reset(at86rf2xx_t *dev)
{
uint8_t tmp;
netdev_ieee802154_reset(&dev->netdev);
/* Reset state machine to ensure a known state */
if (dev->state == AT86RF2XX_STATE_P_ON) {
at86rf2xx_set_state(dev, AT86RF2XX_STATE_FORCE_TRX_OFF);
}
/* set short and long address */
at86rf2xx_set_addr_long(dev, (eui64_t *)dev->netdev.long_addr);
at86rf2xx_set_addr_short(dev, (network_uint16_t *)dev->netdev.short_addr);
/* set default channel, page and TX power */
at86rf2xx_configure_phy(dev, AT86RF2XX_DEFAULT_CHANNEL, AT86RF2XX_DEFAULT_PAGE, AT86RF2XX_DEFAULT_TXPOWER);
/* set default channel */
at86rf2xx_set_chan(dev, AT86RF2XX_DEFAULT_CHANNEL);
/* set default TX power */
at86rf2xx_set_txpower(dev, AT86RF2XX_DEFAULT_TXPOWER);
/* set default options */
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));
}
/* enable safe mode (protect RX FIFO until reading data starts) */
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2,
AT86RF2XX_TRX_CTRL_2_MASK__RX_SAFE_MODE);
#if AT86RF2XX_HAVE_SUBGHZ
at86rf2xx_set_page(dev, AT86RF2XX_DEFAULT_PAGE);
#endif
#if !AT86RF2XX_IS_PERIPH
/* don't populate masked interrupt flags to IRQ_STATUS register */
@ -236,12 +122,6 @@ void at86rf2xx_reset(at86rf2xx_t *dev)
/* clear interrupt flags */
at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);
#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;
#endif
/* State to return after receiving or transmitting */
dev->idle_state = AT86RF2XX_PHY_STATE_RX;
/* go into RX state */
@ -255,19 +135,6 @@ void at86rf2xx_reset(at86rf2xx_t *dev)
DEBUG("at86rf2xx_reset(): reset complete.\n");
}
size_t at86rf2xx_send(at86rf2xx_t *dev, const uint8_t *data, size_t len)
{
/* check data length */
if (len > AT86RF2XX_MAX_PKT_LENGTH) {
DEBUG("[at86rf2xx] Error: data to send exceeds max packet size\n");
return 0;
}
at86rf2xx_tx_prepare(dev);
at86rf2xx_tx_load(dev, data, len, 0);
at86rf2xx_tx_exec(dev);
return len;
}
void at86rf2xx_tx_prepare(at86rf2xx_t *dev)
{
uint8_t state;
@ -290,8 +157,6 @@ size_t at86rf2xx_tx_load(at86rf2xx_t *dev, const uint8_t *data,
void at86rf2xx_tx_exec(at86rf2xx_t *dev)
{
netdev_t *netdev = &dev->netdev.netdev;
#if AT86RF2XX_HAVE_RETRIES
dev->tx_retries = -1;
#endif
@ -301,9 +166,6 @@ void at86rf2xx_tx_exec(at86rf2xx_t *dev)
/* trigger sending of pre-loaded frame */
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_STATE,
AT86RF2XX_TRX_STATE__TX_START);
if (netdev->event_callback) {
netdev->event_callback(netdev, NETDEV_EVENT_TX_STARTED);
}
}
bool at86rf2xx_cca(at86rf2xx_t *dev)

View File

@ -51,127 +51,36 @@ static const uint8_t dbm_to_tx_pow_915[] = { 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x17,
0x04, 0x03, 0x02, 0x01, 0x00, 0x86,
0x40, 0x84, 0x83, 0x82, 0x80, 0xc1,
0xc0 };
static int16_t _tx_pow_to_dbm_212b(uint8_t channel, uint8_t page, uint8_t reg)
{
if (page == 0 || page == 2) {
const uint8_t *dbm_to_tx_pow;
size_t nelem;
if (channel == 0) {
/* Channel 0 is 868.3 MHz */
dbm_to_tx_pow = &dbm_to_tx_pow_868[0];
nelem = ARRAY_SIZE(dbm_to_tx_pow_868);
}
else {
/* Channels 1+ are 915 MHz */
dbm_to_tx_pow = &dbm_to_tx_pow_915[0];
nelem = ARRAY_SIZE(dbm_to_tx_pow_915);
}
for (size_t i = 0; i < nelem; ++i) {
if (dbm_to_tx_pow[i] == reg) {
return (i - AT86RF2XX_TXPOWER_OFF);
}
}
}
return 0;
}
#elif MODULE_AT86RF233
static const int16_t tx_pow_to_dbm[] = { 4, 4, 3, 3, 2, 2, 1,
0, -1, -2, -3, -4, -6, -8, -12, -17 };
static const uint8_t dbm_to_tx_pow[] = { 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e,
0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c,
0x0b, 0x0b, 0x0a, 0x09, 0x08, 0x07,
0x06, 0x05, 0x03, 0x00 };
#else
static const int16_t tx_pow_to_dbm[] = { 3, 3, 2, 2, 1, 1, 0,
-1, -2, -3, -4, -5, -7, -9, -12, -17 };
static const uint8_t dbm_to_tx_pow[] = { 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e,
0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b,
0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,
0x05, 0x03, 0x00 };
#endif
void at86rf2xx_get_addr_short(const at86rf2xx_t *dev, network_uint16_t *addr)
{
memcpy(addr, dev->netdev.short_addr, sizeof(*addr));
}
void at86rf2xx_set_addr_short(at86rf2xx_t *dev, const network_uint16_t *addr)
{
memcpy(dev->netdev.short_addr, addr, sizeof(*addr));
#ifdef MODULE_SIXLOWPAN
/* https://tools.ietf.org/html/rfc4944#section-12 requires the first bit to
* 0 for unicast addresses */
dev->netdev.short_addr[0] &= 0x7F;
#endif
/* device use lsb first, not network byte order */
at86rf2xx_reg_write(dev, AT86RF2XX_REG__SHORT_ADDR_0,
dev->netdev.short_addr[1]);
addr->u8[1]);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__SHORT_ADDR_1,
dev->netdev.short_addr[0]);
}
void at86rf2xx_get_addr_long(const at86rf2xx_t *dev, eui64_t *addr)
{
memcpy(addr, dev->netdev.long_addr, sizeof(*addr));
addr->u8[0]);
}
void at86rf2xx_set_addr_long(at86rf2xx_t *dev, const eui64_t *addr)
{
memcpy(dev->netdev.long_addr, addr, sizeof(*addr));
for (int i = 0; i < 8; i++) {
/* device use lsb first, not network byte order */
at86rf2xx_reg_write(dev, (AT86RF2XX_REG__IEEE_ADDR_0 + i),
dev->netdev.long_addr[IEEE802154_LONG_ADDRESS_LEN - 1 - i]);
addr->uint8[IEEE802154_LONG_ADDRESS_LEN - 1 - i]);
}
}
uint8_t at86rf2xx_get_chan(const at86rf2xx_t *dev)
{
return dev->netdev.chan;
}
void at86rf2xx_set_chan(at86rf2xx_t *dev, uint8_t channel)
{
if ((channel > AT86RF2XX_MAX_CHANNEL)
#if AT86RF2XX_MIN_CHANNEL /* is zero for sub-GHz */
|| (channel < AT86RF2XX_MIN_CHANNEL)
#endif
) {
return;
}
dev->netdev.chan = channel;
at86rf2xx_configure_phy(dev);
}
uint8_t at86rf2xx_get_page(const at86rf2xx_t *dev)
{
#if AT86RF2XX_HAVE_SUBGHZ
return dev->page;
#else
(void) dev;
return 0;
#endif
}
void at86rf2xx_set_page(at86rf2xx_t *dev, uint8_t page)
{
#if AT86RF2XX_HAVE_SUBGHZ
if ((page == 0) || (page == 2)) {
dev->page = page;
at86rf2xx_configure_phy(dev);
}
#else
(void) dev;
(void) page;
#endif
}
uint8_t at86rf2xx_get_phy_mode(at86rf2xx_t *dev)
{
#if AT86RF2XX_HAVE_SUBGHZ
@ -214,11 +123,6 @@ uint8_t at86rf2xx_get_rate(at86rf2xx_t *dev)
return rate;
}
uint16_t at86rf2xx_get_pan(const at86rf2xx_t *dev)
{
return dev->netdev.pan;
}
void at86rf2xx_set_pan(at86rf2xx_t *dev, uint16_t pan)
{
le_uint16_t le_pan = byteorder_htols(pan);
@ -228,21 +132,9 @@ void at86rf2xx_set_pan(at86rf2xx_t *dev, uint16_t pan)
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PAN_ID_1, le_pan.u8[1]);
}
int16_t at86rf2xx_get_txpower(const at86rf2xx_t *dev)
{
#if AT86RF2XX_HAVE_SUBGHZ
uint8_t txpower = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_TX_PWR);
DEBUG("txpower value: %x\n", txpower);
return _tx_pow_to_dbm_212b(dev->netdev.chan, dev->page, txpower);
#else
uint8_t txpower = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_TX_PWR)
& AT86RF2XX_PHY_TX_PWR_MASK__TX_PWR;
return tx_pow_to_dbm[txpower];
#endif
}
void at86rf2xx_set_txpower(const at86rf2xx_t *dev, int16_t txpower)
static inline void _set_txpower(const at86rf2xx_t *dev, int16_t txpower, uint8_t channel)
{
(void) channel;
txpower += AT86RF2XX_TXPOWER_OFF;
if (txpower < 0) {
@ -252,11 +144,11 @@ void at86rf2xx_set_txpower(const at86rf2xx_t *dev, int16_t txpower)
txpower = AT86RF2XX_TXPOWER_MAX;
}
#if AT86RF2XX_HAVE_SUBGHZ
if (dev->netdev.chan == 0) {
if (channel == 0) {
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
dbm_to_tx_pow_868[txpower]);
}
else if (dev->netdev.chan < 11) {
else if (channel < 11) {
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
dbm_to_tx_pow_915[txpower]);
}
@ -266,6 +158,63 @@ void at86rf2xx_set_txpower(const at86rf2xx_t *dev, int16_t txpower)
#endif
}
void at86rf2xx_configure_phy(at86rf2xx_t *dev, uint8_t chan, uint8_t page, int16_t txpower)
{
/* we must be in TRX_OFF before changing the PHY configuration */
uint8_t prev_state = at86rf2xx_set_state(dev, AT86RF2XX_STATE_TRX_OFF);
(void) page;
(void) chan;
(void) txpower;
#if AT86RF2XX_HAVE_SUBGHZ
/* The TX power register must be updated after changing the channel if
* moving between bands. */
uint8_t trx_ctrl2 = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_2);
uint8_t rf_ctrl0 = at86rf2xx_reg_read(dev, AT86RF2XX_REG__RF_CTRL_0);
/* Clear previous configuration for PHY mode */
trx_ctrl2 &= ~(AT86RF2XX_TRX_CTRL_2_MASK__FREQ_MODE);
/* Clear previous configuration for GC_TX_OFFS */
rf_ctrl0 &= ~AT86RF2XX_RF_CTRL_0_MASK__GC_TX_OFFS;
if (chan != 0) {
/* Set sub mode bit on 915 MHz as recommended by the data sheet */
trx_ctrl2 |= AT86RF2XX_TRX_CTRL_2_MASK__SUB_MODE;
}
if (page == 0) {
/* BPSK coding */
/* Data sheet recommends using a +2 dB setting for BPSK */
rf_ctrl0 |= AT86RF2XX_RF_CTRL_0_GC_TX_OFFS__2DB;
}
else if (page == 2) {
/* O-QPSK coding */
trx_ctrl2 |= AT86RF2XX_TRX_CTRL_2_MASK__BPSK_OQPSK;
/* Data sheet recommends using a +1 dB setting for O-QPSK */
rf_ctrl0 |= AT86RF2XX_RF_CTRL_0_GC_TX_OFFS__1DB;
}
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2, trx_ctrl2);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__RF_CTRL_0, rf_ctrl0);
#endif
uint8_t phy_cc_cca = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_CC_CCA);
/* Clear previous configuration for channel number */
phy_cc_cca &= ~(AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
/* Update the channel register */
phy_cc_cca |= (chan & AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_CC_CCA, phy_cc_cca);
/* Update the TX power register to achieve the same power (in dBm) */
_set_txpower(dev, txpower, chan);
/* Return to the state we had before reconfiguring */
at86rf2xx_set_state(dev, prev_state);
}
int8_t at86rf2xx_get_rxsensitivity(const at86rf2xx_t *dev)
{
uint8_t rxsens = at86rf2xx_reg_read(dev, AT86RF2XX_REG__RX_SYN)
@ -413,8 +362,6 @@ void at86rf2xx_set_option(at86rf2xx_t *dev, uint16_t option, bool state)
if (state) {
DEBUG("[at86rf2xx] opt: enabling CSMA mode" \
"(4 retries, min BE: 3 max BE: 5)\n");
/* Initialize CSMA seed with hardware address */
at86rf2xx_set_csma_seed(dev, dev->netdev.long_addr);
at86rf2xx_set_csma_max_retries(dev, 4);
at86rf2xx_set_csma_backoff_exp(dev, 3, 5);
}

View File

@ -164,62 +164,6 @@ void at86rf2xx_hardware_reset(at86rf2xx_t *dev)
&& (dev->state != AT86RF2XX_STATE_P_ON));
}
void at86rf2xx_configure_phy(at86rf2xx_t *dev)
{
/* we must be in TRX_OFF before changing the PHY configuration */
uint8_t prev_state = at86rf2xx_set_state(dev, AT86RF2XX_STATE_TRX_OFF);
#if AT86RF2XX_HAVE_SUBGHZ
/* The TX power register must be updated after changing the channel if
* moving between bands. */
int16_t txpower = at86rf2xx_get_txpower(dev);
uint8_t trx_ctrl2 = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_2);
uint8_t rf_ctrl0 = at86rf2xx_reg_read(dev, AT86RF2XX_REG__RF_CTRL_0);
/* Clear previous configuration for PHY mode */
trx_ctrl2 &= ~(AT86RF2XX_TRX_CTRL_2_MASK__FREQ_MODE);
/* Clear previous configuration for GC_TX_OFFS */
rf_ctrl0 &= ~AT86RF2XX_RF_CTRL_0_MASK__GC_TX_OFFS;
if (dev->netdev.chan != 0) {
/* Set sub mode bit on 915 MHz as recommended by the data sheet */
trx_ctrl2 |= AT86RF2XX_TRX_CTRL_2_MASK__SUB_MODE;
}
if (dev->page == 0) {
/* BPSK coding */
/* Data sheet recommends using a +2 dB setting for BPSK */
rf_ctrl0 |= AT86RF2XX_RF_CTRL_0_GC_TX_OFFS__2DB;
}
else if (dev->page == 2) {
/* O-QPSK coding */
trx_ctrl2 |= AT86RF2XX_TRX_CTRL_2_MASK__BPSK_OQPSK;
/* Data sheet recommends using a +1 dB setting for O-QPSK */
rf_ctrl0 |= AT86RF2XX_RF_CTRL_0_GC_TX_OFFS__1DB;
}
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2, trx_ctrl2);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__RF_CTRL_0, rf_ctrl0);
#endif
uint8_t phy_cc_cca = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_CC_CCA);
/* Clear previous configuration for channel number */
phy_cc_cca &= ~(AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
/* Update the channel register */
phy_cc_cca |= (dev->netdev.chan & AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_CC_CCA, phy_cc_cca);
#if AT86RF2XX_HAVE_SUBGHZ
/* Update the TX power register to achieve the same power (in dBm) */
at86rf2xx_set_txpower(dev, txpower);
#endif
/* Return to the state we had before reconfiguring */
at86rf2xx_set_state(dev, prev_state);
}
#if AT86RF2XX_RANDOM_NUMBER_GENERATOR
void at86rf2xx_get_random(at86rf2xx_t *dev, uint8_t *data, size_t len)
{
@ -240,3 +184,22 @@ void at86rf2xx_get_random(at86rf2xx_t *dev, uint8_t *data, size_t len)
at86rf2xx_enable_smart_idle(dev);
}
#endif
#if !AT86RF2XX_IS_PERIPH
void at86rf2xx_spi_init(at86rf2xx_t *dev, void (*irq_handler)(void *arg))
{
/* initialize GPIOs */
spi_init_cs(dev->params.spi, dev->params.cs_pin);
gpio_init(dev->params.sleep_pin, GPIO_OUT);
gpio_clear(dev->params.sleep_pin);
gpio_init(dev->params.reset_pin, GPIO_OUT);
gpio_set(dev->params.reset_pin);
gpio_init_int(dev->params.int_pin, GPIO_IN, GPIO_RISING, irq_handler, dev);
/* Intentionally check if bus can be acquired, if assertions are on */
if (!IS_ACTIVE(NDEBUG)) {
spi_acquire(dev->params.spi, dev->params.cs_pin, SPI_MODE_0, dev->params.spi_clk);
spi_release(dev->params.spi);
}
}
#endif

View File

@ -39,6 +39,9 @@
#include "at86rf2xx_netdev.h"
#include "at86rf2xx_internal.h"
#include "at86rf2xx_registers.h"
#if IS_USED(IEEE802154_SECURITY)
#include "net/ieee802154_security.h"
#endif
#if IS_USED(MODULE_AT86RF2XX_AES_SPI)
#include "at86rf2xx_aes.h"
#endif
@ -62,15 +65,85 @@ const netdev_driver_t at86rf2xx_driver = {
.set = _set,
};
#if AT86RF2XX_IS_PERIPH
#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
};
#endif /* IS_USED(MODULE_AT86RF2XX_AES_SPI) && \
IS_USED(MODULE_IEEE802154_SECURITY) */
/* SOC has radio interrupts, store reference to netdev */
static netdev_t *at86rfmega_dev;
#else
static void _irq_handler(void *arg)
{
netdev_trigger_event_isr(arg);
}
#endif
static int _init(netdev_t *netdev)
{
@ -78,23 +151,12 @@ static int _init(netdev_t *netdev)
netdev_ieee802154_t, netdev);
at86rf2xx_t *dev = container_of(netdev_ieee802154, at86rf2xx_t, netdev);
#if AT86RF2XX_IS_PERIPH
at86rfmega_dev = netdev;
#else
/* initialize GPIOs */
spi_init_cs(dev->params.spi, dev->params.cs_pin);
gpio_init(dev->params.sleep_pin, GPIO_OUT);
gpio_clear(dev->params.sleep_pin);
gpio_init(dev->params.reset_pin, GPIO_OUT);
gpio_set(dev->params.reset_pin);
gpio_init_int(dev->params.int_pin, GPIO_IN, GPIO_RISING, _irq_handler, dev);
/* Intentionally check if bus can be acquired, if assertions are on */
if (!IS_ACTIVE(NDEBUG)) {
spi_acquire(dev->params.spi, dev->params.cs_pin, SPI_MODE_0, dev->params.spi_clk);
spi_release(dev->params.spi);
if (AT86RF2XX_IS_PERIPH) {
at86rfmega_dev = netdev;
}
else {
at86rf2xx_spi_init(dev, _irq_handler);
}
#endif
/* reset hardware into a defined state */
at86rf2xx_hardware_reset(dev);
@ -106,8 +168,25 @@ static int _init(netdev_t *netdev)
}
/* reset device to default values and put it into RX state */
netdev_ieee802154_reset(&dev->netdev);
at86rf2xx_set_addr_long(dev, (eui64_t *)dev->netdev.long_addr);
at86rf2xx_set_addr_short(dev, (network_uint16_t *)dev->netdev.short_addr);
if (!IS_ACTIVE(AT86RF2XX_BASIC_MODE)) {
static const netopt_enable_t enable = NETOPT_ENABLE;
netdev_ieee802154_set(&dev->netdev, NETOPT_ACK_REQ,
&enable, sizeof(enable));
}
#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;
#endif
at86rf2xx_reset(dev);
/* Initialize CSMA seed with hardware address */
at86rf2xx_set_csma_seed(dev, dev->netdev.long_addr);
/* signal link UP */
netdev->event_callback(netdev, NETDEV_EVENT_LINK_UP);
@ -139,6 +218,9 @@ static int _send(netdev_t *netdev, const iolist_t *iolist)
/* send data out directly if pre-loading id disabled */
if (!(dev->flags & AT86RF2XX_OPT_PRELOADING)) {
at86rf2xx_tx_exec(dev);
if (netdev->event_callback) {
netdev->event_callback(netdev, NETDEV_EVENT_TX_STARTED);
}
}
/* return the number of bytes that were actually loaded into the frame
* buffer/send out */
@ -161,11 +243,7 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
at86rf2xx_fb_start(dev);
/* get the size of the received packet */
#if AT86RF2XX_IS_PERIPH
phr = TST_RX_LENGTH;
#else
at86rf2xx_fb_read(dev, &phr, 1);
#endif
phr = at86rf2xx_get_rx_len(dev);
/* ignore MSB (refer p.80) and subtract length of FCS field */
pkt_len = (phr & 0x7f) - 2;
@ -279,10 +357,23 @@ static int _set_state(at86rf2xx_t *dev, netopt_state_t state)
}
at86rf2xx_set_state(dev, AT86RF2XX_PHY_STATE_TX);
at86rf2xx_tx_exec(dev);
if (dev->netdev.netdev.event_callback) {
dev->netdev.netdev.event_callback(&dev->netdev.netdev, NETDEV_EVENT_TX_STARTED);
}
}
break;
case NETOPT_STATE_RESET:
at86rf2xx_hardware_reset(dev);
netdev_ieee802154_reset(&dev->netdev);
/* set short and long address */
at86rf2xx_set_addr_long(dev, (eui64_t *)dev->netdev.long_addr);
at86rf2xx_set_addr_short(dev, (network_uint16_t *)dev->netdev.short_addr);
if (!IS_ACTIVE(AT86RF2XX_BASIC_MODE)) {
static const netopt_enable_t enable = NETOPT_ENABLE;
netdev_ieee802154_set(&dev->netdev, NETOPT_ACK_REQ,
&enable, sizeof(enable));
}
at86rf2xx_reset(dev);
break;
default:
@ -321,11 +412,13 @@ static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len)
/* getting these options doesn't require the transceiver to be responsive */
switch (opt) {
#if AT86RF2XX_HAVE_SUBGHZ
case NETOPT_CHANNEL_PAGE:
assert(max_len >= sizeof(uint16_t));
((uint8_t *)val)[1] = 0;
((uint8_t *)val)[0] = at86rf2xx_get_page(dev);
((uint8_t *)val)[0] = dev->page;
return sizeof(uint16_t);
#endif
case NETOPT_STATE:
assert(max_len >= sizeof(netopt_state_t));
@ -402,7 +495,7 @@ static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len)
switch (opt) {
case NETOPT_TX_POWER:
assert(max_len >= sizeof(int16_t));
*((uint16_t *)val) = at86rf2xx_get_txpower(dev);
*((uint16_t *)val) = netdev_ieee802154->txpower;
res = sizeof(uint16_t);
break;
@ -502,11 +595,18 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len)
switch (opt) {
case NETOPT_ADDRESS:
assert(len == sizeof(network_uint16_t));
memcpy(dev->netdev.short_addr, val, len);
#ifdef MODULE_SIXLOWPAN
/* https://tools.ietf.org/html/rfc4944#section-12 requires the first bit to
* 0 for unicast addresses */
dev->netdev.short_addr[0] &= 0x7F;
#endif
at86rf2xx_set_addr_short(dev, val);
/* don't set res to set netdev_ieee802154_t::short_addr */
break;
case NETOPT_ADDRESS_LONG:
assert(len == sizeof(eui64_t));
memcpy(dev->netdev.long_addr, val, len);
at86rf2xx_set_addr_long(dev, val);
/* don't set res to set netdev_ieee802154_t::long_addr */
break;
@ -526,7 +626,12 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len)
res = -EINVAL;
break;
}
at86rf2xx_set_chan(dev, chan);
dev->netdev.chan = chan;
#if AT86RF2XX_HAVE_SUBGHZ
at86rf2xx_configure_phy(dev, chan, dev->page, dev->netdev.txpower);
#else
at86rf2xx_configure_phy(dev, chan, 0, dev->netdev.txpower);
#endif
/* don't set res to set netdev_ieee802154_t::chan */
break;
@ -538,7 +643,8 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len)
res = -EINVAL;
}
else {
at86rf2xx_set_page(dev, page);
dev->page = page;
at86rf2xx_configure_phy(dev, dev->netdev.chan, page, dev->netdev.txpower);
res = sizeof(uint16_t);
}
#else
@ -554,7 +660,12 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len)
case NETOPT_TX_POWER:
assert(len <= sizeof(int16_t));
at86rf2xx_set_txpower(dev, *((const int16_t *)val));
netdev_ieee802154->txpower = *((const int16_t *)val);
#if AT86RF2XX_HAVE_SUBGHZ
at86rf2xx_configure_phy(dev, dev->netdev.chan, dev->page, *((const int16_t *)val));
#else
at86rf2xx_configure_phy(dev, dev->netdev.chan, 0, *((const int16_t *)val));
#endif
res = sizeof(uint16_t);
break;
@ -752,12 +863,7 @@ static void _isr(netdev_t *netdev)
}
/* read (consume) device status */
#if AT86RF2XX_IS_PERIPH
irq_mask = dev->irq_status;
dev->irq_status = 0;
#else
irq_mask = at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);
#endif
irq_mask = at86rf2xx_get_irq_flags(dev);
trac_status = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_STATE)
& AT86RF2XX_TRX_STATE_MASK__TRAC;
@ -802,6 +908,32 @@ static void _isr(netdev_t *netdev)
}
}
void at86rf2xx_setup(at86rf2xx_t *dev, const at86rf2xx_params_t *params, uint8_t index)
{
netdev_t *netdev = &dev->netdev.netdev;
netdev->driver = &at86rf2xx_driver;
/* State to return after receiving or transmitting */
dev->idle_state = AT86RF2XX_STATE_TRX_OFF;
/* radio state is P_ON when first powered-on */
dev->state = AT86RF2XX_STATE_P_ON;
dev->pending_tx = 0;
#if AT86RF2XX_IS_PERIPH
(void) params;
/* set all interrupts off */
at86rf2xx_reg_write(dev, AT86RF2XX_REG__IRQ_MASK, 0x00);
#else
/* initialize device descriptor */
dev->params = *params;
#endif
netdev_register(netdev, NETDEV_AT86RF2XX, index);
/* set device address */
netdev_ieee802154_setup(&dev->netdev);
}
#if AT86RF2XX_IS_PERIPH
/**

View File

@ -30,8 +30,8 @@
#if AT86RF2XX_IS_PERIPH
#include <string.h>
#include "at86rf2xx_registers.h"
#endif
#include "at86rf2xx_registers.h"
#ifdef __cplusplus
extern "C" {
@ -220,8 +220,11 @@ void at86rf2xx_hardware_reset(at86rf2xx_t *dev);
* @brief Set PHY parameters based on channel and page number
*
* @param[in,out] dev device to configure
* @param[in] chan channel number to be set
* @param[in] page channel page
* @param[in] txpower TX power in dBm
*/
void at86rf2xx_configure_phy(at86rf2xx_t *dev);
void at86rf2xx_configure_phy(at86rf2xx_t *dev, uint8_t chan, uint8_t page, int16_t txpower);
#if AT86RF2XX_RANDOM_NUMBER_GENERATOR || defined(DOXYGEN)
/**
@ -242,6 +245,54 @@ void at86rf2xx_configure_phy(at86rf2xx_t *dev);
void at86rf2xx_get_random(at86rf2xx_t *dev, uint8_t *data, size_t len);
#endif
/**
* @brief Initialize AT86RF2XX SPI communication
*
* @param[in,out] dev device to initialize
* @param[in] irq_handler IRQ handler
*/
void at86rf2xx_spi_init(at86rf2xx_t *dev, void (*irq_handler)(void *arg));
/**
* @brief Get the PSDU length of the received frame.
*
* @param[in] dev pointer to the device descriptor
*
* @return the PSDU length
*/
static inline uint8_t at86rf2xx_get_rx_len(at86rf2xx_t *dev)
{
(void) dev;
#if AT86RF2XX_IS_PERIPH
return TST_RX_LENGTH;
#else
uint8_t phr;
at86rf2xx_fb_read(dev, &phr, 1);
return phr;
#endif
}
/**
* @brief Get the IRQ flags.
*
* This function clears the IRQ flags
* @param[in,out] dev pointer to the device descriptor
*
* @return IRQ flags
*/
static inline uint8_t at86rf2xx_get_irq_flags(at86rf2xx_t *dev)
{
(void) dev;
#if AT86RF2XX_IS_PERIPH
uint8_t irq_mask = dev->irq_status;
dev->irq_status = 0;
return irq_mask;
#else
return at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);
#endif
}
#ifdef __cplusplus
}
#endif

View File

@ -68,6 +68,7 @@ extern "C" {
#define AT86RF2XX_MIN_CHANNEL (IEEE802154_CHANNEL_MIN)
#define AT86RF2XX_MAX_CHANNEL (IEEE802154_CHANNEL_MAX)
#define AT86RF2XX_DEFAULT_CHANNEL (CONFIG_IEEE802154_DEFAULT_CHANNEL)
#define AT86RF2XX_DEFAULT_PAGE (0)
/* Only page 0 is supported in the 2.4 GHz band */
#endif
/** @} */
@ -328,16 +329,6 @@ void at86rf2xx_setup(at86rf2xx_t *dev, const at86rf2xx_params_t *params, uint8_t
*/
void at86rf2xx_reset(at86rf2xx_t *dev);
/**
* @brief Get the short address of the given device
*
* @param[in] dev device to read from
* @param[out] addr the short address will be stored here
*
* @return the currently set (2-byte) short address
*/
void at86rf2xx_get_addr_short(const at86rf2xx_t *dev, network_uint16_t *addr);
/**
* @brief Set the short address of the given device
*
@ -346,16 +337,6 @@ void at86rf2xx_get_addr_short(const at86rf2xx_t *dev, network_uint16_t *addr);
*/
void at86rf2xx_set_addr_short(at86rf2xx_t *dev, const network_uint16_t *addr);
/**
* @brief Get the configured long address of the given device
*
* @param[in] dev device to read from
* @param[out] addr the long address will be stored here
*
* @return the currently set (8-byte) long address
*/
void at86rf2xx_get_addr_long(const at86rf2xx_t *dev, eui64_t *addr);
/**
* @brief Set the long address of the given device
*
@ -364,40 +345,6 @@ void at86rf2xx_get_addr_long(const at86rf2xx_t *dev, eui64_t *addr);
*/
void at86rf2xx_set_addr_long(at86rf2xx_t *dev, const eui64_t *addr);
/**
* @brief Get the configured channel number of the given device
*
* @param[in] dev device to read from
*
* @return the currently set channel number
*/
uint8_t at86rf2xx_get_chan(const at86rf2xx_t *dev);
/**
* @brief Set the channel number of the given device
*
* @param[in,out] dev device to write to
* @param[in] chan channel number to set
*/
void at86rf2xx_set_chan(at86rf2xx_t *dev, uint8_t chan);
/**
* @brief Get the configured channel page of the given device
*
* @param[in] dev device to read from
*
* @return the currently set channel page
*/
uint8_t at86rf2xx_get_page(const at86rf2xx_t *dev);
/**
* @brief Set the channel page of the given device
*
* @param[in,out] dev device to write to
* @param[in] page channel page to set
*/
void at86rf2xx_set_page(at86rf2xx_t *dev, uint8_t page);
/**
* @brief Get the PHY mode of the given device
*
@ -431,15 +378,6 @@ uint8_t at86rf2xx_get_rate(at86rf2xx_t *dev);
*/
int at86rf2xx_set_rate(at86rf2xx_t *dev, uint8_t rate);
/**
* @brief Get the configured PAN ID of the given device
*
* @param[in] dev device to read from
*
* @return the currently set PAN ID
*/
uint16_t at86rf2xx_get_pan(const at86rf2xx_t *dev);
/**
* @brief Set the PAN ID of the given device
*
@ -448,15 +386,6 @@ uint16_t at86rf2xx_get_pan(const at86rf2xx_t *dev);
*/
void at86rf2xx_set_pan(at86rf2xx_t *dev, uint16_t pan);
/**
* @brief Get the configured transmission power of the given device [in dBm]
*
* @param[in] dev device to read from
*
* @return configured transmission power in dBm
*/
int16_t at86rf2xx_get_txpower(const at86rf2xx_t *dev);
/**
* @brief Set the transmission power of the given device [in dBm]
*
@ -467,8 +396,9 @@ int16_t at86rf2xx_get_txpower(const at86rf2xx_t *dev);
*
* @param[in] dev device to write to
* @param[in] txpower transmission power in dBm
* @param[in] channel the current channel
*/
void at86rf2xx_set_txpower(const at86rf2xx_t *dev, int16_t txpower);
void at86rf2xx_set_txpower(const at86rf2xx_t *dev, int16_t txpower, uint8_t channel);
/**
* @brief Get the configured receiver sensitivity of the given device [in dBm]
@ -601,20 +531,6 @@ void at86rf2xx_set_option(at86rf2xx_t *dev, uint16_t option, bool state);
*/
uint8_t at86rf2xx_set_state(at86rf2xx_t *dev, uint8_t state);
/**
* @brief Convenience function for simply sending data
*
* @note This function ignores the PRELOADING option
*
* @param[in,out] dev device to use for sending
* @param[in] data data to send (must include IEEE802.15.4 header)
* @param[in] len length of @p data
*
* @return number of bytes that were actually send
* @return 0 on error
*/
size_t at86rf2xx_send(at86rf2xx_t *dev, const uint8_t *data, size_t len);
/**
* @brief Prepare for sending of data
*