/*
 * Copyright (C) 2013 INRIA
 *               2014 Freie Universität Berlin
 *               2015 Kaspar Schleiser <kaspar@schleiser.de>
 *               2018,2019 Otto-von-Guericke-Universität Magdeburg
 *
 * 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_cc110x CC1100/CC1100e/CC1101 Sub-GHz transceiver driver
 * @ingroup     drivers_netdev
 *
 * This module contains the driver for the TI CC1100/CC110e/CC1101 Sub-GHz
 * transceivers.
 *
 * @warning How the CC1100/CC1101 operate can be configured quite sophistically.
 *          This has the drawback, that configurations breaking laws and rules
 *          are complete possible. Please make sure that the configured output
 *          power, duty cycle, frequency range, etc. conform to the rules,
 *          standards and laws that apply in your use case.
 *
 *
 * Supported Hardware and how to obtain
 * ====================================
 *
 * This driver has been developed for the CC1101 and the older CC1100
 * transceiver and tested for both. However, it should work with the CC1100e
 * as well - but this has *NOT* been tested at all.
 *
 * It is suggested to go for the CC1101 when considering to buy one of the
 * supported transceivers. The easiest way is to obtain CC1101 break out boards
 * with a complete antenna circuit & antenna that can be connected via jumper
 * wires using an 8 pin DIP pin header. These are sold in various flavours start
 * from less than 2€ at quantity one at your favourite Far East store. Beware
 * that while the CC1101 chip can operate a various base frequencies, the
 * antenna circuit will only work for a single frequency band. Most break out
 * boards will operate at 433 MHz, which is license free in many countries (but
 * verify that for your country before buying!). EU citizens might prefer the
 * 868 MHz band over the 433 MHz, as more license free bandwidth is available
 * in the 868 MHz band in the EU. (But when deploying only a few dozens of
 * devices, the 433 MHz band is also fine for EU citizens.) US citizens should
 * go for the 900 MHz band (as 868 MHz is not license free in the USA), which
 * even contains more bandwidth than the 868 MHz band. (However, the 900 MHz
 * band has not been tested, as using it would be illegal in the EU.)
 *
 *
 * Packet Format
 * =============
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *  0                   1                   2                   3
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |     Preamble (4 bytes, handled by hardware, see MDMCFG1)      |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |     Sync Word (4 bytes, handled by hardware, see MDMCFG2)     |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * | Length Field  |  Destination  |    Source     |  Payload...
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  ... (see Length Field)         |  CRC (handled by hardware)    |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * | Field        | Description                                                |
 * |--------------|------------------------------------------------------------|
 * | Preamble     | 4 bytes, handled by hardware                               |
 * | Sync Word    | 4 bytes, handled by hardware                               |
 * | Length Field | Handled by software & hardware, length of payload + 2      |
 * | Destination  | Handled by software & hardware, destination MAC address    |
 * | Source       | Handled by software only, source MAC address               |
 * | Payload      | Handled by software only, the payload to send              |
 * | CRC          | 2 bytes, handled by hardware                               |
 *
 * The Length Field contains the length of the driver supplied data in bytes,
 * not counting the Length Field. Thus, it contains the length of the payload
 * plus the length of the Destination and Source address.
 *
 *
 * Layer-2 Addresses
 * -----------------
 *
 * The layer 2 addresses of the CC110x transceivers is a single byte long and
 * the special value `0x00` for the destination address is used in broadcast
 * transmissions. The transceiver is configured by this driver to ignore all
 * packets unless the destination address matches the address of the transceiver
 * or the destination address is `0x00`.
 *
 * Please note that the layer 2 address by default is derived from the CPU ID.
 * Due to the birthday paradox with only 20 devices the probability of a
 * collision is already bigger than 50%. Thus, manual address assignment is
 * supported by providing an implementation of @ref cc1xxx_eui_get.
 *
 *
 * Base Band, Data Rate, Channel Bandwidth and Channel Map Configuration
 * =====================================================================
 *
 * This driver allows to configure the base band, the data rate and the channel
 * bandwidth using an @ref cc110x_config_t data structure. Default
 * configurations are supplied and name using the following scheme:
 * `cc110x_config_<BASE-BAND>_<DATA-RATE>_<CHANNEL-BANDWIDTH>`. (E.g.
 * @ref cc110x_config_868mhz_250kbps_300khz is the default configuration used by
 * the MSB-A2 and the MSB-IoT boards.)
 *
 * Using the @ref cc110x_chanmap_t data structure the channel layout can be
 * defined. This map contains 8 entries, each defines the offset from the base
 * frequency defined in the @ref cc110x_config_t data structure for each
 * channel in steps of 50kHz. E.g. @ref cc110x_chanmap_868mhz_lora provides
 * the LoRa channels 10 to 17 in the 868MHz band. (The RIOT channel numbers
 * will always start from 0, and currently only up to eight channels are
 * supported. A special value of 255 as offset from the base frequency in the
 * channel map is used mark the channel as disabled. This can be used if less
 * than 8 non-overlapping channels are possible in the license free band.)
 *
 * Please note that the channel map (@ref cc110x_chanmap_t) must match the
 * base configuration (@ref cc110x_config_t), as the channel map is relative
 * to the configured base frequency. Also, the distance between the channels
 * in the channel map should match the channel bandwidth of the configuration,
 * as otherwise channels could overlap.
 *
 * Both configuration and matching channel map can be applied using
 * @ref cc110x_apply_config. Please consider this as a slow operation, as the
 * transceiver needs to be calibrated for each channel in the channel map.
 *
 *
 * Calibration of the Frequency Generator
 * ======================================
 *
 * The CC110x transceivers use a voltage controlled oscillator (VCO) and a
 * phase locked loop (PLL) for frequency generation. However, they need to be
 * calibrated to work correctly with the given supply voltage and the current
 * temperature. The driver will perform this calibration during startup, but
 * when the supply voltage or the temperature is not stable, a recalibration is
 * required whenever the supply voltage of temperature has changed too much since
 * the last calibration. This can be done by calling
 * @ref cc110x_full_calibration. It is left to the application developer to
 * perform this calibration when needed. During a test of about 2 hours of
 * operation in an in-door environment with a stable temperature the CC1101 has
 * worked reliable without any calibration at all (except for the automatic
 * calibration at start up). So there are use cases which do not require any
 * recalibration at all.
 *
 *
 * Troubleshooting
 * ===============
 *
 * The Driver Does Not Initialize Properly
 * ---------------------------------------
 * Set `ENABLE_DEBUG` in `cc110x_netdev.c` to `1` to get debug output, which
 * will likely tell you what is going wrong. There are basically two things
 * that can fail:
 *
 * Upon initialization the driver will read out the part number and version of
 * the transceiver. If those do not match the ones expected for the CC1100,
 * CC1100E, or the CC1101 the driver will refuse to initialize. If this fails,
 * most likely incorrect values are read out and the SPI communication does not
 * work correctly. However, future revisions of the CC110X transceivers might
 * be produced and might have different values for the part number or version.
 * If this should happen and they remain compatible with the driver, their
 * part number & revision needs to be added to the driver.
 *
 * After uploading the configuration, the driver will read back the
 * configuration to verify it. If the SPI communication is not reliable (e.g.
 * sporadically bits flip), this will fail from time to time. E.g. on the
 * MSB-IoT boards this is the case when the SPI interface operates at a clock of
 * 5MHz, but it becomes reliable when clocked at 1MHz.
 *
 * The Driver Initializes, but Communication Is Impossible
 * -------------------------------------------------------
 * If two transceivers are too close to each other and TX power is at maximum,
 * the signal is just too strong to be received correctly. Reducing TX power
 * or increasing the distance (about half a meter should be fine) will solve
 * this issue.
 *
 * While the chips can operate at any base frequency offered by the driver,
 * the circuit the chip is connected to and the antenna are build for a single
 * base band. Check if your configuration matches the frequency range the
 * board is build for. E.g. most break out boards operate at 433MHz, but there
 * are also boards for 868MHz.
 *
 * @{
 *
 * @file
 * @brief       Interface definition for the CC1100/CC1101 driver
 *
 * @author      Marian Buschsieweke <marian.buschsieweke@ovgu.de>
 * @author      Oliver Hahm <oliver.hahm@inria.fr>
 * @author      Fabian Nack <nack@inf.fu-berlin.de>
 * @author      Kaspar Schleiser <kaspar@schleiser.de>
 */

#ifndef CC110X_H
#define CC110X_H

#include <stdint.h>

#include "cc1xxx_common.h"
#include "mutex.h"
#include "net/gnrc/nettype.h"
#include "net/netdev.h"
#include "periph/adc.h"
#include "periph/gpio.h"
#include "periph/spi.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief   Length of a layer 2 frame
 *
 * This does not include the preamble, sync word, CRC field, and length field.
 */
#define CC110X_MAX_FRAME_SIZE           0xFF

/**
 * @brief   Maximum (layer 2) payload size supported by the driver
 */
#define CC110X_MAX_PAYLOAD_SIZE         (CC110X_MAX_FRAME_SIZE - CC1XXX_HEADER_SIZE)

/**
 * @brief   Maximum number of channels supported by the driver
 */
#define CC110X_MAX_CHANNELS             8

/**
 * @brief   Default protocol for data that is coming in
 */
#ifdef MODULE_GNRC_SIXLOWPAN
#define CC110X_DEFAULT_PROTOCOL         (GNRC_NETTYPE_SIXLOWPAN)
#else
#define CC110X_DEFAULT_PROTOCOL         (GNRC_NETTYPE_UNDEF)
#endif

/**
 * @defgroup drivers_cc110x_config CC1100/CC1100e/CC1101 Sub-GHz transceiver driver compile configuration
 * @ingroup config_drivers_netdev
 * @{
 */
/**
 * @brief The default channel to set up after initializing the device
 */
#ifndef CONFIG_CC110X_DEFAULT_CHANNEL
#define CONFIG_CC110X_DEFAULT_CHANNEL      (0U)
#endif
/** @} */

/**
 * @brief   The state of the CC1100/CC1101 transceiver
 *
 * The three least significant bytes match the representation of the matching
 * transceiver state given in the status byte of the hardware. See Table 32 on
 * page 31 in the data sheet for the possible states in the status byte.
 */
typedef enum {
    CC110X_STATE_IDLE               = 0x00,   /**< IDLE state */
    /**
     * @brief   Frame received, waiting for upper layer to retrieve it
     *
     * Transceiver is in IDLE state.
     */
    CC110X_STATE_FRAME_READY        = 0x08,
    /**
     * @brief   Frame received, waiting for upper layer to retrieve it
     *
     * Transceiver is in SLEEP state. There is no matching representation in the
     * status byte, as reading the status byte will power up the transceiver in
     * bring it in the IDLE state. Thus, we set the three least significant bits
     * to the IDLE state
     */
    CC110X_STATE_OFF                = 0x10,
    CC110X_STATE_RX_MODE            = 0x01,   /**< Listening for frames */
    /**
     * @brief   Receiving a frame just now
     *
     * Transceiver is in RX state.
     */
    CC110X_STATE_RECEIVING          = 0x09,
    CC110X_STATE_TX_MODE            = 0x02,   /**< Transmit mode */
    /**
     * @brief   Waiting for transceiver to complete outgoing transmission
     *
     * Transceiver is in TX state
     */
    CC110X_STATE_TX_COMPLETING      = 0x0A,
    CC110X_STATE_FSTXON             = 0x03,   /**< Fast TX ready */
    CC110X_STATE_CALIBRATE          = 0x04,   /**< Device is calibrating */
    CC110X_STATE_SETTLING           = 0x05,   /**< PLL is settling */
    CC110X_STATE_RXFIFO_OVERFLOW    = 0x06,   /**< RX FIFO overflown */
    CC110X_STATE_TXFIFO_UNDERFLOW   = 0x07,   /**< TX FIFO underflown */
} cc110x_state_t;

/**
 * @brief Enumeration over the possible TX power settings the driver offers
 */
typedef enum {
    CC110X_TX_POWER_MINUS_30_DBM,                   /**< -30 dBm */
    CC110X_TX_POWER_MINUS_20_DBM,                   /**< -20 dBm */
    CC110X_TX_POWER_MINUS_15_DBM,                   /**< -15 dBm */
    CC110X_TX_POWER_MINUS_10_DBM,                   /**< -10 dBm */
    CC110X_TX_POWER_0_DBM,                          /**< 0 dBm */
    CC110X_TX_POWER_PLUS_5_DBM,                     /**< 5 dBm */
    CC110X_TX_POWER_PLUS_7_DBM,                     /**< 7 dBm */
    CC110X_TX_POWER_PLUS_10_DBM,                    /**< 10 dBm */
    CC110X_TX_POWER_NUMOF,                          /**< Number of TX power options */
} cc110x_tx_power_t;

/**
 * @brief   Structure that holds the PATABLE, which allows to configure the
 *          8 available output power levels using a magic number for each level.
 *
 * See Section "24 Output Power Programming" on page 59ff in the data sheet.
 * The values suggested in Table 39 on page 60 in the data sheet are already
 * available by this driver, but will only be linked in (8 bytes of ROM size)
 * when they are referenced.
 *
 * @see cc110x_patable_433mhz
 * @see cc110x_patable_868mhz
 * @see cc110x_patable_915mhz
 */
typedef struct {
    uint8_t data[8]; /**< Magic number to store in the configuration register */
} cc110x_patable_t;


/**
 * @brief   Configuration of the transceiver to use
 *
 * @warning Two transceivers with different configurations will be unable
 *          to communicate.
 *
 * The data uploaded into configuration registers are stored in
 * @ref cc110x_conf. Most of them cannot be changed, as the driver relies on
 * their values. However, the base frequency, the symbol rate (which equals
 * the bit rate for the chosen modulation and error correction) and the
 * channel bandwidth can be configured using this data structure.
 *
 * Please note that while the CC1100/CC1101 chip is compatible with a huge
 * frequency range (300 MHz - 928 MHz), the complete circuit is optimized to
 * a narrow frequency band. So make sure the configured base frequency is within
 * that frequency band that is compatible with that circuit. (Most break out
 * board will operate at the 433 MHz band. In the EU the 868 MHz band would be
 * more interesting, but 433 MHz is license free as well. In the USA the 915 MHz
 * band is license free.
 *
 * Please verify that the driver is configured in a way that allows legal
 * operation according to rules and laws that apply for you.
 */
typedef struct {
    uint8_t base_freq[3]; /**< Base frequency to use */
    /**
     * @brief   FSCTRL1 configuration register value that affects the
     *          intermediate frequency of the transceiver to use
     * @note    The 4 most significant bits have to be 0.
     *
     * Assuming a 26 MHz crystal the IF is calculated as follows (in kHz):
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     * double intermediate_frequency = 26000 / 1024 * fsctrl1;
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */
    uint8_t fsctrl1;
    /**
     * @brief   MDMCFG4 configuration register value that affects channel filter
     *          bandwidth and the data rate
     *
     * See page 76 in the data sheet.
     *
     * Assuming a 26 MHz crystal the channel filter bandwidth is calculated
     * as follows (in kHz):
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     * uint8_t exponent = mdmcfg4 >> 6;
     * uint8_t mantissa = (mdmcfg4 >> 4) & 0x03;
     * double bandwidth = 26000.0 / (8 * (4 + mantissa) * (1L << exponent));
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */
    uint8_t mdmcfg4;
    /**
     * @brief   MDMCFG3 configuration register value that affects the data rate
     *
     * @see     cc110x_config_t::mdmcfg4
     *
     * See page 76 in the data sheet.
     *
     * Assuming a 26 MHz crystal the symbol rate of the transceiver is calculated
     * as follows (in kBaud):
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     * uint8_t exponent = mdmcfg4 & 0x0f;
     * int32_t mantissa = mdmcfg3;
     * double baudrate = (256 + mantissa) * 26000.0 / (1L << (28 - exponent));
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */
    uint8_t mdmcfg3;
    /**
     * @brief   DEVIANT configuration register that affects the amount by which
     *          the radio frequency is shifted in FSK/GFSK modulation
     *
     * @see cc110x_config_t::mdmcfg4
     *
     * See page 79 in the data sheet.
     *
     * In an ideal world the channel bandwidth would be twice the channel
     * deviation. In the real world the used channel bandwidth is higher.
     * Assuming a 26 MHz crystal and GFSK modulation (the driver will configure
     * the transceiver to use GFSK) the deviation
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     * uint8_t exponent = (deviatn >> 4) & 0x07;
     * int32_t mantissa = deviatn & 0x07;
     * double deviation = (8 + mantissa) * 26000.0 / (1L << (17 - exponent));
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     *
     * For reliable operation at high symbol rates, the deviation has to be
     * increased as well.
     */
    uint8_t deviatn;
} cc110x_config_t;

/**
 * @brief   Structure to hold mapping between virtual and physical channel numbers
 *
 * This driver will provide "virtual" channel numbers 0 to 7, which will be
 * translated to "physical" channel numbers before being send to the
 * transceiver. This is used to overcome the following limitations:
 *
 * - The transceiver does not support channel maps with varying distance between
 *   channels. However, e.g. the LoRa channels 10 - 16 in the 868 MHz band have
 *   a distance of 300 kHz, but channel 16 and 17 have a distance of 1 MHz.
 * - The transceiver does not supports channel distances higher than 405.46 kHz.
 *
 * This mapping overcomes both limitations be using 50kHz physical channel
 * spacing and use the map to translate to the correct physical channel. This
 * also allows to keep the same MDMCFG1 and MDMCFG0 configuration register
 * values for all channel layouts. Finally, different channel sets can be
 * used by different groups of IoT device in the same environment to limit
 * collisions between those groups - assuming that enough non-overlapping
 * channels are available.
 *
 * The "virtual" channel (the channel number presented to RIOT) will be used
 * as index in @ref cc110x_chanmap_t::map, the value in there will give the
 * corresponding "physical" channel number, or 255 if this virtual channel
 * number is not available.
 */
typedef struct {
    uint8_t map[CC110X_MAX_CHANNELS]; /**< "Physical" channel numbers */
} cc110x_chanmap_t;

/**
 * @brief   Structure holding all parameter for driver initialization
 */
typedef struct {
    const cc110x_patable_t *patable;  /**< Pointer to the PATABLE to use */
    /**
     * @brief   Pointer to the configuration of the base frequency, data rate
     *          and channel bandwidth; or `NULL` to keep the default.
     */
    const cc110x_config_t *config;
    const cc110x_chanmap_t *channels;   /**< Pointer to the default channel map */
    spi_t spi;                          /**< SPI bus connected to the device */
    spi_clk_t spi_clk;                  /**< SPI clock to use (max 6.5 MHz) */
    spi_cs_t cs;                        /**< GPIO pin connected to chip select */
    gpio_t gdo0;                        /**< GPIO pin connected to GDO0 */
    gpio_t gdo2;                        /**< GPIO pin connected to GDO2 */
} cc110x_params_t;

/**
 * @brief   Structure holding the calibration data of the frequency synthesizer
 */
typedef struct {
    /**
     * @brief   VCO capacitance calibration, which depends on the frequency and,
     *          thus, has to be stored for each channel
     */
    char fscal1[CC110X_MAX_CHANNELS];
    char fscal2;    /**< VCO current calibration, independent of channel */
    char fscal3;    /**< charge pump current calibration, independent of channel */
} cc110x_fs_calibration_t;

/**
 * @brief   Buffer to temporary store incoming/outgoing packet
 *
 * The CC1100/CC1101 transceiver's FIFO sadly is only 64 bytes in size. To
 * support frames bigger than that, chunks of the frame have to be
 * transferred between the MCU and the CC1100/CC1101 transceiver while the
 * frame is in transit.
 */
typedef struct __attribute__((packed)) {
    uint8_t len;            /**< Length of the frame in bytes */
    /**
     * @brief   The payload data of the frame
     */
    uint8_t data[CC110X_MAX_FRAME_SIZE];
    /**
     * @brief   Index of the next @ref cc110x_framebuf_t::data element to
     *          transfer
     *
     * In RX mode: Index of the next @ref cc110x_framebuf_t::data element to
     * store data read from the RX-FIFO into.
     *
     * In TX mode: Index of the next @ref cc110x_framebuf_t::data element to
     * write to the TX-FIFO.
     */
    uint8_t pos;
} cc110x_framebuf_t;

/**
 * @brief   Device descriptor for CC1100/CC1101 transceivers
 */
typedef struct {
    netdev_t netdev;                    /**< RIOT's interface to this driver */
    uint8_t addr;                       /**< Layer 2 address of this device */
    /* Keep above in sync with cc1xx_t members, as they must overlap! */
    cc110x_state_t state;               /**< State of the transceiver */
    cc110x_tx_power_t tx_power;         /**< TX power of the receiver */
    uint8_t channel;                    /**< Currently tuned (virtual) channel */
    /* Struct packing:  addr, state, tx_power and channel add up to 32 bit */
    const cc110x_chanmap_t *channels;   /**< Pointer to the channel map to use. */
    cc110x_params_t params;             /**< Configuration of the driver */
    cc110x_framebuf_t buf;              /**< Temporary frame buffer */
    /**
     * @brief   RSSI and LQI of the last received frame
     */
    cc1xxx_rx_info_t rx_info;
    /**
     * @brief   Frequency synthesizer calibration data
     */
    cc110x_fs_calibration_t fscal;
    /**
     * @brief   Use mutex to block during TX and unblock from ISR when ISR
     *          needs to be handled from thread-context
     *
     * Blocking during TX within the driver prevents the upper layers from
     * calling @ref netdev_driver_t::send while already transmitting a frame.
     */
    mutex_t isr_signal;
    uint8_t rssi_offset;                /**< dBm to subtract from raw RSSI data */
} cc110x_t;

/**
 * @brief   Setup the CC1100/CC1101 driver, but perform no initialization
 *
 * @ref netdev_driver_t::init can be used after this call to initialize the
 * transceiver.
 *
 * @param   dev     Device descriptor to use
 * @param   params  Parameter of the device to setup
 * @param   index   Index of @p params in a global parameter struct array.
 *                  If initialized manually, pass a unique identifier instead.
 *
 * @retval  0       Device successfully set up
 * @retval  -EINVAL @p dev or @p params is `NULL`, or @p params is invalid
 */
int cc110x_setup(cc110x_t *dev, const cc110x_params_t *params, uint8_t index);

/**
 * @brief Apply the given configuration and the given channel map and performs
 *        a recalibration
 *
 * @param   dev     Device descriptor of the transceiver
 * @param   conf    Configuration to apply or `NULL` to only change channel map
 * @param   chanmap Channel map to apply (must be compatible with @p conf)
 * @param   channel The channel to tune in after applying the config
 *
 * @retval  0       Success
 * @retval  -EINVAL Called with invalid argument
 * @retval  -EIO    Communication with the transceiver failed
 * @retval  -ERANGE Channel out of range or not supported by channel map
 *
 * @pre     The application developer checked in the documentation that the
 *          channel map in @p chanmap is compatible with the configuration in
 *          @p conf
 *
 * Because the configuration (potentially) changes the channel bandwidth, the
 * old channel map is rendered invalid. This API therefore asks for both to make
 * sure an application developer does not forget to update the channel map.
 * Because the old calibration data is also rendered invalid,
 * @ref cc110x_full_calibration is called to update it.
 */
int cc110x_apply_config(cc110x_t *dev, const cc110x_config_t *conf,
                        const cc110x_chanmap_t *chanmap, uint8_t channel);

/**
 * @brief   Perform a calibration of the frequency generator for each supported
 *          channel
 *
 * @param   dev     Device descriptor of the transceiver
 *
 * @retval  0       Success
 * @retval  -EINVAL Called with invalid argument
 * @retval  -EAGAIN Current state prevents deliberate calibration
 * @retval  -EIO    Communication with the transceiver failed
 *
 * Tunes in each supported channel and calibrates the transceiver. The
 * calibration data is stored so that @ref cc110x_set_channel can skip the
 * calibration phase and use the stored calibration data instead.
 */
int cc110x_full_calibration(cc110x_t *dev);

/**
 * @brief Hops to the specified channel
 *
 * @param   dev     Device descriptor of the transceiver
 * @param   channel Channel to hop to
 *
 * @retval  0       Success
 * @retval  -EINVAL Called with `NULL` as @p dev
 * @retval  -ERANGE Channel out of range or not supported by channel map
 * @retval  -EAGAIN Currently in a state that does not allow hopping, e.g.
 *                  sending/receiving a packet, calibrating or handling
 *                  transmission errors
 * @retval  -EIO    Communication with the transceiver failed
 *
 * This function implements the fact channel hopping approach outlined in
 * section 28.2 on page 64 in the data sheet, which skips the calibration phase
 * by storing the calibration date for each channel in the driver.
 */
int cc110x_set_channel(cc110x_t *dev, uint8_t channel);

/**
 * @brief   Set the TX power to the specified value
 *
 * @param   dev     Device descriptor of the transceiver
 * @param   power   Output power to apply
 *
 * @retval  0       Success
 * @retval  -EINVAL Called with `NULL` as @p dev
 * @retval  -ERANGE Called with an invalid value for @p power
 * @retval  -EAGAIN Changing the TX power is in the current state not possible
 * @retval  -EIO    Communication with the transceiver failed
 */
int cc110x_set_tx_power(cc110x_t *dev, cc110x_tx_power_t power);

#ifdef __cplusplus
}
#endif

#endif /* CC110X_H */
/** @} */
