Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of SX1276GenericLib by
sx1276/sx1276.cpp
- Committer:
- Helmut Tschemernjak
- Date:
- 2017-11-12
- Revision:
- 95:36a7fc74e437
- Parent:
- 94:e6c0279f550a
- Child:
- 113:7f132cef611d
File content as of revision 95:36a7fc74e437:
/* / _____) _ | | ( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| (C) 2014 Semtech Description: Actual implementation of a SX1276 radio, inherits Radio License: Revised BSD License, see LICENSE.TXT file include in the project Maintainers: Miguel Luis, Gregory Cristian and Nicolas Huguenin */ /* * additional development to make it more generic across multiple OS versions * (c) 2017 Helmut Tschemernjak * 30826 Garbsen (Hannover) Germany */ #include "sx1276.h" const SX1276::BandwidthMap SX1276::FskBandwidths[] = { { 2600 , 0x17 }, { 3100 , 0x0F }, { 3900 , 0x07 }, { 5200 , 0x16 }, { 6300 , 0x0E }, { 7800 , 0x06 }, { 10400 , 0x15 }, { 12500 , 0x0D }, { 15600 , 0x05 }, { 20800 , 0x14 }, { 25000 , 0x0C }, { 31300 , 0x04 }, { 41700 , 0x13 }, { 50000 , 0x0B }, { 62500 , 0x03 }, { 83333 , 0x12 }, { 100000, 0x0A }, { 125000, 0x02 }, { 166700, 0x11 }, { 200000, 0x09 }, { 250000, 0x01 }, { 300000, 0x00 }, // Invalid Bandwidth }; const SX1276::BandwidthMap SX1276::LoRaBandwidths[] = { { 7800, 0 }, // 7.8 kHz requires TCXO { 10400, 1 }, // 10.4 kHz requires TCXO { 15600, 2 }, // 15.6 kHz requires TCXO { 20800, 3 }, // 20.8 kHz requires TCXO { 31250, 4 }, // 31.25 kHz requires TCXO { 41700, 5 }, // 41.7 kHz requires TCXO { 62500, 6 }, // 62.5 kHz requires TCXO { 125000, 7 }, // 125 kHz the LoRa protocol default { 250000, 8 }, // 250 kHz { 500000, 9 }, // 500 kHz { 600000, 10 }, // Invalid Bandwidth, reserved }; /*! * @brief Radio hardware registers initialization definition * * @remark Can be automatically generated by the SX1276 GUI (not yet implemented) */ const SX1276::RadioRegisters SX1276::RadioRegsInit[] = { { MODEM_FSK , REG_LNA , 0x23 }, { MODEM_FSK , REG_RXCONFIG , 0x1E }, { MODEM_FSK , REG_RSSICONFIG , 0xD2 }, { MODEM_FSK , REG_AFCFEI , 0x01 }, { MODEM_FSK , REG_PREAMBLEDETECT , 0xAA }, { MODEM_FSK , REG_OSC , 0x07 }, { MODEM_FSK , REG_SYNCCONFIG , 0x12 }, { MODEM_FSK , REG_SYNCVALUE1 , 0xC1 }, { MODEM_FSK , REG_SYNCVALUE2 , 0x94 }, { MODEM_FSK , REG_SYNCVALUE3 , 0xC1 }, { MODEM_FSK , REG_PACKETCONFIG1 , 0xD8 }, { MODEM_FSK , REG_FIFOTHRESH , 0x8F }, { MODEM_FSK , REG_IMAGECAL , 0x02 }, { MODEM_FSK , REG_DIOMAPPING1 , 0x00 }, { MODEM_FSK , REG_DIOMAPPING2 , 0x30 }, { MODEM_LORA, REG_LR_PAYLOADMAXLENGTH, 0x40 }, }; SX1276::SX1276( RadioEvents_t *events) : Radio( events ), isRadioActive( false ) { this->rxtxBuffer = new uint8_t[RX_BUFFER_SIZE]; this->RadioEvents = events; this->dioIrq = new DioIrqHandler[6]; this->dioIrq[0] = &SX1276::OnDio0Irq; this->dioIrq[1] = &SX1276::OnDio1Irq; this->dioIrq[2] = &SX1276::OnDio2Irq; this->dioIrq[3] = &SX1276::OnDio3Irq; this->dioIrq[4] = &SX1276::OnDio4Irq; this->dioIrq[5] = NULL; this->settings.State = RF_IDLE; } SX1276::~SX1276( ) { delete this->rxtxBuffer; delete this->dioIrq; } bool SX1276::Init( RadioEvents_t *events ) { if (Read(REG_VERSION) == 0x00) return false; this->RadioEvents = events; return true; } void SX1276::RadioRegistersInit( ) { uint8_t i = 0; for( i = 0; i < sizeof( RadioRegsInit ) / sizeof( RadioRegisters ); i++ ) { SetModem( RadioRegsInit[i].Modem ); Write( RadioRegsInit[i].Addr, RadioRegsInit[i].Value ); } } RadioState SX1276::GetStatus( void ) { return this->settings.State; } void SX1276::SetChannel( uint32_t freq ) { this->settings.Channel = freq; freq = ( uint32_t )( ( double )freq / ( double )FREQ_STEP ); Write( REG_FRFMSB, ( uint8_t )( ( freq >> 16 ) & 0xFF ) ); Write( REG_FRFMID, ( uint8_t )( ( freq >> 8 ) & 0xFF ) ); Write( REG_FRFLSB, ( uint8_t )( freq & 0xFF ) ); } bool SX1276::IsChannelFree( RadioModems_t modem, uint32_t freq, int16_t rssiThresh ) { int16_t rssi = 0; SetModem( modem ); SetChannel( freq ); SetOpMode( RF_OPMODE_RECEIVER ); Sleep_ms( 1 ); rssi = GetRssi( modem ); Sleep( ); if( rssi > rssiThresh ) { return false; } return true; } uint32_t SX1276::Random( void ) { uint8_t i; uint32_t rnd = 0; /* * Radio setup for random number generation */ // Set LoRa modem ON SetModem( MODEM_LORA ); // Disable LoRa modem interrupts Write( REG_LR_IRQFLAGSMASK, RFLR_IRQFLAGS_RXTIMEOUT | RFLR_IRQFLAGS_RXDONE | RFLR_IRQFLAGS_PAYLOADCRCERROR | RFLR_IRQFLAGS_VALIDHEADER | RFLR_IRQFLAGS_TXDONE | RFLR_IRQFLAGS_CADDONE | RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL | RFLR_IRQFLAGS_CADDETECTED ); // Set radio in continuous reception SetOpMode( RF_OPMODE_RECEIVER ); for( i = 0; i < 32; i++ ) { Sleep_ms( 1 ); // Unfiltered RSSI value reading. Only takes the LSB value rnd |= ( ( uint32_t )Read( REG_LR_RSSIWIDEBAND ) & 0x01 ) << i; } Sleep( ); return rnd; } /*! * Performs the Rx chain calibration for LF and HF bands * \remark Must be called just after the reset so all registers are at their * default values */ void SX1276::RxChainCalibration( void ) { uint8_t regPaConfigInitVal; uint32_t initialFreq; // Save context regPaConfigInitVal = this->Read( REG_PACONFIG ); initialFreq = ( double )( ( ( uint32_t )this->Read( REG_FRFMSB ) << 16 ) | ( ( uint32_t )this->Read( REG_FRFMID ) << 8 ) | ( ( uint32_t )this->Read( REG_FRFLSB ) ) ) * ( double )FREQ_STEP; // Cut the PA just in case, RFO output, power = -1 dBm this->Write( REG_PACONFIG, 0x00 ); // Launch Rx chain calibration for LF band Write ( REG_IMAGECAL, ( Read( REG_IMAGECAL ) & RF_IMAGECAL_IMAGECAL_MASK ) | RF_IMAGECAL_IMAGECAL_START ); while( ( Read( REG_IMAGECAL ) & RF_IMAGECAL_IMAGECAL_RUNNING ) == RF_IMAGECAL_IMAGECAL_RUNNING ) { } // Sets a Frequency in HF band SetChannel( 868000000 ); // Launch Rx chain calibration for HF band Write ( REG_IMAGECAL, ( Read( REG_IMAGECAL ) & RF_IMAGECAL_IMAGECAL_MASK ) | RF_IMAGECAL_IMAGECAL_START ); while( ( Read( REG_IMAGECAL ) & RF_IMAGECAL_IMAGECAL_RUNNING ) == RF_IMAGECAL_IMAGECAL_RUNNING ) { } // Restore context this->Write( REG_PACONFIG, regPaConfigInitVal ); SetChannel( initialFreq ); } /*! * Returns the known FSK bandwidth registers value * * \param [IN] bandwidth Bandwidth value in Hz * \retval regValue Bandwidth register value. */ uint8_t SX1276::GetFskBandwidthRegValue( uint32_t bandwidth ) { uint8_t i; for( i = 0; i < ( sizeof( FskBandwidths ) / sizeof( BandwidthMap ) ) - 1; i++ ) { if( ( bandwidth >= FskBandwidths[i].bandwidth ) && ( bandwidth < FskBandwidths[i + 1].bandwidth ) ) { return FskBandwidths[i].RegValue; } } // ERROR: Value not found while( 1 ); } /*! * Returns the known LoRa bandwidth registers value * * \param [IN] bandwidth Bandwidth value in Hz * \retval regValue Bandwidth register value. */ uint8_t SX1276::GetLoRaBandwidthRegValue( uint32_t bandwidth ) { uint8_t i; for( i = 0; i < ( sizeof( LoRaBandwidths ) / sizeof( BandwidthMap ) ) - 1; i++ ) { if( ( bandwidth >= LoRaBandwidths[i].bandwidth ) && ( bandwidth < LoRaBandwidths[i + 1].bandwidth ) ) { return LoRaBandwidths[i].RegValue; } } // ERROR: Value not found while( 1 ); } void SX1276::SetRxConfig( RadioModems_t modem, uint32_t bandwidth, uint32_t datarate, uint8_t coderate, uint32_t bandwidthAfc, uint16_t preambleLen, uint16_t symbTimeout, bool fixLen, uint8_t payloadLen, bool crcOn, bool freqHopOn, uint8_t hopPeriod, bool iqInverted, bool rxContinuous ) { SetModem( modem ); switch( modem ) { case MODEM_FSK: { this->settings.Fsk.Bandwidth = bandwidth; this->settings.Fsk.Datarate = datarate; this->settings.Fsk.BandwidthAfc = bandwidthAfc; this->settings.Fsk.FixLen = fixLen; this->settings.Fsk.PayloadLen = payloadLen; this->settings.Fsk.CrcOn = crcOn; this->settings.Fsk.IqInverted = iqInverted; this->settings.Fsk.RxContinuous = rxContinuous; this->settings.Fsk.PreambleLen = preambleLen; this->settings.Fsk.RxSingleTimeout = symbTimeout * ( ( 1.0 / ( double )datarate ) * 8.0 ) * 1e3; datarate = ( uint16_t )( ( double )XTAL_FREQ / ( double )datarate ); Write( REG_BITRATEMSB, ( uint8_t )( datarate >> 8 ) ); Write( REG_BITRATELSB, ( uint8_t )( datarate & 0xFF ) ); Write( REG_RXBW, GetFskBandwidthRegValue( bandwidth ) ); Write( REG_AFCBW, GetFskBandwidthRegValue( bandwidthAfc ) ); Write( REG_PREAMBLEMSB, ( uint8_t )( ( preambleLen >> 8 ) & 0xFF ) ); Write( REG_PREAMBLELSB, ( uint8_t )( preambleLen & 0xFF ) ); if( fixLen == 1 ) { Write( REG_PAYLOADLENGTH, payloadLen ); } else { Write( REG_PAYLOADLENGTH, 0xFF ); // Set payload length to the maximum } Write( REG_PACKETCONFIG1, ( Read( REG_PACKETCONFIG1 ) & RF_PACKETCONFIG1_CRC_MASK & RF_PACKETCONFIG1_PACKETFORMAT_MASK ) | ( ( fixLen == 1 ) ? RF_PACKETCONFIG1_PACKETFORMAT_FIXED : RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE ) | ( crcOn << 4 ) ); Write( REG_PACKETCONFIG2, ( Read( REG_PACKETCONFIG2 ) | RF_PACKETCONFIG2_DATAMODE_PACKET ) ); } break; case MODEM_LORA: { if (bandwidth > 11) // specified in Hz, needs mapping bandwidth = GetLoRaBandwidthRegValue(bandwidth); if( bandwidth > LORA_BANKWIDTH_500kHz ) { // Fatal error: When using LoRa modem only bandwidths 125, 250 and 500 kHz are supported while( 1 ); } this->settings.LoRa.Bandwidth = bandwidth; this->settings.LoRa.Datarate = datarate; this->settings.LoRa.Coderate = coderate; this->settings.LoRa.PreambleLen = preambleLen; this->settings.LoRa.FixLen = fixLen; this->settings.LoRa.PayloadLen = payloadLen; this->settings.LoRa.CrcOn = crcOn; this->settings.LoRa.FreqHopOn = freqHopOn; this->settings.LoRa.HopPeriod = hopPeriod; this->settings.LoRa.IqInverted = iqInverted; this->settings.LoRa.RxContinuous = rxContinuous; if( datarate > LORA_SF12 ) { datarate = LORA_SF12; } else if( datarate < LORA_SF6 ) { datarate = LORA_SF6; } if( ( ( bandwidth == LORA_BANKWIDTH_125kHz ) && ( ( datarate == LORA_SF11 ) || ( datarate == LORA_SF12 ) ) ) || ( ( bandwidth == LORA_BANKWIDTH_250kHz ) && ( datarate == LORA_SF12 ) ) ) { this->settings.LoRa.LowDatarateOptimize = 0x01; } else { this->settings.LoRa.LowDatarateOptimize = 0x00; } Write( REG_LR_MODEMCONFIG1, ( Read( REG_LR_MODEMCONFIG1 ) & RFLR_MODEMCONFIG1_BW_MASK & RFLR_MODEMCONFIG1_CODINGRATE_MASK & RFLR_MODEMCONFIG1_IMPLICITHEADER_MASK ) | ( bandwidth << 4 ) | ( coderate << 1 ) | fixLen ); Write( REG_LR_MODEMCONFIG2, ( Read( REG_LR_MODEMCONFIG2 ) & RFLR_MODEMCONFIG2_SF_MASK & RFLR_MODEMCONFIG2_RXPAYLOADCRC_MASK & RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK ) | ( datarate << 4 ) | ( crcOn << 2 ) | ( ( symbTimeout >> 8 ) & ~RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK ) ); Write( REG_LR_MODEMCONFIG3, ( Read( REG_LR_MODEMCONFIG3 ) & RFLR_MODEMCONFIG3_LOWDATARATEOPTIMIZE_MASK ) | ( this->settings.LoRa.LowDatarateOptimize << 3 ) ); Write( REG_LR_SYMBTIMEOUTLSB, ( uint8_t )( symbTimeout & 0xFF ) ); Write( REG_LR_PREAMBLEMSB, ( uint8_t )( ( preambleLen >> 8 ) & 0xFF ) ); Write( REG_LR_PREAMBLELSB, ( uint8_t )( preambleLen & 0xFF ) ); if( fixLen == 1 ) { Write( REG_LR_PAYLOADLENGTH, payloadLen ); } if( this->settings.LoRa.FreqHopOn == true ) { Write( REG_LR_PLLHOP, ( Read( REG_LR_PLLHOP ) & RFLR_PLLHOP_FASTHOP_MASK ) | RFLR_PLLHOP_FASTHOP_ON ); Write( REG_LR_HOPPERIOD, this->settings.LoRa.HopPeriod ); } if( ( bandwidth == LORA_BANKWIDTH_500kHz ) && ( this->settings.Channel > RF_MID_BAND_THRESH ) ) { // ERRATA 2.1 - Sensitivity Optimization with a 500 kHz Bandwidth Write( REG_LR_TEST36, 0x02 ); Write( REG_LR_TEST3A, 0x64 ); } else if( bandwidth == LORA_BANKWIDTH_500kHz ) { // ERRATA 2.1 - Sensitivity Optimization with a 500 kHz Bandwidth Write( REG_LR_TEST36, 0x02 ); Write( REG_LR_TEST3A, 0x7F ); } else { // ERRATA 2.1 - Sensitivity Optimization with a 500 kHz Bandwidth Write( REG_LR_TEST36, 0x03 ); } if( datarate == LORA_SF6 ) { Write( REG_LR_DETECTOPTIMIZE, ( Read( REG_LR_DETECTOPTIMIZE ) & RFLR_DETECTIONOPTIMIZE_MASK ) | RFLR_DETECTIONOPTIMIZE_SF6 ); Write( REG_LR_DETECTIONTHRESHOLD, RFLR_DETECTIONTHRESH_SF6 ); } else { Write( REG_LR_DETECTOPTIMIZE, ( Read( REG_LR_DETECTOPTIMIZE ) & RFLR_DETECTIONOPTIMIZE_MASK ) | RFLR_DETECTIONOPTIMIZE_SF7_TO_SF12 ); Write( REG_LR_DETECTIONTHRESHOLD, RFLR_DETECTIONTHRESH_SF7_TO_SF12 ); } } break; } } void SX1276::SetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev, uint32_t bandwidth, uint32_t datarate, uint8_t coderate, uint16_t preambleLen, bool fixLen, bool crcOn, bool freqHopOn, uint8_t hopPeriod, bool iqInverted, uint32_t timeout ) { SetModem( modem ); SetRfTxPower( power ); switch( modem ) { case MODEM_FSK: { this->settings.Fsk.Power = power; this->settings.Fsk.Fdev = fdev; this->settings.Fsk.Bandwidth = bandwidth; this->settings.Fsk.Datarate = datarate; this->settings.Fsk.PreambleLen = preambleLen; this->settings.Fsk.FixLen = fixLen; this->settings.Fsk.CrcOn = crcOn; this->settings.Fsk.IqInverted = iqInverted; this->settings.Fsk.TxTimeout = timeout; fdev = ( uint16_t )( ( double )fdev / ( double )FREQ_STEP ); Write( REG_FDEVMSB, ( uint8_t )( fdev >> 8 ) ); Write( REG_FDEVLSB, ( uint8_t )( fdev & 0xFF ) ); datarate = ( uint16_t )( ( double )XTAL_FREQ / ( double )datarate ); Write( REG_BITRATEMSB, ( uint8_t )( datarate >> 8 ) ); Write( REG_BITRATELSB, ( uint8_t )( datarate & 0xFF ) ); Write( REG_PREAMBLEMSB, ( preambleLen >> 8 ) & 0x00FF ); Write( REG_PREAMBLELSB, preambleLen & 0xFF ); Write( REG_PACKETCONFIG1, ( Read( REG_PACKETCONFIG1 ) & RF_PACKETCONFIG1_CRC_MASK & RF_PACKETCONFIG1_PACKETFORMAT_MASK ) | ( ( fixLen == 1 ) ? RF_PACKETCONFIG1_PACKETFORMAT_FIXED : RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE ) | ( crcOn << 4 ) ); Write( REG_PACKETCONFIG2, ( Read( REG_PACKETCONFIG2 ) | RF_PACKETCONFIG2_DATAMODE_PACKET ) ); } break; case MODEM_LORA: { this->settings.LoRa.Power = power; if (bandwidth > 11) // specified in Hz, needs mapping bandwidth = GetLoRaBandwidthRegValue(bandwidth); if( bandwidth > LORA_BANKWIDTH_500kHz ) { // Fatal error: When using LoRa modem only bandwidths 125, 250 and 500 kHz are supported while( 1 ); } this->settings.LoRa.Bandwidth = bandwidth; this->settings.LoRa.Datarate = datarate; this->settings.LoRa.Coderate = coderate; this->settings.LoRa.PreambleLen = preambleLen; this->settings.LoRa.FixLen = fixLen; this->settings.LoRa.FreqHopOn = freqHopOn; this->settings.LoRa.HopPeriod = hopPeriod; this->settings.LoRa.CrcOn = crcOn; this->settings.LoRa.IqInverted = iqInverted; this->settings.LoRa.TxTimeout = timeout; if( datarate > LORA_SF12 ) { datarate = LORA_SF12; } else if( datarate < LORA_SF6 ) { datarate = LORA_SF6; } if( ( ( bandwidth == LORA_BANKWIDTH_125kHz ) && ( ( datarate == LORA_SF11 ) || ( datarate == LORA_SF12 ) ) ) || ( ( bandwidth == LORA_BANKWIDTH_250kHz ) && ( datarate == LORA_SF12 ) ) ) { this->settings.LoRa.LowDatarateOptimize = 0x01; } else { this->settings.LoRa.LowDatarateOptimize = 0x00; } if( this->settings.LoRa.FreqHopOn == true ) { Write( REG_LR_PLLHOP, ( Read( REG_LR_PLLHOP ) & RFLR_PLLHOP_FASTHOP_MASK ) | RFLR_PLLHOP_FASTHOP_ON ); Write( REG_LR_HOPPERIOD, this->settings.LoRa.HopPeriod ); } Write( REG_LR_MODEMCONFIG1, ( Read( REG_LR_MODEMCONFIG1 ) & RFLR_MODEMCONFIG1_BW_MASK & RFLR_MODEMCONFIG1_CODINGRATE_MASK & RFLR_MODEMCONFIG1_IMPLICITHEADER_MASK ) | ( bandwidth << 4 ) | ( coderate << 1 ) | fixLen ); Write( REG_LR_MODEMCONFIG2, ( Read( REG_LR_MODEMCONFIG2 ) & RFLR_MODEMCONFIG2_SF_MASK & RFLR_MODEMCONFIG2_RXPAYLOADCRC_MASK ) | ( datarate << 4 ) | ( crcOn << 2 ) ); Write( REG_LR_MODEMCONFIG3, ( Read( REG_LR_MODEMCONFIG3 ) & RFLR_MODEMCONFIG3_LOWDATARATEOPTIMIZE_MASK ) | ( this->settings.LoRa.LowDatarateOptimize << 3 ) ); Write( REG_LR_PREAMBLEMSB, ( preambleLen >> 8 ) & 0x00FF ); Write( REG_LR_PREAMBLELSB, preambleLen & 0xFF ); if( datarate == LORA_SF6 ) { Write( REG_LR_DETECTOPTIMIZE, ( Read( REG_LR_DETECTOPTIMIZE ) & RFLR_DETECTIONOPTIMIZE_MASK ) | RFLR_DETECTIONOPTIMIZE_SF6 ); Write( REG_LR_DETECTIONTHRESHOLD, RFLR_DETECTIONTHRESH_SF6 ); } else { Write( REG_LR_DETECTOPTIMIZE, ( Read( REG_LR_DETECTOPTIMIZE ) & RFLR_DETECTIONOPTIMIZE_MASK ) | RFLR_DETECTIONOPTIMIZE_SF7_TO_SF12 ); Write( REG_LR_DETECTIONTHRESHOLD, RFLR_DETECTIONTHRESH_SF7_TO_SF12 ); } } break; } } uint32_t SX1276::TimeOnAir( RadioModems_t modem, int16_t pktLen ) { uint32_t airTime = 0; switch( modem ) { case MODEM_FSK: { airTime = rint( ( 8 * ( this->settings.Fsk.PreambleLen + ( ( Read( REG_SYNCCONFIG ) & ~RF_SYNCCONFIG_SYNCSIZE_MASK ) + 1 ) + ( ( this->settings.Fsk.FixLen == 0x01 ) ? 0.0 : 1.0 ) + ( ( ( Read( REG_PACKETCONFIG1 ) & ~RF_PACKETCONFIG1_ADDRSFILTERING_MASK ) != 0x00 ) ? 1.0 : 0 ) + pktLen + ( ( this->settings.Fsk.CrcOn == 0x01 ) ? 2.0 : 0 ) ) / this->settings.Fsk.Datarate ) * 1e3 ); } break; case MODEM_LORA: { double bw = 0.0; // REMARK: When using LoRa modem only bandwidths 125, 250 and 500 kHz are supported switch( this->settings.LoRa.Bandwidth ) { case LORA_BANKWIDTH_7kHz: // 7.8 kHz bw = 78e2; break; case LORA_BANKWIDTH_10kHz: // 10.4 kHz bw = 104e2; break; case LORA_BANKWIDTH_15kHz: // 15.6 kHz bw = 156e2; break; case LORA_BANKWIDTH_20kHz: // 20.8 kHz bw = 208e2; break; case LORA_BANKWIDTH_31kHz: // 31.25 kHz bw = 312e2; break; case LORA_BANKWIDTH_41kHz: // 41.7 kHz bw = 414e2; break; case LORA_BANKWIDTH_62kHz: // 62.5 kHz bw = 625e2; break; case LORA_BANKWIDTH_125kHz: // 125 kHz bw = 125e3; break; case LORA_BANKWIDTH_250kHz: // 250 kHz bw = 250e3; break; case LORA_BANKWIDTH_500kHz: // 500 kHz bw = 500e3; break; } // Symbol rate : time for one symbol (secs) double rs = bw / ( 1 << this->settings.LoRa.Datarate ); double ts = 1 / rs; // time of preamble double tPreamble = ( this->settings.LoRa.PreambleLen + 4.25 ) * ts; // Symbol length of payload and time double tmp = ceil( ( 8 * pktLen - 4 * this->settings.LoRa.Datarate + 28 + 16 * this->settings.LoRa.CrcOn - ( this->settings.LoRa.FixLen ? 20 : 0 ) ) / ( double )( 4 * ( this->settings.LoRa.Datarate - ( ( this->settings.LoRa.LowDatarateOptimize > 0 ) ? 2 : 0 ) ) ) ) * ( this->settings.LoRa.Coderate + 4 ); double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 ); double tPayload = nPayload * ts; // Time on air double tOnAir = tPreamble + tPayload; // return ms secs airTime = floor( tOnAir * 1e3 + 0.999 ); } break; } return airTime; } void SX1276::Send( void *buffer, int16_t size, void *header, int16_t hsize ) { uint32_t txTimeout = 0; switch( this->settings.Modem ) { case MODEM_FSK: { this->settings.FskPacketHandler.NbBytes = 0; this->settings.FskPacketHandler.Size = size + hsize; if( this->settings.Fsk.FixLen == false ) { uint8_t tmpsize = size + hsize; WriteFifo( ( uint8_t* )&tmpsize, 1 ); } else { Write( REG_PAYLOADLENGTH, size + hsize); } if( ( size + hsize > 0 ) && ( size + hsize <= 64 ) ) { this->settings.FskPacketHandler.ChunkSize = size + hsize; } else { if (header) { WriteFifo( header, hsize ); memcpy( rxtxBuffer, header, hsize ); } memcpy( rxtxBuffer+hsize, (uint8_t *)buffer+hsize, size ); this->settings.FskPacketHandler.ChunkSize = 32; } // Write payload buffer if (header) WriteFifo( header, hsize ); WriteFifo( buffer, this->settings.FskPacketHandler.ChunkSize ); this->settings.FskPacketHandler.NbBytes += this->settings.FskPacketHandler.ChunkSize; txTimeout = this->settings.Fsk.TxTimeout; } break; case MODEM_LORA: { if( this->settings.LoRa.IqInverted == true ) { Write( REG_LR_INVERTIQ, ( ( Read( REG_LR_INVERTIQ ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK ) | RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_ON ) ); Write( REG_LR_INVERTIQ2, RFLR_INVERTIQ2_ON ); } else { Write( REG_LR_INVERTIQ, ( ( Read( REG_LR_INVERTIQ ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK ) | RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_OFF ) ); Write( REG_LR_INVERTIQ2, RFLR_INVERTIQ2_OFF ); } this->settings.LoRaPacketHandler.Size = size + hsize; // Initializes the payload size Write( REG_LR_PAYLOADLENGTH, size + hsize); // Full buffer used for Tx Write( REG_LR_FIFOTXBASEADDR, 0 ); Write( REG_LR_FIFOADDRPTR, 0 ); // FIFO operations can not take place in Sleep mode if( ( Read( REG_OPMODE ) & ~RF_OPMODE_MASK ) == RF_OPMODE_SLEEP ) { Standby( ); Sleep_ms( 1 ); } // Write payload buffer if (header) WriteFifo( header, hsize ); WriteFifo( buffer, size ); txTimeout = this->settings.LoRa.TxTimeout; } break; } Tx( txTimeout ); } void SX1276::Sleep( void ) { SetTimeout(TXTimeoutTimer, NULL); SetTimeout(RXTimeoutTimer, NULL); SetOpMode( RF_OPMODE_SLEEP ); this->settings.State = RF_IDLE; } void SX1276::Standby( void ) { SetTimeout(TXTimeoutTimer, NULL); SetTimeout(RXTimeoutTimer, NULL); SetOpMode( RF_OPMODE_STANDBY ); this->settings.State = RF_IDLE; } void SX1276::Rx( uint32_t timeout ) { bool rxContinuous = false; switch( this->settings.Modem ) { case MODEM_FSK: { rxContinuous = this->settings.Fsk.RxContinuous; // DIO0=PayloadReady // DIO1=FifoLevel // DIO2=SyncAddr // DIO3=FifoEmpty // DIO4=Preamble // DIO5=ModeReady Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RF_DIOMAPPING1_DIO0_MASK & RF_DIOMAPPING1_DIO1_MASK & RF_DIOMAPPING1_DIO2_MASK ) | RF_DIOMAPPING1_DIO0_00 | RF_DIOMAPPING1_DIO1_00 | RF_DIOMAPPING1_DIO2_11 ); Write( REG_DIOMAPPING2, ( Read( REG_DIOMAPPING2 ) & RF_DIOMAPPING2_DIO4_MASK & RF_DIOMAPPING2_MAP_MASK ) | RF_DIOMAPPING2_DIO4_11 | RF_DIOMAPPING2_MAP_PREAMBLEDETECT ); this->settings.FskPacketHandler.FifoThresh = Read( REG_FIFOTHRESH ) & 0x3F; Write( REG_RXCONFIG, RF_RXCONFIG_AFCAUTO_ON | RF_RXCONFIG_AGCAUTO_ON | RF_RXCONFIG_RXTRIGER_PREAMBLEDETECT ); this->settings.FskPacketHandler.PreambleDetected = false; this->settings.FskPacketHandler.SyncWordDetected = false; this->settings.FskPacketHandler.NbBytes = 0; this->settings.FskPacketHandler.Size = 0; } break; case MODEM_LORA: { if( this->settings.LoRa.IqInverted == true ) { Write( REG_LR_INVERTIQ, ( ( Read( REG_LR_INVERTIQ ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK ) | RFLR_INVERTIQ_RX_ON | RFLR_INVERTIQ_TX_OFF ) ); Write( REG_LR_INVERTIQ2, RFLR_INVERTIQ2_ON ); } else { Write( REG_LR_INVERTIQ, ( ( Read( REG_LR_INVERTIQ ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK ) | RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_OFF ) ); Write( REG_LR_INVERTIQ2, RFLR_INVERTIQ2_OFF ); } // ERRATA 2.3 - Receiver Spurious Reception of a LoRa Signal if( this->settings.LoRa.Bandwidth < LORA_BANKWIDTH_500kHz ) { Write( REG_LR_DETECTOPTIMIZE, Read( REG_LR_DETECTOPTIMIZE ) & 0x7F ); Write( REG_LR_TEST30, 0x00 ); switch( this->settings.LoRa.Bandwidth ) { case LORA_BANKWIDTH_7kHz: // 7.8 kHz Write( REG_LR_TEST2F, 0x48 ); SetChannel(this->settings.Channel + 7.81e3 ); break; case LORA_BANKWIDTH_10kHz: // 10.4 kHz Write( REG_LR_TEST2F, 0x44 ); SetChannel(this->settings.Channel + 10.42e3 ); break; case LORA_BANKWIDTH_15kHz: // 15.6 kHz Write( REG_LR_TEST2F, 0x44 ); SetChannel(this->settings.Channel + 15.62e3 ); break; case LORA_BANKWIDTH_20kHz: // 20.8 kHz Write( REG_LR_TEST2F, 0x44 ); SetChannel(this->settings.Channel + 20.83e3 ); break; case LORA_BANKWIDTH_31kHz: // 31.25 kHz Write( REG_LR_TEST2F, 0x44 ); SetChannel(this->settings.Channel + 31.25e3 ); break; case LORA_BANKWIDTH_41kHz: // 41.4 kHz Write( REG_LR_TEST2F, 0x44 ); SetChannel(this->settings.Channel + 41.67e3 ); break; case LORA_BANKWIDTH_62kHz: // 62.5 kHz Write( REG_LR_TEST2F, 0x40 ); break; case LORA_BANKWIDTH_125kHz: // 125 kHz Write( REG_LR_TEST2F, 0x40 ); break; case LORA_BANKWIDTH_250kHz: // 250 kHz Write( REG_LR_TEST2F, 0x40 ); break; } } else { Write( REG_LR_DETECTOPTIMIZE, Read( REG_LR_DETECTOPTIMIZE ) | 0x80 ); } rxContinuous = this->settings.LoRa.RxContinuous; if( this->settings.LoRa.FreqHopOn == true ) { Write( REG_LR_IRQFLAGSMASK, //RFLR_IRQFLAGS_RXTIMEOUT | //RFLR_IRQFLAGS_RXDONE | //RFLR_IRQFLAGS_PAYLOADCRCERROR | RFLR_IRQFLAGS_VALIDHEADER | RFLR_IRQFLAGS_TXDONE | RFLR_IRQFLAGS_CADDONE | //RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL | RFLR_IRQFLAGS_CADDETECTED ); // DIO0=RxDone, DIO2=FhssChangeChannel Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RFLR_DIOMAPPING1_DIO0_MASK & RFLR_DIOMAPPING1_DIO2_MASK ) | RFLR_DIOMAPPING1_DIO0_00 | RFLR_DIOMAPPING1_DIO2_00 ); } else { Write( REG_LR_IRQFLAGSMASK, //RFLR_IRQFLAGS_RXTIMEOUT | //RFLR_IRQFLAGS_RXDONE | //RFLR_IRQFLAGS_PAYLOADCRCERROR | RFLR_IRQFLAGS_VALIDHEADER | RFLR_IRQFLAGS_TXDONE | RFLR_IRQFLAGS_CADDONE | RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL | RFLR_IRQFLAGS_CADDETECTED ); // DIO0=RxDone Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RFLR_DIOMAPPING1_DIO0_MASK ) | RFLR_DIOMAPPING1_DIO0_00 ); } Write( REG_LR_FIFORXBASEADDR, 0 ); Write( REG_LR_FIFOADDRPTR, 0 ); } break; } this->settings.State = RF_RX_RUNNING; if( timeout != 0 ) { SetTimeout(RXTimeoutTimer, &SX1276::OnTimeoutIrq, timeout * 1e3); } if( this->settings.Modem == MODEM_FSK ) { SetOpMode( RF_OPMODE_RECEIVER ); if( rxContinuous == false ) { SetTimeout(RXTimeoutSyncWordTimer, &SX1276::OnTimeoutIrq, this->settings.Fsk.RxSingleTimeout * 1e3); } } else { if( rxContinuous == true ) { SetOpMode( RFLR_OPMODE_RECEIVER ); } else { SetOpMode( RFLR_OPMODE_RECEIVER_SINGLE ); } } } bool SX1276::RxSignalPending() { if (this->settings.State != RF_RX_RUNNING) return false; switch( this->settings.Modem ) { case MODEM_FSK: break; case MODEM_LORA: if (Read(REG_LR_MODEMSTAT) & (RFLR_MODEMSTAT_SIGNAL_DETECTED|RFLR_MODEMSTAT_SIGNAL_SYNCRONIZED|RFLR_MODEMSTAT_HEADERINFO_VALID|RFLR_MODEMSTAT_MODEM_CLEAR)) return true; break; } return false; } void SX1276::Tx( uint32_t timeout ) { switch( this->settings.Modem ) { case MODEM_FSK: { // DIO0=PacketSent // DIO1=FifoEmpty // DIO2=FifoFull // DIO3=FifoEmpty // DIO4=LowBat // DIO5=ModeReady Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RF_DIOMAPPING1_DIO0_MASK & RF_DIOMAPPING1_DIO1_MASK & RF_DIOMAPPING1_DIO2_MASK ) | RF_DIOMAPPING1_DIO1_01 ); Write( REG_DIOMAPPING2, ( Read( REG_DIOMAPPING2 ) & RF_DIOMAPPING2_DIO4_MASK & RF_DIOMAPPING2_MAP_MASK ) ); this->settings.FskPacketHandler.FifoThresh = Read( REG_FIFOTHRESH ) & 0x3F; } break; case MODEM_LORA: { if( this->settings.LoRa.FreqHopOn == true ) { Write( REG_LR_IRQFLAGSMASK, RFLR_IRQFLAGS_RXTIMEOUT | RFLR_IRQFLAGS_RXDONE | RFLR_IRQFLAGS_PAYLOADCRCERROR | RFLR_IRQFLAGS_VALIDHEADER | //RFLR_IRQFLAGS_TXDONE | RFLR_IRQFLAGS_CADDONE | //RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL | RFLR_IRQFLAGS_CADDETECTED ); // DIO0=TxDone, DIO2=FhssChangeChannel Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RFLR_DIOMAPPING1_DIO0_MASK & RFLR_DIOMAPPING1_DIO2_MASK ) | RFLR_DIOMAPPING1_DIO0_01 | RFLR_DIOMAPPING1_DIO2_00 ); } else { Write( REG_LR_IRQFLAGSMASK, RFLR_IRQFLAGS_RXTIMEOUT | RFLR_IRQFLAGS_RXDONE | RFLR_IRQFLAGS_PAYLOADCRCERROR | RFLR_IRQFLAGS_VALIDHEADER | //RFLR_IRQFLAGS_TXDONE | RFLR_IRQFLAGS_CADDONE | RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL | RFLR_IRQFLAGS_CADDETECTED ); // DIO0=TxDone Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RFLR_DIOMAPPING1_DIO0_MASK ) | RFLR_DIOMAPPING1_DIO0_01 ); } } break; } this->settings.State = RF_TX_RUNNING; SetTimeout(TXTimeoutTimer, &SX1276::OnTimeoutIrq, timeout * 1e3); SetOpMode( RF_OPMODE_TRANSMITTER ); } void SX1276::StartCad( void ) { switch( this->settings.Modem ) { case MODEM_FSK: { } break; case MODEM_LORA: { Write( REG_LR_IRQFLAGSMASK, RFLR_IRQFLAGS_RXTIMEOUT | RFLR_IRQFLAGS_RXDONE | RFLR_IRQFLAGS_PAYLOADCRCERROR | RFLR_IRQFLAGS_VALIDHEADER | RFLR_IRQFLAGS_TXDONE | //RFLR_IRQFLAGS_CADDONE | RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL // | //RFLR_IRQFLAGS_CADDETECTED ); if (this->dioIrq[3]) { // DIO3=CADDone Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RFLR_DIOMAPPING1_DIO3_MASK ) | RFLR_DIOMAPPING1_DIO3_00 ); } else { // DIO0=CADDone Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RFLR_DIOMAPPING1_DIO0_MASK ) | RFLR_DIOMAPPING1_DIO0_10 ); } this->settings.State = RF_CAD; SetOpMode( RFLR_OPMODE_CAD ); } break; default: break; } } void SX1276::SetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time ) { uint32_t timeout = ( uint32_t )( time * 1e6 ); SetChannel( freq ); SetTxConfig( MODEM_FSK, power, 0, 0, 4800, 0, 5, false, false, 0, 0, 0, timeout ); Write( REG_PACKETCONFIG2, ( Read( REG_PACKETCONFIG2 ) & RF_PACKETCONFIG2_DATAMODE_MASK ) ); // Disable radio interrupts Write( REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_11 | RF_DIOMAPPING1_DIO1_11 ); Write( REG_DIOMAPPING2, RF_DIOMAPPING2_DIO4_10 | RF_DIOMAPPING2_DIO5_10 ); this->settings.State = RF_TX_RUNNING; SetTimeout(TXTimeoutTimer, &SX1276::OnTimeoutIrq, timeout); SetOpMode( RF_OPMODE_TRANSMITTER ); } int16_t SX1276::MaxMTUSize( RadioModems_t modem ) { int16_t mtuSize = 0; switch( modem ) { case MODEM_FSK: mtuSize = RX_BUFFER_SIZE; case MODEM_LORA: mtuSize = RX_BUFFER_SIZE; break; default: mtuSize = -1; break; } return mtuSize; } int16_t SX1276::GetRssi( RadioModems_t modem ) { int16_t rssi = 0; switch( modem ) { case MODEM_FSK: rssi = -( Read( REG_RSSIVALUE ) >> 1 ); break; case MODEM_LORA: if( this->settings.Channel > RF_MID_BAND_THRESH ) { rssi = RSSI_OFFSET_HF + Read( REG_LR_RSSIVALUE ); } else { rssi = RSSI_OFFSET_LF + Read( REG_LR_RSSIVALUE ); } break; default: rssi = -1; break; } return rssi; } int32_t SX1276::GetFrequencyError(RadioModems_t modem ) { int32_t val = 0; if (modem != MODEM_LORA) return 0; val = (Read(REG_LR_FEIMSB) & 0b1111) << 16; // high word, 4 valid bits only val |= ((Read(REG_LR_FEIMID) << 8) | Read(REG_LR_FEILSB)); // high byte, low byte if (val & 0x80000) //convert sign bit val |= 0xfff00000; int32_t bandwidth = 0; for (int i = 0; i < (int)(sizeof(LoRaBandwidths) / sizeof(BandwidthMap)) -1; i++ ) { if (LoRaBandwidths[i].RegValue == this->settings.LoRa.Bandwidth) { bandwidth = LoRaBandwidths[i].bandwidth; break; } } if (!bandwidth) return 0; float bandWidthkHz = (float)bandwidth/1000; int32_t hz = (((float)val * (float)(1<<24)) / ((float)XTAL_FREQ)) * (bandWidthkHz / 500.0); return hz; } void SX1276::SetOpMode( uint8_t opMode ) { if( opMode == RF_OPMODE_SLEEP ) { SetAntSwLowPower( true ); } else { SetAntSwLowPower( false ); SetAntSw( opMode ); } Write( REG_OPMODE, ( Read( REG_OPMODE ) & RF_OPMODE_MASK ) | opMode ); } void SX1276::SetModem( RadioModems_t modem ) { if( ( Read( REG_OPMODE ) & RFLR_OPMODE_LONGRANGEMODE_ON ) != 0 ) { this->settings.Modem = MODEM_LORA; } else { this->settings.Modem = MODEM_FSK; } if( this->settings.Modem == modem ) { return; } this->settings.Modem = modem; switch( this->settings.Modem ) { default: case MODEM_FSK: Sleep( ); Write( REG_OPMODE, ( Read( REG_OPMODE ) & RFLR_OPMODE_LONGRANGEMODE_MASK ) | RFLR_OPMODE_LONGRANGEMODE_OFF ); Write( REG_DIOMAPPING1, 0x00 ); Write( REG_DIOMAPPING2, 0x30 ); // DIO5=ModeReady break; case MODEM_LORA: Sleep( ); Write( REG_OPMODE, ( Read( REG_OPMODE ) & RFLR_OPMODE_LONGRANGEMODE_MASK ) | RFLR_OPMODE_LONGRANGEMODE_ON ); Write( REG_DIOMAPPING1, 0x00 ); Write( REG_DIOMAPPING2, 0x00 ); break; } } void SX1276::SetMaxPayloadLength( RadioModems_t modem, uint8_t max ) { this->SetModem( modem ); switch( modem ) { case MODEM_FSK: if( this->settings.Fsk.FixLen == false ) { this->Write( REG_PAYLOADLENGTH, max ); } break; case MODEM_LORA: this->Write( REG_LR_PAYLOADMAXLENGTH, max ); break; } } void SX1276::SetPublicNetwork( bool enable ) { SetModem( MODEM_LORA ); this->settings.LoRa.PublicNetwork = enable; if( enable == true ) { // Change LoRa modem SyncWord Write( REG_LR_SYNCWORD, LORA_MAC_PUBLIC_SYNCWORD ); } else { // Change LoRa modem SyncWord Write( REG_LR_SYNCWORD, LORA_MAC_PRIVATE_SYNCWORD ); } } void SX1276::OnTimeoutIrq( void ) { switch( this->settings.State ) { case RF_RX_RUNNING: if( this->settings.Modem == MODEM_FSK ) { this->settings.FskPacketHandler.PreambleDetected = false; this->settings.FskPacketHandler.SyncWordDetected = false; this->settings.FskPacketHandler.NbBytes = 0; this->settings.FskPacketHandler.Size = 0; // Clear Irqs Write( REG_IRQFLAGS1, RF_IRQFLAGS1_RSSI | RF_IRQFLAGS1_PREAMBLEDETECT | RF_IRQFLAGS1_SYNCADDRESSMATCH ); Write( REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN ); if( this->settings.Fsk.RxContinuous == true ) { // Continuous mode restart Rx chain Write( REG_RXCONFIG, Read( REG_RXCONFIG ) | RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK ); SetTimeout(RXTimeoutSyncWordTimer, &SX1276::OnTimeoutIrq, this->settings.Fsk.RxSingleTimeout * 1e3); } else { this->settings.State = RF_IDLE; SetTimeout(RXTimeoutSyncWordTimer, NULL); } } if (this->RadioEvents && this->RadioEvents->RxTimeout) { this->RadioEvents->RxTimeout(this, this->RadioEvents->userThisPtr, this->RadioEvents->userData); } break; case RF_TX_RUNNING: // Tx timeout shouldn't happen. // But it has been observed that when it happens it is a result of a corrupted SPI transfer // it depends on the platform design. // // The workaround is to put the radio in a known state. Thus, we re-initialize it. // BEGIN WORKAROUND // Reset the radio Reset( ); // Calibrate Rx chain RxChainCalibration( ); // Initialize radio default values SetOpMode( RF_OPMODE_SLEEP ); RadioRegistersInit( ); SetModem( MODEM_FSK ); // Restore previous network type setting. SetPublicNetwork( this->settings.LoRa.PublicNetwork ); // END WORKAROUND this->settings.State = RF_IDLE; if (this->RadioEvents && this->RadioEvents->TxTimeout) { this->RadioEvents->TxTimeout(this, this->RadioEvents->userThisPtr, this->RadioEvents->userData); } break; default: break; } } void SX1276::OnDio0Irq( void ) { volatile uint8_t irqFlags = 0; switch( this->settings.State ) { case RF_RX_RUNNING: //TimerStop( &RxTimeoutTimer ); // RxDone interrupt switch( this->settings.Modem ) { case MODEM_FSK: if( this->settings.Fsk.CrcOn == true ) { irqFlags = Read( REG_IRQFLAGS2 ); if( ( irqFlags & RF_IRQFLAGS2_CRCOK ) != RF_IRQFLAGS2_CRCOK ) { // Clear Irqs Write( REG_IRQFLAGS1, RF_IRQFLAGS1_RSSI | RF_IRQFLAGS1_PREAMBLEDETECT | RF_IRQFLAGS1_SYNCADDRESSMATCH ); Write( REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN ); SetTimeout(RXTimeoutTimer, NULL); if( this->settings.Fsk.RxContinuous == false ) { SetTimeout(RXTimeoutSyncWordTimer, NULL); this->settings.State = RF_IDLE; } else { // Continuous mode restart Rx chain Write( REG_RXCONFIG, Read( REG_RXCONFIG ) | RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK ); SetTimeout(RXTimeoutSyncWordTimer, &SX1276::OnTimeoutIrq, this->settings.Fsk.RxSingleTimeout * 1e3); } if (this->RadioEvents && this->RadioEvents->RxError) { this->RadioEvents->RxError(this, this->RadioEvents->userThisPtr, this->RadioEvents->userData); } this->settings.FskPacketHandler.PreambleDetected = false; this->settings.FskPacketHandler.SyncWordDetected = false; this->settings.FskPacketHandler.NbBytes = 0; this->settings.FskPacketHandler.Size = 0; break; } } // Read received packet size if( ( this->settings.FskPacketHandler.Size == 0 ) && ( this->settings.FskPacketHandler.NbBytes == 0 ) ) { if( this->settings.Fsk.FixLen == false ) { ReadFifo( ( uint8_t* )&this->settings.FskPacketHandler.Size, 1 ); } else { this->settings.FskPacketHandler.Size = Read( REG_PAYLOADLENGTH ); } ReadFifo( rxtxBuffer + this->settings.FskPacketHandler.NbBytes, this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ); this->settings.FskPacketHandler.NbBytes += ( this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ); } else { ReadFifo( rxtxBuffer + this->settings.FskPacketHandler.NbBytes, this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ); this->settings.FskPacketHandler.NbBytes += ( this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ); } SetTimeout(RXTimeoutTimer, NULL); if( this->settings.Fsk.RxContinuous == false ) { this->settings.State = RF_IDLE; SetTimeout(RXTimeoutSyncWordTimer, NULL); } else { // Continuous mode restart Rx chain Write( REG_RXCONFIG, Read( REG_RXCONFIG ) | RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK ); SetTimeout(RXTimeoutSyncWordTimer, &SX1276::OnTimeoutIrq, this->settings.Fsk.RxSingleTimeout * 1e3); } if (this->RadioEvents && this->RadioEvents->RxDone) { this->RadioEvents->RxDone(this, this->RadioEvents->userThisPtr, this->RadioEvents->userData, rxtxBuffer, this->settings.FskPacketHandler.Size, this->settings.FskPacketHandler.RssiValue, 0 ); } this->settings.FskPacketHandler.PreambleDetected = false; this->settings.FskPacketHandler.SyncWordDetected = false; this->settings.FskPacketHandler.NbBytes = 0; this->settings.FskPacketHandler.Size = 0; break; case MODEM_LORA: { int8_t snr = 0; // Clear Irq Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_RXDONE ); irqFlags = Read( REG_LR_IRQFLAGS ); if( ( irqFlags & RFLR_IRQFLAGS_PAYLOADCRCERROR_MASK ) == RFLR_IRQFLAGS_PAYLOADCRCERROR ) { // Clear Irq Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_PAYLOADCRCERROR ); if( this->settings.LoRa.RxContinuous == false ) { this->settings.State = RF_IDLE; } SetTimeout(RXTimeoutTimer, NULL); if(this->RadioEvents && this->RadioEvents->RxError) { this->RadioEvents->RxError(this, this->RadioEvents->userThisPtr, this->RadioEvents->userData); } break; } this->settings.LoRaPacketHandler.SnrValue = Read( REG_LR_PKTSNRVALUE ); if( this->settings.LoRaPacketHandler.SnrValue & 0x80 ) // The SNR sign bit is 1 { // Invert and divide by 4 snr = ( ( ~this->settings.LoRaPacketHandler.SnrValue + 1 ) & 0xFF ) >> 2; snr = -snr; } else { // Divide by 4 snr = ( this->settings.LoRaPacketHandler.SnrValue & 0xFF ) >> 2; } int16_t rssi = Read( REG_LR_PKTRSSIVALUE ); if( snr < 0 ) { if( this->settings.Channel > RF_MID_BAND_THRESH ) { this->settings.LoRaPacketHandler.RssiValue = RSSI_OFFSET_HF + rssi + ( rssi >> 4 ) + snr; } else { this->settings.LoRaPacketHandler.RssiValue = RSSI_OFFSET_LF + rssi + ( rssi >> 4 ) + snr; } } else { if( this->settings.Channel > RF_MID_BAND_THRESH ) { this->settings.LoRaPacketHandler.RssiValue = RSSI_OFFSET_HF + rssi + ( rssi >> 4 ); } else { this->settings.LoRaPacketHandler.RssiValue = RSSI_OFFSET_LF + rssi + ( rssi >> 4 ); } } this->settings.LoRaPacketHandler.Size = Read( REG_LR_RXNBBYTES ); ReadFifo( rxtxBuffer, this->settings.LoRaPacketHandler.Size ); if( this->settings.LoRa.RxContinuous == false ) { this->settings.State = RF_IDLE; } SetTimeout(RXTimeoutTimer, NULL); if(this->RadioEvents && this->RadioEvents->RxDone) { this->RadioEvents->RxDone(this, this->RadioEvents->userThisPtr, this->RadioEvents->userData, rxtxBuffer, this->settings.LoRaPacketHandler.Size, this->settings.LoRaPacketHandler.RssiValue, this->settings.LoRaPacketHandler.SnrValue ); } } break; default: break; } break; case RF_TX_RUNNING: SetTimeout(TXTimeoutTimer, NULL); // TxDone interrupt switch( this->settings.Modem ) { case MODEM_LORA: // Clear Irq Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_TXDONE ); // Intentional fall through case MODEM_FSK: default: this->settings.State = RF_IDLE; if (this->RadioEvents && this->RadioEvents->TxDone) { this->RadioEvents->TxDone(this, this->RadioEvents->userThisPtr, this->RadioEvents->userData); } break; } break; case RF_CAD: // CadDone interrupt switch( this->settings.Modem ) { case MODEM_LORA: { if( ( Read( REG_LR_IRQFLAGS ) & RFLR_IRQFLAGS_CADDETECTED ) == RFLR_IRQFLAGS_CADDETECTED ) { // Clear Irq Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_CADDETECTED | RFLR_IRQFLAGS_CADDONE ); if (this->RadioEvents && this->RadioEvents->CadDone) { this->RadioEvents->CadDone(this, this->RadioEvents->userThisPtr, this->RadioEvents->userData, true ); } } else { // Clear Irq Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_CADDONE ); if (this->RadioEvents && this->RadioEvents->CadDone) { this->RadioEvents->CadDone(this, this->RadioEvents->userThisPtr, this->RadioEvents->userData, false ); } } } case MODEM_FSK: default: this->settings.State = RF_IDLE; break; } default: break; } } void SX1276::OnDio1Irq( void ) { switch( this->settings.State ) { case RF_RX_RUNNING: switch( this->settings.Modem ) { case MODEM_FSK: // FifoLevel interrupt // Read received packet size if( ( this->settings.FskPacketHandler.Size == 0 ) && ( this->settings.FskPacketHandler.NbBytes == 0 ) ) { if( this->settings.Fsk.FixLen == false ) { ReadFifo( ( uint8_t* )&this->settings.FskPacketHandler.Size, 1 ); } else { this->settings.FskPacketHandler.Size = Read( REG_PAYLOADLENGTH ); } } if( ( this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ) > this->settings.FskPacketHandler.FifoThresh ) { ReadFifo( ( rxtxBuffer + this->settings.FskPacketHandler.NbBytes ), this->settings.FskPacketHandler.FifoThresh ); this->settings.FskPacketHandler.NbBytes += this->settings.FskPacketHandler.FifoThresh; } else { ReadFifo( ( rxtxBuffer + this->settings.FskPacketHandler.NbBytes ), this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ); this->settings.FskPacketHandler.NbBytes += ( this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ); } break; case MODEM_LORA: // Sync time out SetTimeout(RXTimeoutTimer, NULL); // Clear Irq Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_RXTIMEOUT ); this->settings.State = RF_IDLE; if (this->RadioEvents && this->RadioEvents->RxTimeout) { this->RadioEvents->RxTimeout(this, this->RadioEvents->userThisPtr, this->RadioEvents->userData); } break; default: break; } break; case RF_TX_RUNNING: switch( this->settings.Modem ) { case MODEM_FSK: // FifoEmpty interrupt if( ( this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ) > this->settings.FskPacketHandler.ChunkSize ) { WriteFifo( ( rxtxBuffer + this->settings.FskPacketHandler.NbBytes ), this->settings.FskPacketHandler.ChunkSize ); this->settings.FskPacketHandler.NbBytes += this->settings.FskPacketHandler.ChunkSize; } else { // Write the last chunk of data WriteFifo( rxtxBuffer + this->settings.FskPacketHandler.NbBytes, this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ); this->settings.FskPacketHandler.NbBytes += this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes; } break; case MODEM_LORA: break; default: break; } break; default: break; } } void SX1276::OnDio2Irq( void ) { switch( this->settings.State ) { case RF_RX_RUNNING: switch( this->settings.Modem ) { case MODEM_FSK: // Checks if DIO4 is connected. If it is not PreambleDtected is set to true. if( this->dioIrq[4] == NULL ) { this->settings.FskPacketHandler.PreambleDetected = true; } if( ( this->settings.FskPacketHandler.PreambleDetected == true ) && ( this->settings.FskPacketHandler.SyncWordDetected == false ) ) { SetTimeout(RXTimeoutSyncWordTimer, NULL); this->settings.FskPacketHandler.SyncWordDetected = true; this->settings.FskPacketHandler.RssiValue = -( Read( REG_RSSIVALUE ) >> 1 ); this->settings.FskPacketHandler.AfcValue = ( int32_t )( double )( ( ( uint16_t )Read( REG_AFCMSB ) << 8 ) | ( uint16_t )Read( REG_AFCLSB ) ) * ( double )FREQ_STEP; this->settings.FskPacketHandler.RxGain = ( Read( REG_LNA ) >> 5 ) & 0x07; } break; case MODEM_LORA: if( this->settings.LoRa.FreqHopOn == true ) { // Clear Irq Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL ); if (this->RadioEvents && this->RadioEvents->FhssChangeChannel) { this->RadioEvents->FhssChangeChannel(this, this->RadioEvents->userThisPtr, this->RadioEvents->userData, ( Read( REG_LR_HOPCHANNEL ) & RFLR_HOPCHANNEL_CHANNEL_MASK ) ); } } break; default: break; } break; case RF_TX_RUNNING: switch( this->settings.Modem ) { case MODEM_FSK: break; case MODEM_LORA: if( this->settings.LoRa.FreqHopOn == true ) { // Clear Irq Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL ); if (this->RadioEvents && this->RadioEvents->FhssChangeChannel) { this->RadioEvents->FhssChangeChannel(this, this->RadioEvents->userThisPtr, this->RadioEvents->userData, ( Read( REG_LR_HOPCHANNEL ) & RFLR_HOPCHANNEL_CHANNEL_MASK ) ); } } break; default: break; } break; default: break; } } void SX1276::OnDio3Irq( void ) { switch( this->settings.Modem ) { case MODEM_FSK: break; case MODEM_LORA: if( ( Read( REG_LR_IRQFLAGS ) & RFLR_IRQFLAGS_CADDETECTED ) == RFLR_IRQFLAGS_CADDETECTED ) { // Clear Irq Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_CADDETECTED | RFLR_IRQFLAGS_CADDONE ); if (this->RadioEvents && this->RadioEvents->CadDone) { this->RadioEvents->CadDone(this, this->RadioEvents->userThisPtr, this->RadioEvents->userData, true ); } } else { // Clear Irq Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_CADDONE ); if (this->RadioEvents && this->RadioEvents->CadDone) { this->RadioEvents->CadDone(this, this->RadioEvents->userThisPtr, this->RadioEvents->userData, false ); } } break; default: break; } } void SX1276::OnDio4Irq( void ) { switch( this->settings.Modem ) { case MODEM_FSK: { if( this->settings.FskPacketHandler.PreambleDetected == false ) { this->settings.FskPacketHandler.PreambleDetected = true; } } break; case MODEM_LORA: break; default: break; } } void SX1276::OnDio5Irq( void ) { switch( this->settings.Modem ) { case MODEM_FSK: break; case MODEM_LORA: break; default: break; } }