Initial commit

This commit is contained in:
Felix Rusu 2013-06-20 17:06:39 -04:00
parent d287b1967b
commit 61208552ba
7 changed files with 1828 additions and 2 deletions

View File

@ -0,0 +1,99 @@
#include <RFM69.h>
#include <SPI.h>
#define NODEID 1
#define NETWORKID 100
#define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF12_433MHZ, RF12_915MHZ)
#define KEY "thisIsEncryptKey"
#define LED 9
#define SERIAL_BAUD 115200
#define ACK_TIME 10 // # of ms to wait for an ack
RFM69 radio;
bool promiscuousMode = false; //set to 'true' to sniff all packets on the same network
void setup() {
Serial.begin(SERIAL_BAUD);
radio.initialize(RF69_915MHZ,NODEID,NETWORKID);
radio.encrypt(KEY);
radio.promiscuous(promiscuousMode);
char buff[50];
sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
Serial.println(buff);
}
byte ackCount=0;
void loop() {
//process any serial input
if (Serial.available() > 0)
{
char input = Serial.read();
if (input == 'd') //d=dump all register values
radio.readAllRegs();
if (input == 'E') //E=enable encryption
radio.encrypt(KEY);
if (input == 'e') //e=disable encryption
radio.encrypt(null);
if (input == 'p')
{
promiscuousMode = !promiscuousMode;
radio.promiscuous(promiscuousMode);
Serial.print("Promiscuous mode ");Serial.println(promiscuousMode ? "on" : "off");
}
}
if (radio.receiveDone())
{
Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] ");
if (promiscuousMode)
{
Serial.print("to [");Serial.print(radio.TARGETID, DEC);Serial.print("] ");
}
for (byte i = 0; i < radio.DATALEN; i++)
Serial.print((char)radio.DATA[i]);
Serial.print(" [RX_RSSI:");Serial.print(radio.readRSSI());Serial.print("]");
if (radio.ACK_REQUESTED)
{
byte theNodeID = radio.SENDERID;
radio.sendACK();
Serial.print(" - ACK sent.");
// When a node requests an ACK, respond to the ACK
// and also send a packet requesting an ACK (every 3rd one only)
// This way both TX/RX NODE functions are tested on 1 end at the GATEWAY
/*
if (ackCount++%3)
{
Serial.print(" Sending packet to node ");
Serial.print(theNodeID);
delay(5);
radio.send(theNodeID, "ACK TEST", 8, true);
Serial.print(" - waiting for ACK...");
if (waitForAck(theNodeID)) Serial.print("ok!");
else Serial.print("nothing...");
}
*/
}
Serial.println();
Blink(LED,3);
}
}
// wait a few milliseconds for proper ACK to me, return true if indeed received
static bool waitForAck(byte theNodeID) {
long now = millis();
while (millis() - now <= ACK_TIME) {
if (radio.ACKReceived(theNodeID))
return true;
}
return false;
}
void Blink(byte PIN, int DELAY_MS)
{
pinMode(PIN, OUTPUT);
digitalWrite(PIN,HIGH);
delay(DELAY_MS);
digitalWrite(PIN,LOW);
}

116
Examples/Node/Node.ino Normal file
View File

@ -0,0 +1,116 @@
#include <RFM69.h>
#include <SPI.h>
#define NODEID 25
#define NETWORKID 100
#define GATEWAYID 1
#define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF12_433MHZ, RF12_915MHZ)
#define KEY "thisIsEncryptKey"
#define LED 9
#define SERIAL_BAUD 115200
#define ACK_TIME 10 // # of ms to wait for an ack
int TRANSMITPERIOD = 500; //transmit a packet to gateway so often (in ms)
char payload[] = "123 ABCDEFGHIJKLMNOPQRSTUVWXYZ";
byte sendSize=0;
boolean requestACK = false;
RFM69 radio;
void setup() {
Serial.begin(SERIAL_BAUD);
radio.initialize(FREQUENCY,NODEID,NETWORKID);
//radio.setHighPower(); //only for RFM69HW!
radio.encrypt(KEY);
char buff[50];
sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
Serial.println(buff);
}
long lastPeriod = -1;
void loop() {
//process any serial input
if (Serial.available() > 0)
{
char input = Serial.read();
if (input >= 48 && input <= 57) //[0,9]
{
TRANSMITPERIOD = 100 * (input-48);
if (TRANSMITPERIOD == 0) TRANSMITPERIOD = 1000;
Serial.print("\nChanging delay to ");
Serial.print(TRANSMITPERIOD);
Serial.println("ms\n");
}
if (input == 'd') //d=dump register values
radio.readAllRegs();
if (input == 'E') //E=enable encryption
radio.encrypt(KEY);
if (input == 'e') //e=disable encryption
radio.encrypt(null);
}
//check for any received packets
if (radio.receiveDone())
{
Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] ");
for (byte i = 0; i < radio.DATALEN; i++)
Serial.print((char)radio.DATA[i]);
Serial.print(" [RX_RSSI:");Serial.print(radio.readRSSI());Serial.print("]");
if (radio.ACK_REQUESTED)
{
radio.sendACK();
Serial.print(" - ACK sent.");
}
Blink(LED,5);
Serial.println();
}
int currPeriod = millis()/TRANSMITPERIOD;
if (currPeriod != lastPeriod)
{
lastPeriod=currPeriod;
Serial.print("Sending[");
Serial.print(sendSize);
Serial.print("]: ");
for(byte i = 0; i < sendSize; i++)
Serial.print((char)payload[i]);
if (radio.sendWithRetry(GATEWAYID, payload, sendSize))
Serial.print(" ok!");
else Serial.print(" nothing...");
// //manual ACK handling
// requestACK = ((sendSize % 3) == 0); //request ACK every 3rd xmission
// radio.send(GATEWAYID, payload, sendSize, requestACK);
// if (requestACK)
// {
// Serial.print(" - waiting for ACK...");
// if (waitForAck(GATEWAYID)) Serial.print("ok!");
// else Serial.print("nothing...");
// }
sendSize = (sendSize + 1) % 31;
Serial.println();
Blink(LED,3);
}
}
void Blink(byte PIN, int DELAY_MS)
{
pinMode(PIN, OUTPUT);
digitalWrite(PIN,HIGH);
delay(DELAY_MS);
digitalWrite(PIN,LOW);
}
//// wait a few milliseconds for proper ACK to me, return true if indeed received
//static bool waitForAck(byte theNodeID) {
// long now = millis();
// while (millis() - now <= ACK_TIME) {
// if (radio.ACKReceived(theNodeID))
// return true;
// }
// return false;
//}

View File

@ -1,4 +1,42 @@
RFM69
=====
RFM69 Library
----------------
By Felix Rusu (felix@lowpowerlab.com)
<br/>
Creative Commons Attrib Share-Alike License
http://creativecommons.org/licenses/by-sa/3.0/
RFM69 library for RFM69W and RFM69HW (semtech SX1231, SX1231H)
##Features
Among others, this is a set of features implemented in this library:
- easy to use API with a few simple functions for basic usage
- 255 possible nodes on 256 possible networks
- 61 bytes max message length (limited to 61 to support AES hardware encryption)
- customizable transmit power (32 levels) for low-power transmission control
- sleep function for power saving
- automatic ACKs with the sendWithRetry() function
- hardware 128bit AES encryption
- hardware preamble, synch recognition and CRC check
- digital RSSI can be read at any time with readRSSI()
- interrupt driven
- tested on [Moteino R3s (ATMega328p)](http://lowpowerlab.com/shop/Moteino-R3)
- works with RFM69W and RFM69HW, Semtech SX1231/SX1231H transceivers
- promiscuous mode allows any node to listen to any packet on same network
I consider this an initial beta release, it could contain bugs, but the provided Gateway and Node examples should work out of the box. Please let me know if you find issues.
###Installation
Copy the content of this library in the "Arduino/libraries/RFM12B" folder.
<br />
To find your Arduino folder go to File>Preferences in the Arduino IDE.
<br/>
See [this tutorial](http://learn.adafruit.com/arduino-tips-tricks-and-techniques/arduino-libraries) on Arduino libraries.
###Saple usage
- [Node](https://github.com/LowPowerLab/RFM69/blob/master/Examples/Node/Node.ino)
- [Gateway](https://github.com/LowPowerLab/RFM69/blob/master/Examples/Gateway/Gateway.ino)
##Blog writeup
http://lowpowerlab.com/blog/2013/06/20/rfm69-library/

391
RFM69.cpp Normal file
View File

@ -0,0 +1,391 @@
// Driver definition for HopeRF RFM69W/RFM69HW, Semtech SX1231/1231H
// Creative Commons Attrib Share-Alike License
// If you want to use/extend this library please abide with the license terms: http://creativecommons.org/licenses/by-sa/3.0/
// 2013-06-14 (C) felix@lowpowerlab.com
#include <RFM69.h>
#include <RFM69registers.h>
#include <SPI.h>
RFM69* RFM69::selfPointer;
bool RFM69::initialize(byte freqBand, byte nodeID, byte networkID)
{
const byte CONFIG[][2] =
{
/* 0x01 */ { REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY},
/* 0x02 */ { REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00}, //gaussian, bt=1.0
/* 0x03 */ { REG_BITRATEMSB, RF_BITRATEMSB_50000}, //default is 4.8 KBPS
/* 0x04 */ { REG_BITRATELSB, RF_BITRATELSB_50000},
/* 0x05 */ { REG_FDEVMSB, RF_FDEVMSB_50000}, //default is 5khz
/* 0x06 */ { REG_FDEVLSB, RF_FDEVLSB_50000},
/* 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)))},
// 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},
/* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_2},
/* 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
///* 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
/* 0x30 */ { REG_SYNCVALUE2, networkID}, //NETWORK ID
/* 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
//* 0x39 */ { REG_NODEADRS, nodeID}, //turned off because we're not using address filtering
/* 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)
/* 0x6F */ { REG_TESTDAGC, RF_DAGC_CONTINUOUS }, // run DAGC continuously in RX mode
{255, 0}
};
pinMode(_slaveSelectPin, OUTPUT);
unselect();
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV2); //max speed, except on Due which can run at system clock speed
SPI.begin();
do writeReg(REG_SYNCVALUE1, 0xaa); while (readReg(REG_SYNCVALUE1) != 0xaa);
do writeReg(REG_SYNCVALUE1, 0x55); while (readReg(REG_SYNCVALUE1) != 0x55);
for (byte i = 0; CONFIG[i][0] != 255; i++)
writeReg(CONFIG[i][0], CONFIG[i][1]);
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
attachInterrupt(0, RFM69::isr0, RISING);
selfPointer = this;
_address = nodeID;
}
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
// but waiting for mode ready is necessary when going from to sleep because the FIFO may not be immediately available from previous mode
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)
{
_address = addr; //& 0x7F; //make sure MSB is reserved for ACK flagging
writeReg(REG_NODEADRS, _address);
}
// power: 0=min, 31=max
void RFM69::setPowerLevel(byte powerLevel)
{
_powerLevel = powerLevel;
writeReg(REG_PALEVEL, readReg(REG_PALEVEL) & (_powerLevel > 31 ? 31 : _powerLevel));
}
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)
{
while (!canSend()) receiveDone();
sendFrame(toAddress, buffer, bufferSize, requestACK, false);
}
//to dramatically increase the chance of getting a packet across, call this function instead of send
// 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
// rountrips usually take only 5-8ms at 50kbps
bool RFM69::sendWithRetry(byte toAddress, const void* buffer, byte bufferSize, byte attempts, byte retryWaitTime) {
long sentTime;
byte howLong=0;
for (byte i=0; i<attempts; i++)
{
send(toAddress, buffer, bufferSize, true);
sentTime = millis();
while (millis()-sentTime<retryWaitTime)
{
if (ACKReceived(toAddress))
{
////roundtrip millis
//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())
return (SENDERID == fromNodeID || fromNodeID == 0) && ACK_RECEIVED;
return false;
}
/// Should be called immediately after reception in case sender wants ACK
void RFM69::sendACK(const void* buffer, byte bufferSize) {
while (!canSend()) receiveDone();
sendFrame(SENDERID, buffer, bufferSize, false, true);
}
void RFM69::sendFrame(byte toAddress, const void* buffer, byte bufferSize, bool requestACK, bool sendACK)
{
setMode(RF69_MODE_STANDBY); //turn off receiver to prevent reception while filling fifo
while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // Wait for ModeReady
writeReg(REG_DIOMAPPING1, (readReg(REG_DIOMAPPING1) & 0x3F) | RF_DIOMAPPING1_DIO0_00); // DIO0 is "Packet Sent"
writeReg(REG_FIFOTHRESH, (readReg(REG_FIFOTHRESH) & 0x7F) | RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY);
if (bufferSize > MAX_DATA_LEN) bufferSize = MAX_DATA_LEN;
//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);
// wait for IRQ when finished transmitting
while (digitalRead(_interruptPin) == 0); //wait for DIO0 to turn HIGH signalling transmission finish
setMode(RF69_MODE_STANDBY);
}
void RFM69::interruptHandler() {
//Serial.print("MODE:");Serial.print(readReg(REG_OPMODE), BIN);
//Serial.print("\n IRQ1:");Serial.print(readReg(REG_IRQFLAGS1), BIN);
//Serial.print(" IRQ2:");Serial.print(readReg(REG_IRQFLAGS2), BIN);
if (_mode == RF69_MODE_RX && (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY))
{
//Serial.print("\nRDY");
setMode(RF69_MODE_STANDBY);
select();
SPI.transfer(REG_FIFO & 0x7f);
PAYLOADLEN = SPI.transfer(0);
PAYLOADLEN = PAYLOADLEN > 66 ? 66 : PAYLOADLEN; //precaution
TARGETID = SPI.transfer(0);
if(!(_promiscuousMode || TARGETID==_address || TARGETID==0)) //match this node's address, or broadcast addr 0x0 or anything in promiscuous mode
{
PAYLOADLEN = 0;
unselect();
return;
}
SENDERID = SPI.transfer(0);
byte CTLbyte = SPI.transfer(0);
ACK_RECEIVED = CTLbyte & 0x80; //extract ACK-requested flag
ACK_REQUESTED = CTLbyte & 0x40; //extract ACK-received flag
//Serial.print(" *** ");
DATALEN = PAYLOADLEN - 3;
for (byte i= 0; i < DATALEN; i++)
{
DATA[i] = SPI.transfer(0);
//Serial.print((char)DATA[i]);
}
//Serial.println(" ***");
//Serial.println(DATALEN);
unselect();
setMode(RF69_MODE_RX);
}
//else Serial.println("UNK");
}
void RFM69::isr0() { selfPointer->interruptHandler(); }
void RFM69::receiveBegin() {
DATALEN = SENDERID = TARGETID = PAYLOADLEN = ACK_REQUESTED = ACK_RECEIVED = 0;
writeReg(REG_DIOMAPPING1, (readReg(REG_DIOMAPPING1) & 0x3F) | RF_DIOMAPPING1_DIO0_01); //set DIO0 to "PAYLOADREADY" in receive mode
setMode(RF69_MODE_RX);
}
bool RFM69::receiveDone() {
noInterrupts(); //will be re-enabled in the setMode() method
if (_mode == RF69_MODE_RX && PAYLOADLEN>0)
{
setMode(RF69_MODE_STANDBY);
return true;
}
receiveBegin();
return false;
}
// To enable encryption: radio.encrypt("ABCDEFGHIJKLMNOP");
// To disable encryption: radio.encrypt(null) or radio.encrypt(0)
// KEY HAS TO BE 16 bytes !!!
void RFM69::encrypt(const char* key) {
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);
byte oldregval = SPI.transfer(value);
unselect();
}
/// Select the transceiver
void RFM69::select() {
noInterrupts();
digitalWrite(_slaveSelectPin, LOW);
}
/// UNselect the transceiver chip
void RFM69::unselect() {
digitalWrite(_slaveSelectPin, HIGH);
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
void RFM69::readAllRegs()
{
byte regVal;
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);
}
unselect();
}
//// doesnt seem to work as expected
// byte RFM69::readTemp(bool calibrate) {
// if (calibrate)
// {
// writeReg(REG_OSC1, RF_OSC1_RCCAL_START);
// while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00);
// }
// writeReg(REG_TEMP1, RF_TEMP1_MEAS_START);
// while ((readReg(REG_TEMP1) & RF_TEMP1_MEAS_RUNNING));
// return readReg(REG_TEMP2);
// }

92
RFM69.h Normal file
View File

@ -0,0 +1,92 @@
// Driver definition for HopeRF RFM69W/RFM69HW, Semtech SX1231/1231H
// Creative Commons Attrib Share-Alike License
// If you want to use/extend this library please abide with the license terms: http://creativecommons.org/licenses/by-sa/3.0/
// 2013-06-14 (C) felix@lowpowerlab.com
#ifndef RFM69_h
#define RFM69_h
#include <Arduino.h> //assumes Arduino IDE v1.0 or greater
#define 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)
#define SPI_CS SS // SS is the SPI slave select pin, for instance D10 on atmega328
#define RF69_IRQ_PIN 2 // INT0 on AVRs should be connected to DIO0
// ex on Atmega328 it's D2
#define CSMA_LIMIT -100 // upper RX signal sensitivity threshold in dBm for carrier sense access
#define RF69_MODE_SLEEP 0 // XTAL OFF
#define RF69_MODE_STANDBY 1 // XTAL ON
#define RF69_MODE_SYNTH 2 // PLL ON
#define RF69_MODE_RX 3 // RX MODE
#define RF69_MODE_TX 4 // TX MODE
//available frequency bands
#define RF69_315MHZ 31 // non trivial values to avoid misconfiguration
#define RF69_433MHZ 43
#define RF69_868MHZ 86
#define RF69_915MHZ 91
#define null 0
class RFM69 {
public:
volatile byte DATA[MAX_DATA_LEN]; // recv/xmit buf, including hdr & crc bytes
volatile byte DATALEN;
volatile byte SENDERID;
volatile byte TARGETID; //should match _address
volatile byte PAYLOADLEN;
volatile byte ACK_REQUESTED;
volatile byte ACK_RECEIVED; /// Should be polled immediately after sending a packet with ACK request
RFM69(byte slaveSelectPin=SPI_CS, byte interruptPin=RF69_IRQ_PIN, bool isRFM69HW=false) {
_slaveSelectPin = slaveSelectPin;
_interruptPin = interruptPin;
_mode = RF69_MODE_STANDBY;
_promiscuousMode = false;
_powerLevel = 31;
_isRFM69HW = isRFM69HW;
}
bool initialize(byte ID, byte freqBand, byte networkID=1);
void setAddress(byte addr);
bool canSend();
void send(byte toAddress, const void* buffer, byte bufferSize, bool requestACK=false);
bool sendWithRetry(byte toAddress, const void* buffer, byte bufferSize, byte attempts=3, byte retryWaitTime=15);
bool receiveDone();
bool ACKReceived(byte fromNodeID);
void sendACK(const void* buffer = "", uint8_t bufferSize=0);
void setFrequency(uint32_t FRF);
void encrypt(const char* key);
void setCS(byte newSPISlaveSelect);
int readRSSI(bool forceTrigger=false);
void promiscuous(bool onOff=true);
void setHighPower(bool onOFF=true); //for RFM69HW
void sleep();
// allow hacking registers by making these public
byte readReg(byte addr);
void writeReg(byte addr, byte val);
void readAllRegs();
protected:
static void isr0();
void interruptHandler();
void sendFrame(byte toAddress, const void* buffer, byte size, bool requestACK=false, bool sendACK=false);
static RFM69* selfPointer;
byte _slaveSelectPin;
byte _interruptPin;
byte _mode;
byte _address;
byte _powerLevel;
bool _promiscuousMode;
bool _isRFM69HW;
void receiveBegin();
void setMode(byte mode);
void setPowerLevel(byte mode);
void setHighPowerRegs(bool onOff);
void select();
void unselect();
};
#endif

1038
RFM69registers.h Normal file

File diff suppressed because it is too large Load Diff

52
keywords.txt Normal file
View File

@ -0,0 +1,52 @@
#######################################
# Syntax Coloring Map for RFM69
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
#######################################
# Instances (KEYWORD2)
#######################################
RFM69 KEYWORD2
#######################################
# Methods and Functions (KEYWORD2)
#######################################
initialize KEYWORD2
setAddress KEYWORD2
canSend KEYWORD2
send KEYWORD2
sendWithRetry KEYWORD2
receiveDone KEYWORD2
ACKReceived KEYWORD2
sendACK KEYWORD2
setFrequency KEYWORD2
encrypt KEYWORD2
setCS KEYWORD2
readRSSI KEYWORD2
promiscuous KEYWORD2
setHiPower KEYWORD2
CryptFunction KEYWORD2
sleep KEYWORD2
readReg KEYWORD2
writeReg KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
RF69_315MHZ LITERAL1
RF69_433MHZ LITERAL1
RF69_868MHZ LITERAL1
RF69_915MHZ LITERAL1
#######################################
# Variables/Volatiles (LITERAL2)
#######################################
DATA LITERAL2
DATALEN LITERAL2
SENDERID LITERAL2
TARGETID LITERAL2
PAYLOADLEN LITERAL2
ACK_REQUESTED LITERAL2
ACK_RECEIVED LITERAL2