kopia lustrzana https://github.com/cariboulabs/cariboulite
cleaned up and added licenses
rodzic
c633ca456b
commit
1ff0fec2a0
|
@ -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>.
|
|
@ -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>.
|
|
@ -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>.
|
|
@ -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>.
|
|
@ -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>.
|
|
@ -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>.
|
|
@ -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>.
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
||||
/** @} */
|
|
@ -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-10—Channel 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-10—Channel 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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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";
|
||||
}
|
||||
}
|
|
@ -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 */
|
||||
/** @} */
|
Plik diff jest za duży
Load Diff
|
@ -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 */
|
||||
/** @} */
|
|
@ -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 68d—Total number of channels and first channel center frequencies for SUN PHYs
|
||||
* Table 68e—Center frequencies for the MR-O-QPSK PHY operating in the 868–870 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;
|
||||
}
|
|
@ -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 68d—Total 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 68d—Total 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 68d—Total 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 68d—Total 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);
|
||||
}
|
|
@ -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 */
|
Plik diff jest za duży
Load Diff
|
@ -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 */
|
||||
/** @} */
|
|
@ -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 */
|
||||
/** @} */
|
|
@ -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 */
|
||||
/** @} */
|
|
@ -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 */
|
||||
/** @} */
|
|
@ -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 */
|
||||
/** @} */
|
|
@ -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 */
|
||||
/** @} */
|
|
@ -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 */
|
||||
/** @} */
|
|
@ -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 */
|
||||
/** @} */
|
|
@ -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 */
|
||||
/** @} */
|
|
@ -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 */
|
||||
/** @} */
|
|
@ -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 */
|
||||
/** @} */
|
|
@ -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 */
|
|
@ -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
|
||||
...
|
||||
|
|
@ -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
|
||||
*~
|
||||
\#*#
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
```
|
|
@ -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");
|
|
@ -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
|
|
@ -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");
|
|
@ -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)
|
|
@ -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>.
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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>.
|
Ładowanie…
Reference in New Issue