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
// Foundation; either version 2 of the License, or
// (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
// PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General
// Public License along with this program; if not, write
// to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Licence can be viewed at
// http://www.fsf.org/licenses/gpl.txt
//
// 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 ] ;
2013-07-14 04:49:26 +01:00
volatile byte RFM69 : : _mode ; // current transceiver state
volatile byte RFM69 : : DATALEN ;
volatile byte RFM69 : : SENDERID ;
volatile byte RFM69 : : TARGETID ; //should match _address
volatile byte RFM69 : : PAYLOADLEN ;
volatile byte RFM69 : : ACK_REQUESTED ;
volatile byte RFM69 : : ACK_RECEIVED ; /// Should be polled immediately after sending a packet with ACK request
2013-11-07 04:15:51 +00:00
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 } ,
2013-09-06 00:32:11 +01:00
/* 0x02 */ { REG_DATAMODUL , RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00 } , //no shaping
2013-07-14 04:49:26 +01: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 } ,
2013-07-14 04:49:26 +01: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 ) ) ) } ,
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},
2013-07-14 04:49:26 +01:00
///* 0x13 */ { REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95 }, //over current protection (default is 95mA)
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)
2013-07-14 04:49:26 +01:00
/* 0x19 */ { REG_RXBW , RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2 } , //(BitRate < 2 * RxBw)
2014-08-13 03:03:19 +01:00
//for BR-19200: //* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 },
2013-07-14 04:49:26 +01:00
/* 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 } ,
/* 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 } ,
/* 0x38 */ { REG_PAYLOADLENGTH , 66 } , //in variable length mode: the max frame size, not used in TX
2013-07-14 04:49:26 +01:00
//* 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
2013-06-20 22:06:39 +01: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)
2014-08-13 03:03:19 +01:00
//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 ( ) ;
do writeReg ( REG_SYNCVALUE1 , 0xaa ) ; while ( readReg ( REG_SYNCVALUE1 ) ! = 0xaa ) ;
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 ) ;
2013-06-20 22:06:39 +01:00
setHighPower ( _isRFM69HW ) ; //called regardless if it's a RFM69W or RFM69HW
setMode ( RF69_MODE_STANDBY ) ;
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
}
void RFM69 : : setFrequency ( uint32_t FRF )
{
writeReg ( REG_FRFMSB , FRF > > 16 ) ;
writeReg ( REG_FRFMID , FRF > > 8 ) ;
writeReg ( REG_FRFLSB , FRF ) ;
}
void RFM69 : : setMode ( byte newMode )
{
if ( newMode = = _mode ) return ; //TODO: can remove this?
switch ( newMode ) {
case RF69_MODE_TX :
writeReg ( REG_OPMODE , ( readReg ( REG_OPMODE ) & 0xE3 ) | RF_OPMODE_TRANSMITTER ) ;
if ( _isRFM69HW ) setHighPowerRegs ( true ) ;
break ;
case RF69_MODE_RX :
writeReg ( REG_OPMODE , ( readReg ( REG_OPMODE ) & 0xE3 ) | RF_OPMODE_RECEIVER ) ;
if ( _isRFM69HW ) setHighPowerRegs ( false ) ;
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
2013-06-20 22:06:39 +01:00
while ( _mode = = RF69_MODE_SLEEP & & ( readReg ( REG_IRQFLAGS1 ) & RF_IRQFLAGS1_MODEREADY ) = = 0x00 ) ; // Wait for ModeReady
_mode = newMode ;
}
void RFM69 : : sleep ( ) {
setMode ( RF69_MODE_SLEEP ) ;
}
void RFM69 : : setAddress ( byte addr )
{
2013-07-14 04:49:26 +01:00
_address = addr ;
2013-06-20 22:06:39 +01:00
writeReg ( REG_NODEADRS , _address ) ;
}
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 ( )
{
if ( _mode = = RF69_MODE_RX & & PAYLOADLEN = = 0 & & readRSSI ( ) < CSMA_LIMIT ) //if signal stronger than -100dBm is detected assume channel activity
{
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-08-13 03:03:19 +01:00
long now = millis ( ) ;
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
// The reason for the semi-automaton is that the lib is ingterrupt driven and
// 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 ) {
2013-06-20 22:06:39 +01:00
long sentTime ;
2013-07-14 04:49:26 +01: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 ;
}
/// Should be polled immediately after sending a packet with ACK request
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 ;
}
2014-08-13 03:03:19 +01:00
//check whether an ACK was requested in the last received packet (non-broadcasted packet)
bool RFM69 : : ACKRequested ( ) {
return ACK_REQUESTED & & ( TARGETID ! = RF69_BROADCAST_ADDR ) ;
}
2013-06-20 22:06:39 +01:00
/// Should be called immediately after reception in case sender wants ACK
void RFM69 : : sendACK ( const void * buffer , byte bufferSize ) {
2013-07-14 04:49:26 +01:00
byte sender = SENDERID ;
2013-06-20 22:06:39 +01:00
while ( ! canSend ( ) ) receiveDone ( ) ;
2013-07-14 04:49:26 +01:00
sendFrame ( sender , buffer , bufferSize , false , true ) ;
2013-06-20 22:06:39 +01:00
}
void RFM69 : : sendFrame ( byte toAddress , const void * buffer , byte bufferSize , bool requestACK , bool sendACK )
{
2013-07-14 04:49:26 +01:00
setMode ( RF69_MODE_STANDBY ) ; //turn off receiver to prevent reception while filling fifo
2013-06-20 22:06:39 +01:00
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
//write to FIFO
select ( ) ;
SPI . transfer ( REG_FIFO | 0x80 ) ;
SPI . transfer ( bufferSize + 3 ) ;
SPI . transfer ( toAddress ) ;
SPI . transfer ( _address ) ;
//control byte
if ( sendACK )
SPI . transfer ( 0x80 ) ;
else if ( requestACK )
SPI . transfer ( 0x40 ) ;
else SPI . transfer ( 0x00 ) ;
for ( byte i = 0 ; i < bufferSize ; i + + )
SPI . transfer ( ( ( byte * ) buffer ) [ i ] ) ;
unselect ( ) ;
/* no need to wait for transmit mode to be ready since its handled by the radio */
setMode ( RF69_MODE_TX ) ;
while ( digitalRead ( _interruptPin ) = = 0 ) ; //wait for DIO0 to turn HIGH signalling transmission finish
2013-07-14 04:49:26 +01: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 ( ) ;
SPI . transfer ( REG_FIFO & 0x7f ) ;
PAYLOADLEN = SPI . transfer ( 0 ) ;
PAYLOADLEN = PAYLOADLEN > 66 ? 66 : PAYLOADLEN ; //precaution
TARGETID = SPI . transfer ( 0 ) ;
2014-02-02 02:13:40 +00:00
if ( ! ( _promiscuousMode | | TARGETID = = _address | | TARGETID = = RF69_BROADCAST_ADDR ) ) //match this node's address, or broadcast address or anything in promiscuous mode
2013-06-20 22:06:39 +01:00
{
PAYLOADLEN = 0 ;
unselect ( ) ;
2013-07-14 04:49:26 +01:00
//digitalWrite(4, 0);
2013-06-20 22:06:39 +01:00
return ;
}
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 ) ;
ACK_RECEIVED = CTLbyte & 0x80 ; //extract ACK-requested flag
ACK_REQUESTED = CTLbyte & 0x40 ; //extract ACK-received flag
2013-07-14 04:49:26 +01:00
2013-06-20 22:06:39 +01:00
for ( byte i = 0 ; i < DATALEN ; i + + )
{
DATA [ i ] = SPI . transfer ( 0 ) ;
}
2014-08-13 03:03:19 +01: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
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 ( ) {
2013-07-14 04:49:26 +01:00
// ATOMIC_BLOCK(ATOMIC_FORCEON)
// {
2014-02-02 02:13:40 +00:00
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 )
{
2014-02-02 02:13:40 +00:00
setMode ( RF69_MODE_STANDBY ) ; //enables interrupts
2013-06-20 22:06:39 +01:00
return true ;
}
2014-02-02 02:13:40 +00:00
else if ( _mode = = RF69_MODE_RX ) //already in RX no payload yet
{
interrupts ( ) ; //explicitly re-enable interrupts
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 ) ;
if ( key ! = 0 )
{
select ( ) ;
SPI . transfer ( REG_AESKEY1 | 0x80 ) ;
for ( byte i = 0 ; i < 16 ; i + + )
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 )
{
//RSSI trigger not needed if DAGC is in continuous mode
writeReg ( REG_RSSICONFIG , RF_RSSI_START ) ;
while ( ( readReg ( REG_RSSICONFIG ) & RF_RSSI_DONE ) = = 0x00 ) ; // Wait for RSSI_Ready
}
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 ( ) ;
}
/// Select the transceiver
void RFM69 : : select ( ) {
noInterrupts ( ) ;
2014-08-13 03:03:19 +01:00
//save current SPI settings
_SPCR = SPCR ;
_SPSR = SPSR ;
//set RFM69 SPI settings
SPI . setDataMode ( SPI_MODE0 ) ;
SPI . setBitOrder ( MSBFIRST ) ;
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 ) ;
}
/// UNselect the transceiver chip
void RFM69 : : unselect ( ) {
digitalWrite ( _slaveSelectPin , HIGH ) ;
2014-08-13 03:03:19 +01:00
//restore SPI settings to what they were before talking to RFM69
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 ) {
_promiscuousMode = onOff ;
//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 ) ;
if ( _isRFM69HW ) //turning ON
writeReg ( REG_PALEVEL , ( readReg ( REG_PALEVEL ) & 0x1F ) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON ) ; //enable P1 & P2 amplifier stages
else
writeReg ( REG_PALEVEL , RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | _powerLevel ) ; //enable P0 only
}
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 ) ;
}
//for debugging
2014-11-11 05:02:52 +00:00
2014-11-12 04:05:36 +00:00
# define REGISTER_DETAIL 1
# 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 ( )
{
byte 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
byte modeFSK = 0 ;
int bitRate = 0 ;
int freqDev = 0 ;
long freqCenter = 0 ;
# endif
SerialPrint ( " Address - HEX - BIN \n " ) ;
2013-06-20 22:06:39 +01:00
for ( byte regAddr = 1 ; regAddr < = 0x4F ; regAddr + + )
{
select ( ) ;
SPI . transfer ( regAddr & 0x7f ) ; // send address + r/w bit
regVal = SPI . transfer ( 0 ) ;
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
2014-11-11 05:02:52 +00: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 : " ) ;
unsigned long val = 61UL * freqDev ;
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 : " ) ;
unsigned long val = 61UL * freqCenter ;
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
2013-06-20 22:06:39 +01:00
}
unselect ( ) ;
}
2013-09-06 00:32:11 +01:00
byte RFM69 : : readTemperature ( byte calFactor ) //returns centigrade
{
setMode ( RF69_MODE_STANDBY ) ;
writeReg ( REG_TEMP1 , RF_TEMP1_MEAS_START ) ;
while ( ( readReg ( REG_TEMP1 ) & RF_TEMP1_MEAS_RUNNING ) ) Serial . print ( ' * ' ) ;
return ~ readReg ( REG_TEMP2 ) + COURSE_TEMP_COEF + calFactor ; //'complement'corrects the slope, rising temp = rising val
} // COURSE_TEMP_COEF puts reading in the ballpark, user can add additional correction
void RFM69 : : rcCalibration ( )
{
writeReg ( REG_OSC1 , RF_OSC1_RCCAL_START ) ;
while ( ( readReg ( REG_OSC1 ) & RF_OSC1_RCCAL_DONE ) = = 0x00 ) ;
2014-02-02 02:13:40 +00:00
}