Driver for TI's CC1200 radio ICs. Forget hardcoded register settings -- this driver calculates everything from scratch!

Dependents:   CC1200-MorseEncoder CC1200-Examples

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CC1200.h Source File

CC1200.h

00001 //
00002 // Created by jamie on 3/27/2020.
00003 //
00004 
00005 #ifndef LIGHTSPEEDRANGEFINDER_CC1200_H
00006 #define LIGHTSPEEDRANGEFINDER_CC1200_H
00007 
00008 #include <mbed.h>
00009 #include <Stream.h>
00010 
00011 #include <cstdint>
00012 
00013 /**
00014  *  Base driver for the CC1200 radio communications IC.
00015  *  This class provides basic functions and register level IO with the chip.
00016  */
00017 class CC1200
00018 {
00019     // connections to chip
00020     SPI spi;
00021     DigitalOut rst;
00022 
00023     // Output to print debug messages to
00024     Stream * debugStream;
00025 
00026 public:
00027 
00028     // register definitions
00029     enum class Register : uint8_t
00030     {
00031         IOCFG3 = 0x00,
00032         IOCFG2 = 0x01,
00033         IOCFG1 = 0x02,
00034         IOCFG0 = 0x03,
00035         SYNC3 = 0x4,
00036         SYNC2 = 0x5,
00037         SYNC1 = 0x6,
00038         SYNC0 = 0x7,
00039         SYNC_CFG1 = 0x8,
00040         SYNC_CFG0 = 0x9,
00041         DEVIATION_M = 0xA,
00042         MODCFG_DEV_E = 0xB,
00043         DCFILT_CFG  = 0xC,
00044         PREAMBLE_CFG1 = 0xD,
00045         PREAMBLE_CFG0 = 0xE,
00046         IQIC = 0xF,
00047         CHAN_BW = 0x10,
00048         MDMCFG1 = 0x11,
00049         MDMCFG0 = 0x12,
00050         SYMBOL_RATE2 = 0x13,
00051         SYMBOL_RATE1 = 0x14,
00052         SYMBOL_RATE0 = 0x15,
00053         AGC_REF = 0x16,
00054         AGC_CS_THR = 0x17,
00055         AGC_GAIN_ADJUST = 0x18,
00056         AGC_CFG3 = 0x19,
00057         AGC_CFG2 = 0x1A,
00058         AGC_CFG1 = 0x1B,
00059         AGC_CFG0 = 0x1C,
00060         FIFO_CFG = 0x1D,
00061         DEV_ADDR = 0x1E,
00062         SETTLING_CFG = 0x1F,
00063         FS_CFG = 0x20,
00064         WOR_CFG1 = 0x21,
00065         WOR_CFG0 = 0x22,
00066         WOR_EVENT0_MSB = 0x23,
00067         WOR_EVENT0_LSB = 0x24,
00068         RXDCM_TIME = 0x25,
00069         PKT_CFG2 = 0x26,
00070         PKT_CFG1 = 0x27,
00071         PKT_CFG0 = 0x28,
00072         RFEND_CFG1 = 0x29,
00073         RFEND_CFG0 = 0x2A,
00074         PA_CFG1 = 0x2B,
00075         PA_CFG0 = 0x2C,
00076         ASK_CFG = 0x2D,
00077         PKT_LEN = 0x2E
00078     };
00079 
00080     // extended register definitions
00081     enum class ExtRegister : uint8_t
00082     {
00083         IF_MIX_CFG = 0x0,
00084         FREQOFF_CFG = 0x1,
00085         TOC_CFG = 0x2,
00086         //...
00087         MDMCFG2 = 0x5,
00088         //...
00089         FREQOFF1 = 0xA,
00090         FREQOFF2 = 0xB,
00091         FREQ2 = 0xC,
00092         FREQ1 = 0xD,
00093         FREQ0 = 0xE,
00094         IF_ADC2 = 0xF,
00095         IF_ADC1 = 0x10,
00096         IF_ADC0 = 0x11,
00097         FS_DIG1 = 0x12,
00098         FS_DIG0 = 0x13,
00099         //...
00100         FS_CAL1 = 0x16,
00101         FS_CAL0 = 0x17,
00102         FS_CHP = 0x18,
00103         FS_DIVTWO = 0x19,
00104         FS_DSM1 = 0x1A,
00105         FS_DSM0 = 0x1B,
00106         FS_DVC1 = 0x1C,
00107         FS_DVC0 = 0x1D,
00108         FS_LBI = 0x1E,
00109         FS_PFD = 0x1F,
00110         FS_PRE = 0x20,
00111         FS_REG_DIV_CML = 0x21,
00112         FS_SPARE = 0x22,
00113         FS_VCO4 = 0x23,
00114         FS_VCO3 = 0x24,
00115         FS_VCO2 = 0x25,
00116         FS_VCO1 = 0x26,
00117         FS_VCO0 = 0x27,
00118         //...
00119         IFAMP = 0x2F,
00120         //..
00121         XOSC5 = 0x32,
00122         XOSC4 = 0x33,
00123         XOSC3 = 0x34,
00124         XOSC2 = 0x35,
00125         XOSC1 = 0x36,
00126         XOSC0 = 0x37,
00127         //...
00128         RSSI1 = 0x71,
00129         RSSI0 = 0x72,
00130         MARCSTATE = 0x73,
00131         LQI_VAL = 0x74,
00132         //...
00133         FREQOFF_EST1 = 0x77,
00134         FREQOFF_EST2 = 0x78,
00135         //...
00136         FSCAL_CTRL = 0x8D,
00137         PARTNUMBER = 0x8F,
00138         PARTVERSION = 0x90,
00139         //...
00140         RXFIRST = 0xD2,
00141         TXFIRST = 0xD3,
00142         RXLAST = 0xD4,
00143         TXLAST = 0xD5,
00144         NUM_TXBYTES = 0xD6,
00145         NUM_RXBYTES = 0xD7,
00146         //...
00147         RXFIFO_PRE_BUF = 0xDA
00148     };
00149 
00150     // Command strobe definitions.  See user guide section 3.2.2
00151     enum class Command : uint8_t
00152     {
00153         SOFT_RESET = 0x30,
00154         FAST_TX_ON = 0x31,
00155         OSC_OFF = 0x32,
00156         CAL_FREQ_SYNTH = 0x33,
00157         RX = 0x34,
00158         TX = 0x35,
00159         IDLE = 0x36,
00160         AUTO_FREQ_COMP = 0x37,
00161         WAKE_ON_RADIO = 0x38,
00162         SLEEP = 0x39,
00163         FLUSH_RX = 0x3A,
00164         FLUSH_TX = 0x3B,
00165         WOR_RESET = 0x3C,
00166         NOP = 0x3D
00167     };
00168 
00169     // State of the radio chip.  See user guide Figure 2.
00170     enum class State : uint8_t
00171     {
00172         IDLE = 0x0,
00173         RX = 0x1,
00174         TX = 0x2,
00175         FAST_ON = 0x3,
00176         CALIBRATE = 0x4,
00177         SETTLING = 0x5,
00178         RX_FIFO_ERROR = 0x6,
00179         TX_FIFO_ERROR = 0x7
00180     };
00181 
00182 private:
00183     // chip data variables
00184     bool chipReady = false;
00185     State state = State::IDLE;
00186     bool isCC1201;
00187 
00188     // current state variables
00189 
00190     // current symbol rate of the radio
00191     float symbolRateSps = 0;
00192 
00193     // current RX filter params
00194     uint8_t adcCicDecimation = 0;
00195     float currentRXFilterBW = 0;
00196 
00197     // current RF params
00198     float radioFreqHz;
00199 
00200 
00201 public:
00202 
00203     /**
00204      * Construct a CC1200 radio driver from the given set of pins.
00205      *
00206      * @param misoPin
00207      * @param mosiPin
00208      * @param sclkPin
00209      * @param csPin
00210      * @param rstPin
00211      * @param _debugStream Stream to print error/debug information on.
00212      * @param isCC1201 True if the chip is a CC1201, false if it is a CC1200.  The CC1201 is a cheaper option that lacks low bandwidth settings but is otherwise identical.
00213      */
00214     CC1200(PinName mosiPin, PinName misoPin, PinName sclkPin, PinName csPin, PinName rstPin, Stream * _debugStream, bool _isCC1201 = false);
00215 
00216     /**
00217      * Reset the chip and attempt to connect to it.
00218      * Returns whether the chip could be contacted.
00219      * @return
00220      */
00221     bool begin();
00222 
00223     /**
00224      * Get the radio's most recently known state.
00225      * State is updated whenever registers are read or commands are sent, or when you call updateState.
00226      * @return
00227      */
00228     State getState() { return state; }
00229 
00230     // Data tx & rx functions
00231     // ------------------------------------------------------------------------------
00232 
00233     /**
00234      * Get the number of bytes currently in the TX FIFO
00235      * @return
00236      */
00237     size_t getTXFIFOLen();
00238 
00239     /**
00240      * Get the number of bytes currently in the RX FIFO
00241      * @return
00242      */
00243     size_t getRXFIFOLen();
00244 
00245     /**
00246      * Enqueue a packet to be sent over the radio.  It will be sent the next time the radio is in
00247      * transmit state.
00248      *
00249      * In variable length mode, the length of a packet is variable, from 1 byte to 127 bytes.
00250      * The length will be transmitted along with the packet data.
00251      *
00252      * In fixed length mode, the length should be the fixed packet length.
00253      *
00254      * The function is not for use with infinite-length mode, use writeStream() instead.
00255      *
00256      * Also reads the radio's state.
00257      *
00258      * @param data
00259      * @param len
00260      *
00261      * @return Whether the packet was enqueued.  Could return false if there was not enough FIFO
00262      * space to enqueue the packet, or if the packet is too long.
00263      */
00264     bool enqueuePacket(char const * data, size_t len);
00265 
00266     /**
00267      * Check whether there is at least one complete packet in the RX FIFO.
00268      * In infinite length mode, this returns true if any data is present at all.
00269      * NOTE: An alternate way to do this using hardware is to configure one
00270      * of the CC1200's GPIOs as PKT_SYNC_RXTX, then set a falling edge interrupt to receive a packet.
00271      * @return
00272      */
00273     bool hasReceivedPacket();
00274 
00275     /**
00276      * Receive a packet from the radio.  Only packets that pass CRC check are received into the FIFO;
00277      * those which do not pass checksum will be discarded.
00278      *
00279      * This function assumes that there is a packet in the buffer.  You should only call it after
00280      * hasReceivedPacket() is true or a PKT_SYNC_RXTX pulse is received.  If there is not a packet
00281      * in the FIFO, *undefined behavior* can occur.  An arbitrary amount of data will be read from
00282      * the FIFO and garbage may be returned.
00283      *
00284      * The function is not for use with infinite-length mode, use readStream() instead.
00285      *
00286      * NOTE: A null terminator is NOT added unless it was present in the transmitted data.
00287      * Be careful when treating the returned data as a string!
00288      *
00289      * @param buffer Buffer to store received bytes in.
00290      * @param bufferLen Length of the buffer supplied.  If the packet is longer than this buffer, then
00291      *  the full packet will be read from the FIFO but only a buffer's worth will be stored.
00292      * @return Number of bytes actually received.
00293      */
00294     size_t receivePacket(char * buffer, size_t bufferLen);
00295 
00296     // Infinite length tx & rx functions
00297     // ------------------------------------------------------------------------------
00298 
00299     /*
00300      * How to use infinite length from the TX side:
00301      * 1. Place up to 128 bytes of data in the TX FIFO for transmission using writeStream().
00302      * 2. Enable TX mode using startTX()
00303      * 3. Keep streaming in data using writeStream() writeStreamBlocking() or at least as fast as it is transmitted.
00304      * 4. Disable TX mode when done using idle().
00305      *
00306      * Take care that the TX fifo never runs completely out of data, or the chip will go into TX FIFO ERROR state.
00307      */
00308 
00309     /*
00310      * How to use infinite length from the RX side:
00311      * 1. Enable RX mode using startRX().  I'm pretty sure that if sync words are enabled, you must start RX before the transmitter starts transmitting.
00312      * 2. Wait for data to arrive using hasReceivedPacket().
00313      * 3. Start streaming out data using readStream() or readStreamBlocking().
00314      * 4. Disable RX mode when done using idle().
00315      *
00316      * Take care that the RX fifo doesn't become full, or the chip will go into RX FIFO ERROR state.
00317      */
00318 
00319     /**
00320      * Write a stream of data to the chip.  This function is only for use in infinite-length mode.
00321      * As many bytes from the given buffer will be written as can fit in the chip's FIFO.
00322      * If the FIFO is full, this function does nothing.
00323      *
00324      * @param buffer
00325      * @param count
00326      * @return Number of bytes written.
00327      */
00328     size_t writeStream(const char* buffer, size_t count);
00329 
00330     /**
00331      * Write a stream of data to the chip.  This function is only for use in infinite-length mode.
00332      * Will block until all bytes in the given buffer have been written to the TX FIFO, or an error has been
00333      * detected (the radio switches to any state other than TX).
00334      *
00335      * @param buffer
00336      * @param count
00337      * @return True if successful, false if there was an error.
00338      */
00339     bool writeStreamBlocking(const char* buffer, size_t count);
00340 
00341     /**
00342      * Read up to maxLen bytes into buffer.
00343      * @param buffer
00344      * @param maxLen
00345      * @return How many bytes were actually read.  0 if the RX FIFO was empty.
00346      */
00347     size_t readStream(char* buffer, size_t maxLen);
00348 
00349     /**
00350      * Read a stream of data from the chip.  This function is only for use in infinite-length mode.
00351      * Will block until the buffer was filled, an error has been
00352      * detected (the radio switches to any state other than RX), or the timeout expires.
00353      *
00354      * If false is returned, some data may have been written to the buffer, and the rest will not have been modified.
00355      *
00356      * Note: if using a zero timeout, this function could cause a hang if the transmitter stops transmitting.
00357      *
00358      * @param buffer
00359      * @param count
00360      * @param timeout Timeout, or 0us to disable timeout.
00361      * @return True iff the buffer was completely filled.
00362      */
00363     bool readStreamBlocking(char* buffer, size_t count, std::chrono::microseconds timeout=0us);
00364 
00365     // State transition configuration
00366     // ------------------------------------------------------------------------------
00367 
00368     /**
00369      * Set what state the radio will enter when a packet is received.
00370      * @param goodPacket State when a good (CRC pass) packet is received.
00371      * Accepts State::TX, State::IDLE, State::FAST_TX_ON, and State::RX.
00372      * @param badPacket State when a bad (CRC fail) packet is received.
00373      * Accepts State::RX and State::IDLE
00374      */
00375     void setOnReceiveState(State goodPacket, State badPacket);
00376 
00377     /**
00378      * Set what state the radio will enter when a packet is sent.
00379      * @param txState State when a packet is transmitted.
00380      * Accepts State::TX, State::IDLE, State::FAST_TX_ON, and State::RX.
00381      */
00382     void setOnTransmitState(State txState);
00383 
00384     enum class FSCalMode : uint8_t
00385     {
00386         NONE = 0b00, // never calibrate the FS automatically
00387         FROM_IDLE = 0b01, // calibrate the FS when going from idle to TX, RX, or fast TX on
00388         TO_IDLE = 0b10, // calibrate the FS when going from TX, RX, or fast TX on to idle
00389         TO_IDLE_1_4 = 0b11 // calibrate the FS 1/4 of the time when going from TX, RX, or fast TX on to idle
00390     };
00391 
00392     /**
00393      * Set when the radio calibrates its frequency synthesizer.
00394      *
00395      * Per https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz/f/156/t/375189
00396      * it looks like the FS can drift with changes in supply voltage and/or temperature,
00397      * so it is good to continually calibrate it in case these change.
00398      */
00399     void setFSCalMode(FSCalMode mode);
00400 
00401     // GPIO configuration
00402     // ------------------------------------------------------------------------------
00403 
00404     /**
00405      * Enum for all possible GPIO modes.
00406      * Note: Some modes do different things depending on which GPIOs they're assigned to.
00407      * Duplicate enum values have been intentionally defined for this.
00408      */
00409     enum class GPIOMode : uint8_t
00410     {
00411         RXFIFO_THR_PKT = 1,
00412         PKT_SYNC_RXTX = 6,
00413         RSSI_UPDATE = 14, // GPIO3 and GPIO2
00414         AGC_HOLD = 14, // GPIO1
00415         AGC_UPDATE = 14, // GPIO0
00416         SYNC_EVENT = 41, // GPIO2
00417         HIGHZ = 48,
00418         HW0 = 51
00419     };
00420 
00421     /**
00422      * Configure a CC1200 GPIO pin.
00423      * @param gpioNumber Pin number, from 0-3.
00424      * @param mode Mode to set the pin to.
00425      * @param outputInvert Whether to invert the output of the pin.
00426      */
00427     void configureGPIO(uint8_t gpioNumber, GPIOMode mode, bool outputInvert = false);
00428 
00429     // RF configuration
00430     // ------------------------------------------------------------------------------
00431 
00432     /**
00433      * Set up the radio for FIFO mode.
00434      */
00435     void configureFIFOMode();
00436 
00437     enum class PacketMode  : uint8_t
00438     {
00439         /// Use infinite length transmissions (streaming mode).
00440         INFINITE_LENGTH = 0b10,
00441         /// Use fixed length packets.
00442         VARIABLE_LENGTH = 0b1,
00443         /// Use variable length packets, the length is encoded in the first byte of the packet.
00444         FIXED_LENGTH = 0b0
00445     };
00446 
00447     /**
00448      * Set the packet mode that the system will use.
00449      * @param mode
00450      * @param appendStatus Have the radio append a status byte to each packet received.  This takes up
00451      * 2 bytes per packet in the RX FIFO, but provides status information about each packet.
00452      */
00453     void setPacketMode(PacketMode  mode, bool appendStatus = false);
00454 
00455     /**
00456      * Set the packet length when in fixed length packet mode.
00457      * The bit length parameter can be used to send only the x most significant bits of the final byte.
00458      * For example, if your packets are 20 bits long, you should set length to 2 bytes and bitLength to
00459      * 4 bytes, so that 2 complete bytes + 4 extra bits are transmitted.  Buffers used for sending and receiving packets
00460      * should then be 3 bytes long.
00461      *
00462      * When appendStatus is disabled, the max length is 256 bytes.  When it is enabled, the max length is 254 bytes.
00463      * @param length
00464      */
00465     void setPacketLength(uint16_t length, uint8_t bitLength = 0);
00466 
00467 private:
00468     // current packet mode
00469     PacketMode  _packetMode;
00470 
00471     // current packet length when in fixed length packet mode
00472     uint16_t _packetTotalLength = 0; // length in bytes including final partial byte
00473     uint16_t _packetByteLength = 0; // length in whole bytes
00474     uint8_t _packetBitLength = 0; // extra bit length at end
00475 
00476     // Whether the two status bytes are included in each received packet
00477     bool appendStatusEnabled = true;
00478 
00479 public:
00480 
00481     /**
00482      * Set whether the CRC check is enabled.  This driver enables it by default.
00483      * Enabling CRC will cause a 16 bit checksum to be transmitted along with the packet.
00484      * It will be automatically checked by the receiving CC1200, and the packet will be discarded if the CRC
00485      * doesn't match.
00486      *
00487      * NOTE: it is not recommended to disable the CRC when using variable length mode.
00488      * If the length byte is corrupted and the CRC doesn't check this, then the driver could read
00489      * too little or too much from the chip's FIFO and cause the chip to enter the FIFO underflow state.
00490      * @param enabled
00491      */
00492     void setCRCEnabled(bool enabled);
00493 
00494     enum class ModFormat : uint8_t
00495     {
00496         FSK_2 = 0x0,
00497         GFSK_2 = 0x1,
00498         ASK = 0x3,
00499         FSK_4 = 0x4,
00500         GFSK_4 = 0x5
00501     };
00502 
00503     /**
00504      * Set the modulation format of the radio.
00505      * @param format
00506      */
00507     void setModulationFormat(ModFormat format);
00508 
00509     /**
00510      * Set the frequency deviation from the center frequency in Hz.
00511      * See user guide section 5.2.1 for details, and cc1200 datasheet section 4.10.2 for example values.
00512      */
00513     void setFSKDeviation(float deviation);
00514 
00515     /**
00516      * Set the RF symbol rate in Hz.  If this radio is to be used in receive mode you must call
00517      * setRXFilterBandwidth() after calling this function.
00518      * @param symbolRateHz
00519      */
00520     void setSymbolRate(float symbolRateHz);
00521 
00522     /**
00523      * Set the approximate output power in dBm.
00524      * Must be between -16dBm and +14dBm.
00525      * @param outPower
00526      */
00527     void setOutputPower(float outPower);
00528 
00529     // min power to use to turn the radio completely off
00530     const static float ASK_MIN_POWER_OFF;
00531 
00532     /**
00533      * Set the high and low output powers when transmitting in ASK mode.
00534      * Overrides the setOutputPower() power setting.
00535      * @param maxPower High output power.  Must be between -16dBm and +14dBm.
00536      * @param minPower Low output power.  Must be between maxPower and -17.5dBm.  -17.5dBm gives completely off,
00537      *     so OOK modulation instead of ASK.
00538      */
00539     void setASKPowers(float maxPower, float minPower);
00540 
00541     // Radio band for the chip to operate on.
00542     // See user guide description for FS_CFG register.
00543     enum class Band : uint8_t
00544     {
00545         BAND_820_960MHz = 0x2,
00546         BAND_410_480MHz = 0x4,
00547         BAND_273_320MHz = 0x6,
00548         BAND_205_240MHz = 0x8,
00549         BAND_164_192MHz = 0xA,
00550         BAND_136_160MHz = 0xB
00551     };
00552 
00553     /**
00554      * Set the radio band and specific frequency.  See user guide section 9.12 for details.
00555      * Note: Frequency offsets are not currently implemented, so the frequency can't be
00556      * set at the finest resolution.  However, the resolution should be fine for most applications.
00557      * (at 900MHz this function has a resolution of 152.5Hz)
00558      * @param band
00559      * @param frequencyHz
00560      */
00561     void setRadioFrequency(Band band, float frequencyHz);
00562 
00563     /**
00564      * Set the the RX filter bandwidth.  You must call this AFTER setting the symbol rate.
00565      * See user guide section 6.1 for details.
00566      *
00567      * NOTE: The symbol rate and the RX filter bandwidth must be compatible with each other.
00568      * See the user guide for details.
00569      *
00570      * A number of different registers must be configured in order to properly configure the radio for a given bandwidth.
00571      * This call currently sets the following register fields:
00572      * - CHAN_BW.ADC_CIC_DECFACT
00573      * - CHAN_BW.BB_CIC_DECFACT
00574      * - MDMCFG1.DVGA_GAIN
00575      * - MDMCFG0.DATA_FILTER_EN
00576      * - SYNC_CFG0.RX_CONFIG_LIMITATION
00577      *
00578      * @param bandwidthHz the bandwidth in Hz
00579      * @param preferHigherCICDec If there are multiple register value choices, prefer the one with higher CIC decimation
00580      * and lower BB decimation.  This is the recommendation of the datasheet but it actually causes transmission to fail in some cases.
00581      */
00582     void setRXFilterBandwidth(float bandwidthHz, bool preferHigherCICDec = true);
00583 
00584     /**
00585      * Get the ADC CIC decimation that was calculated by the most recent setRXFilterBandwidth() call.
00586      * This is used for certain other calculations such as the DC offset.
00587      * @return
00588      */
00589     uint8_t getADCCICDecimation() { return adcCicDecimation; }
00590 
00591     /**
00592      * Configure the radio's automatic DC offset removal algorithm as enabled.
00593      * DC offset correction must be enabled when using zero IF mode, and in my testing
00594      * it seems to be important when staying in TX mode for a long time at
00595      * higher sample rates.
00596      *
00597      * See the datasheet register description for DCFILT_CFG for explanations of what these values do.
00598      * Maybe you'll actually be able to make some sense out of what it says... I sure couldn't.
00599      *
00600      * @param enableAutoFilter Whether automatic filtering is enabled.
00601      * @param settlingCfg Settling time configuration bits.
00602      * @param cutoffCfg Cutoff frequency configuration bits.
00603      */
00604     void configureDCFilter(bool enableAutoFilter, uint8_t settlingCfg, uint8_t cutoffCfg);
00605 
00606     /**
00607      * Possible intermediate frequency values.
00608      * For right now it seems like you have to get these from SmartRF.
00609      * See the user guide section on IF_MIX_CFG.CMIX_CFG for details.
00610      */
00611     enum class IFCfg : uint8_t
00612     {
00613         ZERO = 0, // Zero IF.  From what I can find, this means samples are taken at the radio frequency.
00614         NEGATIVE_DIV_4 = 0b001,
00615         NEGATIVE_DIV_6 = 0b010,
00616         NEGATIVE_DIV_8 = 0b011,
00617         POSITIVE_DIV_4 = 0b101,
00618         POSITIVE_DIV_6 = 0b110,
00619         POSITIVE_DIV_8 = 0b111
00620     };
00621 
00622     /**
00623      * Set the receiver IF mixing configuration.
00624      * See the user guide section on IF_MIX_CFG.CMIX_CFG for details.
00625      *
00626      * You must call *both* setRXFilterBandwidth() and setRadioFrequency() before calling this function.
00627      *
00628      * @param value Divider value to use, or zero-IF
00629      * @param enableIQIC Whether to enable the ImageExtinct IQ mismatch compensation when supported
00630      *   (when if IF > RX filter bandwidth).
00631      */
00632     void setIFCfg(IFCfg value, bool enableIQIC);
00633 
00634     /**
00635      * Mode describing the size and setup of the sync word.
00636      * See user guide register description for SYNC_CFG1
00637      */
00638     enum class SyncMode : uint8_t
00639     {
00640         SYNC_NONE = 0,
00641         SYNC_11_BITS = 0b1,
00642         SYNC_16_BITS = 0b10,
00643         SYNC_18_BITS = 0b11,
00644         SYNC_24_BITS = 0b100,
00645         SYNC_32_BITS = 0b101,
00646         SYNC_16_BITS_HIGH_BYTE = 0b110,
00647         SYNC_16_BITS_DUAL = 0b111
00648     };
00649 
00650     /**
00651      * Configure the sync word settings of the radio. The sync word is the bit string sent before each packet -- the
00652      * radio knows to switch into receive mode when it detects it.  Specific values with low autocorrelation should
00653      * be used for the sync word.
00654      *
00655      * @param syncWord Sync word value.
00656      * @param mode Sync word mode.  Configures how many bits of the value are significant.
00657      * @param syncThreshold Correspondance threshold before the radio switches into receive mode.
00658      */
00659     void configureSyncWord(uint32_t syncWord, SyncMode mode, uint8_t syncThreshold);
00660 
00661     /**
00662      * Check whether the frequency synthesizer is locked on to the correct frequency.
00663      * If not, then the correct RF frequency is not being used.
00664      * If the FS is not locking then check that the correct black box FS registers are applied
00665      * and that the FS has been calibrated.
00666      * @return
00667      */
00668     bool isFSLocked();
00669 
00670     /**
00671      * Configure the preamble that the radio is configured to send/receive.  The main purpose of the preamble is to
00672      * provide receiving radios with a chance to calibrate their RX gain.  However, you can also require that receiving
00673      * radios see a valid preamble before they can detect the sync word (this is not on by default).
00674      *
00675      * @param preambleLengthCfg Bits that determine the length of the preamble. See the PREAMBLE_CFG1 register description for details. Set to 0 disable transmitting a preamble.
00676      * @param preambleFormatCfg Bits that determine the format of the preamble.  See the PREAMBLE_CFG1 register description for details.
00677      */
00678     void configurePreamble(uint8_t preambleLengthCfg, uint8_t preambleFormatCfg);
00679 
00680     /**
00681      * Enum for different PA ramp times.
00682      */
00683     enum class RampTime : uint8_t
00684     {
00685         RAMP_3_8_SYMBOL = 0b0,
00686         RAMP_3_2_SYMBOL = 0b1,
00687         RAMP_3_SYMBOL = 0b10,
00688         RAMP_6_SYMBOL = 0b11
00689     };
00690 
00691     /**
00692      * Enable the the power amplifier ramp-up curve and set its shape and time.
00693      * See section 7.1 for details.
00694      * This is also used to set the ASK ramping between different power levels.
00695      *
00696      * The PA will gradually ramp from off to full amplitude in rampTime relative to the
00697      * symbol rate.  At 1/3 of rampTime it will have ramped to (firstRampLevel / 16) * full amplitude,
00698      * and at 2/3 of rampTime it will have ramped to ((secondRampLevel + 7) / 16) * full amplitude.
00699      */
00700     void setPARampRate(uint8_t firstRampLevel, uint8_t secondRampLevel, RampTime rampTime);
00701 
00702     /**
00703      * Disable the power amplifier ramp-up curve.
00704      */
00705     void disablePARamping();
00706 
00707     // Automatic Gain Control (AGC) Config
00708     // ------------------------------------------------------------------------------
00709 
00710     /**
00711      * Set the AGC reference level which is the internal target power level that
00712      * the AGC tries to adjust to.
00713      *
00714      * The user manual section 6.4 gives a rough formula to calculate this, but I've just used the SmartRF values.
00715      *
00716      * @param level Internal power level in dB.
00717      */
00718     void setAGCReferenceLevel(uint8_t level);
00719 
00720     /**
00721      * Enum for possible AGC actions after is a sync word detection.
00722      * See AGC_CFG3 register description for more info.
00723      */
00724     enum class SyncBehavior : uint8_t
00725     {
00726         FREEZE_NONE = 0b000,
00727         FREEZE_GAIN = 0b001,
00728         AGC_SLOWMODE = 0b010,
00729         FREEZE_BOTH = 0b011
00730     };
00731 
00732     /**
00733      * Set the AGC behavior after a sync word is detected.
00734      * @param behavior
00735      */
00736     void setAGCSyncBehavior(SyncBehavior behavior);
00737 
00738     /**
00739      * Enum for possible gain tables to use.
00740      * See AGC_CFG2 register description for more info.
00741      */
00742     enum class GainTable : uint8_t
00743     {
00744         OPTIMIZED_LINEARITY = 0b00,
00745         NORMAL = 0b01,
00746         LOW_POWER = 0b10,
00747         ZERO_IF = 0b11
00748     };
00749 
00750     /**
00751      * Set the gain table and min and max values within that table to use.
00752      * Min and max values are indexes into the current selected table.
00753      */
00754     void setAGCGainTable(GainTable table, uint8_t minGainIndex, uint8_t maxGainIndex);
00755 
00756     /**
00757      * Configure the change in input signal power that must be sensed before the AGC starts to adjust itself.
00758      * See the register description for AGC_CFG0.AGC_HYST_LEVEL
00759      * @param hysteresisCfg
00760      */
00761     void setAGCHysteresis(uint8_t hysteresisCfg);
00762 
00763     /**
00764      * Configure the rate that the AGC changes the receive gain.
00765      * See the register description for AGC_CFG0.AGC_SLEWRATE_LIMIT
00766      * @param slewrateCfg
00767      */
00768     void setAGCSlewRate(uint8_t slewrateCfg);
00769 
00770     /**
00771      * Configure the time that the AGC takes to settle.
00772      * See the register description for AGC_CFG1.AGC_SETTLE_WAIT
00773      * @param settleWaitCfg bytes to write to AGC_CFG1.AGC_SETTLE_WAIT
00774      */
00775      void setAGCSettleWait(uint8_t settleWaitCfg);
00776 
00777     // Received Signal Strength Indicator (RSSI) and Link Quality Indicator (LQI) functions
00778     // ------------------------------------------------------------------------------
00779 
00780 private:
00781     // data from packet status bytes
00782     int8_t lastRSSI;
00783     uint8_t lastLQI;
00784 
00785 public:
00786 
00787     /**
00788      * Get the RSSI as of the last packet received.
00789      * Only provides valid data if appendStatus is enabled.
00790      * @return RSSI in dBm, or -128 if no valid RSSI measurement exists.
00791      */
00792     int8_t getLastRSSI() {return lastRSSI;}
00793 
00794     /**
00795      * Get the current RSSI from the RSSI register.  Note: I think
00796      * this might only work while the radio is actively receiving.
00797      *
00798      * @return RSSI in dBm, or NaN if no valid RSSI measurement exists.
00799      */
00800     float getRSSIRegister();
00801 
00802     /**
00803      * Set the RSSI gain adjustment.  This value is added to the reported RSSI, and also used
00804      * in the calculation of the Carrier Sense (CS) line.
00805      * You have to calibrate this in a lab by feeding in a known amplitude signal,
00806      * see the user manual section 6.9 for details.
00807      */
00808     void setRSSIOffset(int8_t adjust);
00809 
00810     /**
00811      * Get the LQI from the LQI_VAL register.
00812      * This is a qualitative estimate from 1-128 of how easily a packet can be demodulated.
00813      * Lower is better, but 0 indicates invalid.
00814      * @return
00815      */
00816     uint8_t getLQIRegister();
00817 
00818     /**
00819      * Get the LQI as of the last packet received.
00820      * Only provides valid data if appendStatus is enabled.
00821      * This is a qualitative estimate from 1-128 of how easily a packet can be demodulated.
00822      * Lower is better, but 0 indicates invalid.
00823      */
00824     uint8_t getLastLQI() {return lastLQI;}
00825 
00826     // Register level functions
00827     // ------------------------------------------------------------------------------
00828 
00829     /**
00830      * Read a register and return the byte value.  Also reads the radio's state.
00831      */
00832     uint8_t readRegister(Register reg);
00833 
00834     /**
00835     * Write a register with a byte value. Also reads the radio's state.
00836     */
00837     void writeRegister(Register reg, uint8_t value);
00838 
00839     /**
00840     * Write a series of consecutive registers with byte values. Also reads the radio's state.
00841     */
00842     void writeRegisters(CC1200::Register startReg, uint8_t const *values, size_t numRegisters);
00843 
00844     /**
00845     * Write a series of consecutive registers with byte values. Also reads the radio's state.
00846     * Template version that takes an std::array.
00847     */
00848     template<size_t numRegisters>
00849     void writeRegisters(CC1200::Register startReg, std::array<uint8_t, numRegisters> const & values)
00850     {
00851         writeRegisters(startReg, values.data(), values.size());
00852     }
00853 
00854     /**
00855     * Read an extended register and return the byte value. Also reads the radio's state.
00856     */
00857     uint8_t readRegister(ExtRegister reg);
00858 
00859     /**
00860     * Write an extended register with a byte value. Also reads the radio's state.
00861     */
00862     void writeRegister(ExtRegister reg, uint8_t value);
00863 
00864     /**
00865     * Write a series of consecutive extended registers with byte values. Also reads the radio's state.
00866     */
00867     void writeRegisters(CC1200::ExtRegister startReg, uint8_t const *values, size_t numRegisters);
00868 
00869     /**
00870     * Write a series of consecutive registers with byte values. Also reads the radio's state.
00871     * Template version that takes an std::array.
00872     */
00873     template<size_t numRegisters>
00874     void writeRegisters(CC1200::ExtRegister startReg, std::array<uint8_t, numRegisters> const & values)
00875     {
00876         writeRegisters(startReg, values.data(), values.size());
00877     }
00878 
00879 
00880     /**
00881      * Send a command. Also reads the radio's state.
00882      * @param command
00883      */
00884     void sendCommand(Command command);
00885 
00886     /**
00887      * Update the current known state of the radio.
00888      */
00889     void updateState() { sendCommand(Command::NOP); }
00890 
00891     /**
00892      * Get a byte from the RX FIFO.
00893      * @param address The byte address, from 0-127.
00894      */
00895     uint8_t readRXFIFOByte(uint8_t address);
00896 
00897     // State change functions
00898     // ------------------------------------------------------------------------------
00899 
00900     /**
00901      * Send the STX strobe to change the radio into TX state.
00902      * Valid when the radio is in IDLE, FAST_TX_ON, and RX.
00903      * A calibration will be performed if needed.
00904      *
00905      * The radio will stay in TX state until it is commanded to a different state, or a packet is
00906      * transmitted and it is configured to change states when this happens, or a FIFO error occurs (which
00907      * shouldn't be possible with the current configuration).
00908      */
00909     void startTX() { sendCommand(Command::TX); }
00910 
00911     /**
00912      * Send the SRX strobe to change the radio into TX state.
00913      * Valid when the radio is in IDLE, FAST_TX_ON, and TX.
00914      * A calibration will be performed if needed.
00915      *
00916      * The radio will stay in RX state until it is commanded to a different state, or a packet is
00917      * received and it configured to change states when this happens, or a FIFO overflow occurs
00918      * (because the host is not reading data out fast enough).
00919      */
00920     void startRX() { sendCommand(Command::RX); }
00921 
00922     /**
00923      * Send the radio into idle mode.  Stops a currently running tx or rx.
00924      */
00925     void idle() { sendCommand(Command::IDLE); }
00926 
00927 private:
00928 
00929     /**
00930      * Called whenever we get a status byte from another operation.  Saves the info from it to member variables.
00931      * @param status
00932      */
00933     void loadStatusByte(uint8_t status);
00934 };
00935 
00936 
00937 #endif //LIGHTSPEEDRANGEFINDER_CC1200_H