Jamie Smith / CC1200

Dependents:   CC1200-MorseEncoder CC1200-Examples

Revision:
5:d22a8885800b
Parent:
4:c609cc7c9ea7
--- a/CC1200.h	Fri Aug 28 15:39:31 2020 -0700
+++ b/CC1200.h	Mon May 03 02:41:34 2021 -0700
@@ -125,6 +125,11 @@
 		XOSC1 = 0x36,
 		XOSC0 = 0x37,
 		//...
+		RSSI1 = 0x71,
+		RSSI0 = 0x72,
+		MARCSTATE = 0x73,
+		LQI_VAL = 0x74,
+		//...
 		FREQOFF_EST1 = 0x77,
 		FREQOFF_EST2 = 0x78,
 		//...
@@ -185,8 +190,13 @@
 	// current symbol rate of the radio
 	float symbolRateSps = 0;
 
-	// current ADC CIC decimation of the radio
+	// current RX filter params
 	uint8_t adcCicDecimation = 0;
+	float currentRXFilterBW = 0;
+
+	// current RF params
+	float radioFreqHz;
+
 
 public:
 
@@ -241,6 +251,8 @@
 	 *
 	 * In fixed length mode, the length should be the fixed packet length.
 	 *
+	 * The function is not for use with infinite-length mode, use writeStream() instead.
+	 *
 	 * Also reads the radio's state.
 	 *
 	 * @param data
@@ -253,6 +265,7 @@
 
 	/**
 	 * Check whether there is at least one complete packet in the RX FIFO.
+	 * In infinite length mode, this returns true if any data is present at all.
 	 * NOTE: An alternate way to do this using hardware is to configure one
 	 * of the CC1200's GPIOs as PKT_SYNC_RXTX, then set a falling edge interrupt to receive a packet.
 	 * @return
@@ -268,6 +281,8 @@
 	 * in the FIFO, *undefined behavior* can occur.  An arbitrary amount of data will be read from
 	 * the FIFO and garbage may be returned.
 	 *
+	 * The function is not for use with infinite-length mode, use readStream() instead.
+	 *
 	 * NOTE: A null terminator is NOT added unless it was present in the transmitted data.
 	 * Be careful when treating the returned data as a string!
 	 *
@@ -278,6 +293,78 @@
 	 */
 	size_t receivePacket(char * buffer, size_t bufferLen);
 
+	// Infinite length tx & rx functions
+	// ------------------------------------------------------------------------------
+
+	/*
+	 * How to use infinite length from the TX side:
+	 * 1. Place up to 128 bytes of data in the TX FIFO for transmission using writeStream().
+	 * 2. Enable TX mode using startTX()
+	 * 3. Keep streaming in data using writeStream() writeStreamBlocking() or at least as fast as it is transmitted.
+	 * 4. Disable TX mode when done using idle().
+	 *
+	 * Take care that the TX fifo never runs completely out of data, or the chip will go into TX FIFO ERROR state.
+	 */
+
+	/*
+	 * How to use infinite length from the RX side:
+	 * 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.
+	 * 2. Wait for data to arrive using hasReceivedPacket().
+	 * 3. Start streaming out data using readStream() or readStreamBlocking().
+	 * 4. Disable RX mode when done using idle().
+	 *
+	 * Take care that the RX fifo doesn't become full, or the chip will go into RX FIFO ERROR state.
+	 */
+
+	/**
+	 * Write a stream of data to the chip.  This function is only for use in infinite-length mode.
+	 * As many bytes from the given buffer will be written as can fit in the chip's FIFO.
+	 * If the FIFO is full, this function does nothing.
+	 *
+	 * @param buffer
+	 * @param count
+	 * @return Number of bytes written.
+	 */
+	size_t writeStream(const char* buffer, size_t count);
+
+	/**
+	 * Write a stream of data to the chip.  This function is only for use in infinite-length mode.
+	 * Will block until all bytes in the given buffer have been written to the TX FIFO, or an error has been
+	 * detected (the radio switches to any state other than TX).
+	 *
+	 * @param buffer
+	 * @param count
+	 * @return True if successful, false if there was an error.
+	 */
+	bool writeStreamBlocking(const char* buffer, size_t count);
+
+	/**
+	 * Read up to maxLen bytes into buffer.
+	 * @param buffer
+	 * @param maxLen
+	 * @return How many bytes were actually read.  0 if the RX FIFO was empty.
+	 */
+	size_t readStream(char* buffer, size_t maxLen);
+
+	/**
+	 * Read a stream of data from the chip.  This function is only for use in infinite-length mode.
+	 * Will block until the buffer was filled, an error has been
+	 * detected (the radio switches to any state other than RX), or the timeout expires.
+	 *
+	 * If false is returned, some data may have been written to the buffer, and the rest will not have been modified.
+	 *
+	 * Note: if using a zero timeout, this function could cause a hang if the transmitter stops transmitting.
+	 *
+	 * @param buffer
+	 * @param count
+	 * @param timeout Timeout, or 0us to disable timeout.
+	 * @return True iff the buffer was completely filled.
+	 */
+	bool readStreamBlocking(char* buffer, size_t count, std::chrono::microseconds timeout=0us);
+
+	// State transition configuration
+	// ------------------------------------------------------------------------------
+
 	/**
 	 * Set what state the radio will enter when a packet is received.
 	 * @param goodPacket State when a good (CRC pass) packet is received.
@@ -349,6 +436,8 @@
 
 	enum class PacketMode : uint8_t
 	{
+		/// Use infinite length transmissions (streaming mode).
+		INFINITE_LENGTH = 0b10,
 		/// Use fixed length packets.
 		VARIABLE_LENGTH = 0b1,
 		/// Use variable length packets, the length is encoded in the first byte of the packet.
@@ -356,10 +445,12 @@
 	};
 
 	/**
-	 * Set the packet mode that the system will use
+	 * Set the packet mode that the system will use.
 	 * @param mode
+	 * @param appendStatus Have the radio append a status byte to each packet received.  This takes up
+	 * 2 bytes per packet in the RX FIFO, but provides status information about each packet.
 	 */
-	void setPacketMode(PacketMode mode);
+	void setPacketMode(PacketMode mode, bool appendStatus = false);
 
 	/**
 	 * Set the packet length when in fixed length packet mode.
@@ -367,19 +458,24 @@
 	 * For example, if your packets are 20 bits long, you should set length to 2 bytes and bitLength to
 	 * 4 bytes, so that 2 complete bytes + 4 extra bits are transmitted.  Buffers used for sending and receiving packets
 	 * should then be 3 bytes long.
+	 *
+	 * When appendStatus is disabled, the max length is 256 bytes.  When it is enabled, the max length is 254 bytes.
 	 * @param length
 	 */
-	void setPacketLength(uint8_t length, uint8_t bitLength = 0);
+	void setPacketLength(uint16_t length, uint8_t bitLength = 0);
 
 private:
 	// current packet mode
 	PacketMode _packetMode;
 
 	// current packet length when in fixed length packet mode
-	uint8_t _packetTotalLength = 0; // length in bytes including final partial byte
-	uint8_t _packetByteLength = 0; // length in whole bytes
+	uint16_t _packetTotalLength = 0; // length in bytes including final partial byte
+	uint16_t _packetByteLength = 0; // length in whole bytes
 	uint8_t _packetBitLength = 0; // extra bit length at end
 
+	// Whether the two status bytes are included in each received packet
+	bool appendStatusEnabled = true;
+
 public:
 
 	/**
@@ -480,8 +576,10 @@
 	 * - SYNC_CFG0.RX_CONFIG_LIMITATION
 	 *
 	 * @param bandwidthHz the bandwidth in Hz
+	 * @param preferHigherCICDec If there are multiple register value choices, prefer the one with higher CIC decimation
+	 * and lower BB decimation.  This is the recommendation of the datasheet but it actually causes transmission to fail in some cases.
 	 */
-	void setRXFilterBandwidth(float bandwidthHz);
+	void setRXFilterBandwidth(float bandwidthHz, bool preferHigherCICDec = true);
 
 	/**
 	 * Get the ADC CIC decimation that was calculated by the most recent setRXFilterBandwidth() call.
@@ -491,7 +589,7 @@
 	uint8_t getADCCICDecimation() { return adcCicDecimation; }
 
 	/**
-	 * Configure the radio's automatic DC offset removal algorithm is enabled.
+	 * Configure the radio's automatic DC offset removal algorithm as enabled.
 	 * DC offset correction must be enabled when using zero IF mode, and in my testing
 	 * it seems to be important when staying in TX mode for a long time at
 	 * higher sample rates.
@@ -506,17 +604,32 @@
 	void configureDCFilter(bool enableAutoFilter, uint8_t settlingCfg, uint8_t cutoffCfg);
 
 	/**
-	 * Set the IF mixing configuration.
+	 * Possible intermediate frequency values.
+	 * For right now it seems like you have to get these from SmartRF.
 	 * See the user guide section on IF_MIX_CFG.CMIX_CFG for details.
 	 */
-	void setIFMixCFG(uint8_t value);
+	enum class IFCfg : uint8_t
+	{
+		ZERO = 0, // Zero IF.  From what I can find, this means samples are taken at the radio frequency.
+		NEGATIVE_DIV_4 = 0b001,
+		NEGATIVE_DIV_6 = 0b010,
+		NEGATIVE_DIV_8 = 0b011,
+		POSITIVE_DIV_4 = 0b101,
+		POSITIVE_DIV_6 = 0b110,
+		POSITIVE_DIV_8 = 0b111
+	};
 
 	/**
-	 * Set whether the ImageExtinct IQ mismatch compensation logic is enabled.
-	 * This should be disabled if IF < RX filter bandwidth
-	 * @param enabled
+	 * Set the receiver IF mixing configuration.
+	 * See the user guide section on IF_MIX_CFG.CMIX_CFG for details.
+	 *
+	 * You must call *both* setRXFilterBandwidth() and setRadioFrequency() before calling this function.
+	 *
+	 * @param value Divider value to use, or zero-IF
+	 * @param enableIQIC Whether to enable the ImageExtinct IQ mismatch compensation when supported
+	 *   (when if IF > RX filter bandwidth).
 	 */
-	void setIQMismatchCompensationEnabled(bool enabled);
+	void setIFCfg(IFCfg value, bool enableIQIC);
 
 	/**
 	 * Mode describing the size and setup of the sync word.
@@ -654,6 +767,62 @@
 	 */
 	void setAGCSlewRate(uint8_t slewrateCfg);
 
+	/**
+	 * Configure the time that the AGC takes to settle.
+	 * See the register description for AGC_CFG1.AGC_SETTLE_WAIT
+	 * @param settleWaitCfg bytes to write to AGC_CFG1.AGC_SETTLE_WAIT
+	 */
+	 void setAGCSettleWait(uint8_t settleWaitCfg);
+
+	// Received Signal Strength Indicator (RSSI) and Link Quality Indicator (LQI) functions
+	// ------------------------------------------------------------------------------
+
+private:
+	// data from packet status bytes
+	int8_t lastRSSI;
+	uint8_t lastLQI;
+
+public:
+
+	/**
+	 * Get the RSSI as of the last packet received.
+	 * Only provides valid data if appendStatus is enabled.
+	 * @return RSSI in dBm, or -128 if no valid RSSI measurement exists.
+	 */
+	int8_t getLastRSSI() {return lastRSSI;}
+
+	/**
+	 * Get the current RSSI from the RSSI register.  Note: I think
+	 * this might only work while the radio is actively receiving.
+	 *
+	 * @return RSSI in dBm, or NaN if no valid RSSI measurement exists.
+	 */
+	float getRSSIRegister();
+
+	/**
+	 * Set the RSSI gain adjustment.  This value is added to the reported RSSI, and also used
+	 * in the calculation of the Carrier Sense (CS) line.
+	 * You have to calibrate this in a lab by feeding in a known amplitude signal,
+	 * see the user manual section 6.9 for details.
+	 */
+	void setRSSIOffset(int8_t adjust);
+
+	/**
+	 * Get the LQI from the LQI_VAL register.
+	 * This is a qualitative estimate from 1-128 of how easily a packet can be demodulated.
+	 * Lower is better, but 0 indicates invalid.
+	 * @return
+	 */
+	uint8_t getLQIRegister();
+
+	/**
+	 * Get the LQI as of the last packet received.
+	 * Only provides valid data if appendStatus is enabled.
+	 * This is a qualitative estimate from 1-128 of how easily a packet can be demodulated.
+	 * Lower is better, but 0 indicates invalid.
+	 */
+	uint8_t getLastLQI() {return lastLQI;}
+
 	// Register level functions
 	// ------------------------------------------------------------------------------