cleaned up and added licenses

bug_fixes_integration_tx
David Michaeli 2021-06-18 15:45:15 +03:00
rodzic c633ca456b
commit 1ff0fec2a0
43 zmienionych plików z 38 dodań i 15308 usunięć

2
docs/README.md 100644
Wyświetl plik

@ -0,0 +1,2 @@
# License
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International License</a>.

Wyświetl plik

@ -1,2 +1,5 @@
# CaribouLite FPGA Firmware
TBD
# License
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.

Wyświetl plik

@ -1,2 +1,5 @@
# Raspberry Pi Script Definitions
TBD
# Raspberry Pi Scripts
TBD
# License
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.

Wyświetl plik

@ -1,2 +1,5 @@
# CaribouLite Software
TBD
TBD
# License
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.

Wyświetl plik

@ -1,2 +1,5 @@
# CaribouLite SoapiSDR Driver
TODO
# License
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.

Wyświetl plik

@ -1,2 +1,5 @@
# RPI SDR Soapy Driver
TODO
# License
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.

Wyświetl plik

@ -1,2 +1,6 @@
# CaribouLite RPI Low-Level API
TODO
# License
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.

Wyświetl plik

@ -1,377 +0,0 @@
/*
* Copyright (C) 2019 ML!PA Consulting GmbH
*
* 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.
*/
/**
* @ingroup drivers_at86rf215
* @{
*
* @file
* @brief Implementation of public functions for AT86RF215 driver
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
* @}
*/
#include <errno.h>
//#include "board.h"
#include "byteorder.h"
//#include "net/ieee802154.h"
//#include "net/gnrc.h"
//#include "unaligned.h"
#include "at86rf215_internal.h"
//#include "at86rf215_netdev.h"
//#include "kernel_defines.h"
#define ENABLE_DEBUG 0
#include "debug.h"
static void _setup_interface(at86rf215_t *dev, const at86rf215_params_t *params, uint8_t index)
{
netdev_t *netdev = (netdev_t *)dev;
netdev->driver = &at86rf215_driver;
dev->params = *params;
dev->state = AT86RF215_STATE_OFF;
netdev_register(netdev, NETDEV_AT86RF215, index);
}
void at86rf215_setup(at86rf215_t *dev_09, at86rf215_t *dev_24, const at86rf215_params_t *params, uint8_t index)
{
/* configure the sub-GHz interface */
if (dev_09) {
dev_09->RF = &RF09_regs;
dev_09->BBC = &BBC0_regs;
_setup_interface(dev_09, params, 2 * index);
dev_09->sibling = dev_24;
}
/* configure the 2.4 GHz interface */
if (dev_24) {
dev_24->RF = &RF24_regs;
dev_24->BBC = &BBC1_regs;
_setup_interface(dev_24, params, 2 * index + 1);
dev_24->sibling = dev_09;
}
}
void at86rf215_reset_and_cfg(at86rf215_t *dev)
{
netdev_ieee802154_reset(&dev->netdev);
/* set device address */
netdev_ieee802154_setup(&dev->netdev);
if (is_subGHz(dev)) {
dev->netdev.chan = CONFIG_AT86RF215_DEFAULT_SUBGHZ_CHANNEL;
} else {
dev->netdev.chan = CONFIG_AT86RF215_DEFAULT_CHANNEL;
}
dev->netdev.pan = CONFIG_IEEE802154_DEFAULT_PANID;
/* set default options */
dev->retries_max = AT86RF215_RETRIES_MAX_DEFAULT;
dev->csma_retries_max = AT86RF215_CSMA_RETRIES_MAX_DEFAULT;
dev->csma_maxbe = AT86RF215_CSMA_MAX_BE_DEFAULT;
dev->csma_minbe = AT86RF215_CSMA_MIN_BE_DEFAULT;
dev->flags |= AT86RF215_OPT_AUTOACK
| AT86RF215_OPT_CSMA
#if CONFIG_AT86RF215_RPC
| AT86RF215_OPT_RPC
#endif
;
/* apply the configuration */
at86rf215_reset(dev);
/* default to requesting ACKs, just like at86rf2xx */
const netopt_enable_t enable = NETOPT_ENABLE;
netdev_ieee802154_set(&dev->netdev, NETOPT_ACK_REQ, &enable, sizeof(enable));
/* enable RX start IRQs */
at86rf215_reg_or(dev, dev->BBC->RG_IRQM, BB_IRQ_RXAM);
}
void at86rf215_reset(at86rf215_t *dev)
{
uint8_t reg;
dev->state = AT86RF215_STATE_OFF;
/* Reset state machine to ensure a known state */
at86rf215_rf_cmd(dev, CMD_RF_TRXOFF);
at86rf215_await_state(dev, RF_STATE_TRXOFF);
if (!dev->sibling) {
/* disable 2.4-GHz IRQs if the interface is not enabled */
if (is_subGHz(dev)) {
at86rf215_reg_write(dev, RG_BBC1_IRQM, 0);
at86rf215_reg_write(dev, RG_RF24_IRQM, 0);
at86rf215_reg_write(dev, RG_RF24_CMD, CMD_RF_SLEEP);
/* disable sub-GHz IRQs if the interface is not enabled */
} else {
at86rf215_reg_write(dev, RG_BBC0_IRQM, 0);
at86rf215_reg_write(dev, RG_RF09_IRQM, 0);
at86rf215_reg_write(dev, RG_RF09_CMD, CMD_RF_SLEEP);
}
}
/* enable clock output */
at86rf215_reg_write(dev, RG_RF_CLKO, 0);
/* allow to configure board-specific trim */
//at86rf215_set_trim(dev, CONFIG_AT86RF215_TRIM_VAL);
/* enable TXFE & RXFE IRQ */
at86rf215_reg_write(dev, dev->BBC->RG_IRQM, BB_IRQ_TXFE | BB_IRQ_RXFE);
/* enable EDC IRQ */
at86rf215_reg_write(dev, dev->RF->RG_IRQM, RF_IRQ_EDC | RF_IRQ_TRXRDY);
/* set energy detect threshold to -84 dBm */
at86rf215_set_cca_threshold(dev, AT86RF215_EDT_DEFAULT);
/* enable address filter 0 */
at86rf215_reg_write(dev, dev->BBC->RG_AFC0, AFC0_AFEN0_MASK );
at86rf215_reg_write(dev, dev->BBC->RG_AMAACKPD, AMAACKPD_PD0_MASK);
/* enable auto-ACK with Frame Checksum & Data Rate derived from RX frame */
reg = AMCS_AACKFA_MASK | AMCS_AACKDR_MASK;
if (dev->flags & AT86RF215_OPT_AUTOACK) {
reg |= AMCS_AACK_MASK;
}
at86rf215_reg_write(dev, dev->BBC->RG_AMCS, reg);
if (CONFIG_AT86RF215_DEFAULT_PHY_MODE == IEEE802154_PHY_OQPSK) {
at86rf215_configure_legacy_OQPSK(dev, CONFIG_AT86RF215_DEFAULT_OQPSK_RATE);
}
if (CONFIG_AT86RF215_DEFAULT_PHY_MODE == IEEE802154_PHY_MR_OQPSK) {
at86rf215_configure_OQPSK(dev, CONFIG_AT86RF215_DEFAULT_MR_OQPSK_CHIPS,
CONFIG_AT86RF215_DEFAULT_MR_OQPSK_RATE);
}
if (CONFIG_AT86RF215_DEFAULT_PHY_MODE == IEEE802154_PHY_MR_OFDM) {
at86rf215_configure_OFDM(dev, CONFIG_AT86RF215_DEFAULT_MR_OFDM_OPT,
CONFIG_AT86RF215_DEFAULT_MR_OFDM_MCS);
}
if (CONFIG_AT86RF215_DEFAULT_PHY_MODE == IEEE802154_PHY_MR_FSK) {
at86rf215_configure_FSK(dev, CONFIG_AT86RF215_DEFAULT_MR_FSK_SRATE,
CONFIG_AT86RF215_DEFAULT_MR_FSK_MOD_IDX,
CONFIG_AT86RF215_DEFAULT_MR_FSK_MORD,
CONFIG_AT86RF215_DEFAULT_MR_FSK_FEC);
}
/* set default channel */
at86rf215_set_chan(dev, dev->netdev.chan);
/* set short and long address */
uint64_t long_addr;
memcpy(&long_addr, dev->netdev.long_addr, sizeof(long_addr));
at86rf215_set_addr_long(dev, long_addr);
at86rf215_set_addr_short(dev, 0, unaligned_get_u16(dev->netdev.short_addr));
/* set default PAN id */
at86rf215_set_pan(dev, 0, dev->netdev.pan);
/* set default TX power */
at86rf215_set_txpower(dev, CONFIG_AT86RF215_DEFAULT_TXPOWER);
/* start listening for incoming packets */
at86rf215_rf_cmd(dev, CMD_RF_RX);
at86rf215_await_state(dev, RF_STATE_RX);
dev->state = AT86RF215_STATE_IDLE;
}
ssize_t at86rf215_send(at86rf215_t *dev, const void *data, size_t len)
{
/* check data length */
if (len > AT86RF215_MAX_PKT_LENGTH) {
DEBUG("[at86rf215] Error: data to send exceeds max packet size\n");
return -EOVERFLOW;
}
if (at86rf215_tx_prepare(dev)) {
return -EBUSY;
}
at86rf215_tx_load(dev, data, len, 0);
at86rf215_tx_exec(dev);
return len;
}
void at86rf215_tx_done(at86rf215_t *dev)
{
uint8_t amcs = at86rf215_reg_read(dev, dev->BBC->RG_AMCS);
/* re-enable AACK, disable TX2RX */
amcs &= ~AMCS_TX2RX_MASK;
if (dev->flags & AT86RF215_OPT_AUTOACK) {
amcs |= AMCS_AACK_MASK;
}
at86rf215_reg_write(dev, dev->BBC->RG_AMCS, amcs);
}
static bool _tx_ongoing(at86rf215_t *dev)
{
if (dev->flags & AT86RF215_OPT_TX_PENDING) {
return true;
}
/* we can still fill the TX buffer and queue TX
when in AT86RF215_STATE_RX_SEND_ACK */
if (dev->state == AT86RF215_STATE_TX ||
dev->state == AT86RF215_STATE_TX_WAIT_ACK) {
return true;
}
return false;
}
/*
* As there is no packet queue in RIOT we have to block in send()
* when the device is busy sending a previous frame.
*
* Since both _send() and _isr() are running in the same thread
* we have to service radio events while waiting in order to
* advance the previous transmission.
*/
static void _block_while_busy(at86rf215_t *dev)
{
gpio_irq_disable(dev->params.int_pin);
do {
if (gpio_read(dev->params.int_pin) || dev->timeout) {
at86rf215_driver.isr((netdev_t *) dev);
}
/* allow the other interface to process events */
thread_yield();
} while (_tx_ongoing(dev));
gpio_irq_enable(dev->params.int_pin);
}
static void at86rf215_block_while_busy(at86rf215_t *dev)
{
if (!IS_ACTIVE(MODULE_AT86RF215_BLOCKING_SEND)) {
return;
}
if (_tx_ongoing(dev)) {
DEBUG("[at86rf215] Block while TXing\n");
_block_while_busy(dev);
}
}
int at86rf215_tx_prepare(at86rf215_t *dev)
{
if (dev->state == AT86RF215_STATE_SLEEP) {
return -EAGAIN;
}
if (!IS_ACTIVE(MODULE_AT86RF215_BLOCKING_SEND) && _tx_ongoing(dev)) {
return -EBUSY;
} else {
at86rf215_block_while_busy(dev);
}
dev->tx_frame_len = IEEE802154_FCS_LEN;
return 0;
}
size_t at86rf215_tx_load(at86rf215_t *dev, const uint8_t *data,
size_t len, size_t offset)
{
/* set bit if ACK was requested and retransmission is enabled */
if (offset == 0 && (data[0] & IEEE802154_FCF_ACK_REQ) && dev->retries_max) {
dev->flags |= AT86RF215_OPT_ACK_REQUESTED;
}
at86rf215_reg_write_bytes(dev, dev->BBC->RG_FBTXS + offset, data, len);
dev->tx_frame_len += (uint16_t) len;
return offset + len;
}
int at86rf215_tx_exec(at86rf215_t *dev)
{
/* write frame length */
at86rf215_reg_write16(dev, dev->BBC->RG_TXFLL, dev->tx_frame_len);
dev->retries = dev->retries_max;
dev->csma_retries = dev->csma_retries_max;
dev->flags |= AT86RF215_OPT_TX_PENDING;
if ((dev->flags & AT86RF215_OPT_CSMA) && !(dev->flags & AT86RF215_OPT_CCATX)) {
dev->flags |= AT86RF215_OPT_CCA_PENDING;
}
if (dev->state == AT86RF215_STATE_IDLE) {
at86rf215_rf_cmd(dev, CMD_RF_TXPREP);
} else {
DEBUG("[at86rf215] will TX after %s\n", at86rf215_sw_state2a(dev->state));
}
return 0;
}
void at86rf215_tx_abort(at86rf215_t *dev)
{
dev->flags &= ~(AT86RF215_OPT_CCA_PENDING | AT86RF215_OPT_TX_PENDING);
at86rf215_tx_done(dev);
at86rf215_enable_baseband(dev);
at86rf215_rf_cmd(dev, CMD_RF_RX);
dev->state = AT86RF215_STATE_IDLE;
}
bool at86rf215_cca(at86rf215_t *dev)
{
bool clear;
uint8_t old_state;
if (dev->state != AT86RF215_STATE_IDLE) {
return false;
}
if (dev->flags & AT86RF215_OPT_TX_PENDING) {
return false;
}
if (!at86rf215_set_rx_from_idle(dev, &old_state)) {
return false;
}
/* disable ED IRQ, baseband */
at86rf215_reg_and(dev, dev->RF->RG_IRQM, ~(RF_IRQ_EDC | RF_IRQ_TRXRDY));
at86rf215_reg_and(dev, dev->BBC->RG_PC, ~PC_BBEN_MASK);
at86rf215_disable_rpc(dev);
/* start energy detect */
at86rf215_reg_write(dev, dev->RF->RG_EDC, RF_EDSINGLE);
while (!(at86rf215_reg_read(dev, dev->RF->RG_IRQS) & RF_IRQ_EDC)) {}
clear = !(at86rf215_reg_read(dev, dev->BBC->RG_AMCS) & AMCS_CCAED_MASK);
/* enable ED IRQ, baseband */
at86rf215_reg_or(dev, dev->RF->RG_IRQM, RF_IRQ_EDC | RF_IRQ_TRXRDY);
at86rf215_reg_or(dev, dev->BBC->RG_PC, PC_BBEN_MASK);
at86rf215_enable_rpc(dev);
at86rf215_set_idle_from_rx(dev, old_state);
return clear;
}

Wyświetl plik

@ -1,654 +0,0 @@
/*
* Copyright (C) 2019 2019 ML!PA Consulting GmbH
*
* 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.
*/
/**
* @defgroup drivers_at86rf215 AT86RF215 based drivers
* @ingroup drivers_netdev
*
* This module contains a driver for the Atmel AT86RF215 radio.
*
* @{
*
* @file
* @brief Interface definition for AT86RF215 based drivers
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*/
#ifndef AT86RF215_H
#define AT86RF215_H
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Registers for the Radio Frontend
*/
typedef struct at86rf215_RF_regs at86rf215_RF_regs_t;
/**
* @brief Registers for the BaseBand Controller
*/
typedef struct at86rf215_BBC_regs at86rf215_BBC_regs_t;
/**
* @brief Signature for the Battery monitor callback.
*
* @param[in] arg optional argument which is passed to the
* callback
*/
typedef void (*at86rf215_batmon_cb_t)(void *arg);
/**
* @brief MR-O-QPSK chip rates (kChip/s)
*/
enum {
AT86RF215_FCHIP_100,
AT86RF215_FCHIP_200,
AT86RF215_FCHIP_1000,
AT86RF215_FCHIP_2000,
};
/**
* @brief Maximum possible packet size in byte
*/
#define AT86RF215_MAX_PKT_LENGTH (2047)
/**
* @defgroup drivers_at86rf215_config AT86RF215 driver compile configuration
* @ingroup config_drivers_netdev
* @{
*/
/**
* @brief Set to 1 if the clock output of the AT86RF215 is used
* as a clock source on the board.
* Otherwise it is turned off to save energy.
*/
#ifdef DOXYGEN
#define CONFIG_AT86RF215_USE_CLOCK_OUTPUT
#endif
#if defined(DOXYGEN) && !defined(CONFIG_AT86RF215_TRIM_VAL)
/**
* @brief Trim value for the external crystal oscillator.
*
* Each increment adds 300nF capacitance between the crystal oscillator pins
* TCXO and XTAL2.
*
* Range: 0..15
*
* Use in conjunction with @see CONFIG_AT86RF215_USE_CLOCK_OUTPUT and a frequency
* meter connected to the clock output pin of the AT86RF215.
* Tweak the value until the measured clock output matches 26 MHz the best.
*/
#define CONFIG_AT86RF215_TRIM_VAL (0)
#endif
/**
* @name Channel configuration
* @{
*/
#ifndef CONFIG_AT86RF215_DEFAULT_CHANNEL
#define CONFIG_AT86RF215_DEFAULT_CHANNEL (CONFIG_IEEE802154_DEFAULT_CHANNEL)
#endif
#ifndef CONFIG_AT86RF215_DEFAULT_SUBGHZ_CHANNEL
#define CONFIG_AT86RF215_DEFAULT_SUBGHZ_CHANNEL (CONFIG_IEEE802154_DEFAULT_SUBGHZ_CHANNEL)
#endif
/** @} */
/**
* @name Enable Reduced Power Consumption
* @{
*/
#ifndef CONFIG_AT86RF215_RPC_EN
#define CONFIG_AT86RF215_RPC_EN (0)
#endif
/** @} */
/**
* @name Default Battery Monitor trigger threshold (in mV)
* if battery monitoring is enabled
* @{
*/
#ifndef CONFIG_AT86RF215_BATMON_THRESHOLD
#define CONFIG_AT86RF215_BATMON_THRESHOLD (1800)
#endif
/** @} */
/**
* @name Default PHY Mode
* @{
*/
#define CONFIG_AT86RF215_DEFAULT_PHY_MODE (IEEE802154_PHY_OQPSK)
/** @} */
/**
* @name Default O-QPSK Rate Mode
* Non-zero value enables proprietary high data rate by default
* @{
*/
#ifndef CONFIG_AT86RF215_DEFAULT_OQPSK_RATE
#define CONFIG_AT86RF215_DEFAULT_OQPSK_RATE (0)
#endif
/** @} */
/**
* @name Default MR-O-QPSK Chip Rate
* @{
*/
#define CONFIG_AT86RF215_DEFAULT_MR_OQPSK_CHIPS (AT86RF215_FCHIP_1000)
/** @} */
/**
* @name Default MR-O-QPSK Rate Mode
* @{
*/
#ifndef CONFIG_AT86RF215_DEFAULT_MR_OQPSK_RATE
#define CONFIG_AT86RF215_DEFAULT_MR_OQPSK_RATE (2)
#endif
/** @} */
/**
* @name Default MR-OFDM Option
* @{
*/
#ifndef CONFIG_AT86RF215_DEFAULT_MR_OFDM_OPT
#define CONFIG_AT86RF215_DEFAULT_MR_OFDM_OPT (2)
#endif
/** @} */
/**
* @name Default MR-OFDM Modulation & Coding Scheme
* @{
*/
#ifndef CONFIG_AT86RF215_DEFAULT_MR_OFDM_MCS
#define CONFIG_AT86RF215_DEFAULT_MR_OFDM_MCS (2)
#endif
/** @} */
/**
* @name Default MR-FSK Symbol Rate
* @{
*/
#ifndef CONFIG_AT86RF215_DEFAULT_MR_FSK_SRATE
#define CONFIG_AT86RF215_DEFAULT_MR_FSK_SRATE FSK_SRATE_200K
#endif
/** @} */
/**
* @name Default MR-FSK Modulation Index, fraction of 64
* @{
*/
#ifndef CONFIG_AT86RF215_DEFAULT_MR_FSK_MOD_IDX
#define CONFIG_AT86RF215_DEFAULT_MR_FSK_MOD_IDX (64)
#endif
/** @} */
/**
* @name Default MR-FSK Modulation Order
* @{
*/
#ifndef CONFIG_AT86RF215_DEFAULT_MR_FSK_MORD
#define CONFIG_AT86RF215_DEFAULT_MR_FSK_MORD FSK_MORD_4SFK
#endif
/** @} */
/**
* @name Default MR-FSK Forward Error Correction Scheme
* @{
*/
#ifndef CONFIG_AT86RF215_DEFAULT_MR_FSK_FEC
#define CONFIG_AT86RF215_DEFAULT_MR_FSK_FEC IEEE802154_FEC_NONE
#endif
/** @} */
/**
* @brief Default TX power (0dBm)
*/
#ifndef CONFIG_AT86RF215_DEFAULT_TXPOWER
#define CONFIG_AT86RF215_DEFAULT_TXPOWER (CONFIG_IEEE802154_DEFAULT_TXPOWER)
#endif
/** @} */
/**
* @name Flags for device internal states (see datasheet)
* @{
*/
typedef enum {
AT86RF215_STATE_OFF, /**< radio not configured */
AT86RF215_STATE_IDLE, /**< idle state, listening */
AT86RF215_STATE_RX_SEND_ACK,/**< receiving frame, sending ACK */
AT86RF215_STATE_TX, /**< sending frame */
AT86RF215_STATE_TX_WAIT_ACK,/**< sending frame, wait for ACK */
AT86RF215_STATE_SLEEP /**< sleep mode, not listening */
} at86rf215_state_t;
/** @} */
enum {
AT86RF215_MODE_LEGACY_OQPSK,
AT86RF215_MODE_MR_OQPSK,
AT86RF215_MODE_MR_OFDM,
AT86RF215_MODE_MR_FSK
};
/**
* @name Clock Output Driver Strength
* @{
*/
typedef enum {
AT86RF215_CLKO_2mA = 0 << 3, /**< 2 mA */
AT86RF215_CLKO_4mA = 1 << 3, /**< 4 mA */
AT86RF215_CLKO_6mA = 2 << 3, /**< 6 mA */
AT86RF215_CLKO_8mA = 3 << 3, /**< 8 mA */
} at86rf215_clko_cur_t;
/** @} */
/**
* @name Clock Output Frequency
* @{
*/
typedef enum {
AT86RF215_CLKO_OFF = 0, /**< Clock Output Disabled */
AT86RF215_CLKO_26_MHz, /**< 26 MHz */
AT86RF215_CLKO_32_MHz, /**< 32 MHz */
AT86RF215_CLKO_16_MHz, /**< 16 MHz */
AT86RF215_CLKO_8_MHz, /**< 8 MHz */
AT86RF215_CLKO_4_MHz, /**< 4 MHz */
AT86RF215_CLKO_2_MHz, /**< 2 MHz */
AT86RF215_CLKO_1_MHz, /**< 1 MHz */
} at86rf215_clko_freq_t;
/**
* @name Internal device option flags
* @{
*/
#define AT86RF215_OPT_CSMA (0x0010) /**< CSMA active */
#define AT86RF215_OPT_PROMISCUOUS (0x0020) /**< promiscuous mode active */
#define AT86RF215_OPT_PRELOADING (0x0040) /**< preloading enabled */
#define AT86RF215_OPT_AUTOACK (0x0080) /**< Auto ACK active */
#define AT86RF215_OPT_ACK_REQUESTED (0x0100) /**< ACK requested for current frame */
#define AT86RF215_OPT_AGCH (0x0200) /**< AGC Hold active */
#define AT86RF215_OPT_TX_PENDING (0x0400) /**< Frame is loaded into TX buffer */
#define AT86RF215_OPT_CCA_PENDING (0x0800) /**< CCA needs to be done for the current frame */
#define AT86RF215_OPT_RPC (0x1000) /**< Enable Reduced Power Consumption */
#define AT86RF215_OPT_CCATX (0x2000) /**< TX after CCA performd automatically */
/** @} */
/**
* @name Internal timeout flags
* @{
*/
#define AT86RF215_TIMEOUT_ACK (0x0001) /**< ACK timeout */
#define AT86RF215_TIMEOUT_CSMA (0x0002) /**< CMSA timeout */
/** @} */
/**
* @brief struct holding all params needed for device initialization
*/
typedef struct at86rf215_params {
int spi; /**< SPI bus the device is connected to */
int spi_clk; /**< SPI clock speed to use */
int cs_pin; /**< GPIO pin connected to chip select */
int int_pin; /**< GPIO pin connected to the interrupt pin */
int reset_pin; /**< GPIO pin connected to the reset pin */
} at86rf215_params_t;
/**
* @brief Device descriptor for AT86RF215 radio devices
*
* @extends netdev_ieee802154_t
*/
typedef struct at86rf215
{
/* device specific fields */
at86rf215_params_t params; /**< parameters for initialization */
struct at86rf215 *sibling; /**< The other radio */
const at86rf215_RF_regs_t *RF; /**< Radio Frontend Registers */
const at86rf215_BBC_regs_t *BBC; /**< Baseband Registers */
uint32_t ack_timeout_usec; /**< time to wait before retransmission in µs */
uint32_t csma_backoff_period; /**< CSMA Backoff period */
uint16_t flags; /**< Device specific flags */
uint16_t num_chans; /**< Number of legal channel at current modulation */
uint16_t tx_frame_len; /**< length of the current TX frame */
uint8_t timeout; /**< indicates which timeout was reached */
uint8_t state; /**< current state of the radio */
uint8_t retries_max; /**< number of retries until ACK is received */
uint8_t retries; /**< retries left */
uint8_t csma_retries_max; /**< number of retries until channel is clear */
uint8_t csma_retries; /**< CSMA retries left */
uint8_t fsk_pl; /**< FSK Preamble Length */
uint8_t csma_minbe; /**< CSMA minimum backoff exponent */
uint8_t csma_maxbe; /**< CSMA maximum backoff exponent */
int8_t csma_ed; /**< CSMA energy detect threshold */
} at86rf215_t;
/**
* @brief Setup an AT86RF215 based device state
*
* @param[out] dev_09 sub-GHz device descriptor
* @param[out] dev_24 2.4 GHz device descriptor
* @param[in] params parameters for device initialization
* @param[in] index index of @p params in a global parameter struct array.
* If initialized manually, pass a unique identifier instead.
*/
void at86rf215_setup(at86rf215_t *dev_09, at86rf215_t *dev_24, const at86rf215_params_t *params, uint8_t index);
/**
* @brief Trigger a hardware reset and configure radio with default values.
*
* @param[in,out] dev device to configure
*/
void at86rf215_reset_and_cfg(at86rf215_t *dev);
/**
* @brief Trigger a hardware reset, configuration is retained.
*
* @param[in,out] dev device to reset
*/
void at86rf215_reset(at86rf215_t *dev);
/**
* @brief Get the short address of the given device form multi address filter
*
* @param[in] dev device to read from
* @param[in] filter address filter to read
*
* @return the currently set (2-byte) short address
*/
uint16_t at86rf215_get_addr_short(const at86rf215_t *dev, uint8_t filter);
/**
* @brief Set the short address of the given device to multi address filter
*
* @param[in,out] dev device to write to
* @param[in] filter (1-byte) address filter to set
* @param[in] addr (2-byte) short address to set
*/
void at86rf215_set_addr_short(at86rf215_t *dev, uint8_t filter, uint16_t addr);
/**
* @brief Get whether a frame filter is enabled or not
*
* @param[in] dev device to read from
* @param[in] filter (1-byte) filter to get
*
* @return (bool) the current state of the filter
*/
bool at86rf215_get_framefilter_enabled(at86rf215_t *dev, uint8_t filter);
/**
* @brief Enables a frame filter
*
* @param[in] dev device to read from
* @param[in] filter (1-byte) filter to get
*
*/
void at86rf215_disable_framefilter(at86rf215_t *dev, uint8_t filter);
/**
* @brief Disables a frame filter
*
* @param[in] dev device to read from
* @param[in] filter (1-byte) filter to get
*
*/
void at86rf215_enable_framefilter(at86rf215_t *dev, uint8_t filter);
/**
* @brief Get the configured long address of the given device
*
* @param[in] dev device to read from
*
* @return the currently set (8-byte) long address
*/
uint64_t at86rf215_get_addr_long(const at86rf215_t *dev);
/**
* @brief Set the long address of the given device
*
* @param[in,out] dev device to write to
* @param[in] addr (8-byte) long address to set
*/
void at86rf215_set_addr_long(at86rf215_t *dev, uint64_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 at86rf215_get_chan(const at86rf215_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 at86rf215_set_chan(at86rf215_t *dev, uint16_t chan);
/**
* @brief Get the configured PAN ID of the given device from multi address filter
*
* @param[in] dev device to read from
* @param[in] filter address filter to read from
*
* @return the currently set PAN ID
*/
uint16_t at86rf215_get_pan(const at86rf215_t *dev, uint8_t filter);
/**
* @brief Set the PAN ID of the given address filter
*
* @param[in,out] dev device to write to
* @param[in] filter address filter to set
* @param[in] pan PAN ID to set
*/
void at86rf215_set_pan(at86rf215_t *dev, uint8_t filter, 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 at86rf215_get_txpower(const at86rf215_t *dev);
/**
* @brief Set the transmission power of the given device [in dBm]
*
* If the device does not support the exact dBm value given, it will set a value
* as close as possible to the given value. If the given value is larger or
* lower then the maximal or minimal possible value, the min or max value is
* set, respectively.
*
* @param[in] dev device to write to
* @param[in] txpower transmission power in dBm
*/
void at86rf215_set_txpower(const at86rf215_t *dev, int16_t txpower);
/**
* @brief Get the CCA threshold value
*
* @param[in] dev device to read value from
*
* @return the current CCA threshold value
*/
int8_t at86rf215_get_cca_threshold(const at86rf215_t *dev);
/**
* @brief Set the CCA threshold value
*
* @param[in] dev device to write to
* @param[in] value the new CCA threshold value
*/
void at86rf215_set_cca_threshold(at86rf215_t *dev, int8_t value);
/**
* @brief Get the latest ED level measurement
*
* @param[in] dev device to read value from
*
* @return the last ED level
*/
int8_t at86rf215_get_ed_level(at86rf215_t *dev);
/**
* @brief Enable or disable driver specific options
*
* @param[in,out] dev device to set/clear option flag for
* @param[in] option option to enable/disable
* @param[in] state true for enable, false for disable
*/
void at86rf215_set_option(at86rf215_t *dev, uint16_t option, bool state);
/**
* @brief Set crystal oscillator trim value.
*
* An internal capacitance array is connected to the
* crystal oscillator pins TCXO and XTAL2.
*
* Each increment of the trim value adds 0.3pF capacitance
* to the oscillator circuit.
*
* To trim a board, enable the clock output with
* @ref at86rf215_set_clock_output and connect a frequency
* counter to the clock output pin.
* Then adjust the trim value until it the measured frequency
* closely matches the configured output frequency.
*
* It is recommended to use a 26 MHz output frequency for the
* test as this is the raw frequency of the external oscillator.
*
* The resulting trim value must then be stored in a persistent
* memory area of the board to be set via @ref CONFIG_AT86RF215_TRIM_VAL
*
* @param[in] dev device to configure
* @param[in] trim trim value
*/
void at86rf215_set_trim(at86rf215_t *dev, uint8_t trim);
/**
* @brief Configure the Clock Output pin
*
* @param[in] dev device to configure
* @param[in] cur Clock output current
* @param[in] freq Clock output frequency
*/
void at86rf215_set_clock_output(at86rf215_t *dev,
at86rf215_clko_cur_t cur, at86rf215_clko_freq_t freq);
/**
* @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 or negative error code
*/
ssize_t at86rf215_send(at86rf215_t *dev, const void *data, size_t len);
/**
* @brief Prepare for sending of data
*
* This function puts the given device into the TX state, so no receiving of
* data is possible after it was called.
*
* @param[in,out] dev device to prepare for sending
*
* @return 0 on success, error otherwise
*/
int at86rf215_tx_prepare(at86rf215_t *dev);
/**
* @brief Load chunks of data into the transmit buffer of the given device
*
* @param[in,out] dev device to write data to
* @param[in] data buffer containing the data to load
* @param[in] len number of bytes in @p buffer
* @param[in] offset offset used when writing data to internal buffer
*
* @return offset + number of bytes written
*/
size_t at86rf215_tx_load(at86rf215_t *dev, const uint8_t *data,
size_t len, size_t offset);
/**
* @brief Trigger sending of data previously loaded into transmit buffer
*
* @param[in] dev device to trigger
*
* @return 0 on success, error otherwise
*/
int at86rf215_tx_exec(at86rf215_t *dev);
/**
* @brief Abort sending of data previously loaded into transmit buffer
*
* @param[in] dev device to abort TX on
*/
void at86rf215_tx_abort(at86rf215_t *dev);
/**
* @brief Signal that the transfer of the frame (and optional ACK reception)
* has finished. Sets the radio in RX mode.
*
* @param[in] dev device to use
*/
void at86rf215_tx_done(at86rf215_t *dev);
/**
* @brief Perform one manual channel clear assessment (CCA)
*
* The CCA mode and threshold level depends on the current transceiver settings.
*
* @param[in] dev device to use
*
* @return true if channel is determined clear
* @return false if channel is determined busy
*/
bool at86rf215_cca(at86rf215_t *dev);
/**
* @brief Generate an interrupt if supply voltage drops below the configured
* threshold.
*
* @param[in] dev device to configure
* @param[in] voltage Threshold voltage in mV
*
* @return 0 on success, error otherwise
*/
int at86rf215_enable_batmon(at86rf215_t *dev, unsigned voltage);
/**
* @brief Disable the Battery Monitor interrupt.
*
* @param[in] dev device to configure
*/
void at86rf215_disable_batmon(at86rf215_t *dev);
#ifdef __cplusplus
}
#endif
#endif /* AT86RF215_H */
/** @} */

Wyświetl plik

@ -1,618 +0,0 @@
/*
* Copyright (C) 2019 ML!PA Consulting GmbH
*
* 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.
*/
/**
* @ingroup drivers_at86rf215
* @{
*
* @file
* @brief Configuration of the MR-FSK PHY on the AT86RF215 chip
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
* @}
*/
#include <errno.h>
#include "at86rf215.h"
#include "at86rf215_internal.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/* symbol time is always 20 µs for MR-FSK (table 0, pg. 7) */
#define FSK_SYMBOL_TIME_US 20
/* also used by at86rf215_netdev.c */
const uint8_t _at86rf215_fsk_srate_10kHz[] = {
[FSK_SRATE_50K] = 5,
[FSK_SRATE_100K] = 10,
[FSK_SRATE_150K] = 15,
[FSK_SRATE_200K] = 20,
[FSK_SRATE_300K] = 30,
[FSK_SRATE_400K] = 40
};
/* also used by at86rf215_netdev.c */
const uint8_t _at86rf215_fsk_channel_spacing_25kHz[] = {
[FSK_CHANNEL_SPACING_200K] = 8,
[FSK_CHANNEL_SPACING_400K] = 16,
};
/* IEEE Std 802.15.4™-2015
* Table 10-10Channel numbering for SUN PHYs,
* index is channel spacing */
static const uint16_t _chan_center_freq0_subghz_25khz[] = {
[FSK_CHANNEL_SPACING_200K] = 863125U / 25,
[FSK_CHANNEL_SPACING_400K] = 863225U / 25
};
/* IEEE Std 802.15.4™-2015
* Table 10-10Channel numbering for SUN PHYs,
* index is channel spacing */
static const uint16_t _chan_center_freq0_24ghz_25khz[] = {
[FSK_CHANNEL_SPACING_200K] = (2400200U - CCF0_24G_OFFSET) / 25,
[FSK_CHANNEL_SPACING_400K] = (2400400U - CCF0_24G_OFFSET) / 25
};
/* Table 6-57, index is symbol rate */
static const uint8_t _FSKPE_Val[3][6] = {
{ 0x02, 0x0E, 0x3E, 0x74, 0x05, 0x13 }, /* FSKPE0 */
{ 0x03, 0x0F, 0x3F, 0x7F, 0x3C, 0x29 }, /* FSKPE1 */
{ 0xFC, 0xF0, 0xC0, 0x80, 0xC3, 0xC7 } /* FSKPE2 */
};
/* table 6-51: Symbol Rate Settings */
static uint8_t _TXDFE_SR(at86rf215_t *dev, uint8_t srate)
{
const uint8_t version = at86rf215_reg_read(dev, RG_RF_VN);
switch (srate) {
case FSK_SRATE_50K:
return version == 1 ? RF_SR_400K : RF_SR_500K;
case FSK_SRATE_100K:
return version == 1 ? RF_SR_800K : RF_SR_1000K;
case FSK_SRATE_150K:
case FSK_SRATE_200K:
return RF_SR_2000K;
case FSK_SRATE_300K:
case FSK_SRATE_400K:
return RF_SR_4000K;
}
return 0;
}
/* table 6-51: Symbol Rate Settings */
static uint8_t _RXDFE_SR(uint8_t srate)
{
switch (srate) {
case FSK_SRATE_50K:
return RF_SR_400K;
case FSK_SRATE_100K:
return RF_SR_800K;
case FSK_SRATE_150K:
case FSK_SRATE_200K:
return RF_SR_1000K;
case FSK_SRATE_300K:
case FSK_SRATE_400K:
return RF_SR_2000K;
}
return 0;
}
/* table 6-53 Recommended Configuration of the Transmitter Frontend */
static uint8_t _TXCUTC_PARAMP(uint8_t srate)
{
switch (srate) {
case FSK_SRATE_50K:
return RF_PARAMP32U;
case FSK_SRATE_100K:
case FSK_SRATE_150K:
case FSK_SRATE_200K:
return RF_PARAMP16U;
case FSK_SRATE_300K:
case FSK_SRATE_400K:
return RF_PARAMP8U;
}
return 0;
}
/* Table 6-53. Recommended Configuration of the Transmitter Frontend (modulation index 0.5) */
static uint8_t _TXCUTC_LPFCUT_half(uint8_t srate)
{
switch (srate) {
case FSK_SRATE_50K:
return RF_FLC80KHZ;
case FSK_SRATE_100K:
return RF_FLC100KHZ;
case FSK_SRATE_150K:
return RF_FLC160KHZ;
case FSK_SRATE_200K:
return RF_FLC200KHZ;
case FSK_SRATE_300K:
return RF_FLC315KHZ;
case FSK_SRATE_400K:
return RF_FLC400KHZ;
}
return 0;
}
/* Table 6-54. Recommended Configuration of the Transmitter Frontend (modulation index 1) */
static uint8_t _TXCUTC_LPFCUT_full(uint8_t srate)
{
switch (srate) {
case FSK_SRATE_50K:
return RF_FLC80KHZ;
case FSK_SRATE_100K:
return RF_FLC160KHZ;
case FSK_SRATE_150K:
return RF_FLC250KHZ;
case FSK_SRATE_200K:
return RF_FLC315KHZ;
case FSK_SRATE_300K:
return RF_FLC500KHZ;
case FSK_SRATE_400K:
return RF_FLC625KHZ;
}
return 0;
}
static inline uint8_t _TXCUTC_LPFCUT(uint8_t srate, bool half)
{
return half ? _TXCUTC_LPFCUT_half(srate) : _TXCUTC_LPFCUT_full(srate);
}
/* Table 6-60. Recommended Configuration values of the sub-1GHz Receiver Frontend (modulation index 1/2) */
static uint8_t _RXBWC_BW_subGHz_half(uint8_t srate)
{
switch (srate) {
case FSK_SRATE_50K:
return RF_BW160KHZ_IF250KHZ;
case FSK_SRATE_100K:
return RF_BW200KHZ_IF250KHZ;
case FSK_SRATE_150K:
case FSK_SRATE_200K:
return RF_BW320KHZ_IF500KHZ;
case FSK_SRATE_300K:
return (RF_BW500KHZ_IF500KHZ | (1 << RXBWC_IFS_SHIFT));
case FSK_SRATE_400K:
return RF_BW630KHZ_IF1000KHZ;
}
return 0;
}
/* Table 6-61. Recommended Configuration values of the 2.4GHz Receiver Frontend (modulation index 1/2) */
static uint8_t _RXBWC_BW_2dot4GHz_half(uint8_t srate)
{
switch (srate) {
case FSK_SRATE_50K:
return RF_BW160KHZ_IF250KHZ;
case FSK_SRATE_100K:
return RF_BW200KHZ_IF250KHZ;
case FSK_SRATE_150K:
return RF_BW320KHZ_IF500KHZ;
case FSK_SRATE_200K:
return RF_BW400KHZ_IF500KHZ;
case FSK_SRATE_300K:
return RF_BW630KHZ_IF1000KHZ;
case FSK_SRATE_400K:
return RF_BW800KHZ_IF1000KHZ;
}
return 0;
}
/* Table 6-62. Recommended Configuration values of the sub-1GHz Receiver Frontend (modulation index 1) */
static uint8_t _RXBWC_BW_subGHz_full(uint8_t srate)
{
switch (srate) {
case FSK_SRATE_50K:
return RF_BW160KHZ_IF250KHZ;
case FSK_SRATE_100K:
return RF_BW320KHZ_IF500KHZ;
case FSK_SRATE_150K:
return RF_BW400KHZ_IF500KHZ;
case FSK_SRATE_200K:
return (RF_BW500KHZ_IF500KHZ | (1 << RXBWC_IFS_SHIFT));
case FSK_SRATE_300K:
return RF_BW630KHZ_IF1000KHZ;
case FSK_SRATE_400K:
return (RF_BW1000KHZ_IF1000KHZ | (1 << RXBWC_IFS_SHIFT));
}
return 0;
}
/* Table 6-63. Recommended Configuration values of the 2.4 GHz Receiver Frontend (modulation index 1) */
static uint8_t _RXBWC_BW_2dot4GHz_full(uint8_t srate)
{
switch (srate) {
case FSK_SRATE_50K:
return RF_BW200KHZ_IF250KHZ;
case FSK_SRATE_100K:
return RF_BW400KHZ_IF500KHZ;
case FSK_SRATE_150K:
case FSK_SRATE_200K:
return RF_BW630KHZ_IF1000KHZ;
case FSK_SRATE_300K:
return RF_BW800KHZ_IF1000KHZ;
case FSK_SRATE_400K:
return (RF_BW1000KHZ_IF1000KHZ | (1 << RXBWC_IFS_SHIFT));
}
return 0;
}
static inline uint8_t _RXBWC_BW(uint8_t srate, bool subGHz, bool half)
{
if (subGHz) {
return half ? _RXBWC_BW_subGHz_half(srate) : _RXBWC_BW_subGHz_full(srate);
} else {
return half ? _RXBWC_BW_2dot4GHz_half(srate) : _RXBWC_BW_2dot4GHz_full(srate);
}
}
static uint8_t _RXDFE_RCUT_half(uint8_t srate, bool subGHz)
{
if (srate == FSK_SRATE_200K) {
return RF_RCUT_FS_BY_5P3;
}
if (srate == FSK_SRATE_400K && !subGHz) {
return RF_RCUT_FS_BY_5P3;
}
return RF_RCUT_FS_BY_8;
}
static uint8_t _RXDFE_RCUT_full(uint8_t srate, bool subGHz)
{
switch (srate) {
case FSK_SRATE_50K:
case FSK_SRATE_100K:
case FSK_SRATE_300K:
return RF_RCUT_FS_BY_5P3;
case FSK_SRATE_150K:
case FSK_SRATE_400K:
return subGHz ? RF_RCUT_FS_BY_5P3 : RF_RCUT_FS_BY_4;
case FSK_SRATE_200K:
return subGHz ? RF_RCUT_FS_BY_4 : RF_RCUT_FS_BY_2P6;
}
return 0;
}
/* Table 6-64. Minimum Preamble Length */
static uint8_t _FSKPL(uint8_t srate)
{
switch (srate) {
case FSK_SRATE_50K:
return 2;
case FSK_SRATE_100K:
return 3;
case FSK_SRATE_150K:
case FSK_SRATE_200K:
case FSK_SRATE_300K:
return 8;
case FSK_SRATE_400K:
return 10;
}
return 0;
}
/* fsk modulation indices / 8 */
static const uint8_t _fsk_mod_idx[] = {
3, 4, 6, 8, 10, 12, 14, 16
};
/* FSK modulation scale / 8 */
static const uint8_t _fsk_mod_idx_scale[] = {
7, 8, 9, 10
};
static void _fsk_mod_idx_get(uint8_t num, uint8_t *idx, uint8_t *scale)
{
*idx = 0;
*scale = 0;
uint8_t diff = 0xFF;
for (uint8_t i = 0; i < ARRAY_SIZE(_fsk_mod_idx_scale); ++i) {
for (uint8_t j = 0; j < ARRAY_SIZE(_fsk_mod_idx); ++j) {
if (abs(num - _fsk_mod_idx_scale[i] * _fsk_mod_idx[j]) < diff) {
diff = abs(num - _fsk_mod_idx_scale[i] * _fsk_mod_idx[j]);
*idx = j;
*scale = i;
}
}
}
}
static inline uint8_t _RXDFE_RCUT(uint8_t srate, bool subGHz, bool half)
{
return half ? _RXDFE_RCUT_half(srate, subGHz) : _RXDFE_RCUT_full(srate, subGHz);
}
void at86rf215_FSK_prepare_rx(at86rf215_t *dev)
{
at86rf215_reg_write(dev, dev->BBC->RG_FSKPLL, dev->fsk_pl);
/* Preamble detection takes RSSI values into account if the preamble length is less than 8 octets. */
if (dev->fsk_pl < 8) {
at86rf215_reg_or(dev, dev->BBC->RG_FSKC2, FSKC2_PDTM_MASK);
} else {
at86rf215_reg_and(dev, dev->BBC->RG_FSKC2, (uint8_t) ~FSKC2_PDTM_MASK);
}
}
void at86rf215_FSK_prepare_tx(at86rf215_t *dev)
{
/* send long preamble when TXing */
at86rf215_reg_write(dev, dev->BBC->RG_FSKPLL, dev->fsk_pl * 8);
}
static void _set_srate(at86rf215_t *dev, uint8_t srate, bool mod_idx_half)
{
/* Set Receiver Bandwidth: fBW = 160 kHz, fIF = 250 kHz */
at86rf215_reg_write(dev, dev->RF->RG_RXBWC, _RXBWC_BW(srate, is_subGHz(dev), mod_idx_half));
/* fS = 400 kHz; fCUT = fS/5.333 = 75 kHz */
at86rf215_reg_write(dev, dev->RF->RG_RXDFE, _RXDFE_SR(srate)
| _RXDFE_RCUT(srate, is_subGHz(dev), mod_idx_half));
/* Power Amplifier Ramp Time = 32 µs; fLPCUT = 80 kHz */
at86rf215_reg_write(dev, dev->RF->RG_TXCUTC, _TXCUTC_PARAMP(srate)
| _TXCUTC_LPFCUT(srate, mod_idx_half));
/* fS = 500 kHz; fCUT = fS/2 = 250 kHz */
at86rf215_reg_write(dev, dev->RF->RG_TXDFE, _TXDFE_SR(dev, srate)
| (mod_idx_half ? RF_RCUT_FS_BY_8 : RF_RCUT_FS_BY_2)
| TXDFE_DM_MASK);
/* configure pre-emphasis */
at86rf215_reg_write(dev, dev->BBC->RG_FSKPE0, _FSKPE_Val[0][srate]);
at86rf215_reg_write(dev, dev->BBC->RG_FSKPE1, _FSKPE_Val[1][srate]);
at86rf215_reg_write(dev, dev->BBC->RG_FSKPE2, _FSKPE_Val[2][srate]);
/* set preamble length in octets */
dev->fsk_pl = _FSKPL(srate);
at86rf215_FSK_prepare_rx(dev);
/* t_on = t_off = t_min (time to TX minimal preamble length) */
uint8_t t_on = 4 * _FSKPL(srate) * 100 / _at86rf215_fsk_srate_10kHz[srate];
at86rf215_reg_write(dev, dev->BBC->RG_FSKRPCONT, t_on);
at86rf215_reg_write(dev, dev->BBC->RG_FSKRPCOFFT, t_on);
DEBUG("[at86rf215] t_on: %d µs\n", t_on);
/* set symbol rate, preamble is less than 256 so set high bits 0 */
at86rf215_reg_write(dev, dev->BBC->RG_FSKC1, srate);
}
static void _set_ack_timeout(at86rf215_t *dev, bool mord4, bool fec)
{
uint8_t ack_len = AT86RF215_ACK_PSDU_BYTES;
/* PHR uses same data rate as PSDU */
ack_len += 2;
/* 4-FSK doubles data rate */
if (mord4) {
ack_len /= 2;
}
/* forward error correction halves data rate */
if (fec) {
ack_len *= 2;
}
dev->ack_timeout_usec = dev->csma_backoff_period
+ IEEE802154G_ATURNAROUNDTIME_US
/* long Preamble + SFD; SFD=2 */
+ ((dev->fsk_pl * 8 + 2)
+ ack_len) * 8 * FSK_SYMBOL_TIME_US;
DEBUG("[%s] ACK timeout: %"PRIu32" µs\n", "FSK", dev->ack_timeout_usec);
}
static void _set_csma_backoff_period(at86rf215_t *dev)
{
dev->csma_backoff_period = IEEE802154_CCA_DURATION_IN_SYMBOLS * FSK_SYMBOL_TIME_US
+ IEEE802154G_ATURNAROUNDTIME_US;
DEBUG("[%s] CSMA BACKOFF: %"PRIu32" µs\n", "FSK", dev->csma_backoff_period);
}
int at86rf215_configure_FSK(at86rf215_t *dev, uint8_t srate, uint8_t mod_idx, uint8_t mod_order, uint8_t fec)
{
if (srate > FSK_SRATE_400K) {
DEBUG("[%s] invalid symbol rate: %d\n", __func__, srate);
return -EINVAL;
}
bool mod_idx_half = mod_idx <= 32;
uint8_t _mod_idx, _mod_idx_scale;
_fsk_mod_idx_get(mod_idx, &_mod_idx, &_mod_idx_scale);
at86rf215_await_state_end(dev, RF_STATE_TX);
/* disable radio */
at86rf215_reg_write(dev, dev->BBC->RG_PC, 0);
_set_srate(dev, srate, mod_idx_half);
/* set receiver gain target according to data sheet */
at86rf215_reg_write(dev, dev->RF->RG_AGCS, 1 << AGCS_TGT_SHIFT);
/* enable automatic receiver gain */
at86rf215_reg_write(dev, dev->RF->RG_AGCC, AGCC_EN_MASK);
/* set Bandwidth Time Product, Modulation Index & Modulation Order */
/* effective modulation index = MIDXS * MIDX */
at86rf215_reg_write(dev, dev->BBC->RG_FSKC0, FSK_BT_20
| (_mod_idx << FSKC0_MIDX_SHIFT)
| (_mod_idx_scale << FSKC0_MIDXS_SHIFT)
| mod_order
);
/* enable direct modulation */
at86rf215_reg_write(dev, dev->BBC->RG_FSKDM, FSKDM_EN_MASK | FSKDM_PE_MASK);
/* 16 µs base time */
uint8_t fskrpc = 0x5;
/* Enable / Disable Reduced Power Consumption */
if (dev->flags & AT86RF215_OPT_RPC) {
fskrpc |= FSKRPC_EN_MASK;
}
at86rf215_reg_write(dev, dev->BBC->RG_FSKRPC, fskrpc);
/* set forward error correction */
at86rf215_FSK_set_fec(dev, fec);
at86rf215_FSK_set_channel_spacing(dev, FSK_CHANNEL_SPACING_400K);
at86rf215_enable_radio(dev, BB_MRFSK);
return 0;
}
uint8_t at86rf215_FSK_get_mod_order(at86rf215_t *dev)
{
return at86rf215_reg_read(dev, dev->BBC->RG_FSKC0) & FSKC0_MORD_MASK;
}
int at86rf215_FSK_set_mod_order(at86rf215_t *dev, uint8_t mod_order) {
at86rf215_await_state_end(dev, RF_STATE_TX);
if (mod_order) {
at86rf215_reg_or(dev, dev->BBC->RG_FSKC0, FSK_MORD_4SFK);
} else {
at86rf215_reg_and(dev, dev->BBC->RG_FSKC0, ~FSK_MORD_4SFK);
}
_set_ack_timeout(dev, mod_order, at86rf215_FSK_get_fec(dev));
return 0;
}
uint8_t at86rf215_FSK_get_mod_idx(at86rf215_t *dev)
{
uint8_t fskc0 = at86rf215_reg_read(dev, dev->BBC->RG_FSKC0);
uint8_t _mod_idx = (fskc0 & FSKC0_MIDX_MASK) >> FSKC0_MIDX_SHIFT;
uint8_t _mod_idx_scale = (fskc0 & FSKC0_MIDXS_MASK) >> FSKC0_MIDXS_SHIFT;
return _fsk_mod_idx[_mod_idx] * _fsk_mod_idx_scale[_mod_idx_scale];
}
int at86rf215_FSK_set_mod_idx(at86rf215_t *dev, uint8_t mod_idx)
{
uint8_t _mod_idx, _mod_idx_scale;
at86rf215_await_state_end(dev, RF_STATE_TX);
_set_srate(dev, at86rf215_FSK_get_srate(dev), mod_idx <= 32);
_fsk_mod_idx_get(mod_idx, &_mod_idx, &_mod_idx_scale);
at86rf215_reg_write(dev, dev->BBC->RG_FSKC0, FSK_BT_20
| (_mod_idx << FSKC0_MIDX_SHIFT)
| (_mod_idx_scale << FSKC0_MIDXS_SHIFT)
| at86rf215_FSK_get_mod_order(dev)
);
return 0;
}
uint8_t at86rf215_FSK_get_srate(at86rf215_t *dev)
{
return at86rf215_reg_read(dev, dev->BBC->RG_FSKC1) & FSKC1_SRATE_MASK;
}
int at86rf215_FSK_set_srate(at86rf215_t *dev, uint8_t srate)
{
if (srate > FSK_SRATE_400K) {
return -1;
}
at86rf215_await_state_end(dev, RF_STATE_TX);
_set_srate(dev, srate, at86rf215_FSK_get_mod_idx(dev) <= 32);
_set_csma_backoff_period(dev);
return 0;
}
int at86rf215_FSK_set_fec(at86rf215_t *dev, uint8_t mode)
{
at86rf215_await_state_end(dev, RF_STATE_TX);
switch (mode) {
case IEEE802154_FEC_NONE:
at86rf215_reg_and(dev, dev->BBC->RG_FSKPHRTX, ~FSKPHRTX_SFD_MASK);
break;
case IEEE802154_FEC_NRNSC:
at86rf215_reg_or(dev, dev->BBC->RG_FSKPHRTX, FSKPHRTX_SFD_MASK);
at86rf215_reg_and(dev, dev->BBC->RG_FSKC2, ~FSKC2_FECS_MASK);
break;
case IEEE802154_FEC_RSC:
at86rf215_reg_or(dev, dev->BBC->RG_FSKPHRTX, FSKPHRTX_SFD_MASK);
at86rf215_reg_or(dev, dev->BBC->RG_FSKC2, FSKC2_FECS_MASK);
break;
default:
return -1;
}
_set_ack_timeout(dev, mode, at86rf215_FSK_get_mod_order(dev));
_set_csma_backoff_period(dev);
return 0;
}
uint8_t at86rf215_FSK_get_fec(at86rf215_t *dev)
{
/* SFD0 -> Uncoded IEEE mode */
/* SFD1 -> Coded IEEE mode */
if (!(at86rf215_reg_read(dev, dev->BBC->RG_FSKPHRTX) & FSKPHRTX_SFD_MASK)) {
return IEEE802154_FEC_NONE;
}
if (at86rf215_reg_read(dev, dev->BBC->RG_FSKC2) & FSKC2_FECS_MASK) {
return IEEE802154_FEC_RSC;
} else {
return IEEE802154_FEC_NRNSC;
}
}
int at86rf215_FSK_set_channel_spacing(at86rf215_t *dev, uint8_t ch_space)
{
if (ch_space > FSK_CHANNEL_SPACING_400K) {
return -1;
}
at86rf215_await_state_end(dev, RF_STATE_TX);
/* set channel spacing, same for both sub-GHz & 2.4 GHz */
at86rf215_reg_write(dev, dev->RF->RG_CS, _at86rf215_fsk_channel_spacing_25kHz[ch_space]);
/* set center frequency */
if (is_subGHz(dev)) {
at86rf215_reg_write16(dev, dev->RF->RG_CCF0L, _chan_center_freq0_subghz_25khz[ch_space]);
} else {
at86rf215_reg_write16(dev, dev->RF->RG_CCF0L, _chan_center_freq0_24ghz_25khz[ch_space]);
}
DEBUG("CCF0 configured as: %lu kHz\n",
25UL * at86rf215_reg_read16(dev, dev->RF->RG_CCF0L) + (is_subGHz(dev) ? 0 : CCF0_24G_OFFSET));
/* adjust channel spacing */
dev->num_chans = is_subGHz(dev) ? 34 / (ch_space + 1) : (416 / (ch_space + 1)) - (ch_space * 2);
dev->netdev.chan = at86rf215_chan_valid(dev, dev->netdev.chan);
at86rf215_reg_write16(dev, dev->RF->RG_CNL, dev->netdev.chan);
return 0;
}

Wyświetl plik

@ -1,448 +0,0 @@
/*
* Copyright (C) 2019 ML!PA Consulting GmbH
*
* 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.
*/
/**
* @ingroup drivers_at86rf215
* @{
*
* @file
* @brief Getter and setter functions for the AT86RF215 driver
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
* @}
*/
#include <string.h>
#include <errno.h>
#include "at86rf215.h"
#include "at86rf215_internal.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/* we can still go +3 dBm higher by increasing PA current */
#define PAC_DBM_MIN (-31) /* dBm */
uint16_t at86rf215_get_addr_short(const at86rf215_t *dev, uint8_t filter)
{
if (filter > 3) {
return 0;
}
/* Each frame filter has a 2 byte short addr + 2 byte PAN ID, so we have to
skip 4 bytes per filter */
return ntohs(at86rf215_reg_read16(dev, dev->BBC->RG_MACSHA0F0 + (4 * filter)));
}
void at86rf215_set_addr_short(at86rf215_t *dev, uint8_t filter, uint16_t addr)
{
/* do not overwrite node address for filters other than 0 */
if (filter == 0) {
dev->netdev.short_addr[0] = (uint8_t)(addr);
dev->netdev.short_addr[1] = (uint8_t)(addr >> 8);
}
if (filter > 3) {
return;
}
at86rf215_reg_write16(dev, dev->BBC->RG_MACSHA0F0 + (4 * filter), htons(addr));
}
bool at86rf215_get_framefilter_enabled(at86rf215_t *dev, uint8_t filter)
{
return (at86rf215_reg_read(dev, dev->BBC->RG_AFC0) >> (AFC0_AFEN0_SHIFT + filter)) & 1;
}
void at86rf215_enable_framefilter(at86rf215_t *dev, uint8_t filter)
{
at86rf215_reg_or(dev, dev->BBC->RG_AFC0, 1 << (AFC0_AFEN0_SHIFT + filter));
}
void at86rf215_disable_framefilter(at86rf215_t *dev, uint8_t filter)
{
at86rf215_reg_and(dev, dev->BBC->RG_AFC0, 1 << (AFC0_AFEN0_SHIFT + filter));
}
uint64_t at86rf215_get_addr_long(const at86rf215_t *dev)
{
uint64_t addr;
at86rf215_reg_read_bytes(dev, dev->BBC->RG_MACEA0, &addr, sizeof(addr));
return addr;
}
void at86rf215_set_addr_long(at86rf215_t *dev, uint64_t addr)
{
memcpy(dev->netdev.long_addr, &addr, sizeof(addr));
addr = ntohll(addr);
at86rf215_reg_write_bytes(dev, dev->BBC->RG_MACEA0, &addr, sizeof(addr));
}
uint8_t at86rf215_get_chan(const at86rf215_t *dev)
{
return at86rf215_reg_read16(dev, dev->RF->RG_CNL);
}
void at86rf215_set_trim(at86rf215_t *dev, uint8_t trim)
{
assert(trim <= 0xF);
at86rf215_reg_write(dev, RG_RF_XOC, trim | XOC_FS_MASK);
}
void at86rf215_set_clock_output(at86rf215_t *dev,
at86rf215_clko_cur_t cur, at86rf215_clko_freq_t freq)
{
at86rf215_reg_write(dev, RG_RF_CLKO, cur | freq);
}
void at86rf215_set_chan(at86rf215_t *dev, uint16_t channel)
{
at86rf215_await_state_end(dev, RF_STATE_TX);
uint8_t old_state = at86rf215_get_rf_state(dev);
/* frequency has to be updated in TRXOFF or TXPREP (datatsheet: 6.3.2) */
if (old_state == RF_STATE_RX) {
at86rf215_rf_cmd(dev, CMD_RF_TXPREP);
}
at86rf215_reg_write16(dev, dev->RF->RG_CNL, channel);
dev->netdev.chan = channel;
/* enable the radio again */
if (old_state == RF_STATE_RX) {
at86rf215_rf_cmd(dev, old_state);
}
}
uint16_t at86rf215_get_channel_spacing(at86rf215_t *dev) {
/* 25 kHz resolution */
return 25 * at86rf215_reg_read(dev, dev->RF->RG_CS);
}
uint8_t at86rf215_get_phy_mode(at86rf215_t *dev)
{
switch (at86rf215_reg_read(dev, dev->BBC->RG_PC) & PC_PT_MASK) {
case 0x1: return IEEE802154_PHY_MR_FSK;
case 0x2: return IEEE802154_PHY_MR_OFDM;
case 0x3: return at86rf215_OQPSK_is_legacy(dev)
? IEEE802154_PHY_OQPSK
: IEEE802154_PHY_MR_OQPSK;
default: return IEEE802154_PHY_DISABLED;
}
}
uint16_t at86rf215_get_pan(const at86rf215_t *dev, uint8_t filter)
{
if (filter > 3) {
return 0;
}
return at86rf215_reg_read16(dev, dev->BBC->RG_MACPID0F0 + (4 * filter));
}
void at86rf215_set_pan(at86rf215_t *dev, uint8_t filter, uint16_t pan)
{
if (filter == 0) {
dev->netdev.pan = pan;
}
if (filter > 3) {
return;
}
at86rf215_reg_write16(dev, dev->BBC->RG_MACPID0F0 + (4 * filter), pan);
}
// TODO: take modulation into account
int16_t at86rf215_get_txpower(const at86rf215_t *dev)
{
uint8_t pac = at86rf215_reg_read(dev, dev->RF->RG_PAC);
/* almost linear, each PACUR step adds ~1 dBm */
return PAC_DBM_MIN + (pac & PAC_TXPWR_MASK) +
((pac & PAC_PACUR_MASK) >> PAC_PACUR_SHIFT);
}
// TODO: take modulation into account
void at86rf215_set_txpower(const at86rf215_t *dev, int16_t txpower)
{
uint8_t pacur = 0;
txpower -= PAC_DBM_MIN;
if (txpower < 0) {
txpower = 0;
}
if (txpower > PAC_TXPWR_MASK) {
switch (txpower - PAC_TXPWR_MASK) {
case 1:
pacur = 1 << PAC_PACUR_SHIFT;
break;
case 2:
pacur = 2 << PAC_PACUR_SHIFT;
break;
default:
pacur = 3 << PAC_PACUR_SHIFT;
break;
}
txpower = PAC_TXPWR_MASK;
}
at86rf215_reg_write(dev, dev->RF->RG_PAC, pacur | txpower);
}
int8_t at86rf215_get_cca_threshold(const at86rf215_t *dev)
{
return dev->csma_ed;
}
void at86rf215_set_cca_threshold(at86rf215_t *dev, int8_t value)
{
dev->csma_ed = value;
at86rf215_reg_write(dev, dev->BBC->RG_AMEDT, value);
}
int8_t at86rf215_get_ed_level(at86rf215_t *dev)
{
return at86rf215_reg_read(dev, dev->RF->RG_EDV);
}
void at86rf215_enable_rpc(at86rf215_t *dev)
{
if (!(dev->flags & AT86RF215_OPT_RPC) || !CONFIG_AT86RF215_RPC_EN) {
return;
}
/* no Reduced Power mode available for OFDM */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
if (dev->fsk_pl) {
/* MR-FSK */
at86rf215_reg_or(dev, dev->BBC->RG_FSKRPC, FSKRPC_EN_MASK);
return;
}
#endif
#ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK
{
/* MR-O-QPSK */
at86rf215_reg_or(dev, dev->BBC->RG_OQPSKC2, OQPSKC2_RPC_MASK);
}
#endif
}
void at86rf215_disable_rpc(at86rf215_t *dev)
{
if (!(dev->flags & AT86RF215_OPT_RPC) || !CONFIG_AT86RF215_RPC_EN) {
return;
}
/* no Reduced Power mode available for OFDM */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
if (dev->fsk_pl) {
/* MR-FSK */
at86rf215_reg_and(dev, dev->BBC->RG_FSKRPC, ~FSKRPC_EN_MASK);
return;
}
#endif
#ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK
{
/* MR-O-QPSK */
at86rf215_reg_and(dev, dev->BBC->RG_OQPSKC2, ~OQPSKC2_RPC_MASK);
}
#endif
}
void at86rf215_set_option(at86rf215_t *dev, uint16_t option, bool state)
{
/* set option field */
dev->flags = (state) ? (dev->flags | option)
: (dev->flags & ~option);
switch (option) {
case AT86RF215_OPT_PROMISCUOUS:
if (state) {
at86rf215_reg_or(dev, dev->BBC->RG_AFC0, AFC0_PM_MASK);
} else {
at86rf215_reg_and(dev, dev->BBC->RG_AFC0, ~AFC0_PM_MASK);
}
break;
case AT86RF215_OPT_AUTOACK:
if (state) {
at86rf215_reg_or(dev, dev->BBC->RG_AMCS, AMCS_AACK_MASK);
} else {
at86rf215_reg_and(dev, dev->BBC->RG_AMCS, ~AMCS_AACK_MASK);
}
break;
case AT86RF215_OPT_CCATX:
if (state){
at86rf215_reg_or(dev, dev->BBC->RG_AMCS, AMCS_CCATX_MASK);
} else {
at86rf215_reg_and(dev, dev->BBC->RG_AMCS, ~AMCS_CCATX_MASK);
}
break;
case AT86RF215_OPT_RPC:
if (state) {
at86rf215_enable_rpc(dev);
} else {
at86rf215_disable_rpc(dev);
}
break;
default:
/* do nothing */
break;
}
}
static void _wake_from_sleep(at86rf215_t *dev)
{
/* wake the transceiver */
at86rf215_rf_cmd(dev, CMD_RF_TRXOFF);
at86rf215_await_state(dev, RF_STATE_TRXOFF);
/* config is lost after SLEEP */
at86rf215_reset(dev);
/* if both transceivers were sleeping, the chip entered DEEP_SLEEP.
Waking one device in that mode wakes the other one too. */
if (dev->sibling && dev->sibling->state == AT86RF215_STATE_SLEEP)
{
at86rf215_rf_cmd(dev->sibling, CMD_RF_SLEEP);
}
}
bool at86rf215_set_rx_from_idle(at86rf215_t *dev, uint8_t *state)
{
if (dev->state == AT86RF215_STATE_SLEEP) {
_wake_from_sleep(dev);
}
uint8_t s;
while ((s = at86rf215_get_rf_state(dev)) == RF_STATE_TRANSITION) {}
if (state) {
*state = s;
}
if (s == RF_STATE_RESET) {
at86rf215_rf_cmd(dev, CMD_RF_TRXOFF);
at86rf215_await_state(dev, RF_STATE_TRXOFF);
s = RF_STATE_TRXOFF;
}
if (s == RF_STATE_TRXOFF) {
at86rf215_rf_cmd(dev, CMD_RF_RX);
at86rf215_await_state(dev, RF_STATE_RX);
s = RF_STATE_RX;
}
if (s == RF_STATE_RX) {
return true;
}
return false;
}
bool at86rf215_set_idle_from_rx(at86rf215_t *dev, uint8_t state)
{
if (state == RF_STATE_TX || state == CMD_RF_TXPREP) {
return false;
}
if (dev->state == AT86RF215_STATE_SLEEP) {
if (state == CMD_RF_SLEEP) {
return true;
}
_wake_from_sleep(dev);
}
uint8_t s;
while ((s = at86rf215_get_rf_state(dev)) == RF_STATE_TRANSITION) {}
if (s != RF_STATE_RX) {
return false;
}
if (state == RF_STATE_RX) {
return true;
}
at86rf215_rf_cmd(dev, CMD_RF_TRXOFF);
at86rf215_await_state(dev, RF_STATE_TRXOFF);
if (state == RF_STATE_TRXOFF) {
return true;
}
/* clear IRQ */
at86rf215_reg_read(dev, dev->BBC->RG_IRQS);
at86rf215_reg_read(dev, dev->RF->RG_IRQS);
at86rf215_rf_cmd(dev, CMD_RF_SLEEP);
dev->state = AT86RF215_STATE_SLEEP;
if (state == RF_STATE_RESET) {
return true;
}
return false;
}
int at86rf215_enable_batmon(at86rf215_t *dev, unsigned voltage)
{
uint8_t bmdvc;
/* only configure BATMON on one interface */
if (!is_subGHz(dev) && dev->sibling != NULL) {
dev = dev->sibling;
}
/* ensure valid range */
if (voltage < 1700 || voltage > 3675) {
return -ERANGE;
}
if (voltage > 2500) {
/* high range */
bmdvc = (voltage - 2550 + 37) / 75;
DEBUG("[at86rf215] BATMON set to %u mV\n", 2550 + 75 * bmdvc);
bmdvc |= BMDVC_BMHR_MASK;
} else {
/* low range */
bmdvc = (voltage - 1700 + 25) / 50;
DEBUG("[at86rf215] BATMON set to %u mV\n", 1700 + 50 * bmdvc);
}
/* set batmon threshold */
at86rf215_reg_write(dev, RG_RF_BMDVC, bmdvc);
/* enable interrupt */
at86rf215_reg_or(dev, dev->RF->RG_IRQM, RF_IRQ_BATLOW);
return 0;
}
void at86rf215_disable_batmon(at86rf215_t *dev)
{
/* only configure BATMON on one interface */
if (!is_subGHz(dev) && dev->sibling != NULL) {
dev = dev->sibling;
}
/* disable interrupt */
at86rf215_reg_and(dev, dev->RF->RG_IRQM, ~RF_IRQ_BATLOW);
}

Wyświetl plik

@ -1,224 +0,0 @@
/**
* @ingroup drivers_at86rf215
* @{
*
* @file
* @brief Low-Level functions for the AT86RF215 driver
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
* @}
*/
#include "at86rf215_internal.h"
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#define SPIDEV (dev->params.spi)
#define CSPIN (dev->params.cs_pin)
int spi_acquire(int spi, int cs, int mode, int clock);
void spi_release(int spi);
void spi_transfer_bytes (int bus, int cs, bool cont, const void *out, void *in, size_t len);
uint8_t spi_transfer_byte(int bus, int cs, bool cont, uint8_t out);
uint8_t spi_transfer_reg(int bus, int cs, uint8_t reg, uint8_t out);
void spi_transfer_regs(int bus, int cs, uint8_t reg, const void *out, void *in, size_t len);
void gpio_clear(int pin);
void gpio_set(int pin);
void usleep(int usec);
static inline void getbus(const at86rf215_t *dev)
{
spi_acquire(SPIDEV, CSPIN, 0, dev->params.spi_clk);
}
/* only to be used by at86rf215_hardware_reset()
can't use normal at86rf215_reg_read() because
we already hold the lock */
static inline uint8_t _get_reg_with_lock(at86rf215_t *dev, uint16_t r)
{
uint16_t reg = htons(r | FLAG_READ);
spi_transfer_bytes(SPIDEV, CSPIN, true, &reg, NULL, sizeof(reg));
return spi_transfer_byte(SPIDEV, CSPIN, false, 0);
}
int at86rf215_hardware_reset(at86rf215_t *dev)
{
/* prevent access during reset */
getbus(dev);
/* trigger hardware reset */
gpio_clear(dev->params.reset_pin);
usleep(CONFIG_AT86RF215_RESET_PULSE_WIDTH_US);
gpio_set(dev->params.reset_pin);
usleep(AT86RF215_RESET_DELAY_US);
/* While the device is in RESET / DEEP SLEEP, all registers
but STATE will read 0xFF.
WAKEUP IRQ signals that the device is ready. */
uint8_t state = 0;
uint8_t tries = 255;
while (--tries && (state == 0xFF || !(state & IRQS_WAKEUP_MASK))) {
state = _get_reg_with_lock(dev, dev->RF->RG_IRQS);
}
spi_release(SPIDEV);
/* no device connected */
if (!tries) {
return -ENODEV;
}
/* enable battery monitor */
// at86rf215_enable_batmon(dev, CONFIG_AT86RF215_BATMON_THRESHOLD);
/* clear interrupts */
at86rf215_reg_read(dev, RG_RF09_IRQS);
at86rf215_reg_read(dev, RG_RF24_IRQS);
at86rf215_reg_read(dev, RG_BBC0_IRQS);
at86rf215_reg_read(dev, RG_BBC1_IRQS);
return 0;
}
void at86rf215_reg_write(const at86rf215_t *dev, uint16_t reg, uint8_t value)
{
reg = htons(reg | FLAG_WRITE);
getbus(dev);
spi_transfer_bytes(SPIDEV, CSPIN, true, &reg, NULL, sizeof(reg));
spi_transfer_byte(SPIDEV, CSPIN, false, value);
spi_release(SPIDEV);
}
void at86rf215_reg_write_bytes(const at86rf215_t *dev, uint16_t reg, const void *data, size_t len)
{
reg = htons(reg | FLAG_WRITE);
getbus(dev);
spi_transfer_bytes(SPIDEV, CSPIN, true, &reg, NULL, sizeof(reg));
spi_transfer_bytes(SPIDEV, CSPIN, false, data, NULL, len);
spi_release(SPIDEV);
}
uint8_t at86rf215_reg_read(const at86rf215_t *dev, uint16_t reg)
{
uint8_t val;
reg = htons(reg | FLAG_READ);
getbus(dev);
spi_transfer_bytes(SPIDEV, CSPIN, true, &reg, NULL, sizeof(reg));
val = spi_transfer_byte(SPIDEV, CSPIN, false, 0);
spi_release(SPIDEV);
return val;
}
void at86rf215_reg_read_bytes(const at86rf215_t *dev, uint16_t reg, void *data, size_t len)
{
reg = htons(reg | FLAG_READ);
getbus(dev);
spi_transfer_bytes(SPIDEV, CSPIN, true, &reg, NULL, sizeof(reg));
spi_transfer_bytes(SPIDEV, CSPIN, false, NULL, data, len);
spi_release(SPIDEV);
}
#define IEEE802154_FCF_TYPE_ACK (2)
#define IEEE802154_FCF_TYPE_BEACON (0x00)
#define IEEE802154_FCF_TYPE_DATA (0x01)
#define IEEE802154_FCF_TYPE_MACCMD (0x03)
void at86rf215_filter_ack(at86rf215_t *dev, bool on)
{
/* only listen for ACK frames */
uint8_t val = on ? (1 << IEEE802154_FCF_TYPE_ACK)
: (1 << IEEE802154_FCF_TYPE_BEACON)
| (1 << IEEE802154_FCF_TYPE_DATA)
| (1 << IEEE802154_FCF_TYPE_MACCMD);
at86rf215_reg_write(dev, dev->BBC->RG_AFFTM, val);
}
void at86rf215_get_random(at86rf215_t *dev, void *data, size_t len)
{
/* store previous PHY control state */
uint8_t state_pc = at86rf215_reg_read(dev, dev->BBC->RG_PC);
/* disable baseband processor */
at86rf215_reg_write(dev, dev->BBC->RG_PC, state_pc & ~PC_BBEN_MASK);
/* store previous RX bandwidth settings */
uint8_t rxbwc = at86rf215_reg_read(dev, dev->RF->RG_RXBWC);
/* The analog frontend of the radio must be configured to the
widest filter bandwidth; The bit RXBWC.IFS must be set to 1 */
at86rf215_reg_write(dev, dev->RF->RG_RXBWC, 0x1B);
uint8_t *data8 = data;
while (len--) {
*data8++ = at86rf215_reg_read(dev, dev->RF->RG_RNDV);
}
/* restore RX bandwidth settings */
at86rf215_reg_write(dev, dev->RF->RG_RXBWC, rxbwc);
/* restore PHY control settings */
at86rf215_reg_write(dev, dev->BBC->RG_PC, state_pc);
}
#define IEEE802154_CHANNEL_MIN 2
uint16_t at86rf215_chan_valid(at86rf215_t *dev, uint16_t chan)
{
if (is_subGHz(dev))
{
if (chan >= dev->num_chans)
{
return dev->num_chans - 1;
}
}
else
{
if (chan < IEEE802154_CHANNEL_MIN)
{
return IEEE802154_CHANNEL_MIN;
}
else if (chan >= IEEE802154_CHANNEL_MIN + dev->num_chans)
{
return IEEE802154_CHANNEL_MIN + dev->num_chans - 1;
}
}
return chan;
}
const char* at86rf215_hw_state2a(uint8_t state)
{
switch (state) {
case RF_STATE_TRXOFF: return "TRXOFF";
case RF_STATE_TXPREP: return "TXPREP";
case RF_STATE_TX: return "TX";
case RF_STATE_RX: return "RX";
case RF_STATE_TRANSITION: return "TRANSITION";
case RF_STATE_RESET: return "RESET";
default: return "invalid";
}
}
const char* at86rf215_sw_state2a(at86rf215_state_t state) {
switch (state) {
case AT86RF215_STATE_OFF: return "OFF";
case AT86RF215_STATE_IDLE: return "IDLE";
case AT86RF215_STATE_RX_SEND_ACK: return "RX (sending ACK)";
case AT86RF215_STATE_TX: return "TX";
case AT86RF215_STATE_TX_WAIT_ACK: return "TX (wait for ACK)";
case AT86RF215_STATE_SLEEP: return "SLEEP";
default: return "invalid";
}
}

Wyświetl plik

@ -1,697 +0,0 @@
/*
* Copyright (C) 2019 ML!PA Consulting GmbH
*
* 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.
*/
/**
* @ingroup drivers_at86rf215
* @{
*
* @file
* @brief Low-Level functions for the AT86RF215 driver
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*/
#ifndef AT86RF215_INTERNAL_H
#define AT86RF215_INTERNAL_H
#include <stdint.h>
#include <stdlib.h>
#include "at86rf215.h"
#include "at86rf215_regs.h"
#include "at86rf215_registers.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Minimum reset pulse width (tRST) in µs
*/
#ifndef CONFIG_AT86RF215_RESET_PULSE_WIDTH_US
#define CONFIG_AT86RF215_RESET_PULSE_WIDTH_US (16U)
#endif
/**
* @brief The typical transition time to TRX_OFF after reset (tPOWERON) in µs
*/
#define AT86RF215_RESET_DELAY_US (16U)
/** Default energy detect threshold for CSMA (reset value) */
#define AT86RF215_EDT_DEFAULT (-84) /* dBm */
/**
* Default Parameters for 802.15.4 retransmissions & CSMA
* @{
*/
#define AT86RF215_RETRIES_MAX_DEFAULT (3)
#define AT86RF215_CSMA_RETRIES_MAX_DEFAULT (4)
#define AT86RF215_CSMA_MIN_BE_DEFAULT (3)
#define AT86RF215_CSMA_MAX_BE_DEFAULT (5)
/** @} */
/** An ACK consists of 5 payload bytes */
#define AT86RF215_ACK_PSDU_BYTES (5)
/**
* This is used to calculate the ACK timeout based on the bitrate.
* AT86RF233 uses an ACK timeout of 54 symbol periods, or 864 µs @ 250 kbit/s
* -> 864µs * 250kbit/s = 216 bit */
#define AT86RF215_ACK_PERIOD_IN_SYMBOLS (54U)
#define AT86RF215_OQPSK_MODE_LEGACY (0x1) /**< legacy mode, 250 kbit/s */
#define AT86RF215_OQPSK_MODE_LEGACY_HDR (0x3) /**< legacy mode, high data rate */
#define AT86RF215_MR_OQPSK_MODE(n) ((n) << OQPSKPHRTX_MOD_SHIFT) /**< MR-QPSK */
/**
* @brief Perform a reset of the entire chip.
*
* @param dev device to reset, will also reset sibling device
* @return 0 on success, error if device is not available
*/
int at86rf215_hardware_reset(at86rf215_t *dev);
/**
* @brief Write to a register at address `addr` from device `dev`.
*
* @param[in] dev device to write to
* @param[in] reg address of the register to write
* @param[in] val value to write to the given register
*/
void at86rf215_reg_write(const at86rf215_t *dev, uint16_t reg, uint8_t val);
/**
* @brief Write a chunk of data into the memory of the given device
*
* @param[in] dev device to write to
* @param[in] reg address in the device to write to
* @param[in] data data to copy into the device
* @param[in] len number of bytes to write into the device
*/
void at86rf215_reg_write_bytes(const at86rf215_t *dev, uint16_t reg, const void *data, size_t len);
/**
* @brief Read from a register at address `addr` from device `dev`.
*
* @param[in] dev device to read from
* @param[in] reg address of the register to read
*
* @return the value of the specified register
*/
uint8_t at86rf215_reg_read(const at86rf215_t *dev, uint16_t reg);
/**
* @brief Read a chunk of data from the memory of the given device
*
* @param[in] dev device to read from
* @param[in] reg starting address to read from
* @param[out] data buffer to read data into
* @param[in] len number of bytes to read
*/
void at86rf215_reg_read_bytes(const at86rf215_t *dev, uint16_t reg, void *data, size_t len);
/**
* @brief Enable / Disable the ACK filter
*
* @param[in] dev device to configure
* @param[in] on if true, only ACK frames are received
* if false, only non-ACK frames are received
*/
void at86rf215_filter_ack(at86rf215_t *dev, bool on);
/**
* @brief Read random data from the RNG
*
* @pre The device has to be in state RX with PLL locked.
*
* @param[in] dev device to configure
* @param[out] data buffer to copy the random data to
* @param[in] len number of random bytes to store in data
*/
void at86rf215_get_random(at86rf215_t *dev, void *data, size_t len);
/**
* @ingroup drivers_at86rf215
* @defgroup drivers_at86rf215_fsk AT86RF215 MR-FSK PHY
* @{
*/
/**
* @brief Symbol Rates for register values, in 10kHz
*/
extern const uint8_t _at86rf215_fsk_srate_10kHz[];
/**
* @brief Channel Spacing for register values, in 25kHz
*/
extern const uint8_t _at86rf215_fsk_channel_spacing_25kHz[];
/**
* @brief Configure the radio to make use of FSK modulation
*
* @param[in] dev device to configure
* @param[in] srate symbol rate, possible values: FSK_SRATE_50K FSK_SRATE_400K
* @param[in] mod_idx modulation index, multiplied by 64 (½ -> 32; 1 -> 64)
* @param[in] mod_order modulation order, may be FSK_MORD_2SFK or FSK_MORD_4SFK
* @param[in] fec forward error correction, may be @ref IEEE802154_FEC_NONE,
* @ref IEEE802154_FEC_NRNSC or @ref IEEE802154_FEC_RSC
*
* @return 0 on success, error otherwise
*/
int at86rf215_configure_FSK(at86rf215_t *dev, uint8_t srate, uint8_t mod_idx, uint8_t mod_order, uint8_t fec);
/**
* @brief Configure the symbol rate of the FSK modulation
*
* @param[in] dev device to configure
* @param[in] srate symbol rate, possible values: FSK_SRATE_50K FSK_SRATE_400K
*/
int at86rf215_FSK_set_srate(at86rf215_t *dev, uint8_t srate);
/**
* @brief Get the symbol rate of the FSK modulation
*
* @param[in] dev device to read from
*
* @return symbol rate, possible values: FSK_SRATE_50K FSK_SRATE_400K
*/
uint8_t at86rf215_FSK_get_srate(at86rf215_t *dev);
/**
* @brief Configure the modulation index of the FSK modulation
* The modulation index is a fractional value, it is represented as
* fractions of 64.
* Not all possible fractional values are configurable by the hardware.
* If the fractional can not be mapped to the hardware, the nearest matching
* one is chosen.
*
* @param[in] dev device to configure
* @param[in] mod_idx modulation index, multiplied by 64 (½ -> 32; 1 -> 64)
*
* @return 0 on success, failure otherwise
*/
int at86rf215_FSK_set_mod_idx(at86rf215_t *dev, uint8_t mod_idx);
/**
* @brief Get the current modulation index of the FSK modulation
* The modulation index is a fractional value, it is represented as
* fractions of 64.
*
* @param[in] dev device to read from
*
* @return the current modulation index, multiplied by 64
*/
uint8_t at86rf215_FSK_get_mod_idx(at86rf215_t *dev);
/**
* @brief Configure the Forward Error Correction (coding) scheme for FSK modulation.
* Supported values are:
* - no error correction
* - non-recursive and non-systematic code (NRNSC)
* - recursive and systematic code (RSC)
*
* @param[in] dev device to configure
* @param[in] mode forward error correction, may be @ref IEEE802154_FEC_NONE,
* @ref IEEE802154_FEC_NRNSC or @ref IEEE802154_FEC_RSC
*
* @return 0 on success, failure otherwise
*/
int at86rf215_FSK_set_fec(at86rf215_t *dev, uint8_t mode);
/**
* @brief Get the Forward Error Correction (coding) scheme for FSK modulation.
* Supported values are:
* - no error correction
* - non-recursive and non-systematic code (NRNSC)
* - recursive and systematic code (RSC)
*
* @param[in] dev device to read from
*
* @return current coding scheme, may be @ref IEEE802154_FEC_NONE,
* @ref IEEE802154_FEC_NRNSC or @ref IEEE802154_FEC_RSC
*/
uint8_t at86rf215_FSK_get_fec(at86rf215_t *dev);
/**
* @brief Configure the channel spacing for the FSK modulation
*
* @param[in] dev device to configure
* @param[in] ch_space channel spacing, possible values: FSK_CHANNEL_SPACING_200K _400K
*
* @return 0 on success, failure otherwise
*/
int at86rf215_FSK_set_channel_spacing(at86rf215_t *dev, uint8_t ch_space);
/**
* @brief Get the configured channel spacing
*
* @param[in] dev device to read from
*
* @return channel spacing in kHz
*/
uint16_t at86rf215_get_channel_spacing(at86rf215_t *dev);
/**
* @brief Configure the FSK modulation order.
* You can choose between 2-level and 4-level FSK
*
* @param[in] dev device to configure
* @param[in] mod_order modulation order, may be FSK_MORD_2SFK or FSK_MORD_4SFK
*
* @return 0 on success, failure otherwise
*/
int at86rf215_FSK_set_mod_order(at86rf215_t *dev, uint8_t mod_order);
/**
* @brief Get the current FSK modulation order.
* You can choose between 2-level and 4-level FSK
*
* @param[in] dev device to read from
*
* @return modulation order, may be FSK_MORD_2SFK or FSK_MORD_4SFK
*/
uint8_t at86rf215_FSK_get_mod_order(at86rf215_t *dev);
/**
* @brief The FSK premable length needs to be switched between RX and TX
* This function takes care of putting FSK into RX mode.
*
* @param[in] dev device that is entering RX mode
*/
void at86rf215_FSK_prepare_rx(at86rf215_t *dev);
/**
* @brief The FSK premable length needs to be switched between RX and TX
* This function takes care of putting FSK into TX mode.
*
* @param[in] dev device that is entering TX mode
*/
void at86rf215_FSK_prepare_tx(at86rf215_t *dev);
/** @} */
/**
* @ingroup drivers_at86rf215
* @defgroup drivers_at86rf215_ofdm AT86RF215 MR-OFDM PHY
* @{
*/
/**
* @brief Configure the radio to make use of OFDM modulation.
* There are 4 OFDM options, each with a different number of active tones.
* The device supports BPSK, QPSK and 16-QAM modulation and coding schemes (MCS)
*
* @param[in] dev device to configure
* @param[in] option modulation option, each increment halves the data rate
* @param[in] mcs modulation scheme, `BB_MCS_BPSK_REP4` `BB_MCS_16QAM_3BY4`
*
* @return 0 on success, error otherwise
*/
int at86rf215_configure_OFDM(at86rf215_t *dev, uint8_t option, uint8_t mcs);
/**
* @brief Set the current modulation and coding scheme (MCS)
*
* @param[in] dev device to configure
* @param[in] mcs modulation and coding scheme
*
* @return 0 on success, error otherwise
*/
int at86rf215_OFDM_set_scheme(at86rf215_t *dev, uint8_t mcs);
/**
* @brief Get the current modulation and coding scheme (MCS)
*
* @param[in] dev device to read from
*
* @return the current modulation & coding scheme
*/
uint8_t at86rf215_OFDM_get_scheme(at86rf215_t *dev);
/**
* @brief Set the current OFDM option
*
* @param[in] dev device to configure
* @param[in] option OFDM option
*
* @return 0 on success, error otherwise
*/
int at86rf215_OFDM_set_option(at86rf215_t *dev, uint8_t option);
/**
* @brief Get the current OFDM option
*
* @param[in] dev device to read from
*
* @return the current OFDM option
*/
uint8_t at86rf215_OFDM_get_option(at86rf215_t *dev);
/** @} */
/**
* @ingroup drivers_at86rf215
* @defgroup drivers_at86rf215_oqpsk AT86RF215 MR-O-QPSK PHY
* @{
*/
/**
* @brief Configure the radio to make use of O-QPSK modulation.
* The rate mode may be
* - 0 for compatibility with first-gen 802.15.4 devices (250 kbit/s)
* - 1 for compatibility with the proprietary high-data rate modes of at86rf2xx
*
* @param[in] dev device to configure
* @param[in] high_rate use proprietary high data rate compatible with at86rf2xx
*
* @return 0 on success, error otherwise
*/
int at86rf215_configure_legacy_OQPSK(at86rf215_t *dev, bool high_rate);
/**
* @brief Configure the radio to make use of O-QPSK modulation.
* The chip rate is the number of bits per second (chips per second) used in the spreading signal.
* The rate mode may be
* - @ref AT86RF215_OQPSK_MODE_LEGACY for compatibility with first-gen 802.15.4 devices (250 kbit/s)
* - @ref AT86RF215_OQPSK_MODE_LEGACY_HDR for compatibility with the proprietary high-data rate mode
* of the at86rf233 (1000 kbit/s, 2.4 GHz) and at86rf212b (500 kbit/s, sub-GHz)
* - @ref AT86RF215_MR_OQPSK_MODE for the rate modes specified in 802.15.4g-2012
*
* @param[in] dev device to configure
* @param[in] chips chip rate, `BB_FCHIP100` `BB_FCHIP2000`
* @param[in] rate rate mode, may be @ref AT86RF215_OQPSK_MODE_LEGACY or @ref AT86RF215_MR_OQPSK_MODE
*
* @return 0 on success, error otherwise
*/
int at86rf215_configure_OQPSK(at86rf215_t *dev, uint8_t chips, uint8_t rate);
/**
* @brief Get the current O-QPSK chip rate
*
* @param[in] dev device to read from
*
* @return the current chip rate
*/
uint8_t at86rf215_OQPSK_get_chips(at86rf215_t *dev);
/**
* @brief Set the current O-QPSK chip rate
*
* @param[in] dev device to configure
* @param[in] chips chip rate in chip/s
*
* @return 0 on success, error otherwise
*/
int at86rf215_OQPSK_set_chips(at86rf215_t *dev, uint8_t chips);
/**
* @brief Get the current O-QPSK rate mode
*
* @param[in] dev device to read from
*
* @return the current rate mode
*/
uint8_t at86rf215_OQPSK_get_mode(at86rf215_t *dev);
/**
* @brief Set the current O-QPSK rate mode
*
* @param[in] dev device to configure
* @param[in] mode rate mode
*
* @return 0 on success, error otherwise
*/
int at86rf215_OQPSK_set_mode(at86rf215_t *dev, uint8_t mode);
/**
* @brief Get the current legacy O-QPSK mode
*
* @param[in] dev device to read from
*
* @return 0 for IEEE 802.15.4 mode, 1 for high data rate
*/
uint8_t at86rf215_OQPSK_get_mode_legacy(at86rf215_t *dev);
/**
* @brief Set the current legacy O-QPSK rate mode
*
* @param[in] dev device to configure
* @param[in] high_rate set to use proprietary high data rate
*
* @return 0 on success, error otherwise
*/
int at86rf215_OQPSK_set_mode_legacy(at86rf215_t *dev, bool high_rate);
/**
* @brief Test if O-QPSK PHY operates in legacy mode
*
* @param[in] dev device to test
*
* @return true if device operates in legacy mode
*/
static inline bool at86rf215_OQPSK_is_legacy(at86rf215_t *dev) {
return at86rf215_reg_read(dev, dev->BBC->RG_OQPSKPHRTX) & AT86RF215_OQPSK_MODE_LEGACY;
}
/** @} */
/**
* @brief Get the current PHY modulation.
* May be @ref IEEE802154_PHY_MR_FSK, @ref IEEE802154_PHY_MR_OFDM,
* @ref IEEE802154_PHY_MR_OQPSK, @ref IEEE802154_PHY_OQPSK
* or @ref IEEE802154_PHY_DISABLED.
*
* @param[in] dev device to read from
*
* @return the current PHY mode the device is operating with
*/
uint8_t at86rf215_get_phy_mode(at86rf215_t *dev);
/**
* @brief Check if a channel number is valid.
* The function takes the current frequency band and modulation into
* account to determine if `chan` would be a legal channel number.
* If so, it is returned unmodified. Otherwise the next closest legal
* channel number is returned.
*
* @note This function does not change the configuration.
*
* @param[in] dev device to check against
* @param[in] chan the channel number to check
*
* @return If the channel number is legal, `chan` is returned.
* Otherwise the next closest legal channel number is
* returned.
*/
uint16_t at86rf215_chan_valid(at86rf215_t *dev, uint16_t chan);
/**
* @brief Converts radio state into human readable string.
*
* @param[in] state radio state
*
* @return fixed string representation of the radio state
*/
const char* at86rf215_hw_state2a(uint8_t state);
/**
* @brief Converts state machine state into human readable string.
*
* @param[in] state state of the driver's state machine
*
* @return fixed string representation of the state machine state
*/
const char* at86rf215_sw_state2a(at86rf215_state_t state);
/**
* @brief Reads the contents of `reg`, apply `val` with a bitwise AND
* and then writes the result back to `reg`.
*
* @param[in] dev device to write to
* @param[in] reg register to write to
* @param[in] val value to bitwise AND with the register content
*/
static inline void at86rf215_reg_and(const at86rf215_t *dev, uint16_t reg, uint8_t val)
{
val &= at86rf215_reg_read(dev, reg);
at86rf215_reg_write(dev, reg, val);
}
/**
* @brief Reads the contents of `reg`, apply `val` with a bitwise OR
* and then writes the result back to `reg`.
*
* @param[in] dev device to write to
* @param[in] reg register to write to
* @param[in] val value to bitwise OR with the register content
*/
static inline void at86rf215_reg_or(const at86rf215_t *dev, uint16_t reg, uint8_t val)
{
val |= at86rf215_reg_read(dev, reg);
at86rf215_reg_write(dev, reg, val);
}
/**
* @brief Write a 16-bit word to a register at address `addr` from device `dev`.
*
* @param[in] dev device to write to
* @param[in] reg address of the register to write
* @param[in] val value to write to the given register
*/
static inline void at86rf215_reg_write16(const at86rf215_t *dev, uint16_t reg, uint16_t val)
{
at86rf215_reg_write_bytes(dev, reg, &val, sizeof(val));
}
/**
* @brief Read a 16-bit word from a register at address `addr` from device `dev`.
*
* @param[in] dev device to read from
* @param[in] reg address of the register to read
*
* @return the value of the specified register
*/
static inline uint16_t at86rf215_reg_read16(const at86rf215_t *dev, uint16_t reg)
{
uint16_t value;
at86rf215_reg_read_bytes(dev, reg, &value, sizeof(value));
return value;
}
/**
* @brief Issue a radio command to the device
*
* @param[in] dev device to configure
* @param[in] rf_cmd command to send
*/
static inline void at86rf215_rf_cmd(const at86rf215_t *dev, uint8_t rf_cmd)
{
at86rf215_reg_write(dev, dev->RF->RG_CMD, rf_cmd);
}
/**
* @brief Get the radio state of the device
*
* @param[in] dev device to read from
*
* @return the current radio state
*/
static inline uint8_t at86rf215_get_rf_state(const at86rf215_t *dev)
{
return at86rf215_reg_read(dev, dev->RF->RG_STATE) & STATE_STATE_MASK;
}
/**
* @brief Blocks until the device has reached the given state
*
* @param[in] dev device to poll
* @param[in] state the expected state
*/
static inline void at86rf215_await_state(const at86rf215_t *dev, uint8_t state)
{
while (at86rf215_get_rf_state(dev) != state) {}
}
/**
* @brief Blocks until the device has reached the given state
*
* @param[in] dev device to poll
* @param[in] state the expected state
*/
static inline void at86rf215_await_state_end(const at86rf215_t *dev, uint8_t state)
{
while (at86rf215_get_rf_state(dev) == state) {}
}
/**
* @brief Switch device back to IDLE-RX from non-RX idle
*
* @param[in] dev device to update
* @param[out] old_state pointer to store the previous state, may be NULL
*
* @return true if the operation was possible
*/
bool at86rf215_set_rx_from_idle(at86rf215_t *dev, uint8_t *old_state);
/**
* @brief Switch device to non-RX idle state from RX
*
* @param[in] dev device to update
* @param[out] state the new state (may be CMD_RF_TRXOFF or CMD_RF_SLEEP)
*
* @return true if the operation was possible
*/
bool at86rf215_set_idle_from_rx(at86rf215_t *dev, uint8_t state);
/**
* @brief Enable the baseband processor of the device
*
* @param[in] dev device to enable the baseband on
*/
static inline void at86rf215_enable_baseband(const at86rf215_t *dev)
{
at86rf215_reg_or(dev, dev->BBC->RG_PC, PC_BBEN_MASK);
}
/**
* @brief Disable the baseband processor of the device
*
* @param[in] dev device to disable the baseband on
*/
static inline void at86rf215_disable_baseband(const at86rf215_t *dev) {
at86rf215_reg_and(dev, dev->BBC->RG_PC, ~PC_BBEN_MASK);
}
/**
* @brief Enable the radio hardware with a given modulation.
*
* @param[in] dev device to enable
* @param[in] modulation modulation to configure on the radio
*/
static inline void at86rf215_enable_radio(at86rf215_t *dev, uint8_t modulation)
{
/* 16 bit frame-checksum, baseband enabled, checksum calculated by chip,
frames with invalid cs are dropped */
at86rf215_reg_write(dev, dev->BBC->RG_PC, modulation | PC_BBEN_MASK
| PC_FCST_MASK | PC_TXAFCS_MASK
| PC_FCSFE_MASK);
}
/**
* @brief Internal convenience function to disable reduced power
* consumption (RPC) for energy detection.
*
* @param[in] dev device to configure
*/
void at86rf215_disable_rpc(at86rf215_t *dev);
/**
* @brief Internal convenience function to re-enable reduced power
* consumption (RPC) after energy detection.
*
* @param[in] dev device to configure
*/
void at86rf215_enable_rpc(at86rf215_t *dev);
/**
* @brief Checks whether the device operates in the sub-GHz band.
*
* @param[in] dev device to read from
*
* @return true if the device operates in the sub-GHz band
* false if the device operates in the 2.4-GHz band
*/
static inline bool is_subGHz(const at86rf215_t *dev)
{
return dev->RF->RG_IRQS == RG_RF09_IRQS;
}
#ifdef __cplusplus
}
#endif
#endif /* AT86RF215_INTERNAL_H */
/** @} */

Wyświetl plik

@ -1,39 +0,0 @@
/*
* Copyright (C) 2019 ML!PA Consulting GmbH
*
* 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.
*/
/**
* @ingroup drivers_at86rf215
* @{
*
* @file
* @brief Netdev interface to AT86RF215 driver
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
* @}
*/
#ifndef AT86RF215_NETDEV_H
#define AT86RF215_NETDEV_H
#include "net/netdev.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reference to the netdev device driver struct
*/
extern const netdev_driver_t at86rf215_driver;
#ifdef __cplusplus
}
#endif
#endif /* AT86RF215_NETDEV_H */
/** @} */

Wyświetl plik

@ -1,479 +0,0 @@
/*
* Copyright (C) 2019 ML!PA Consulting GmbH
*
* 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.
*/
/**
* @ingroup drivers_at86rf215
* @{
*
* @file
* @brief Configuration of the MR-O-QPSK PHY on the AT86RF215 chip
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
* @}
*/
#include "at86rf215.h"
#include "at86rf215_internal.h"
#include "debug.h"
/* IEEE Std 802.15.4g™-2012 Amendment 3
* Table 68dTotal number of channels and first channel center frequencies for SUN PHYs
* Table 68eCenter frequencies for the MR-O-QPSK PHY operating in the 868870 MHz band
*/
/* currently only EU-868 MHz band is supported */
#define QPSK_CHANNEL_SPACING_SUBGHZ (650U) /* kHz */
#define QPSK_CENTER_FREQUENCY_SUBGHZ (868300U) /* Hz */
#define QPSK_CHANNEL_SPACING_24GHZ (5000U) /* kHz */
#define QPSK_CENTER_FREQUENCY_24GHZ (2350000U - CCF0_24G_OFFSET) /* Hz */
#define LEGACY_QPSK_SYMBOL_TIME_US (16)
/* Table 6-103. O-QPSK Transmitter Frontend Configuration */
static uint8_t _TXCUTC_PARAMP(uint8_t chips)
{
switch (chips) {
case BB_FCHIP100:
return RF_PARAMP32U;
case BB_FCHIP200:
return RF_PARAMP16U;
case BB_FCHIP1000:
case BB_FCHIP2000:
return RF_PARAMP4U;
}
return 0;
}
/* Table 6-103. O-QPSK Transmitter Frontend Configuration */
static uint8_t _TXCUTC_LPFCUT(uint8_t chips)
{
switch (chips) {
case BB_FCHIP100:
case BB_FCHIP200:
return RF_FLC400KHZ;
case BB_FCHIP1000:
case BB_FCHIP2000:
return RF_FLC1000KHZ;
}
return 0;
}
/* Table 6-103. O-QPSK Transmitter Frontend Configuration */
static uint8_t _TXDFE_SR(uint8_t chips)
{
switch (chips) {
case BB_FCHIP100:
return RF_SR_400K;
case BB_FCHIP200:
return RF_SR_800K;
case BB_FCHIP1000:
return RF_SR_4000K;
case BB_FCHIP2000:
return RF_SR_4000K;
}
return 0;
}
/* Table 6-103. O-QPSK Transmitter Frontend Configuration */
static uint8_t _TXDFE_RCUT(uint8_t chips)
{
return (chips == BB_FCHIP2000 ? RF_RCUT_FS_BY_2 : RF_RCUT_FS_BY_2P6);
}
/* Table 6-105. O-QPSK Receiver Frontend Configuration (Filter Settings) */
static uint8_t _RXBWC_BW(uint8_t chips)
{
switch (chips) {
case BB_FCHIP100:
return RF_BW160KHZ_IF250KHZ;
case BB_FCHIP200:
return RF_BW250KHZ_IF250KHZ;
case BB_FCHIP1000:
return RF_BW1000KHZ_IF1000KHZ;
case BB_FCHIP2000:
return RF_BW2000KHZ_IF2000KHZ;
}
return 0;
}
/* Table 6-105. O-QPSK Receiver Frontend Configuration (Filter Settings) */
static uint8_t _RXDFE_SR(uint8_t chips)
{
switch (chips) {
case BB_FCHIP100:
return RF_SR_400K;
case BB_FCHIP200:
return RF_SR_800K;
case BB_FCHIP1000:
case BB_FCHIP2000:
return RF_SR_4000K;
}
return 0;
}
/* Table 6-105. O-QPSK Receiver Frontend Configuration (Filter Settings) */
static uint8_t _RXDFE_RCUT(uint8_t chips)
{
switch (chips) {
case BB_FCHIP100:
case BB_FCHIP200:
return RF_RCUT_FS_BY_5P3;
case BB_FCHIP1000:
return RF_RCUT_FS_BY_8;
case BB_FCHIP2000:
return RF_RCUT_FS_BY_4;
}
return 0;
}
/* Table 6-106. O-QPSK Receiver Frontend Configuration (AGC Settings) */
static inline uint8_t _AGCC(uint8_t chips)
{
if (chips > BB_FCHIP200) {
/* 32 samples */
return (2 << AGCC_AVGS_SHIFT) | AGCC_EN_MASK;
} else {
return AGCC_EN_MASK;
}
}
static inline uint16_t _get_symbol_duration_us(uint8_t chips)
{
/* 802.15.4g, Table 183 / Table 165 */
switch (chips) {
case BB_FCHIP100:
return 320;
case BB_FCHIP200:
return 160;
case BB_FCHIP1000:
case BB_FCHIP2000:
default:
return 64;
}
}
static inline uint8_t _get_cca_duration_syms(uint8_t chips)
{
/* 802.15.4g, Table 188 */
return (chips < BB_FCHIP1000) ? 4 : 8;
}
static inline uint8_t _get_shr_duration_syms(uint8_t chips)
{
/* 802.15.4g, Table 184 / Table 165 */
return (chips < BB_FCHIP1000) ? 48 : 72;
}
static uint8_t _get_spreading(uint8_t chips, uint8_t mode)
{
if (mode == 4) {
return 1;
}
uint8_t spread = 1 << (3 - mode);
if (chips == BB_FCHIP1000) {
return 2 * spread;
}
if (chips == BB_FCHIP2000) {
return 4 * spread;
}
return spread;
}
static inline uint8_t _get_ack_psdu_duration_syms(uint8_t chips, uint8_t mode)
{
/* pg. 119, section 18.3.2.14 */
static const uint8_t sym_len[] = { 32, 32, 64, 128 };
const uint8_t Ns = sym_len[chips];
const uint8_t Rspread = _get_spreading(chips, mode);
/* Nd == 63, since ACK length is 5 or 7 octects only */
const uint16_t Npsdu = Rspread * 2 * 63;
/* phyPSDUDuration = ceiling(Npsdu / Ns) + ceiling(Npsdu / Mp) */
/* with Mp = Np * 16, see Table 182 */
return (Npsdu + Ns/2) / Ns + (Npsdu + 8 * Ns) / (16 * Ns);
}
static uint8_t _set_mode(at86rf215_t *dev, uint8_t mode)
{
mode = AT86RF215_MR_OQPSK_MODE(mode);
/* TX with selected rate mode */
at86rf215_reg_write(dev, dev->BBC->RG_OQPSKPHRTX, mode);
/* power save mode only works when not listening to legacy frames */
/* listening to both uses ~1mA more that just listening to legacy */
/* TODO: make this configurable */
uint8_t rxm = RXM_MR_OQPSK;
if (dev->flags & AT86RF215_OPT_RPC) {
rxm |= OQPSKC2_RPC_MASK; /* enable Reduced Power Consumption */
}
at86rf215_reg_write(dev, dev->BBC->RG_OQPSKC2,
rxm /* receive mode, MR-O-QPSK */
| OQPSKC2_FCSTLEG_MASK /* 16 bit frame checksum */
| OQPSKC2_ENPROP_MASK); /* enable RX of proprietary modes */
return mode;
}
static void _set_chips(at86rf215_t *dev, uint8_t chips)
{
/* enable direct modulation if the chip supports it */
uint8_t direct_modulation;
if (chips < BB_FCHIP1000 && at86rf215_reg_read(dev, RG_RF_VN) >= 3) {
direct_modulation = TXDFE_DM_MASK;
} else {
direct_modulation = 0;
}
/* Set Receiver Bandwidth */
at86rf215_reg_write(dev, dev->RF->RG_RXBWC, _RXBWC_BW(chips));
/* Set fS; fCUT for RX */
at86rf215_reg_write(dev, dev->RF->RG_RXDFE, _RXDFE_SR(chips)
| _RXDFE_RCUT(chips));
/* Set Power Amplifier Ramp Time; fLPCUT */
at86rf215_reg_write(dev, dev->RF->RG_TXCUTC, _TXCUTC_PARAMP(chips)
| _TXCUTC_LPFCUT(chips));
/* Set fS; fCUT for TX */
at86rf215_reg_write(dev, dev->RF->RG_TXDFE, _TXDFE_SR(chips)
| _TXDFE_RCUT(chips)
| direct_modulation);
/* set receiver gain target according to data sheet, p125 */
at86rf215_reg_write(dev, dev->RF->RG_AGCS, 3 << AGCS_TGT_SHIFT);
at86rf215_reg_write(dev, dev->RF->RG_AGCC, _AGCC(chips));
/* use RC-0.8 shaping */
at86rf215_reg_write(dev, dev->BBC->RG_OQPSKC0, chips | direct_modulation);
}
static void _set_legacy(at86rf215_t *dev, bool high_rate)
{
uint8_t chips;
/* enable/disable legacy high data rate, only use SFD_1 */
if (high_rate) {
at86rf215_reg_write(dev, dev->BBC->RG_OQPSKC3, OQPSKC3_HRLEG_MASK);
} else {
at86rf215_reg_write(dev, dev->BBC->RG_OQPSKC3, 0);
}
if (is_subGHz(dev)) {
chips = BB_FCHIP1000;
} else {
chips = BB_FCHIP2000;
}
_set_chips(dev, chips);
at86rf215_reg_write(dev, dev->BBC->RG_OQPSKPHRTX, AT86RF215_OQPSK_MODE_LEGACY);
at86rf215_reg_write(dev, dev->BBC->RG_OQPSKC2,
RXM_LEGACY_OQPSK /* receive mode, legacy O-QPSK */
| OQPSKC2_FCSTLEG_MASK /* 16 bit frame checksum */
| OQPSKC2_ENPROP_MASK); /* enable RX of proprietary modes */
}
static inline void _set_ack_timeout_legacy(at86rf215_t *dev)
{
dev->ack_timeout_usec = AT86RF215_ACK_PERIOD_IN_SYMBOLS * LEGACY_QPSK_SYMBOL_TIME_US;
DEBUG("[%s] ACK timeout: %"PRIu32" µs\n", "legacy O-QPSK", dev->ack_timeout_usec);
}
static void _set_ack_timeout(at86rf215_t *dev, uint8_t chips, uint8_t mode)
{
/* see 802.15.4g-2012, p. 30 */
uint16_t symbols = _get_cca_duration_syms(chips)
+ _get_shr_duration_syms(chips)
+ 15 /* PHR duration */
+ _get_ack_psdu_duration_syms(chips, mode);
dev->ack_timeout_usec = _get_symbol_duration_us(chips) * symbols
+ IEEE802154G_ATURNAROUNDTIME_US;
DEBUG("[%s] ACK timeout: %"PRIu32" µs\n", "O-QPSK", dev->ack_timeout_usec);
}
static inline void _set_csma_backoff_period(at86rf215_t *dev, uint8_t chips)
{
dev->csma_backoff_period = _get_cca_duration_syms(chips) * _get_symbol_duration_us(chips)
+ IEEE802154G_ATURNAROUNDTIME_US;
DEBUG("[%s] CSMA BACKOFF: %"PRIu32" µs\n", "O-QPSK", dev->csma_backoff_period);
}
static inline void _set_csma_backoff_period_legacy(at86rf215_t *dev)
{
dev->csma_backoff_period = (IEEE802154_ATURNAROUNDTIME_IN_SYMBOLS + IEEE802154_CCA_DURATION_IN_SYMBOLS)
* LEGACY_QPSK_SYMBOL_TIME_US;
DEBUG("[%s] CSMA BACKOFF: %"PRIu32" µs\n", "legacy O-QPSK", dev->csma_backoff_period);
}
void _end_configure_OQPSK(at86rf215_t *dev)
{
/* set channel spacing with 25 kHz resolution */
if (is_subGHz(dev)) {
at86rf215_reg_write(dev, dev->RF->RG_CS, QPSK_CHANNEL_SPACING_SUBGHZ / 25);
at86rf215_reg_write16(dev, dev->RF->RG_CCF0L, QPSK_CENTER_FREQUENCY_SUBGHZ / 25);
} else {
at86rf215_reg_write(dev, dev->RF->RG_CS, QPSK_CHANNEL_SPACING_24GHZ / 25);
at86rf215_reg_write16(dev, dev->RF->RG_CCF0L, QPSK_CENTER_FREQUENCY_24GHZ / 25);
}
/* lowest preamble detection sensitivity, enable receiver override */
at86rf215_reg_write(dev, dev->BBC->RG_OQPSKC1, OQPSKC1_RXO_MASK | OQPSKC1_RXOLEG_MASK);
/* make sure the channel config is still valid */
dev->num_chans = is_subGHz(dev) ? 1 : 16;
dev->netdev.chan = at86rf215_chan_valid(dev, dev->netdev.chan);
at86rf215_reg_write16(dev, dev->RF->RG_CNL, dev->netdev.chan);
/* disable FSK preamble switching */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
dev->fsk_pl = 0;
#endif
at86rf215_enable_radio(dev, BB_MROQPSK);
}
int at86rf215_configure_OQPSK(at86rf215_t *dev, uint8_t chips, uint8_t mode)
{
if (chips > BB_FCHIP2000) {
DEBUG("[%s] invalid chips: %d\n", __func__, chips);
return -EINVAL;
}
if (mode > 4) {
DEBUG("[%s] invalid mode: %d\n", __func__, mode);
return -EINVAL;
}
/* mode 4 only supports 2000 kchip/s */
if (mode == 4 && chips != BB_FCHIP2000) {
DEBUG("[%s] mode 4 only supports 2000 kChip/s\n", __func__);
return -EINVAL;
}
at86rf215_await_state_end(dev, RF_STATE_TX);
/* disable radio */
at86rf215_reg_write(dev, dev->BBC->RG_PC, 0);
_set_mode(dev, mode);
_set_chips(dev, chips);
_set_csma_backoff_period(dev, chips);
_set_ack_timeout(dev, chips, mode);
_end_configure_OQPSK(dev);
return 0;
}
int at86rf215_configure_legacy_OQPSK(at86rf215_t *dev, bool high_rate)
{
at86rf215_await_state_end(dev, RF_STATE_TX);
/* disable radio */
at86rf215_reg_write(dev, dev->BBC->RG_PC, 0);
_set_legacy(dev, high_rate);
_set_csma_backoff_period_legacy(dev);
_set_ack_timeout_legacy(dev);
_end_configure_OQPSK(dev);
return 0;
}
int at86rf215_OQPSK_set_chips(at86rf215_t *dev, uint8_t chips)
{
uint8_t mode;
mode = at86rf215_reg_read(dev, dev->BBC->RG_OQPSKPHRTX);
if (mode & AT86RF215_OQPSK_MODE_LEGACY) {
DEBUG("[%s] can't set chip rate in legacy mode\n", __func__);
return -1;
}
at86rf215_await_state_end(dev, RF_STATE_TX);
_set_chips(dev, chips);
_set_csma_backoff_period(dev, chips);
_set_ack_timeout(dev, chips, mode >> OQPSKPHRTX_MOD_SHIFT);
return 0;
}
uint8_t at86rf215_OQPSK_get_chips(at86rf215_t *dev)
{
return at86rf215_reg_read(dev, dev->BBC->RG_OQPSKC0) & OQPSKC0_FCHIP_MASK;
}
int at86rf215_OQPSK_set_mode(at86rf215_t *dev, uint8_t mode)
{
if (mode > 4) {
return -1;
}
uint8_t chips = at86rf215_OQPSK_get_chips(dev);
at86rf215_await_state_end(dev, RF_STATE_TX);
if (mode == 4 && chips != BB_FCHIP2000) {
_set_chips(dev, BB_FCHIP2000);
}
_set_mode(dev, mode);
_set_csma_backoff_period(dev, chips);
_set_ack_timeout(dev, chips, mode);
return 0;
}
uint8_t at86rf215_OQPSK_get_mode(at86rf215_t *dev)
{
uint8_t mode = at86rf215_reg_read(dev, dev->BBC->RG_OQPSKPHRTX);
return (mode & OQPSKPHRTX_MOD_MASK) >> OQPSKPHRTX_MOD_SHIFT;
}
int at86rf215_OQPSK_set_mode_legacy(at86rf215_t *dev, bool high_rate)
{
/* enable/disable legacy high data rate */
if (high_rate) {
at86rf215_reg_write(dev, dev->BBC->RG_OQPSKC3, OQPSKC3_HRLEG_MASK);
} else {
at86rf215_reg_write(dev, dev->BBC->RG_OQPSKC3, 0);
}
_set_csma_backoff_period_legacy(dev);
_set_ack_timeout_legacy(dev);
return 0;
}
uint8_t at86rf215_OQPSK_get_mode_legacy(at86rf215_t *dev)
{
if (at86rf215_reg_read(dev, dev->BBC->RG_OQPSKC3) & OQPSKC3_HRLEG_MASK) {
return 1;
}
return 0;
}

Wyświetl plik

@ -1,332 +0,0 @@
/*
* Copyright (C) 2019 ML!PA Consulting GmbH
*
* 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.
*/
/**
* @ingroup drivers_at86rf215
* @{
*
* @file
* @brief Configuration of the MR-OFDM PHY on the AT86RF215 chip
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
* @}
*/
#include <errno.h>
#include "at86rf215.h"
#include "at86rf215_internal.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/* symbol time is always 120 µs for MR-OFDM */
#define OFDM_SYMBOL_TIME_US 120
/* IEEE Std 802.15.4g™-2012 Amendment 3
* Table 68dTotal number of channels and first channel center frequencies for SUN PHYs */
static uint32_t _channel_spacing_kHz(uint8_t option)
{
switch (option) {
case 1: return 1200;
case 2: return 800;
case 3: return 400;
case 4: return 200;
}
return 0;
}
/* IEEE Std 802.15.4g™-2012 Amendment 3
* Table 68dTotal number of channels and first channel center frequencies for SUN PHYs */
static uint32_t _channel_center_freq_kHz_868MHz(uint8_t option)
{
switch (option) {
case 1: return 863625;
case 2: return 863425;
case 3: return 863225;
case 4: return 863125;
}
return 0;
}
/* IEEE Std 802.15.4g™-2012 Amendment 3
* Table 68dTotal number of channels and first channel center frequencies for SUN PHYs */
static uint32_t _channel_center_freq_kHz_2400MHz(uint8_t option)
{
return 2400000 + _channel_spacing_kHz(option) - CCF0_24G_OFFSET;
}
/* IEEE Std 802.15.4g™-2012 Amendment 3
* Table 68dTotal number of channels and first channel center frequencies for SUN PHYs */
static uint16_t _get_max_chan(at86rf215_t *dev, uint8_t option)
{
if (is_subGHz(dev)) {
switch (option) {
case 1: return 5;
case 2: return 8;
case 3: return 17;
case 4: return 34;
}
}
else {
switch (option) {
case 1: return 64;
case 2: return 97;
case 3: return 207;
case 4: return 416;
}
}
return 0;
}
/* Table 6-90. Recommended Transmitter Frontend Configuration */
static uint32_t _TXCUTC_LPFCUT(uint8_t option)
{
switch (option) {
case 1: return 10 << TXCUTC_LPFCUT_SHIFT;
case 2: return 8 << TXCUTC_LPFCUT_SHIFT;
case 3: return 5 << TXCUTC_LPFCUT_SHIFT;
case 4: return 3 << TXCUTC_LPFCUT_SHIFT;
}
return 0;
}
/* Table 6-90. Recommended Transmitter Frontend Configuration */
static uint32_t _TXDFE_SR(uint8_t option)
{
switch (option) {
case 1:
case 2: return 3 << TXDFE_SR_SHIFT;
case 3:
case 4: return 6 << TXDFE_SR_SHIFT;
}
return 0;
}
/* Table 6-90. Recommended Transmitter Frontend Configuration */
static uint32_t _TXDFE_RCUT(uint8_t option)
{
switch (option) {
case 1: return 3 << TXDFE_RCUT_SHIFT;
case 2:
case 3: return 3 << TXDFE_RCUT_SHIFT;
case 4: return 2 << TXDFE_RCUT_SHIFT;
}
return 0;
}
/* Table 6-93. Recommended PHY Receiver and Digital Frontend Configuration */
static uint32_t _RXDFE_RCUT(uint8_t option, bool superGHz)
{
switch (option) {
case 1: return 4 << RXDFE_RCUT_SHIFT;
case 2: return 2 << RXDFE_RCUT_SHIFT;
case 3: return (2 + superGHz) << RXDFE_RCUT_SHIFT;
case 4: return 1 << RXDFE_RCUT_SHIFT;
}
return 0;
}
/* Table 6-93. Recommended PHY Receiver and Digital Frontend Configuration */
static uint32_t _RXBWC_BW(uint8_t option, bool superGHz)
{
switch (option) {
case 1: return (9 + superGHz) << RXBWC_BW_SHIFT;
case 2: return 7 << RXBWC_BW_SHIFT;
case 3: return (4 + superGHz) << RXBWC_BW_SHIFT;
case 4: return (2 + superGHz) << RXBWC_BW_SHIFT;
}
return 0;
}
/* Table 6-93. Recommended PHY Receiver and Digital Frontend Configuration */
static uint32_t _RXBWC_IFS(uint8_t option, bool superGHz)
{
switch (option) {
case 1:
case 2: return 1;
case 3: return superGHz;
case 4: return !superGHz;
}
return 0;
}
static void _set_option(at86rf215_t *dev, uint8_t option)
{
const bool superGHz = !is_subGHz(dev);
/* Set Receiver Bandwidth */
at86rf215_reg_write(dev, dev->RF->RG_RXBWC,
_RXBWC_BW(option, superGHz) | _RXBWC_IFS(option, superGHz));
/* Set fS (same as TX); fCUT for RX */
at86rf215_reg_write(dev, dev->RF->RG_RXDFE,
_TXDFE_SR(option) | _RXDFE_RCUT(option, superGHz));
/* Set Power Amplifier Ramp Time; fLPCUT */
at86rf215_reg_write(dev, dev->RF->RG_TXCUTC,
RF_PARAMP8U | _TXCUTC_LPFCUT(option));
/* Set fS; fCUT for TX */
at86rf215_reg_write(dev, dev->RF->RG_TXDFE,
_TXDFE_SR(option) | _TXDFE_RCUT(option));
/* set channel spacing with 25 kHz resolution */
at86rf215_reg_write(dev, dev->RF->RG_CS, _channel_spacing_kHz(option) / 25);
/* set channel center frequency with 25 kHz resolution */
if (superGHz) {
at86rf215_reg_write16(dev, dev->RF->RG_CCF0L,
1 + _channel_center_freq_kHz_2400MHz(option) / 25);
}
else {
at86rf215_reg_write16(dev, dev->RF->RG_CCF0L,
1 + _channel_center_freq_kHz_868MHz(option) / 25);
}
at86rf215_reg_write(dev, dev->BBC->RG_OFDMC, option - 1);
/* make sure channel config is still valid */
dev->num_chans = _get_max_chan(dev, option);
dev->netdev.chan = at86rf215_chan_valid(dev, dev->netdev.chan);
at86rf215_reg_write16(dev, dev->RF->RG_CNL, dev->netdev.chan);
}
static unsigned _get_frame_duration(uint8_t option, uint8_t scheme,
uint8_t bytes)
{
/* Table 150 - phySymbolsPerOctet values for MR-OFDM PHY, IEEE 802.15.4g-2012 */
static const uint8_t quot[] = { 3, 3, 6, 12, 18, 24, 36 };
--option;
/* phyMaxFrameDuration = phySHRDuration + phyPHRDuration + ceiling [(aMaxPHYPacketSize + 1) x phySymbolsPerOctet] */
const unsigned phySHRDuration = 6;
const unsigned phyPHRDuration = option ? 6 : 3;
const unsigned phyPDUDuration = ((bytes + 1) * (1 << option) + quot[scheme] - 1)
/ quot[scheme];
return (phySHRDuration + phyPHRDuration + phyPDUDuration) * OFDM_SYMBOL_TIME_US;
}
static void _set_ack_timeout(at86rf215_t *dev, uint8_t option, uint8_t scheme)
{
dev->ack_timeout_usec = dev->csma_backoff_period
+ IEEE802154G_ATURNAROUNDTIME_US
+ _get_frame_duration(option, scheme,
AT86RF215_ACK_PSDU_BYTES);
DEBUG("[%s] ACK timeout: %" PRIu32 " µs\n", "OFDM", dev->ack_timeout_usec);
}
static bool _option_mcs_valid(uint8_t option, uint8_t mcs)
{
if (option < 1 || option > 4) {
return false;
}
if (mcs > BB_MCS_16QAM_3BY4) {
return false;
}
if (mcs == BB_MCS_BPSK_REP4 && option > 2) {
return false;
}
if (mcs == BB_MCS_BPSK_REP2 && option == 4) {
return false;
}
return true;
}
int at86rf215_configure_OFDM(at86rf215_t *dev, uint8_t option, uint8_t scheme)
{
if (!_option_mcs_valid(option, scheme)) {
DEBUG("[%s] invalid option/MCS: %d | %d\n", __func__, option, scheme);
return -EINVAL;
}
at86rf215_await_state_end(dev, RF_STATE_TX);
/* disable radio */
at86rf215_reg_write(dev, dev->BBC->RG_PC, 0);
/* set receiver gain target according to data sheet */
at86rf215_reg_write(dev, dev->RF->RG_AGCS, 3 << AGCS_TGT_SHIFT);
/* enable automatic receiver gain */
at86rf215_reg_write(dev, dev->RF->RG_AGCC, AGCC_EN_MASK);
_set_option(dev, option);
at86rf215_reg_write(dev, dev->BBC->RG_OFDMPHRTX, scheme);
dev->csma_backoff_period = IEEE802154G_ATURNAROUNDTIME_US
+ IEEE802154_CCA_DURATION_IN_SYMBOLS
* OFDM_SYMBOL_TIME_US;
DEBUG("[%s] CSMA BACKOFF: %" PRIu32 " µs\n", "OFDM",
dev->csma_backoff_period);
_set_ack_timeout(dev, option, scheme);
/* disable FSK preamble switching */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
dev->fsk_pl = 0;
#endif
at86rf215_enable_radio(dev, BB_MROFDM);
return 0;
}
int at86rf215_OFDM_set_scheme(at86rf215_t *dev, uint8_t scheme)
{
uint8_t option = at86rf215_OFDM_get_option(dev);
if (!_option_mcs_valid(option, scheme)) {
DEBUG("[%s] invalid MCS: %d\n", __func__, scheme);
return -1;
}
at86rf215_await_state_end(dev, RF_STATE_TX);
at86rf215_reg_write(dev, dev->BBC->RG_OFDMPHRTX, scheme);
_set_ack_timeout(dev, at86rf215_OFDM_get_option(dev), scheme);
return 0;
}
uint8_t at86rf215_OFDM_get_scheme(at86rf215_t *dev)
{
return at86rf215_reg_read(dev, dev->BBC->RG_OFDMPHRTX) & OFDMPHRTX_MCS_MASK;
}
int at86rf215_OFDM_set_option(at86rf215_t *dev, uint8_t option)
{
uint8_t mcs = at86rf215_OFDM_get_scheme(dev);
if (!_option_mcs_valid(option, mcs)) {
DEBUG("[%s] invalid option: %d\n", __func__, option);
return -1;
}
at86rf215_await_state_end(dev, RF_STATE_TX);
_set_option(dev, option);
_set_ack_timeout(dev, option, mcs);
return 0;
}
uint8_t at86rf215_OFDM_get_option(at86rf215_t *dev)
{
return 1 + (at86rf215_reg_read(dev, dev->BBC->RG_OFDMC) & OFDMC_OPT_MASK);
}

Wyświetl plik

@ -1,618 +0,0 @@
/*
* Copyright (C) 2019 ML!PA Consulting GmbH
*
* 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.
*/
/**
* @ingroup drivers_at86rf215
* @{
*
* @file
* @brief Register Definitions for the AT86RF215 chip
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
* @}
*/
#ifndef AT86RF215_REGISTERS_H
#define AT86RF215_REGISTERS_H
#include <stdint.h>
#include "at86rf215_regs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Radio Frontend registers
* @{
*/
struct at86rf215_RF_regs {
uint16_t RG_IRQS; /**< see datasheet */
uint16_t RG_IRQM; /**< see datasheet */
uint16_t RG_AUXS; /**< see datasheet */
uint16_t RG_STATE; /**< see datasheet */
uint16_t RG_CMD; /**< see datasheet */
uint16_t RG_CS; /**< see datasheet */
uint16_t RG_CCF0L; /**< see datasheet */
uint16_t RG_CCF0H; /**< see datasheet */
uint16_t RG_CNL; /**< see datasheet */
uint16_t RG_CNM; /**< see datasheet */
uint16_t RG_RXBWC; /**< see datasheet */
uint16_t RG_RXDFE; /**< see datasheet */
uint16_t RG_AGCC; /**< see datasheet */
uint16_t RG_AGCS; /**< see datasheet */
uint16_t RG_RSSI; /**< see datasheet */
uint16_t RG_EDC; /**< see datasheet */
uint16_t RG_EDD; /**< see datasheet */
uint16_t RG_EDV; /**< see datasheet */
uint16_t RG_RNDV; /**< see datasheet */
uint16_t RG_TXCUTC; /**< see datasheet */
uint16_t RG_TXDFE; /**< see datasheet */
uint16_t RG_PAC; /**< see datasheet */
uint16_t RG_PADFE; /**< see datasheet */
uint16_t RG_PLL; /**< see datasheet */
uint16_t RG_PLLCF; /**< see datasheet */
uint16_t RG_TXCI; /**< see datasheet */
uint16_t RG_TXCQ; /**< see datasheet */
uint16_t RG_TXDACI; /**< see datasheet */
uint16_t RG_TXDACQ; /**< see datasheet */
};
/** @} */
/**
* @brief Base Band Controller registers
* @{
*/
struct at86rf215_BBC_regs {
uint16_t RG_IRQS; /**< see datasheet */
uint16_t RG_FBRXS; /**< see datasheet */
uint16_t RG_FBRXE; /**< see datasheet */
uint16_t RG_FBTXS; /**< see datasheet */
uint16_t RG_FBTXE; /**< see datasheet */
uint16_t RG_IRQM; /**< see datasheet */
uint16_t RG_PC; /**< see datasheet */
uint16_t RG_PS; /**< see datasheet */
uint16_t RG_RXFLL; /**< see datasheet */
uint16_t RG_RXFLH; /**< see datasheet */
uint16_t RG_TXFLL; /**< see datasheet */
uint16_t RG_TXFLH; /**< see datasheet */
uint16_t RG_FBLL; /**< see datasheet */
uint16_t RG_FBLH; /**< see datasheet */
uint16_t RG_FBLIL; /**< see datasheet */
uint16_t RG_FBLIH; /**< see datasheet */
uint16_t RG_OFDMPHRTX; /**< see datasheet */
uint16_t RG_OFDMPHRRX; /**< see datasheet */
uint16_t RG_OFDMC; /**< see datasheet */
uint16_t RG_OFDMSW; /**< see datasheet */
uint16_t RG_OQPSKC0; /**< see datasheet */
uint16_t RG_OQPSKC1; /**< see datasheet */
uint16_t RG_OQPSKC2; /**< see datasheet */
uint16_t RG_OQPSKC3; /**< see datasheet */
uint16_t RG_OQPSKPHRTX; /**< see datasheet */
uint16_t RG_OQPSKPHRRX; /**< see datasheet */
uint16_t RG_AFC0; /**< see datasheet */
uint16_t RG_AFC1; /**< see datasheet */
uint16_t RG_AFFTM; /**< see datasheet */
uint16_t RG_AFFVM; /**< see datasheet */
uint16_t RG_AFS; /**< see datasheet */
uint16_t RG_MACEA0; /**< see datasheet */
uint16_t RG_MACEA1; /**< see datasheet */
uint16_t RG_MACEA2; /**< see datasheet */
uint16_t RG_MACEA3; /**< see datasheet */
uint16_t RG_MACEA4; /**< see datasheet */
uint16_t RG_MACEA5; /**< see datasheet */
uint16_t RG_MACEA6; /**< see datasheet */
uint16_t RG_MACEA7; /**< see datasheet */
uint16_t RG_MACPID0F0; /**< see datasheet */
uint16_t RG_MACPID1F0; /**< see datasheet */
uint16_t RG_MACSHA0F0; /**< see datasheet */
uint16_t RG_MACSHA1F0; /**< see datasheet */
uint16_t RG_MACPID0F1; /**< see datasheet */
uint16_t RG_MACPID1F1; /**< see datasheet */
uint16_t RG_MACSHA0F1; /**< see datasheet */
uint16_t RG_MACSHA1F1; /**< see datasheet */
uint16_t RG_MACPID0F2; /**< see datasheet */
uint16_t RG_MACPID1F2; /**< see datasheet */
uint16_t RG_MACSHA0F2; /**< see datasheet */
uint16_t RG_MACSHA1F2; /**< see datasheet */
uint16_t RG_MACPID0F3; /**< see datasheet */
uint16_t RG_MACPID1F3; /**< see datasheet */
uint16_t RG_MACSHA0F3; /**< see datasheet */
uint16_t RG_MACSHA1F3; /**< see datasheet */
uint16_t RG_AMCS; /**< see datasheet */
uint16_t RG_AMEDT; /**< see datasheet */
uint16_t RG_AMAACKPD; /**< see datasheet */
uint16_t RG_AMAACKTL; /**< see datasheet */
uint16_t RG_AMAACKTH; /**< see datasheet */
uint16_t RG_FSKC0; /**< see datasheet */
uint16_t RG_FSKC1; /**< see datasheet */
uint16_t RG_FSKC2; /**< see datasheet */
uint16_t RG_FSKC3; /**< see datasheet */
uint16_t RG_FSKC4; /**< see datasheet */
uint16_t RG_FSKPLL; /**< see datasheet */
uint16_t RG_FSKSFD0L; /**< see datasheet */
uint16_t RG_FSKSFD0H; /**< see datasheet */
uint16_t RG_FSKSFD1L; /**< see datasheet */
uint16_t RG_FSKSFD1H; /**< see datasheet */
uint16_t RG_FSKPHRTX; /**< see datasheet */
uint16_t RG_FSKPHRRX; /**< see datasheet */
uint16_t RG_FSKRPC; /**< see datasheet */
uint16_t RG_FSKRPCONT; /**< see datasheet */
uint16_t RG_FSKRPCOFFT; /**< see datasheet */
uint16_t RG_FSKRRXFLL; /**< see datasheet */
uint16_t RG_FSKRRXFLH; /**< see datasheet */
uint16_t RG_FSKDM; /**< see datasheet */
uint16_t RG_FSKPE0; /**< see datasheet */
uint16_t RG_FSKPE1; /**< see datasheet */
uint16_t RG_FSKPE2; /**< see datasheet */
uint16_t RG_PMUC; /**< see datasheet */
uint16_t RG_PMUVAL; /**< see datasheet */
uint16_t RG_PMUQF; /**< see datasheet */
uint16_t RG_PMUI; /**< see datasheet */
uint16_t RG_PMUQ; /**< see datasheet */
uint16_t RG_CNTC; /**< see datasheet */
uint16_t RG_CNT0; /**< see datasheet */
uint16_t RG_CNT1; /**< see datasheet */
uint16_t RG_CNT2; /**< see datasheet */
uint16_t RG_CNT3; /**< see datasheet */
};
/** @} */
/**
* @name sub-GHz Radio Frontend register map
* @{
*/
static const struct at86rf215_RF_regs RF09_regs = {
.RG_IRQS = 0x00,
.RG_IRQM = 0x100,
.RG_AUXS = 0x101,
.RG_STATE = 0x102,
.RG_CMD = 0x103,
.RG_CS = 0x104,
.RG_CCF0L = 0x105,
.RG_CCF0H = 0x106,
.RG_CNL = 0x107,
.RG_CNM = 0x108,
.RG_RXBWC = 0x109,
.RG_RXDFE = 0x10A,
.RG_AGCC = 0x10B,
.RG_AGCS = 0x10C,
.RG_RSSI = 0x10D,
.RG_EDC = 0x10E,
.RG_EDD = 0x10F,
.RG_EDV = 0x110,
.RG_RNDV = 0x111,
.RG_TXCUTC = 0x112,
.RG_TXDFE = 0x113,
.RG_PAC = 0x114,
.RG_PADFE = 0x116,
.RG_PLL = 0x121,
.RG_PLLCF = 0x122,
.RG_TXCI = 0x125,
.RG_TXCQ = 0x126,
.RG_TXDACI = 0x127,
.RG_TXDACQ = 0x128,
};
/** @} */
/**
* @name 2.4 GHz Radio Frontend register map
* @{
*/
static const struct at86rf215_RF_regs RF24_regs = {
.RG_IRQS = 0x01,
.RG_IRQM = 0x200,
.RG_AUXS = 0x201,
.RG_STATE = 0x202,
.RG_CMD = 0x203,
.RG_CS = 0x204,
.RG_CCF0L = 0x205,
.RG_CCF0H = 0x206,
.RG_CNL = 0x207,
.RG_CNM = 0x208,
.RG_RXBWC = 0x209,
.RG_RXDFE = 0x20A,
.RG_AGCC = 0x20B,
.RG_AGCS = 0x20C,
.RG_RSSI = 0x20D,
.RG_EDC = 0x20E,
.RG_EDD = 0x20F,
.RG_EDV = 0x210,
.RG_RNDV = 0x211,
.RG_TXCUTC = 0x212,
.RG_TXDFE = 0x213,
.RG_PAC = 0x214,
.RG_PADFE = 0x216,
.RG_PLL = 0x221,
.RG_PLLCF = 0x222,
.RG_TXCI = 0x225,
.RG_TXCQ = 0x226,
.RG_TXDACI = 0x227,
.RG_TXDACQ = 0x228,
};
/** @} */
/**
* @name sub-GHz Radio Frontend register map
* @{
*/
static const struct at86rf215_BBC_regs BBC0_regs = {
.RG_IRQS = 0x02,
.RG_FBRXS = 0x2000,
.RG_FBRXE = 0x27FE,
.RG_FBTXS = 0x2800,
.RG_FBTXE = 0x2FFE,
.RG_IRQM = 0x300,
.RG_PC = 0x301,
.RG_PS = 0x302,
.RG_RXFLL = 0x304,
.RG_RXFLH = 0x305,
.RG_TXFLL = 0x306,
.RG_TXFLH = 0x307,
.RG_FBLL = 0x308,
.RG_FBLH = 0x309,
.RG_FBLIL = 0x30A,
.RG_FBLIH = 0x30B,
.RG_OFDMPHRTX = 0x30C,
.RG_OFDMPHRRX = 0x30D,
.RG_OFDMC = 0x30E,
.RG_OFDMSW = 0x30F,
.RG_OQPSKC0 = 0x310,
.RG_OQPSKC1 = 0x311,
.RG_OQPSKC2 = 0x312,
.RG_OQPSKC3 = 0x313,
.RG_OQPSKPHRTX = 0x314,
.RG_OQPSKPHRRX = 0x315,
.RG_AFC0 = 0x320,
.RG_AFC1 = 0x321,
.RG_AFFTM = 0x322,
.RG_AFFVM = 0x323,
.RG_AFS = 0x324,
.RG_MACEA0 = 0x325,
.RG_MACEA1 = 0x326,
.RG_MACEA2 = 0x327,
.RG_MACEA3 = 0x328,
.RG_MACEA4 = 0x329,
.RG_MACEA5 = 0x32A,
.RG_MACEA6 = 0x32B,
.RG_MACEA7 = 0x32C,
.RG_MACPID0F0 = 0x32D,
.RG_MACPID1F0 = 0x32E,
.RG_MACSHA0F0 = 0x32F,
.RG_MACSHA1F0 = 0x330,
.RG_MACPID0F1 = 0x331,
.RG_MACPID1F1 = 0x332,
.RG_MACSHA0F1 = 0x333,
.RG_MACSHA1F1 = 0x334,
.RG_MACPID0F2 = 0x335,
.RG_MACPID1F2 = 0x336,
.RG_MACSHA0F2 = 0x337,
.RG_MACSHA1F2 = 0x338,
.RG_MACPID0F3 = 0x339,
.RG_MACPID1F3 = 0x33A,
.RG_MACSHA0F3 = 0x33B,
.RG_MACSHA1F3 = 0x33C,
.RG_AMCS = 0x340,
.RG_AMEDT = 0x341,
.RG_AMAACKPD = 0x342,
.RG_AMAACKTL = 0x343,
.RG_AMAACKTH = 0x344,
.RG_FSKC0 = 0x360,
.RG_FSKC1 = 0x361,
.RG_FSKC2 = 0x362,
.RG_FSKC3 = 0x363,
.RG_FSKC4 = 0x364,
.RG_FSKPLL = 0x365,
.RG_FSKSFD0L = 0x366,
.RG_FSKSFD0H = 0x367,
.RG_FSKSFD1L = 0x368,
.RG_FSKSFD1H = 0x369,
.RG_FSKPHRTX = 0x36A,
.RG_FSKPHRRX = 0x36B,
.RG_FSKRPC = 0x36C,
.RG_FSKRPCONT = 0x36D,
.RG_FSKRPCOFFT = 0x36E,
.RG_FSKRRXFLL = 0x370,
.RG_FSKRRXFLH = 0x371,
.RG_FSKDM = 0x372,
.RG_FSKPE0 = 0x373,
.RG_FSKPE1 = 0x374,
.RG_FSKPE2 = 0x375,
.RG_PMUC = 0x380,
.RG_PMUVAL = 0x381,
.RG_PMUQF = 0x382,
.RG_PMUI = 0x383,
.RG_PMUQ = 0x384,
.RG_CNTC = 0x390,
.RG_CNT0 = 0x391,
.RG_CNT1 = 0x392,
.RG_CNT2 = 0x393,
.RG_CNT3 = 0x394,
};
/** @} */
/**
* @name 2.4 GHz Radio Frontend register map
* @{
*/
static const struct at86rf215_BBC_regs BBC1_regs = {
.RG_IRQS = 0x03,
.RG_FBRXS = 0x3000,
.RG_FBRXE = 0x37FE,
.RG_FBTXS = 0x3800,
.RG_FBTXE = 0x3FFE,
.RG_IRQM = 0x400,
.RG_PC = 0x401,
.RG_PS = 0x402,
.RG_RXFLL = 0x404,
.RG_RXFLH = 0x405,
.RG_TXFLL = 0x406,
.RG_TXFLH = 0x407,
.RG_FBLL = 0x408,
.RG_FBLH = 0x409,
.RG_FBLIL = 0x40A,
.RG_FBLIH = 0x40B,
.RG_OFDMPHRTX = 0x40C,
.RG_OFDMPHRRX = 0x40D,
.RG_OFDMC = 0x40E,
.RG_OFDMSW = 0x40F,
.RG_OQPSKC0 = 0x410,
.RG_OQPSKC1 = 0x411,
.RG_OQPSKC2 = 0x412,
.RG_OQPSKC3 = 0x413,
.RG_OQPSKPHRTX = 0x414,
.RG_OQPSKPHRRX = 0x415,
.RG_AFC0 = 0x420,
.RG_AFC1 = 0x421,
.RG_AFFTM = 0x422,
.RG_AFFVM = 0x423,
.RG_AFS = 0x424,
.RG_MACEA0 = 0x425,
.RG_MACEA1 = 0x426,
.RG_MACEA2 = 0x427,
.RG_MACEA3 = 0x428,
.RG_MACEA4 = 0x429,
.RG_MACEA5 = 0x42A,
.RG_MACEA6 = 0x42B,
.RG_MACEA7 = 0x42C,
.RG_MACPID0F0 = 0x42D,
.RG_MACPID1F0 = 0x42E,
.RG_MACSHA0F0 = 0x42F,
.RG_MACSHA1F0 = 0x430,
.RG_MACPID0F1 = 0x431,
.RG_MACPID1F1 = 0x432,
.RG_MACSHA0F1 = 0x433,
.RG_MACSHA1F1 = 0x434,
.RG_MACPID0F2 = 0x435,
.RG_MACPID1F2 = 0x436,
.RG_MACSHA0F2 = 0x437,
.RG_MACSHA1F2 = 0x438,
.RG_MACPID0F3 = 0x439,
.RG_MACPID1F3 = 0x43A,
.RG_MACSHA0F3 = 0x43B,
.RG_MACSHA1F3 = 0x43C,
.RG_AMCS = 0x440,
.RG_AMEDT = 0x441,
.RG_AMAACKPD = 0x442,
.RG_AMAACKTL = 0x443,
.RG_AMAACKTH = 0x444,
.RG_FSKC0 = 0x460,
.RG_FSKC1 = 0x461,
.RG_FSKC2 = 0x462,
.RG_FSKC3 = 0x463,
.RG_FSKC4 = 0x464,
.RG_FSKPLL = 0x465,
.RG_FSKSFD0L = 0x466,
.RG_FSKSFD0H = 0x467,
.RG_FSKSFD1L = 0x468,
.RG_FSKSFD1H = 0x469,
.RG_FSKPHRTX = 0x46A,
.RG_FSKPHRRX = 0x46B,
.RG_FSKRPC = 0x46C,
.RG_FSKRPCONT = 0x46D,
.RG_FSKRPCOFFT = 0x46E,
.RG_FSKRRXFLL = 0x470,
.RG_FSKRRXFLH = 0x471,
.RG_FSKDM = 0x472,
.RG_FSKPE0 = 0x473,
.RG_FSKPE1 = 0x474,
.RG_FSKPE2 = 0x475,
.RG_PMUC = 0x480,
.RG_PMUVAL = 0x481,
.RG_PMUQF = 0x482,
.RG_PMUI = 0x483,
.RG_PMUQ = 0x484,
.RG_CNTC = 0x490,
.RG_CNT0 = 0x491,
.RG_CNT1 = 0x492,
.RG_CNT2 = 0x493,
.RG_CNT3 = 0x494,
};
/** @} */
/**
* @name Part Numbers
* @{
*/
#define AT86RF215_PN (0x34) /* sub-GHz & 2.4 GHz */
#define AT86RF215IQ_PN (0x35) /* I/Q radio only */
#define AT86RF215M_PN (0x36) /* sub-GHz only */
/** @} */
/**
* @name SPI command prefixes
* @{
*/
#define FLAG_WRITE 0x8000
#define FLAG_READ 0x0000
/** @} */
/**
* @name Radio Commands written to RF->RG_CMD
* @{
*/
#define CMD_RF_NOP 0x0
#define CMD_RF_SLEEP 0x1
#define CMD_RF_TRXOFF 0x2
#define CMD_RF_TXPREP 0x3
#define CMD_RF_TX 0x4
#define CMD_RF_RX 0x5
#define CMD_RF_RESET 0x7 /* transceiver reset, the transceiver state
will automatically end up in state TRXOFF */
/** @} */
/**
* @name Radio States, read from RF->RG_STATE
* @{
*/
#define RF_STATE_TRXOFF 0x2 /* Transceiver off, SPI active */
#define RF_STATE_TXPREP 0x3 /* Transmit preparation */
#define RF_STATE_TX 0x4 /* Transmit */
#define RF_STATE_RX 0x5 /* Receive */
#define RF_STATE_TRANSITION 0x6 /* State transition in progress */
#define RF_STATE_RESET 0x7 /* Transceiver is in state RESET or SLEEP */
/** @} */
/** offset (in Hz) for CCF0 in 2.4 GHz mode */
#define CCF0_24G_OFFSET 1500000U
/** The sub-register configures the sampling frequency of the received signal.
* Undefined values are mapped to default setting fS=4000kHz
* @{
*/
#define RF_SR_4000K 0x1
#define RF_SR_2000K 0x2
#define RF_SR_1333K 0x3
#define RF_SR_1000K 0x4
#define RF_SR_800K 0x5
#define RF_SR_666K 0x6
#define RF_SR_500K 0x8
#define RF_SR_400K 0xA
/** @} */
/* The sub-register configures the relative cut-off frequency fCUT
where 1.0 refers to half the sample frequency fS. */
/** Fcut = 0.25 * Fs/2 */
#define RF_RCUT_FS_BY_8 (0x0 << RXDFE_RCUT_SHIFT)
/** Fcut = 0.375 * Fs/2 */
#define RF_RCUT_FS_BY_5P3 (0x1 << RXDFE_RCUT_SHIFT)
/** Fcut = 0.5 * Fs/2 */
#define RF_RCUT_FS_BY_4 (0x2 << RXDFE_RCUT_SHIFT)
/** Fcut = 0.75 * Fs/2 */
#define RF_RCUT_FS_BY_2P6 (0x3 << RXDFE_RCUT_SHIFT)
/** Fcut = 1.0 * Fs/2 */
#define RF_RCUT_FS_BY_2 (0x4 << RXDFE_RCUT_SHIFT)
/** The averaging time is calculated by T[μs]=DF*DTB.
* @{
*/
#define RF_DTB_2_US 0x0
#define RF_DTB_8_US 0x1
#define RF_DTB_32_US 0x2
#define RF_DTB_128_US 0x3
/** @} */
/** BPSK, rate ½, 4 x frequency repetition */
#define BB_MCS_BPSK_REP4 0
/** BPSK, rate ½, 2 x frequency repetition */
#define BB_MCS_BPSK_REP2 1
/** QPSK, rate ½, 2 x frequency repetition */
#define BB_MCS_QPSK_REP2 2
/** QPSK, rate ½ */
#define BB_MCS_QPSK_1BY2 3
/** QPSK, rate ¾ */
#define BB_MCS_QPSK_3BY4 4
/** 16-QAM, rate ½ */
#define BB_MCS_16QAM_1BY2 5
/** 16-QAM, rate ¾ */
#define BB_MCS_16QAM_3BY4 6
/** receive only MR-O-QPSK */
#define RXM_MR_OQPSK 0x0
/** receive only legacy O-QPSK */
#define RXM_LEGACY_OQPSK 0x1
/** receive both legacy & MR-O-QPSK */
#define RXM_BOTH_OQPSK 0x2
/** receive nothing */
#define RXM_DISABLE 0x3
/** Modulation Order 2-FSK */
#define FSK_MORD_2SFK (0 << FSKC0_MORD_SHIFT)
/** Modulation Order 4-FSK */
#define FSK_MORD_4SFK (1 << FSKC0_MORD_SHIFT)
/**
* FSK modulation index
* @{
*/
#define FSK_MIDX_3_BY_8 (0 << FSKC0_MIDX_SHIFT)
#define FSK_MIDX_4_BY_8 (1 << FSKC0_MIDX_SHIFT)
#define FSK_MIDX_6_BY_8 (2 << FSKC0_MIDX_SHIFT)
#define FSK_MIDX_8_BY_8 (3 << FSKC0_MIDX_SHIFT)
#define FSK_MIDX_10_BY_8 (4 << FSKC0_MIDX_SHIFT)
#define FSK_MIDX_12_BY_8 (5 << FSKC0_MIDX_SHIFT)
#define FSK_MIDX_14_BY_8 (6 << FSKC0_MIDX_SHIFT)
#define FSK_MIDX_16_BY_8 (7 << FSKC0_MIDX_SHIFT)
/** @} */
/**
* FSK modulation index scale
* @{
*/
#define FSK_MIDXS_SCALE_7_BY_8 (0 << FSKC0_MIDXS_SHIFT)
#define FSK_MIDXS_SCALE_8_BY_8 (1 << FSKC0_MIDXS_SHIFT)
#define FSK_MIDXS_SCALE_9_BY_8 (2 << FSKC0_MIDXS_SHIFT)
#define FSK_MIDXS_SCALE_10_BY_8 (3 << FSKC0_MIDXS_SHIFT)
/** @} */
/**
* FSK bandwidth time product
* @{
*/
#define FSK_BT_05 (0 << FSKC0_BT_SHIFT)
#define FSK_BT_10 (1 << FSKC0_BT_SHIFT)
#define FSK_BT_15 (2 << FSKC0_BT_SHIFT)
#define FSK_BT_20 (3 << FSKC0_BT_SHIFT)
/** @} */
/**
* FSK symbol rate (kHz)
* @{
*/
#define FSK_SRATE_50K 0x0
#define FSK_SRATE_100K 0x1
#define FSK_SRATE_150K 0x2
#define FSK_SRATE_200K 0x3
#define FSK_SRATE_300K 0x4
#define FSK_SRATE_400K 0x5
/** @} */
/**
* FSK channel spacing (kHz)
* @{
*/
#define FSK_CHANNEL_SPACING_200K 0x0
#define FSK_CHANNEL_SPACING_400K 0x1
/** @} */
/** Lower values increase the SFD detector sensitivity.
Higher values increase the SFD selectivity.
The default value 8 is recommended for simultaneous sensing
of the SFD pairs according to IEEE 802.15.4g. */
#define FSKC3_SFDT(n) (((n) << FSKC3_SFDT_SHIFT) & FSKC3_SFDT_MASK)
/** Lower values increase the preamble detector sensitivity. */
#define FSKC3_PDT(n) (((n) << FSKC3_PDT_SHIFT) & FSKC3_PDT_MASK)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* AT86RF215_REGISTERS_H */

Wyświetl plik

@ -1,690 +0,0 @@
/*
* Copyright (C) 2014 René Kijewski
*
* 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.
*/
/**
* @ingroup sys
* @{
*
* @file
* @brief Functions to work with different byte orders.
*
* @author René Kijewski <rene.kijewski@fu-berlin.de>
*/
#ifndef BYTEORDER_H
#define BYTEORDER_H
#include <stdint.h>
#include "unaligned.h"
#if defined(__MACH__)
# include "clang_compat.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* ******************************* INTERFACE ******************************* */
/**
* @brief A 16 bit integer in little endian.
* @details This is a wrapper around an uint16_t to catch missing conversions
* between different byte orders at compile time.
*/
typedef union __attribute__((packed)) {
uint16_t u16; /**< 16 bit representation */
uint8_t u8[2]; /**< 8 bit representation */
} le_uint16_t;
/**
* @brief A 32 bit integer in little endian.
* @details This is a wrapper around an uint32_t to catch missing conversions
* between different byte orders at compile time.
*/
typedef union __attribute__((packed)) {
uint32_t u32; /**< 32 bit representation */
uint8_t u8[4]; /**< 8 bit representation */
uint16_t u16[2]; /**< 16 bit representation */
le_uint16_t l16[2]; /**< little endian 16 bit representation */
} le_uint32_t;
/**
* @brief A 64 bit integer in little endian.
* @details This is a wrapper around an uint64_t to catch missing conversions
* between different byte orders at compile time.
*/
typedef union __attribute__((packed)) {
uint64_t u64; /**< 64 bit representation */
uint8_t u8[8]; /**< 8 bit representation */
uint16_t u16[4]; /**< 16 bit representation */
uint32_t u32[2]; /**< 32 bit representation */
le_uint16_t l16[4]; /**< little endian 16 bit representation */
le_uint32_t l32[2]; /**< little endian 32 bit representation */
} le_uint64_t;
/**
* @brief A 16 bit integer in big endian aka network byte order.
* @details This is a wrapper around an uint16_t to catch missing conversions
* between different byte orders at compile time.
*/
typedef union __attribute__((packed)) {
uint16_t u16; /**< 16 bit representation */
uint8_t u8[2]; /**< 8 bit representation */
} be_uint16_t;
/**
* @brief A 32 bit integer in big endian aka network byte order.
* @details This is a wrapper around an uint32_t to catch missing conversions
* between different byte orders at compile time.
*/
typedef union __attribute__((packed)) {
uint32_t u32; /**< 32 bit representation */
uint8_t u8[4]; /**< 8 bit representation */
uint16_t u16[2]; /**< 16 bit representation */
be_uint16_t b16[2]; /**< big endian 16 bit representation */
} be_uint32_t;
/**
* @brief A 64 bit integer in big endian aka network byte order.
* @details This is a wrapper around an uint64_t to catch missing conversions
* between different byte orders at compile time.
*/
typedef union __attribute__((packed)) {
uint64_t u64; /**< 64 bit representation */
uint8_t u8[8]; /**< 8 bit representation */
uint16_t u16[4]; /**< 16 bit representation */
uint32_t u32[2]; /**< 32 bit representation */
be_uint16_t b16[4]; /**< big endian 16 bit representation */
be_uint32_t b32[2]; /**< big endian 32 bit representation */
} be_uint64_t;
/**
* @brief A 16 bit integer in network byte order.
*/
typedef be_uint16_t network_uint16_t;
/**
* @brief A 32 bit integer in network byte order.
*/
typedef be_uint32_t network_uint32_t;
/**
* @brief A 64 bit integer in network byte order.
*/
typedef be_uint64_t network_uint64_t;
/**
* @brief Convert from little endian to host byte order, 16 bit.
* @param[in] v The integer in little endian.
* @returns `v` converted to host byte order.
*/
static inline uint16_t byteorder_ltohs(le_uint16_t v);
/**
* @brief Convert from little endian to host byte order, 32 bit.
* @param[in] v The integer in little endian.
* @returns `v` converted to host byte order.
*/
static inline uint32_t byteorder_ltohl(le_uint32_t v);
/**
* @brief Convert from little endian to host byte order, 64 bit.
* @param[in] v The integer in little endian.
* @returns `v` converted to host byte order.
*/
static inline uint64_t byteorder_ltohll(le_uint64_t v);
/**
* @brief Convert from little endian to big endian, 16 bit.
* @param[in] v The integer in little endian.
* @returns `v` converted to big endian.
*/
static inline be_uint16_t byteorder_ltobs(le_uint16_t v);
/**
* @brief Convert from little endian to big endian, 32 bit.
* @param[in] v The integer in little endian.
* @returns `v` converted to big endian.
*/
static inline be_uint32_t byteorder_ltobl(le_uint32_t v);
/**
* @brief Convert from little endian to big endian, 64 bit.
* @param[in] v The integer in little endian.
* @returns `v` converted to big endian.
*/
static inline be_uint64_t byteorder_ltobll(le_uint64_t v);
/**
* @brief Convert from big endian to little endian, 16 bit.
* @param[in] v The integer in big endian.
* @returns `v` converted to little endian.
*/
static inline le_uint16_t byteorder_btols(be_uint16_t v);
/**
* @brief Convert from big endian to little endian, 32 bit.
* @param[in] v The integer in big endian.
* @returns `v` converted to little endian.
*/
static inline le_uint32_t byteorder_btoll(be_uint32_t v);
/**
* @brief Convert from big endian to little endian, 64 bit.
* @param[in] v The integer in big endian.
* @returns `v` converted to little endian.
*/
static inline le_uint64_t byteorder_btolll(be_uint64_t v);
/**
* @brief Convert from host byte order to little endian, 16 bit.
* @param[in] v The integer in host byte order.
* @returns `v` converted to little endian.
*/
static inline le_uint16_t byteorder_htols(uint16_t v);
/**
* @brief Convert from host byte order to little endian, 32 bit.
* @param[in] v The integer in host byte order.
* @returns `v` converted to little endian.
*/
static inline le_uint32_t byteorder_htoll(uint32_t v);
/**
* @brief Convert from host byte order to little endian, 64 bit.
* @param[in] v The integer in host byte order.
* @returns `v` converted to little endian.
*/
static inline le_uint64_t byteorder_htolll(uint64_t v);
/**
* @brief Convert from host byte order to network byte order, 16 bit.
* @param[in] v The integer in host byte order.
* @returns `v` converted to network byte order.
*/
static inline network_uint16_t byteorder_htons(uint16_t v);
/**
* @brief Convert from host byte order to network byte order, 32 bit.
* @param[in] v The integer in host byte order.
* @returns `v` converted to network byte order.
*/
static inline network_uint32_t byteorder_htonl(uint32_t v);
/**
* @brief Convert from host byte order to network byte order, 64 bit.
* @param[in] v The integer in host byte order.
* @returns `v` converted to network byte order.
*/
static inline network_uint64_t byteorder_htonll(uint64_t v);
/**
* @brief Convert from network byte order to host byte order, 16 bit.
* @param[in] v The integer in network byte order.
* @returns `v` converted to host byte order.
*/
static inline uint16_t byteorder_ntohs(network_uint16_t v);
/**
* @brief Convert from network byte order to host byte order, 32 bit.
* @param[in] v The integer in network byte order.
* @returns `v` converted to host byte order.
*/
static inline uint32_t byteorder_ntohl(network_uint32_t v);
/**
* @brief Convert from network byte order to host byte order, 64 bit.
* @param[in] v The integer in network byte order.
* @returns `v` converted to host byte order.
*/
static inline uint64_t byteorder_ntohll(network_uint64_t v);
/**
* @brief Swap byte order, 16 bit.
* @param[in] v The integer to swap.
* @returns The swapped integer.
*/
static inline uint16_t byteorder_swaps(uint16_t v);
/**
* @brief Swap byte order, 32 bit.
* @param[in] v The integer to swap.
* @returns The swapped integer.
*/
static inline uint32_t byteorder_swapl(uint32_t v);
/**
* @brief Swap byte order, 64 bit.
* @param[in] v The integer to swap.
* @returns The swapped integer.
*/
static inline uint64_t byteorder_swapll(uint64_t v);
/**
* @brief Read a big endian encoded unsigned integer from a buffer
* into host byte order encoded variable, 16-bit
*
* @note This function is agnostic to the alignment of the target
* value in the given buffer
*
* @param[in] buf position in a buffer holding the target value
*
* @return 16-bit unsigned integer in host byte order
*/
static inline uint16_t byteorder_bebuftohs(const uint8_t *buf);
/**
* @brief Read a big endian encoded unsigned integer from a buffer
* into host byte order encoded variable, 32-bit
*
* @note This function is agnostic to the alignment of the target
* value in the given buffer
*
* @param[in] buf position in a buffer holding the target value
*
* @return 32-bit unsigned integer in host byte order
*/
static inline uint32_t byteorder_bebuftohl(const uint8_t *buf);
/**
* @brief Read a big endian encoded unsigned integer from a buffer
* into host byte order encoded variable, 64-bit
*
* @note This function is agnostic to the alignment of the target
* value in the given buffer
*
* @param[in] buf position in a buffer holding the target value
*
* @return 64-bit unsigned integer in host byte order
*/
static inline uint64_t byteorder_bebuftohll(const uint8_t *buf);
/**
* @brief Write a host byte order encoded unsigned integer as big
* endian encoded value into a buffer, 16-bit
*
* @note This function is alignment agnostic and works with any given
* memory location of the buffer
*
* @param[out] buf target buffer, must be able to accept 2 bytes
* @param[in] val value written to the buffer, in host byte order
*/
static inline void byteorder_htobebufs(uint8_t *buf, uint16_t val);
/**
* @brief Write a host byte order encoded unsigned integer as big
* endian encoded value into a buffer, 32-bit
*
* @note This function is alignment agnostic and works with any given
* memory location of the buffer
*
* @param[out] buf target buffer, must be able to accept 4 bytes
* @param[in] val value written to the buffer, in host byte order
*/
static inline void byteorder_htobebufl(uint8_t *buf, uint32_t val);
/**
* @brief Write a host byte order encoded unsigned integer as big
* endian encoded value into a buffer, 64-bit
*
* @note This function is alignment agnostic and works with any given
* memory location of the buffer
*
* @param[out] buf target buffer, must be able to accept 8 bytes
* @param[in] val value written to the buffer, in host byte order
*/
static inline void byteorder_htobebufll(uint8_t *buf, uint64_t val);
/**
* @brief Convert from host byte order to network byte order, 16 bit.
* @see byteorder_htons()
* @param[in] v The integer to convert.
* @returns Converted integer.
*/
static inline uint16_t htons(uint16_t v);
/**
* @brief Convert from host byte order to network byte order, 32 bit.
* @see byteorder_htonl()
* @param[in] v The integer to convert.
* @returns Converted integer.
*/
static inline uint32_t htonl(uint32_t v);
/**
* @brief Convert from host byte order to network byte order, 64 bit.
* @see byteorder_htonll()
* @param[in] v The integer to convert.
* @returns Converted integer.
*/
static inline uint64_t htonll(uint64_t v);
/**
* @brief Convert from network byte order to host byte order, 16 bit.
* @see byteorder_ntohs()
* @param[in] v The integer to convert.
* @returns Converted integer.
*/
static inline uint16_t ntohs(uint16_t v);
/**
* @brief Convert from network byte order to host byte order, 32 bit.
* @see byteorder_ntohl()
* @param[in] v The integer to convert.
* @returns Converted integer.
*/
static inline uint32_t ntohl(uint32_t v);
/**
* @brief Convert from network byte order to host byte order, 64 bit.
* @see byteorder_ntohll()
* @param[in] v The integer to convert.
* @returns Converted integer.
*/
static inline uint64_t ntohll(uint64_t v);
/* **************************** IMPLEMENTATION ***************************** */
#ifdef HAVE_NO_BUILTIN_BSWAP16
static inline unsigned short __builtin_bswap16(unsigned short a)
{
return (a << 8) | (a >> 8);
}
#endif
static inline uint16_t byteorder_swaps(uint16_t v)
{
#ifndef MODULE_MSP430_COMMON
return __builtin_bswap16(v);
#else
network_uint16_t result = { v };
uint8_t tmp = result.u8[0];
result.u8[0] = result.u8[1];
result.u8[1] = tmp;
return result.u16;
#endif
}
static inline uint32_t byteorder_swapl(uint32_t v)
{
return __builtin_bswap32(v);
}
static inline uint64_t byteorder_swapll(uint64_t v)
{
return __builtin_bswap64(v);
}
/**
* @brief Swaps the byteorder according to the endianness (host -> le)
*/
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define _byteorder_swap_le(V, T) (V)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define _byteorder_swap_le(V, T) (byteorder_swap ## T((V)))
#else
# error "Byte order is neither little nor big!"
#endif
static inline uint16_t byteorder_ltohs(le_uint16_t v)
{
return _byteorder_swap_le(v.u16, s);
}
static inline uint32_t byteorder_ltohl(le_uint32_t v)
{
return _byteorder_swap_le(v.u32, l);
}
static inline uint64_t byteorder_ltohll(le_uint64_t v)
{
return _byteorder_swap_le(v.u64, ll);
}
static inline be_uint16_t byteorder_ltobs(le_uint16_t v)
{
be_uint16_t result = { byteorder_swaps(v.u16) };
return result;
}
static inline be_uint32_t byteorder_ltobl(le_uint32_t v)
{
be_uint32_t result = { byteorder_swapl(v.u32) };
return result;
}
static inline be_uint64_t byteorder_ltobll(le_uint64_t v)
{
be_uint64_t result = { byteorder_swapll(v.u64) };
return result;
}
static inline le_uint16_t byteorder_btols(be_uint16_t v)
{
le_uint16_t result = { byteorder_swaps(v.u16) };
return result;
}
static inline le_uint32_t byteorder_btoll(be_uint32_t v)
{
le_uint32_t result = { byteorder_swapl(v.u32) };
return result;
}
static inline le_uint64_t byteorder_btolll(be_uint64_t v)
{
le_uint64_t result = { byteorder_swapll(v.u64) };
return result;
}
static inline le_uint16_t byteorder_htols(uint16_t v)
{
le_uint16_t result = { _byteorder_swap_le(v, s) };
return result;
}
static inline le_uint32_t byteorder_htoll(uint32_t v)
{
le_uint32_t result = { _byteorder_swap_le(v, l) };
return result;
}
static inline le_uint64_t byteorder_htolll(uint64_t v)
{
le_uint64_t result = { _byteorder_swap_le(v, ll) };
return result;
}
/**
* @brief Swaps the byteorder according to the endianness (host -> BE)
*/
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define _byteorder_swap(V, T) (byteorder_swap ## T((V)))
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define _byteorder_swap(V, T) (V)
#else
# error "Byte order is neither little nor big!"
#endif
static inline network_uint16_t byteorder_htons(uint16_t v)
{
network_uint16_t result = { _byteorder_swap(v, s) };
return result;
}
static inline network_uint32_t byteorder_htonl(uint32_t v)
{
network_uint32_t result = { _byteorder_swap(v, l) };
return result;
}
static inline network_uint64_t byteorder_htonll(uint64_t v)
{
network_uint64_t result = { _byteorder_swap(v, ll) };
return result;
}
static inline uint16_t byteorder_ntohs(network_uint16_t v)
{
return _byteorder_swap(v.u16, s);
}
static inline uint32_t byteorder_ntohl(network_uint32_t v)
{
return _byteorder_swap(v.u32, l);
}
static inline uint64_t byteorder_ntohll(network_uint64_t v)
{
return _byteorder_swap(v.u64, ll);
}
static inline uint16_t htons(uint16_t v)
{
return byteorder_htons(v).u16;
}
static inline uint32_t htonl(uint32_t v)
{
return byteorder_htonl(v).u32;
}
static inline uint64_t htonll(uint64_t v)
{
return byteorder_htonll(v).u64;
}
static inline uint16_t ntohs(uint16_t v)
{
network_uint16_t input = { v };
return byteorder_ntohs(input);
}
static inline uint32_t ntohl(uint32_t v)
{
network_uint32_t input = { v };
return byteorder_ntohl(input);
}
static inline uint64_t ntohll(uint64_t v)
{
network_uint64_t input = { v };
return byteorder_ntohll(input);
}
static inline uint16_t byteorder_bebuftohs(const uint8_t *buf)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return (uint16_t)((buf[0] << 8) | (buf[1] << 0));
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* big endian to big endian conversion is easy, but buffer might be
* unaligned */
return unaligned_get_u16(buf);
#endif
}
static inline uint32_t byteorder_bebuftohl(const uint8_t *buf)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return (((uint32_t) buf[0] << 24)
| ((uint32_t) buf[1] << 16)
| ((uint32_t) buf[2] << 8)
| ((uint32_t) buf[3] << 0));
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* big endian to big endian conversion is easy, but buffer might be
* unaligned */
return unaligned_get_u32(buf);
#endif
}
static inline uint64_t byteorder_bebuftohll(const uint8_t *buf)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return (((uint64_t) buf[0] << 56)
| ((uint64_t) buf[1] << 48)
| ((uint64_t) buf[2] << 40)
| ((uint64_t) buf[3] << 32)
| ((uint64_t) buf[4] << 24)
| ((uint64_t) buf[5] << 16)
| ((uint64_t) buf[6] << 8)
| ((uint64_t) buf[7] << 0));
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* big endian to big endian conversion is easy, but buffer might be
* unaligned */
return unaligned_get_u64(buf);
#endif
}
static inline void byteorder_htobebufs(uint8_t *buf, uint16_t val)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
buf[0] = (uint8_t)(val >> 8);
buf[1] = (uint8_t)(val >> 0);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* big endian to big endian conversion is easy, but buffer might be
* unaligned */
memcpy(buf, &val, sizeof(val));
#endif
}
static inline void byteorder_htobebufl(uint8_t *buf, uint32_t val)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
buf[0] = (uint8_t)(val >> 24);
buf[1] = (uint8_t)(val >> 16);
buf[2] = (uint8_t)(val >> 8);
buf[3] = (uint8_t)(val >> 0);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* big endian to big endian conversion is easy, but buffer might be
* unaligned */
memcpy(buf, &val, sizeof(val));
#endif
}
static inline void byteorder_htobebufll(uint8_t *buf, uint64_t val)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
buf[0] = (uint8_t)(val >> 56);
buf[1] = (uint8_t)(val >> 48);
buf[2] = (uint8_t)(val >> 40);
buf[3] = (uint8_t)(val >> 32);
buf[4] = (uint8_t)(val >> 24);
buf[5] = (uint8_t)(val >> 16);
buf[6] = (uint8_t)(val >> 8);
buf[7] = (uint8_t)(val >> 0);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* big endian to big endian conversion is easy, but buffer might be
* unaligned */
memcpy(buf, &val, sizeof(val));
#endif
}
#ifdef __cplusplus
}
#endif
#endif /* BYTEORDER_H */
/** @} */

Wyświetl plik

@ -1,122 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
*
* 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.
*/
/**
* @ingroup core_util
* @{
*
* @file
* @brief Debug-header
*
* @details If *ENABLE_DEBUG* is defined inside an implementation file, all
* calls to ::DEBUG will work the same as *printf* and output the
* given information to stdout. If *ENABLE_DEBUG* is not defined,
* all calls to ::DEBUG will be ignored.
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifndef DEBUG_H
#define DEBUG_H
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @def DEBUG_PRINT
*
* @brief Print debug information if the calling thread stack is large enough
*
* Use this macro the same as `printf`. When `DEVELHELP` is defined inside an
* implementation file, all usages of ::DEBUG_PRINT will print the given
* information to stdout after verifying the stack is big enough. If `DEVELHELP`
* is not set, this check is not performed. (CPU exception may occur)
*/
#ifdef DEVELHELP
#include "cpu_conf.h"
#define DEBUG_PRINT(...) \
do { \
if ((thread_get_active() == NULL) || \
(thread_get_active()->stack_size >= \
THREAD_EXTRA_STACKSIZE_PRINTF)) { \
printf(__VA_ARGS__); \
} \
else { \
puts("Cannot debug, stack too small. Consider using DEBUG_PUTS()."); \
} \
} while (0)
#else
#define DEBUG_PRINT(...) printf(__VA_ARGS__)
#endif
/**
* @name Debugging defines
* @{
*/
/**
* @brief This macro can be defined as 0 or other on a file-based level.
* @ref DEBUG() will generate output only if ENABLE_DEBUG is non-zero.
*/
#if !defined(ENABLE_DEBUG) || defined(DOXYGEN)
#define ENABLE_DEBUG 0
#endif
/**
* @def DEBUG_FUNC
*
* @brief Contains the function name if given compiler supports it.
* Otherwise it is an empty string.
*/
# if defined(__cplusplus) && defined(__GNUC__)
# define DEBUG_FUNC __PRETTY_FUNCTION__
# elif __STDC_VERSION__ >= 199901L
# define DEBUG_FUNC __func__
# elif __GNUC__ >= 2
# define DEBUG_FUNC __FUNCTION__
# else
# define DEBUG_FUNC ""
# endif
/**
* @def DEBUG
*
* @brief Print debug information to stdout
*
* @note Another name for ::DEBUG_PRINT
*/
#define DEBUG(...) if (ENABLE_DEBUG) { DEBUG_PRINT(__VA_ARGS__); }
/**
* @def DEBUG_PUTS
*
* @brief Print debug information to stdout using puts(), so no stack size
* restrictions do apply.
*/
#define DEBUG_PUTS(str) if (ENABLE_DEBUG) { puts(str); }
/** @} */
/**
* @def DEBUG_EXTRA_STACKSIZE
*
* @brief Extra stacksize needed when ENABLE_DEBUG==1
*/
#if ENABLE_DEBUG
#define DEBUG_EXTRA_STACKSIZE THREAD_EXTRA_STACKSIZE_PRINTF
#else
#define DEBUG_EXTRA_STACKSIZE (0)
#endif
#ifdef __cplusplus
}
#endif
#endif /* DEBUG_H */
/** @} */

Wyświetl plik

@ -1,200 +0,0 @@
/*
* Copyright (C) 2017-2018 Freie Universität Berlin
*
* 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.
*/
/**
* @defgroup drivers_netdev_ble netdev BLE mode
* @ingroup drivers_netdev_api
* @brief BLE adaption of netdev
* @{
*
* @warning This API is experimental and in an early state - expect
* significant changes!
*
* # About
*
* BLE defines a very specific environment for the used radio, both in terms of
* communication sequences and in terms of timings. BLE communication is
* structured in so called events, where each event is a sequence of request and
* reply packets send between two peers. A radio context (frequency, CRC
* initializer, and access address) is used throughout such an event and
* typically changed for the next one. In addition, the timing of the packets
* sent in a sequence is fixed to an inter-frame-spacing of exactly 150us.
*
* To cater with these specific attributes of BLE, this interface tailors the
* generic netdev interface to be used for BLE radios.
*
*
* # Interface Adaption / Netdev Interpretation
*
* ## Transmission Sequence Based Approach
*
* To be able to handle the exact inter-packet-spacing if 150us seconds, this
* interface expects the device driver to stay in a continuous alternating
* RX-TX sequence, until it is manually aborted. While in this sequence, the
* radio driver needs to take care of switching to RX mode 150us after sending
* the last packet, and to send the next packet 150us after the last packet was
* received.
*
* Such a transmission sequence is started by calling either the radio's send
* or receive function while the radio is in idle/standby mode.
*
* Once a transmission sequence is in progress, the next packet to be send, or
* the next reception buffer to be used is specified also using the send/recv
* functions. They should be called in the `event_callback` right after the
* last transmission (RX or TX) was finished.
*
* The transmission sequence is aborted by calling `netdev_ble_stop(dev)`
* (`netdev->set(dev, NETOPT_BLE_CTX, NULL, 0)`). This will put the radio back
* into idle/standby mode.
*
* ## Radio Context
*
* As BLE uses time sliced channel hopping, the used channel needs to be set
* regularly. Additionally, also the used access address and the CRC initializer
* need to be set regularly, as they differ for different BLE connections. To
* make setting these values more efficient, this interface combines these three
* values in to a so called `radio context` and adds a `netopt` option to set
* all three values at once using `netdev_ble_set_ctx(dev, ctx)`
* (`netdev->set(dev, NETOPT_BLE_CTX, ctx, sizeof(netdev_ble_ctx_t))`).
*
*
* # Implementation Status and Limitations
* - This interface works for memory mapped radios only (no support for
* bus-connected devices). This is mainly for timing reasons.
* - No support for LE Data Length Extension (bigger packet size), yet
*
* @file
* @brief BLE specific adaption for the Netdev API
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef NET_NETDEV_BLE_H
#define NET_NETDEV_BLE_H
#include "netdev.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Maximum payload length of a standard BLE packet
*/
#define NETDEV_BLE_PDU_MAXLEN (37U)
/**
* @brief Mask for the actual (3 byte) CRC data in the context's CRC field
*/
#define NETDEV_BLE_CRC_MASK (0x00ffffff)
/**
* @brief Flag for marking a correct CRC on packet reception
*/
#define NETDEV_BLE_CRC_OK (0x80000000)
/**
* @brief BLE packet structure (as defined by the BLE standard)
*/
typedef struct __attribute__((packed)) {
uint8_t flags; /**< header flags */
uint8_t len; /**< actual length of PDU */
uint8_t pdu[NETDEV_BLE_PDU_MAXLEN]; /**< protocol data unit (PDU) */
} netdev_ble_pkt_t;
/**
* @brief Radio context
*/
typedef struct {
union {
uint8_t raw[4]; /**< byte-wise access */
uint32_t u32; /**< compact access */
} aa; /**< access address */
uint32_t crc; /**< CRC: 3 LSB for CRC, most
* significant bit for RX state*/
uint8_t chan; /**< channel to use/used */
} netdev_ble_ctx_t;
/**
* @brief Send the given packet on the next occasion
*
* If a transmission sequence is in progress, the given packet will be send
* after 150us after receptions of the last packet. If no sequence is currently
* active, the packet will be send immediately and a new transmission sequence
* is started.
*
* @note Call this function only to start a new transmission sequence (radio
* is currently idle), or right after a packet was received. If called
* at any other point in time, the behavior is undefined.
*
* @param[in] dev radio to use for sending
* @param[in] pkt data to send
*
* @return 0 on success
* @return `< 0` on error
*/
static inline int netdev_ble_send(netdev_t *dev, netdev_ble_pkt_t *pkt)
{
struct iolist data = { NULL, pkt, sizeof(netdev_ble_pkt_t) };
return dev->driver->send(dev, &data);
}
/**
* @brief Start listening for an incoming packet and write it into @p pkt
*
* If a transmission sequence is in progress, the radio will use the given
* buffer for reception when it goes in to RX mode 150us after sending the last
* packet. If no sequence is in progress, the radio will go into RX mode
* immediately (using the given RX buffer), and a new transmission sequence is
* started.
*
* @note Call this function only to start a new transmission sequence (radio
* is currently idle), or right after a packet was sent. If called
* at any other point in time, the behavior is undefined.
*
* @param[in] dev radio to use for receiving
* @param[out] pkt buffer to write new packet to
*
* @return 0 on success
* @return `< 0` on error
*/
static inline int netdev_ble_recv(netdev_t *dev, netdev_ble_pkt_t *pkt)
{
return dev->driver->recv(dev, pkt, sizeof(netdev_ble_pkt_t), NULL);
}
/**
* @brief Set the radio context for the given radio device
*
* @param[in] dev target radio device
* @param[in] ctx new radio context (CRC, channel, access address)
*/
static inline void netdev_ble_set_ctx(netdev_t *dev, netdev_ble_ctx_t *ctx)
{
dev->driver->set(dev, NETOPT_BLE_CTX, ctx, sizeof(netdev_ble_ctx_t));
}
/**
* @brief Stop the ongoing RX/TX sequence
*
* @note This function has not effect if the radio is in the middle of a
* data transfer
*
* @param[in] dev target radio device
*/
static inline void netdev_ble_stop(netdev_t *dev)
{
dev->driver->set(dev, NETOPT_BLE_CTX, NULL, 0);
}
#ifdef __cplusplus
}
#endif
#endif /* NET_NETDEV_BLE_H */
/** @} */

Wyświetl plik

@ -1,86 +0,0 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
*
* 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.
*/
/**
* @defgroup drivers_netdev_eth Ethernet drivers
* @ingroup drivers_netdev_api
* @{
*
* @file
* @brief Definitions for netdev common ethernet code
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifndef NET_NETDEV_ETH_H
#define NET_NETDEV_ETH_H
#include <stdint.h>
#include "netdev.h"
#include "netopt.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Flags for use in @ref netdev_eth_rx_info_t::flags
* @{
*/
#define NETDEV_ETH_RX_INFO_FLAG_TIMESTAMP (0x01) /**< Timestamp valid */
/** @} */
/**
* @brief Received frame status information for Ethernet devices
*/
typedef struct {
/**
* @brief Time of the reception of the start of frame delimiter in
* nanoseconds since epoch
*/
uint64_t timestamp;
uint8_t flags; /**< Flags e.g. used to mark other fields as valid */
} netdev_eth_rx_info_t;
/**
* @brief Fallback function for netdev ethernet devices' _get function
*
* Supposed to be used by netdev drivers as default case.
*
* @warning Driver *MUST* implement NETOPT_ADDRESS case!
*
* @param[in] dev network device descriptor
* @param[in] opt option type
* @param[out] value pointer to store the option's value in
* @param[in] max_len maximal amount of byte that fit into @p value
*
* @return number of bytes written to @p value
* @return <0 on error
*/
int netdev_eth_get(netdev_t *dev, netopt_t opt, void *value, size_t max_len);
/**
* @brief Fallback function for netdev ethernet devices' _set function
*
* @param[in] dev network device descriptor
* @param[in] opt option type
* @param[in] value value to set
* @param[in] value_len the length of @p value
*
* @return number of bytes used from @p value
* @return <0 on error
*/
int netdev_eth_set(netdev_t *dev, netopt_t opt, const void *value, size_t value_len);
#ifdef __cplusplus
}
#endif
#endif /* NET_NETDEV_ETH_H */
/** @} */

Wyświetl plik

@ -1,228 +0,0 @@
/*
* Copyright (C) 2016-2019 Freie Universität Berlin
*
* 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.
*/
/**
* @defgroup drivers_netdev_ieee802154 802.15.4 radio drivers
* @ingroup drivers_netdev_api
* @brief
* @{
*
* @file
* @brief Definitions for netdev common IEEE 802.15.4 code
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef NET_NETDEV_IEEE802154_H
#define NET_NETDEV_IEEE802154_H
#include "net/eui_provider.h"
#include "net/ieee802154.h"
#if IS_USED(MODULE_IEEE802154_SECURITY)
#include "net/ieee802154_security.h"
#endif
#include "net/gnrc/nettype.h"
#include "net/netopt.h"
#include "net/netdev.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name IEEE 802.15.4 netdev flags
* @brief Flags for netdev_ieee802154_t::flags
*
* The flag-space `0xff00` is available for device-specific flags.
* The flag-space `0x00ff` was chosen for global flags to be in accordance to
* the IEEE 802.15.4 MAC header flags.
* @{
*/
#define NETDEV_IEEE802154_SEND_MASK (0x0028) /**< flags to take for send packets */
#define NETDEV_IEEE802154_RAW (0x0002) /**< pass raw frame to upper layer */
/**
* @brief use long source address (set) or short source address (unset)
*/
#define NETDEV_IEEE802154_SRC_MODE_LONG (0x0004)
/**
* @brief enable security
*/
#define NETDEV_IEEE802154_SECURITY_EN (IEEE802154_FCF_SECURITY_EN)
/**
* @brief request ACK from receiver
*/
#define NETDEV_IEEE802154_ACK_REQ (IEEE802154_FCF_ACK_REQ)
/**
* @brief set frame pending bit
*/
#define NETDEV_IEEE802154_FRAME_PEND (IEEE802154_FCF_FRAME_PEND)
/**
* @}
*/
/**
* @brief Option parameter to be used with @ref NETOPT_CCA_MODE to set
* the mode of the clear channel assessment (CCA) defined
* in Std 802.15.4.
*/
typedef enum {
NETDEV_IEEE802154_CCA_MODE_1 = 1, /**< Energy above threshold */
NETDEV_IEEE802154_CCA_MODE_2, /**< Carrier sense only */
NETDEV_IEEE802154_CCA_MODE_3, /**< Carrier sense with energy above threshold */
NETDEV_IEEE802154_CCA_MODE_4, /**< ALOHA */
NETDEV_IEEE802154_CCA_MODE_5, /**< UWB preamble sense based on the SHR of a frame */
NETDEV_IEEE802154_CCA_MODE_6, /**< UWB preamble sense based on the packet
* with the multiplexed preamble */
} netdev_ieee802154_cca_mode_t;
/**
* @brief Extended structure to hold IEEE 802.15.4 driver state
*
* @extends netdev_t
*
* Supposed to be extended by driver implementations.
* The extended structure should contain all variable driver state.
*/
typedef struct {
netdev_t netdev; /**< @ref netdev_t base class */
/**
* @brief IEEE 802.15.4 specific fields
* @{
*/
#ifdef MODULE_GNRC
gnrc_nettype_t proto; /**< Protocol for upper layer */
#endif
/**
* @brief PAN ID in network byte order
*/
uint16_t pan;
/**
* @brief Short address in network byte order
*/
uint8_t short_addr[IEEE802154_SHORT_ADDRESS_LEN];
/**
* @brief Long address in network byte order
*/
uint8_t long_addr[IEEE802154_LONG_ADDRESS_LEN];
uint8_t seq; /**< sequence number */
uint8_t chan; /**< channel */
uint8_t page; /**< channel page */
uint16_t flags; /**< flags as defined above */
int16_t txpower; /**< tx power in dBm */
#if IS_USED(MODULE_IEEE802154_SECURITY) || defined(DOXYGEN)
ieee802154_sec_context_t sec_ctx; /**< security context */
#endif
/** @} */
} netdev_ieee802154_t;
/**
* @brief Received packet status information for IEEE 802.15.4 radios
*/
typedef struct netdev_radio_rx_info netdev_ieee802154_rx_info_t;
/**
* @brief Reset function for ieee802154 common fields
*
* Supposed to be used by netdev drivers to reset the ieee802154 fields when
* resetting the device
*
* @param[in] dev network device descriptor
*/
void netdev_ieee802154_reset(netdev_ieee802154_t *dev);
/**
* @brief Fallback function for netdev IEEE 802.15.4 devices' _get function
*
* Supposed to be used by netdev drivers as default case.
*
* @param[in] dev network device descriptor
* @param[in] opt option type
* @param[out] value pointer to store the option's value in
* @param[in] max_len maximal amount of byte that fit into @p value
*
* @return number of bytes written to @p value
* @return <0 on error
*/
int netdev_ieee802154_get(netdev_ieee802154_t *dev, netopt_t opt, void *value,
size_t max_len);
/**
* @brief Fallback function for netdev IEEE 802.15.4 devices' _set function
*
* Sets netdev_ieee802154_t::pan, netdev_ieee802154_t::short_addr, and
* netdev_ieee802154_t::long_addr in device struct.
* Additionally @ref NETDEV_IEEE802154_SRC_MODE_LONG,
* @ref NETDEV_IEEE802154_RAW and, @ref NETDEV_IEEE802154_ACK_REQ in
* netdev_ieee802154_t::flags can be set or unset.
*
* The setting of netdev_ieee802154_t::chan is omitted since the legality of
* its value can be very device specific and can't be checked in this function.
* Please set it in the netdev_driver_t::set function of your driver.
*
* Be aware that this only manipulates the netdev_ieee802154_t struct.
* Configuration to the device needs to be done in the netdev_driver_t::set
* function of the device driver (which should call this function as a fallback
* afterwards).
*
* @param[in] dev network device descriptor
* @param[in] opt option type
* @param[in] value value to set
* @param[in] value_len the length of @p value
*
* @return number of bytes used from @p value
* @return <0 on error
*/
int netdev_ieee802154_set(netdev_ieee802154_t *dev, netopt_t opt, const void *value,
size_t value_len);
/**
* @brief This function compares destination address and pan id with addresses
* and pan id of the device
*
* this function is meant top be used by drivers that do not support address
* filtering in hw
*
* @param[in] dev network device descriptor
* @param[in] mhr mac header
*
* @return 0 successful if packet is for the device
* @return 1 fails if packet is not for the device or pan
*/
int netdev_ieee802154_dst_filter(netdev_ieee802154_t *dev, const uint8_t *mhr);
/**
* @brief Configure the hardware address of a IEEE 802.15.4 devices
*
* This will obtain a long and short address based on the netdev ID.
* The addresses is stored in the netdev's `long_addr` & `short_addr`.
* The caller must take care of writing them to the hardware.
*
* @pre the netdev registered itself with @see netdev_register
*
* @param[out] dev Netdev to configure
*/
static inline void netdev_ieee802154_setup(netdev_ieee802154_t *dev)
{
/* generate EUI-64 and short address */
netdev_eui64_get(&dev->netdev, (eui64_t *)&dev->long_addr);
eui_short_from_eui64((eui64_t *)&dev->long_addr,
(network_uint16_t *)&dev->short_addr);
}
#ifdef __cplusplus
}
#endif
#endif /* NET_NETDEV_IEEE802154_H */
/** @} */

Wyświetl plik

@ -1,70 +0,0 @@
/*
* Copyright (C) 2020 HAW Hamburg
*
* 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.
*/
/**
* @defgroup drivers_netdev_ieee802154_submac IEEE802.15.4 SubMAC netdev layer
* @ingroup drivers_netdev_api
* @experimental This API is experimental and in an early state - expect
* changes!
* @brief This module defines implements the netdev API on top of the
* IEEE 802.15.4 radio HAL
*
* @{
*
* @author José I. Alamos <jose.alamos@haw-hamburg.de>
*/
#ifndef NET_NETDEV_IEEE802154_SUBMAC_H
#define NET_NETDEV_IEEE802154_SUBMAC_H
#ifdef __cplusplus
extern "C" {
#endif
#include "netdev.h"
#include "net/netdev/ieee802154.h"
#include "net/ieee802154/submac.h"
#include "net/ieee802154/radio.h"
#include "od.h"
#include "event/thread.h"
#include "event/callback.h"
#define NETDEV_SUBMAC_FLAGS_ACK_TIMEOUT (1 << 0) /**< Flag for ACK Timeout event */
#define NETDEV_SUBMAC_FLAGS_TX_DONE (1 << 1) /**< Flag for TX Done event */
#define NETDEV_SUBMAC_FLAGS_RX_DONE (1 << 2) /**< Flag for RX Done event */
#define NETDEV_SUBMAC_FLAGS_CRC_ERROR (1 << 3) /**< Flag for CRC ERROR event */
/**
* @brief IEEE 802.15.4 SubMAC netdev descriptor
*/
typedef struct {
netdev_ieee802154_t dev; /**< IEEE 802.15.4 netdev descriptor */
ieee802154_submac_t submac; /**< IEEE 802.15.4 SubMAC descriptor */
xtimer_t ack_timer; /**< xtimer descriptor for the ACK timeout timer */
int isr_flags; /**< netdev submac @ref NETDEV_EVENT_ISR flags */
int8_t retrans; /**< number of frame retransmissions of the last TX */
} netdev_ieee802154_submac_t;
/**
* @brief Init the IEEE 802.15.4 SubMAC netdev adoption.
*
* @param[in] netdev_submac pointer to the netdev submac descriptor.
* @param[in] dev pointer to the device associated to @p netdev_submac.
*
* @return 0 on success.
* @return negative errno on failure.
*/
int netdev_ieee802154_submac_init(netdev_ieee802154_submac_t *netdev_submac,
ieee802154_dev_t *dev);
#ifdef __cplusplus
}
#endif
#endif /* NET_NETDEV_IEEE802154_SUBMAC_H */
/** @} */

Wyświetl plik

@ -1,89 +0,0 @@
/*
* Copyright (C) 2018 Kaspar Schleiser <kaspar@schleiser.de>
* 2018 Inria
* 2018 Freie Universität Berlin
*
* 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.
*/
/**
* @defgroup sys_iolist iolist scatter / gather IO
* @ingroup sys
* @brief Provides linked-list scatter / gather IO
*
* @{
*
* @file
* @brief iolist scatter / gather IO
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifndef IOLIST_H
#define IOLIST_H
#include <unistd.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @brief iolist forward declaration */
typedef struct iolist iolist_t;
/**
* @brief iolist structure definition
*/
struct iolist {
iolist_t *iol_next; /**< ptr to next list entry */
void *iol_base; /**< ptr to this list entries data */
size_t iol_len; /**< size of data pointet to by ptr */
};
/**
* @brief Count number of entries in an iolist_t
*
* @param[in] iolist iolist to count
*
* @returns number of entries (zero for NULL parameter)
*/
unsigned iolist_count(const iolist_t *iolist);
/**
* @brief Sum up number of bytes in iolist
*
* This function returns the summed ip length values of all entries in @p
* iolist.
*
* @param[in] iolist iolist to sum up
*
* @returns summed up number of bytes or zero if @p iolist == NULL
*/
size_t iolist_size(const iolist_t *iolist);
/** @brief struct iovec anonymous declaration */
struct iovec;
/**
* @brief Create struct iovec from iolist
*
* This function fills an array of struct iovecs with the contents of @p
* iolist. It will write the number of used array entries into @p count.
*
* The caller *must* ensure that @p iov p points to an array of size >= count!
*
* @param[in] iolist iolist to read from
* @param[out] iov ptr to array of struct iovec that will be filled
* @param[out] count number of elements in @p iolist
*
* @returns iolist_size(iolist)
*/
size_t iolist_to_iovec(const iolist_t *iolist, struct iovec *iov, unsigned *count);
#ifdef __cplusplus
}
#endif
#endif /* IOLIST_H */
/** @} */

Wyświetl plik

@ -1,144 +0,0 @@
/*
* Copyright (C) 2017 Koen Zandberg <koen@bergzand.net>
*
* 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.
*/
/**
* @ingroup drivers_netdev_api
* @{
*
* @file
* @brief Netdev layer helper functions.
*
* @author Koen Zandberg <koen@bergzand.net>
*/
#ifndef NET_NETDEV_LAYER_H
#define NET_NETDEV_LAYER_H
#ifdef __cplusplus
extern "C" {
#endif
#include "net/netdev.h"
#include "assert.h"
/**
* @brief Add a netdev layer to the netdev layer stack
*
* @param[in] top Last netdev device added to the stack.
* @param[in] dev New layer to push to the top of the stack.
*
* @return The new top netdev layer of the netdev stack.
*/
static inline netdev_t *netdev_add_layer(netdev_t *top, netdev_t *dev)
{
assert(top);
assert(dev);
dev->lower = top;
top->context = dev;
return dev;
}
/**
* @brief Passthrough init function.
*
* See also @ref netdev_driver for the extended description of this functions
* behaviour
*
* @param[in] dev network device descriptor
* @return `< 0` on error, 0 on success
*/
int netdev_init_pass(netdev_t *dev);
/**
* @brief Passthrough isr function.
*
* See also @ref netdev_driver for the extended description of this functions
* behaviour
*
* @param[in] dev network device descriptor
*/
void netdev_isr_pass(netdev_t *dev);
/**
* @brief Passthrough send function.
*
* See also @ref netdev_driver for the extended description of this functions
* behaviour
*
* @param[in] dev network device descriptor
* @param[in] iolist io vector list to send
*
* @return number of bytes sent, or `< 0` on error
*/
int netdev_send_pass(netdev_t *dev, const iolist_t *iolist);
/**
* @brief Passthrough recv function.
*
* See also @ref netdev_driver for the extended description of this functions
* behaviour
*
* @param[in] dev network device descriptor
* @param[out] buf buffer to write into or NULL
* @param[in] len maximum number of bytes to read
* @param[out] info status information for the received packet. Might
* be of different type for different netdev devices.
* May be NULL if not needed or applicable.
*
* @return `< 0` on error
* @return number of bytes read if buf != NULL
* @return packet size if buf == NULL
*/
int netdev_recv_pass(netdev_t *dev, void *buf, size_t len, void *info);
/**
* @brief Passthrough get function.
*
* See also @ref netdev_driver for the extended description of this functions
* behaviour
*
* @param[in] dev network device descriptor
* @param[in] opt option type
* @param[out] value pointer to store the option's value in
* @param[in] max_len maximal amount of byte that fit into @p value
*
* @return number of bytes written to @p value
* @return `< 0` on error, 0 on success
*/
int netdev_get_pass(netdev_t *dev, netopt_t opt, void *value, size_t max_len);
/**
* @brief Passthrough set function.
*
* See also @ref netdev_driver for the extended description of this functions
* behaviour
*
* @param[in] dev network device descriptor
* @param[in] opt option type
* @param[in] value value to set
* @param[in] value_len the length of @p value
*
* @return number of bytes used from @p value
* @return `< 0` on error, 0 on success
*/
int netdev_set_pass(netdev_t *dev, netopt_t opt, const void *value, size_t value_len);
/**
* @brief Passthrough event callback function.
*
* @param[in] dev network device descriptor
* @param[in] event type of the event
*/
void netdev_event_cb_pass(netdev_t *dev, netdev_event_t event);
#ifdef __cplusplus
}
#endif
#endif /* NET_NETDEV_LAYER_H */
/** @} */

Wyświetl plik

@ -1,46 +0,0 @@
/*
* Copyright (C) 2019 HAW Hamburg
*
* 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.
*/
/**
* @defgroup drivers_netdev_lora LoRa drivers
* @ingroup drivers_netdev_api
* @{
*
* @file
* @brief Definitions for netdev common LoRa code
*
* @author José Ignacio Alamos <jose.alamos@haw-hamburg.de>
*/
#ifndef NET_NETDEV_LORA_H
#define NET_NETDEV_LORA_H
#include <stdint.h>
#include "netdev.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Received LoRa packet status information
*/
typedef struct {
uint8_t rssi; /**< RSSI of a received packet */
int8_t snr; /**< S/N ratio */
} netdev_lora_rx_info_t;
#ifdef __cplusplus
}
#endif
#endif /* NET_NETDEV_LORA_H */
/** @} */

Wyświetl plik

@ -1,432 +0,0 @@
#ifndef NET_NETDEV_H
#define NET_NETDEV_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <errno.h>
#include "iolist.h"
#include "netopt.h"
#ifdef MODULE_L2FILTER
#include "net/l2filter.h"
#endif
/**
* @name Network device types
* @anchor net_netdev_type
* @attention When implementing a new type that is able to carry IPv6, have
* a look if you need to update @ref net_l2util as well.
* @{
*/
enum {
NETDEV_TYPE_UNKNOWN,
NETDEV_TYPE_TEST,
NETDEV_TYPE_RAW,
NETDEV_TYPE_ETHERNET,
NETDEV_TYPE_IEEE802154,
NETDEV_TYPE_BLE,
NETDEV_TYPE_CC110X,
NETDEV_TYPE_LORA,
NETDEV_TYPE_NRFMIN,
NETDEV_TYPE_NRF24L01P_NG,
NETDEV_TYPE_SLIP,
NETDEV_TYPE_ESP_NOW,
};
/** @} */
/**
* @brief Possible event types that are send from the device driver to the
* upper layer
*/
typedef enum {
NETDEV_EVENT_ISR, /**< driver needs it's ISR handled */
NETDEV_EVENT_RX_STARTED, /**< started to receive a frame */
NETDEV_EVENT_RX_COMPLETE, /**< finished receiving a frame */
NETDEV_EVENT_TX_STARTED, /**< started to transfer a frame */
NETDEV_EVENT_TX_COMPLETE, /**< transfer frame complete */
/**
* @brief transfer frame complete and data pending flag
*
* @deprecated Issue an NETDEV_EVENT_TX_COMPLETE event instead and pass
* the data pending info in netdev_driver_t::confirm_send
* via the `info` parameter
*/
NETDEV_EVENT_TX_COMPLETE_DATA_PENDING,
/**
* @brief ACK requested but not received
*
* @deprecated Issue an NETDEV_EVENT_TX_COMPLETE event instead and return
* `-ECOMM` in netdev_driver_t::confirm_send. Via the `info`
* parameter additional details about the error can be passed
*/
NETDEV_EVENT_TX_NOACK,
/**
* @brief couldn't transfer frame
*
* @deprecated Issue an NETDEV_EVENT_TX_COMPLETE event instead and return
* `-EBUSY` in netdev_driver_t::confirm_send.
*/
NETDEV_EVENT_TX_MEDIUM_BUSY,
NETDEV_EVENT_LINK_UP, /**< link established */
NETDEV_EVENT_LINK_DOWN, /**< link gone */
NETDEV_EVENT_TX_TIMEOUT, /**< timeout when sending */
NETDEV_EVENT_RX_TIMEOUT, /**< timeout when receiving */
NETDEV_EVENT_CRC_ERROR, /**< wrong CRC */
NETDEV_EVENT_FHSS_CHANGE_CHANNEL, /**< channel changed */
NETDEV_EVENT_CAD_DONE, /**< channel activity detection done */
/* expand this list if needed */
} netdev_event_t;
/**
* @brief Received frame status information for most radios
*
* May be different for certain radios.
*/
struct netdev_radio_rx_info {
int16_t rssi; /**< RSSI of a received frame in dBm */
uint8_t lqi; /**< LQI of a received frame */
};
/**
* @brief Forward declaration for netdev struct
*/
typedef struct netdev netdev_t;
/**
* @brief Event callback for signaling event to upper layers
*
* @param[in] type type of the event
*/
typedef void (*netdev_event_cb_t)(netdev_t *dev, netdev_event_t event);
/**
* @brief Driver types for netdev.
*
* @warning New entries must be added at the bottom of the list
* because the values need to remain constant to
* generate stable L2 addresses.
* @{
*/
typedef enum {
NETDEV_ANY = 0, /**< Will match any device type */
NETDEV_AT86RF215,
NETDEV_AT86RF2XX,
NETDEV_CC2538,
NETDEV_DOSE,
NETDEV_ENC28J60,
NETDEV_KW41ZRF,
NETDEV_MRF24J40,
NETDEV_NRF802154,
NETDEV_STM32_ETH,
NETDEV_CC110X,
NETDEV_SX127X,
NETDEV_SAM0_ETH,
NETDEV_ESP_NOW,
NETDEV_NRF24L01P_NG,
NETDEV_SOCKET_ZEP,
NETDEV_SX126X,
NETDEV_CC2420,
/* add more if needed */
} netdev_type_t;
/** @} */
/**
* @brief Will match any device index
*/
#define NETDEV_INDEX_ANY (0xFF)
/**
* @brief Structure to hold driver state
*
* Supposed to be extended by driver implementations.
* The extended structure should contain all variable driver state.
*
* Contains a field @p context which is not used by the drivers, but supposed to
* be used by upper layers to store reference information.
*/
struct netdev {
const struct netdev_driver *driver; /**< ptr to that driver's interface. */
netdev_event_cb_t event_callback; /**< callback for device events */
void *context; /**< ptr to network stack context */
#ifdef MODULE_NETDEV_LAYER
netdev_t *lower; /**< ptr to the lower netdev layer */
#endif
#ifdef MODULE_L2FILTER
l2filter_t filter[CONFIG_L2FILTER_LISTSIZE]; /**< link layer address filters */
#endif
#ifdef MODULE_NETDEV_REGISTER
netdev_type_t type; /**< driver type used for netdev */
uint8_t index; /**< instance number of the device */
#endif
};
/**
* @brief Register a device with netdev.
* Must by called by the driver's setup function.
*
* @param[out] dev the new netdev
* @param[in] type the driver used for the netdev
* @param[in] index the index in the config struct
*/
static inline void netdev_register(struct netdev *dev, netdev_type_t type, uint8_t index)
{
#ifdef MODULE_NETDEV_REGISTER
dev->type = type;
dev->index = index;
#else
(void) dev;
(void) type;
(void) index;
#endif
}
/**
* @brief Structure to hold driver interface -> function mapping
*
* The send/receive functions expect/return a full ethernet
* frame (dst mac, src mac, ethertype, payload, no checksum).
*/
typedef struct netdev_driver {
/**
* @brief Start transmission of the given frame and return directly
*
* @pre `(dev != NULL) && (iolist != NULL)`
*
* @param[in] dev Network device descriptor. Must not be NULL.
* @param[in] iolist IO vector list to send. Elements of this list may
* have iolist_t::iol_size == 0 and (in this case only)
* iolist_t::iol_data == 0.
*
* @retval -EBUSY Driver is temporarily unable to send, e.g. because
* an incoming frame on a half-duplex medium is
* received
* @retval -ENETDOWN Device is powered down
* @retval <0 Other error
* @retval 0 Transmission successfully started
* @retval >0 Number of bytes transmitted (deprecated!)
*
* This function will cause the driver to start the transmission in an
* async fashion. The driver will "own" the `iolist` until a subsequent
* call to @ref netdev_driver_t::confirm_send returns something different
* than `-EAGAIN`. The driver must signal completion using the
* NETDEV_EVENT_TX_COMPLETE event, regardless of success or failure.
*
* Old drivers might not be ported to the new API and have
* netdev_driver_t::confirm_send set to `NULL`. In that case the driver
* will return the number of bytes transmitted on success (instead of `0`)
* and will likely block until completion.
*/
int (*send)(netdev_t *dev, const iolist_t *iolist);
/**
* @brief Fetch the status of a transmission and perform any potential
* cleanup
*
* @param[in] dev Network device descriptor. Must not be NULL.
* @param[out] info Device class specific type to fetch transmission
* info. May be `NULL` if not needed by upper layer.
* May be ignored by driver.
*
* @return Number of bytes transmitted. (The size of the transmitted
* frame including all overhead, such as frame check sequence,
* bit stuffing, escaping, headers, trailers, preambles, start of
* frame delimiters, etc. May be an estimate for performance
* reasons.)
* @retval -EAGAIN Transmission still ongoing. (Call later again!)
* @retval -ECOMM Any kind of transmission error, such as collision
* detected, layer 2 ACK timeout, etc.
* Use @p info for more details
* @retval -EBUSY Medium is busy. (E.g. Auto-CCA failed / timed out)
* @retval <0 Other error. (Please use a negative errno code.)
*
* @warning After netdev_driver_t::send was called and returned zero, this
* function must be called until it returns anything other than
* `-EAGAIN`.
* @note The driver will signal completion using the
* NETDEV_EVENT_TX_COMPLETE event. This function must not return
* `-EAGAIN` after that event was received.
*/
int (*confirm_send)(netdev_t *dev, void *info);
/**
* @brief Drop a received frame, **OR** get the length of a received
* frame, **OR** get a received frame.
*
* @pre `(dev != NULL)`
*
* Supposed to be called from
* @ref netdev_t::event_callback "netdev->event_callback()"
*
* If @p buf == NULL and @p len == 0, returns the frame size -- or an upper
* bound estimation of the size -- without dropping the frame.
* If @p buf == NULL and @p len > 0, drops the frame and returns the frame
* size.
*
* If called with @p buf != NULL and @p len is smaller than the received
* frame:
* - The received frame is dropped
* - The content in @p buf becomes invalid. (The driver may use the memory
* to implement the dropping - or may not change it.)
* - `-ENOBUFS` is returned
*
* @param[in] dev network device descriptor. Must not be NULL.
* @param[out] buf buffer to write into or NULL to return the frame
* size.
* @param[in] len maximum number of bytes to read. If @p buf is NULL
* the currently buffered frame is dropped when
* @p len > 0. Must not be 0 when @p buf != NULL.
* @param[out] info status information for the received frame. Might
* be of different type for different netdev devices.
* May be NULL if not needed or applicable.
*
* @retval -ENOBUFS if supplied buffer is too small
* @return number of bytes read if buf != NULL
* @return frame size (or upper bound estimation) if buf == NULL
*/
int (*recv)(netdev_t *dev, void *buf, size_t len, void *info);
/**
* @brief the driver's initialization function
*
* @pre `(dev != NULL)`
*
* @param[in] dev network device descriptor. Must not be NULL.
*
* @retval <0 on error
* @retval 0 on success
*/
int (*init)(netdev_t *dev);
/**
* @brief a driver's user-space ISR handler
*
* @pre `(dev != NULL)`
*
* This function will be called from a network stack's loop when being
* notified by netdev_isr.
*
* It is supposed to call
* @ref netdev_t::event_callback "netdev->event_callback()" for each
* occurring event.
*
* See receive frame flow description for details.
*
* @param[in] dev network device descriptor. Must not be NULL.
*/
void (*isr)(netdev_t *dev);
/**
* @brief Get an option value from a given network device
*
* @pre `(dev != NULL)`
* @pre for scalar types of @ref netopt_t @p max_len must be of exactly
* that length (see [netopt documentation](@ref net_netopt) for
* type)
* @pre for array types of @ref netopt_t @p max_len must greater or
* equal the required length (see
* [netopt documentation](@ref net_netopt) for type)
* @pre @p value must have the natural alignment of its type (see
* [netopt documentation](@ref net_netopt) for type)
*
* @param[in] dev network device descriptor
* @param[in] opt option type
* @param[out] value pointer to store the option's value in
* @param[in] max_len maximal amount of byte that fit into @p value
*
* @return number of bytes written to @p value
* @retval -ENOTSUP if @p opt is not provided by the device
*/
int (*get)(netdev_t *dev, netopt_t opt,
void *value, size_t max_len);
/**
* @brief Set an option value for a given network device
*
* @pre `(dev != NULL)`
* @pre for scalar types of @ref netopt_t @p value_len must be of
* exactly that length (see [netopt documentation](@ref net_netopt)
* for type)
* @pre for array types of @ref netopt_t @p value_len must lesser or
* equal the required length (see
* [netopt documentation](@ref net_netopt) for type)
* @pre @p value must have the natural alignment of its type (see
* [netopt documentation](@ref net_netopt) for type)
*
* @param[in] dev network device descriptor
* @param[in] opt option type
* @param[in] value value to set
* @param[in] value_len the length of @p value
*
* @return number of bytes written to @p value
* @retval -ENOTSUP if @p opt is not configurable for the device
* @retval -EINVAL if @p value is an invalid value with regards to
* @p opt
*/
int (*set)(netdev_t *dev, netopt_t opt,
const void *value, size_t value_len);
} netdev_driver_t;
/**
* @brief Convenience function for declaring get() as not supported in general
*
* @param[in] dev ignored
* @param[in] opt ignored
* @param[in] value ignored
* @param[in] max_len ignored
*
* @return always returns `-ENOTSUP`
*/
static inline int netdev_get_notsup(netdev_t *dev, netopt_t opt,
void *value, size_t max_len)
{
(void)dev;
(void)opt;
(void)value;
(void)max_len;
return -ENOTSUP;
}
/**
* @brief Convenience function for declaring set() as not supported in general
*
* @param[in] dev ignored
* @param[in] opt ignored
* @param[in] value ignored
* @param[in] value_len ignored
*
* @return always returns `-ENOTSUP`
*/
static inline int netdev_set_notsup(netdev_t *dev, netopt_t opt,
const void *value, size_t value_len)
{
(void)dev;
(void)opt;
(void)value;
(void)value_len;
return -ENOTSUP;
}
/**
* @brief Informs netdev there was an interrupt request from the network device.
*
* This function calls @ref netdev_t::event_callback with
* NETDEV_EVENT_ISR event.
*
* @param netdev netdev instance of the device associated to the interrupt.
*/
static inline void netdev_trigger_event_isr(netdev_t *netdev)
{
if (netdev->event_callback) {
netdev->event_callback(netdev, NETDEV_EVENT_ISR);
}
}
#ifdef __cplusplus
}
#endif
#endif /* NET_NETDEV_H */
/** @} */

Wyświetl plik

@ -1,866 +0,0 @@
/*
* Copyright (C) 2015 Freie Universität Berlin
* 2015 Kaspar Schleiser <kaspar@schleiser.de>
*
* 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.
*/
/**
* @defgroup net_netopt Netopt - Configuration options for network APIs
* @ingroup net
* @brief List of available configuration options for the
* @ref drivers_netdev_api and the @ref net_gnrc_netapi
* @{
*
* @file
* @brief Definition of global configuration options
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifndef NET_NETOPT_H
#define NET_NETOPT_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief A deprecated alias for @ref NETOPT_MAX_PDU_SIZE
*
* @deprecated Please use @ref NETOPT_MAX_PDU_SIZE instead of
* `NETOPT_MAX_PACKET_SIZE`
*/
#define NETOPT_MAX_PACKET_SIZE NETOPT_MAX_PDU_SIZE
/**
* @brief Global list of configuration options available throughout the
* network stack, e.g. by netdev and netapi
*
* The data type specified in parentheses for each individual option is the
* data type to use for the argument when getting/setting the value of the option.
*
* All arguments longer than 1 byte (e.g. uint16_t) are given in host byte order
* unless anything else is specified below.
*/
typedef enum {
/**
* @brief (uint16_t) channel number
*/
NETOPT_CHANNEL,
/**
* @brief (@ref netopt_enable_t) check whether the network medium is clear
*
* Getting this option can be used to trigger a manual clear channel
* assessment (CCA) on some wireless devices.
*/
NETOPT_IS_CHANNEL_CLR,
/**
* @brief (byte array, see below) link layer address in network byte order
*
* Device type | Length | Meaning
* ------------- | ------ | -----
* IEEE 802.15.4 | 2 | device short address
* Ethernet | 6 | device MAC address
* nrfmin | 2 | device short address
* CC110x | 1 | device address
* NRF24L01+ | 5 | device address
* LoRaWAN | 4 | device address
*/
NETOPT_ADDRESS,
/**
* @brief (byte array, see below) long link layer address in network byte order
*
* Device type | Length | Meaning
* ------------- | -------- | -----
* IEEE 802.15.4 | 8 | device long address (EUI-64), @ref eui64_t
* nrfmin | 8 | device long address (based on short address)
* BLE | 8 | device long address (EUI-64), @ref eui64_t
* LoRaWAN | 8 | Device EUI
*/
NETOPT_ADDRESS_LONG,
/**
* @brief (uint16_t) get the default address length a network device expects
*/
NETOPT_ADDR_LEN,
/**
* @brief (uint16_t) address length to use for the link layer source address
*/
NETOPT_SRC_LEN,
/**
* @brief (uint16_t) network ID
*
* Examples for this include the PAN ID in IEEE 802.15.4 and netid in
* LoRaWAN (uint32_t in this case)
*/
NETOPT_NID,
/**
* @brief (uint8_t) hop limit
*/
NETOPT_HOP_LIMIT,
/**
* @brief (@ref eui64_t) get the IPv6 interface identifier of a network interface
*
* @see <a href="https://tools.ietf.org/html/rfc4291#section-2.5.1">
* RFC 4291, section 2.5.1
* </a>
*
* @note Do not implement this in a network device driver. Other APIs
* utilizing [netopt](@ref net_netopt) such as @ref net_gnrc_netif
* or @ref net_netif may still implement it.
*
* The generation of the interface identifier is dependent on the link-layer.
* Please refer to the appropriate IPv6 over `<link>` specification for
* further implementation details (such as
* <a href="https://tools.ietf.org/html/rfc2464">RFC 2464</a> or
* <a href="https://tools.ietf.org/html/rfc4944">RFC 4944</a>).
*/
NETOPT_IPV6_IID,
/**
* @brief (@ref ipv6_addr_t[]) get IPv6 addresses of an interface as array
* of @ref ipv6_addr_t or add an IPv6 address as @ref ipv6_addr_t
* to an interface
*
* When adding an IPv6 address to a GNRC interface using
* @ref GNRC_NETAPI_MSG_TYPE_SET, the gnrc_netapi_opt_t::context field can
* be used to pass the prefix length (8 MSB) and some flags (8 LSB)
* according to @ref net_gnrc_netif_ipv6_addrs_flags. The address is however
* always considered to be manually added.
* When getting the option you can pass an array of @ref ipv6_addr_t of any
* length greater than 0 to the getter. The array will be filled up to to
* its maximum and the remaining addresses on the interface will be ignored
*/
NETOPT_IPV6_ADDR,
/**
* @brief (@ref ipv6_addr_t) Removes an IPv6 address from an interface
*/
NETOPT_IPV6_ADDR_REMOVE,
/**
* @brief (array of uint8_t) get the flags to the addresses returned by
* @ref NETOPT_IPV6_ADDR as array
*
* The information contained in the array is very specific to the
* interface's API. For GNRC e.g. the values are according to
* @ref net_gnrc_netif_ipv6_addrs_flags.
*/
NETOPT_IPV6_ADDR_FLAGS,
/**
* @brief (@ref ipv6_addr_t) get IPv6 multicast groups of an interface as
* array of @ref ipv6_addr_t or join an IPv6 multicast group as
* @ref ipv6_addr_t on an interface
*
* When adding an IPv6 address to a GNRC interface using
* @ref GNRC_NETAPI_MSG_TYPE_SET, the gnrc_netapi_opt_t::context field can
* be used to pass the prefix length (8 MSB) and some flags (8 LSB)
* according to @ref net_gnrc_netif_ipv6_addrs_flags. The address is however always
* considered to be manually added.
* When getting the option you can pass an array of @ref ipv6_addr_t of any
* length greater than 0 to the getter. The array will be filled up to to
* its maximum and the remaining addresses on the interface will be ignored
*/
NETOPT_IPV6_GROUP,
/**
* @brief (@ref ipv6_addr_t) Leave an IPv6 multicast group on an interface
*/
NETOPT_IPV6_GROUP_LEAVE,
/**
* @brief (@ref netopt_enable_t) IPv6 forwarding state
*/
NETOPT_IPV6_FORWARDING,
/**
* @brief (@ref netopt_enable_t) sending of IPv6 router advertisements
*/
NETOPT_IPV6_SND_RTR_ADV,
/**
* @brief (int16_t) transmit power for radio devices in dBm
*/
NETOPT_TX_POWER,
/**
* @brief (uint16_t) maximum protocol data unit
*/
NETOPT_MAX_PDU_SIZE,
/**
* @brief (uint16_t) protocol data unit size
*
* When set, fixes the number of bytes to be received. This is required for
* MAC layers with implicit header mode (no packet length information in
* PDDU) and predictable packet length (e.g LoRaWAN beacons). The device
* driver implementation should attempt to read exactly the expected number
* of bytes (possibly filling it up with garbage data if the payload is
* smaller).
*
* When get, returns the number of expected bytes for the next reception.
*
* In some MAC layers it will only be effective if used in conjunction with
* @ref NETOPT_FIXED_HEADER
*/
NETOPT_PDU_SIZE,
/**
* @brief (@ref netopt_enable_t) frame preloading
*
* Preload frame data using gnrc_netdev_driver_t::send_data() or gnrc_netapi_send(),
* trigger sending by setting state to @ref NETOPT_STATE_TX
*/
NETOPT_PRELOADING,
/**
* @brief (@ref netopt_enable_t) promiscuous mode
*/
NETOPT_PROMISCUOUSMODE,
/**
* @brief (@ref netopt_enable_t) automatic link layer ACKs
*/
NETOPT_AUTOACK,
/**
* @brief (@ref netopt_enable_t) frame pending bit of ACKs
*
* For IEEE 802.15.4, this bit is copied into the frame pending subfield of
* the ACK if it is the response to a data request MAC command frame.
*/
NETOPT_ACK_PENDING,
/**
* @brief (@ref netopt_enable_t) acknowledgement request on outgoing frames
*
* For IEEE 802.15.4, this bit is copied into the ACK req subfield of the
* frame control field.
*/
NETOPT_ACK_REQ,
/**
* @brief (uint8_t) maximum number of retransmissions
*/
NETOPT_RETRANS,
/**
* @brief (@ref gnrc_nettype_t) the protocol for the layer
*/
NETOPT_PROTO,
/**
* @brief (@ref netopt_state_t) state of network device
*/
NETOPT_STATE,
/**
* @brief (@ref netopt_enable_t) when enabled, bypass protocol processing of incoming frames
*/
NETOPT_RAWMODE,
/**
* @brief (@ref netopt_enable_t) Used to check if the driver generates NETDEV_EVENT_RX_STARTED
* events
*
* It is mostly triggered after the preamble is correctly received
*
* @warning This value is read-only and cannot be configured at run-time
*/
NETOPT_RX_START_IRQ,
/**
* @brief (@ref netopt_enable_t) Used to check if the driver generates
* NETDEV_EVENT_RX_COMPLETE events
*
* This interrupt is triggered after a complete frame is received.
*
* @note In case a transceiver does not support this interrupt, the event
* may be triggered by the driver
* @warning This value is read-only and cannot be configured at run-time
*/
NETOPT_RX_END_IRQ,
/**
* @brief (@ref netopt_enable_t) Used to check if the driver generates NETDEV_EVENT_TX_STARTED
* events
*
* This interrupt is triggered when the transceiver starts to send out the
* frame.
*
* @note In case a transceiver does not support this interrupt, the event
* may be triggered by the driver
* @warning This value is read-only and cannot be configured at run-time
*/
NETOPT_TX_START_IRQ,
/**
* @brief (@ref netopt_enable_t) Used to check if the driver generates
* NETDEV_EVENT_TX_COMPLETE events
*
* This interrupt is triggered when the full frame has been transmitted.
*
* @note not all transceivers may support this interrupt
*/
NETOPT_TX_END_IRQ,
/**
* @brief (@ref netopt_enable_t) perform channel clear assessment before transmitting
*
* This may be a hardware feature of the given transceiver, or might be
* otherwise implemented in software. If the device supports CSMA this
* option will enable CSMA with a certain set of parameters to emulate the
* desired behaviour.
*
* @note Be sure not to set NETOPT_CSMA simultaneously.
*
* @todo How to get feedback?
*/
NETOPT_AUTOCCA,
/**
* @brief (@ref netopt_enable_t) network interface link status.
*
* This option is used to set or check the link status (up or down).
*
* @note On error this option should return a negative number.
*/
NETOPT_LINK,
/**
* @brief (@ref netopt_enable_t) CSMA/CA support
*
* If the device supports CSMA in hardware, this option enables it with
* default parameters. For further configuration refer to the other
* NETOPT_CSMA_* options.
*/
NETOPT_CSMA,
/**
* @brief (uint8_t) maximum number of CSMA retries
*
* The maximum number of backoffs the CSMA-CA algorithm will attempt before
* declaring a channel access failure. Named macMaxCsmaBackoffs in
* IEEE Std 802.15.4-2015.
*
* IEEE 802.15.4 default: 4
*/
NETOPT_CSMA_RETRIES,
/**
* @brief (uint8_t) maximum backoff exponent for the CSMA-CA algorithm
*
* Named macMaxBE in IEEE Std 802.15.4-2015.
*
* IEEE 802.15.4 default: 5
*/
NETOPT_CSMA_MAXBE,
/**
* @brief (uint8_t) minimum backoff exponent for the CSMA-CA algorithm
*
* Named macMinBE in IEEE Std 802.15.4-2015.
*
* IEEE 802.15.4 default: 3
*/
NETOPT_CSMA_MINBE,
/**
* @brief (@ref netopt_enable_t) block transceiver sleep
*
* Enabling this option tells the MAC layer to never put the radio to sleep.
* Useful in gateways and routers not running on batteries to improve
* responsiveness and allow battery powered nodes on the same network to
* sleep more often.
*/
NETOPT_MAC_NO_SLEEP,
/**
* @brief (@ref netopt_enable_t) read-only check for a wired interface.
*
* This option will return -ENOTSUP for wireless interfaces.
*
* @note Setting this option will always return -ENOTSUP.
*/
NETOPT_IS_WIRED,
/**
* @brief (uint16_t) device type
*
* e.g. NETDEV_TYPE_ETHERNET, NETDEV_TYPE_IEEE802154, etc.
*/
NETOPT_DEVICE_TYPE,
/**
* @brief (uint16_t) channel page as defined by IEEE 802.15.4
*/
NETOPT_CHANNEL_PAGE,
/**
* @brief (int8_t) CCA threshold for the radio transceiver
*
* This is the value, in dBm, that the radio transceiver uses to decide
* whether the channel is clear or not (CCA). If the current signal strength
* (RSSI/ED) is stronger than this CCA threshold value, the transceiver
* usually considers that the radio medium is busy. Otherwise, i.e. if
* RSSI/ED value is less than the CCA threshold value, the radio medium is
* supposed to be free (the possibly received weak signal is considered to
* be background, meaningless noise).
*
* Most transceivers allow to set this CCA threshold value. Some research
* work has proven that dynamically adapting it to network environment can
* improve QoS, especially in WSN.
*/
NETOPT_CCA_THRESHOLD,
/**
* @brief (uint8_t) CCA mode for the radio transceiver
*
* Get/set the CCA mode corresponding to the respective PHY standard.
* - IEEE 802.15.4: @ref netdev_ieee802154_cca_mode_t
*/
NETOPT_CCA_MODE,
/**
* @brief (@ref netstats_t*) get statistics about sent and received packets and data of the device or protocol
*
* Expects a pointer to a @ref netstats_t struct that will be pointed to
* the corresponding @ref netstats_t of the module.
*/
NETOPT_STATS,
/**
* @brief (@ref netopt_enable_t) link layer encryption.
*/
NETOPT_ENCRYPTION,
/**
* @brief (byte array) set encryption key
*
* The required byte array size is dependent on encryption algorithm and device.
*/
NETOPT_ENCRYPTION_KEY,
/**
* @brief (@ref netopt_rf_testmode_t) Test mode for the radio, e.g. for CE or FCC certification
*
* Get/set the test mode as type @ref netopt_rf_testmode_t or as uint8_t if
* the radio supports other vendor specific test modes.
*
* @note Setting this option should always return -ENOTSUP, unless it was
* explicitly allowed at build time, therefore it should be secured with an
* additional macro in the device driver.
*
* @attention For development and certification purposes only! These test
* modes can disturb normal radio communications and exceed the limits
* established by the regulatory authority.
*
*/
NETOPT_RF_TESTMODE,
/**
* @brief (@ref l2filter_t) add an address to a link layer filter list
*
* Getting this option from a device will return a pointer of type
* @ref l2filter_t to the first entry of a filter list.
* When setting this option a pointer to an link layer address as well as
* the length of the address are expected as parameters.
*/
NETOPT_L2FILTER,
/**
* @brief (@ref l2filter_t) remove an address from a link layer filter list
*
* Getting this value always returns -ENOTSUP.
* When setting this option a pointer to an link layer address as well as
* the length of the address are expected as parameters. Setting this
* option will lead to the given address being removed from the filer list.
*/
NETOPT_L2FILTER_RM,
/**
* @brief (int8_t) Energy level during the last performed CCA or RX frame
*
* Get the last ED level available as an int8_t. The source of the
* measurement is unspecified and may come from the latest CCA
* measurement (CCA mode 1), or from the last received frame.
*/
NETOPT_LAST_ED_LEVEL,
/**
* @brief (uint16_t) preamble length
*/
NETOPT_PREAMBLE_LENGTH,
/**
* @brief (@ref netopt_enable_t) frame integrity check (e.g CRC)
*/
NETOPT_INTEGRITY_CHECK,
/**
* @brief (uint32_t) channel center frequency
*
* For example, with LoRa, this corresponds to the center frequency of
* each channel (867300000, etc) for a given frequency band
* (868, 915, etc).
*/
NETOPT_CHANNEL_FREQUENCY,
/**
* @brief (@ref netopt_enable_t) channel hopping
*/
NETOPT_CHANNEL_HOP,
/**
* @brief (uint8_t) channel hopping period
*/
NETOPT_CHANNEL_HOP_PERIOD,
/**
* @brief (@ref netopt_enable_t) single frame reception
*
* If enabled, RX is turned off upon reception of a frame
*/
NETOPT_SINGLE_RECEIVE,
/**
* @brief (uint32_t) reception timeout of a frame
*
* @todo in what time unit?
*/
NETOPT_RX_TIMEOUT,
/**
* @brief (uint32_t) transmission timeout of a frame
*
* @todo in what time unit?
*/
NETOPT_TX_TIMEOUT,
/**
* @brief (uint8_t) radio modulation bandwidth
*/
NETOPT_BANDWIDTH,
/**
* @brief (uint8_t) radio spreading factor
*/
NETOPT_SPREADING_FACTOR,
/**
* @brief (uint8_t) radio coding rate
*/
NETOPT_CODING_RATE,
/**
* @brief (@ref netopt_enable_t) fixed header mode
*/
NETOPT_FIXED_HEADER,
/**
* @brief (@ref netopt_enable_t) IQ inverted
*/
NETOPT_IQ_INVERT,
/**
* @brief (@ref netopt_enable_t) 6Lo support
*
* @see [RFC 4944](https://tools.ietf.org/html/rfc4944)
*/
NETOPT_6LO,
/**
* @brief (@ref netopt_enable_t) header compression
*
* @see [RFC 6282](https://tools.ietf.org/html/rfc6282)
*/
NETOPT_6LO_IPHC,
/**
* @brief (uint8_t) retry amount from missing ACKs of the last transmission
*
* This retrieves the number of retries needed for the last transmission.
* Only retransmissions due to missing ACK frames are considered, retries
* due to CCA failures are not counted.
*/
NETOPT_TX_RETRIES_NEEDED,
/**
* @brief (netdev_ble_ctx_t) set BLE radio context (channel, CRC, AA)
*
* @warning As @ref drivers_netdev_ble is still experimental, use with care!
*/
NETOPT_BLE_CTX,
/**
* @brief (@ref netopt_enable_t) enable hardware checksumming
*
* If enabled, enable hardware checksumming of incoming frames.
*/
NETOPT_CHECKSUM,
/**
* @brief (@ref netopt_enable_t) enable busy mode
*
* When set, the PHY will enter busy mode, in which it will not accept
* incoming frames until unset.
*/
NETOPT_PHY_BUSY,
/**
* @brief (uint8_t*) LoRaWAN application EUI (8 bytes length)
*/
NETOPT_LORAWAN_APPEUI,
/**
* @brief (uint8_t*) LoRaWAN application key (16 bytes length)
*/
NETOPT_LORAWAN_APPKEY,
/**
* @brief (uint8_t*) LoRaWAN network session key (16 bytes length)
*/
NETOPT_LORAWAN_NWKSKEY,
/**
* @brief (uint8_t*) LoRaWAN application session key (16 bytes length)
*/
NETOPT_LORAWAN_APPSKEY,
/**
* @brief (uint8_t) LoRaWAN device class (A, B, C)
* - LoRaWAN: @ref loramac_class_t
*/
NETOPT_LORAWAN_DEVICE_CLASS,
/**
* @brief (uint8_t) LoRaWAN datarate
* - LoRaWAN: @ref loramac_dr_idx_t
*/
NETOPT_LORAWAN_DR,
/**
* @brief (@ref netopt_enable_t) LoRaWAN adaptive datarate
*/
NETOPT_LORAWAN_ADR,
/**
* @brief (@ref netopt_enable_t) LoRaWAN public network
*/
NETOPT_LORAWAN_PUBLIC_NETWORK,
/**
* @brief (uint8_t) LoRaWAN TX application port
* - LoRaWAN: between 1 and 223 (included)
*/
NETOPT_LORAWAN_TX_PORT,
/**
* @brief (loramac_dr_idx_t) LoRaWAN datarate for second RX window
* - LoRaWAN: @ref loramac_dr_idx_t
*/
NETOPT_LORAWAN_RX2_DR,
/**
* @brief (uint32_t) LoRaWAN frequency used for second RX window
*/
NETOPT_LORAWAN_RX2_FREQ,
/**
* @brief (uint32_t) LoRaWAN maximum system overall timing error (ms)
*/
NETOPT_LORAWAN_MAX_RX_ERROR,
/**
* @brief (uint8_t) LoRaWAN maximum system overall timing error (symbols)
*/
NETOPT_LORAWAN_MIN_RX_SYMBOL,
/**
* @brief (uint8_t) 802.15.4 PHY mode
*/
NETOPT_IEEE802154_PHY,
/**
* @brief (uint8_t) legacy O-QPSK proprietary mode
* Allows to select higher data rates than standard 250 kbit/s
* Not compatible across vendors, only use with radios of the same type.
*/
NETOPT_OQPSK_RATE,
/**
* @brief (uint8_t) MR-O-QPSK Chip Rate (kchip/s)
*/
NETOPT_MR_OQPSK_CHIPS,
/**
* @brief (uint8_t) MR-O-QPSK Rate Mode
*/
NETOPT_MR_OQPSK_RATE,
/**
* @brief (uint8_t) MR-OFDM PHY Option (Values: 1-4)
*/
NETOPT_MR_OFDM_OPTION,
/**
* @brief (uint8_t) MR-OFDM PHY Modulation and Coding Scheme (Values: 0-6)
*/
NETOPT_MR_OFDM_MCS,
/**
* @brief (uint8_t) MR-FSK PHY Modulation Index (x 64)
*/
NETOPT_MR_FSK_MODULATION_INDEX,
/**
* @brief (uint8_t) MR-FSK Modulation Order
*/
NETOPT_MR_FSK_MODULATION_ORDER,
/**
* @brief (uint8_t) MR-FSK PHY Symbol Rate (kHz)
*/
NETOPT_MR_FSK_SRATE,
/**
* @brief (uint8_t) MR-FSK PHY Forward Error Correction
*/
NETOPT_MR_FSK_FEC,
/**
* @brief (uint8_t) PHY Channel Spacing (kHz)
*/
NETOPT_CHANNEL_SPACING,
/**
* @brief (uint8_t*) phy layer syncword
*/
NETOPT_SYNCWORD,
/**
* @brief (uint32_t) Get a random value from the device
*
* Nothing happens when set
*/
NETOPT_RANDOM,
/**
* @brief (uint8_t) Get or set the number of PHY symbols before assuming there's no data
*/
NETOPT_RX_SYMBOL_TIMEOUT,
/* add more options if needed */
/**
* @brief (@ref netopt_enable_t) Enable or disable OTAA activation (LoRaWAN)
*/
NETOPT_OTAA,
/**
* @brief (uint8_t) Get the demodulation margin of the last Link Check request.
*/
NETOPT_DEMOD_MARGIN,
/**
* @brief (uint8_t) Get the number of gateways of the last Link Check request.
*/
NETOPT_NUM_GATEWAYS,
/**
* @brief (@ref netopt_enable_t) Perform a Link Check request (LoRaWAN)
*
* When set, the next transmission will request a Link Check and will
* be received on the next downlink
*/
NETOPT_LINK_CHECK,
/**
* @brief (int8_t) Received Signal Strength Indicator (RSSI)
*
* The RSSI is an indicator for the received field strength in wireless
* channels. It is often represented as the ratio of received power to
* a given unit, for example milliwatts. With a device-dependent scaling
* factor, the RSSI value can be expressed as power level in the unit
* dBm or ASU (Arbitrary Strength Unit).
*/
NETOPT_RSSI,
/**
* @brief (uint16_t) Set the battery monitor voltage (in mV).
*
* When set, a @ref SYS_BUS_POWER_EVENT_LOW_VOLTAGE event is generated
* on the SYS_BUS_POWER bus if the supply voltage falls below the set value.
*
* Set to 0 to disable battery monitoring.
*/
NETOPT_BATMON,
/**
* @brief (array of byte array) get link layer multicast groups as array
* of byte arrays (length of each byte array corresponds to the
* length of @ref NETOPT_ADDRESS) or join a link layer multicast
* group as byte array on an interface
*
* When getting the option you can pass an array of byte arrays of any
* length greater than 0 to the getter. The array will be filled up to to
* its maximum and the remaining addresses on the interface will be ignored
*/
NETOPT_L2_GROUP,
/**
* @brief (array of byte arrays) Leave an link layer multicast group
*/
NETOPT_L2_GROUP_LEAVE,
/**
* @brief maximum number of options defined here.
*
* @note Interfaces are not meant to respond to this option
*/
NETOPT_NUMOF,
} netopt_t;
/**
* @brief Binary parameter for enabling and disabling options
*/
typedef enum {
NETOPT_DISABLE = 0, /**< disable a given option */
NETOPT_ENABLE = 1, /**< enable a given option */
} netopt_enable_t;
/**
* @brief Option parameter to be used with @ref NETOPT_STATE to set or get
* the state of a network device or protocol implementation
*/
typedef enum {
NETOPT_STATE_OFF = 0, /**< powered off */
NETOPT_STATE_SLEEP, /**< sleep mode */
NETOPT_STATE_IDLE, /**< idle mode,
* the device listens to receive packets */
NETOPT_STATE_RX, /**< receive mode,
* the device currently receives a packet */
NETOPT_STATE_TX, /**< transmit mode,
* set: triggers transmission of a preloaded packet
* (see @ref NETOPT_PRELOADING*). The resulting
* state of the network device is @ref NETOPT_STATE_IDLE
* get: the network device is in the process of
* transmitting a packet */
NETOPT_STATE_RESET, /**< triggers a hardware reset. The resulting
* state of the network device is @ref NETOPT_STATE_IDLE */
NETOPT_STATE_STANDBY, /**< standby mode. The devices is awake but
* not listening to packets. */
/* add other states if needed */
} netopt_state_t;
/**
* @brief Option parameter to be used with @ref NETOPT_RF_TESTMODE
*/
typedef enum {
NETOPT_RF_TESTMODE_IDLE = 0, /**< idle mode, radio off */
NETOPT_RF_TESTMODE_CRX, /**< continuous rx mode */
NETOPT_RF_TESTMODE_CTX_CW, /**< carrier wave continuous tx mode */
NETOPT_RF_TESTMODE_CTX_PRBS9, /**< PRBS9 continuous tx mode */
} netopt_rf_testmode_t;
/**
* @brief Get a string ptr corresponding to opt, for debugging
*
* @param[in] opt The option to get a string representation for
*
* @return ptr to string representation for given option or "unknown"
*/
const char *netopt2str(netopt_t opt);
#ifdef __cplusplus
}
#endif
#endif /* NET_NETOPT_H */
/** @} */

Wyświetl plik

@ -1,105 +0,0 @@
/*
* Copyright (C) 2019 Kaspar Schleiser <kaspar@schleiser.de>
*
* 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.
*/
/**
* @defgroup sys_unaligned unaligned memory access methods
* @ingroup sys
* @brief Provides functions for safe unaligned memory accesses
*
* This header provides functions to read values from pointers that are not
* necessarily aligned to the type's alignment requirements.
*
* E.g.,
*
* uint16_t *foo = 0x123;
* printf("%u\n", *foo);
*
* ... might cause an unaligned access, if `uint16_t` is usually aligned at
* 2-byte-boundaries, as foo has an odd address.
*
* The current implementation casts a pointer to a packed struct, which forces
* the compiler to deal with possibly unalignedness. Idea taken from linux
* kernel sources.
*
* @{
*
* @file
* @brief Unaligned but safe memory access functions
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifndef UNALIGNED_H
#define UNALIGNED_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Unaligned access helper struct (uint16_t version) */
typedef struct __attribute__((packed)) {
uint16_t val; /**< value */
} uint16_una_t;
/** @brief Unaligned access helper struct (uint32_t version) */
typedef struct __attribute__((packed)) {
uint32_t val; /**< value */
} uint32_una_t;
/** @brief Unaligned access helper struct (uint64_t version) */
typedef struct __attribute__((packed)) {
uint64_t val; /**< value */
} uint64_una_t;
/**
* @brief Get uint16_t from possibly unaligned pointer
*
* @param[in] ptr pointer to read from
*
* @returns value read from @p ptr
*/
static inline uint16_t unaligned_get_u16(const void *ptr)
{
const uint16_una_t *tmp = (const uint16_una_t *)ptr;
return tmp->val;
}
/**
* @brief Get uint32_t from possibly unaligned pointer
*
* @param[in] ptr pointer to read from
*
* @returns value read from @p ptr
*/
static inline uint32_t unaligned_get_u32(const void *ptr)
{
const uint32_una_t *tmp = (const uint32_una_t *)ptr;
return tmp->val;
}
/**
* @brief Get uint64_t from possibly unaligned pointer
*
* @param[in] ptr pointer to read from
*
* @returns value read from @p ptr
*/
static inline uint64_t unaligned_get_u64(const void *ptr)
{
const uint64_una_t *tmp = (const uint64_una_t *)ptr;
return tmp->val;
}
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* UNALIGNED_H */

Wyświetl plik

@ -1,114 +0,0 @@
---
Language: Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Linux
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 8
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
RawStringFormats:
- Delimiter: pb
Language: TextProto
BasedOnStyle: google
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
...

Wyświetl plik

@ -1,82 +0,0 @@
#
# NOTE! Don't add files that are generated in specific
# subdirectories here. Add them in the ".gitignore" file
# in that subdirectory instead.
#
# NOTE! Please use 'git ls-files -i --exclude-standard'
# command after changing this file, to see if there are
# any tracked files which get ignored after the change.
#
# Normal rules (sorted alphabetically)
#
.*
*.a
*.asn1.[ch]
*.bin
*.bz2
*.c.[012]*.*
*.dtb
*.dtbo
*.dtb.S
*.dwo
*.elf
*.gcno
*.gz
*.i
*.ko
*.lex.c
*.ll
*.lst
*.lz4
*.lzma
*.lzo
*.mod.c
*.o
*.o.*
*.order
*.patch
*.s
*.so
*.so.dbg
*.su
*.symtypes
*.tab.[ch]
*.tar
*.xz
Module.symvers
modules.builtin
#
# Top-level generic files
#
/tags
/TAGS
/linux
/vmlinux
/vmlinux.32
/vmlinux-gdb.py
/vmlinuz
/System.map
/Module.markers
#
# git files that we don't want to ignore even if they are dot-files
#
!.gitignore
!.mailmap
!.cocciconfig
!.clang-format
# cscope files
cscope.*
ncscope.*
# gnu global files
GPATH
GRTAGS
GSYMS
GTAGS
*.orig
*~
\#*#

Wyświetl plik

@ -1,52 +0,0 @@
# A prerequisite to cross-compiling an out-of-tree kernel module for the
# Raspberry Pi running a **stock kernel** is to get and cross-compile the kernel
# source code for the version **matching exactly** the one running on your
# board. Figure out the version of the kernel running on your board
#
# pi@raspberrypi:~ $ uname -r
# 4.19.57-v7+
#
# pi@raspberrypi:~$ vcgencmd version
# Jul 9 2019 14:40:53
# Copyright (c) 2012 Broadcom
# version 6c3fe3f096a93de3b34252ad98cdccadeb534be2 (clean) (release) (start)
#
# Clone only the relevant Git branch on your development host
#
# $ git clone --branch raspberrypi-kernel_1.20190709-1 --depth 1 https://github.com/raspberrypi/linux.git
#
# $ cd linux
#
# $ head -5 Makefile
# # SPDX-License-Identifier: GPL-2.0
# VERSION = 4
# PATCHLEVEL = 19
# SUBLEVEL = 57
# EXTRAVERSION =
#
# Cross-compile the kernel source code for your specific board model as
# instructed in the official documentation. For instance, for a Raspberry Pi 3
# Model B+
#
# $ KERNEL=kernel7
#
# $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
#
# $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs
#
CFLAGS_MODULE += -Werror
CFLAGS_MODULE += -DDEBUG
ARCH := arm
KERNELDIR := /home/godzilla/making/linux
CROSS_COMPILE := arm-linux-gnueabihf-
PWD := $(shell pwd)
obj-m := at86rf215.o ping.o
default:
$(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf .*.cmd .tmp_versions *~ *.ko *.mod.c *.o modules.order Module.symvers

Wyświetl plik

@ -1,97 +0,0 @@
Atmel Performance Analyzer
IRQ handler is defined in
~/making/perf_analyzer/ASF/thirdparty/wireless/avr2025_mac/source/tal/at86rf215/src/tal_irq_handler.
Some processing of the IRQ status is performed in the handler but some if
deferred to the TAL task by updating a volatile variable that holds the latest
register value.
SPI read/write routines are defined in
~/making/perf_analyzer/ASF/thirdparty/wireless/services/trx_access/trx_access_2.c
The TAL task function is defined in
~/making/perf_analyzer/ASF/thirdparty/wireless/avr2025_mac/source/tal/at86rf215/src/tal.c
For now we don't care for the 2.4 GHz radio and associated baseband core. The
only exception is when we clear the IRQ line at initialization for which we need
to read the 2.4 GHz radio IRQ status register.
On the RPi, interrupt GPIO is BCM 23
uncrustify -c ~/making/zephyr/.uncrustify.cfg --replace ping.c
AT86RF215 Channel Configuration
OFDM Option1 in in the 902–928 frequency band
ChanSpacing: 1.2 MHz
TotalNumChan: 20
ChanCenterFreq0: 903.2 Mhz
Center frequency for channel 3 is 906.8 according to
ChanCenterFreq = ChanCenterFreq0 + NumChan × ChanSpacing
Do NOT enable SPI in Raspberry Pi boot config file
sudo dtoverlay at86rf233
/home/godzilla/making/linux/arch/arm/boot/dts/overlays/at86rf233-overlay.dts
Enable verbose output for make
make V=1
iwpan dev wpan0 set pan_id 0x1111
iwpan dev wpan0 set short_addr 0x0001
ip link set wpan0 up
wpan-ping -c 1 --address 0x1234
root@raspberrypi:/sys/kernel/debug/tracing# cat trace
# tracer: function
#
# entries-in-buffer/entries-written: 2/2 #P:4
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
wpan-ping-1129 [002] .... 413347.967856: at86rf215_xmit_async <-ieee802154_tx
wpan-ping-1129 [002] .... 413347.967951: <stack trace>
=> at86rf215_xmit_async
=> ieee802154_tx
=> ieee802154_subif_start_xmit
=> dev_hard_start_xmit
=> sch_direct_xmit
=> __qdisc_run
=> __dev_queue_xmit
=> dev_queue_xmit
=> dgram_sendmsg
=> ieee802154_sock_sendmsg
=> sock_sendmsg
=> __sys_sendto
=> sys_sendto
=> ret_fast_syscall

Wyświetl plik

@ -1,80 +0,0 @@
# Description
A Linux driver for the Atmel AT86RF215 radio transceiver. The development target
is the Raspberry Pi 3.
# Compilation
A prerequisite to cross-compiling an out-of-tree kernel module for the Raspberry
Pi running a **stock kernel** is to get and cross-compile the kernel source code
for the exact version running on your board. To find out the version of the
kernel running on your board execute
```
pi@raspberrypi:~ $ uname -r
4.19.57-v7+
```
```
pi@raspberrypi:~$ vcgencmd version
Jul 9 2019 14:40:53
Copyright (c) 2012 Broadcom
version 6c3fe3f096a93de3b34252ad98cdccadeb534be2 (clean) (release) (start)
```
Clone only the relevant Git branch on your development host
```
$ git clone --branch raspberrypi-kernel_1.20190709-1 --depth 1 https://github.com/raspberrypi/linux.git
$ cd linux
$ head -5 Makefile
\# SPDX-License-Identifier: GPL-2.0
VERSION = 4
PATCHLEVEL = 19
SUBLEVEL = 57
EXTRAVERSION =
```
Cross-compile the kernel source code for your specific board model as instructed
in the official documentation. For instance, for a Raspberry Pi 3 Model B+
execute
```
$ KERNEL=kernel7
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs
```
# Loading
Make sure to load the IEEE 802.15.4 "soft MAC"
```
pi@raspberrypi:~ $ sudo modprobe mac802154
```
before loading the driver module
```
pi@raspberrypi:~ $ sudo insmod /path/to/at86rf215.ko
```
This should result in the enumeration of a new network interface
```
pi@raspberrypi:~ $ ip link
...
8: wpan0: <BROADCAST,NOARP> mtu 123 qdisc noop state DOWN mode DEFAULT group default qlen 300
link/ieee802.15.4 5a:52:9d:09:b9:40:86:73 brd ff:ff:ff:ff:ff:ff:ff:ff
...
```
To unload the driver execute
```
pi@raspberrypi:~ $ sudo rmmod at86rf215
```

Wyświetl plik

@ -1,201 +0,0 @@
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/printk.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/spi/at86rf230.h>
#include <linux/spi/spi.h>
#include <net/mac802154.h>
struct at86rf215_private {
struct regmap *regmap;
struct ieee802154_hw *hw;
};
static const struct regmap_config at86rf215_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.read_flag_mask = 0x0, /* [0|0|A|A|A|A|A|A|A|A|A|A|A|A|A|A] */
.write_flag_mask = 0x80, /* [1|0|A|A|A|A|A|A|A|A|A|A|A|A|A|A] */
.cache_type = REGCACHE_RBTREE,
.max_register = 0x3FFE,
};
static struct at86rf215_private *priv;
static int at86rf215_start(struct ieee802154_hw *hw)
{
return 0;
}
static void at86rf215_stop(struct ieee802154_hw *hw)
{
}
static int at86rf215_xmit_async(struct ieee802154_hw *hw, struct sk_buff *skb)
{
return 0;
}
static int at86rf215_ed(struct ieee802154_hw *hw, u8 *level)
{
return 0;
}
static int at86rf215_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
{
return 0;
}
static const struct ieee802154_ops at86rf215_ieee802154_ops = {
.start = at86rf215_start,
.stop = at86rf215_stop,
.xmit_async = at86rf215_xmit_async,
.ed = at86rf215_ed,
.set_channel = at86rf215_set_channel
};
/* Retrieve RSTN pin number from device tree */
static int at86rf215_get_platform_data(struct spi_device *spi, int *rstn_pin_num)
{
if (!spi->dev.of_node) {
dev_err(&spi->dev, "no device tree node found!\n");
return -ENOENT;
}
*rstn_pin_num = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0);
return 0;
}
static int at86rf215_probe(struct spi_device *spi)
{
#if 1
int rstn_pin_num = 0;
#define RG_RF_PN (0x0D)
#define RG_RF_VN (0x0E)
u8 cmd1[3] = {0, RG_RF_PN, 0xff};
/* u8 cmd2[3] = {0, RG_RF_VN, 0xff}; */
u8 rx_buf[3] = {0};
struct spi_message msg;
struct spi_transfer xfer = {
.len = 3,
.tx_buf = &cmd1[0],
.rx_buf = &rx_buf[0]
};
/* Retrieve RSTN pin number */
if (at86rf215_get_platform_data(spi, &rstn_pin_num) < 0 ||
!gpio_is_valid(rstn_pin_num)) {
return -1;
}
dev_dbg(&spi->dev, "RSTN pin number is %d\n", rstn_pin_num);
/* Configure as output, active low */
if (devm_gpio_request_one(&spi->dev, rstn_pin_num,
GPIOF_OUT_INIT_HIGH, "reset") < 0) {
}
/*
* Reset transceiver. The pulse width at pin RSTN must last at least
* 625ns
*/
/*
* udelay(1);
* gpio_set_value_cansleep(rstn_pin_num, 0);
* udelay(1);
* gpio_set_value_cansleep(rstn_pin_num, 1);
*/
/*
* spi_write(spi, cmd1, 3);
* usleep_range(500, 1000);
* spi_write(spi, cmd2, 3);
*/
spi_message_init(&msg);
/* Read transceiver Part Number */
xfer.tx_buf = &cmd1[0];
spi_message_add_tail(&xfer, &msg);
spi_sync(spi, &msg);
print_hex_dump_bytes("", DUMP_PREFIX_NONE, rx_buf, 3);
/* FIXME: the added code below leads to kernel crash */
/* Read transceiver Version Number */
/*
* xfer.tx_buf = &cmd2[0];
* spi_message_add_tail(&xfer, &msg);
* spi_sync(spi, &msg);
*
* print_hex_dump_bytes("", DUMP_PREFIX_NONE, rx_buf, 3);
*/
#else
int ret = 0;
struct ieee802154_hw *hw;
if (priv != NULL)
{
return -1;
}
hw = ieee802154_alloc_hw(sizeof(priv), &at86rf215_ieee802154_ops);
if (!hw)
return -ENOMEM;
priv = hw->priv;
priv->hw = hw;
ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
ret = ieee802154_register_hw(hw);
if (ret)
ieee802154_free_hw(hw);
#endif
return 0;
}
static int at86rf215_remove(struct spi_device *spi)
{
#if 1
priv = NULL;
#else
ieee802154_unregister_hw(priv->hw);
ieee802154_free_hw(priv->hw);
priv = NULL;
#endif
return 0;
}
static const struct of_device_id at86rf215_of_match[] = {
{ .compatible = "atmel,at86rf233", },
{ },
};
MODULE_DEVICE_TABLE(of, at86rf215_of_match);
static const struct spi_device_id at86rf215_device_id[] = {
{ .name = "at86rf233", },
{ },
};
MODULE_DEVICE_TABLE(spi, at86rf215_device_id);
static struct spi_driver at86rf215_driver = {
.id_table = at86rf215_device_id,
.driver = {
.of_match_table = of_match_ptr(at86rf215_of_match),
.name = "at86rf233"
},
.probe = at86rf215_probe,
.remove = at86rf215_remove
};
module_spi_driver(at86rf215_driver);
MODULE_DESCRIPTION("Atmel AT86RF215 radio transceiver driver");
MODULE_LICENSE("GPL v2");

Wyświetl plik

@ -1,80 +0,0 @@
indent_with_tabs = 2 # 1=indent to level only, 2=indent with tabs
input_tab_size = 8 # original tab size
output_tab_size = 8 # new tab size
indent_columns = output_tab_size
indent_label = 1 # pos: absolute col, neg: relative column
indent_switch_case = 0 # number
#
# inter-symbol newlines
#
nl_enum_brace = remove # "enum {" vs "enum \n {"
nl_union_brace = remove # "union {" vs "union \n {"
nl_struct_brace = remove # "struct {" vs "struct \n {"
nl_do_brace = remove # "do {" vs "do \n {"
nl_if_brace = remove # "if () {" vs "if () \n {"
nl_for_brace = remove # "for () {" vs "for () \n {"
nl_else_brace = remove # "else {" vs "else \n {"
nl_while_brace = remove # "while () {" vs "while () \n {"
nl_switch_brace = remove # "switch () {" vs "switch () \n {"
nl_brace_while = remove # "} while" vs "} \n while" - cuddle while
nl_brace_else = remove # "} \n else" vs "} else"
nl_func_var_def_blk = 1
nl_fcall_brace = remove # "list_for_each() {" vs "list_for_each()\n{"
nl_fdef_brace = add # "int foo() {" vs "int foo()\n{"
#
# Source code modifications
#
mod_paren_on_return = ignore # "return 1;" vs "return (1);"
mod_full_brace_if = add # "if() { } else { }" vs "if() else"
#
# inter-character spacing options
#
sp_sizeof_paren = remove # "sizeof (int)" vs "sizeof(int)"
sp_before_sparen = force # "if (" vs "if("
sp_after_sparen = force # "if () {" vs "if (){"
sp_inside_braces = add # "{ 1 }" vs "{1}"
sp_inside_braces_struct = add # "{ 1 }" vs "{1}"
sp_inside_braces_enum = add # "{ 1 }" vs "{1}"
sp_assign = add
sp_arith = add
sp_bool = add
sp_compare = add
sp_assign = add
sp_after_comma = add
sp_func_def_paren = remove # "int foo (){" vs "int foo(){"
sp_func_call_paren = remove # "foo (" vs "foo("
sp_func_proto_paren = remove # "int foo ();" vs "int foo();"
sp_inside_fparen = remove # "func( arg )" vs "func(arg)"
sp_else_brace = add # ignore/add/remove/force
sp_before_ptr_star = add # ignore/add/remove/force
sp_after_ptr_star = remove # ignore/add/remove/force
sp_between_ptr_star = remove # ignore/add/remove/force
sp_inside_paren = remove # remove spaces inside parens
sp_paren_paren = remove # remove spaces between nested parens
sp_inside_sparen = remove # remove spaces inside parens for if, while and the like
sp_brace_else = add # ignore/add/remove/force
sp_before_nl_cont = ignore
sp_cmt_cpp_start = add
sp_brace_typedef = add # }typedefd_name -> } typedefd_name
cmt_sp_after_star_cont = 1
#
# Aligning stuff
#
align_with_tabs = FALSE # use tabs to align
align_on_tabstop = TRUE # align on tabstops
align_enum_equ_span = 4 # '=' in enum definition
align_struct_init_span = 0 # align stuff in a structure init '= { }'
align_right_cmt_span = 3
align_nl_cont = TRUE
sp_pp_concat = ignore # ignore/add/remove/force

Wyświetl plik

@ -1,819 +0,0 @@
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/printk.h>
/* #include <linux/platform_device.h> */
#include <linux/regmap.h>
/* #include <linux/spi/at86rf230.h> */
#include <linux/spi/spi.h>
/* #include <net/mac802154.h> */
#include "reg.h"
#define NUM_TRX 2
/** Enumeration for RF commands and states used for trx command and state
* registers */
typedef enum rf_cmd_status_tag {
/** Constant RF_TRXOFF for sub-register @ref SR_CMD */
STATUS_RF_TRXOFF = (0x2),
/** Constant RF_TXPREP for sub-register @ref SR_CMD */
STATUS_RF_TXPREP = (0x3),
/** Constant RF_TX for sub-register @ref SR_CMD */
STATUS_RF_TX = (0x4),
/** Constant RF_RX for sub-register @ref SR_CMD */
STATUS_RF_RX = (0x5),
/** Constant RF_RX for sub-register @ref SR_CMD */
STATUS_RF_TRANSITION = (0x6),
/** Constant RF_RESET for sub-register @ref SR_CMD */
STATUS_RF_RESET = (0x7)
} rf_cmd_status_t;
/** Enumeration for RF IRQs used for IRQS and IRQM registers */
typedef enum rf_irq_tag {
/** Constant RF_IRQ_IQIFSF for sub-register @ref SR_IQIFSF */
RF_IRQ_IQIFSF = (0x20),
/** Constant RF_IRQ_TRXERR for sub-register @ref SR_TRXERR */
RF_IRQ_TRXERR = (0x10),
/** Constant RF_IRQ_BATLOW for sub-register @ref SR_BATLOW */
RF_IRQ_BATLOW = (0x08),
/** Constant RF_IRQ_EDC for sub-register @ref SR_EDC */
RF_IRQ_EDC = (0x04),
/** Constant RF_IRQ_TRXRDY for sub-register @ref SR_TRXRDY */
RF_IRQ_TRXRDY = (0x02),
/** Constant RF_IRQ_WAKEUP for sub-register @ref SR_WAKEUP */
RF_IRQ_WAKEUP = (0x01),
/** No interrupt is indicated by IRQ_STATUS register */
RF_IRQ_NO_IRQ = (0x00),
/** All interrupts are indicated by IRQ_STATUS register */
RF_IRQ_ALL_IRQ = (0x3F)
} rf_irq_t;
/** Enumeration for BB IRQs */
typedef enum bb_irq_tag {
/** Constant BB_IRQ_FBLI for sub-register @ref SR_FBLI */
BB_IRQ_FBLI = (0x80),
/** Constant BB_IRQ_AGCR for sub-register @ref SR_AGCR */
BB_IRQ_AGCR = (0x40),
/** Constant BB_IRQ_AGCH for sub-register @ref SR_AGCH */
BB_IRQ_AGCH = (0x20),
/** Constant BB_IRQ_TXFE for sub-register @ref SR_TXFE */
BB_IRQ_TXFE = (0x10),
/** Constant BB_IRQ_RXEM for sub-register @ref SR_RXEM */
BB_IRQ_RXEM = (0x08),
/** Constant BB_IRQ_RXAM for sub-register @ref SR_RXAM */
BB_IRQ_RXAM = (0x04),
/** Constant BB_IRQ_RXFE for sub-register @ref SR_RXFE */
BB_IRQ_RXFE = (0x02),
/** Constant BB_IRQ_RXFS for sub-register @ref SR_RXFS */
BB_IRQ_RXFS = (0x01),
/** No interrupt is indicated by IRQ_STATUS register */
BB_IRQ_NO_IRQ = (0x00),
/** All interrupts are indicated by IRQ_STATUS register */
BB_IRQ_ALL_IRQ = (0xFF)
} bb_irq_t;
static bool is_configured;
enum { AT86RF215 = 0x34, AT86RF215IQ, AT86RF215M };
static const struct trx_id {
unsigned char part_number;
const char *description;
} trx_ids[] = {
{ AT86RF215, "AT86RF215" },
{ AT86RF215IQ, "AT86RF215IQ" },
{ AT86RF215M, "AT86RF215M" },
};
#define num_of_trx_ids (sizeof(trx_ids) / sizeof(trx_ids[0]))
enum { RF_DUMMY1 = 0x0,
RF_DUMMY2,
RF_TRXOFF = 0x2, /* Transceiver off, SPI active */
RF_TXPREP, /* Transmit preparation */
RF_TX, /* Transmit */
RF_RX, /* Receive */
RF_TRANSITION, /* State transition in progress */
RF_RESET, /* Transceiver is in state RESET or SLEEP */
RF_MAX };
static const char *trx_state_descs[RF_MAX] = {
"DUMMY1", "DUMMY2", "TRXOFF", "TXPREP", "TX", "RX", "TRANSITION", "RESET"
};
static const struct trx_state {
unsigned char value;
const char *description;
} trx_states[] = {
{ RF_TRXOFF, "TRXOFF" }, { RF_TXPREP, "TXPREP" }, { RF_TX, "TX" },
{ RF_RX, "RX" }, { RF_TRANSITION, "TRANSITION" }, { RF_RESET, "RESET" }
};
#define num_of_trx_states (sizeof(trx_states) / sizeof(trx_states[0])
static struct at86rf215_priv {
struct spi_device *spi;
int cookie;
} at86rf215_priv = { .cookie = 0xbabef00d };
static struct at86rf215_priv *priv = &at86rf215_priv;
enum { CMD_NOP,
CMD_SLEEP,
CMD_TRXOFF,
CMD_TXPREP,
CMD_TX,
CMD_RX,
CMD_RESET = 0x7 };
/* SPI block read access data structures and functions */
static u8 trx_read_tx_buf[2];
static volatile u8 trx_read_rx_buf[2047];
static struct spi_message trx_read_msg;
static struct spi_transfer trx_read_xfers[2];
static struct {
const char *names[4];
u8 values[4];
} at86rf215_irqs = {
{ "RF09_IRQS", "RF24_IRQS", "BBC0_IRQS", "BBC1_IRQS" },
{ 0 }
};
/** Sub-registers of Register @ref IRQS */
/** Bit Mask for Sub-Register IRQS.WAKEUP */
#define IRQS_WAKEUP_MASK 0x01
/** Bit Offset for Sub-Register IRQS.WAKEUP */
#define IRQS_WAKEUP_SHIFT 0
/** Bit Mask for Sub-Register IRQS.TRXRDY */
#define IRQS_TRXRDY_MASK 0x02
/** Bit Offset for Sub-Register IRQS.TRXRDY */
#define IRQS_TRXRDY_SHIFT 1
/** Bit Mask for Sub-Register IRQS.EDC */
#define IRQS_EDC_MASK 0x04
/** Bit Offset for Sub-Register IRQS.EDC */
#define IRQS_EDC_SHIFT 2
/** Bit Mask for Sub-Register IRQS.BATLOW */
#define IRQS_BATLOW_MASK 0x08
/** Bit Offset for Sub-Register IRQS.BATLOW */
#define IRQS_BATLOW_SHIFT 3
/** Bit Mask for Sub-Register IRQS.TRXERR */
#define IRQS_TRXERR_MASK 0x10
/** Bit Offset for Sub-Register IRQS.TRXERR */
#define IRQS_TRXERR_SHIFT 4
/** Bit Mask for Sub-Register IRQS.IQIFSF */
#define IRQS_IQIFSF_MASK 0x20
/** Bit Offset for Sub-Register IRQS.IQIFSF */
#define IRQS_IQIFSF_SHIFT 5
#define RF_IRQS_MAX_SHIFT IRQS_IQIFSF_SHIFT
/** Sub-registers of Register @ref IRQS */
/** Bit Mask for Sub-Register IRQS.RXFS */
#define IRQS_RXFS_MASK 0x01
/** Bit Offset for Sub-Register IRQS.RXFS */
#define IRQS_RXFS_SHIFT 0
/** Bit Mask for Sub-Register IRQS.RXFE */
#define IRQS_RXFE_MASK 0x02
/** Bit Offset for Sub-Register IRQS.RXFE */
#define IRQS_RXFE_SHIFT 1
/** Bit Mask for Sub-Register IRQS.RXAM */
#define IRQS_RXAM_MASK 0x04
/** Bit Offset for Sub-Register IRQS.RXAM */
#define IRQS_RXAM_SHIFT 2
/** Bit Mask for Sub-Register IRQS.RXEM */
#define IRQS_RXEM_MASK 0x08
/** Bit Offset for Sub-Register IRQS.RXEM */
#define IRQS_RXEM_SHIFT 3
/** Bit Mask for Sub-Register IRQS.TXFE */
#define IRQS_TXFE_MASK 0x10
/** Bit Offset for Sub-Register IRQS.TXFE */
#define IRQS_TXFE_SHIFT 4
/** Bit Mask for Sub-Register IRQS.AGCH */
#define IRQS_AGCH_MASK 0x20
/** Bit Offset for Sub-Register IRQS.AGCH */
#define IRQS_AGCH_SHIFT 5
/** Bit Mask for Sub-Register IRQS.AGCR */
#define IRQS_AGCR_MASK 0x40
/** Bit Offset for Sub-Register IRQS.AGCR */
#define IRQS_AGCR_SHIFT 6
/** Bit Mask for Sub-Register IRQS.FBLI */
#define IRQS_FBLI_MASK 0x80
/** Bit Offset for Sub-Register IRQS.FBLI */
#define IRQS_FBLI_SHIFT 7
#define BB_IRQS_MAX_SHIFT IRQS_FBLI_SHIFT
static void at86rf215_rf_irqs_print(const char *name, u8 val)
{
char str[RF_IRQS_MAX_SHIFT + 2];
str[RF_IRQS_MAX_SHIFT + 1] = '\0';
printk("\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
" _------==> IQIFSF",
" / _-----==> TRXERR",
" | / _----==> BATLOW",
" || / _---==> EDC",
" ||| / _--==> TRXRDY",
" |||| / _-==> WAKEUP",
" ||||| /",
" ||||||"
);
str[RF_IRQS_MAX_SHIFT - IRQS_WAKEUP_SHIFT] =
val & IRQS_WAKEUP_MASK ? '1' : '.';
str[RF_IRQS_MAX_SHIFT - IRQS_TRXRDY_SHIFT] =
val & IRQS_TRXRDY_MASK ? '1' : '.';
str[RF_IRQS_MAX_SHIFT - IRQS_EDC_SHIFT] =
val & IRQS_EDC_MASK ? '1' : '.';
str[RF_IRQS_MAX_SHIFT - IRQS_BATLOW_SHIFT] =
val & IRQS_BATLOW_MASK ? '1' : '.';
str[RF_IRQS_MAX_SHIFT - IRQS_TRXERR_SHIFT] =
val & IRQS_TRXERR_MASK ? '1' : '.';
str[RF_IRQS_MAX_SHIFT - IRQS_IQIFSF_SHIFT] =
val & IRQS_IQIFSF_MASK ? '1' : '.';
printk("%s %s\n", name, str);
}
static void at86rf215_bb_irqs_print(const char *name, u8 val)
{
char str[BB_IRQS_MAX_SHIFT + 2];
str[BB_IRQS_MAX_SHIFT + 1] = '\0';
printk("\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
" _--------==> FBLI",
" / _-------==> AGCR",
" | / _------==> AGCH",
" || / _-----==> TXFE",
" ||| / _----==> RXEM",
" |||| / _---==> RXAM",
" ||||| / _--==> RXFE",
" |||||| / _-==> RXFS",
" ||||||| /",
" ||||||||");
str[BB_IRQS_MAX_SHIFT - IRQS_RXFS_SHIFT] =
val & IRQS_RXFS_MASK ? '1' : '.';
str[BB_IRQS_MAX_SHIFT - IRQS_RXFE_SHIFT] =
val & IRQS_RXFE_MASK ? '1' : '.';
str[BB_IRQS_MAX_SHIFT - IRQS_RXAM_SHIFT] =
val & IRQS_RXAM_MASK ? '1' : '.';
str[BB_IRQS_MAX_SHIFT - IRQS_RXEM_SHIFT] =
val & IRQS_RXEM_MASK ? '1' : '.';
str[BB_IRQS_MAX_SHIFT - IRQS_TXFE_SHIFT] =
val & IRQS_TXFE_MASK ? '1' : '.';
str[BB_IRQS_MAX_SHIFT - IRQS_AGCH_SHIFT] =
val & IRQS_AGCH_MASK ? '1' : '.';
str[BB_IRQS_MAX_SHIFT - IRQS_AGCR_SHIFT] =
val & IRQS_AGCR_MASK ? '1' : '.';
str[BB_IRQS_MAX_SHIFT - IRQS_FBLI_SHIFT] =
val & IRQS_FBLI_MASK ? '1' : '.';
printk("%s %s\n", name, str);
}
static void at86rf215_irqs_read_complete(void *context)
{
struct at86rf215_priv *priv = context;
int i;
(void)priv;
for (i = 0; i < NUM_TRX; i++) {
/* if (at86rf215_irqs.values[i]) */
at86rf215_rf_irqs_print(at86rf215_irqs.names[i],
at86rf215_irqs.values[i]);
/* if (at86rf215_irqs.values[i + 2]) */
at86rf215_bb_irqs_print(at86rf215_irqs.names[i + 2],
at86rf215_irqs.values[i + 2]);
}
}
static void at86rf215_trx_read(struct at86rf215_priv *priv, u16 addr,
u8 *data, size_t len,
void (*complete)(void *context))
{
/* The first transfer carries the two command bytes */
trx_read_xfers[0].len = 2;
trx_read_tx_buf[0] = addr >> 8;
trx_read_tx_buf[1] = addr;
trx_read_xfers[0].tx_buf = &trx_read_tx_buf[0];
trx_read_xfers[0].rx_buf = NULL;
/*
* The second transfer reads payload. According to the SPI API
* documentation, the chip select normally remains active until after
* the last transfer in a message.
*/
trx_read_xfers[1].len = len;
trx_read_xfers[1].tx_buf = NULL;
trx_read_xfers[1].rx_buf = data;
spi_message_init_with_transfers(&trx_read_msg, trx_read_xfers,
sizeof(trx_read_xfers) / sizeof(trx_read_xfers[0]));
trx_read_msg.complete = complete;
trx_read_msg.context = priv;
spi_async(priv->spi, &trx_read_msg);
}
/* SPI block write access data structures and functions */
static u8 trx_write_tx_buf[2047 + 2];
static struct spi_message trx_write_msg;
static struct spi_transfer trx_write_xfers[2];
static void at86rf215_trx_write_complete(void *context)
{
struct at86rf215_priv *priv = context;
printk("%s in_interrupt: %s cookie: 0x%x\n", __func__,
in_interrupt() ? "yes" : "no", priv->cookie);
}
static void at86rf215_trx_write(struct at86rf215_priv *priv, u16 addr, u8 *data,
size_t len)
{
/* The first transfer carries the two command bytes */
trx_write_xfers[0].len = 2;
trx_write_tx_buf[0] = (addr >> 8) | 0x8000;
trx_write_tx_buf[1] = addr;
trx_write_xfers[0].tx_buf = &trx_write_tx_buf[0];
trx_write_xfers[0].rx_buf = NULL;
/*
* The second transfer writes payload. According to the SPI API
* documentation, the chip select normally remains active until after
* the last transfer in a message.
*/
trx_write_xfers[1].len = len;
trx_write_xfers[1].tx_buf = data;
trx_write_xfers[1].rx_buf = NULL;
spi_message_init_with_transfers(&trx_write_msg, trx_write_xfers,
sizeof(trx_write_xfers) / sizeof(trx_write_xfers[0]));
trx_write_msg.complete = at86rf215_trx_write_complete;
trx_write_msg.context = priv;
spi_async(priv->spi, &trx_write_msg);
}
/*
* TODO: confirm that it's preferable to allocate context on the heap. Make sure to free allocated
* memory!
*/
static irqreturn_t at86rf215_irq_handler(int irq, void *data)
{
struct at86rf215_priv *priv = data;
printk("%s in_interrupt: %s\n", __func__,
in_interrupt() ? "yes" : "no");
disable_irq_nosync(irq);
/* TODO: disable all IRQs on the transceiver by writing BBCx_IRQM and RFx_IRQM */
/* Read all IRQ status registers. This will clear the interrupt line. */
at86rf215_trx_read(priv, RG_RF09_IRQS, &at86rf215_irqs.values[0],
sizeof(at86rf215_irqs.values),
at86rf215_irqs_read_complete);
return IRQ_HANDLED;
}
static struct timer_list ping_timer;
/* RSTN pin number */
static int rstn_pin_num;
static struct regmap *regmap;
/* Registers whose value can be written */
static bool at86rf215_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case RG_RF09_IRQM:
case RG_RF09_CMD:
case RG_RF09_CS:
case RG_RF09_CCF0L:
case RG_RF09_CCF0H:
case RG_RF09_CNL:
case RG_RF09_CNM:
case RG_RF09_RXBWC:
case RG_RF09_RXDFE:
case RG_RF09_EDD:
case RG_RF09_RNDV:
case RG_RF09_TXCUTC:
case RG_RF09_TXDFE:
case RG_RF09_PAC:
case RG_BBC0_IRQM:
case RG_BBC0_PC:
case RG_BBC0_OFDMPHRTX:
return true;
default:
return false;
}
}
/* Registers whose value can be read */
static bool at86rf215_readable_reg(struct device *dev, unsigned int reg)
{
bool ret;
ret = at86rf215_writeable_reg(dev, reg);
if (ret) {
return ret;
}
switch (reg) {
case RG_RF09_IRQS:
case RG_RF24_IRQS:
case RG_RF_PN:
case RG_RF_VN:
case RG_RF09_STATE:
case RG_RF09_RSSI:
return true;
default:
return false;
}
}
/* Registers whose value shouldn't be cached */
static bool at86rf215_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case RG_RF09_IRQS:
case RG_RF24_IRQS:
case RG_RF_PN: /* TODO: remove */
case RG_RF_VN: /* TODO: remove */
case RG_RF09_STATE:
case RG_RF09_RSSI:
return true;
default:
return false;
}
}
/* Registers whose value should not be read outside a call from the driver */
/* The IRQ status registers are cleared automatically by reading the
* corresponding register via SPI. */
static bool at86rf215_precious_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
/* case RG_RF09_IRQS: */
case RG_BBC0_IRQS:
return true;
default:
return false;
}
}
/* AT86RF215 register map configuration */
static const struct regmap_config at86rf215_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.writeable_reg = at86rf215_writeable_reg,
.readable_reg = at86rf215_readable_reg,
.volatile_reg = at86rf215_volatile_reg,
.precious_reg = at86rf215_precious_reg,
.read_flag_mask = 0x0, /* [0|0|x|x|x|x|x|x|x|x|x|x|x|x|x|x] */
.write_flag_mask = 0x80, /* [1|0|x|x|x|x|x|x|x|x|x|x|x|x|x|x] */
.cache_type = REGCACHE_RBTREE,
.max_register = 0x3FFE,
};
/* Retrieve RSTN pin number from device tree */
static int at86rf215_get_platform_data(struct spi_device *spi,
int *rstn_pin_num)
{
if (!spi->dev.of_node) {
dev_err(&spi->dev, "no device tree node found!\n");
return -ENOENT;
}
*rstn_pin_num = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0);
return 0;
}
static void at86rf215_configure(void)
{
int ret;
/* Radio IRQ mask configuration */
ret = regmap_write(regmap, RG_RF09_IRQM, 0x1F);
if (ret < 0) {
pr_err("can't write radio IRQ mask\n");
return;
}
/* Baseband IRQ mask configuration */
ret = regmap_write(regmap, RG_BBC0_IRQM, 0x1F);
if (ret < 0) {
pr_err("can't write baseband IRQ mask\n");
return;
}
/* Channel configuration */
ret = regmap_write(regmap, RG_RF09_CS, 0x30);
if (ret < 0) {
pr_err("can't write channel spacing\n");
return;
}
ret = regmap_write(regmap, RG_RF09_CCF0L, 0x20);
if (ret < 0) {
pr_err("can't write channel center freq0 low byte\n");
return;
}
ret = regmap_write(regmap, RG_RF09_CCF0H, 0x8D);
if (ret < 0) {
pr_err("can't write channel center freq0 high byte\n");
return;
}
ret = regmap_write(regmap, RG_RF09_CNL, 0x3);
if (ret < 0) {
pr_err("can't write channel number\n");
return;
}
ret = regmap_write(regmap, RG_RF09_CNM, 0);
if (ret < 0) {
pr_err("can't trigger channel setting update\n");
return;
}
/*
* ret = regmap_write(regmap, , );
* if (ret < 0) {
* pr_err("can't write transceiver's \n");
* return;
* }
*/
/* Frontend configuration */
/* TXCUTC.LPFCUT is set to 0xB */
ret = regmap_write(regmap, RG_RF09_TXCUTC, 0xB);
if (ret < 0) {
pr_err("can't write TX filter cut-off freq\n");
return;
}
/* TXDFE.SR is set to 3, TXDFE.RCUT is set to 4 */
ret = regmap_write(regmap, RG_RF09_TXDFE, 0x83);
if (ret < 0) {
pr_err("can't write TX sample rate\n");
return;
}
/* PAC.TXPWR is set to 0x1C */
ret = regmap_write(regmap, RG_RF09_PAC, 0x7C);
if (ret < 0) {
pr_err("can't write TX output power\n");
return;
}
/* Energy Measurement and AGC Configuration */
/* The reset values for the AGC configuration are already suitable for
* ODFM Option 1 */
ret = regmap_write(regmap, RG_RF09_EDD, 0x7A);
if (ret < 0) {
pr_err("can't write RX energy detection averaging duration\n");
return;
}
/* Modulation configuration */
/* PC.PT is set to 2 (MR-OFDM) */
ret = regmap_write(regmap, RG_BBC0_PC, 0x56);
if (ret < 0) {
pr_err("can't write PHY type\n");
return;
}
/* OFDMPHRTX.MCS is set to 3 (800kb/s) */
ret = regmap_write(regmap, RG_BBC0_OFDMPHRTX, 0x3);
if (ret < 0) {
pr_err("can't write bit rate\n");
return;
}
/* Initiate transceiver state change */
ret = regmap_write(regmap, RG_RF09_CMD, RF_TXPREP);
if (ret < 0) {
pr_err("can't write command\n");
return;
}
is_configured = true;
}
static void ping_process(struct timer_list *t)
{
int ret, i;
unsigned int val;
const char *description = NULL;
(void)ret;
(void)i;
(void)val;
(void)description;
(void)trx_state_descs;
if (!is_configured) {
pr_debug("configuring transceiver...");
at86rf215_configure();
} else {
/* pr_debug("transceiver is already configured"); */
}
#if 0
ret = regmap_read(regmap, RG_RF_PN, &val);
if (ret < 0) {
pr_err("can't read transceiver part number\n");
return;
}
for (i = 0; i < num_of_trx_ids; i++) {
if (trx_ids[i].part_number == val) {
description = trx_ids[i].description;
break;
}
}
if (description == NULL) {
pr_err("unknown transceiver part number 0x%x\n", val);
return;
}
ret = regmap_read(regmap, RG_RF_VN, &val);
if (ret < 0) {
pr_err("can't read transceiver version number\n");
return;
}
pr_debug("detected %sv%d transceiver\n", description, val);
ret = regmap_read(regmap, RG_RF09_STATE, &val);
if (ret < 0) {
pr_err("can't read transceiver's current state\n");
return;
}
pr_debug("transceiver's current state is %s\n", trx_state_descs[val]);
/* Initiate transceiver state change */
ret = regmap_write(regmap, RG_RF09_CMD, RF_TXPREP);
if (ret < 0) {
pr_err("can't write command\n");
return;
}
#endif
mod_timer(&ping_timer, jiffies + msecs_to_jiffies(1000));
}
static int at86rf215_probe(struct spi_device *spi)
{
unsigned int val;
unsigned long irqflags = 0;
(void)val;
(void)at86rf215_trx_write;
if (!spi->irq) {
dev_err(&spi->dev, "no IRQ number\n");
return -1;
}
dev_dbg(&spi->dev, "IRQ number is %d\n", spi->irq);
/* Retrieve RSTN pin number */
if (at86rf215_get_platform_data(spi, &rstn_pin_num) < 0 ||
!gpio_is_valid(rstn_pin_num)) {
return -1;
}
dev_dbg(&spi->dev, "RSTN pin number is %d\n", rstn_pin_num);
/* Configure as output, active low */
if (devm_gpio_request_one(&spi->dev, rstn_pin_num, GPIOF_OUT_INIT_HIGH,
"rstn") < 0) {
return -1;
}
/* TODO: reset transceiver by asserting RTSN low */
/* Initialize register map */
regmap = devm_regmap_init_spi(spi, &at86rf215_regmap_config);
if (IS_ERR(regmap)) {
int ret = PTR_ERR(regmap);
dev_err(&spi->dev, "can't alloc regmap 0x%x\n", ret);
devm_gpio_free(&spi->dev, rstn_pin_num);
return -1;
}
priv->spi = spi;
timer_setup(&ping_timer, ping_process, 0);
/* Read IRQ status regs to reset line */
regmap_read(regmap, RG_RF09_IRQS, &val);
regmap_read(regmap, RG_RF24_IRQS, &val);
ping_process(NULL);
irqflags = irq_get_trigger_type(spi->irq);
dev_dbg(&spi->dev, "irqflags 0x%lx\n", irqflags);
if (!irqflags) {
irqflags = IRQF_TRIGGER_HIGH;
}
if (devm_request_irq(&spi->dev, spi->irq, at86rf215_irq_handler,
IRQF_SHARED | irqflags,
dev_name(&spi->dev), &at86rf215_priv) < 0) {
dev_err(&spi->dev, "can't allocate IRQ\n");
devm_gpio_free(&spi->dev, rstn_pin_num);
return -1;
}
/* disable_irq(spi->irq); */
return 0;
}
static int at86rf215_remove(struct spi_device *spi)
{
if (del_timer(&ping_timer)) {
pr_debug("deactivated active timer\n");
}
devm_free_irq(&spi->dev, spi->irq, &at86rf215_priv);
devm_gpio_free(&spi->dev, rstn_pin_num);
return 0;
}
static const struct of_device_id at86rf215_of_match[] = {
{
.compatible = "atmel,at86rf233",
},
{},
};
MODULE_DEVICE_TABLE(of, at86rf215_of_match);
static const struct spi_device_id at86rf215_device_id[] = {
{
.name = "at86rf233",
},
{},
};
MODULE_DEVICE_TABLE(spi, at86rf215_device_id);
static struct spi_driver at86rf215_driver = {
.id_table = at86rf215_device_id,
.driver = { .of_match_table = of_match_ptr(at86rf215_of_match),
.name = "at86rf233" },
.probe = at86rf215_probe,
.remove = at86rf215_remove
};
module_spi_driver(at86rf215_driver);
MODULE_DESCRIPTION("Atmel AT86RF215 radio transceiver driver");
MODULE_LICENSE("GPL v2");

Wyświetl plik

@ -1,250 +0,0 @@
#define RG_RF09_IRQS (0x00)
#define RG_RF24_IRQS (0x01)
#define RG_BBC0_IRQS (0x02)
#define RG_BBC1_IRQS (0x03)
#define RG_RF_RST (0x05)
#define RG_RF_CFG (0x06)
#define RG_RF_CLKO (0x07)
#define RG_RF_BMDVC (0x08)
#define RG_RF_XOC (0x09)
#define RG_RF_IQIFC0 (0x0A)
#define RG_RF_IQIFC1 (0x0B)
#define RG_RF_IQIFC2 (0x0C)
#define RG_RF_PN (0x0D)
#define RG_RF_VN (0x0E)
#define RG_RF09_IRQM (0x100)
#define RG_RF09_AUXS (0x101)
#define RG_RF09_STATE (0x102)
#define RG_RF09_CMD (0x103)
#define RG_RF09_CS (0x104)
#define RG_RF09_CCF0L (0x105)
#define RG_RF09_CCF0H (0x106)
#define RG_RF09_CNL (0x107)
#define RG_RF09_CNM (0x108)
#define RG_RF09_RXBWC (0x109)
#define RG_RF09_RXDFE (0x10A)
#define RG_RF09_AGCC (0x10B)
#define RG_RF09_AGCS (0x10C)
#define RG_RF09_RSSI (0x10D)
#define RG_RF09_EDC (0x10E)
#define RG_RF09_EDD (0x10F)
#define RG_RF09_EDV (0x110)
#define RG_RF09_RNDV (0x111)
#define RG_RF09_TXCUTC (0x112)
#define RG_RF09_TXDFE (0x113)
#define RG_RF09_PAC (0x114)
#define RG_RF09_PADFE (0x116)
#define RG_RF09_PLL (0x121)
#define RG_RF09_PLLCF (0x122)
#define RG_RF09_TXCI (0x125)
#define RG_RF09_TXCQ (0x126)
#define RG_RF09_TXDACI (0x127)
#define RG_RF09_TXDACQ (0x128)
#define RG_RF24_IRQM (0x200)
#define RG_BBC0_FBRXS (0x2000)
#define RG_RF24_AUXS (0x201)
#define RG_RF24_STATE (0x202)
#define RG_RF24_CMD (0x203)
#define RG_RF24_CS (0x204)
#define RG_RF24_CCF0L (0x205)
#define RG_RF24_CCF0H (0x206)
#define RG_RF24_CNL (0x207)
#define RG_RF24_CNM (0x208)
#define RG_RF24_RXBWC (0x209)
#define RG_RF24_RXDFE (0x20A)
#define RG_RF24_AGCC (0x20B)
#define RG_RF24_AGCS (0x20C)
#define RG_RF24_RSSI (0x20D)
#define RG_RF24_EDC (0x20E)
#define RG_RF24_EDD (0x20F)
#define RG_RF24_EDV (0x210)
#define RG_RF24_RNDV (0x211)
#define RG_RF24_TXCUTC (0x212)
#define RG_RF24_TXDFE (0x213)
#define RG_RF24_PAC (0x214)
#define RG_RF24_PADFE (0x216)
#define RG_RF24_PLL (0x221)
#define RG_RF24_PLLCF (0x222)
#define RG_RF24_TXCI (0x225)
#define RG_RF24_TXCQ (0x226)
#define RG_RF24_TXDACI (0x227)
#define RG_RF24_TXDACQ (0x228)
#define RG_BBC0_FBRXE (0x27FE)
#define RG_BBC0_FBTXS (0x2800)
#define RG_BBC0_FBTXE (0x2FFE)
#define RG_BBC0_IRQM (0x300)
#define RG_BBC1_FBRXS (0x3000)
#define RG_BBC0_PC (0x301)
#define RG_BBC0_PS (0x302)
#define RG_BBC0_RXFLL (0x304)
#define RG_BBC0_RXFLH (0x305)
#define RG_BBC0_TXFLL (0x306)
#define RG_BBC0_TXFLH (0x307)
#define RG_BBC0_FBLL (0x308)
#define RG_BBC0_FBLH (0x309)
#define RG_BBC0_FBLIL (0x30A)
#define RG_BBC0_FBLIH (0x30B)
#define RG_BBC0_OFDMPHRTX (0x30C)
#define RG_BBC0_OFDMPHRRX (0x30D)
#define RG_BBC0_OFDMC (0x30E)
#define RG_BBC0_OFDMSW (0x30F)
#define RG_BBC0_OQPSKC0 (0x310)
#define RG_BBC0_OQPSKC1 (0x311)
#define RG_BBC0_OQPSKC2 (0x312)
#define RG_BBC0_OQPSKC3 (0x313)
#define RG_BBC0_OQPSKPHRTX (0x314)
#define RG_BBC0_OQPSKPHRRX (0x315)
#define RG_BBC0_AFC0 (0x320)
#define RG_BBC0_AFC1 (0x321)
#define RG_BBC0_AFFTM (0x322)
#define RG_BBC0_AFFVM (0x323)
#define RG_BBC0_AFS (0x324)
#define RG_BBC0_MACEA0 (0x325)
#define RG_BBC0_MACEA1 (0x326)
#define RG_BBC0_MACEA2 (0x327)
#define RG_BBC0_MACEA3 (0x328)
#define RG_BBC0_MACEA4 (0x329)
#define RG_BBC0_MACEA5 (0x32A)
#define RG_BBC0_MACEA6 (0x32B)
#define RG_BBC0_MACEA7 (0x32C)
#define RG_BBC0_MACPID0F0 (0x32D)
#define RG_BBC0_MACPID1F0 (0x32E)
#define RG_BBC0_MACSHA0F0 (0x32F)
#define RG_BBC0_MACSHA1F0 (0x330)
#define RG_BBC0_MACPID0F1 (0x331)
#define RG_BBC0_MACPID1F1 (0x332)
#define RG_BBC0_MACSHA0F1 (0x333)
#define RG_BBC0_MACSHA1F1 (0x334)
#define RG_BBC0_MACPID0F2 (0x335)
#define RG_BBC0_MACPID1F2 (0x336)
#define RG_BBC0_MACSHA0F2 (0x337)
#define RG_BBC0_MACSHA1F2 (0x338)
#define RG_BBC0_MACPID0F3 (0x339)
#define RG_BBC0_MACPID1F3 (0x33A)
#define RG_BBC0_MACSHA0F3 (0x33B)
#define RG_BBC0_MACSHA1F3 (0x33C)
#define RG_BBC0_AMCS (0x340)
#define RG_BBC0_AMEDT (0x341)
#define RG_BBC0_AMAACKPD (0x342)
#define RG_BBC0_AMAACKTL (0x343)
#define RG_BBC0_AMAACKTH (0x344)
#define RG_BBC0_FSKC0 (0x360)
#define RG_BBC0_FSKC1 (0x361)
#define RG_BBC0_FSKC2 (0x362)
#define RG_BBC0_FSKC3 (0x363)
#define RG_BBC0_FSKC4 (0x364)
#define RG_BBC0_FSKPLL (0x365)
#define RG_BBC0_FSKSFD0L (0x366)
#define RG_BBC0_FSKSFD0H (0x367)
#define RG_BBC0_FSKSFD1L (0x368)
#define RG_BBC0_FSKSFD1H (0x369)
#define RG_BBC0_FSKPHRTX (0x36A)
#define RG_BBC0_FSKPHRRX (0x36B)
#define RG_BBC0_FSKRPC (0x36C)
#define RG_BBC0_FSKRPCONT (0x36D)
#define RG_BBC0_FSKRPCOFFT (0x36E)
#define RG_BBC0_FSKRRXFLL (0x370)
#define RG_BBC0_FSKRRXFLH (0x371)
#define RG_BBC0_FSKDM (0x372)
#define RG_BBC0_FSKPE0 (0x373)
#define RG_BBC0_FSKPE1 (0x374)
#define RG_BBC0_FSKPE2 (0x375)
#define RG_BBC1_FBRXE (0x37FE)
#define RG_BBC0_PMUC (0x380)
#define RG_BBC1_FBTXS (0x3800)
#define RG_BBC0_PMUVAL (0x381)
#define RG_BBC0_PMUQF (0x382)
#define RG_BBC0_PMUI (0x383)
#define RG_BBC0_PMUQ (0x384)
#define RG_BBC0_CNTC (0x390)
#define RG_BBC0_CNT0 (0x391)
#define RG_BBC0_CNT1 (0x392)
#define RG_BBC0_CNT2 (0x393)
#define RG_BBC0_CNT3 (0x394)
#define RG_BBC1_FBTXE (0x3FFE)
#define RG_BBC1_IRQM (0x400)
#define RG_BBC1_PC (0x401)
#define RG_BBC1_PS (0x402)
#define RG_BBC1_RXFLL (0x404)
#define RG_BBC1_RXFLH (0x405)
#define RG_BBC1_TXFLL (0x406)
#define RG_BBC1_TXFLH (0x407)
#define RG_BBC1_FBLL (0x408)
#define RG_BBC1_FBLH (0x409)
#define RG_BBC1_FBLIL (0x40A)
#define RG_BBC1_FBLIH (0x40B)
#define RG_BBC1_OFDMPHRTX (0x40C)
#define RG_BBC1_OFDMPHRRX (0x40D)
#define RG_BBC1_OFDMC (0x40E)
#define RG_BBC1_OFDMSW (0x40F)
#define RG_BBC1_OQPSKC0 (0x410)
#define RG_BBC1_OQPSKC1 (0x411)
#define RG_BBC1_OQPSKC2 (0x412)
#define RG_BBC1_OQPSKC3 (0x413)
#define RG_BBC1_OQPSKPHRTX (0x414)
#define RG_BBC1_OQPSKPHRRX (0x415)
#define RG_BBC1_AFC0 (0x420)
#define RG_BBC1_AFC1 (0x421)
#define RG_BBC1_AFFTM (0x422)
#define RG_BBC1_AFFVM (0x423)
#define RG_BBC1_AFS (0x424)
#define RG_BBC1_MACEA0 (0x425)
#define RG_BBC1_MACEA1 (0x426)
#define RG_BBC1_MACEA2 (0x427)
#define RG_BBC1_MACEA3 (0x428)
#define RG_BBC1_MACEA4 (0x429)
#define RG_BBC1_MACEA5 (0x42A)
#define RG_BBC1_MACEA6 (0x42B)
#define RG_BBC1_MACEA7 (0x42C)
#define RG_BBC1_MACPID0F0 (0x42D)
#define RG_BBC1_MACPID1F0 (0x42E)
#define RG_BBC1_MACSHA0F0 (0x42F)
#define RG_BBC1_MACSHA1F0 (0x430)
#define RG_BBC1_MACPID0F1 (0x431)
#define RG_BBC1_MACPID1F1 (0x432)
#define RG_BBC1_MACSHA0F1 (0x433)
#define RG_BBC1_MACSHA1F1 (0x434)
#define RG_BBC1_MACPID0F2 (0x435)
#define RG_BBC1_MACPID1F2 (0x436)
#define RG_BBC1_MACSHA0F2 (0x437)
#define RG_BBC1_MACSHA1F2 (0x438)
#define RG_BBC1_MACPID0F3 (0x439)
#define RG_BBC1_MACPID1F3 (0x43A)
#define RG_BBC1_MACSHA0F3 (0x43B)
#define RG_BBC1_MACSHA1F3 (0x43C)
#define RG_BBC1_AMCS (0x440)
#define RG_BBC1_AMEDT (0x441)
#define RG_BBC1_AMAACKPD (0x442)
#define RG_BBC1_AMAACKTL (0x443)
#define RG_BBC1_AMAACKTH (0x444)
#define RG_BBC1_FSKC0 (0x460)
#define RG_BBC1_FSKC1 (0x461)
#define RG_BBC1_FSKC2 (0x462)
#define RG_BBC1_FSKC3 (0x463)
#define RG_BBC1_FSKC4 (0x464)
#define RG_BBC1_FSKPLL (0x465)
#define RG_BBC1_FSKSFD0L (0x466)
#define RG_BBC1_FSKSFD0H (0x467)
#define RG_BBC1_FSKSFD1L (0x468)
#define RG_BBC1_FSKSFD1H (0x469)
#define RG_BBC1_FSKPHRTX (0x46A)
#define RG_BBC1_FSKPHRRX (0x46B)
#define RG_BBC1_FSKRPC (0x46C)
#define RG_BBC1_FSKRPCONT (0x46D)
#define RG_BBC1_FSKRPCOFFT (0x46E)
#define RG_BBC1_FSKRRXFLL (0x470)
#define RG_BBC1_FSKRRXFLH (0x471)
#define RG_BBC1_FSKDM (0x472)
#define RG_BBC1_FSKPE0 (0x473)
#define RG_BBC1_FSKPE1 (0x474)
#define RG_BBC1_FSKPE2 (0x475)
#define RG_BBC1_PMUC (0x480)
#define RG_BBC1_PMUVAL (0x481)
#define RG_BBC1_PMUQF (0x482)
#define RG_BBC1_PMUI (0x483)
#define RG_BBC1_PMUQ (0x484)
#define RG_BBC1_CNTC (0x490)
#define RG_BBC1_CNT0 (0x491)
#define RG_BBC1_CNT1 (0x492)
#define RG_BBC1_CNT2 (0x493)
#define RG_BBC1_CNT3 (0x494)

Wyświetl plik

@ -1,2 +1,5 @@
# Overview
This Lattice ICE40 programming and management library was originally written by Eric Brombaugh (https://github.com/emeb) and used in https://github.com/emeb/icehat ("...RPi hat which comprises a Lattice iCE40 Ultra FPGA type ice5LP4K-SG48...").
This Lattice ICE40 programming and management library was originally written by Eric Brombaugh (https://github.com/emeb) and used in https://github.com/emeb/icehat ("...RPi hat which comprises a Lattice iCE40 Ultra FPGA type ice5LP4K-SG48...").
# License
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.

Wyświetl plik

@ -1,3 +1,9 @@
# RFFC5072
Raspberry Pi SPI drivers for Qorvo's RFFC5072 - synthesizer integrated RF mixers
This file was derived from code written by HackRF Team: (https://github.com/mossmann/hackrf)
1. 2012 Michael Ossmann
2. 2014 Jared Boone <jared@sharebrained.com>
and was modified by David Michaeli (cariboulabs.co@gmail.com) to adapt if for the CaribouLite project running on Linux OS (RPI).
The license for the modified code is licensed according to the original license accoring to: https://github.com/mossmann/hackrf/blob/master/COPYING

Wyświetl plik

@ -1,2 +1,6 @@
# Raspberry Pi SDR Driver
TODO
# License
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.