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.cpp Source File

CC1200.cpp

00001 #pragma clang diagnostic push
00002 #pragma ide diagnostic ignored "readability-magic-numbers"
00003 //
00004 // Created by jamie on 3/27/2020.
00005 //
00006 
00007 #include "CC1200.h"
00008 #include "CC1200Bits.h"
00009 
00010 #include <cinttypes>
00011 #include <cmath>
00012 #include <array>
00013 
00014 // change to 1 to print debug info
00015 #define CC1200_DEBUG 1
00016 
00017 // change to 1 to print register read/write level debug info
00018 #define CC1200_REGISTER_LEVEL_DEBUG 0
00019 
00020 // miscellaneous constants
00021 #define CC1200_READ (1 << 7) // SPI initial byte flag indicating read
00022 #define CC1200_WRITE 0 // SPI initial byte flag indicating write
00023 #define CC1200_BURST (1 << 6) // SPI initial byte flag indicating burst access
00024 
00025 // SPI commands to access data buffers.  Can be used with CC1200_BURST.
00026 #define CC1200_ENQUEUE_TX_FIFO 0x3F
00027 #define CC1200_DEQUEUE_RX_FIFO 0xBF
00028 
00029 // SPI command to access FIFO memory (or several other areas depending on mode)
00030 #define CC1200_MEM_ACCESS 0x3E
00031 
00032 #define CC1200_RX_FIFO (1 << 7) // address flag to access RX FIFO
00033 #define CC1200_TX_FIFO 0 // address flag to access TX FIFO
00034 
00035 
00036 #define CC1200_PART_NUMBER ((uint8_t)0x20) // part number we expect the chip to read
00037 #define CC1201_PART_NUMBER ((uint8_t)0x21)
00038 #define CC1200_EXT_ADDR 0x2F // SPI initial byte address indicating extended register space
00039 
00040 #define SPI_MODE 0
00041 #define SPI_FREQ 5000000 // hz
00042 // NOTE: the chip supports a higher frequency for most operations but reads to extended registers require a lower frequency
00043 
00044 // frequency of the chip's crystal oscillator
00045 #define CC1200_OSC_FREQ 40000000 // hz
00046 #define CC1200_OSC_FREQ_LOG2 25.253496f // log2 of above number
00047 
00048 // length of the TX and RX FIFOS
00049 #define CC1200_FIFO_SIZE 128
00050 
00051 // maximum length of the packets we can send, including the length byte which we add.
00052 // Since the TX and RX FIFOs are 128 bytes, supporting packet lengths longer than 128 bytes
00053 // requires streaming bytes in during the transmission, which would make things complicated.
00054 #define MAX_PACKET_LENGTH 128
00055 
00056 // Length of the status bytes that can be appended to packets
00057 #define PACKET_STATUS_LEN 2U
00058 
00059 // utility function: compile-time power calculator.
00060 // Works on all signed and unsigned integer types for T.
00061 // from: http://prosepoetrycode.potterpcs.net/2015/07/a-simple-constexpr-power-function-c/
00062 template <typename T>
00063 constexpr T constexpr_pow(T num, unsigned int pow)
00064 {
00065     return pow == 0 ? 1 : num * constexpr_pow(num, pow-1);
00066 }
00067 
00068 // power of two constants
00069 const float twoToThe16 = constexpr_pow(2.0f, 16);
00070 const float twoToThe20 = constexpr_pow(2.0f, 20);
00071 const float twoToThe21 = constexpr_pow(2.0f, 21);
00072 const float twoToThe22 = constexpr_pow(2.0f, 22);
00073 const float twoToThe38 = constexpr_pow(2.0f, 38);
00074 const float twoToThe39 = constexpr_pow(2.0f, 39);
00075 
00076 // binary value size constants
00077 const size_t maxValue3Bits = constexpr_pow(2, 3) - 1;
00078 const size_t maxValue4Bits = constexpr_pow(2, 4) - 1;
00079 const size_t maxValue8Bits = constexpr_pow(2, 8) - 1;
00080 const size_t maxValue20Bits = constexpr_pow(2, 20) - 1;
00081 const size_t maxValue24Bits = constexpr_pow(2, 24) - 1;
00082 
00083 CC1200::CC1200(PinName mosiPin, PinName misoPin, PinName sclkPin, PinName csPin, PinName rstPin, Stream * _debugStream, bool _isCC1201):
00084 spi(mosiPin, misoPin, sclkPin, csPin, use_gpio_ssel),
00085 rst(rstPin, 1),
00086 debugStream(_debugStream),
00087 isCC1201(_isCC1201)
00088 {
00089     spi.format(8, SPI_MODE);
00090     spi.frequency(SPI_FREQ);
00091 }
00092 
00093 bool CC1200::begin()
00094 {
00095     chipReady = false;
00096 
00097     // reset
00098     rst.write(0);
00099     wait_us(100);
00100     rst.write(1);
00101 
00102     const auto resetTimeout = 10ms;
00103     Timer timeoutTimer;
00104     timeoutTimer.start();
00105 
00106     while(!chipReady)
00107     {
00108         // datasheet specifies 240us reset time
00109         wait_us(250);
00110         updateState();
00111 
00112         if(timeoutTimer.elapsed_time() > resetTimeout)
00113         {
00114             debugStream->printf("Timeout waiting for ready response from CC1200\n");
00115             break;
00116         }
00117     }
00118 
00119     // read ID register
00120     uint8_t partNumber = readRegister(ExtRegister::PARTNUMBER);
00121     uint8_t partVersion = readRegister(ExtRegister::PARTVERSION);
00122 
00123     uint8_t expectedPartNumber = isCC1201 ? CC1201_PART_NUMBER : CC1200_PART_NUMBER;
00124     if(partNumber != expectedPartNumber)
00125     {
00126         debugStream->printf("Read incorrect part number 0x%" PRIx8 " from CC1200, expected 0x%" PRIx8 "\n", partNumber, expectedPartNumber);
00127         return false;
00128     }
00129 
00130 #if CC1200_DEBUG
00131     debugStream->printf("Detected CC1200, Part Number 0x%" PRIx8 ", Hardware Version %" PRIx8 "\n", partNumber, partVersion);
00132 #endif
00133 
00134 
00135     // Set packet format settings for this driver
00136     // ------------------------------------------------------------------------
00137 
00138     // enable CRC but disable status bytes
00139     writeRegister(Register::PKT_CFG1, (0b01 << PKT_CFG1_CRC_CFG));
00140 
00141     return true;
00142 }
00143 
00144 size_t CC1200::getTXFIFOLen()
00145 {
00146     return readRegister(ExtRegister::NUM_TXBYTES);
00147 }
00148 
00149 size_t CC1200::getRXFIFOLen()
00150 {
00151     return readRegister(ExtRegister::NUM_RXBYTES);
00152 }
00153 
00154 bool CC1200::enqueuePacket(char const * data, size_t len)
00155 {
00156     uint8_t totalLength = len + 1; // add one byte for length byte
00157 
00158     if(totalLength > MAX_PACKET_LENGTH)
00159     {
00160         // packet too big
00161         return false;
00162     }
00163 
00164     uint8_t txFreeBytes = CC1200_FIFO_SIZE - getTXFIFOLen();
00165     if(totalLength > txFreeBytes)
00166     {
00167         // packet doesn't fit in TX FIFO
00168         return false;
00169     }
00170 
00171     // burst write to TX FIFO
00172     spi.select();
00173     loadStatusByte(spi.write(CC1200_ENQUEUE_TX_FIFO | CC1200_BURST));
00174     if(_packetMode == PacketMode::VARIABLE_LENGTH)
00175     {
00176         spi.write(len);
00177     }
00178     for(size_t byteIndex = 0; byteIndex < len; ++byteIndex)
00179     {
00180         spi.write(data[byteIndex]);
00181     }
00182     spi.deselect();
00183 
00184 #if CC1200_REGISTER_LEVEL_DEBUG
00185     debugStream->printf("Wrote packet of data length %zu:", len);
00186     if(_packetMode == PacketMode::VARIABLE_LENGTH)
00187     {
00188         debugStream->printf(" %02" PRIx8, static_cast<uint8_t>(len));
00189     }
00190     for(size_t byteIndex = 0; byteIndex < len; ++byteIndex)
00191     {
00192         debugStream->printf(" %02" PRIx8, data[byteIndex]);
00193     }
00194     debugStream->printf("\n");
00195 #endif
00196     return true;
00197 }
00198 
00199 bool CC1200::hasReceivedPacket()
00200 {
00201     size_t bytesReceived = getRXFIFOLen();
00202 
00203     if(bytesReceived < 1)
00204     {
00205         // no bytes at all, can't check the length
00206         return false;
00207     }
00208 
00209     if(_packetMode == PacketMode::FIXED_LENGTH)
00210     {
00211         return bytesReceived >= _packetTotalLength + (appendStatusEnabled ? PACKET_STATUS_LEN : 0);
00212     }
00213     else if(_packetMode == PacketMode::INFINITE_LENGTH)
00214     {
00215         // Any amount of bytes constitutes a packet.
00216         return bytesReceived > 0;
00217     }
00218     else // _packetMode == PacketMode::VARIABLE_LENGTH
00219     {
00220         // get value of first byte of the packet, which is the length.
00221 
00222         // The datasheet is wrong about this!  It says that the first byte in the RX FIFO can
00223         // be found by accessing address RXFIRST via direct fifo access.
00224         // However, in my own testing, RXFIRST points to the second entry in the FIFO, and
00225         // the first entry must be accessed through RXFIFO_PRE_BUF.
00226         uint8_t packetLen = readRegister(ExtRegister::RXFIFO_PRE_BUF);
00227 
00228         // if we have received a full packet's worth of bytes, then we have received a full packet.
00229         return bytesReceived >= static_cast<size_t>(packetLen + 1 /* Add one because length field does not include itself */) + (appendStatusEnabled ? PACKET_STATUS_LEN : 0);
00230     }
00231 }
00232 
00233 size_t CC1200::receivePacket(char *buffer, size_t bufferLen)
00234 {
00235     // burst read from RX FIFO
00236     spi.select();
00237     loadStatusByte(spi.write(CC1200_DEQUEUE_RX_FIFO | CC1200_BURST));
00238 
00239     uint8_t dataLen;
00240     if(_packetMode == PacketMode::VARIABLE_LENGTH)
00241     {
00242         // first read length byte
00243         dataLen = spi.write(0);
00244     }
00245     else // _packetMode == PacketMode::FIXED_LENGTH)
00246     {
00247         dataLen = _packetTotalLength;
00248     }
00249 
00250     for(size_t byteIndex = 0; byteIndex < dataLen; ++byteIndex)
00251     {
00252         uint8_t currByte = spi.write(0);
00253         if(byteIndex < bufferLen)
00254         {
00255             buffer[byteIndex] = currByte;
00256         }
00257     }
00258 
00259     if(appendStatusEnabled)
00260     {
00261         uint8_t statusBytes[PACKET_STATUS_LEN];
00262         for(size_t byteIndex = 0; byteIndex < PACKET_STATUS_LEN; ++byteIndex)
00263         {
00264             statusBytes[byteIndex] = spi.write(0);
00265         }
00266 
00267         lastRSSI = statusBytes[0];
00268         lastLQI = statusBytes[1] & 0b01111111;
00269     }
00270 
00271     spi.deselect();
00272 
00273 #if CC1200_REGISTER_LEVEL_DEBUG
00274     debugStream->printf("Read packet of data length %" PRIu8 ": %" PRIx8, dataLen, static_cast<uint8_t>(dataLen));
00275     for(size_t byteIndex = 0; byteIndex < dataLen; ++byteIndex)
00276     {
00277         debugStream->printf(" %" PRIx8, buffer[byteIndex]);
00278     }
00279     debugStream->printf("\n");
00280 #endif
00281 
00282     return dataLen;
00283 }
00284 
00285 size_t CC1200::writeStream(const char *buffer, size_t count)
00286 {
00287     size_t freeBytes = CC1200_FIFO_SIZE - getTXFIFOLen();
00288 
00289     /*if(state == State::TX)
00290     {
00291         if(freeBytes > 0)
00292         {
00293             freeBytes--;
00294         }
00295     }*/
00296 
00297     size_t bytesToWrite = std::min(freeBytes, count);
00298 
00299     if(bytesToWrite == 0)
00300     {
00301         return 0;
00302     }
00303 
00304     spi.select();
00305     loadStatusByte(spi.write(CC1200_ENQUEUE_TX_FIFO | CC1200_BURST));
00306     for(size_t byteIndex = 0; byteIndex < bytesToWrite; ++byteIndex)
00307     {
00308         spi.write(buffer[byteIndex]);
00309     }
00310     spi.deselect();
00311 
00312 #if CC1200_REGISTER_LEVEL_DEBUG
00313     debugStream->printf("%zu bytes were free, wrote stream of data length %zu:", freeBytes, bytesToWrite);
00314     for(size_t byteIndex = 0; byteIndex < bytesToWrite; ++byteIndex)
00315     {
00316         debugStream->printf(" %02" PRIx8, buffer[byteIndex]);
00317     }
00318     debugStream->printf("\n");
00319 #endif
00320 
00321     return bytesToWrite;
00322 }
00323 
00324 bool CC1200::writeStreamBlocking(const char *buffer, size_t count)
00325 {
00326     //size_t origCount = count;
00327     size_t bufferOffset = 0;
00328     while(state == State::TX && count > 0)
00329     {
00330         size_t bytesWritten = writeStream(buffer + bufferOffset, count);
00331         count -= bytesWritten;
00332         bufferOffset += bytesWritten;
00333     }
00334 
00335     //debugStream->printf("Read stream of data length %zu\n:", origCount);
00336 
00337     return count == 0;
00338 }
00339 
00340 size_t CC1200::readStream(char *buffer, size_t maxLen)
00341 {
00342     size_t bytesToRead = std::min(maxLen, getRXFIFOLen());
00343     if(bytesToRead == 0)
00344     {
00345         return 0;
00346     }
00347 
00348     // burst read from RX FIFO
00349     spi.select();
00350     loadStatusByte(spi.write(CC1200_DEQUEUE_RX_FIFO | CC1200_BURST));
00351     for(size_t byteIndex = 0; byteIndex < bytesToRead; ++byteIndex)
00352     {
00353         buffer[byteIndex] = spi.write(0);
00354     }
00355     spi.deselect();
00356 
00357 #if CC1200_REGISTER_LEVEL_DEBUG
00358     debugStream->printf("Read stream of data length %zu:", bytesToRead);
00359     for(size_t byteIndex = 0; byteIndex < bytesToRead; ++byteIndex)
00360     {
00361         debugStream->printf(" %" PRIx8, buffer[byteIndex]);
00362     }
00363     debugStream->printf("\n");
00364 #endif
00365 
00366     return bytesToRead;
00367 }
00368 
00369 bool CC1200::readStreamBlocking(char *buffer, size_t count, std::chrono::microseconds timeout)
00370 {
00371     //size_t origCount = count;
00372     Timer timeoutTimer;
00373 
00374     if(timeout > 0us)
00375     {
00376         timeoutTimer.start();
00377     }
00378 
00379     size_t bufferOffset = 0;
00380     while((timeoutTimer.elapsed_time() < timeout || timeout == 0us) && state == State::RX && count > 0)
00381     {
00382         size_t bytesRead = readStream(buffer + bufferOffset, count);
00383         count -= bytesRead;
00384         bufferOffset += bytesRead;
00385     }
00386 
00387     //debugStream->printf("Read stream of data length %zu, first %" PRIx8 " last %" PRIx8 "\n:", origCount,
00388     //      buffer[0], buffer[origCount - 1]);
00389 
00390     return count == 0;
00391 }
00392 
00393 
00394 // helper function: convert a state to the bits for RXOFF_MODE and TXOFF_MODE
00395 inline uint8_t getOffModeBits(CC1200::State state)
00396 {
00397     uint8_t offBits = 0b0;
00398     if(state == CC1200::State::IDLE)
00399     {
00400         offBits = 0b0;
00401     }
00402     else if(state == CC1200::State::FAST_ON)
00403     {
00404         offBits = 0b1;
00405     }
00406     else if(state == CC1200::State::TX)
00407     {
00408         offBits = 0b10;
00409     }
00410     else if(state == CC1200::State::RX)
00411     {
00412         offBits = 0b11;
00413     }
00414     return offBits;
00415 }
00416 
00417 void CC1200::setOnReceiveState(CC1200::State goodPacket, CC1200::State badPacket)
00418 {
00419     // configure good packet action via RXOFF_MODE
00420     uint8_t rfendCfg1 = readRegister(Register::RFEND_CFG1);
00421     rfendCfg1 &= ~(0b11 << RFEND_CFG1_RXOFF_MODE);
00422     rfendCfg1 |= getOffModeBits(goodPacket) << RFEND_CFG1_RXOFF_MODE;
00423     writeRegister(Register::RFEND_CFG1, rfendCfg1);
00424 
00425     // configure bad packet action via TERM_ON_BAD_PACKET_EN
00426     uint8_t rfendCfg0 = readRegister(Register::RFEND_CFG0);
00427     if(badPacket == State::RX)
00428     {
00429         rfendCfg0 &= ~(1 << RFEND_CFG0_TERM_ON_BAD_PACKET_EN);
00430     }
00431     else
00432     {
00433         rfendCfg0 |= 1 << RFEND_CFG1_RXOFF_MODE;
00434     }
00435     writeRegister(Register::RFEND_CFG0, rfendCfg0);
00436 }
00437 
00438 void CC1200::setOnTransmitState(CC1200::State txState)
00439 {
00440     uint8_t rfendCfg0 = readRegister(Register::RFEND_CFG0);
00441     rfendCfg0 &= ~(0b11 << RFEND_CFG0_TXOFF_MODE);
00442     rfendCfg0 |= getOffModeBits(txState) << RFEND_CFG0_TXOFF_MODE;
00443     writeRegister(Register::RFEND_CFG0, rfendCfg0);
00444 }
00445 
00446 void CC1200::setFSCalMode(FSCalMode mode)
00447 {
00448     uint8_t settlingCfg = readRegister(Register::SETTLING_CFG);
00449     settlingCfg &= ~(0b11 << SETTLING_CFG_FS_AUTOCAL);
00450     settlingCfg |= static_cast<uint8_t>(mode) << SETTLING_CFG_FS_AUTOCAL;
00451     writeRegister(Register::SETTLING_CFG, settlingCfg);
00452 }
00453 
00454 void CC1200::configureGPIO(uint8_t gpioNumber, CC1200::GPIOMode mode, bool outputInvert)
00455 {
00456     // gpio 3 is the first register, then it goes down to 0
00457     Register gpioReg = static_cast<Register>(static_cast<uint8_t>(Register::IOCFG3) + (3 - gpioNumber));
00458 
00459     uint8_t gpioCfgVal = static_cast<uint8_t>(mode);
00460     if(outputInvert)
00461     {
00462         gpioCfgVal |= (1 << GPIO_INV);
00463     }
00464     writeRegister(gpioReg, gpioCfgVal);
00465 }
00466 
00467 void CC1200::configureFIFOMode()
00468 {
00469     // configure packet format
00470     uint8_t pktCfg2 = readRegister(Register::PKT_CFG2);
00471     pktCfg2 &= ~(0b11 << PKT_CFG2_PKT_FORMAT);
00472     writeRegister(Register::PKT_CFG2, pktCfg2);
00473 
00474     // enable fifo
00475     uint8_t mdmCfg1 = readRegister(Register::MDMCFG1);
00476     mdmCfg1 |= 1 << MDMCFG1_FIFO_EN;
00477     writeRegister(Register::MDMCFG1, mdmCfg1);
00478 
00479     // make sure transparent mode is disabled
00480     uint8_t mdmCfg0 = readRegister(Register::MDMCFG0);
00481     mdmCfg0 &= ~(1 << MDMCFG0_TRANSPARENT_MODE_EN);
00482     writeRegister(Register::MDMCFG0, mdmCfg0);
00483 }
00484 
00485 void CC1200::setPacketMode(PacketMode  mode, bool appendStatus)
00486 {
00487     _packetMode = mode;
00488 
00489     uint8_t pktCfg0 = readRegister(Register::PKT_CFG0);
00490     // set length config field
00491     pktCfg0 &= ~(0b11 << PKT_CFG0_LENGTH_CONFIG);
00492     pktCfg0 |= static_cast<uint8_t>(mode) << PKT_CFG0_LENGTH_CONFIG;
00493     writeRegister(Register::PKT_CFG0, pktCfg0);
00494 
00495     if(mode == PacketMode::VARIABLE_LENGTH)
00496     {
00497         // disable packet length limit
00498         writeRegister(Register::PKT_LEN, MAX_PACKET_LENGTH);
00499     }
00500     else if(mode == PacketMode::FIXED_LENGTH)
00501     {
00502         // reset to selected fixed lengths
00503         setPacketLength(_packetByteLength, _packetBitLength);
00504     }
00505     else
00506     {
00507         // Infinite length packets, PKT_LEN register is a don't care.
00508     }
00509 
00510     // set append status
00511     appendStatusEnabled = appendStatus;
00512     uint8_t pktCfg1 = readRegister(Register::PKT_CFG1);
00513     if(appendStatus)
00514     {
00515         pktCfg1 |= 1 << PKT_CFG1_APPEND_STATUS;
00516     }
00517     else
00518     {
00519         pktCfg1 &= ~(1 << PKT_CFG1_APPEND_STATUS);
00520     }
00521     writeRegister(Register::PKT_CFG1, pktCfg1);
00522 }
00523 
00524 void CC1200::setPacketLength(uint16_t length, uint8_t bitLength)
00525 {
00526     _packetByteLength = length;
00527     _packetBitLength = bitLength;
00528     _packetTotalLength = _packetByteLength;
00529 
00530     if(bitLength > 0)
00531     {
00532         // tell the driver to read the extra bits into another byte
00533         _packetTotalLength++;
00534     }
00535 
00536     if(_packetTotalLength == 256)
00537     {
00538         // Length byte of 0 indicates 256 bytes
00539         writeRegister(Register::PKT_LEN, 0);
00540     }
00541     else
00542     {
00543         writeRegister(Register::PKT_LEN, _packetByteLength);
00544     }
00545 
00546     uint8_t pktCfg0 = readRegister(Register::PKT_CFG0);
00547     pktCfg0 &= ~(0b111 << PKT_CFG0_PKT_BIT_LEN);
00548     pktCfg0 |= _packetBitLength << PKT_CFG0_PKT_BIT_LEN;
00549     writeRegister(Register::PKT_CFG0, pktCfg0);
00550 
00551 #if CC1200_DEBUG
00552     debugStream->printf("Set total length to %zu, byte length = %zu, bit length = %" PRIu8 "\n", _packetTotalLength, _packetByteLength, _packetBitLength);
00553 #endif
00554 }
00555 
00556 void CC1200::setCRCEnabled(bool enabled)
00557 {
00558     uint8_t pktCfg1 = readRegister(Register::PKT_CFG1);
00559     pktCfg1 &= ~(0b11 << PKT_CFG1_CRC_CFG);
00560     pktCfg1 |= (enabled ? 0b01 : 0b00) << PKT_CFG1_CRC_CFG;
00561     writeRegister(Register::PKT_CFG1, pktCfg1);
00562 }
00563 
00564 void CC1200::setModulationFormat(CC1200::ModFormat format)
00565 {
00566     uint8_t modcfgDevE = readRegister(Register::MODCFG_DEV_E);
00567     modcfgDevE &= ~(0b111 << MODCFG_DEV_E_MOD_FORMAT);
00568     modcfgDevE |= static_cast<uint8_t>(format) << MODCFG_DEV_E_MOD_FORMAT;
00569     writeRegister(Register::MODCFG_DEV_E, modcfgDevE);
00570 }
00571 
00572 void CC1200::setFSKDeviation(float deviation)
00573 {
00574     // Deviation is set as two values, an exponent register from 0-3 and a mantissa register from 0-256.
00575     // See user guide page 81 for the original equation, this function was worked out from that
00576 
00577     // First assume mantissa is zero and calculate the needed exponent
00578     float exactExponent = std::log2(deviation) - CC1200_OSC_FREQ_LOG2 + 14;
00579     uint8_t actualExponent = static_cast<uint8_t>(std::min(static_cast<float>(maxValue3Bits), exactExponent));
00580     // note: 14 comes from log2(2^22) - log2(256)
00581 
00582     float exactMantissa;
00583     if(actualExponent >= 1)
00584     {
00585         exactMantissa = (std::pow(2.0f, static_cast<float>(22 - actualExponent)) * deviation)
00586                         / CC1200_OSC_FREQ - 256;
00587     }
00588     else
00589     {
00590         // use alternate high-resolution formula for case where exponent = 0
00591         exactMantissa = deviation * twoToThe21 / CC1200_OSC_FREQ;
00592     }
00593 
00594     // now calculate closest mantissa
00595     uint8_t actualMantissa = static_cast<uint8_t>(std::min(static_cast<float>(maxValue8Bits), exactMantissa));
00596 
00597     // set exponent and mantissa
00598     writeRegister(Register::DEVIATION_M, actualMantissa);
00599 
00600     uint8_t modcfgDevE = readRegister(Register::MODCFG_DEV_E);
00601     modcfgDevE &= ~(0b111 << MODCFG_DEV_E_DEV_E);
00602     modcfgDevE |= actualExponent << MODCFG_DEV_E_DEV_E;
00603     writeRegister(Register::MODCFG_DEV_E, modcfgDevE);
00604 
00605 #if CC1200_DEBUG
00606     debugStream->printf("Setting FSK deviation, requested +-%.00f Hz, setting DEV_E = 0x%" PRIx8 " DEV_M = 0x%" PRIx8 "\n",
00607             deviation, actualExponent, actualMantissa);
00608 
00609     float actualDeviation;
00610     if(actualExponent == 0)
00611     {
00612         actualDeviation = CC1200_OSC_FREQ * actualMantissa / twoToThe21;
00613     }
00614     else
00615     {
00616         actualDeviation = (CC1200_OSC_FREQ / twoToThe22) * (256.0f + static_cast<float>(actualMantissa)) * pow(2.0f, static_cast<float>(actualExponent));
00617     }
00618     // sanity check: calculate actual deviation
00619     debugStream->printf("This yields an actual deviation of +-%.00f Hz\n", actualDeviation);
00620 #endif
00621 }
00622 
00623 void CC1200::setSymbolRate(float symbolRateHz)
00624 {
00625     // Datasheet says that the cc1200 works in ksps, but testing with SmartRF studio
00626     // shows that it actually is sps.
00627 
00628     symbolRateSps = symbolRateHz;
00629 
00630     // Note: these equations are given on page 29 of the user guide
00631 
00632     float exactExponent = std::log2(symbolRateSps) - CC1200_OSC_FREQ_LOG2 + 19;
00633     // note: 19 comes from log2(2^39) - 20
00634     uint8_t actualExponent = static_cast<uint8_t>(std::min(static_cast<float>(maxValue4Bits), exactExponent));
00635 
00636     float exactMantissa;
00637     if(actualExponent >= 1)
00638     {
00639         exactMantissa = (std::pow(2.0f, static_cast<float>(39 - actualExponent)) * symbolRateSps)
00640           / CC1200_OSC_FREQ - twoToThe20;
00641     }
00642     else
00643     {
00644         // use alternate high-resolution formula for case where exponent = 0
00645         exactMantissa = symbolRateSps * twoToThe38 / CC1200_OSC_FREQ;
00646     }
00647 
00648     // mantissa is a 20 bit number, so restrict it to that domain
00649     uint32_t actualMantissa = static_cast<uint32_t>(std::min(static_cast<float>(maxValue20Bits), exactMantissa));
00650 
00651     // program symbol rate registers
00652     std::array<uint8_t, 3> symbolRateRegisters ={
00653             static_cast<uint8_t>((actualExponent << SYMBOL_RATE2_SRATE_E) | (static_cast<uint8_t>((actualMantissa >> 16) & 0xFF) << SYMBOL_RATE2_SRATE_M_19_16)),
00654             static_cast<uint8_t>((actualMantissa >> 8) & 0xFF),
00655             static_cast<uint8_t>((actualMantissa & 0xFF))
00656     };
00657     writeRegisters(Register::SYMBOL_RATE2, symbolRateRegisters);
00658 
00659     // Calculate upsampler value according to the formula in its register description
00660     float upsamplingFactor = CC1200_OSC_FREQ / (64 * symbolRateSps); // 2^upsamplerPVal needs to be less than this value
00661     uint8_t upsamplerPVal = std::floor(std::log2(upsamplingFactor));
00662 
00663     // prevent low sampling rates from choosing a nonexistent upsampling
00664     upsamplerPVal = std::min<uint8_t>(upsamplerPVal, 0b110);
00665 
00666     uint8_t mdmcfg2 = readRegister(ExtRegister::MDMCFG2);
00667     mdmcfg2 &= ~(0b111 << MDMCFG2_UPSAMPLER_P);
00668     mdmcfg2 |= (upsamplerPVal << MDMCFG2_UPSAMPLER_P);
00669 
00670     writeRegister(ExtRegister::MDMCFG2, mdmcfg2);
00671 
00672 #if CC1200_DEBUG
00673     debugStream->printf("Setting symbol rate, requested %.03f Hz, setting SRATE_E = 0x%" PRIx8 " SRATE_M = 0x%" PRIx32 "\n",
00674                         symbolRateHz, actualExponent, actualMantissa);
00675 
00676     // sanity check: calculate actual symbol rate
00677     float actualSymbolRateSps;
00678     if(actualExponent == 0)
00679     {
00680         actualSymbolRateSps = (static_cast<float>(actualMantissa) * CC1200_OSC_FREQ) / twoToThe38;
00681     }
00682     else
00683     {
00684 
00685         actualSymbolRateSps = ((static_cast<float>(actualMantissa) + twoToThe20) *
00686                                pow(2.0f,static_cast<float>(actualExponent)) * CC1200_OSC_FREQ)
00687                               / twoToThe39;
00688     }
00689 
00690     debugStream->printf("This yields an actual symbol rate of %.02f Hz\n", actualSymbolRateSps);
00691 
00692     uint8_t actualUpsampling = static_cast<uint8_t>(pow(2.0f, static_cast<float>(upsamplerPVal)));
00693     debugStream->printf("Also setting upsampling factor to %" PRIu8 " via UPSAMPLER_P = %" PRIx8 "\n", actualUpsampling, upsamplerPVal);
00694 #endif
00695 }
00696 
00697 // helper function for power setting
00698 inline uint8_t dBPowerToRegValue(float powerDB)
00699 {
00700     const float minOutputPower = -16.0f;
00701 
00702     // note: datasheet says this is 14.5, but that must be a mistake: 14.5 would produce a number
00703     // too large to fit into 6 bits.
00704     const float maxOutputPower = 14.0f;
00705 
00706     // clamp output power into correct range
00707     powerDB = std::min(powerDB, maxOutputPower);
00708     powerDB = std::max(powerDB, minOutputPower);
00709 
00710     // this equation derived from user guide section 7.1
00711     float exactPowerRamp = (2 * powerDB) + 35;
00712     return static_cast<uint8_t>(exactPowerRamp); // round to nearest
00713 }
00714 
00715 void CC1200::setOutputPower(float outPower)
00716 {
00717     uint8_t actualPowerRamp = dBPowerToRegValue(outPower);
00718 
00719     uint8_t paCfg1 = readRegister(Register::PA_CFG1);
00720     paCfg1 &= ~(0b111111 << PA_CFG1_PA_POWER_RAMP);
00721     paCfg1 |= actualPowerRamp << PA_CFG1_PA_POWER_RAMP;
00722     writeRegister(Register::PA_CFG1, paCfg1);
00723 
00724 #if CC1200_DEBUG
00725     debugStream->printf("Output power set to %.01f dBm\n", outPower);
00726 #endif
00727 }
00728 
00729 const float CC1200::ASK_MIN_POWER_OFF = -17.5f;
00730 
00731 void CC1200::setASKPowers(float maxPower, float minPower)
00732 {
00733     uint8_t maxPowerValue = dBPowerToRegValue(maxPower);
00734 
00735     minPower = std::min(minPower, maxPower);
00736     minPower = std::max(minPower, -17.5f);
00737 
00738     // calculate min power using formula derived from manual
00739     uint8_t minPowerValue = static_cast<uint8_t>((maxPower - minPower) * 2);
00740 
00741     // write registers
00742     uint8_t paCfg1 = readRegister(Register::PA_CFG1);
00743     paCfg1 &= ~(0b111111 << PA_CFG1_PA_POWER_RAMP);
00744     paCfg1 |= maxPowerValue << PA_CFG1_PA_POWER_RAMP;
00745     writeRegister(Register::PA_CFG1, paCfg1);
00746 
00747     uint8_t askCfg = readRegister(Register::ASK_CFG);
00748     askCfg &= ~(0b111111 << ASK_CFG_ASK_DEPTH);
00749     askCfg |= minPowerValue << ASK_CFG_ASK_DEPTH;
00750     writeRegister(Register::ASK_CFG, askCfg);
00751 }
00752 
00753 void CC1200::setRadioFrequency(CC1200::Band band, float frequencyHz)
00754 {
00755     // Frequency synthesizer configuration.  This is completely opaque and it is unknown what these bits do --
00756     // they are only generated by SmartRF studio.
00757     // I manually deduplicated them since only a few change based on frequency.
00758     writeRegister(ExtRegister::IF_ADC1,0xEE);
00759     writeRegister(ExtRegister::IF_ADC0,0x10);
00760     writeRegister(ExtRegister::FS_DIG1,0x04);
00761     writeRegister(ExtRegister::FS_CAL1,0x40);
00762     writeRegister(ExtRegister::FS_CAL0,0x0E);
00763     writeRegister(ExtRegister::FS_DIVTWO,0x03);
00764     writeRegister(ExtRegister::FS_DSM0,0x33);
00765     writeRegister(ExtRegister::FS_DVC1,0xF7);
00766     writeRegister(ExtRegister::FS_PFD,0x00);
00767     writeRegister(ExtRegister::FS_PRE,0x6E);
00768     writeRegister(ExtRegister::FS_REG_DIV_CML,0x1C);
00769     writeRegister(ExtRegister::FS_SPARE,0xAC);
00770     writeRegister(ExtRegister::FS_VCO0,0xB5);
00771     writeRegister(ExtRegister::XOSC5,0x0E);
00772     writeRegister(ExtRegister::XOSC1,0x03);
00773     if(band == Band::BAND_820_960MHz)
00774     {
00775         writeRegister(ExtRegister::FS_DIG0,0x55);
00776         writeRegister(ExtRegister::FS_DVC0,0x17);
00777         writeRegister(ExtRegister::IFAMP,0x09);
00778     }
00779     else if(band == Band::BAND_410_480MHz)
00780     {
00781         writeRegister(ExtRegister::FS_DIG0,0xA3);
00782         writeRegister(ExtRegister::FS_DVC0,0x0F);
00783         writeRegister(ExtRegister::IFAMP,0x0D);
00784     }
00785     else if(band == Band::BAND_164_192MHz)
00786     {
00787         writeRegister(ExtRegister::FS_DIG0,0x50);
00788         writeRegister(ExtRegister::FS_DVC0,0x0F);
00789         writeRegister(ExtRegister::IFAMP,0x0D);
00790     }
00791     else
00792     {
00793         // TI doesn't make settings public for the other radio bands.
00794         // Let's take a guess and use the 164-192MHz values.
00795         writeRegister(ExtRegister::FS_DIG0,0x50);
00796         writeRegister(ExtRegister::FS_DVC0,0x0F);
00797         writeRegister(ExtRegister::IFAMP,0x0D);
00798     }
00799 
00800     // convert band to LO Divider value.
00801     // Most of the bands just multiply the register value by 2, but nooo, not BAND_136_160MHz.
00802     uint8_t loDividerValue;
00803     if(band == Band::BAND_136_160MHz)
00804     {
00805         loDividerValue = 24;
00806     }
00807     else
00808     {
00809         loDividerValue = static_cast<uint8_t>(band) * 2;
00810     }
00811 
00812     // program band (also enable FS out of lock detector, which is useful for testing)
00813     writeRegister(Register::FS_CFG, (1 << FS_CFG_FS_LOCK_EN) | (static_cast<uint8_t>(band) << FS_CFG_FSD_BANDSELECT));
00814 
00815     // equation derived from user guide section 9.12
00816     float exactFreqRegValue = (twoToThe16 * frequencyHz * static_cast<float>(loDividerValue)) / CC1200_OSC_FREQ;
00817     uint32_t actualFreqRegValue = static_cast<uint32_t>(std::min(static_cast<float>(maxValue24Bits), exactFreqRegValue));
00818 
00819     // program frequency registers
00820     std::array<uint8_t, 3> freqRegisters ={
00821             static_cast<uint8_t>((actualFreqRegValue >> 16) & 0xFF),
00822             static_cast<uint8_t>((actualFreqRegValue >> 8) & 0xFF),
00823             static_cast<uint8_t>((actualFreqRegValue & 0xFF))
00824     };
00825     writeRegisters(ExtRegister::FREQ2, freqRegisters);
00826 
00827     // sanity check: calculate actual frequency
00828     radioFreqHz = (static_cast<float>(actualFreqRegValue) * CC1200_OSC_FREQ) / (twoToThe16 * static_cast<float>(loDividerValue));
00829 
00830 #if CC1200_DEBUG
00831     debugStream->printf("Setting radio frequency, requested %.00f Hz, setting FREQ = 0x%" PRIx32 "\n",
00832                         frequencyHz, actualFreqRegValue);
00833     debugStream->printf("This yields an actual frequency of %.00f Hz\n", radioFreqHz);
00834 #endif
00835 }
00836 
00837 // helper function for setRXFilterBandwidth:
00838 // calculate actual receive bandwidth from the given decimations.
00839 float calcReceiveBandwidth(uint8_t adcDecimation, uint8_t cicDecimation)
00840 {
00841     return CC1200_OSC_FREQ / (static_cast<float>(adcDecimation) * static_cast<float>(cicDecimation) * 2);
00842 }
00843 
00844 void CC1200::setRXFilterBandwidth(float bandwidthHz, bool preferHigherCICDec)
00845 {
00846     // settings that the chip supports
00847     const uint8_t possibleADCDecimations[] = {12, 24, 48}; // indexes in this array represent the register value
00848     const size_t numADCDecimations = sizeof(possibleADCDecimations) / sizeof(uint8_t);
00849     const uint8_t minBBDecimation = 1;
00850 
00851     // maximum supported BB decimation based on ADC decimation varies based on chip
00852     const uint8_t maxBBDecimations1201[] = {33, 16, 8};
00853     const uint8_t maxBBDecimations1200[] = {44, 44, 44};
00854     uint8_t const * maxBBDecimations = isCC1201 ? maxBBDecimations1201 : maxBBDecimations1200;
00855 
00856     // the datasheet suggests to use the highest possible ADC decimation factor that will work for the requested frequency.
00857     // So, we compute the closest we can get with each ADC decimation, and if there's a tie, we choose the one with the higher ADC bandwidth
00858 
00859     uint8_t actualBBDecimations[numADCDecimations];
00860 
00861     for(size_t adcDecimationIndex = 0; adcDecimationIndex < numADCDecimations; ++adcDecimationIndex)
00862     {
00863         uint8_t adcDecimation = possibleADCDecimations[adcDecimationIndex];
00864 
00865         // calculate BB decimation closest to the requested frequency
00866         // derived from formula in section 6.1
00867         float exactBBDecimation = CC1200_OSC_FREQ / (2 * bandwidthHz * static_cast<float>(adcDecimation));
00868         exactBBDecimation = std::max(exactBBDecimation, static_cast<float>(minBBDecimation));
00869         exactBBDecimation = std::min(exactBBDecimation, static_cast<float>(maxBBDecimations[adcDecimationIndex]));
00870 
00871         actualBBDecimations[adcDecimationIndex] = static_cast<uint8_t>(exactBBDecimation);
00872     }
00873 
00874     // now, choose the best of the ones we calculated
00875     uint8_t bestDecimationIndex = 0;
00876     float bestDecimationError = std::abs(bandwidthHz - calcReceiveBandwidth(possibleADCDecimations[0], actualBBDecimations[0]));
00877 
00878     for(size_t adcDecimationIndex = 1; adcDecimationIndex < numADCDecimations; ++adcDecimationIndex)
00879     {
00880         float thisDecimationError = std::abs(bandwidthHz -
00881                 calcReceiveBandwidth(possibleADCDecimations[adcDecimationIndex], actualBBDecimations[adcDecimationIndex]));
00882         if((preferHigherCICDec && thisDecimationError <= bestDecimationError) || (!preferHigherCICDec && thisDecimationError < bestDecimationError))
00883         {
00884             bestDecimationError = thisDecimationError;
00885             bestDecimationIndex = adcDecimationIndex;
00886         }
00887     }
00888 
00889     // now use the best value!
00890     uint8_t chanBwValue = (bestDecimationIndex << CHAN_BW_ADC_CIC_DECFACT) | (actualBBDecimations[bestDecimationIndex] << CHAN_BW_BB_CIC_DECFACT);
00891     writeRegister(Register::CHAN_BW, chanBwValue);
00892 
00893     // also set DVGA_GAIN, which depends on bandwidth
00894     uint8_t mdmCfg1Value = readRegister(Register::MDMCFG1);
00895 
00896     mdmCfg1Value &= ~(0b11 << MDMCFG1_DVGA_GAIN);
00897     if(bandwidthHz >= 100000)
00898     {
00899         mdmCfg1Value |= 1 << MDMCFG1_DVGA_GAIN;
00900     }
00901 
00902     writeRegister(Register::MDMCFG1, mdmCfg1Value);
00903 
00904     // also set MDMCFG0.DATA_FILTER_EN, which should be 0b11 iff bandwidth / symbol rate > 10
00905     uint8_t mdmCfg0Val = readRegister(Register::MDMCFG0);
00906 
00907     if(bandwidthHz / symbolRateSps > 10.0f)
00908     {
00909         mdmCfg0Val |= 0b11 << MDMCFG0_DATA_FILTER_EN;
00910     }
00911     else
00912     {
00913         mdmCfg0Val &= ~(0b11 << MDMCFG0_DATA_FILTER_EN);
00914     }
00915 
00916     writeRegister(Register::MDMCFG0, mdmCfg0Val);
00917 
00918     // finally, we need to set RX_CONFIG_LIMITATION.  It's not exactly clear what this does, but its setting changes
00919     // based on the filter BW.
00920     uint8_t syncCfg0Value = readRegister(Register::SYNC_CFG0);
00921 
00922     if(symbolRateSps < bandwidthHz / 2 || bandwidthHz > 1500000)
00923     {
00924         // clear RX_CONFIG_LIMITATION
00925         syncCfg0Value &= ~(1 << SYNC_CFG0_RX_CONFIG_LIMITATION);
00926     }
00927     else
00928     {
00929         // set RX_CONFIG_LIMITATION
00930         syncCfg0Value |= (1 << SYNC_CFG0_RX_CONFIG_LIMITATION);
00931     }
00932 
00933     writeRegister(Register::SYNC_CFG0, syncCfg0Value);
00934 
00935     adcCicDecimation = possibleADCDecimations[bestDecimationIndex];
00936     currentRXFilterBW = calcReceiveBandwidth(possibleADCDecimations[bestDecimationIndex], actualBBDecimations[bestDecimationIndex]);
00937 
00938 #if CC1200_DEBUG
00939     debugStream->printf("Setting BB decimation to %" PRIu8 " and ADC decimation to %" PRIu8 "\n",
00940             actualBBDecimations[bestDecimationIndex], possibleADCDecimations[bestDecimationIndex]);
00941     debugStream->printf("This yields an actual RX filter BW of %.00f\n", currentRXFilterBW);
00942 #endif
00943 }
00944 
00945 void CC1200::configureDCFilter(bool enableAutoFilter, uint8_t settlingCfg, uint8_t cutoffCfg)
00946 {
00947     uint8_t dcfiltCfg = 0;
00948 
00949     if(!enableAutoFilter)
00950     {
00951         // set "freeze coeff" bit
00952         dcfiltCfg |= (1 << DCFILT_CFG_DCFILT_FREEZE_COEFF);
00953     }
00954 
00955     dcfiltCfg |= settlingCfg << DCFILT_CFG_DCFILT_BW_SETTLE;
00956     dcfiltCfg |= cutoffCfg << DCFILT_CFG_DCFILT_BW;
00957 
00958     writeRegister(Register::DCFILT_CFG, dcfiltCfg);
00959 }
00960 
00961 void CC1200::configureSyncWord(uint32_t syncWord, CC1200::SyncMode mode, uint8_t syncThreshold)
00962 {
00963     // program sync word registers
00964     std::array<uint8_t, 4> syncWordRegisters ={
00965             static_cast<uint8_t>((syncWord >> 24) & 0xFF),
00966             static_cast<uint8_t>((syncWord >> 16) & 0xFF),
00967             static_cast<uint8_t>((syncWord >> 8) & 0xFF),
00968             static_cast<uint8_t>(syncWord & 0xFF)
00969     };
00970     writeRegisters(Register::SYNC3, syncWordRegisters);
00971 
00972     // program sync word cfg
00973     writeRegister(Register::SYNC_CFG1, (static_cast<uint8_t>(mode) << SYNC_CFG1_SYNC_MODE) | (syncThreshold << SYNC_CFG1_SYNC_THR));
00974 }
00975 
00976 bool CC1200::isFSLocked()
00977 {
00978     return readRegister(ExtRegister::FSCAL_CTRL) & (1 << FSCAL_CTRL_LOCK);
00979 }
00980 
00981 void CC1200::configurePreamble(uint8_t preambleLengthCfg, uint8_t preambleFormatCfg)
00982 {
00983     uint8_t preambleCfg1 = 0;
00984     preambleCfg1 |= preambleLengthCfg << PREAMBLE_CFG1_NUM_PREAMBLE;
00985     preambleCfg1 |= preambleFormatCfg << PREAMBLE_CFG1_PREAMBLE_WORD;
00986     writeRegister(Register::PREAMBLE_CFG1, preambleCfg1);
00987 
00988 #if CC1200_DEBUG
00989     debugStream->printf("Preamble length CFG set to 0x%" PRIx8 "\n", preambleLengthCfg);
00990 #endif
00991 }
00992 
00993 void CC1200::setPARampRate(uint8_t firstRampLevel, uint8_t secondRampLevel, CC1200::RampTime rampTime)
00994 {
00995     // enable PA ramping
00996     uint8_t paCfg1Val = readRegister(Register::PA_CFG1);
00997     paCfg1Val |= 1 << PA_CFG1_PA_RAMP_SHAPE_EN;
00998     writeRegister(Register::PA_CFG1, paCfg1Val);
00999 
01000     // configure properties
01001     uint8_t paCfg0Val = 0;
01002     paCfg0Val |= (firstRampLevel << PA_CFG0_FIRST_IPL);
01003     paCfg0Val |= (secondRampLevel << PA_CFG0_SECOND_IPL);
01004     paCfg0Val |= (static_cast<uint8_t>(rampTime) << PA_CFG0_RAMP_SHAPE);
01005 
01006     writeRegister(Register::PA_CFG0, paCfg0Val);
01007 }
01008 
01009 void CC1200::disablePARamping()
01010 {
01011     uint8_t paCfg1Val = readRegister(Register::PA_CFG1);
01012     paCfg1Val &= ~(1 << PA_CFG1_PA_RAMP_SHAPE_EN);
01013     writeRegister(Register::PA_CFG1, paCfg1Val);
01014 }
01015 
01016 void CC1200::setAGCReferenceLevel(uint8_t level)
01017 {
01018     writeRegister(Register::AGC_REF, level);
01019 }
01020 
01021 void CC1200::setAGCSyncBehavior(CC1200::SyncBehavior behavior)
01022 {
01023     uint8_t agcCfg3Val = readRegister(Register::AGC_CFG3);
01024     agcCfg3Val &= ~(0b111 << AGC_CFG3_AGC_SYNC_BEHAVIOUR);
01025     agcCfg3Val |= static_cast<uint8_t>(behavior) << AGC_CFG3_AGC_SYNC_BEHAVIOUR;
01026     writeRegister(Register::AGC_CFG3, agcCfg3Val);
01027 }
01028 
01029 void CC1200::setAGCGainTable(CC1200::GainTable table, uint8_t minGainIndex, uint8_t maxGainIndex)
01030 {
01031     uint8_t agcCfg3Val = readRegister(Register::AGC_CFG3);
01032     uint8_t agcCfg2Val = readRegister(Register::AGC_CFG2);
01033 
01034     agcCfg3Val &= ~(0b11111 << AGC_CFG3_AGC_MIN_GAIN);
01035     agcCfg2Val &= ~(0b11 << AGC_CFG2_FE_PERFORMANCE_MODE);
01036     agcCfg2Val &= ~(0b11111 << AGC_CFG2_AGC_MAX_GAIN);
01037 
01038     agcCfg3Val |= minGainIndex << AGC_CFG3_AGC_MIN_GAIN;
01039     agcCfg2Val |= static_cast<uint8_t>(table) << AGC_CFG2_FE_PERFORMANCE_MODE;
01040     agcCfg2Val |= maxGainIndex << AGC_CFG2_AGC_MAX_GAIN;
01041 
01042     writeRegister(Register::AGC_CFG3, agcCfg3Val);
01043     writeRegister(Register::AGC_CFG2, agcCfg2Val);
01044 }
01045 
01046 void CC1200::setAGCHysteresis(uint8_t hysteresisCfg)
01047 {
01048     uint8_t agcCfg0Val = readRegister(Register::AGC_CFG0);
01049     agcCfg0Val &= ~(0b11 << AGC_CFG0_AGC_HYST_LEVEL);
01050     agcCfg0Val |= hysteresisCfg << AGC_CFG0_AGC_HYST_LEVEL;
01051     writeRegister(Register::AGC_CFG0, agcCfg0Val);
01052 }
01053 
01054 void CC1200::setAGCSlewRate(uint8_t slewrateCfg)
01055 {
01056     uint8_t agcCfg0Val = readRegister(Register::AGC_CFG0);
01057     agcCfg0Val &= ~(0b11 << AGC_CFG0_AGC_SLEWRATE_LIMIT);
01058     agcCfg0Val |= slewrateCfg << AGC_CFG0_AGC_SLEWRATE_LIMIT;
01059     writeRegister(Register::AGC_CFG0, agcCfg0Val);
01060 }
01061 
01062 void CC1200::setAGCSettleWait(uint8_t settleWaitCfg)
01063 {
01064     uint8_t agcCfg1Val = readRegister(Register::AGC_CFG1);
01065     agcCfg1Val &= ~(0b111 << AGC_CFG1_AGC_SETTLE_WAIT);
01066     agcCfg1Val |= (settleWaitCfg << AGC_CFG1_AGC_SETTLE_WAIT);
01067     writeRegister(Register::AGC_CFG1, agcCfg1Val);
01068 }
01069 
01070 float CC1200::getRSSIRegister()
01071 {
01072     uint8_t rssi1Val = readRegister(ExtRegister::RSSI1);
01073     uint8_t rssi0Val = readRegister(ExtRegister::RSSI0);
01074 
01075     if(!(rssi0Val & (1 << RSSI0_RSSI_VALID)))
01076     {
01077         // no valid measurement
01078         return NAN;
01079     }
01080 
01081     // first convert to two's compliment number
01082     int16_t rssiInt = 0;
01083     rssiInt |= (rssi0Val >> RSSI0_RSSI_3_0) & 0b1111;
01084     rssiInt |= rssi1Val << 4;
01085 
01086     if(rssi1Val & 0x80)
01087     {
01088         // negative number, sign extend from 12 to 16 bits
01089         rssiInt |= (0b1111 << 12);
01090     }
01091 
01092     //debugStream->printf("Approx RSSI: %" PRIi8 ", exact RSSI: %f\n", static_cast<int8_t>(rssi1Val), static_cast<float>(rssiInt) * 0.0625f);
01093 
01094     return static_cast<float>(rssiInt) * 0.0625f; // conversion factor given in datasheet
01095 }
01096 
01097 void CC1200::setRSSIOffset(int8_t adjust)
01098 {
01099     writeRegister(Register::AGC_GAIN_ADJUST, static_cast<uint8_t>(adjust));
01100 }
01101 
01102 uint8_t CC1200::getLQIRegister()
01103 {
01104     return readRegister(ExtRegister::LQI_VAL) & 0b1111111;
01105 }
01106 
01107 void CC1200::setIFCfg(IFCfg value, bool enableIQIC)
01108 {
01109     // make sure prerequisites have been run
01110     MBED_ASSERT(radioFreqHz > 0);
01111     MBED_ASSERT(adcCicDecimation > 0 && currentRXFilterBW > 0);
01112 
01113     uint8_t ifMixCfg = readRegister(ExtRegister::IF_MIX_CFG);
01114     ifMixCfg &= ~(0b111 << IF_MIX_CFG_CMIX_CFG);
01115     ifMixCfg |= (static_cast<uint8_t>(value) << IF_MIX_CFG_CMIX_CFG);
01116     writeRegister(ExtRegister::IF_MIX_CFG, ifMixCfg);
01117 
01118     float effectiveIF;
01119 
01120     // calculate effective IF value
01121     if(value == IFCfg::ZERO)
01122     {
01123         effectiveIF = radioFreqHz;
01124     }
01125     else
01126     {
01127         int32_t dividerValue = 0;
01128         switch(value)
01129         {
01130             case IFCfg::NEGATIVE_DIV_4: dividerValue = -4; break;
01131             case IFCfg::NEGATIVE_DIV_6: dividerValue = -6; break;
01132             case IFCfg::NEGATIVE_DIV_8: dividerValue = -8; break;
01133             case IFCfg::POSITIVE_DIV_4: dividerValue = 4; break;
01134             case IFCfg::POSITIVE_DIV_6: dividerValue = 6; break;
01135             case IFCfg::POSITIVE_DIV_8: dividerValue = 8; break;
01136             default: break;
01137         }
01138 
01139         // formula from IF_MIX_CFG register description
01140         effectiveIF = (CC1200_OSC_FREQ / static_cast<float>(adcCicDecimation * dividerValue)) * 1000;
01141     }
01142 
01143     uint8_t iqicValue = readRegister(Register::IQIC);
01144     if(enableIQIC && effectiveIF > currentRXFilterBW)
01145     {
01146         iqicValue |= (1 << IQIC_IQIC_EN);
01147     }
01148     else
01149     {
01150         iqicValue &= ~(1 << IQIC_IQIC_EN);
01151     }
01152     writeRegister(Register::IQIC, iqicValue);
01153 
01154 #if CC1200_DEBUG
01155     debugStream->printf("Setting IF Mix Cfg to 0x%" PRIx8 " and IQIC_EN to %d\n", static_cast<uint8_t>(value),
01156                      !!(iqicValue & (1 << IQIC_IQIC_EN))); // note: double ! used to convert boolean to either 1 or 0.
01157     debugStream->printf("This yields an actual IF of %.00f\n", effectiveIF);
01158 #endif
01159 }
01160 
01161 uint8_t CC1200::readRegister(CC1200::Register reg)
01162 {
01163     spi.select();
01164     loadStatusByte(spi.write(CC1200_READ | static_cast<uint8_t>(reg)));
01165     uint8_t regValue = spi.write(0);
01166     spi.deselect();
01167 
01168 #if CC1200_REGISTER_LEVEL_DEBUG
01169     debugStream->printf("Read register 0x%" PRIx8 " -> 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), regValue);
01170 #endif
01171 
01172     return regValue;
01173 }
01174 
01175 void CC1200::writeRegister(Register reg, uint8_t value)
01176 {
01177     spi.select();
01178     loadStatusByte(spi.write(CC1200_WRITE | static_cast<uint8_t>(reg)));
01179     spi.write(value);
01180     spi.deselect();
01181 
01182 #if CC1200_REGISTER_LEVEL_DEBUG
01183     debugStream->printf("Wrote register 0x%" PRIx8 " <- 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), value);
01184 #endif
01185 }
01186 
01187 void CC1200::writeRegisters(CC1200::Register startReg, uint8_t const *values, size_t numRegisters)
01188 {
01189     spi.select();
01190     loadStatusByte(spi.write(CC1200_WRITE | CC1200_BURST | static_cast<uint8_t>(startReg)));
01191 
01192     for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
01193     {
01194         spi.write(values[byteIndex]);
01195     }
01196     spi.deselect();
01197 
01198 #if CC1200_REGISTER_LEVEL_DEBUG
01199     for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
01200     {
01201         debugStream->printf("Wrote register 0x%" PRIx8 " <- 0x%" PRIx8 "\n",
01202                 static_cast<uint8_t>(static_cast<uint8_t>(startReg) + byteIndex),
01203                 values[byteIndex]);
01204     }
01205 #endif
01206 }
01207 
01208 void CC1200::loadStatusByte(uint8_t status)
01209 {
01210     chipReady = !(status >> 7);
01211     state = static_cast<State>((status >> 4) & 0x7);
01212 
01213 #if CC1200_REGISTER_LEVEL_DEBUG
01214     debugStream->printf("Updated status, state = 0x%" PRIx8 " ready = %s\n", static_cast<uint8_t>(state), chipReady ? "true" : "false");
01215 #endif
01216 }
01217 
01218 uint8_t CC1200::readRegister(CC1200::ExtRegister reg)
01219 {
01220     spi.select();
01221     loadStatusByte(spi.write(CC1200_READ | CC1200_EXT_ADDR));
01222     spi.write(static_cast<uint8_t>(reg));
01223     uint8_t regValue = spi.write(0);
01224     spi.deselect();
01225 
01226 #if CC1200_REGISTER_LEVEL_DEBUG
01227     debugStream->printf("Read ext register 0x%" PRIx8 " -> 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), regValue);
01228 #endif
01229 
01230     return regValue;
01231 }
01232 
01233 void CC1200::writeRegister(CC1200::ExtRegister reg, uint8_t value)
01234 {
01235     spi.select();
01236     loadStatusByte(spi.write(CC1200_WRITE | CC1200_EXT_ADDR));
01237     spi.write(static_cast<uint8_t>(reg));
01238     spi.write(value);
01239     spi.deselect();
01240 
01241 #if CC1200_REGISTER_LEVEL_DEBUG
01242     debugStream->printf("Wrote ext register 0x%" PRIx8 " <- 0x%" PRIx8 "\n", static_cast<uint8_t>(reg), value);
01243 #endif
01244 }
01245 
01246 void CC1200::writeRegisters(CC1200::ExtRegister startReg, uint8_t const *values, size_t numRegisters)
01247 {
01248     spi.select();
01249     loadStatusByte(spi.write(CC1200_WRITE | CC1200_BURST | CC1200_EXT_ADDR));
01250     spi.write(static_cast<uint8_t>(startReg));
01251 
01252     for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
01253     {
01254         spi.write(values[byteIndex]);
01255     }
01256     spi.deselect();
01257 
01258 #if CC1200_REGISTER_LEVEL_DEBUG
01259     for(size_t byteIndex = 0; byteIndex < numRegisters; ++byteIndex)
01260     {
01261         debugStream->printf("Wrote extended register 0x%" PRIx8 " <- 0x%" PRIx8 "\n",
01262                             static_cast<uint8_t>(static_cast<uint8_t>(startReg) + byteIndex),
01263                             values[byteIndex]);
01264     }
01265 #endif
01266 }
01267 
01268 void CC1200::sendCommand(CC1200::Command command)
01269 {
01270     spi.select();
01271     loadStatusByte(spi.write(static_cast<uint8_t>(command)));
01272     spi.deselect();
01273 
01274 #if CC1200_REGISTER_LEVEL_DEBUG
01275     debugStream->printf("Sent SPI command 0x%" PRIx8 "\n", static_cast<uint8_t>(command));
01276 #endif
01277 }
01278 
01279 uint8_t CC1200::readRXFIFOByte(uint8_t address)
01280 {
01281     spi.select();
01282     loadStatusByte(spi.write(CC1200_READ | CC1200_MEM_ACCESS));
01283     spi.write(CC1200_RX_FIFO | address);
01284     int value = spi.write(0);
01285     spi.deselect();
01286 
01287 #if CC1200_REGISTER_LEVEL_DEBUG
01288     debugStream->printf("Read RX FIFO[0x%" PRIx8 "]: 0x%x 0x%x -> 0x%" PRIx8 "\n", static_cast<uint8_t>(address), CC1200_READ | CC1200_MEM_ACCESS, CC1200_RX_FIFO | address, value);
01289 #endif
01290 
01291     return value;
01292 }