mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
8f9233f329
drivers/cc110x: add power off (sleep) functions
657 lines
28 KiB
C
657 lines
28 KiB
C
/*
|
|
* 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 time 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 Devices is powered down
|
|
*
|
|
* 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);
|
|
|
|
/**
|
|
* @brief Wakes the transceiver from SLEEP mode and enters RX mode
|
|
*
|
|
* @retval 0 Success
|
|
* @retval -EIO Communication with the transceiver failed
|
|
*/
|
|
int cc110x_wakeup(cc110x_t *dev);
|
|
|
|
/**
|
|
* @brief Sets the transceiver into SLEEP mode.
|
|
*
|
|
* Only @ref cc110x_wakeup can awake the device again.
|
|
*/
|
|
void cc110x_sleep(cc110x_t *dev);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* CC110X_H */
|
|
/** @} */
|