David Rimer / RadioHead-148
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers RH_RF69.cpp Source File

RH_RF69.cpp

00001 // RH_RF69.cpp
00002 //
00003 // Copyright (C) 2011 Mike McCauley
00004 // $Id: RH_RF69.cpp,v 1.25 2015/05/17 00:11:26 mikem Exp $
00005 
00006 #include <RH_RF69.h>
00007 
00008 // Interrupt vectors for the 3 Arduino interrupt pins
00009 // Each interrupt can be handled by a different instance of RH_RF69, allowing you to have
00010 // 2 or more RF69s per Arduino
00011 RH_RF69* RH_RF69::_deviceForInterrupt[RH_RF69_NUM_INTERRUPTS] = {0, 0, 0};
00012 uint8_t RH_RF69::_interruptCount = 0; // Index into _deviceForInterrupt for next device
00013 
00014 // These are indexed by the values of ModemConfigChoice
00015 // Stored in flash (program) memory to save SRAM
00016 // It is important to keep the modulation index for FSK between 0.5 and 10
00017 // modulation index = 2 * Fdev / BR
00018 // Note that I have not had much success with FSK with Fd > ~5
00019 // You have to construct these by hand, using the data from the RF69 Datasheet :-(
00020 // or use the SX1231 starter kit software (Ctl-Alt-N to use that without a connected radio)
00021 #define CONFIG_FSK (RH_RF69_DATAMODUL_DATAMODE_PACKET | RH_RF69_DATAMODUL_MODULATIONTYPE_FSK | RH_RF69_DATAMODUL_MODULATIONSHAPING_FSK_NONE)
00022 #define CONFIG_GFSK (RH_RF69_DATAMODUL_DATAMODE_PACKET | RH_RF69_DATAMODUL_MODULATIONTYPE_FSK | RH_RF69_DATAMODUL_MODULATIONSHAPING_FSK_BT1_0)
00023 #define CONFIG_OOK (RH_RF69_DATAMODUL_DATAMODE_PACKET | RH_RF69_DATAMODUL_MODULATIONTYPE_OOK | RH_RF69_DATAMODUL_MODULATIONSHAPING_OOK_NONE)
00024 
00025 // Choices for RH_RF69_REG_37_PACKETCONFIG1:
00026 #define CONFIG_NOWHITE (RH_RF69_PACKETCONFIG1_PACKETFORMAT_VARIABLE | RH_RF69_PACKETCONFIG1_DCFREE_NONE | RH_RF69_PACKETCONFIG1_CRC_ON | RH_RF69_PACKETCONFIG1_ADDRESSFILTERING_NONE)
00027 #define CONFIG_WHITE (RH_RF69_PACKETCONFIG1_PACKETFORMAT_VARIABLE | RH_RF69_PACKETCONFIG1_DCFREE_WHITENING | RH_RF69_PACKETCONFIG1_CRC_ON | RH_RF69_PACKETCONFIG1_ADDRESSFILTERING_NONE)
00028 #define CONFIG_MANCHESTER (RH_RF69_PACKETCONFIG1_PACKETFORMAT_VARIABLE | RH_RF69_PACKETCONFIG1_DCFREE_MANCHESTER | RH_RF69_PACKETCONFIG1_CRC_ON | RH_RF69_PACKETCONFIG1_ADDRESSFILTERING_NONE)
00029 PROGMEM static const RH_RF69::ModemConfig MODEM_CONFIG_TABLE[] =
00030 {
00031     //  02,        03,   04,   05,   06,   19,   1a,  37
00032     // FSK, No Manchester, no shaping, whitening, CRC, no address filtering
00033     // AFC BW == RX BW == 2 x bit rate
00034     // Low modulation indexes of ~ 1 at slow speeds do not seem to work very well. Choose MI of 2.
00035     { CONFIG_FSK,  0x3e, 0x80, 0x00, 0x52, 0xf4, 0xf4, CONFIG_WHITE}, // FSK_Rb2Fd5      
00036     { CONFIG_FSK,  0x34, 0x15, 0x00, 0x4f, 0xf4, 0xf4, CONFIG_WHITE}, // FSK_Rb2_4Fd4_8
00037     { CONFIG_FSK,  0x1a, 0x0b, 0x00, 0x9d, 0xf4, 0xf4, CONFIG_WHITE}, // FSK_Rb4_8Fd9_6
00038 
00039     { CONFIG_FSK,  0x0d, 0x05, 0x01, 0x3b, 0xf4, 0xf4, CONFIG_WHITE}, // FSK_Rb9_6Fd19_2
00040     { CONFIG_FSK,  0x06, 0x83, 0x02, 0x75, 0xf3, 0xf3, CONFIG_WHITE}, // FSK_Rb19_2Fd38_4
00041     { CONFIG_FSK,  0x03, 0x41, 0x04, 0xea, 0xf2, 0xf2, CONFIG_WHITE}, // FSK_Rb38_4Fd76_8
00042 
00043     { CONFIG_FSK,  0x02, 0x2c, 0x07, 0xae, 0xe2, 0xe2, CONFIG_WHITE}, // FSK_Rb57_6Fd120
00044     { CONFIG_FSK,  0x01, 0x00, 0x08, 0x00, 0xe1, 0xe1, CONFIG_WHITE}, // FSK_Rb125Fd125
00045     { CONFIG_FSK,  0x00, 0x80, 0x10, 0x00, 0xe0, 0xe0, CONFIG_WHITE}, // FSK_Rb250Fd250
00046     { CONFIG_FSK,  0x02, 0x40, 0x03, 0x33, 0x42, 0x42, CONFIG_WHITE}, // FSK_Rb55555Fd50 
00047 
00048     //  02,        03,   04,   05,   06,   19,   1a,  37
00049     // GFSK (BT=1.0), No Manchester, whitening, CRC, no address filtering
00050     // AFC BW == RX BW == 2 x bit rate
00051     { CONFIG_GFSK, 0x3e, 0x80, 0x00, 0x52, 0xf4, 0xf5, CONFIG_WHITE}, // GFSK_Rb2Fd5
00052     { CONFIG_GFSK, 0x34, 0x15, 0x00, 0x4f, 0xf4, 0xf4, CONFIG_WHITE}, // GFSK_Rb2_4Fd4_8
00053     { CONFIG_GFSK, 0x1a, 0x0b, 0x00, 0x9d, 0xf4, 0xf4, CONFIG_WHITE}, // GFSK_Rb4_8Fd9_6
00054 
00055     { CONFIG_GFSK, 0x0d, 0x05, 0x01, 0x3b, 0xf4, 0xf4, CONFIG_WHITE}, // GFSK_Rb9_6Fd19_2
00056     { CONFIG_GFSK, 0x06, 0x83, 0x02, 0x75, 0xf3, 0xf3, CONFIG_WHITE}, // GFSK_Rb19_2Fd38_4
00057     { CONFIG_GFSK, 0x03, 0x41, 0x04, 0xea, 0xf2, 0xf2, CONFIG_WHITE}, // GFSK_Rb38_4Fd76_8
00058 
00059     { CONFIG_GFSK, 0x02, 0x2c, 0x07, 0xae, 0xe2, 0xe2, CONFIG_WHITE}, // GFSK_Rb57_6Fd120
00060     { CONFIG_GFSK, 0x01, 0x00, 0x08, 0x00, 0xe1, 0xe1, CONFIG_WHITE}, // GFSK_Rb125Fd125
00061     { CONFIG_GFSK, 0x00, 0x80, 0x10, 0x00, 0xe0, 0xe0, CONFIG_WHITE}, // GFSK_Rb250Fd250
00062     { CONFIG_GFSK, 0x02, 0x40, 0x03, 0x33, 0x42, 0x42, CONFIG_WHITE}, // GFSK_Rb55555Fd50 
00063 
00064     //  02,        03,   04,   05,   06,   19,   1a,  37
00065     // OOK, No Manchester, no shaping, whitening, CRC, no address filtering
00066     // with the help of the SX1231 configuration program
00067     // AFC BW == RX BW
00068     // All OOK configs have the default:
00069     // Threshold Type: Peak
00070     // Peak Threshold Step: 0.5dB
00071     // Peak threshiold dec: ONce per chip
00072     // Fixed threshold: 6dB
00073     { CONFIG_OOK,  0x7d, 0x00, 0x00, 0x10, 0x88, 0x88, CONFIG_WHITE}, // OOK_Rb1Bw1
00074     { CONFIG_OOK,  0x68, 0x2b, 0x00, 0x10, 0xf1, 0xf1, CONFIG_WHITE}, // OOK_Rb1_2Bw75
00075     { CONFIG_OOK,  0x34, 0x15, 0x00, 0x10, 0xf5, 0xf5, CONFIG_WHITE}, // OOK_Rb2_4Bw4_8
00076     { CONFIG_OOK,  0x1a, 0x0b, 0x00, 0x10, 0xf4, 0xf4, CONFIG_WHITE}, // OOK_Rb4_8Bw9_6
00077     { CONFIG_OOK,  0x0d, 0x05, 0x00, 0x10, 0xf3, 0xf3, CONFIG_WHITE}, // OOK_Rb9_6Bw19_2
00078     { CONFIG_OOK,  0x06, 0x83, 0x00, 0x10, 0xf2, 0xf2, CONFIG_WHITE}, // OOK_Rb19_2Bw38_4
00079     { CONFIG_OOK,  0x03, 0xe8, 0x00, 0x10, 0xe2, 0xe2, CONFIG_WHITE}, // OOK_Rb32Bw64
00080 
00081 //    { CONFIG_FSK,  0x68, 0x2b, 0x00, 0x52, 0x55, 0x55, CONFIG_WHITE}, // works: Rb1200 Fd 5000 bw10000, DCC 400
00082 //    { CONFIG_FSK,  0x0c, 0x80, 0x02, 0x8f, 0x52, 0x52, CONFIG_WHITE}, // works 10/40/80
00083 //    { CONFIG_FSK,  0x0c, 0x80, 0x02, 0x8f, 0x53, 0x53, CONFIG_WHITE}, // works 10/40/40
00084 
00085 };
00086 RH_RF69::RH_RF69(PINS slaveSelectPin, PINS interruptPin, RHGenericSPI& spi)
00087     :
00088     RHSPIDriver(slaveSelectPin, spi),
00089     _interruptPin(interruptPin)
00090 {
00091     _idleMode = RH_RF69_OPMODE_MODE_STDBY;
00092     _myInterruptIndex = 0xff; // Not allocated yet
00093 }
00094 
00095 void RH_RF69::setIdleMode(uint8_t idleMode)
00096 {
00097     _idleMode = idleMode;
00098 }
00099 
00100 bool RH_RF69::init()
00101 {
00102     if (!RHSPIDriver::init())
00103     return false;
00104 
00105 #if (RH_PLATFORM != RH_PLATFORM_MBED)
00106     // Determine the interrupt number that corresponds to the interruptPin
00107     int interruptNumber = digitalPinToInterrupt(_interruptPin);
00108     if (interruptNumber == NOT_AN_INTERRUPT)
00109     return false;
00110 #endif
00111 
00112     // Get the device type and check it
00113     // This also tests whether we are really connected to a device
00114     // My test devices return 0x24
00115     _deviceType = spiRead(RH_RF69_REG_10_VERSION);
00116     if (_deviceType == 00 ||
00117     _deviceType == 0xff)
00118     return false;
00119 
00120     // Add by Adrien van den Bossche <vandenbo@univ-tlse2.fr> for Teensy
00121     // ARM M4 requires the below. else pin interrupt doesn't work properly.
00122     // On all other platforms, its innocuous, belt and braces
00123 #if (RH_PLATFORM != RH_PLATFORM_MBED)
00124     pinMode(_interruptPin, INPUT); 
00125 #endif
00126 
00127 
00128 
00129     // Set up interrupt handler
00130     // Since there are a limited number of interrupt glue functions isr*() available,
00131     // we can only support a limited number of devices simultaneously
00132     // ON some devices, notably most Arduinos, the interrupt pin passed in is actuallt the 
00133     // interrupt number. You have to figure out the interruptnumber-to-interruptpin mapping
00134     // yourself based on knwledge of what Arduino board you are running on.
00135     if (_myInterruptIndex == 0xff)
00136     {
00137     // First run, no interrupt allocated yet
00138     if (_interruptCount <= RH_RF69_NUM_INTERRUPTS)
00139         _myInterruptIndex = _interruptCount++;
00140     else
00141         return false; // Too many devices, not enough interrupt vectors
00142     }
00143     _deviceForInterrupt[_myInterruptIndex] = this;
00144 #if (RH_PLATFORM == RH_PLATFORM_MBED)
00145     if (_myInterruptIndex == 0)
00146         _interruptPin.rise(&isr0);
00147     else if (_myInterruptIndex == 1)
00148         _interruptPin.rise(&isr1);
00149     else if (_myInterruptIndex == 2)
00150         _interruptPin.rise(&isr2);
00151     else
00152     return false; // Too many devices, not enough interrupt vectors
00153 #else
00154     if (_myInterruptIndex == 0)
00155         attachInterrupt(interruptNumber, isr0, RISING);
00156     else if (_myInterruptIndex == 1)
00157         attachInterrupt(interruptNumber, isr1, RISING);
00158     else if (_myInterruptIndex == 2)
00159         attachInterrupt(interruptNumber, isr2, RISING);
00160     else
00161         return false; // Too many devices, not enough interrupt vectors
00162 #endif
00163 
00164 
00165     setModeIdle();
00166 
00167     // Configure important RH_RF69 registers
00168     // Here we set up the standard packet format for use by the RH_RF69 library:
00169     // 4 bytes preamble
00170     // 2 SYNC words 2d, d4
00171     // 2 CRC CCITT octets computed on the header, length and data (this in the modem config data)
00172     // 0 to 60 bytes data
00173     // RSSI Threshold -114dBm
00174     // We dont use the RH_RF69s address filtering: instead we prepend our own headers to the beginning
00175     // of the RH_RF69 payload
00176     spiWrite(RH_RF69_REG_3C_FIFOTHRESH, RH_RF69_FIFOTHRESH_TXSTARTCONDITION_NOTEMPTY | 0x0f); // thresh 15 is default
00177     // RSSITHRESH is default
00178 //    spiWrite(RH_RF69_REG_29_RSSITHRESH, 220); // -110 dbM
00179     // SYNCCONFIG is default. SyncSize is set later by setSyncWords()
00180 //    spiWrite(RH_RF69_REG_2E_SYNCCONFIG, RH_RF69_SYNCCONFIG_SYNCON); // auto, tolerance 0
00181     // PAYLOADLENGTH is default
00182 //    spiWrite(RH_RF69_REG_38_PAYLOADLENGTH, RH_RF69_FIFO_SIZE); // max size only for RX
00183     // PACKETCONFIG 2 is default 
00184     spiWrite(RH_RF69_REG_6F_TESTDAGC, RH_RF69_TESTDAGC_CONTINUOUSDAGC_IMPROVED_LOWBETAOFF);
00185     // If high power boost set previously, disable it
00186     spiWrite(RH_RF69_REG_5A_TESTPA1, RH_RF69_TESTPA1_NORMAL);
00187     spiWrite(RH_RF69_REG_5C_TESTPA2, RH_RF69_TESTPA2_NORMAL);
00188 
00189     // The following can be changed later by the user if necessary.
00190     // Set up default configuration
00191     uint8_t syncwords[] = { 0x2d, 0xd4 };
00192     setSyncWords(syncwords, sizeof(syncwords)); // Same as RF22's
00193     // Reasonably fast and reliable default speed and modulation
00194     setModemConfig(GFSK_Rb250Fd250);
00195 
00196     // 3 would be sufficient, but this is the same as RF22's
00197     setPreambleLength(4);
00198     // An innocuous ISM frequency, same as RF22's
00199     setFrequency(434.0);
00200     // No encryption
00201     setEncryptionKey(NULL);
00202     // +13dBm, same as power-on default
00203     setTxPower(13); 
00204 
00205     return true;
00206 }
00207 
00208 // C++ level interrupt handler for this instance
00209 // RH_RF69 is unusual in Mthat it has several interrupt lines, and not a single, combined one.
00210 // On Moteino, only one of the several interrupt lines (DI0) from the RH_RF69 is connnected to the processor.
00211 // We use this to get PACKETSDENT and PAYLOADRADY interrupts.
00212 void RH_RF69::handleInterrupt()
00213 {
00214     // Get the interrupt cause
00215     uint8_t irqflags2 = spiRead(RH_RF69_REG_28_IRQFLAGS2);
00216     if (_mode == RHModeTx && (irqflags2 & RH_RF69_IRQFLAGS2_PACKETSENT))
00217     {
00218     // A transmitter message has been fully sent
00219     setModeIdle(); // Clears FIFO
00220     _txGood++;
00221 //  Serial.println("PACKETSENT");
00222     }
00223     // Must look for PAYLOADREADY, not CRCOK, since only PAYLOADREADY occurs _after_ AES decryption
00224     // has been done
00225     if (_mode == RHModeRx && (irqflags2 & RH_RF69_IRQFLAGS2_PAYLOADREADY))
00226     {
00227     // A complete message has been received with good CRC
00228     _lastRssi = -((int8_t)(spiRead(RH_RF69_REG_24_RSSIVALUE) >> 1));
00229     _lastPreambleTime = millis();
00230 
00231     setModeIdle();
00232     // Save it in our buffer
00233     readFifo();
00234 //  Serial.println("PAYLOADREADY");
00235     }
00236 }
00237 
00238 // Low level function reads the FIFO and checks the address
00239 // Caution: since we put our headers in what the RH_RF69 considers to be the payload, if encryption is enabled
00240 // we have to suffer the cost of decryption before we can determine whether the address is acceptable. 
00241 // Performance issue?
00242 void RH_RF69::readFifo()
00243 {
00244     ATOMIC_BLOCK_START;
00245     digitalWrite(_slaveSelectPin, LOW);
00246     _spi.transfer(RH_RF69_REG_00_FIFO); // Send the start address with the write mask off
00247     uint8_t payloadlen = _spi.transfer(0); // First byte is payload len (counting the headers)
00248     if (payloadlen <= RH_RF69_MAX_ENCRYPTABLE_PAYLOAD_LEN &&
00249     payloadlen >= RH_RF69_HEADER_LEN)
00250     {
00251     _rxHeaderTo = _spi.transfer(0);
00252     // Check addressing
00253     if (_promiscuous ||
00254         _rxHeaderTo == _thisAddress ||
00255         _rxHeaderTo == RH_BROADCAST_ADDRESS)
00256     {
00257         // Get the rest of the headers
00258         _rxHeaderFrom  = _spi.transfer(0);
00259         _rxHeaderId    = _spi.transfer(0);
00260         _rxHeaderFlags = _spi.transfer(0);
00261         // And now the real payload
00262         for (_bufLen = 0; _bufLen < (payloadlen - RH_RF69_HEADER_LEN); _bufLen++)
00263         _buf[_bufLen] = _spi.transfer(0);
00264         _rxGood++;
00265         _rxBufValid = true;
00266     }
00267     }
00268     digitalWrite(_slaveSelectPin, HIGH);
00269     ATOMIC_BLOCK_END;
00270     // Any junk remaining in the FIFO will be cleared next time we go to receive mode.
00271 }
00272 
00273 // These are low level functions that call the interrupt handler for the correct
00274 // instance of RH_RF69.
00275 // 3 interrupts allows us to have 3 different devices
00276 void RH_RF69::isr0()
00277 {
00278     if (_deviceForInterrupt[0])
00279     _deviceForInterrupt[0]->handleInterrupt();
00280 }
00281 void RH_RF69::isr1()
00282 {
00283     if (_deviceForInterrupt[1])
00284     _deviceForInterrupt[1]->handleInterrupt();
00285 }
00286 void RH_RF69::isr2()
00287 {
00288     if (_deviceForInterrupt[2])
00289     _deviceForInterrupt[2]->handleInterrupt();
00290 }
00291 
00292 int8_t RH_RF69::temperatureRead()
00293 {
00294     // Caution: must be ins standby.
00295 //    setModeIdle();
00296     spiWrite(RH_RF69_REG_4E_TEMP1, RH_RF69_TEMP1_TEMPMEASSTART); // Start the measurement
00297     while (spiRead(RH_RF69_REG_4E_TEMP1) & RH_RF69_TEMP1_TEMPMEASRUNNING)
00298     ; // Wait for the measurement to complete
00299     return 166 - spiRead(RH_RF69_REG_4F_TEMP2); // Very approximate, based on observation
00300 }
00301 
00302 bool RH_RF69::setFrequency(float centre, float afcPullInRange)
00303 {
00304     // Frf = FRF / FSTEP
00305     uint32_t frf = (uint32_t)((centre * 1000000.0) / RH_RF69_FSTEP);
00306     spiWrite(RH_RF69_REG_07_FRFMSB, (frf >> 16) & 0xff);
00307     spiWrite(RH_RF69_REG_08_FRFMID, (frf >> 8) & 0xff);
00308     spiWrite(RH_RF69_REG_09_FRFLSB, frf & 0xff);
00309 
00310     // afcPullInRange is not used
00311     return true;
00312 }
00313 
00314 int8_t RH_RF69::rssiRead()
00315 {
00316     // Force a new value to be measured
00317     // Hmmm, this hangs forever!
00318 #if 0
00319     spiWrite(RH_RF69_REG_23_RSSICONFIG, RH_RF69_RSSICONFIG_RSSISTART);
00320     while (!(spiRead(RH_RF69_REG_23_RSSICONFIG) & RH_RF69_RSSICONFIG_RSSIDONE))
00321     ;
00322 #endif
00323     return -((int8_t)(spiRead(RH_RF69_REG_24_RSSIVALUE) >> 1));
00324 }
00325 
00326 void RH_RF69::setOpMode(uint8_t mode)
00327 {
00328     uint8_t opmode = spiRead(RH_RF69_REG_01_OPMODE);
00329     opmode &= ~RH_RF69_OPMODE_MODE;
00330     opmode |= (mode & RH_RF69_OPMODE_MODE);
00331     spiWrite(RH_RF69_REG_01_OPMODE, opmode);
00332 
00333     // Wait for mode to change.
00334     while (!(spiRead(RH_RF69_REG_27_IRQFLAGS1) & RH_RF69_IRQFLAGS1_MODEREADY))
00335     ;
00336 }
00337 
00338 void RH_RF69::setModeIdle()
00339 {
00340     if (_mode != RHModeIdle)
00341     {
00342     if (_power >= 18)
00343     {
00344         // If high power boost, return power amp to receive mode
00345         spiWrite(RH_RF69_REG_5A_TESTPA1, RH_RF69_TESTPA1_NORMAL);
00346         spiWrite(RH_RF69_REG_5C_TESTPA2, RH_RF69_TESTPA2_NORMAL);
00347     }
00348     setOpMode(_idleMode);
00349     _mode = RHModeIdle;
00350     }
00351 }
00352 
00353 bool RH_RF69::sleep()
00354 {
00355     if (_mode != RHModeSleep)
00356     {
00357     spiWrite(RH_RF69_REG_01_OPMODE, RH_RF69_OPMODE_MODE_SLEEP);
00358     _mode = RHModeSleep;
00359     }
00360     return true;
00361 }
00362 
00363 void RH_RF69::setModeRx()
00364 {
00365     if (_mode != RHModeRx)
00366     {
00367     if (_power >= 18)
00368     {
00369         // If high power boost, return power amp to receive mode
00370         spiWrite(RH_RF69_REG_5A_TESTPA1, RH_RF69_TESTPA1_NORMAL);
00371         spiWrite(RH_RF69_REG_5C_TESTPA2, RH_RF69_TESTPA2_NORMAL);
00372     }
00373     spiWrite(RH_RF69_REG_25_DIOMAPPING1, RH_RF69_DIOMAPPING1_DIO0MAPPING_01); // Set interrupt line 0 PayloadReady
00374     setOpMode(RH_RF69_OPMODE_MODE_RX); // Clears FIFO
00375     _mode = RHModeRx;
00376     }
00377 }
00378 
00379 void RH_RF69::setModeTx()
00380 {
00381     if (_mode != RHModeTx)
00382     {
00383     if (_power >= 18)
00384     {
00385         // Set high power boost mode
00386         // Note that OCP defaults to ON so no need to change that.
00387         spiWrite(RH_RF69_REG_5A_TESTPA1, RH_RF69_TESTPA1_BOOST);
00388         spiWrite(RH_RF69_REG_5C_TESTPA2, RH_RF69_TESTPA2_BOOST);
00389     }
00390     spiWrite(RH_RF69_REG_25_DIOMAPPING1, RH_RF69_DIOMAPPING1_DIO0MAPPING_00); // Set interrupt line 0 PacketSent
00391     setOpMode(RH_RF69_OPMODE_MODE_TX); // Clears FIFO
00392     _mode = RHModeTx;
00393     }
00394 }
00395 
00396 void RH_RF69::setTxPower(int8_t power)
00397 {
00398     _power = power;
00399 
00400     uint8_t palevel;
00401     if (_power < -18)
00402     _power = -18;
00403 
00404     // See http://www.hoperf.com/upload/rfchip/RF69-V1.2.pdf section 3.3.6
00405     // for power formulas
00406     if (_power <= 13)
00407     {
00408     // -18dBm to +13dBm
00409     palevel = RH_RF69_PALEVEL_PA0ON | ((_power + 18) & RH_RF69_PALEVEL_OUTPUTPOWER);
00410     }
00411     else if (_power >= 18)
00412     {
00413     // +18dBm to +20dBm
00414     // Need PA1+PA2
00415     // Also need PA boost settings change when tx is turned on and off, see setModeTx()
00416     palevel = RH_RF69_PALEVEL_PA1ON | RH_RF69_PALEVEL_PA2ON | ((_power + 11) & RH_RF69_PALEVEL_OUTPUTPOWER);
00417     }
00418     else
00419     {
00420     // +14dBm to +17dBm
00421     // Need PA1+PA2
00422     palevel = RH_RF69_PALEVEL_PA1ON | RH_RF69_PALEVEL_PA2ON | ((_power + 14) & RH_RF69_PALEVEL_OUTPUTPOWER);
00423     }
00424     spiWrite(RH_RF69_REG_11_PALEVEL, palevel);
00425 }
00426 
00427 // Sets registers from a canned modem configuration structure
00428 void RH_RF69::setModemRegisters(const ModemConfig* config)
00429 {
00430     spiBurstWrite(RH_RF69_REG_02_DATAMODUL,     &config->reg_02, 5);
00431     spiBurstWrite(RH_RF69_REG_19_RXBW,          &config->reg_19, 2);
00432     spiWrite(RH_RF69_REG_37_PACKETCONFIG1,       config->reg_37);
00433 }
00434 
00435 // Set one of the canned FSK Modem configs
00436 // Returns true if its a valid choice
00437 bool RH_RF69::setModemConfig(ModemConfigChoice index)
00438 {
00439     if (index > (signed int)(sizeof(MODEM_CONFIG_TABLE) / sizeof(ModemConfig)))
00440         return false;
00441 
00442     ModemConfig cfg;
00443     memcpy_P(&cfg, &MODEM_CONFIG_TABLE[index], sizeof(RH_RF69::ModemConfig));
00444     setModemRegisters(&cfg);
00445 
00446     return true;
00447 }
00448 
00449 void RH_RF69::setPreambleLength(uint16_t bytes)
00450 {
00451     spiWrite(RH_RF69_REG_2C_PREAMBLEMSB, bytes >> 8);
00452     spiWrite(RH_RF69_REG_2D_PREAMBLELSB, bytes & 0xff);
00453 }
00454 
00455 void RH_RF69::setSyncWords(const uint8_t* syncWords, uint8_t len)
00456 {
00457     uint8_t syncconfig = spiRead(RH_RF69_REG_2E_SYNCCONFIG);
00458     if (syncWords && len && len <= 4)
00459     {
00460     spiBurstWrite(RH_RF69_REG_2F_SYNCVALUE1, syncWords, len);
00461     syncconfig |= RH_RF69_SYNCCONFIG_SYNCON;
00462     }
00463     else
00464     syncconfig &= ~RH_RF69_SYNCCONFIG_SYNCON;
00465     syncconfig &= ~RH_RF69_SYNCCONFIG_SYNCSIZE;
00466     syncconfig |= (len-1) << 3;
00467     spiWrite(RH_RF69_REG_2E_SYNCCONFIG, syncconfig);
00468 }
00469 
00470 void RH_RF69::setEncryptionKey(uint8_t* key)
00471 {
00472     if (key)
00473     {
00474     spiBurstWrite(RH_RF69_REG_3E_AESKEY1, key, 16);
00475     spiWrite(RH_RF69_REG_3D_PACKETCONFIG2, spiRead(RH_RF69_REG_3D_PACKETCONFIG2) | RH_RF69_PACKETCONFIG2_AESON);
00476     }
00477     else
00478     {
00479     spiWrite(RH_RF69_REG_3D_PACKETCONFIG2, spiRead(RH_RF69_REG_3D_PACKETCONFIG2) & ~RH_RF69_PACKETCONFIG2_AESON);
00480     }
00481 }
00482 
00483 bool RH_RF69::available()
00484 {
00485     if (_mode == RHModeTx)
00486     return false;
00487     setModeRx(); // Make sure we are receiving
00488     return _rxBufValid;
00489 }
00490 
00491 bool RH_RF69::recv(uint8_t* buf, uint8_t* len)
00492 {
00493     if (!available())
00494     return false;
00495 
00496     if (buf && len)
00497     {
00498     ATOMIC_BLOCK_START;
00499     if (*len > _bufLen)
00500         *len = _bufLen;
00501     memcpy(buf, _buf, *len);
00502     ATOMIC_BLOCK_END;
00503     }
00504     _rxBufValid = false; // Got the most recent message
00505 //    printBuffer("recv:", buf, *len);
00506     return true;
00507 }
00508 
00509 bool RH_RF69::send(const uint8_t* data, uint8_t len)
00510 {
00511     if (len > RH_RF69_MAX_MESSAGE_LEN)
00512     return false;
00513 
00514     waitPacketSent(); // Make sure we dont interrupt an outgoing message
00515     setModeIdle(); // Prevent RX while filling the fifo
00516 
00517     ATOMIC_BLOCK_START;
00518     digitalWrite(_slaveSelectPin, LOW);
00519     _spi.transfer(RH_RF69_REG_00_FIFO | RH_RF69_SPI_WRITE_MASK); // Send the start address with the write mask on
00520     _spi.transfer(len + RH_RF69_HEADER_LEN); // Include length of headers
00521     // First the 4 headers
00522     _spi.transfer(_txHeaderTo);
00523     _spi.transfer(_txHeaderFrom);
00524     _spi.transfer(_txHeaderId);
00525     _spi.transfer(_txHeaderFlags);
00526     // Now the payload
00527     while (len--)
00528     _spi.transfer(*data++);
00529     digitalWrite(_slaveSelectPin, HIGH);
00530     ATOMIC_BLOCK_END;
00531 
00532     setModeTx(); // Start the transmitter
00533     return true;
00534 }
00535 
00536 uint8_t RH_RF69::maxMessageLength()
00537 {
00538     return RH_RF69_MAX_MESSAGE_LEN;
00539 }
00540 
00541 bool RH_RF69::printRegister(uint8_t reg)
00542 {  
00543 #ifdef RH_HAVE_SERIAL
00544     Serial.print(reg, HEX);
00545     Serial.print(" ");
00546     Serial.println(spiRead(reg), HEX);
00547 #endif
00548     return true;
00549 }
00550 
00551 bool RH_RF69::printRegisters()
00552 {  
00553     uint8_t i;
00554     for (i = 0; i < 0x50; i++)
00555     printRegister(i);
00556     // Non-contiguous registers
00557     printRegister(RH_RF69_REG_58_TESTLNA);
00558     printRegister(RH_RF69_REG_6F_TESTDAGC);
00559     printRegister(RH_RF69_REG_71_TESTAFC);
00560     
00561     return true;
00562 }