Skip to content

Commit 6cdc933

Browse files
committed
Added IRQLESS mode, moteino and modem config
1 parent 814a0b8 commit 6cdc933

File tree

2 files changed

+158
-17
lines changed

2 files changed

+158
-17
lines changed

RH_RF69.cpp

Lines changed: 122 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
// Interrupt vectors for the 3 Arduino interrupt pins
99
// Each interrupt can be handled by a different instance of RH_RF69, allowing you to have
1010
// 2 or more RF69s per Arduino
11+
#ifndef RH_RF69_IRQLESS
1112
RH_RF69* RH_RF69::_deviceForInterrupt[RH_RF69_NUM_INTERRUPTS] = {0, 0, 0};
1213
uint8_t RH_RF69::_interruptCount = 0; // Index into _deviceForInterrupt for next device
14+
#endif
1315

1416
// These are indexed by the values of ModemConfigChoice
1517
// Stored in flash (program) memory to save SRAM
@@ -45,6 +47,10 @@ PROGMEM static const RH_RF69::ModemConfig MODEM_CONFIG_TABLE[] =
4547
{ CONFIG_FSK, 0x00, 0x80, 0x10, 0x00, 0xe0, 0xe0, CONFIG_WHITE}, // FSK_Rb250Fd250
4648
{ CONFIG_FSK, 0x02, 0x40, 0x03, 0x33, 0x42, 0x42, CONFIG_WHITE}, // FSK_Rb55555Fd50
4749

50+
// MOTEINO
51+
// REGAFCBW set to default 0x8A, No DC-free encoding/decoding performed
52+
{ CONFIG_FSK, 0x02, 0x40, 0x03, 0x33, 0x42, 0x8A, CONFIG_NOWHITE}, // FSK_MOTEINO
53+
4854
// 02, 03, 04, 05, 06, 19, 1a, 37
4955
// GFSK (BT=1.0), No Manchester, whitening, CRC, no address filtering
5056
// AFC BW == RX BW == 2 x bit rate
@@ -87,33 +93,56 @@ RH_RF69::RH_RF69(uint8_t slaveSelectPin, uint8_t interruptPin, RHGenericSPI& spi
8793
:
8894
RHSPIDriver(slaveSelectPin, spi)
8995
{
96+
#ifndef RH_RF69_IRQLESS
9097
_interruptPin = interruptPin;
91-
_idleMode = RH_RF69_OPMODE_MODE_STDBY;
9298
_myInterruptIndex = 0xff; // Not allocated yet
99+
#endif
100+
_idleMode = RH_RF69_OPMODE_MODE_STDBY;
93101
}
94102

95103
void RH_RF69::setIdleMode(uint8_t idleMode)
96104
{
97105
_idleMode = idleMode;
98106
}
99107

100-
bool RH_RF69::init()
108+
// Set configuration to be moteino compatible
109+
void RH_RF69::setConfigMoteino()
110+
{
111+
setModemConfig(FSK_MOTEINO);
112+
setPreambleLength(3);
113+
spiWrite(RH_RF69_REG_29_RSSITHRESH, 220);
114+
spiWrite(RH_RF69_REG_3D_PACKETCONFIG2, RH_RF69_PACKETCONFIG2_RXRESTARTDELAY_2BITS | RH_RF69_PACKETCONFIG2_AUTORXRESTARTON);
115+
// default moteino Frequency For 433 MHz
116+
setFrequency(433.0);
117+
118+
// Moteino default network ID is 1
119+
uint8_t syncwords[] = { 0x2d, 1 };
120+
setSyncWords(syncwords, sizeof(syncwords));
121+
//spiWrite(RH_RF69_REG_07_FRFMSB, 0x6C);
122+
//spiWrite(RH_RF69_REG_08_FRFMID, 0x40);
123+
//spiWrite(RH_RF69_REG_09_FRFLSB, 0x00);
124+
}
125+
126+
bool RH_RF69::init(void)
101127
{
102128
if (!RHSPIDriver::init())
103129
return false;
104130

131+
#ifndef RH_RF69_IRQLESS
105132
// Determine the interrupt number that corresponds to the interruptPin
106133
int interruptNumber = digitalPinToInterrupt(_interruptPin);
107134
if (interruptNumber == NOT_AN_INTERRUPT)
108135
return false;
136+
#endif
109137

110138
// Get the device type and check it
111139
// This also tests whether we are really connected to a device
112140
// My test devices return 0x24
113-
_deviceType = spiRead(RH_RF69_REG_10_VERSION);
114-
if (_deviceType == 00 ||
115-
_deviceType == 0xff)
116-
return false;
141+
_deviceType = spiRead(RH_RF69_REG_10_VERSION);
142+
if (_deviceType == 00 || _deviceType == 0xff)
143+
return false;
144+
145+
#ifndef RH_RF69_IRQLESS
117146

118147
// Add by Adrien van den Bossche <[email protected]> for Teensy
119148
// ARM M4 requires the below. else pin interrupt doesn't work properly.
@@ -144,6 +173,7 @@ bool RH_RF69::init()
144173
else
145174
return false; // Too many devices, not enough interrupt vectors
146175

176+
#endif
147177
setModeIdle();
148178

149179
// Configure important RH_RF69 registers
@@ -172,7 +202,6 @@ bool RH_RF69::init()
172202
// Set up default configuration
173203
uint8_t syncwords[] = { 0x2d, 0xd4 };
174204
setSyncWords(syncwords, sizeof(syncwords)); // Same as RF22's
175-
// Reasonably fast and reliable default speed and modulation
176205
setModemConfig(GFSK_Rb250Fd250);
177206

178207
// 3 would be sufficient, but this is the same as RF22's
@@ -184,23 +213,27 @@ bool RH_RF69::init()
184213
// +13dBm, same as power-on default
185214
setTxPower(13);
186215

216+
// override and set config to moteino
217+
setConfigMoteino();
218+
187219
return true;
188220
}
189221

190222
// C++ level interrupt handler for this instance
191223
// RH_RF69 is unusual in Mthat it has several interrupt lines, and not a single, combined one.
192224
// On Moteino, only one of the several interrupt lines (DI0) from the RH_RF69 is connnected to the processor.
193225
// We use this to get PACKETSDENT and PAYLOADRADY interrupts.
226+
#ifndef RH_RF69_IRQLESS
194227
void RH_RF69::handleInterrupt()
195228
{
196229
// Get the interrupt cause
197230
uint8_t irqflags2 = spiRead(RH_RF69_REG_28_IRQFLAGS2);
198231
if (_mode == RHModeTx && (irqflags2 & RH_RF69_IRQFLAGS2_PACKETSENT))
199232
{
233+
// Serial.println("PACKETSENT");
200234
// A transmitter message has been fully sent
201235
setModeIdle(); // Clears FIFO
202236
_txGood++;
203-
// Serial.println("PACKETSENT");
204237
}
205238
// Must look for PAYLOADREADY, not CRCOK, since only PAYLOADREADY occurs _after_ AES decryption
206239
// has been done
@@ -210,12 +243,14 @@ void RH_RF69::handleInterrupt()
210243
_lastRssi = -((int8_t)(spiRead(RH_RF69_REG_24_RSSIVALUE) >> 1));
211244
_lastPreambleTime = millis();
212245

246+
// Serial.println("PAYLOADREADY");
213247
setModeIdle();
248+
214249
// Save it in our buffer
215250
readFifo();
216-
// Serial.println("PAYLOADREADY");
217251
}
218252
}
253+
#endif
219254

220255
// Low level function reads the FIFO and checks the address
221256
// Caution: since we put our headers in what the RH_RF69 considers to be the payload, if encryption is enabled
@@ -231,18 +266,20 @@ void RH_RF69::readFifo()
231266
payloadlen >= RH_RF69_HEADER_LEN)
232267
{
233268
_rxHeaderTo = _spi.transfer(0);
234-
// Check addressing
269+
// Check addressing
235270
if (_promiscuous ||
236271
_rxHeaderTo == _thisAddress ||
237272
_rxHeaderTo == RH_BROADCAST_ADDRESS)
238273
{
239274
// Get the rest of the headers
240275
_rxHeaderFrom = _spi.transfer(0);
241-
_rxHeaderId = _spi.transfer(0);
276+
_rxHeaderId = _spi.transfer(0);
242277
_rxHeaderFlags = _spi.transfer(0);
278+
243279
// And now the real payload
244280
for (_bufLen = 0; _bufLen < (payloadlen - RH_RF69_HEADER_LEN); _bufLen++)
245-
_buf[_bufLen] = _spi.transfer(0);
281+
_buf[_bufLen] = _spi.transfer(0);
282+
246283
_rxGood++;
247284
_rxBufValid = true;
248285
}
@@ -255,6 +292,7 @@ void RH_RF69::readFifo()
255292
// These are low level functions that call the interrupt handler for the correct
256293
// instance of RH_RF69.
257294
// 3 interrupts allows us to have 3 different devices
295+
#ifndef RH_RF69_IRQLESS
258296
void RH_RF69::isr0()
259297
{
260298
if (_deviceForInterrupt[0])
@@ -270,6 +308,7 @@ void RH_RF69::isr2()
270308
if (_deviceForInterrupt[2])
271309
_deviceForInterrupt[2]->handleInterrupt();
272310
}
311+
#endif
273312

274313
int8_t RH_RF69::temperatureRead()
275314
{
@@ -307,6 +346,17 @@ int8_t RH_RF69::rssiRead()
307346

308347
void RH_RF69::setOpMode(uint8_t mode)
309348
{
349+
/*
350+
Serial.print("\r\nsetOpMode ");
351+
if (mode & 0x40) Serial.print(" ListOn");
352+
if (mode & 0x20) Serial.print(" ListAbrt");
353+
if ((mode & 0x1C) == 0x00) Serial.print(" Sleep");
354+
if ((mode & 0x1C) == 0x04) Serial.print(" Standby");
355+
if ((mode & 0x1C) == 0x08) Serial.print(" FS");
356+
if ((mode & 0x1C) == 0x0C) Serial.print(" TX");
357+
if ((mode & 0x1C) == 0x10) Serial.print(" RX");
358+
*/
359+
310360
uint8_t opmode = spiRead(RH_RF69_REG_01_OPMODE);
311361
opmode &= ~RH_RF69_OPMODE_MODE;
312362
opmode |= (mode & RH_RF69_OPMODE_MODE);
@@ -369,6 +419,12 @@ void RH_RF69::setModeTx()
369419
spiWrite(RH_RF69_REG_5A_TESTPA1, RH_RF69_TESTPA1_BOOST);
370420
spiWrite(RH_RF69_REG_5C_TESTPA2, RH_RF69_TESTPA2_BOOST);
371421
}
422+
423+
/*
424+
Serial.print(" 5A_PA1=0x"); Serial.print(spiRead(RH_RF69_REG_5A_TESTPA1),HEX);
425+
Serial.print(" 5C_PA2=0x"); Serial.print(spiRead(RH_RF69_REG_5C_TESTPA2),HEX);
426+
Serial.print(" TxPower=0x"); Serial.println(spiRead(RH_RF69_REG_11_PALEVEL),HEX);
427+
*/
372428
spiWrite(RH_RF69_REG_25_DIOMAPPING1, RH_RF69_DIOMAPPING1_DIO0MAPPING_00); // Set interrupt line 0 PacketSent
373429
setOpMode(RH_RF69_OPMODE_MODE_TX); // Clears FIFO
374430
_mode = RHModeTx;
@@ -428,6 +484,15 @@ bool RH_RF69::setModemConfig(ModemConfigChoice index)
428484
return true;
429485
}
430486

487+
bool RH_RF69::getModemConfig(ModemConfigChoice index, ModemConfig* config)
488+
{
489+
if (index > (signed int)(sizeof(MODEM_CONFIG_TABLE) / sizeof(ModemConfig)))
490+
return false;
491+
492+
memcpy_P(config, &MODEM_CONFIG_TABLE[index], sizeof(RH_RF69::ModemConfig));
493+
494+
return true;
495+
}
431496
void RH_RF69::setPreambleLength(uint16_t bytes)
432497
{
433498
spiWrite(RH_RF69_REG_2C_PREAMBLEMSB, bytes >> 8);
@@ -464,10 +529,31 @@ void RH_RF69::setEncryptionKey(uint8_t* key)
464529

465530
bool RH_RF69::available()
466531
{
467-
if (_mode == RHModeTx)
468-
return false;
469-
setModeRx(); // Make sure we are receiving
470-
return _rxBufValid;
532+
#ifdef RH_RF69_IRQLESS
533+
// Must look for PAYLOADREADY, not CRCOK, since only PAYLOADREADY occurs _after_ AES decryption
534+
// has been done
535+
536+
// Get the interrupt state
537+
uint8_t irqflags2 = spiRead(RH_RF69_REG_28_IRQFLAGS2);
538+
539+
if (_mode == RHModeRx && (irqflags2 & RH_RF69_IRQFLAGS2_PAYLOADREADY))
540+
{
541+
// A complete message has been received with good CRC
542+
_lastRssi = -((int8_t)(spiRead(RH_RF69_REG_24_RSSIVALUE) >> 1));
543+
_lastPreambleTime = millis();
544+
545+
setModeIdle();
546+
547+
// Save it in our buffer
548+
readFifo();
549+
}
550+
#endif
551+
552+
if (_mode == RHModeTx)
553+
return false;
554+
555+
setModeRx(); // Make sure we are receiving
556+
return _rxBufValid;
471557
}
472558

473559
bool RH_RF69::recv(uint8_t* buf, uint8_t* len)
@@ -507,14 +593,33 @@ bool RH_RF69::send(const uint8_t* data, uint8_t len)
507593
_spi.transfer(_txHeaderFlags);
508594
// Now the payload
509595
while (len--)
510-
_spi.transfer(*data++);
596+
_spi.transfer(*data++);
511597
digitalWrite(_slaveSelectPin, HIGH);
512598
ATOMIC_BLOCK_END;
513599

514600
setModeTx(); // Start the transmitter
515601
return true;
516602
}
517603

604+
#ifdef RH_RF69_IRQLESS
605+
bool RH_RF69::waitPacketSent()
606+
{
607+
// If we are not currently in transmit mode, there is no packet to wait for
608+
if (_mode != RHModeTx)
609+
return false;
610+
611+
while (!(spiRead(RH_RF69_REG_28_IRQFLAGS2) & RH_RF69_IRQFLAGS2_PACKETSENT)){
612+
YIELD;
613+
}
614+
615+
// A transmitter message has been fully sent
616+
setModeIdle(); // Clears FIFO
617+
_txGood++;
618+
return true;
619+
}
620+
#endif
621+
622+
518623
uint8_t RH_RF69::maxMessageLength()
519624
{
520625
return RH_RF69_MAX_MESSAGE_LEN;

RH_RF69.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,19 @@
262262
#define RH_RF69_FIFOTHRESH_FIFOTHRESHOLD 0x7f
263263

264264
// RH_RF69_REG_3D_PACKETCONFIG2
265+
#define RH_RF69_PACKETCONFIG2_RXRESTARTDELAY_1BIT 0x00 // Default
266+
#define RH_RF69_PACKETCONFIG2_RXRESTARTDELAY_2BITS 0x10
267+
#define RH_RF69_PACKETCONFIG2_RXRESTARTDELAY_4BITS 0x20
268+
#define RH_RF69_PACKETCONFIG2_RXRESTARTDELAY_8BITS 0x30
269+
#define RH_RF69_PACKETCONFIG2_RXRESTARTDELAY_16BITS 0x40
270+
#define RH_RF69_PACKETCONFIG2_RXRESTARTDELAY_32BITS 0x50
271+
#define RH_RF69_PACKETCONFIG2_RXRESTARTDELAY_64BITS 0x60
272+
#define RH_RF69_PACKETCONFIG2_RXRESTARTDELAY_128BITS 0x70
273+
#define RH_RF69_PACKETCONFIG2_RXRESTARTDELAY_256BITS 0x80
274+
#define RH_RF69_PACKETCONFIG2_RXRESTARTDELAY_512BITS 0x90
275+
#define RH_RF69_PACKETCONFIG2_RXRESTARTDELAY_1024BITS 0xA0
276+
#define RH_RF69_PACKETCONFIG2_RXRESTARTDELAY_2048BITS 0xB0
277+
#define RH_RF69_PACKETCONFIG2_RXRESTARTDELAY_NONE 0xC0
265278
#define RH_RF69_PACKETCONFIG2_INTERPACKETRXDELAY 0xf0
266279
#define RH_RF69_PACKETCONFIG2_RESTARTRX 0x04
267280
#define RH_RF69_PACKETCONFIG2_AUTORXRESTARTON 0x02
@@ -583,6 +596,7 @@ class RH_RF69 : public RHSPIDriver
583596
FSK_Rb125Fd125, ///< FSK, Whitening, Rb = 125kbs, Fd = 125kHz
584597
FSK_Rb250Fd250, ///< FSK, Whitening, Rb = 250kbs, Fd = 250kHz
585598
FSK_Rb55555Fd50, ///< FSK, Whitening, Rb = 55555kbs,Fd = 50kHz for RFM69 lib compatibility
599+
FSK_MOTEINO, ///< FSK, No Whitening, Rb = 55555kbs,Fd = 50kHz, No DC-Free for RFM69 lib compatibility
586600

587601
GFSK_Rb2Fd5, ///< GFSK, Whitening, Rb = 2kbs, Fd = 5kHz
588602
GFSK_Rb2_4Fd4_8, ///< GFSK, Whitening, Rb = 2.4kbs, Fd = 4.8kHz
@@ -636,6 +650,10 @@ class RH_RF69 : public RHSPIDriver
636650
/// \return true if everything was successful
637651
bool init();
638652

653+
654+
/// Configure the radio module to be in Moteino configuration
655+
void setConfigMoteino();
656+
639657
/// Reads the on-chip temperature sensor.
640658
/// The RF69 must be in Idle mode (= RF69 Standby) to measure temperature.
641659
/// The measurement is uncalibrated and without calibration, you can expect it to be far from
@@ -698,6 +716,13 @@ class RH_RF69 : public RHSPIDriver
698716
/// \return true if index is a valid choice.
699717
bool setModemConfig(ModemConfigChoice index);
700718

719+
/// Get the values of one of the predefined modem configurations.
720+
///
721+
/// \param[in] index The configuration choice.
722+
/// \param[in] config A ModemConfig structure that will contains values of the modem configuration values.
723+
/// \return true if index is a valid choice and config has been filled with values
724+
bool getModemConfig(ModemConfigChoice index, ModemConfig* config);
725+
701726
/// Starts the receiver and checks whether a received message is available.
702727
/// This can be called multiple times in a timeout loop
703728
/// \return true if a complete, valid message has been received and is able to be retrieved by
@@ -723,6 +748,13 @@ class RH_RF69 : public RHSPIDriver
723748
/// \return true if the message length was valid and it was correctly queued for transmit
724749
bool send(const uint8_t* data, uint8_t len);
725750

751+
/// Blocks until the current message (if any)
752+
/// has been transmitted
753+
/// \return true on success, false if the chip is not in transmit mode or other transmit failure
754+
#ifdef RH_RF69_IRQLESS
755+
virtual bool waitPacketSent();
756+
#endif
757+
726758
/// Sets the length of the preamble
727759
/// in bytes.
728760
/// Caution: this should be set to the same
@@ -787,13 +819,16 @@ class RH_RF69 : public RHSPIDriver
787819
/// This is a low level function to handle the interrupts for one instance of RF69.
788820
/// Called automatically by isr*()
789821
/// Should not need to be called by user code.
822+
#ifndef RH_RF69_IRQLESS
790823
void handleInterrupt();
824+
#endif
791825

792826
/// Low level function to read the FIFO and put the received data into the receive buffer
793827
/// Should not need to be called by user code.
794828
void readFifo();
795829

796830
protected:
831+
#ifndef RH_RF69_IRQLESS
797832
/// Low level interrupt service routine for RF69 connected to interrupt 0
798833
static void isr0();
799834

@@ -815,6 +850,7 @@ class RH_RF69 : public RHSPIDriver
815850
/// The index into _deviceForInterrupt[] for this device (if an interrupt is already allocated)
816851
/// else 0xff
817852
uint8_t _myInterruptIndex;
853+
#endif
818854

819855
/// The radio OP mode to use when mode is RHModeIdle
820856
uint8_t _idleMode;

0 commit comments

Comments
 (0)