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.
Fork of RadioHead-148 by
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 20:15:57 by
1.7.2
