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
// **********************************************************************************
2014-08-13 03:03:19 +01:00
// Copyright Felix Rusu (2014), felix@lowpowerlab.com
// http://lowpowerlab.com/
// **********************************************************************************
// 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.
//
// You should have received a copy of the GNU General
2014-11-14 20:25:45 +00:00
// Public License along with this program.
// If not, see <http://www.gnu.org/licenses/>.
2014-08-13 03:03:19 +01:00
//
// 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
// **********************************************************************************
2013-06-20 22:06:39 +01:00
# include <RFM69.h>
# include <RFM69registers.h>
# include <SPI.h>
2015-01-12 10:34:16 +00:00
volatile uint8_t RFM69 : : DATA [ RF69_MAX_DATA_LEN ] ;
volatile uint8_t RFM69 : : _mode ; // current transceiver state
volatile uint8_t RFM69 : : DATALEN ;
volatile uint8_t RFM69 : : SENDERID ;
volatile uint8_t RFM69 : : TARGETID ; // should match _address
volatile uint8_t RFM69 : : PAYLOADLEN ;
volatile uint8_t RFM69 : : ACK_REQUESTED ;
volatile uint8_t RFM69 : : ACK_RECEIVED ; // should be polled immediately after sending a packet with ACK request
volatile int16_t RFM69 : : RSSI ; // most accurate RSSI during reception (closest to the reception)
2013-06-20 22:06:39 +01:00
RFM69 * RFM69 : : selfPointer ;
2015-01-12 10:34:16 +00:00
bool RFM69 : : initialize ( uint8_t freqBand , uint8_t nodeID , uint8_t networkID )
2013-06-20 22:06:39 +01:00
{
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
2013-06-20 22:06:39 +01:00
// looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm
// +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-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
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-06 14:25:29 +00:00
///* 0x6F */ { REG_TESTDAGC, RF_DAGC_CONTINUOUS }, // run DAGC continuously in RX mode
2014-01-02 21:57:18 +00:00
/* 0x6F */ { REG_TESTDAGC , RF_DAGC_IMPROVED_LOWBETA0 } , // run DAGC continuously in RX mode, 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 ) ;
SPI . begin ( ) ;
2015-01-06 13:46:04 +00:00
2015-01-12 10:00:43 +00:00
do writeReg ( REG_SYNCVALUE1 , 0xAA ) ; while ( readReg ( REG_SYNCVALUE1 ) ! = 0xAA ) ;
2015-01-06 13:46:04 +00:00
do writeReg ( REG_SYNCVALUE1 , 0x55 ) ; while ( readReg ( REG_SYNCVALUE1 ) ! = 0x55 ) ;
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-01-06 14:25:29 +00:00
while ( ( readReg ( REG_IRQFLAGS1 ) & RF_IRQFLAGS1_MODEREADY ) = = 0x00 ) ; // wait for ModeReady
2014-08-13 03:03:19 +01:00
attachInterrupt ( _interruptNum , RFM69 : : isr0 , RISING ) ;
2013-06-20 22:06:39 +01:00
selfPointer = this ;
_address = nodeID ;
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 )
{
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
}
void RFM69 : : sleep ( ) {
setMode ( RF69_MODE_SLEEP ) ;
}
2015-01-12 10:34:16 +00:00
void RFM69 : : setAddress ( uint8_t addr )
2013-06-20 22:06:39 +01:00
{
2013-07-14 04:49:26 +01:00
_address = addr ;
2015-01-06 13:46:04 +00:00
writeReg ( REG_NODEADRS , _address ) ;
2013-06-20 22:06:39 +01:00
}
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 ) ;
2014-11-14 20:25:45 +00:00
}
2015-01-12 10:00:43 +00:00
// set 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-01-12 10:34:16 +00:00
void RFM69 : : setPowerLevel ( uint8_t powerLevel )
2013-06-20 22:06:39 +01:00
{
_powerLevel = powerLevel ;
2013-08-18 02:33:12 +01:00
writeReg ( REG_PALEVEL , ( readReg ( REG_PALEVEL ) & 0xE0 ) | ( _powerLevel > 31 ? 31 : _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 ;
}
2015-01-12 10:34:16 +00:00
void RFM69 : : send ( uint8_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
2015-01-12 10:34:16 +00:00
bool RFM69 : : sendWithRetry ( uint8_t toAddress , const void * buffer , uint8_t bufferSize , uint8_t retries , uint8_t retryWaitTime ) {
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
{
if ( ACKReceived ( toAddress ) )
{
2015-01-12 10:00:43 +00:00
//Serial.print(" ~ms:"); Serial.print(millis() - sentTime);
2013-06-20 22:06:39 +01:00
return true ;
}
}
2015-01-12 10:00:43 +00:00
//Serial.print(" RETRY#"); Serial.println(i + 1);
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
2015-01-12 10:34:16 +00:00
bool RFM69 : : ACKReceived ( uint8_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 ( ) {
return ACK_REQUESTED & & ( TARGETID ! = RF69_BROADCAST_ADDR ) ;
}
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 ) {
uint8_t sender = SENDERID ;
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 ( ) ;
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-01-12 10:34:16 +00:00
void RFM69 : : sendFrame ( uint8_t toAddress , const void * buffer , uint8_t bufferSize , bool requestACK , bool sendACK )
2013-06-20 22:06:39 +01:00
{
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
2013-07-14 04:49:26 +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-01-06 14:25:29 +00:00
// write to FIFO
2015-01-06 13:46:04 +00:00
select ( ) ;
SPI . transfer ( REG_FIFO | 0x80 ) ;
SPI . transfer ( bufferSize + 3 ) ;
SPI . transfer ( toAddress ) ;
2013-06-20 22:06:39 +01:00
SPI . transfer ( _address ) ;
2015-01-06 13:46:04 +00:00
2015-01-06 14:25:29 +00:00
// control byte
2013-06-20 22:06:39 +01:00
if ( sendACK )
SPI . transfer ( 0x80 ) ;
else if ( requestACK )
SPI . transfer ( 0x40 ) ;
else SPI . transfer ( 0x00 ) ;
2015-01-06 13:46:04 +00:00
2015-01-12 10:34:16 +00:00
for ( uint8_t i = 0 ; i < bufferSize ; i + + )
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 ) ;
2015-01-12 10:34:16 +00:00
uint32_t txStart = millis ( ) ;
2015-01-12 10:00:43 +00:00
while ( digitalRead ( _interruptPin ) = = 0 & & millis ( ) - txStart < RF69_TX_LIMIT_MS ) ; // wait for DIO0 to turn HIGH signalling transmission finish
2015-01-06 14:25:29 +00:00
//while (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PACKETSENT == 0x00); // wait for ModeReady
2013-06-20 22:06:39 +01:00
setMode ( RF69_MODE_STANDBY ) ;
}
void RFM69 : : interruptHandler ( ) {
2013-07-14 04:49:26 +01:00
//pinMode(4, OUTPUT);
//digitalWrite(4, 1);
2013-06-20 22:06:39 +01:00
if ( _mode = = RF69_MODE_RX & & ( readReg ( REG_IRQFLAGS2 ) & RF_IRQFLAGS2_PAYLOADREADY ) )
{
2014-08-13 03:03:19 +01:00
//RSSI = readRSSI();
2013-06-20 22:06:39 +01:00
setMode ( RF69_MODE_STANDBY ) ;
select ( ) ;
2015-01-12 10:00:43 +00:00
SPI . transfer ( REG_FIFO & 0x7F ) ;
2013-06-20 22:06:39 +01:00
PAYLOADLEN = SPI . transfer ( 0 ) ;
2015-01-06 14:25:29 +00:00
PAYLOADLEN = PAYLOADLEN > 66 ? 66 : PAYLOADLEN ; // precaution
2013-06-20 22:06:39 +01:00
TARGETID = SPI . transfer ( 0 ) ;
2015-01-06 14:25:29 +00:00
if ( ! ( _promiscuousMode | | TARGETID = = _address | | TARGETID = = RF69_BROADCAST_ADDR ) // match this node's address, or broadcast address or anything in promiscuous mode
| | 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-07-14 04:49:26 +01:00
//digitalWrite(4, 0);
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 ;
2013-07-14 04:49:26 +01:00
SENDERID = SPI . transfer ( 0 ) ;
2015-01-12 10:34:16 +00:00
uint8_t CTLbyte = SPI . transfer ( 0 ) ;
2015-01-06 13:46:04 +00:00
2015-01-06 14:25:29 +00:00
ACK_RECEIVED = CTLbyte & 0x80 ; // extract ACK-received flag
ACK_REQUESTED = CTLbyte & 0x40 ; // extract ACK-requested flag
2015-01-06 13:46:04 +00:00
2015-01-12 10:34:16 +00:00
for ( uint8_t i = 0 ; i < DATALEN ; i + + )
2013-06-20 22:06:39 +01:00
{
DATA [ i ] = SPI . transfer ( 0 ) ;
}
2015-01-12 10:00:43 +00:00
if ( DATALEN < RF69_MAX_DATA_LEN ) DATA [ DATALEN ] = 0 ; // 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-09-06 00:32:11 +01:00
//digitalWrite(4, 0);
2013-06-20 22:06:39 +01:00
}
void RFM69 : : isr0 ( ) { selfPointer - > interruptHandler ( ) ; }
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 ;
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 ) ;
}
bool RFM69 : : receiveDone ( ) {
2015-01-06 14:25:29 +00:00
//ATOMIC_BLOCK(ATOMIC_FORCEON)
//{
noInterrupts ( ) ; // re-enabled in unselect() via setMode() or via receiveBegin()
2015-01-12 10:00:43 +00:00
if ( _mode = = RF69_MODE_RX & & PAYLOADLEN > 0 )
2013-06-20 22:06:39 +01:00
{
2015-01-06 14:25:29 +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
{
2015-01-06 14:25:29 +00:00
interrupts ( ) ; // explicitly re-enable interrupts
2014-02-02 02:13:40 +00:00
return false ;
}
2013-06-20 22:06:39 +01:00
receiveBegin ( ) ;
return false ;
2013-07-14 04:49:26 +01:00
//}
2013-06-20 22:06:39 +01:00
}
// 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 ) {
setMode ( RF69_MODE_STANDBY ) ;
2015-01-06 14:25:29 +00:00
if ( key ! = 0 )
2013-06-20 22:06:39 +01:00
{
select ( ) ;
SPI . transfer ( REG_AESKEY1 | 0x80 ) ;
2015-01-12 10:34:16 +00:00
for ( uint8_t i = 0 ; i < 16 ; i + + )
2013-06-20 22:06:39 +01:00
SPI . transfer ( key [ i ] ) ;
unselect ( ) ;
}
writeReg ( REG_PACKETCONFIG2 , ( readReg ( REG_PACKETCONFIG2 ) & 0xFE ) | ( key ? 1 : 0 ) ) ;
}
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 ( ) ;
SPI . transfer ( addr & 0x7F ) ;
2015-01-12 10:34:16 +00:00
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 ( ) ;
SPI . transfer ( addr | 0x80 ) ;
2013-10-27 23:53:02 +00:00
SPI . transfer ( value ) ;
2013-06-20 22:06:39 +01:00
unselect ( ) ;
}
2015-01-06 14:25:29 +00:00
// select the transceiver
2013-06-20 22:06:39 +01:00
void RFM69 : : select ( ) {
noInterrupts ( ) ;
2015-01-06 14:25:29 +00:00
// save current SPI settings
2014-08-13 03:03:19 +01:00
_SPCR = SPCR ;
_SPSR = SPSR ;
2015-01-06 14:25:29 +00:00
// set RFM69 SPI settings
2014-08-13 03:03:19 +01:00
SPI . setDataMode ( SPI_MODE0 ) ;
SPI . setBitOrder ( MSBFIRST ) ;
2015-01-06 14:25:29 +00:00
SPI . setClockDivider ( SPI_CLOCK_DIV4 ) ; // decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present
2013-06-20 22:06:39 +01:00
digitalWrite ( _slaveSelectPin , LOW ) ;
}
2015-01-06 14:25:29 +00:00
// UNselect the transceiver chip
2013-06-20 22:06:39 +01:00
void RFM69 : : unselect ( ) {
digitalWrite ( _slaveSelectPin , HIGH ) ;
2015-01-06 14:25:29 +00:00
// restore SPI settings to what they were before talking to RFM69
2014-08-13 03:03:19 +01:00
SPCR = _SPCR ;
SPSR = _SPSR ;
2013-06-20 22:06:39 +01:00
interrupts ( ) ;
}
// ON = disable filtering to capture all frames on network
2015-01-12 10:00:43 +00:00
// OFF = enable node/broadcast filtering to capture only frames sent to this/broadcast address
2013-06-20 22:06:39 +01:00
void RFM69 : : promiscuous ( bool onOff ) {
2015-01-06 14:25:29 +00:00
_promiscuousMode = 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));
}
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
}
void RFM69 : : setHighPowerRegs ( bool onOff ) {
writeReg ( REG_TESTPA1 , onOff ? 0x5D : 0x55 ) ;
writeReg ( REG_TESTPA2 , onOff ? 0x7C : 0x70 ) ;
}
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 ) ;
}
2015-01-06 14:25:29 +00:00
// for debugging
2013-06-20 22:06:39 +01:00
void RFM69 : : readAllRegs ( )
{
2015-01-12 10:34:16 +00:00
uint8_t regVal ;
2015-01-06 13:46:04 +00:00
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 ( ) ;
2015-01-12 10:00:43 +00:00
SPI . transfer ( regAddr & 0x7F ) ; // send address + r/w bit
2013-06-20 22:06:39 +01:00
regVal = SPI . transfer ( 0 ) ;
unselect ( ) ;
Serial . print ( regAddr , HEX ) ;
Serial . print ( " - " ) ;
Serial . print ( regVal , HEX ) ;
Serial . print ( " - " ) ;
Serial . println ( regVal , BIN ) ;
2015-01-06 13:46:04 +00:00
}
2013-06-20 22:06:39 +01:00
unselect ( ) ;
}
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 ) ;
2015-01-03 01:24:25 +00:00
}