Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 }
Generated on Tue Jul 12 2022 18:05:55 by
