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>
2014-08-13 03:03:19 +01:00
volatile byte RFM69 : : DATA [ RF69_MAX_DATA_LEN ] ;
2015-01-06 14:25:29 +00:00
volatile byte RFM69 : : _mode ; // current transceiver state
2013-07-14 04:49:26 +01:00
volatile byte RFM69 : : DATALEN ;
volatile byte RFM69 : : SENDERID ;
2015-01-06 14:25:29 +00:00
volatile byte RFM69 : : TARGETID ; // should match _address
2013-07-14 04:49:26 +01:00
volatile byte RFM69 : : PAYLOADLEN ;
volatile byte RFM69 : : ACK_REQUESTED ;
2015-01-06 14:25:29 +00:00
volatile byte RFM69 : : ACK_RECEIVED ; // should be polled immediately after sending a packet with ACK request
volatile int RFM69 : : RSSI ; // most accurate RSSI during reception (closest to the reception)
2013-06-20 22:06:39 +01:00
RFM69 * RFM69 : : selfPointer ;
bool RFM69 : : initialize ( byte freqBand , byte nodeID , byte networkID )
{
const byte CONFIG [ ] [ 2 ] =
{
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
/* 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-06 14:25:29 +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 } ,
2013-07-14 04:49:26 +01:00
/* 0x07 */ { REG_FRFMSB , ( freqBand = = RF69_315MHZ ? RF_FRFMSB_315 : ( freqBand = = RF69_433MHZ ? RF_FRFMSB_433 : ( freqBand = = RF69_868MHZ ? RF_FRFMSB_868 : RF_FRFMSB_915 ) ) ) } ,
/* 0x08 */ { REG_FRFMID , ( freqBand = = RF69_315MHZ ? RF_FRFMID_315 : ( freqBand = = RF69_433MHZ ? RF_FRFMID_433 : ( freqBand = = RF69_868MHZ ? RF_FRFMID_868 : RF_FRFMID_915 ) ) ) } ,
/* 0x09 */ { REG_FRFLSB , ( 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
// +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)
///* 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
2013-09-06 00:32:11 +01: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
/* 0x29 */ { REG_RSSITHRESH , 220 } , // must be set to dBm = (-Sensitivity / 2) - default is 0xE4=228 so -114dBm
2013-06-20 22:06:39 +01:00
///* 0x2d */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE } // default 3 preamble bytes 0xAAAAAA
2013-07-14 04:49:26 +01:00
/* 0x2e */ { REG_SYNCCONFIG , RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0 } ,
2015-01-06 14:25:29 +00:00
/* 0x2f */ { REG_SYNCVALUE1 , 0x2D } , // attempt to make this compatible with sync1 byte of RFM12B lib
/* 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
/* 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)
///* 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
2013-06-20 22:06:39 +01:00
pinMode ( _slaveSelectPin , OUTPUT ) ;
SPI . begin ( ) ;
2015-01-06 13:46:04 +00:00
2013-06-20 22:06:39 +01: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
2013-06-20 22:06:39 +01:00
for ( byte i = 0 ; CONFIG [ i ] [ 0 ] ! = 255 ; i + + )
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
{
2014-11-14 20:25:45 +00:00
return RF69_FSTEP * ( ( ( uint32_t ) readReg ( REG_FRFMSB ) < < 16 ) + ( ( uint16_t ) readReg ( REG_FRFMID ) < < 8 ) + readReg ( REG_FRFLSB ) ) ;
}
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-06 14:25:29 +00:00
// TODO: p38 hopping sequence may need to be followed in some cases
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 ) ;
2013-06-20 22:06:39 +01:00
}
void RFM69 : : setMode ( byte newMode )
{
2015-01-06 14:25:29 +00:00
if ( newMode = = _mode ) return ; // TODO: can remove this?
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 ;
default : return ;
}
// 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 ) ;
}
void RFM69 : : setAddress ( byte addr )
{
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
}
2014-11-14 20:25:45 +00:00
void RFM69 : : setNetwork ( byte networkID )
{
2015-01-06 13:46:04 +00:00
writeReg ( REG_SYNCVALUE2 , networkID ) ;
2014-11-14 20:25:45 +00:00
}
2013-08-17 02:35:34 +01:00
// set output power: 0=min, 31=max
// this results in a "weaker" transmitted signal, and directly results in a lower RSSI at the receiver
2013-08-18 02:33:12 +01:00
void RFM69 : : setPowerLevel ( byte 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 ;
}
void RFM69 : : send ( byte toAddress , const void * buffer , byte bufferSize , bool requestACK )
{
2013-07-14 04:49:26 +01:00
writeReg ( REG_PACKETCONFIG2 , ( readReg ( REG_PACKETCONFIG2 ) & 0xFB ) | RF_PACKET2_RXRESTART ) ; // avoid RX deadlocks
2014-11-17 19:58:00 +00:00
unsigned long now = millis ( ) ;
2014-08-13 03:03:19 +01: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
2013-07-14 04:49:26 +01:00
// replies usually take only 5-8ms at 50kbps@915Mhz
bool RFM69 : : sendWithRetry ( byte toAddress , const void * buffer , byte bufferSize , byte retries , byte retryWaitTime ) {
2014-11-17 19:58:00 +00:00
unsigned long sentTime ;
2015-01-06 14:25:29 +00:00
for ( byte i = 0 ; i < = retries ; i + + )
2013-06-20 22:06:39 +01:00
{
send ( toAddress , buffer , bufferSize , true ) ;
sentTime = millis ( ) ;
while ( millis ( ) - sentTime < retryWaitTime )
{
if ( ACKReceived ( toAddress ) )
{
//Serial.print(" ~ms:");Serial.print(millis()-sentTime);
return true ;
}
}
//Serial.print(" RETRY#");Serial.println(i+1);
}
return false ;
}
2015-01-06 14:25:29 +00:00
// should be polled immediately after sending a packet with ACK request
2013-06-20 22:06:39 +01:00
bool RFM69 : : ACKReceived ( byte fromNodeID ) {
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
2013-06-20 22:06:39 +01:00
void RFM69 : : sendACK ( const void * buffer , byte bufferSize ) {
2013-07-14 04:49:26 +01:00
byte sender = SENDERID ;
2015-01-06 14:25:29 +00:00
int _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
unsigned long now = millis ( ) ;
2014-11-14 20:25:45 +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
}
void RFM69 : : sendFrame ( byte toAddress , const void * buffer , byte bufferSize , bool requestACK , bool sendACK )
{
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
for ( byte i = 0 ; i < bufferSize ; i + + )
2013-06-20 22:06:39 +01:00
SPI . transfer ( ( ( byte * ) buffer ) [ i ] ) ;
2015-01-06 13:46:04 +00:00
unselect ( ) ;
2013-06-20 22:06:39 +01:00
2015-01-06 13:46:04 +00:00
/* no need to wait for transmit mode to be ready since its handled by the radio */
setMode ( RF69_MODE_TX ) ;
2014-11-17 19:58:00 +00:00
unsigned long txStart = millis ( ) ;
2015-01-06 14:25:29 +00: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 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 ( ) ;
SPI . transfer ( REG_FIFO & 0x7f ) ;
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 ) ;
2013-06-20 22:06:39 +01:00
byte 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-06 14:25:29 +00:00
for ( byte i = 0 ; i < DATALEN ; i + + )
2013-06-20 22:06:39 +01:00
{
DATA [ i ] = SPI . transfer ( 0 ) ;
}
2015-01-06 14:25:29 +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()
2013-06-20 22:06:39 +01:00
if ( _mode = = RF69_MODE_RX & & PAYLOADLEN > 0 )
{
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-06 14:25:29 +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-06 14:25:29 +00:00
for ( byte 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 ) ) ;
}
int RFM69 : : readRSSI ( bool forceTrigger ) {
int rssi = 0 ;
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 ;
}
byte RFM69 : : readReg ( byte addr )
{
select ( ) ;
SPI . transfer ( addr & 0x7F ) ;
byte regval = SPI . transfer ( 0 ) ;
unselect ( ) ;
return regval ;
}
void RFM69 : : writeReg ( byte addr , byte value )
{
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
// OFF = enable node+broadcast filtering to capture only frames sent to this/broadcast address
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 ) ;
}
void RFM69 : : setCS ( byte newSPISlaveSelect ) {
_slaveSelectPin = newSPISlaveSelect ;
pinMode ( _slaveSelectPin , OUTPUT ) ;
}
2015-01-06 14:25:29 +00:00
// for debugging
2013-06-20 22:06:39 +01:00
void RFM69 : : readAllRegs ( )
{
byte regVal ;
2015-01-06 13:46:04 +00:00
2013-06-20 22:06:39 +01:00
for ( byte regAddr = 1 ; regAddr < = 0x4F ; regAddr + + )
2015-01-06 13:46:04 +00:00
{
2013-06-20 22:06:39 +01:00
select ( ) ;
2015-01-06 14:25:29 +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-06 14:25:29 +00:00
byte RFM69 : : readTemperature ( byte 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-06 14:25:29 +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
}