/* * 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 */ #ifndef AT86RF215_H #define AT86RF215_H #include #include #include "board.h" #include "periph/spi.h" #include "periph/gpio.h" #include "net/netdev.h" #include "net/netdev/ieee802154.h" #include "net/gnrc/nettype.h" #include "xtimer.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 * @{ */ #if IS_ACTIVE(CONFIG_AT86RF215_DEFAULT_LEGACY_OQPSK) #define CONFIG_AT86RF215_DEFAULT_PHY_MODE (IEEE802154_PHY_OQPSK) #elif IS_ACTIVE(CONFIG_AT86RF215_DEFAULT_MR_OQPSK) #define CONFIG_AT86RF215_DEFAULT_PHY_MODE (IEEE802154_PHY_MR_OQPSK) #elif IS_ACTIVE(CONFIG_AT86RF215_DEFAULT_MR_OFDM) #define CONFIG_AT86RF215_DEFAULT_PHY_MODE (IEEE802154_PHY_MR_OFDM) #endif #ifndef CONFIG_AT86RF215_DEFAULT_PHY_MODE #define CONFIG_AT86RF215_DEFAULT_PHY_MODE (IEEE802154_PHY_OQPSK) #endif /** @} */ /** * @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 * @{ */ #if IS_ACTIVE(CONFIG_AT86RF215_DEFAULT_MR_OQPSK_CHIPS_100) #define CONFIG_AT86RF215_DEFAULT_MR_OQPSK_CHIPS (AT86RF215_FCHIP_100) #elif IS_ACTIVE(CONFIG_AT86RF215_DEFAULT_MR_OQPSK_CHIPS_200) #define CONFIG_AT86RF215_DEFAULT_MR_OQPSK_CHIPS (AT86RF215_FCHIP_200) #elif IS_ACTIVE(CONFIG_AT86RF215_DEFAULT_MR_OQPSK_CHIPS_1000) #define CONFIG_AT86RF215_DEFAULT_MR_OQPSK_CHIPS (AT86RF215_FCHIP_1000) #elif IS_ACTIVE(CONFIG_AT86RF215_DEFAULT_MR_OQPSK_CHIPS_2000) #define CONFIG_AT86RF215_DEFAULT_MR_OQPSK_CHIPS (AT86RF215_FCHIP_2000) #endif #ifndef CONFIG_AT86RF215_DEFAULT_MR_OQPSK_CHIPS #define CONFIG_AT86RF215_DEFAULT_MR_OQPSK_CHIPS (AT86RF215_FCHIP_1000) #endif /** @} */ /** * @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 { spi_t spi; /**< SPI bus the device is connected to */ spi_clk_t spi_clk; /**< SPI clock speed to use */ spi_cs_t cs_pin; /**< GPIO pin connected to chip select */ gpio_t int_pin; /**< GPIO pin connected to the interrupt pin */ gpio_t 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 { netdev_ieee802154_t netdev; /**< netdev parent struct */ /* 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 */ xtimer_t timer; /**< timer for ACK & CSMA timeout */ 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 */ #ifdef MODULE_NETDEV_IEEE802154_MR_FSK uint8_t fsk_pl; /**< FSK Preamble Length */ #endif 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 */ /** @} */