* Derive default interrupt from configured instead of default pin Derive DEFAULT_RFM69_IRQ_NUM from MY_RFM69_IRQ_PIN instead of DEFAULT_RFM69_IRQ_PIN so that _NUM does not have to be defined if _PIN is redefined * Change default IRQ pin for RFM69/95 on ESP8266 to GPIO5=D1 The originally defined pin GPIO2 prevent ESP8266 from booting, since it has to be pulled high for booting and DIO0 from the RFM69 is defaul low. For this reason, it is improbably that anyone is using the default and would be affected by this change.
229 lines
9.9 KiB
C++
229 lines
9.9 KiB
C++
// **********************************************************************************
|
|
// Driver definition for HopeRF RFM69W/RFM69HW/RFM69CW/RFM69HCW, Semtech SX1231/1231H
|
|
// **********************************************************************************
|
|
// 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
//
|
|
// Licence can be viewed at
|
|
// http://www.gnu.org/licenses/gpl-3.0.txt
|
|
//
|
|
// Please maintain this license information along with authorship
|
|
// and copyright notices in any redistribution of this code
|
|
// **********************************************************************************
|
|
#ifndef RFM69_h
|
|
#define RFM69_h
|
|
#include <Arduino.h> // assumes Arduino IDE v1.0 or greater
|
|
#include <SPI.h>
|
|
|
|
#define RFM69_MAX_DATA_LEN 61 // to take advantage of the built in AES/CRC we want to limit the frame size to the internal FIFO size (66 bytes - 3 bytes overhead - 2 bytes crc)
|
|
|
|
#if defined(ARDUINO_ARCH_AVR)
|
|
#if defined(__AVR_ATmega32U4__)
|
|
#define DEFAULT_RFM69_IRQ_PIN (3) //!< DEFAULT_RFM69_IRQ_PIN
|
|
#else
|
|
#define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN
|
|
#endif
|
|
#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
|
|
#elif defined(ARDUINO_ARCH_ESP8266)
|
|
#define DEFAULT_RFM69_IRQ_PIN (5) //!< DEFAULT_RFM69_IRQ_PIN
|
|
#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
|
|
#elif defined(ARDUINO_ARCH_ESP32)
|
|
#warning not implemented yet
|
|
#elif defined(ARDUINO_ARCH_SAMD)
|
|
#define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN
|
|
#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
|
|
#elif defined(LINUX_ARCH_RASPBERRYPI)
|
|
#define DEFAULT_RFM69_IRQ_PIN (22) //!< DEFAULT_RFM69_IRQ_PIN
|
|
#define DEFAULT_RFM69_IRQ_NUM DEFAULT_RFM69_IRQ_PIN //!< DEFAULT_RFM69_IRQ_NUM
|
|
#elif defined(ARDUINO_ARCH_STM32F1)
|
|
#define DEFAULT_RFM69_IRQ_PIN (PA3) //!< DEFAULT_RFM69_IRQ_PIN
|
|
#define DEFAULT_RFM69_IRQ_NUM DEFAULT_RFM69_IRQ_PIN //!< DEFAULT_RFM69_IRQ_NUM
|
|
#elif defined(TEENSYDUINO)
|
|
#define DEFAULT_RFM69_IRQ_PIN (8) //!< DEFAULT_RFM69_IRQ_PIN
|
|
#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM
|
|
#else
|
|
#define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN
|
|
#define DEFAULT_RFM69_IRQ_NUM (2) //!< DEFAULT_RFM69_IRQ_NUM
|
|
#endif
|
|
|
|
#define DEFAULT_RFM69_CS_PIN (SS) //!< DEFAULT_RFM69_CS_PIN
|
|
|
|
// SPI clock divier for non-transaction implementations
|
|
#if (MY_RFM69_SPI_SPEED >= F_CPU / 2)
|
|
#define RFM69_CLOCK_DIV SPI_CLOCK_DIV2 //!< SPI clock divider 2
|
|
#elif (MY_RFM69_SPI_SPEED >= F_CPU / 4)
|
|
#define RFM69_CLOCK_DIV SPI_CLOCK_DIV4 //!< SPI clock divider 4
|
|
#elif (MY_RFM69_SPI_SPEED >= F_CPU / 8)
|
|
#define RFM69_CLOCK_DIV SPI_CLOCK_DIV8 //!< SPI clock divider 8
|
|
#elif (MY_RFM69_SPI_SPEED >= F_CPU / 16)
|
|
#define RFM69_CLOCK_DIV SPI_CLOCK_DIV16 //!< SPI clock divider 16
|
|
#elif (MY_RFM69_SPI_SPEED >= F_CPU / 32)
|
|
#define RFM69_CLOCK_DIV SPI_CLOCK_DIV32 //!< SPI clock divider 32
|
|
#elif (MY_RFM69_SPI_SPEED >= F_CPU / 64)
|
|
#define RFM69_CLOCK_DIV SPI_CLOCK_DIV64 //!< SPI clock divider 64
|
|
#elif (MY_RFM69_SPI_SPEED >= F_CPU / 128)
|
|
#define RFM69_CLOCK_DIV SPI_CLOCK_DIV128 //!< SPI clock divider 128
|
|
#else
|
|
#define RFM69_CLOCK_DIV SPI_CLOCK_DIV256 //!< SPI clock divider 256
|
|
#endif
|
|
|
|
// powerup delay
|
|
#define RFM69_POWERUP_DELAY_MS (100u) //!< Power up delay, allow VCC to settle, transport to become fully operational
|
|
|
|
#define CSMA_LIMIT -90 // upper RX signal sensitivity threshold in dBm for carrier sense access
|
|
#define RFM69_MODE_SLEEP 0 // XTAL OFF
|
|
#define RFM69_MODE_STANDBY 1 // XTAL ON
|
|
#define RFM69_MODE_SYNTH 2 // PLL ON
|
|
#define RFM69_MODE_RX 3 // RX MODE
|
|
#define RFM69_MODE_TX 4 // TX MODE
|
|
|
|
// available frequency bands
|
|
#define RFM69_315MHZ 31 // non trivial values to avoid misconfiguration
|
|
#define RFM69_433MHZ 43
|
|
#define RFM69_868MHZ 86
|
|
#define RFM69_915MHZ 91
|
|
|
|
#define null 0
|
|
#define COURSE_TEMP_COEF -90 // puts the temperature reading in the ballpark, user can fine tune the returned value
|
|
#define RFM69_BROADCAST_ADDR 255
|
|
#define RFM69_CSMA_LIMIT_MS 1000
|
|
#define RFM69_TX_LIMIT_MS 1000
|
|
|
|
#define RFM69_FXOSC (32*1000000ul) //!< The crystal oscillator frequency of the module, 32MHz
|
|
#define RFM69_FSTEP (RFM69_FXOSC / 524288ul) //!< The Frequency Synthesizer step
|
|
|
|
// TWS: define CTLbyte bits
|
|
#define RFM69_CTL_SENDACK 0x80
|
|
#define RFM69_CTL_REQACK 0x40
|
|
|
|
/** RFM69 class */
|
|
class RFM69
|
|
{
|
|
public:
|
|
static volatile uint8_t DATA[RFM69_MAX_DATA_LEN]; //!< recv/xmit buf, including hdr & crc bytes
|
|
static volatile uint8_t DATALEN; //!< DATALEN
|
|
static volatile uint8_t SENDERID; //!< SENDERID
|
|
static volatile uint8_t TARGETID; //!< should match _address
|
|
static volatile uint8_t PAYLOADLEN; //!< PAYLOADLEN
|
|
static volatile uint8_t ACK_REQUESTED; //!< ACK_REQUESTED
|
|
static volatile uint8_t
|
|
ACK_RECEIVED; //!< Should be polled immediately after sending a packet with ACK requestwith ACK request
|
|
static volatile int16_t RSSI; //!< most accurate RSSI during reception (closest to the reception)
|
|
static volatile uint8_t _mode; //!< should be protected?
|
|
|
|
/**
|
|
* @brief Constructor
|
|
*
|
|
* @param slaveSelectPin ChipSelect pin.
|
|
* @param interruptPin Interrupt pin.
|
|
* @param isRFM69HW Set to @c true to indicate RFM69HW variant.
|
|
* @param interruptNum Interrupt number.
|
|
*/
|
|
RFM69(uint8_t slaveSelectPin=MY_RFM69_CS_PIN, uint8_t interruptPin=MY_RFM69_IRQ_PIN,
|
|
bool isRFM69HW=false,
|
|
uint8_t interruptNum=digitalPinToInterrupt(MY_RFM69_IRQ_PIN))
|
|
{
|
|
_slaveSelectPin = slaveSelectPin;
|
|
_interruptPin = interruptPin;
|
|
_interruptNum = interruptNum;
|
|
_mode = RFM69_MODE_STANDBY;
|
|
_promiscuousMode = false;
|
|
_powerLevel = 31;
|
|
_isRFM69HW = isRFM69HW;
|
|
_address = RFM69_BROADCAST_ADDR;
|
|
#if !defined(SPI_HAS_TRANSACTION)
|
|
#if defined (SPCR) && defined (SPSR)
|
|
_SPCR = 0;
|
|
_SPSR = 0;
|
|
#endif
|
|
#if defined (SREG)
|
|
_SREG = 0;
|
|
#endif
|
|
#endif // SPI_HAS_TRANSACTION
|
|
}
|
|
|
|
bool initialize(uint8_t freqBand, uint8_t ID, uint8_t networkID=1); //!< initialize
|
|
void setAddress(uint8_t addr); //!< setAddress
|
|
void setNetwork(uint8_t networkID); //!< setNetwork
|
|
bool canSend(); //!< canSend
|
|
virtual void send(uint8_t toAddress, const void* buffer, uint8_t bufferSize,
|
|
bool requestACK=false); //!< send
|
|
virtual bool sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize,
|
|
uint8_t retries=5, uint8_t retryWaitTime=
|
|
200); //!< sendWithRetry (40ms roundtrip req for 61byte packets, adjusted)
|
|
virtual bool receiveDone(); //!< receiveDone
|
|
bool ACKReceived(uint8_t fromNodeID); //!< ACKReceived
|
|
bool ACKRequested(); //!< ACKRequested
|
|
virtual void sendACK(const void* buffer = "", uint8_t bufferSize=0); //!< sendACK
|
|
uint32_t getFrequency(); //!< getFrequency
|
|
void setFrequency(uint32_t freqHz); //!< setFrequency
|
|
void encrypt(const char* key); //!< encrypt
|
|
void setCS(uint8_t newSPISlaveSelect); //!< setCS
|
|
int16_t readRSSI(bool forceTrigger=false); //!< readRSSI
|
|
void promiscuous(bool onOff=true); //!< promiscuous
|
|
virtual void setHighPower(bool onOFF=
|
|
true); //!< setHighPower (have to call it after initialize for RFM69HW)
|
|
virtual void setPowerLevel(uint8_t level); //!< setPowerLevel (reduce/increase transmit power level)
|
|
void sleep(void); //!< sleep
|
|
void standBy(void); //!< standBy
|
|
void powerDown(void); //!< powerDown
|
|
void powerUp(void); //!< powerUp
|
|
void reset(void); //!< reset
|
|
bool sanityCheck(void); //!< sanityCheck
|
|
uint8_t readTemperature(uint8_t calFactor=0); //!< readTemperature (get CMOS temperature (8bit))
|
|
void rcCalibration(); //!< rcCalibration (calibrate the internal RC oscillator for use in wide temperature variations - see datasheet section [4.3.5. RC Timer Accuracy])
|
|
|
|
// allow hacking registers by making these public
|
|
uint8_t readReg(uint8_t addr); //!< readReg
|
|
void writeReg(uint8_t addr, uint8_t val); //!< writeReg
|
|
void readAllRegs(); //!< readAllRegs
|
|
protected:
|
|
static void isr0(); //!< isr0
|
|
void virtual interruptHandler(); //!< interruptHandler
|
|
virtual void interruptHook(uint8_t CTLbyte); //!< interruptHook
|
|
virtual void sendFrame(uint8_t toAddress, const void* buffer, uint8_t size, bool requestACK=false,
|
|
bool sendACK=false); //!< sendFrame
|
|
|
|
static RFM69* selfPointer; //!< selfPointer
|
|
uint8_t _slaveSelectPin; //!< _slaveSelectPin
|
|
uint8_t _interruptPin; //!< _interruptPin
|
|
uint8_t _interruptNum; //!< _interruptNum
|
|
uint8_t _address; //!< _address
|
|
bool _promiscuousMode; //!< _promiscuousMode
|
|
uint8_t _powerLevel; //!< _powerLevel
|
|
bool _isRFM69HW; //!< _isRFM69HW
|
|
#if defined (SPCR) && defined (SPSR)
|
|
uint8_t _SPCR; //!< _SPCR
|
|
uint8_t _SPSR; //!< _SPSR
|
|
#endif
|
|
#if defined (SREG)
|
|
uint8_t _SREG; //!< _SREG
|
|
#endif
|
|
|
|
virtual void receiveBegin(); //!< receiveBegin
|
|
virtual void setMode(uint8_t mode); //!< setMode
|
|
virtual void setHighPowerRegs(bool onOff); //!< setHighPowerRegs
|
|
virtual void select(); //!< select
|
|
virtual void unselect(); //!< unselect
|
|
};
|
|
|
|
#endif
|