2013-07-14 04:49:26 +01:00
// **********************************************************************************
2014-08-13 03:03:19 +01:00
// Driver definition for HopeRF RFM69W/RFM69HW/RFM69CW/RFM69HCW, Semtech SX1231/1231H
2013-07-14 04:49:26 +01:00
// **********************************************************************************
2018-04-09 19:19:14 +01:00
// Copyright LowPowerLab LLC 2018, https://www.LowPowerLab.com/contact
2014-08-13 03:03:19 +01:00
// **********************************************************************************
// License
// **********************************************************************************
// This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU General
// Public License as published by the Free Software
2014-11-14 20:25:45 +00:00
// Foundation; either version 3 of the License, or
2014-08-13 03:03:19 +01:00
// (at your option) any later version.
//
// This program is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A
2014-11-14 20:25:45 +00:00
// PARTICULAR PURPOSE. See the GNU General Public
2014-08-13 03:03:19 +01:00
// License for more details.
//
// Licence can be viewed at
2014-11-14 20:25:45 +00:00
// http://www.gnu.org/licenses/gpl-3.0.txt
2014-08-13 03:03:19 +01:00
//
// Please maintain this license information along with authorship
// and copyright notices in any redistribution of this code
2013-07-14 04:49:26 +01:00
// **********************************************************************************
2020-02-14 11:02:28 +00:00
# include "RFM69.h"
# include "RFM69registers.h"
2013-06-20 22:06:39 +01:00
# include <SPI.h>
2019-06-05 16:38:14 +01:00
uint8_t RFM69 : : DATA [ RF69_MAX_DATA_LEN + 1 ] ;
2019-01-16 00:29:39 +00:00
uint8_t RFM69 : : _mode ; // current transceiver state
uint8_t RFM69 : : DATALEN ;
2019-05-01 17:02:03 +01:00
uint16_t RFM69 : : SENDERID ;
uint16_t RFM69 : : TARGETID ; // should match _address
2019-01-16 00:29:39 +00:00
uint8_t RFM69 : : PAYLOADLEN ;
uint8_t RFM69 : : ACK_REQUESTED ;
uint8_t RFM69 : : ACK_RECEIVED ; // should be polled immediately after sending a packet with ACK request
int16_t RFM69 : : RSSI ; // most accurate RSSI during reception (closest to the reception)
2018-08-08 20:34:31 +01:00
volatile bool RFM69 : : _haveData ;
2013-06-20 22:06:39 +01:00
2018-04-05 21:00:36 +01:00
RFM69 : : RFM69 ( uint8_t slaveSelectPin , uint8_t interruptPin , bool isRFM69HW )
{
_slaveSelectPin = slaveSelectPin ;
_interruptPin = interruptPin ;
_mode = RF69_MODE_STANDBY ;
2020-01-21 17:52:45 +00:00
_spyMode = false ;
2018-04-05 21:00:36 +01:00
_powerLevel = 31 ;
_isRFM69HW = isRFM69HW ;
2018-04-05 21:20:12 +01:00
# if defined(RF69_LISTENMODE_ENABLE)
2018-04-05 21:00:36 +01:00
_isHighSpeed = true ;
_haveEncryptKey = false ;
uint32_t rxDuration = DEFAULT_LISTEN_RX_US ;
uint32_t idleDuration = DEFAULT_LISTEN_IDLE_US ;
listenModeSetDurations ( rxDuration , idleDuration ) ;
# endif
}
2019-05-01 17:02:03 +01:00
bool RFM69 : : initialize ( uint8_t freqBand , uint16_t nodeID , uint8_t networkID )
2013-06-20 22:06:39 +01:00
{
2018-04-05 21:00:36 +01:00
_interruptNum = digitalPinToInterrupt ( _interruptPin ) ;
if ( _interruptNum = = NOT_AN_INTERRUPT ) return false ;
# ifdef RF69_ATTACHINTERRUPT_TAKES_PIN_NUMBER
_interruptNum = _interruptPin ;
# endif
2015-01-12 10:34:16 +00:00
const uint8_t CONFIG [ ] [ 2 ] =
2013-06-20 22:06:39 +01:00
{
2013-07-14 04:49:26 +01:00
/* 0x01 */ { REG_OPMODE , RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY } ,
2015-01-06 14:25:29 +00:00
/* 0x02 */ { REG_DATAMODUL , RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00 } , // no shaping
2015-01-12 10:00:43 +00:00
/* 0x03 */ { REG_BITRATEMSB , RF_BITRATEMSB_55555 } , // default: 4.8 KBPS
2013-06-28 21:13:38 +01:00
/* 0x04 */ { REG_BITRATELSB , RF_BITRATELSB_55555 } ,
2015-01-12 10:00:43 +00:00
/* 0x05 */ { REG_FDEVMSB , RF_FDEVMSB_50000 } , // default: 5KHz, (FDEV + BitRate / 2 <= 500KHz)
2013-06-20 22:06:39 +01:00
/* 0x06 */ { REG_FDEVLSB , RF_FDEVLSB_50000 } ,
2015-01-12 14:09:49 +00:00
/* 0x07 */ { REG_FRFMSB , ( uint8_t ) ( freqBand = = RF69_315MHZ ? RF_FRFMSB_315 : ( freqBand = = RF69_433MHZ ? RF_FRFMSB_433 : ( freqBand = = RF69_868MHZ ? RF_FRFMSB_868 : RF_FRFMSB_915 ) ) ) } ,
/* 0x08 */ { REG_FRFMID , ( uint8_t ) ( freqBand = = RF69_315MHZ ? RF_FRFMID_315 : ( freqBand = = RF69_433MHZ ? RF_FRFMID_433 : ( freqBand = = RF69_868MHZ ? RF_FRFMID_868 : RF_FRFMID_915 ) ) ) } ,
/* 0x09 */ { REG_FRFLSB , ( uint8_t ) ( freqBand = = RF69_315MHZ ? RF_FRFLSB_315 : ( freqBand = = RF69_433MHZ ? RF_FRFLSB_433 : ( freqBand = = RF69_868MHZ ? RF_FRFLSB_868 : RF_FRFLSB_915 ) ) ) } ,
2015-01-06 13:46:04 +00:00
2019-08-02 21:38:00 +01:00
// looks like PA1 and PA2 are not implemented on RFM69W/CW, hence the max output power is 13dBm
2013-06-20 22:06:39 +01:00
// +17dBm and +20dBm are possible on RFM69HW
2015-01-12 10:00:43 +00:00
// +13dBm formula: Pout = -18 + OutputPower (with PA0 or PA1**)
// +17dBm formula: Pout = -14 + OutputPower (with PA1 and PA2)**
// +20dBm formula: Pout = -11 + OutputPower (with PA1 and PA2)** and high power PA settings (section 3.3.7 in datasheet)
2013-06-20 22:06:39 +01:00
///* 0x11 */ { REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | RF_PALEVEL_OUTPUTPOWER_11111},
2015-01-06 14:25:29 +00:00
///* 0x13 */ { REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95 }, // over current protection (default is 95mA)
2015-01-06 13:46:04 +00:00
2015-01-12 10:00:43 +00:00
// RXBW defaults are { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_5} (RxBw: 10.4KHz)
2015-01-06 14:25:29 +00:00
/* 0x19 */ { REG_RXBW , RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2 } , // (BitRate < 2 * RxBw)
//for BR-19200: /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 },
/* 0x25 */ { REG_DIOMAPPING1 , RF_DIOMAPPING1_DIO0_01 } , // DIO0 is the only IRQ we're using
2015-01-24 14:10:52 +00:00
/* 0x26 */ { REG_DIOMAPPING2 , RF_DIOMAPPING2_CLKOUT_OFF } , // DIO5 ClkOut disable for power saving
2015-01-18 11:09:08 +00:00
/* 0x28 */ { REG_IRQFLAGS2 , RF_IRQFLAGS2_FIFOOVERRUN } , // writing to this bit ensures that the FIFO & status flags are reset
2015-01-12 10:00:43 +00:00
/* 0x29 */ { REG_RSSITHRESH , 220 } , // must be set to dBm = (-Sensitivity / 2), default is 0xE4 = 228 so -114dBm
///* 0x2D */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE } // default 3 preamble bytes 0xAAAAAA
/* 0x2E */ { REG_SYNCCONFIG , RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0 } ,
/* 0x2F */ { REG_SYNCVALUE1 , 0x2D } , // attempt to make this compatible with sync1 byte of RFM12B lib
2015-01-06 14:25:29 +00:00
/* 0x30 */ { REG_SYNCVALUE2 , networkID } , // NETWORK ID
2019-08-02 21:38:00 +01:00
//* 0x31 */ { REG_SYNCVALUE3, 0xAA },
//* 0x31 */ { REG_SYNCVALUE4, 0xBB },
2013-06-20 22:06:39 +01:00
/* 0x37 */ { REG_PACKETCONFIG1 , RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF } ,
2015-01-06 14:25:29 +00:00
/* 0x38 */ { REG_PAYLOADLENGTH , 66 } , // in variable length mode: the max frame size, not used in TX
///* 0x39 */ { REG_NODEADRS, nodeID }, // turned off because we're not using address filtering
/* 0x3C */ { REG_FIFOTHRESH , RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE } , // TX on FIFO not empty
2015-01-12 10:00:43 +00:00
/* 0x3D */ { REG_PACKETCONFIG2 , RF_PACKET2_RXRESTARTDELAY_2BITS | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF } , // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent)
//for BR-19200: /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent)
2015-01-24 13:13:15 +00:00
/* 0x6F */ { REG_TESTDAGC , RF_DAGC_IMPROVED_LOWBETA0 } , // run DAGC continuously in RX mode for Fading Margin Improvement, recommended default for AfcLowBetaOn=0
2013-06-20 22:06:39 +01:00
{ 255 , 0 }
} ;
2013-07-14 04:49:26 +01:00
2015-01-18 11:31:16 +00:00
digitalWrite ( _slaveSelectPin , HIGH ) ;
2013-06-20 22:06:39 +01:00
pinMode ( _slaveSelectPin , OUTPUT ) ;
2020-03-31 16:51:11 +01:00
# if defined(ESP32)
SPI . begin ( 18 , 19 , 23 , 5 ) ; //SPI3 (SCK,MISO,MOSI,CS)
//SPI.begin(14,12,13,15); //SPI2 (SCK,MISO,MOSI,CS)
# else
SPI . begin ( ) ;
# endif
2018-12-14 00:39:20 +00:00
# ifdef SPI_HAS_TRANSACTION
2020-05-18 16:12:28 +01:00
_settings = SPISettings ( 8000000 , MSBFIRST , SPI_MODE0 ) ;
2018-12-14 00:39:20 +00:00
# endif
2019-08-02 21:38:00 +01:00
uint32_t start = millis ( ) ;
2015-10-01 17:15:28 +01:00
uint8_t timeout = 50 ;
do writeReg ( REG_SYNCVALUE1 , 0xAA ) ; while ( readReg ( REG_SYNCVALUE1 ) ! = 0xaa & & millis ( ) - start < timeout ) ;
start = millis ( ) ;
do writeReg ( REG_SYNCVALUE1 , 0x55 ) ; while ( readReg ( REG_SYNCVALUE1 ) ! = 0x55 & & millis ( ) - start < timeout ) ;
2014-08-13 03:03:19 +01:00
2015-01-12 10:34:16 +00:00
for ( uint8_t i = 0 ; CONFIG [ i ] [ 0 ] ! = 255 ; i + + )
2013-06-20 22:06:39 +01:00
writeReg ( CONFIG [ i ] [ 0 ] , CONFIG [ i ] [ 1 ] ) ;
2014-01-02 21:57:18 +00:00
// Encryption is persistent between resets and can trip you up during debugging.
// Disable it during initialization so we always start from a known state.
encrypt ( 0 ) ;
2015-01-06 14:25:29 +00:00
setHighPower ( _isRFM69HW ) ; // called regardless if it's a RFM69W or RFM69HW
2013-06-20 22:06:39 +01:00
setMode ( RF69_MODE_STANDBY ) ;
2015-10-01 17:15:28 +01:00
start = millis ( ) ;
while ( ( ( readReg ( REG_IRQFLAGS1 ) & RF_IRQFLAGS1_MODEREADY ) = = 0x00 ) & & millis ( ) - start < timeout ) ; // wait for ModeReady
if ( millis ( ) - start > = timeout )
return false ;
2014-08-13 03:03:19 +01:00
attachInterrupt ( _interruptNum , RFM69 : : isr0 , RISING ) ;
2013-06-20 22:06:39 +01:00
_address = nodeID ;
2018-04-05 21:20:12 +01:00
# if defined(RF69_LISTENMODE_ENABLE)
2019-08-02 21:38:00 +01:00
selfPointer = this ;
2018-04-05 21:20:12 +01:00
_freqBand = freqBand ;
_networkID = networkID ;
# endif
2013-10-27 23:53:02 +00:00
return true ;
2013-06-20 22:06:39 +01:00
}
2015-01-06 14:25:29 +00:00
// return the frequency (in Hz)
2014-11-14 20:25:45 +00:00
uint32_t RFM69 : : getFrequency ( )
2013-06-20 22:06:39 +01:00
{
2015-01-12 10:00:43 +00:00
return RF69_FSTEP * ( ( ( uint32_t ) readReg ( REG_FRFMSB ) < < 16 ) + ( ( uint16_t ) readReg ( REG_FRFMID ) < < 8 ) + readReg ( REG_FRFLSB ) ) ;
2014-11-14 20:25:45 +00:00
}
2015-01-06 14:25:29 +00:00
// set the frequency (in Hz)
2014-11-14 20:25:45 +00:00
void RFM69 : : setFrequency ( uint32_t freqHz )
2013-06-20 22:06:39 +01:00
{
2015-01-18 11:22:43 +00:00
uint8_t oldMode = _mode ;
if ( oldMode = = RF69_MODE_TX ) {
setMode ( RF69_MODE_RX ) ;
}
2015-01-06 14:25:29 +00:00
freqHz / = RF69_FSTEP ; // divide down by FSTEP to get FRF
2014-11-14 20:25:45 +00:00
writeReg ( REG_FRFMSB , freqHz > > 16 ) ;
writeReg ( REG_FRFMID , freqHz > > 8 ) ;
writeReg ( REG_FRFLSB , freqHz ) ;
2015-01-18 11:22:43 +00:00
if ( oldMode = = RF69_MODE_RX ) {
setMode ( RF69_MODE_SYNTH ) ;
}
setMode ( oldMode ) ;
2013-06-20 22:06:39 +01:00
}
2015-01-12 10:34:16 +00:00
void RFM69 : : setMode ( uint8_t newMode )
2013-06-20 22:06:39 +01:00
{
2015-01-18 11:22:43 +00:00
if ( newMode = = _mode )
return ;
2013-06-20 22:06:39 +01:00
2015-01-06 13:46:04 +00:00
switch ( newMode ) {
case RF69_MODE_TX :
writeReg ( REG_OPMODE , ( readReg ( REG_OPMODE ) & 0xE3 ) | RF_OPMODE_TRANSMITTER ) ;
2013-06-20 22:06:39 +01:00
if ( _isRFM69HW ) setHighPowerRegs ( true ) ;
2015-01-06 13:46:04 +00:00
break ;
case RF69_MODE_RX :
writeReg ( REG_OPMODE , ( readReg ( REG_OPMODE ) & 0xE3 ) | RF_OPMODE_RECEIVER ) ;
2013-06-20 22:06:39 +01:00
if ( _isRFM69HW ) setHighPowerRegs ( false ) ;
2015-01-06 13:46:04 +00:00
break ;
case RF69_MODE_SYNTH :
writeReg ( REG_OPMODE , ( readReg ( REG_OPMODE ) & 0xE3 ) | RF_OPMODE_SYNTHESIZER ) ;
break ;
case RF69_MODE_STANDBY :
writeReg ( REG_OPMODE , ( readReg ( REG_OPMODE ) & 0xE3 ) | RF_OPMODE_STANDBY ) ;
break ;
case RF69_MODE_SLEEP :
writeReg ( REG_OPMODE , ( readReg ( REG_OPMODE ) & 0xE3 ) | RF_OPMODE_SLEEP ) ;
break ;
2015-01-18 11:22:43 +00:00
default :
return ;
2015-01-06 13:46:04 +00:00
}
// we are using packet mode, so this check is not really needed
2013-07-14 04:49:26 +01:00
// but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode
2015-01-06 14:25:29 +00:00
while ( _mode = = RF69_MODE_SLEEP & & ( readReg ( REG_IRQFLAGS1 ) & RF_IRQFLAGS1_MODEREADY ) = = 0x00 ) ; // wait for ModeReady
2013-06-20 22:06:39 +01:00
2015-01-06 13:46:04 +00:00
_mode = newMode ;
2013-06-20 22:06:39 +01:00
}
2015-05-19 20:08:41 +01:00
//put transceiver in sleep mode to save battery - to wake or resume receiving just call receiveDone()
2013-06-20 22:06:39 +01:00
void RFM69 : : sleep ( ) {
setMode ( RF69_MODE_SLEEP ) ;
}
2015-05-19 20:08:41 +01:00
//set this node's address
2019-05-01 17:02:03 +01:00
void RFM69 : : setAddress ( uint16_t addr )
2013-06-20 22:06:39 +01:00
{
2013-07-14 04:49:26 +01:00
_address = addr ;
2019-05-01 17:02:03 +01:00
writeReg ( REG_NODEADRS , _address ) ; //unused in packet mode
2013-06-20 22:06:39 +01:00
}
2015-05-19 20:08:41 +01:00
//set this node's network id
2015-01-12 10:34:16 +00:00
void RFM69 : : setNetwork ( uint8_t networkID )
2014-11-14 20:25:45 +00:00
{
2015-01-06 13:46:04 +00:00
writeReg ( REG_SYNCVALUE2 , networkID ) ;
2013-06-20 22:06:39 +01:00
}
2015-04-01 21:26:47 +01:00
// set *transmit/TX* output power: 0=min, 31=max
2013-08-17 02:35:34 +01:00
// this results in a "weaker" transmitted signal, and directly results in a lower RSSI at the receiver
2015-04-01 21:26:47 +01:00
// the power configurations are explained in the SX1231H datasheet (Table 10 on p21; RegPaLevel p66): http://www.semtech.com/images/datasheet/sx1231h.pdf
// valid powerLevel parameter values are 0-31 and result in a directly proportional effect on the output/transmission power
// this function implements 2 modes as follows:
// - for RFM69W the range is from 0-31 [-18dBm to 13dBm] (PA0 only on RFIO pin)
// - for RFM69HW the range is from 0-31 [5dBm to 20dBm] (PA1 & PA2 on PA_BOOST pin & high Power PA settings - see section 3.3.7 in datasheet, p22)
2015-01-12 10:34:16 +00:00
void RFM69 : : setPowerLevel ( uint8_t powerLevel )
2013-06-20 22:06:39 +01:00
{
2015-04-01 21:26:47 +01:00
_powerLevel = ( powerLevel > 31 ? 31 : powerLevel ) ;
if ( _isRFM69HW ) _powerLevel / = 2 ;
writeReg ( REG_PALEVEL , ( readReg ( REG_PALEVEL ) & 0xE0 ) | _powerLevel ) ;
2013-06-20 22:06:39 +01:00
}
bool RFM69 : : canSend ( )
{
2015-01-06 14:25:29 +00:00
if ( _mode = = RF69_MODE_RX & & PAYLOADLEN = = 0 & & readRSSI ( ) < CSMA_LIMIT ) // if signal stronger than -100dBm is detected assume channel activity
2013-06-20 22:06:39 +01:00
{
setMode ( RF69_MODE_STANDBY ) ;
return true ;
}
return false ;
}
2019-05-01 17:02:03 +01:00
void RFM69 : : send ( uint16_t toAddress , const void * buffer , uint8_t bufferSize , bool requestACK )
2013-06-20 22:06:39 +01:00
{
2013-07-14 04:49:26 +01:00
writeReg ( REG_PACKETCONFIG2 , ( readReg ( REG_PACKETCONFIG2 ) & 0xFB ) | RF_PACKET2_RXRESTART ) ; // avoid RX deadlocks
2015-01-12 10:34:16 +00:00
uint32_t now = millis ( ) ;
2015-01-12 10:00:43 +00:00
while ( ! canSend ( ) & & millis ( ) - now < RF69_CSMA_LIMIT_MS ) receiveDone ( ) ;
2013-06-20 22:06:39 +01:00
sendFrame ( toAddress , buffer , bufferSize , requestACK , false ) ;
}
2013-07-14 04:49:26 +01:00
// to increase the chance of getting a packet across, call this function instead of send
2013-06-20 22:06:39 +01:00
// and it handles all the ACK requesting/retrying for you :)
// The only twist is that you have to manually listen to ACK requests on the other side and send back the ACKs
2015-01-06 14:25:29 +00:00
// The reason for the semi-automaton is that the lib is interrupt driven and
2013-06-20 22:06:39 +01:00
// requires user action to read the received data and decide what to do with it
2015-01-12 10:00:43 +00:00
// replies usually take only 5..8ms at 50kbps@915MHz
2019-05-01 17:02:03 +01:00
bool RFM69 : : sendWithRetry ( uint16_t toAddress , const void * buffer , uint8_t bufferSize , uint8_t retries , uint8_t retryWaitTime ) {
2015-01-12 10:34:16 +00:00
uint32_t sentTime ;
for ( uint8_t i = 0 ; i < = retries ; i + + )
2013-06-20 22:06:39 +01:00
{
send ( toAddress , buffer , bufferSize , true ) ;
sentTime = millis ( ) ;
2015-01-12 10:00:43 +00:00
while ( millis ( ) - sentTime < retryWaitTime )
2013-06-20 22:06:39 +01:00
{
2019-05-01 17:02:03 +01:00
if ( ACKReceived ( toAddress ) ) return true ;
2013-06-20 22:06:39 +01:00
}
}
return false ;
}
2015-01-06 14:25:29 +00:00
// should be polled immediately after sending a packet with ACK request
2019-05-01 17:02:03 +01:00
bool RFM69 : : ACKReceived ( uint16_t fromNodeID ) {
2013-06-20 22:06:39 +01:00
if ( receiveDone ( ) )
2014-02-02 02:13:40 +00:00
return ( SENDERID = = fromNodeID | | fromNodeID = = RF69_BROADCAST_ADDR ) & & ACK_RECEIVED ;
2013-06-20 22:06:39 +01:00
return false ;
}
2015-01-06 14:25:29 +00:00
// check whether an ACK was requested in the last received packet (non-broadcasted packet)
2014-08-13 03:03:19 +01:00
bool RFM69 : : ACKRequested ( ) {
2020-01-21 17:56:23 +00:00
return ACK_REQUESTED & & ( TARGETID = = _address ) ;
2014-08-13 03:03:19 +01:00
}
2015-01-06 14:25:29 +00:00
// should be called immediately after reception in case sender wants ACK
2015-01-12 10:34:16 +00:00
void RFM69 : : sendACK ( const void * buffer , uint8_t bufferSize ) {
2015-10-01 17:15:28 +01:00
ACK_REQUESTED = 0 ; // TWS added to make sure we don't end up in a timing race and infinite loop sending Acks
2019-05-01 17:02:03 +01:00
uint16_t sender = SENDERID ;
2015-01-12 10:34:16 +00:00
int16_t _RSSI = RSSI ; // save payload received RSSI value
2014-11-17 19:58:00 +00:00
writeReg ( REG_PACKETCONFIG2 , ( readReg ( REG_PACKETCONFIG2 ) & 0xFB ) | RF_PACKET2_RXRESTART ) ; // avoid RX deadlocks
2015-01-12 10:34:16 +00:00
uint32_t now = millis ( ) ;
2015-01-12 10:00:43 +00:00
while ( ! canSend ( ) & & millis ( ) - now < RF69_CSMA_LIMIT_MS ) receiveDone ( ) ;
2016-02-29 19:36:24 +00:00
SENDERID = sender ; // TWS: Restore SenderID after it gets wiped out by receiveDone()
2013-07-14 04:49:26 +01:00
sendFrame ( sender , buffer , bufferSize , false , true ) ;
2015-01-06 14:25:29 +00:00
RSSI = _RSSI ; // restore payload RSSI
2013-06-20 22:06:39 +01:00
}
2015-05-19 20:08:41 +01:00
// internal function
2019-05-01 17:02:03 +01:00
void RFM69 : : sendFrame ( uint16_t toAddress , const void * buffer , uint8_t bufferSize , bool requestACK , bool sendACK )
2013-06-20 22:06:39 +01:00
{
2020-05-18 16:12:28 +01:00
//NOTE: overridden in RFM69_ATC!
2015-01-06 14:25:29 +00:00
setMode ( RF69_MODE_STANDBY ) ; // turn off receiver to prevent reception while filling fifo
while ( ( readReg ( REG_IRQFLAGS1 ) & RF_IRQFLAGS1_MODEREADY ) = = 0x00 ) ; // wait for ModeReady
2019-08-02 21:38:00 +01:00
//writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00); // DIO0 is "Packet Sent"
2014-08-13 03:03:19 +01:00
if ( bufferSize > RF69_MAX_DATA_LEN ) bufferSize = RF69_MAX_DATA_LEN ;
2013-06-20 22:06:39 +01:00
2015-02-06 11:21:13 +00:00
// control byte
uint8_t CTLbyte = 0x00 ;
2013-06-20 22:06:39 +01:00
if ( sendACK )
2015-10-01 17:15:28 +01:00
CTLbyte = RFM69_CTL_SENDACK ;
2013-06-20 22:06:39 +01:00
else if ( requestACK )
2015-10-01 17:15:28 +01:00
CTLbyte = RFM69_CTL_REQACK ;
2015-02-06 11:21:13 +00:00
2019-05-01 17:02:03 +01:00
if ( toAddress > 0xFF ) CTLbyte | = ( toAddress & 0x300 ) > > 6 ; //assign last 2 bits of address if > 255
if ( _address > 0xFF ) CTLbyte | = ( _address & 0x300 ) > > 8 ; //assign last 2 bits of address if > 255
2015-01-06 14:25:29 +00:00
// write to FIFO
2015-01-06 13:46:04 +00:00
select ( ) ;
2018-04-05 20:15:36 +01:00
SPI . transfer ( REG_FIFO | 0x80 ) ;
SPI . transfer ( bufferSize + 3 ) ;
2019-05-01 17:02:03 +01:00
SPI . transfer ( ( uint8_t ) toAddress ) ;
SPI . transfer ( ( uint8_t ) _address ) ;
2018-04-05 20:15:36 +01:00
SPI . transfer ( CTLbyte ) ;
2015-01-06 13:46:04 +00:00
2015-01-12 10:34:16 +00:00
for ( uint8_t i = 0 ; i < bufferSize ; i + + )
2018-04-05 20:15:36 +01:00
SPI . transfer ( ( ( uint8_t * ) buffer ) [ i ] ) ;
2015-01-06 13:46:04 +00:00
unselect ( ) ;
2013-06-20 22:06:39 +01:00
2015-01-12 10:00:43 +00:00
// no need to wait for transmit mode to be ready since its handled by the radio
2015-01-06 13:46:04 +00:00
setMode ( RF69_MODE_TX ) ;
2020-03-04 03:57:06 +00:00
//uint32_t txStart = millis();
2019-08-02 21:38:00 +01:00
//while (digitalRead(_interruptPin) == 0 && millis() - txStart < RF69_TX_LIMIT_MS); // wait for DIO0 to turn HIGH signalling transmission finish
while ( ( readReg ( REG_IRQFLAGS2 ) & RF_IRQFLAGS2_PACKETSENT ) = = 0x00 ) ; // wait for PacketSent
2013-06-20 22:06:39 +01:00
setMode ( RF69_MODE_STANDBY ) ;
}
2015-05-19 20:08:41 +01:00
// internal function - interrupt gets called when a packet is received
2013-06-20 22:06:39 +01:00
void RFM69 : : interruptHandler ( ) {
if ( _mode = = RF69_MODE_RX & & ( readReg ( REG_IRQFLAGS2 ) & RF_IRQFLAGS2_PAYLOADREADY ) )
{
setMode ( RF69_MODE_STANDBY ) ;
select ( ) ;
2018-04-05 20:15:36 +01:00
SPI . transfer ( REG_FIFO & 0x7F ) ;
PAYLOADLEN = SPI . transfer ( 0 ) ;
2015-01-06 14:25:29 +00:00
PAYLOADLEN = PAYLOADLEN > 66 ? 66 : PAYLOADLEN ; // precaution
2018-04-05 20:15:36 +01:00
TARGETID = SPI . transfer ( 0 ) ;
2019-05-01 17:02:03 +01:00
SENDERID = SPI . transfer ( 0 ) ;
uint8_t CTLbyte = SPI . transfer ( 0 ) ;
TARGETID | = ( uint16_t ( CTLbyte ) & 0x0C ) < < 6 ; //10 bit address (most significant 2 bits stored in bits(2,3) of CTL byte
SENDERID | = ( uint16_t ( CTLbyte ) & 0x03 ) < < 8 ; //10 bit address (most sifnigicant 2 bits stored in bits(0,1) of CTL byte
2019-08-02 21:38:00 +01:00
2020-01-21 17:52:45 +00:00
if ( ! ( _spyMode | | TARGETID = = _address | | TARGETID = = RF69_BROADCAST_ADDR ) // match this node's address, or broadcast address or anything in spy mode
2015-01-06 14:25:29 +00:00
| | PAYLOADLEN < 3 ) // address situation could receive packets that are malformed and don't fit this libraries extra fields
2013-06-20 22:06:39 +01:00
{
PAYLOADLEN = 0 ;
unselect ( ) ;
2014-11-17 19:58:00 +00:00
receiveBegin ( ) ;
2013-06-20 22:06:39 +01:00
return ;
}
2014-11-17 19:58:00 +00:00
2013-09-06 00:32:11 +01:00
DATALEN = PAYLOADLEN - 3 ;
2015-10-01 17:15:28 +01:00
ACK_RECEIVED = CTLbyte & RFM69_CTL_SENDACK ; // extract ACK-received flag
ACK_REQUESTED = CTLbyte & RFM69_CTL_REQACK ; // extract ACK-requested flag
interruptHook ( CTLbyte ) ; // TWS: hook to derived class interrupt function
2015-01-06 13:46:04 +00:00
2019-06-05 16:38:14 +01:00
for ( uint8_t i = 0 ; i < DATALEN ; i + + ) DATA [ i ] = SPI . transfer ( 0 ) ;
DATA [ DATALEN ] = 0 ; // add null at end of string // add null at end of string
2013-06-20 22:06:39 +01:00
unselect ( ) ;
setMode ( RF69_MODE_RX ) ;
}
2013-11-07 04:15:51 +00:00
RSSI = readRSSI ( ) ;
2013-06-20 22:06:39 +01:00
}
2015-05-19 20:08:41 +01:00
// internal function
2019-07-25 15:41:14 +01:00
ISR_PREFIX void RFM69 : : isr0 ( ) { _haveData = true ; }
2013-06-20 22:06:39 +01:00
2015-05-19 20:08:41 +01:00
// internal function
2013-06-20 22:06:39 +01:00
void RFM69 : : receiveBegin ( ) {
2013-07-14 04:49:26 +01:00
DATALEN = 0 ;
SENDERID = 0 ;
TARGETID = 0 ;
PAYLOADLEN = 0 ;
ACK_REQUESTED = 0 ;
ACK_RECEIVED = 0 ;
2018-04-05 21:20:12 +01:00
# if defined(RF69_LISTENMODE_ENABLE)
RF69_LISTEN_BURST_REMAINING_MS = 0 ;
# endif
2013-11-07 04:15:51 +00:00
RSSI = 0 ;
2013-07-14 04:49:26 +01:00
if ( readReg ( REG_IRQFLAGS2 ) & RF_IRQFLAGS2_PAYLOADREADY )
writeReg ( REG_PACKETCONFIG2 , ( readReg ( REG_PACKETCONFIG2 ) & 0xFB ) | RF_PACKET2_RXRESTART ) ; // avoid RX deadlocks
2015-01-06 14:25:29 +00:00
writeReg ( REG_DIOMAPPING1 , RF_DIOMAPPING1_DIO0_01 ) ; // set DIO0 to "PAYLOADREADY" in receive mode
2013-06-20 22:06:39 +01:00
setMode ( RF69_MODE_RX ) ;
}
2015-05-19 20:08:41 +01:00
// checks if a packet was received and/or puts transceiver in receive (ie RX or listen) mode
2013-06-20 22:06:39 +01:00
bool RFM69 : : receiveDone ( ) {
2018-08-08 20:34:31 +01:00
if ( _haveData ) {
_haveData = false ;
interruptHandler ( ) ;
}
2015-01-12 10:00:43 +00:00
if ( _mode = = RF69_MODE_RX & & PAYLOADLEN > 0 )
2013-06-20 22:06:39 +01:00
{
2016-03-01 02:21:52 +00:00
setMode ( RF69_MODE_STANDBY ) ; // enables interrupts
2013-06-20 22:06:39 +01:00
return true ;
}
2015-01-12 10:00:43 +00:00
else if ( _mode = = RF69_MODE_RX ) // already in RX no payload yet
2014-02-02 02:13:40 +00:00
{
return false ;
}
2013-06-20 22:06:39 +01:00
receiveBegin ( ) ;
return false ;
}
// To enable encryption: radio.encrypt("ABCDEFGHIJKLMNOP");
// To disable encryption: radio.encrypt(null) or radio.encrypt(0)
// KEY HAS TO BE 16 bytes !!!
void RFM69 : : encrypt ( const char * key ) {
2018-04-05 21:20:12 +01:00
# if defined(RF69_LISTENMODE_ENABLE)
_haveEncryptKey = key ;
# endif
2013-06-20 22:06:39 +01:00
setMode ( RF69_MODE_STANDBY ) ;
2015-01-06 14:25:29 +00:00
if ( key ! = 0 )
2013-06-20 22:06:39 +01:00
{
2018-04-05 21:20:12 +01:00
# if defined(RF69_LISTENMODE_ENABLE)
memcpy ( _encryptKey , key , 16 ) ;
# endif
2013-06-20 22:06:39 +01:00
select ( ) ;
2018-04-05 20:15:36 +01:00
SPI . transfer ( REG_AESKEY1 | 0x80 ) ;
2015-01-12 10:34:16 +00:00
for ( uint8_t i = 0 ; i < 16 ; i + + )
2018-04-05 20:15:36 +01:00
SPI . transfer ( key [ i ] ) ;
2013-06-20 22:06:39 +01:00
unselect ( ) ;
}
writeReg ( REG_PACKETCONFIG2 , ( readReg ( REG_PACKETCONFIG2 ) & 0xFE ) | ( key ? 1 : 0 ) ) ;
}
2015-05-19 20:08:41 +01:00
// get the received signal strength indicator (RSSI)
2015-01-12 10:34:16 +00:00
int16_t RFM69 : : readRSSI ( bool forceTrigger ) {
int16_t rssi = 0 ;
2013-06-20 22:06:39 +01:00
if ( forceTrigger )
{
2015-01-06 14:25:29 +00:00
// RSSI trigger not needed if DAGC is in continuous mode
2013-06-20 22:06:39 +01:00
writeReg ( REG_RSSICONFIG , RF_RSSI_START ) ;
2015-01-06 14:25:29 +00:00
while ( ( readReg ( REG_RSSICONFIG ) & RF_RSSI_DONE ) = = 0x00 ) ; // wait for RSSI_Ready
2013-06-20 22:06:39 +01:00
}
rssi = - readReg ( REG_RSSIVALUE ) ;
rssi > > = 1 ;
return rssi ;
}
2015-01-12 10:34:16 +00:00
uint8_t RFM69 : : readReg ( uint8_t addr )
2013-06-20 22:06:39 +01:00
{
select ( ) ;
2018-04-05 20:15:36 +01:00
SPI . transfer ( addr & 0x7F ) ;
uint8_t regval = SPI . transfer ( 0 ) ;
2013-06-20 22:06:39 +01:00
unselect ( ) ;
return regval ;
}
2015-01-12 10:34:16 +00:00
void RFM69 : : writeReg ( uint8_t addr , uint8_t value )
2013-06-20 22:06:39 +01:00
{
select ( ) ;
2018-04-05 20:15:36 +01:00
SPI . transfer ( addr | 0x80 ) ;
SPI . transfer ( value ) ;
2013-06-20 22:06:39 +01:00
unselect ( ) ;
}
2015-05-19 20:08:41 +01:00
// select the RFM69 transceiver (save SPI settings, set CS low)
2013-06-20 22:06:39 +01:00
void RFM69 : : select ( ) {
2016-03-01 02:21:52 +00:00
# if defined (SPCR) && defined (SPSR)
// save current SPI settings
_SPCR = SPCR ;
_SPSR = SPSR ;
# endif
2018-12-14 00:39:20 +00:00
# ifdef SPI_HAS_TRANSACTION
SPI . beginTransaction ( _settings ) ;
2020-01-21 17:57:21 +00:00
# else
// set RFM69 SPI settings explicitly
2018-04-05 20:15:36 +01:00
SPI . setDataMode ( SPI_MODE0 ) ;
SPI . setBitOrder ( MSBFIRST ) ;
2020-05-18 16:12:28 +01:00
# ifdef defined(__SAMD51__)
SPI . setClockDivider ( SPI_CLOCK_DIV16 ) ;
# else
SPI . setClockDivider ( SPI_CLOCK_DIV2 ) ;
# endif
2018-01-26 00:35:46 +00:00
# endif
2013-06-20 22:06:39 +01:00
digitalWrite ( _slaveSelectPin , LOW ) ;
}
2015-05-19 20:08:41 +01:00
// unselect the RFM69 transceiver (set CS high, restore SPI settings)
2013-06-20 22:06:39 +01:00
void RFM69 : : unselect ( ) {
digitalWrite ( _slaveSelectPin , HIGH ) ;
2018-12-14 00:39:20 +00:00
# ifdef SPI_HAS_TRANSACTION
SPI . endTransaction ( ) ;
# endif
2015-01-06 14:25:29 +00:00
// restore SPI settings to what they were before talking to RFM69
2016-03-01 02:21:52 +00:00
# if defined (SPCR) && defined (SPSR)
SPCR = _SPCR ;
SPSR = _SPSR ;
2016-02-29 19:36:24 +00:00
# endif
2013-06-20 22:06:39 +01:00
}
2020-01-21 17:52:45 +00:00
// true = disable ID filtering to capture all packets on network, regardless of TARGETID
// false (default) = enable node/broadcast ID filtering to capture only frames sent to this/broadcast address
void RFM69 : : spyMode ( bool onOff ) {
_spyMode = onOff ;
2013-06-20 22:06:39 +01:00
//writeReg(REG_PACKETCONFIG1, (readReg(REG_PACKETCONFIG1) & 0xF9) | (onOff ? RF_PACKET1_ADRSFILTERING_OFF : RF_PACKET1_ADRSFILTERING_NODEBROADCAST));
}
2020-01-21 17:52:45 +00:00
void RFM69 : : promiscuous ( bool onOff ) {
2020-04-16 14:57:48 +01:00
# pragma message ("\nRFM69::promiscuous(bool): DEPRECATED, use spyMode(bool) instead!\n")
2020-01-21 17:52:45 +00:00
spyMode ( onOff ) ;
}
2015-05-19 20:08:41 +01:00
// for RFM69HW only: you must call setHighPower(true) after initialize() or else transmission won't work
2013-06-20 22:06:39 +01:00
void RFM69 : : setHighPower ( bool onOff ) {
_isRFM69HW = onOff ;
writeReg ( REG_OCP , _isRFM69HW ? RF_OCP_OFF : RF_OCP_ON ) ;
2015-01-06 14:25:29 +00:00
if ( _isRFM69HW ) // turning ON
writeReg ( REG_PALEVEL , ( readReg ( REG_PALEVEL ) & 0x1F ) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON ) ; // enable P1 & P2 amplifier stages
2013-06-20 22:06:39 +01:00
else
2015-01-06 14:25:29 +00:00
writeReg ( REG_PALEVEL , RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | _powerLevel ) ; // enable P0 only
2013-06-20 22:06:39 +01:00
}
2015-05-19 20:08:41 +01:00
// internal function
2013-06-20 22:06:39 +01:00
void RFM69 : : setHighPowerRegs ( bool onOff ) {
writeReg ( REG_TESTPA1 , onOff ? 0x5D : 0x55 ) ;
writeReg ( REG_TESTPA2 , onOff ? 0x7C : 0x70 ) ;
}
2015-05-19 20:08:41 +01:00
// set the slave select (CS) pin
2015-01-12 10:34:16 +00:00
void RFM69 : : setCS ( uint8_t newSPISlaveSelect ) {
2013-06-20 22:06:39 +01:00
_slaveSelectPin = newSPISlaveSelect ;
2015-01-18 11:31:16 +00:00
digitalWrite ( _slaveSelectPin , HIGH ) ;
2013-06-20 22:06:39 +01:00
pinMode ( _slaveSelectPin , OUTPUT ) ;
}
//for debugging
2015-08-23 03:13:20 +01:00
# define REGISTER_DETAIL 0
2014-11-12 04:05:36 +00:00
# if REGISTER_DETAIL
// SERIAL PRINT
// replace Serial.print("string") with SerialPrint("string")
# define SerialPrint(x) SerialPrint_P(PSTR(x))
void SerialWrite ( uint8_t c ) {
Serial . write ( c ) ;
}
void SerialPrint_P ( PGM_P str , void ( * f ) ( uint8_t ) = SerialWrite ) {
for ( uint8_t c ; ( c = pgm_read_byte ( str ) ) ; str + + ) ( * f ) ( c ) ;
}
# endif
2013-06-20 22:06:39 +01:00
void RFM69 : : readAllRegs ( )
{
2015-01-12 10:34:16 +00:00
uint8_t regVal ;
2014-11-12 04:05:36 +00:00
# if REGISTER_DETAIL
2014-11-11 05:02:52 +00:00
int capVal ;
2014-11-10 00:01:51 +00:00
2014-11-12 04:05:36 +00:00
//... State Variables for intelligent decoding
2015-08-23 02:03:51 +01:00
uint8_t modeFSK = 0 ;
2014-11-12 04:05:36 +00:00
int bitRate = 0 ;
int freqDev = 0 ;
long freqCenter = 0 ;
# endif
2015-08-23 03:13:20 +01:00
Serial . println ( " Address - HEX - BIN " ) ;
2015-01-12 10:34:16 +00:00
for ( uint8_t regAddr = 1 ; regAddr < = 0x4F ; regAddr + + )
2015-01-06 13:46:04 +00:00
{
2013-06-20 22:06:39 +01:00
select ( ) ;
2018-04-05 20:15:36 +01:00
SPI . transfer ( regAddr & 0x7F ) ; // send address + r/w bit
regVal = SPI . transfer ( 0 ) ;
2013-06-20 22:06:39 +01:00
unselect ( ) ;
Serial . print ( regAddr , HEX ) ;
Serial . print ( " - " ) ;
Serial . print ( regVal , HEX ) ;
Serial . print ( " - " ) ;
Serial . println ( regVal , BIN ) ;
2014-11-11 05:02:52 +00:00
2014-11-12 04:05:36 +00:00
# if REGISTER_DETAIL
2015-08-23 02:03:51 +01:00
switch ( regAddr )
{
2014-11-12 04:05:36 +00:00
case 0x1 : {
SerialPrint ( " Controls the automatic Sequencer ( see section 4.2 ) \n SequencerOff : " ) ;
2014-11-11 05:02:52 +00:00
if ( 0x80 & regVal ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 1 -> Mode is forced by the user \n " ) ;
2014-11-11 05:02:52 +00:00
} else {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 0 -> Operating mode as selected with Mode bits in RegOpMode is automatically reached with the Sequencer \n " ) ;
2014-11-11 05:02:52 +00:00
}
2014-11-12 04:05:36 +00:00
SerialPrint ( " \n Enables Listen mode, should be enabled whilst in Standby mode: \n ListenOn : " ) ;
2014-11-11 05:02:52 +00:00
if ( 0x40 & regVal ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 1 -> On \n " ) ;
2014-11-11 05:02:52 +00:00
} else {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 0 -> Off ( see section 4.3) \n " ) ;
2014-11-11 05:02:52 +00:00
}
2014-11-12 04:05:36 +00:00
SerialPrint ( " \n Aborts Listen mode when set together with ListenOn=0 See section 4.3.4 for details (Always reads 0.) \n " ) ;
2014-11-11 05:02:52 +00:00
if ( 0x20 & regVal ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " ERROR - ListenAbort should NEVER return 1 this is a write only register \n " ) ;
2014-11-11 05:02:52 +00:00
}
2014-11-12 04:05:36 +00:00
SerialPrint ( " \n Transceiver's operating modes: \n Mode : " ) ;
2014-11-11 05:02:52 +00:00
capVal = ( regVal > > 2 ) & 0x7 ;
if ( capVal = = 0b000 ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 000 -> Sleep mode (SLEEP) \n " ) ;
2014-11-11 05:02:52 +00:00
} else if ( capVal = 0b001 ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 001 -> Standby mode (STDBY) \n " ) ;
2014-11-11 05:02:52 +00:00
} else if ( capVal = 0b010 ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 010 -> Frequency Synthesizer mode (FS) \n " ) ;
2014-11-11 05:02:52 +00:00
} else if ( capVal = 0b011 ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 011 -> Transmitter mode (TX) \n " ) ;
2014-11-11 05:02:52 +00:00
} else if ( capVal = 0b100 ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 100 -> Receiver Mode (RX) \n " ) ;
2014-11-11 05:02:52 +00:00
} else {
Serial . print ( capVal , BIN ) ;
2014-11-12 04:05:36 +00:00
SerialPrint ( " -> RESERVED \n " ) ;
2014-11-11 05:02:52 +00:00
}
2014-11-12 04:05:36 +00:00
SerialPrint ( " \n " ) ;
2014-11-11 05:02:52 +00:00
break ;
}
case 0x2 : {
2014-11-12 04:05:36 +00:00
SerialPrint ( " Data Processing mode: \n DataMode : " ) ;
2014-11-11 05:02:52 +00:00
capVal = ( regVal > > 5 ) & 0x3 ;
if ( capVal = = 0b00 ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 00 -> Packet mode \n " ) ;
2014-11-11 05:02:52 +00:00
} else if ( capVal = = 0b01 ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 01 -> reserved \n " ) ;
2014-11-11 05:02:52 +00:00
} else if ( capVal = = 0b10 ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 10 -> Continuous mode with bit synchronizer \n " ) ;
2014-11-11 05:02:52 +00:00
} else if ( capVal = = 0b11 ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 11 -> Continuous mode without bit synchronizer \n " ) ;
2014-11-11 05:02:52 +00:00
}
2014-11-12 04:05:36 +00:00
SerialPrint ( " \n Modulation scheme: \n Modulation Type : " ) ;
2014-11-11 05:02:52 +00:00
capVal = ( regVal > > 3 ) & 0x3 ;
if ( capVal = = 0b00 ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 00 -> FSK \n " ) ;
modeFSK = 1 ;
2014-11-11 05:02:52 +00:00
} else if ( capVal = = 0b01 ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 01 -> OOK \n " ) ;
2014-11-11 05:02:52 +00:00
} else if ( capVal = = 0b10 ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 10 -> reserved \n " ) ;
2014-11-11 05:02:52 +00:00
} else if ( capVal = = 0b11 ) {
2014-11-12 04:05:36 +00:00
SerialPrint ( " 11 -> reserved \n " ) ;
2014-11-11 05:02:52 +00:00
}
2014-11-12 04:05:36 +00:00
SerialPrint ( " \n Data shaping: " ) ;
if ( modeFSK ) {
SerialPrint ( " in FSK: \n " ) ;
} else {
SerialPrint ( " in OOK: \n " ) ;
}
SerialPrint ( " ModulationShaping : " ) ;
capVal = regVal & 0x3 ;
if ( modeFSK ) {
if ( capVal = = 0b00 ) {
SerialPrint ( " 00 -> no shaping \n " ) ;
} else if ( capVal = = 0b01 ) {
SerialPrint ( " 01 -> Gaussian filter, BT = 1.0 \n " ) ;
} else if ( capVal = = 0b10 ) {
SerialPrint ( " 10 -> Gaussian filter, BT = 0.5 \n " ) ;
} else if ( capVal = = 0b11 ) {
SerialPrint ( " 11 -> Gaussian filter, BT = 0.3 \n " ) ;
}
} else {
if ( capVal = = 0b00 ) {
SerialPrint ( " 00 -> no shaping \n " ) ;
} else if ( capVal = = 0b01 ) {
SerialPrint ( " 01 -> filtering with f(cutoff) = BR \n " ) ;
} else if ( capVal = = 0b10 ) {
SerialPrint ( " 10 -> filtering with f(cutoff) = 2*BR \n " ) ;
} else if ( capVal = = 0b11 ) {
SerialPrint ( " ERROR - 11 is reserved \n " ) ;
}
}
2014-11-11 05:02:52 +00:00
2014-11-12 04:05:36 +00:00
SerialPrint ( " \n " ) ;
2014-11-11 05:02:52 +00:00
break ;
}
2014-11-12 04:05:36 +00:00
case 0x3 : {
bitRate = ( regVal < < 8 ) ;
break ;
}
case 0x4 : {
bitRate | = regVal ;
SerialPrint ( " Bit Rate (Chip Rate when Manchester encoding is enabled) \n BitRate : " ) ;
unsigned long val = 32UL * 1000UL * 1000UL / bitRate ;
Serial . println ( val ) ;
SerialPrint ( " \n " ) ;
break ;
}
case 0x5 : {
freqDev = ( ( regVal & 0x3f ) < < 8 ) ;
break ;
}
case 0x6 : {
freqDev | = regVal ;
SerialPrint ( " Frequency deviation \n Fdev : " ) ;
2018-04-15 19:57:45 +01:00
unsigned long val = RF69_FSTEP * freqDev ;
2014-11-12 04:05:36 +00:00
Serial . println ( val ) ;
SerialPrint ( " \n " ) ;
break ;
}
case 0x7 : {
unsigned long tempVal = regVal ;
freqCenter = ( tempVal < < 16 ) ;
break ;
}
case 0x8 : {
unsigned long tempVal = regVal ;
freqCenter = freqCenter | ( tempVal < < 8 ) ;
break ;
}
case 0x9 : {
freqCenter = freqCenter | regVal ;
SerialPrint ( " RF Carrier frequency \n FRF : " ) ;
2018-04-15 19:57:45 +01:00
unsigned long val = RF69_FSTEP * freqCenter ;
2014-11-12 04:05:36 +00:00
Serial . println ( val ) ;
SerialPrint ( " \n " ) ;
break ;
}
case 0xa : {
SerialPrint ( " RC calibration control & status \n RcCalDone : " ) ;
if ( 0x40 & regVal ) {
SerialPrint ( " 1 -> RC calibration is over \n " ) ;
} else {
SerialPrint ( " 0 -> RC calibration is in progress \n " ) ;
}
SerialPrint ( " \n " ) ;
break ;
2014-11-11 05:02:52 +00:00
}
2014-11-12 04:05:36 +00:00
case 0xb : {
SerialPrint ( " Improved AFC routine for signals with modulation index lower than 2. Refer to section 3.4.16 for details \n AfcLowBetaOn : " ) ;
if ( 0x20 & regVal ) {
SerialPrint ( " 1 -> Improved AFC routine \n " ) ;
} else {
SerialPrint ( " 0 -> Standard AFC routine \n " ) ;
}
SerialPrint ( " \n " ) ;
break ;
}
case 0xc : {
SerialPrint ( " Reserved \n \n " ) ;
break ;
}
case 0xd : {
byte val ;
SerialPrint ( " Resolution of Listen mode Idle time (calibrated RC osc): \n ListenResolIdle : " ) ;
val = regVal > > 6 ;
if ( val = = 0b00 ) {
SerialPrint ( " 00 -> reserved \n " ) ;
} else if ( val = = 0b01 ) {
SerialPrint ( " 01 -> 64 us \n " ) ;
} else if ( val = = 0b10 ) {
SerialPrint ( " 10 -> 4.1 ms \n " ) ;
} else if ( val = = 0b11 ) {
SerialPrint ( " 11 -> 262 ms \n " ) ;
}
2014-11-11 05:02:52 +00:00
2014-11-12 04:05:36 +00:00
SerialPrint ( " \n Resolution of Listen mode Rx time (calibrated RC osc): \n ListenResolRx : " ) ;
val = ( regVal > > 4 ) & 0x3 ;
if ( val = = 0b00 ) {
SerialPrint ( " 00 -> reserved \n " ) ;
} else if ( val = = 0b01 ) {
SerialPrint ( " 01 -> 64 us \n " ) ;
} else if ( val = = 0b10 ) {
SerialPrint ( " 10 -> 4.1 ms \n " ) ;
} else if ( val = = 0b11 ) {
SerialPrint ( " 11 -> 262 ms \n " ) ;
}
SerialPrint ( " \n Criteria for packet acceptance in Listen mode: \n ListenCriteria : " ) ;
if ( 0x8 & regVal ) {
SerialPrint ( " 1 -> signal strength is above RssiThreshold and SyncAddress matched \n " ) ;
} else {
SerialPrint ( " 0 -> signal strength is above RssiThreshold \n " ) ;
}
2014-11-11 05:02:52 +00:00
2014-11-12 04:05:36 +00:00
SerialPrint ( " \n Action taken after acceptance of a packet in Listen mode: \n ListenEnd : " ) ;
val = ( regVal > > 1 ) & 0x3 ;
if ( val = = 0b00 ) {
SerialPrint ( " 00 -> chip stays in Rx mode. Listen mode stops and must be disabled (see section 4.3) \n " ) ;
} else if ( val = = 0b01 ) {
SerialPrint ( " 01 -> chip stays in Rx mode until PayloadReady or Timeout interrupt occurs. It then goes to the mode defined by Mode. Listen mode stops and must be disabled (see section 4.3) \n " ) ;
} else if ( val = = 0b10 ) {
SerialPrint ( " 10 -> chip stays in Rx mode until PayloadReady or Timeout occurs. Listen mode then resumes in Idle state. FIFO content is lost at next Rx wakeup. \n " ) ;
} else if ( val = = 0b11 ) {
SerialPrint ( " 11 -> Reserved \n " ) ;
}
SerialPrint ( " \n " ) ;
break ;
}
2014-11-11 05:02:52 +00:00
2014-11-12 04:05:36 +00:00
default : {
}
2014-11-11 05:02:52 +00:00
}
# endif
2015-01-06 13:46:04 +00:00
}
2013-06-20 22:06:39 +01:00
unselect ( ) ;
}
2017-07-24 18:41:41 +01:00
void RFM69 : : readAllRegsCompact ( ) {
// Print the header row and first register entry
Serial . println ( ) ; Serial . print ( " " ) ;
for ( uint8_t reg = 0x00 ; reg < 0x10 ; reg + + ) {
Serial . print ( reg , HEX ) ;
Serial . print ( " " ) ;
}
Serial . println ( ) ;
Serial . print ( " 00: -- " ) ;
// Loop over the registers from 0x01 to 0x7F and print their values
for ( uint8_t reg = 0x01 ; reg < 0x80 ; reg + + ) {
if ( reg % 16 = = 0 ) { // Print the header column entries
Serial . println ( ) ;
Serial . print ( reg , HEX ) ;
Serial . print ( " : " ) ;
}
// Print the actual register values
uint8_t ret = readReg ( reg ) ;
if ( ret < 0x10 ) Serial . print ( " 0 " ) ; // Handle values less than 10
Serial . print ( ret , HEX ) ;
Serial . print ( " " ) ;
}
}
2015-01-12 10:34:16 +00:00
uint8_t RFM69 : : readTemperature ( uint8_t calFactor ) // returns centigrade
2013-09-06 00:32:11 +01:00
{
setMode ( RF69_MODE_STANDBY ) ;
writeReg ( REG_TEMP1 , RF_TEMP1_MEAS_START ) ;
2015-01-03 01:24:25 +00:00
while ( ( readReg ( REG_TEMP1 ) & RF_TEMP1_MEAS_RUNNING ) ) ;
2015-01-12 10:00:43 +00:00
return ~ readReg ( REG_TEMP2 ) + COURSE_TEMP_COEF + calFactor ; // 'complement' corrects the slope, rising temp = rising val
2015-01-06 13:46:04 +00:00
} // COURSE_TEMP_COEF puts reading in the ballpark, user can add additional correction
2013-09-06 00:32:11 +01:00
void RFM69 : : rcCalibration ( )
{
writeReg ( REG_OSC1 , RF_OSC1_RCCAL_START ) ;
while ( ( readReg ( REG_OSC1 ) & RF_OSC1_RCCAL_DONE ) = = 0x00 ) ;
2016-06-04 19:22:45 +01:00
}
2018-04-05 21:20:12 +01:00
//=============================================================================
// ListenMode specific functions
//=============================================================================
# if defined(RF69_LISTENMODE_ENABLE)
2019-08-02 21:38:00 +01:00
RFM69 * RFM69 : : selfPointer = 0 ;
2018-04-05 21:20:12 +01:00
volatile uint16_t RFM69 : : RF69_LISTEN_BURST_REMAINING_MS = 0 ;
//=============================================================================
// reinitRadio() - use base class initialization with saved values
//=============================================================================
bool RFM69 : : reinitRadio ( )
{
if ( ! initialize ( _freqBand , _address , _networkID ) ) return false ;
if ( _haveEncryptKey ) RFM69 : : encrypt ( _encryptKey ) ; // Restore the encryption key if necessary
if ( _isHighSpeed ) writeReg ( REG_LNA , ( readReg ( REG_LNA ) & ~ 0x3 ) | RF_LNA_GAINSELECT_AUTO ) ;
return true ;
}
static uint32_t getUsForResolution ( uint8_t resolution )
{
switch ( resolution ) {
case RF_LISTEN1_RESOL_RX_64 :
case RF_LISTEN1_RESOL_IDLE_64 :
return 64 ;
case RF_LISTEN1_RESOL_RX_4100 :
case RF_LISTEN1_RESOL_IDLE_4100 :
return 4100 ;
case RF_LISTEN1_RESOL_RX_262000 :
case RF_LISTEN1_RESOL_IDLE_262000 :
return 262000 ;
default :
// Whoops
return 0 ;
}
}
static uint32_t getCoefForResolution ( uint8_t resolution , uint32_t duration )
{
uint32_t resolDuration = getUsForResolution ( resolution ) ;
uint32_t result = duration / resolDuration ;
// If the next-higher coefficient is closer, use that
if ( abs ( duration - ( ( result + 1 ) * resolDuration ) ) < abs ( duration - ( result * resolDuration ) ) )
return result + 1 ;
return result ;
}
static bool chooseResolutionAndCoef ( uint8_t * resolutions , uint32_t duration , uint8_t & resolOut , uint8_t & coefOut )
{
for ( int i = 0 ; resolutions [ i ] ; i + + ) {
uint32_t coef = getCoefForResolution ( resolutions [ i ] , duration ) ;
if ( coef < = 255 ) {
coefOut = coef ;
resolOut = resolutions [ i ] ;
return true ;
}
}
// out of range
return false ;
}
bool RFM69 : : listenModeSetDurations ( uint32_t & rxDuration , uint32_t & idleDuration )
{
uint8_t rxResolutions [ ] = { RF_LISTEN1_RESOL_RX_64 , RF_LISTEN1_RESOL_RX_4100 , RF_LISTEN1_RESOL_RX_262000 , 0 } ;
uint8_t idleResolutions [ ] = { RF_LISTEN1_RESOL_IDLE_64 , RF_LISTEN1_RESOL_IDLE_4100 , RF_LISTEN1_RESOL_IDLE_262000 , 0 } ;
if ( ! chooseResolutionAndCoef ( rxResolutions , rxDuration , _rxListenResolution , _rxListenCoef ) )
return false ;
if ( ! chooseResolutionAndCoef ( idleResolutions , idleDuration , _idleListenResolution , _idleListenCoef ) )
return false ;
rxDuration = getUsForResolution ( _rxListenResolution ) * _rxListenCoef ;
idleDuration = getUsForResolution ( _idleListenResolution ) * _idleListenCoef ;
_listenCycleDurationUs = rxDuration + idleDuration ;
return true ;
}
void RFM69 : : listenModeGetDurations ( uint32_t & rxDuration , uint32_t & idleDuration )
{
rxDuration = getUsForResolution ( _rxListenResolution ) * _rxListenCoef ;
idleDuration = getUsForResolution ( _idleListenResolution ) * _idleListenCoef ;
}
void RFM69 : : listenModeReset ( void )
{
DATALEN = 0 ;
SENDERID = 0 ;
TARGETID = 0 ;
PAYLOADLEN = 0 ;
ACK_REQUESTED = 0 ;
ACK_RECEIVED = 0 ;
RF69_LISTEN_BURST_REMAINING_MS = 0 ;
}
//=============================================================================
// irq handler, simply calls listenModeInterruptHandler method so internal methods can be accessed easily
//=============================================================================
2020-03-04 03:57:06 +00:00
ISR_PREFIX void RFM69 : : listenModeIrq ( ) { selfPointer - > listenModeInterruptHandler ( ) ; }
2018-04-05 21:20:12 +01:00
//=============================================================================
// listenModeInterruptHandler() - only called by listen irq handler
//=============================================================================
void RFM69 : : listenModeInterruptHandler ( void )
{
if ( DATALEN ! = 0 ) return ;
listenModeReset ( ) ;
noInterrupts ( ) ;
select ( ) ;
union / / union to simplify addressing of long and short parts of time offset
{
uint32_t l ;
uint8_t b [ 4 ] ;
} burstRemaining ;
burstRemaining . l = 0 ;
SPI . transfer ( REG_FIFO & 0x7F ) ;
PAYLOADLEN = SPI . transfer ( 0 ) ;
PAYLOADLEN = PAYLOADLEN > 64 ? 64 : PAYLOADLEN ; // precaution
TARGETID = SPI . transfer ( 0 ) ;
2020-01-21 17:52:45 +00:00
if ( ! ( _spyMode | | TARGETID = = _address | | TARGETID = = RF69_BROADCAST_ADDR ) // match this node's address, or broadcast address or anything in spy mode
2018-04-05 21:20:12 +01:00
| | PAYLOADLEN < 3 ) // address situation could receive packets that are malformed and don't fit this library's extra fields
{
listenModeReset ( ) ;
goto out ;
}
// We've read the target, and will read the sender id and two time offset bytes for a total of 4 bytes
DATALEN = PAYLOADLEN - 4 ;
SENDERID = SPI . transfer ( 0 ) ;
burstRemaining . b [ 0 ] = SPI . transfer ( 0 ) ; // and get the time remaining
burstRemaining . b [ 1 ] = SPI . transfer ( 0 ) ;
RF69_LISTEN_BURST_REMAINING_MS = burstRemaining . l ;
for ( uint8_t i = 0 ; i < DATALEN ; i + + )
DATA [ i ] = SPI . transfer ( 0 ) ;
if ( DATALEN < RF69_MAX_DATA_LEN )
DATA [ DATALEN ] = 0 ; // add null at end of string
out :
unselect ( ) ;
interrupts ( ) ;
}
//=============================================================================
// listenModeStart() - switch radio to Listen Mode in prep for sleep until burst
//=============================================================================
void RFM69 : : listenModeStart ( void )
{
//pRadio = this;
while ( readReg ( REG_IRQFLAGS2 ) & RF_IRQFLAGS2_PACKETSENT = = 0x00 ) ; // wait for ModeReady
listenModeReset ( ) ;
detachInterrupt ( _interruptNum ) ;
attachInterrupt ( _interruptNum , listenModeIrq , RISING ) ;
setMode ( RF69_MODE_STANDBY ) ;
writeReg ( REG_DIOMAPPING1 , RF_DIOMAPPING1_DIO0_01 ) ;
writeReg ( REG_FRFMSB , readReg ( REG_FRFMSB ) + 1 ) ;
writeReg ( REG_FRFLSB , readReg ( REG_FRFLSB ) ) ; // MUST write to LSB to affect change!
listenModeApplyHighSpeedSettings ( ) ;
writeReg ( REG_PACKETCONFIG1 , RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_WHITENING | RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON ) ;
writeReg ( REG_PACKETCONFIG2 , RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF ) ;
writeReg ( REG_SYNCVALUE1 , 0x5A ) ;
writeReg ( REG_SYNCVALUE2 , 0x5A ) ;
writeReg ( REG_LISTEN1 , _rxListenResolution | _idleListenResolution | RF_LISTEN1_CRITERIA_RSSI | RF_LISTEN1_END_10 ) ;
writeReg ( REG_LISTEN2 , _idleListenCoef ) ;
writeReg ( REG_LISTEN3 , _rxListenCoef ) ;
writeReg ( REG_RSSITHRESH , 180 ) ;
writeReg ( REG_RXTIMEOUT2 , 75 ) ;
writeReg ( REG_OPMODE , RF_OPMODE_SEQUENCER_ON | RF_OPMODE_STANDBY ) ;
writeReg ( REG_OPMODE , RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_ON | RF_OPMODE_STANDBY ) ;
}
//=============================================================================
// listenModeEnd() - exit listen mode and reinit the radio
//=============================================================================
void RFM69 : : listenModeEnd ( void )
{
detachInterrupt ( _interruptNum ) ;
writeReg ( REG_OPMODE , RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTENABORT | RF_OPMODE_STANDBY ) ;
writeReg ( REG_OPMODE , RF_OPMODE_SEQUENCER_ON | RF_OPMODE_STANDBY ) ;
writeReg ( REG_RXTIMEOUT2 , 0 ) ;
setMode ( RF69_MODE_STANDBY ) ;
while ( ( readReg ( REG_IRQFLAGS1 ) & RF_IRQFLAGS1_MODEREADY ) = = 0x00 ) ; // wait for ModeReady
listenModeReset ( ) ;
reinitRadio ( ) ;
}
void RFM69 : : listenModeApplyHighSpeedSettings ( )
{
if ( ! _isHighSpeed ) return ;
writeReg ( REG_BITRATEMSB , RF_BITRATEMSB_200000 ) ;
writeReg ( REG_BITRATELSB , RF_BITRATELSB_200000 ) ;
writeReg ( REG_FDEVMSB , RF_FDEVMSB_100000 ) ;
writeReg ( REG_FDEVLSB , RF_FDEVLSB_100000 ) ;
writeReg ( REG_RXBW , RF_RXBW_DCCFREQ_000 | RF_RXBW_MANT_20 | RF_RXBW_EXP_0 ) ;
// Force LNA to the highest gain
//writeReg(REG_LNA, (readReg(REG_LNA) << 2) | RF_LNA_GAINSELECT_MAX);
}
//=============================================================================
// sendBurst() - send a burst of packets to a sleeping listening node (or all)
//=============================================================================
2019-05-01 16:35:34 +01:00
void RFM69 : : listenModeSendBurst ( uint8_t targetNode , const void * buffer , uint8_t size )
2018-04-05 21:20:12 +01:00
{
detachInterrupt ( _interruptNum ) ;
setMode ( RF69_MODE_STANDBY ) ;
writeReg ( REG_PACKETCONFIG1 , RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_WHITENING | RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON ) ;
writeReg ( REG_PACKETCONFIG2 , RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF ) ;
writeReg ( REG_SYNCVALUE1 , 0x5A ) ;
writeReg ( REG_SYNCVALUE2 , 0x5A ) ;
listenModeApplyHighSpeedSettings ( ) ;
writeReg ( REG_FRFMSB , readReg ( REG_FRFMSB ) + 1 ) ;
writeReg ( REG_FRFLSB , readReg ( REG_FRFLSB ) ) ; // MUST write to LSB to affect change!
union / / union to simplify addressing of long and short parts of time offset
{
int32_t l ;
uint8_t b [ 4 ] ;
} timeRemaining ;
uint16_t cycleDurationMs = _listenCycleDurationUs / 1000 ;
timeRemaining . l = cycleDurationMs ;
# ifdef RF69_WL_DEBUG
Serial . print ( " Sending burst for " ) ;
Serial . print ( cycleDurationMs , DEC ) ;
Serial . println ( " ms " ) ;
# endif
setMode ( RF69_MODE_TX ) ;
uint32_t numSent = 0 ;
uint32_t startTime = millis ( ) ;
while ( timeRemaining . l > 0 ) {
noInterrupts ( ) ;
// write to FIFO
select ( ) ;
SPI . transfer ( REG_FIFO | 0x80 ) ;
SPI . transfer ( size + 4 ) ; // two bytes for target and sender node, two bytes for the burst time remaining
SPI . transfer ( targetNode ) ;
SPI . transfer ( _address ) ;
// We send the burst time remaining with the packet so the receiver knows how long to wait before trying to reply
SPI . transfer ( timeRemaining . b [ 0 ] ) ;
SPI . transfer ( timeRemaining . b [ 1 ] ) ;
for ( uint8_t i = 0 ; i < size ; i + + ) {
SPI . transfer ( ( ( uint8_t * ) buffer ) [ i ] ) ;
}
unselect ( ) ;
interrupts ( ) ;
while ( ( readReg ( REG_IRQFLAGS2 ) & RF_IRQFLAGS2_FIFONOTEMPTY ) ! = 0x00 ) ; // make sure packet is sent before putting more into the FIFO
timeRemaining . l = cycleDurationMs - ( millis ( ) - startTime ) ;
}
setMode ( RF69_MODE_STANDBY ) ;
reinitRadio ( ) ;
}
# endif