#include "CC1101.h" CC1101::CC1101(Module* module) : PhysicalLayer(CC1101_CRYSTAL_FREQ, CC1101_DIV_EXPONENT) { _mod = module; } int16_t CC1101::begin(float freq, float br, float rxBw, float freqDev) { // set module properties _mod->SPIreadCommand = CC1101_CMD_READ; _mod->SPIwriteCommand = CC1101_CMD_WRITE; _mod->init(USE_SPI, INT_0); // try to find the CC1101 chip uint8_t i = 0; bool flagFound = false; while((i < 10) && !flagFound) { uint8_t version = SPIreadRegister(CC1101_REG_VERSION); if(version == 0x14) { flagFound = true; } else { #ifdef KITELIB_DEBUG Serial.print(F("CC1101 not found! (")); Serial.print(i + 1); Serial.print(F(" of 10 tries) CC1101_REG_VERSION == ")); char buffHex[7]; sprintf(buffHex, "0x%04X", version); Serial.print(buffHex); Serial.print(F(", expected 0x0014")); Serial.println(); #endif delay(1000); i++; } } if(!flagFound) { DEBUG_PRINTLN_STR("No CC1101 found!"); SPI.end(); return(ERR_CHIP_NOT_FOUND); } else { DEBUG_PRINTLN_STR("Found CC1101! (match by CC1101_REG_VERSION == 0x14)"); } // configure settings not accessible by API int16_t state = config(); if(state != ERR_NONE) { return(state); } // configure publicly accessible settings state = setFrequency(freq); if(state != ERR_NONE) { return(state); } state = setBitRate(br); if(state != ERR_NONE) { return(state); } state = setRxBandwidth(rxBw); if(state != ERR_NONE) { return(state); } state = setFrequencyDeviation(freqDev); if(state != ERR_NONE) { return(state); } return(state); } int16_t CC1101::transmit(String& str, uint8_t addr) { return(CC1101::transmit(str.c_str())); } int16_t CC1101::transmit(const char* str, uint8_t addr) { return(CC1101::transmit((uint8_t*)str, strlen(str))); } int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { // TODO // check packet length // set GDO0 and GDO2 mapping // set mode to standby return(ERR_NONE); } int16_t CC1101::receive(String& str, size_t len) { // create temporary array to store received data char* data = new char[len + 1]; int16_t state = CC1101::receive((uint8_t*)data, len); // if packet was received successfully, copy data into String if(state == ERR_NONE) { str = String(data); } delete[] data; return(state); } int16_t CC1101::receive(uint8_t* data, size_t len) { // TODO return(ERR_NONE); } int16_t CC1101::standby() { SPIsendCommand(CC1101_CMD_IDLE); return(ERR_NONE); } int16_t CC1101::transmitDirect(uint32_t FRF) { // user requested to start transmitting immediately (required for RTTY) if(FRF != 0) { _mod->SPIwriteRegister(CC1101_REG_FREQ2, (FRF & 0xFF0000) >> 16); _mod->SPIwriteRegister(CC1101_REG_FREQ1, (FRF & 0x00FF00) >> 8); _mod->SPIwriteRegister(CC1101_REG_FREQ0, FRF & 0x0000FF); SPIsendCommand(CC1101_CMD_TX); } // activate direct mode int16_t state = directMode(); if(state != ERR_NONE) { return(state); } // start transmitting SPIsendCommand(CC1101_CMD_TX); return(state); } int16_t CC1101::receiveDirect() { // TODO return(ERR_NONE); } int16_t CC1101::setFrequency(float freq) { // check allowed frequency range if(!(((freq > 300.0) && (freq < 348.0)) || ((freq > 387.0) && (freq < 464.0)) || ((freq > 779.0) && (freq < 928.0)))) { return(ERR_INVALID_FREQUENCY); } // set mode to standby SPIsendCommand(CC1101_CMD_IDLE); //set carrier frequency uint32_t base = 1; uint32_t FRF = (freq * (base << 16)) / 26.0; int16_t state = _mod->SPIsetRegValue(CC1101_REG_FREQ2, (FRF & 0xFF0000) >> 16, 7, 0); state |= _mod->SPIsetRegValue(CC1101_REG_FREQ1, (FRF & 0x00FF00) >> 8, 7, 0); state |= _mod->SPIsetRegValue(CC1101_REG_FREQ0, FRF & 0x0000FF, 7, 0); return(state); } int16_t CC1101::setBitRate(float br) { // check allowed bit rate range if(!((br >= 0.025) && (br <= 600.0))) { return(ERR_INVALID_BIT_RATE); } // set mode to standby SPIsendCommand(CC1101_CMD_IDLE); // calculate exponent and mantisa values uint8_t e = 0; uint8_t m = 0; getExpMant(br * 1000.0, 256, 28, 14, e, m); // set bit rate value int16_t state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG4, e, 3, 0); state |= _mod->SPIsetRegValue(CC1101_REG_MDMCFG3, m); return(state); } int16_t CC1101::setRxBandwidth(float rxBw) { // check allowed bandwidth range if(!((rxBw >= 58) && (rxBw <= 812))) { return(ERR_INVALID_RX_BANDWIDTH); } // set mode to standby SPIsendCommand(CC1101_CMD_IDLE); // calculate exponent and mantisa values for(int8_t e = 3; e >= 0; e--) { for(int8_t m = 3; m >= 0; m --) { float point = (CC1101_CRYSTAL_FREQ * 1000000.0)/(8 * (m + 4) * ((uint32_t)1 << e)); if(abs((rxBw * 1000.0) - point) <= 0.001) { // set Rx channel filter bandwidth return(_mod->SPIsetRegValue(CC1101_REG_MDMCFG4, (e << 6) | (m << 4), 7, 4)); } } } return(ERR_UNKNOWN); } int16_t CC1101::setFrequencyDeviation(float freqDev) { // set frequency deviation to lowest available setting (required for RTTY) if(freqDev == 0.0) { int16_t state = _mod->SPIsetRegValue(CC1101_REG_DEVIATN, 0, 6, 4); state |= _mod->SPIsetRegValue(CC1101_REG_DEVIATN, 0, 2, 0); return(state); } // check allowed frequency deviation range if(!((freqDev >= 1.587) && (freqDev <= 380.8))) { return(ERR_INVALID_FREQUENCY_DEVIATION); } // set mode to standby SPIsendCommand(CC1101_CMD_IDLE); // calculate exponent and mantisa values uint8_t e = 0; uint8_t m = 0; getExpMant(freqDev * 1000.0, 8, 17, 7, e, m); // set frequency deviation value int16_t state = _mod->SPIsetRegValue(CC1101_REG_DEVIATN, (e << 4), 6, 4); state |= _mod->SPIsetRegValue(CC1101_REG_DEVIATN, m, 2, 0); return(state); } int16_t CC1101::config() { // enable autmatic frequency synthesizer calibration int16_t state = _mod->SPIsetRegValue(CC1101_REG_MCSM0, CC1101_FS_AUTOCAL_IDLE_TO_RXTX, 5, 4); return(state); } int16_t CC1101::directMode() { // set mode to standby SPIsendCommand(CC1101_CMD_IDLE); // set GDO0 and GDO2 mapping int16_t state = _mod->SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_SERIAL_CLOCK , 5, 0); state |= _mod->SPIsetRegValue(CC1101_REG_IOCFG2, CC1101_GDOX_SERIAL_DATA_SYNC , 5, 0); // set continuous mode state |= _mod->SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_PKT_FORMAT_SYNCHRONOUS, 5, 4); return(state); } void CC1101::getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8_t expMax, uint8_t& exp, uint8_t& mant) { // get table origin point (exp = 0, mant = 0) float origin = (mantOffset * CC1101_CRYSTAL_FREQ * 1000000.0)/((uint32_t)1 << divExp); // iterate over possible exponent values for(int8_t e = expMax; e >= 0; e--) { // get table column start value (exp = e, mant = 0); float intervalStart = ((uint32_t)1 << e) * origin; // check if target value is in this column if(target >= intervalStart) { // save exponent value exp = e; // calculate size of step between table rows float stepSize = intervalStart/(float)mantOffset; // get target point position (exp = e, mant = m) mant = ((target - intervalStart) / stepSize); // we only need the first match, terminate return; } } } int16_t CC1101::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) { return(_mod->SPIgetRegValue(reg | CC1101_CMD_ACCESS_STATUS_REG, msb, lsb)); } uint8_t CC1101::SPIreadRegister(uint8_t reg) { return(_mod->SPIreadRegister(reg | CC1101_CMD_ACCESS_STATUS_REG)); } void CC1101::SPIsendCommand(uint8_t cmd) { digitalWrite(_mod->getCs(), LOW); SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); SPI.transfer(cmd); SPI.endTransaction(); digitalWrite(_mod->getCs(), HIGH); }