#include "SX1272.h" #include #if !RADIOLIB_EXCLUDE_SX127X SX1272::SX1272(Module* mod) : SX127x(mod) { } int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part uint8_t version = RADIOLIB_SX1272_CHIP_VERSION; int16_t state = SX127x::begin(&version, 1, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setBandwidth(bw); RADIOLIB_ASSERT(state); state = setFrequency(freq); RADIOLIB_ASSERT(state); state = setSpreadingFactor(sf); RADIOLIB_ASSERT(state); state = setCodingRate(cr); RADIOLIB_ASSERT(state); state = setOutputPower(power); RADIOLIB_ASSERT(state); state = setGain(gain); RADIOLIB_ASSERT(state); // set publicly accessible settings that are not a part of begin method state = setCRC(true); RADIOLIB_ASSERT(state); return(state); } int16_t SX1272::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part uint8_t version = RADIOLIB_SX1272_CHIP_VERSION; int16_t state = SX127x::beginFSK(&version, 1, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure settings not accessible by API state = configFSK(); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); RADIOLIB_ASSERT(state); state = setBitRate(br); RADIOLIB_ASSERT(state); state = setOutputPower(power); RADIOLIB_ASSERT(state); if(enableOOK) { state = setDataShapingOOK(RADIOLIB_SHAPING_NONE); RADIOLIB_ASSERT(state); } else { state = setDataShaping(RADIOLIB_SHAPING_NONE); RADIOLIB_ASSERT(state); } // set publicly accessible settings that are not a part of begin method state = setCRC(true); RADIOLIB_ASSERT(state); return(state); } void SX1272::reset() { Module* mod = this->getMod(); mod->hal->pinMode(mod->getRst(), mod->hal->GpioModeOutput); mod->hal->digitalWrite(mod->getRst(), mod->hal->GpioLevelHigh); mod->hal->delay(1); mod->hal->digitalWrite(mod->getRst(), mod->hal->GpioLevelLow); mod->hal->delay(5); } int16_t SX1272::setFrequency(float freq) { RADIOLIB_CHECK_RANGE(freq, 860.0f, 1020.0f, RADIOLIB_ERR_INVALID_FREQUENCY); // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); if(state == RADIOLIB_ERR_NONE) { SX127x::frequency = freq; } return(state); } int16_t SX1272::setBandwidth(float bw) { // check active modem if(getActiveModem() != RADIOLIB_SX127X_LORA) { return(RADIOLIB_ERR_WRONG_MODEM); } uint8_t newBandwidth; // check allowed bandwidth values if(fabsf(bw - 125.0f) <= 0.001f) { newBandwidth = RADIOLIB_SX1272_BW_125_00_KHZ; } else if(fabsf(bw - 250.0f) <= 0.001f) { newBandwidth = RADIOLIB_SX1272_BW_250_00_KHZ; } else if(fabsf(bw - 500.0f) <= 0.001f) { newBandwidth = RADIOLIB_SX1272_BW_500_00_KHZ; } else { return(RADIOLIB_ERR_INVALID_BANDWIDTH); } // set bandwidth and if successful, save the new setting int16_t state = SX1272::setBandwidthRaw(newBandwidth); if(state == RADIOLIB_ERR_NONE) { SX127x::bandwidth = bw; // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; Module* mod = this->getMod(); if(symbolLength >= 16.0f) { state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); } } } return(state); } int16_t SX1272::setSpreadingFactor(uint8_t sf) { // check active modem if(getActiveModem() != RADIOLIB_SX127X_LORA) { return(RADIOLIB_ERR_WRONG_MODEM); } uint8_t newSpreadingFactor; // check allowed spreading factor values switch(sf) { case 6: newSpreadingFactor = RADIOLIB_SX127X_SF_6; break; case 7: newSpreadingFactor = RADIOLIB_SX127X_SF_7; break; case 8: newSpreadingFactor = RADIOLIB_SX127X_SF_8; break; case 9: newSpreadingFactor = RADIOLIB_SX127X_SF_9; break; case 10: newSpreadingFactor = RADIOLIB_SX127X_SF_10; break; case 11: newSpreadingFactor = RADIOLIB_SX127X_SF_11; break; case 12: newSpreadingFactor = RADIOLIB_SX127X_SF_12; break; default: return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR); } // set spreading factor and if successful, save the new setting int16_t state = SX1272::setSpreadingFactorRaw(newSpreadingFactor); if(state == RADIOLIB_ERR_NONE) { SX127x::spreadingFactor = sf; // calculate symbol length and set low data rate optimization, if auto-configuration is enabled if(this->ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth; Module* mod = this->getMod(); if(symbolLength >= 16.0f) { state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); } else { state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); } } } return(state); } int16_t SX1272::setCodingRate(uint8_t cr) { // check active modem if(getActiveModem() != RADIOLIB_SX127X_LORA) { return(RADIOLIB_ERR_WRONG_MODEM); } uint8_t newCodingRate; // check allowed coding rate values switch(cr) { case 5: newCodingRate = RADIOLIB_SX1272_CR_4_5; break; case 6: newCodingRate = RADIOLIB_SX1272_CR_4_6; break; case 7: newCodingRate = RADIOLIB_SX1272_CR_4_7; break; case 8: newCodingRate = RADIOLIB_SX1272_CR_4_8; break; default: return(RADIOLIB_ERR_INVALID_CODING_RATE); } // set coding rate and if successful, save the new setting int16_t state = SX1272::setCodingRateRaw(newCodingRate); if(state == RADIOLIB_ERR_NONE) { SX127x::codingRate = cr; } return(state); } int16_t SX1272::setBitRate(float br) { return(SX127x::setBitRateCommon(br, RADIOLIB_SX1272_REG_BIT_RATE_FRAC)); } int16_t SX1272::setDataRate(DataRate_t dr) { int16_t state = RADIOLIB_ERR_UNKNOWN; // select interpretation based on active modem uint8_t modem = this->getActiveModem(); if(modem == RADIOLIB_SX127X_FSK_OOK) { // set the bit rate state = this->setBitRate(dr.fsk.bitRate); RADIOLIB_ASSERT(state); // set the frequency deviation state = this->setFrequencyDeviation(dr.fsk.freqDev); } else if(modem == RADIOLIB_SX127X_LORA) { // set the spreading factor state = this->setSpreadingFactor(dr.lora.spreadingFactor); RADIOLIB_ASSERT(state); // set the bandwidth state = this->setBandwidth(dr.lora.bandwidth); RADIOLIB_ASSERT(state); // set the coding rate state = this->setCodingRate(dr.lora.codingRate); } return(state); } int16_t SX1272::checkDataRate(DataRate_t dr) { int16_t state = RADIOLIB_ERR_UNKNOWN; // select interpretation based on active modem int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_FSK_OOK) { RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE); if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) { return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION); } return(RADIOLIB_ERR_NONE); } else if(modem == RADIOLIB_SX127X_LORA) { RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR); RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 100.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH); RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE); return(RADIOLIB_ERR_NONE); } return(state); } int16_t SX1272::setOutputPower(int8_t power) { return(this->setOutputPower(power, false)); } int16_t SX1272::setOutputPower(int8_t power, bool forceRfo) { // check if power value is configurable bool useRfo = (power < 2) || forceRfo; int16_t state = checkOutputPower(power, NULL, useRfo); RADIOLIB_ASSERT(state); // set mode to standby state = SX127x::standby(); Module* mod = this->getMod(); if(useRfo) { // RFO output state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power + 1), 3, 0); state |= mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); } else { if(power <= 17) { // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power - 2), 3, 0); state |= mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0); } else { // power is 18 - 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, (power - 5), 3, 0); state |= mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0); } } return(state); } int16_t SX1272::checkOutputPower(int8_t power, int8_t* clipped) { return(checkOutputPower(power, clipped, false)); } int16_t SX1272::checkOutputPower(int8_t power, int8_t* clipped, bool useRfo) { // check allowed power range if(useRfo) { if(clipped) { *clipped = RADIOLIB_MAX(-1, RADIOLIB_MIN(14, power)); } RADIOLIB_CHECK_RANGE(power, -1, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER); } else { if(clipped) { *clipped = RADIOLIB_MAX(2, RADIOLIB_MIN(20, power)); } RADIOLIB_CHECK_RANGE(power, 2, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER); } return(RADIOLIB_ERR_NONE); } int16_t SX1272::setGain(uint8_t gain) { // check allowed range if(gain > 6) { return(RADIOLIB_ERR_INVALID_GAIN); } // set mode to standby int16_t state = SX127x::standby(); Module* mod = this->getMod(); // get modem int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { // set gain if(gain == 0) { // gain set to 0, enable AGC loop state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_AGC_AUTO_ON, 2, 2); } else { state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1272_AGC_AUTO_OFF, 2, 2); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // set gain if(gain == 0) { // gain set to 0, enable AGC loop state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); } else { state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON); } } return(state); } int16_t SX1272::setDataShaping(uint8_t sh) { // check active modem if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { return(RADIOLIB_ERR_WRONG_MODEM); } // check modulation if(SX127x::ookEnabled) { return(RADIOLIB_ERR_INVALID_MODULATION); } // set mode to standby int16_t state = SX127x::standby(); RADIOLIB_ASSERT(state); // set data shaping Module* mod = this->getMod(); switch(sh) { case RADIOLIB_SHAPING_NONE: return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_NO_SHAPING, 4, 3)); case RADIOLIB_SHAPING_0_3: return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_0_3, 4, 3)); case RADIOLIB_SHAPING_0_5: return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_0_5, 4, 3)); case RADIOLIB_SHAPING_1_0: return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_FSK_GAUSSIAN_1_0, 4, 3)); default: return(RADIOLIB_ERR_INVALID_DATA_SHAPING); } } int16_t SX1272::setDataShapingOOK(uint8_t sh) { // check active modem if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) { return(RADIOLIB_ERR_WRONG_MODEM); } // check modulation if(!SX127x::ookEnabled) { return(RADIOLIB_ERR_INVALID_MODULATION); } // set mode to standby int16_t state = SX127x::standby(); // set data shaping Module* mod = this->getMod(); switch(sh) { case 0: state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_NO_SHAPING, 4, 3); break; case 1: state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_OOK_FILTER_BR, 4, 3); break; case 2: state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX1272_OOK_FILTER_2BR, 4, 3); break; default: state = RADIOLIB_ERR_INVALID_DATA_SHAPING; break; } return(state); } float SX1272::getRSSI() { return(SX1272::getRSSI(true, false)); } float SX1272::getRSSI(bool packet, bool skipReceive) { return(SX127x::getRSSI(packet, skipReceive, -139)); } int16_t SX1272::setCRC(bool enable, bool mode) { Module* mod = this->getMod(); if(getActiveModem() == RADIOLIB_SX127X_LORA) { // set LoRa CRC SX127x::crcEnabled = enable; if(enable) { return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_RX_CRC_MODE_ON, 1, 1)); } else { return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_RX_CRC_MODE_OFF, 1, 1)); } } else { // set FSK CRC int16_t state = RADIOLIB_ERR_NONE; if(enable) { state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4); } else { state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4); } RADIOLIB_ASSERT(state); // set FSK CRC mode if(mode) { return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0)); } else { return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0)); } } } int16_t SX1272::forceLDRO(bool enable) { if(getActiveModem() != RADIOLIB_SX127X_LORA) { return(RADIOLIB_ERR_WRONG_MODEM); } this->ldroAuto = false; Module* mod = this->getMod(); if(enable) { return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_ON, 0, 0)); } else { return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0)); } } int16_t SX1272::autoLDRO() { if(getActiveModem() != RADIOLIB_SX127X_LORA) { return(RADIOLIB_ERR_WRONG_MODEM); } this->ldroAuto = true; return(RADIOLIB_ERR_NONE); } int16_t SX1272::implicitHeader(size_t len) { this->implicitHdr = true; return(setHeaderType(RADIOLIB_SX1272_HEADER_IMPL_MODE, 2, len)); } int16_t SX1272::explicitHeader() { this->implicitHdr = false; return(setHeaderType(RADIOLIB_SX1272_HEADER_EXPL_MODE, 2)); } int16_t SX1272::setBandwidthRaw(uint8_t newBandwidth) { // set mode to standby int16_t state = SX127x::standby(); // write register Module* mod = this->getMod(); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 6); return(state); } int16_t SX1272::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { // set mode to standby int16_t state = SX127x::standby(); // write registers Module* mod = this->getMod(); if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) { this->implicitHdr = true; state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_IMPL_MODE | (SX127x::crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6); } else { this->implicitHdr = false; state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1272_HEADER_EXPL_MODE | (SX127x::crcEnabled ? RADIOLIB_SX1272_RX_CRC_MODE_ON : RADIOLIB_SX1272_RX_CRC_MODE_OFF), 2, 1); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12); } return(state); } int16_t SX1272::setCodingRateRaw(uint8_t newCodingRate) { // set mode to standby int16_t state = SX127x::standby(); // write register Module* mod = this->getMod(); state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 5, 3); return(state); } int16_t SX1272::configFSK() { // configure common registers int16_t state = SX127x::configFSK(); RADIOLIB_ASSERT(state); // set fast PLL hop Module* mod = this->getMod(); state = mod->SPIsetRegValue(RADIOLIB_SX1272_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7); return(state); } void SX1272::errataFix(bool rx) { (void)rx; // mitigation of receiver spurious response // see SX1272/73 Errata, section 2.2 for details Module* mod = this->getMod(); mod->SPIsetRegValue(0x31, 0b10000000, 7, 7); } int16_t SX1272::setModem(ModemType_t modem) { switch(modem) { case(ModemType_t::RADIOLIB_MODEM_LORA): { return(this->begin()); } break; case(ModemType_t::RADIOLIB_MODEM_FSK): { return(this->beginFSK()); } break; default: return(RADIOLIB_ERR_WRONG_MODEM); } } #endif