This is code is part of a Technion course project in advanced IoT, implementing a device to receive and present sensors data from a Formula racing car built by students at Technion - Israel Institute of Technology.
Fork of DISCO-L072CZ-LRWAN1_LoRa_PingPong by
This is code is part of a Technion course project in advanced IoT, implementing a device to receive sensors data from another L072CZ-LRWAN1 installed on a Formula racing car (built by students at Technion - Israel Institute of Technology), and sends it to a GUI presenting the data (GUI project: github.com/ward-mattar/TechnionFormulaGUI).
How to install
- Create an account on Mbed: https://os.mbed.com/account/signup/
- Import project into Compiler
- In the Program Workspace select "Formula_Nucleo_Receiver"
- Select a Platform like so:
- Click button at top-left
- Add Board
- Search "NUCLEO F103RB" and then "Add to your Mbed Compiler"
- Finally click "Compile", if the build was successful, the binary would download automatically
- To install it on device simply plug it in to a PC, open device drive and drag then drop binary file in it
SX1276GenericLib/sx1276/sx1276.cpp
- Committer:
- wardm
- Date:
- 2018-05-19
- Revision:
- 12:046346a16ff4
File content as of revision 12:046346a16ff4:
/* / _____) _ | | ( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| (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 ); // DIO3=CADDone Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RFLR_DIOMAPPING1_DIO3_MASK ) | RFLR_DIOMAPPING1_DIO3_00 ); 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 & 0x8000) //sconvert ign 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; 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; } }