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_RF95.cpp
00001 // RH_RF22.cpp 00002 // 00003 // Copyright (C) 2011 Mike McCauley 00004 // $Id: RH_RF95.cpp,v 1.8 2015/08/12 23:18:51 mikem Exp $ 00005 00006 #include <RH_RF95.h> 00007 00008 // Interrupt vectors for the 3 Arduino interrupt pins 00009 // Each interrupt can be handled by a different instance of RH_RF95, allowing you to have 00010 // 2 or more LORAs per Arduino 00011 RH_RF95* RH_RF95::_deviceForInterrupt[RH_RF95_NUM_INTERRUPTS] = {0, 0, 0}; 00012 uint8_t RH_RF95::_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 PROGMEM static const RH_RF95::ModemConfig MODEM_CONFIG_TABLE[] = 00017 { 00018 // 1d, 1e, 26 00019 { 0x72, 0x74, 0x00}, // Bw125Cr45Sf128 (the chip default) 00020 { 0x92, 0x74, 0x00}, // Bw500Cr45Sf128 00021 { 0x48, 0x94, 0x00}, // Bw31_25Cr48Sf512 00022 { 0x78, 0xc4, 0x00}, // Bw125Cr48Sf4096 00023 00024 }; 00025 00026 RH_RF95::RH_RF95(PINS slaveSelectPin, PINS interruptPin, RHGenericSPI& spi) 00027 : 00028 RHSPIDriver(slaveSelectPin, spi), 00029 _rxBufValid(0), 00030 _interruptPin(interruptPin) 00031 { 00032 _myInterruptIndex = 0xff; // Not allocated yet 00033 } 00034 00035 bool RH_RF95::init() 00036 { 00037 if (!RHSPIDriver::init()) 00038 return false; 00039 00040 #if (RH_PLATFORM != RH_PLATFORM_MBED) 00041 // Determine the interrupt number that corresponds to the interruptPin 00042 int interruptNumber = digitalPinToInterrupt(_interruptPin); 00043 if (interruptNumber == NOT_AN_INTERRUPT) 00044 return false; 00045 #endif 00046 00047 // No way to check the device type :-( 00048 00049 // Set sleep mode, so we can also set LORA mode: 00050 spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_SLEEP | RH_RF95_LONG_RANGE_MODE); 00051 delay(10); // Wait for sleep mode to take over from say, CAD 00052 // Check we are in sleep mode, with LORA set 00053 if (spiRead(RH_RF95_REG_01_OP_MODE) != (RH_RF95_MODE_SLEEP | RH_RF95_LONG_RANGE_MODE)) 00054 { 00055 // Serial.println(spiRead(RH_RF95_REG_01_OP_MODE), HEX); 00056 return false; // No device present? 00057 } 00058 00059 #if (RH_PLATFORM != RH_PLATFORM_MBED) 00060 // Add by Adrien van den Bossche <vandenbo@univ-tlse2.fr> for Teensy 00061 // ARM M4 requires the below. else pin interrupt doesn't work properly. 00062 // On all other platforms, its innocuous, belt and braces 00063 pinMode(_interruptPin, INPUT); 00064 #endif 00065 00066 // Set up interrupt handler 00067 // Since there are a limited number of interrupt glue functions isr*() available, 00068 // we can only support a limited number of devices simultaneously 00069 // ON some devices, notably most Arduinos, the interrupt pin passed in is actuallt the 00070 // interrupt number. You have to figure out the interruptnumber-to-interruptpin mapping 00071 // yourself based on knwledge of what Arduino board you are running on. 00072 if (_myInterruptIndex == 0xff) 00073 { 00074 // First run, no interrupt allocated yet 00075 if (_interruptCount <= RH_RF95_NUM_INTERRUPTS) 00076 _myInterruptIndex = _interruptCount++; 00077 else 00078 return false; // Too many devices, not enough interrupt vectors 00079 } 00080 _deviceForInterrupt[_myInterruptIndex] = this; 00081 00082 #if (RH_PLATFORM == RH_PLATFORM_MBED) 00083 if (_myInterruptIndex == 0) 00084 _interruptPin.rise(&isr0); 00085 else if (_myInterruptIndex == 1) 00086 _interruptPin.rise(&isr1); 00087 else if (_myInterruptIndex == 2) 00088 _interruptPin.rise(&isr2); 00089 else 00090 return false; // Too many devices, not enough interrupt vectors 00091 #else 00092 if (_myInterruptIndex == 0) 00093 attachInterrupt(interruptNumber, isr0, RISING); 00094 else if (_myInterruptIndex == 1) 00095 attachInterrupt(interruptNumber, isr1, RISING); 00096 else if (_myInterruptIndex == 2) 00097 attachInterrupt(interruptNumber, isr2, RISING); 00098 else 00099 return false; // Too many devices, not enough interrupt vectors 00100 #endif 00101 // Set up FIFO 00102 // We configure so that we can use the entire 256 byte FIFO for either receive 00103 // or transmit, but not both at the same time 00104 spiWrite(RH_RF95_REG_0E_FIFO_TX_BASE_ADDR, 0); 00105 spiWrite(RH_RF95_REG_0F_FIFO_RX_BASE_ADDR, 0); 00106 00107 // Packet format is preamble + explicit-header + payload + crc 00108 // Explicit Header Mode 00109 // payload is TO + FROM + ID + FLAGS + message data 00110 // RX mode is implmented with RXCONTINUOUS 00111 // max message data length is 255 - 4 = 251 octets 00112 00113 setModeIdle(); 00114 00115 // Set up default configuration 00116 // No Sync Words in LORA mode. 00117 setModemConfig(Bw125Cr45Sf128); // Radio default 00118 // setModemConfig(Bw125Cr48Sf4096); // slow and reliable? 00119 setPreambleLength(8); // Default is 8 00120 // An innocuous ISM frequency, same as RF22's 00121 setFrequency(434.0); 00122 // Lowish power 00123 setTxPower(13); 00124 00125 return true; 00126 } 00127 00128 // C++ level interrupt handler for this instance 00129 // LORA is unusual in that it has several interrupt lines, and not a single, combined one. 00130 // On MiniWirelessLoRa, only one of the several interrupt lines (DI0) from the RFM95 is usefuly 00131 // connnected to the processor. 00132 // We use this to get RxDone and TxDone interrupts 00133 void RH_RF95::handleInterrupt() 00134 { 00135 // Read the interrupt register 00136 uint8_t irq_flags = spiRead(RH_RF95_REG_12_IRQ_FLAGS); 00137 if (_mode == RHModeRx && irq_flags & (RH_RF95_RX_TIMEOUT | RH_RF95_PAYLOAD_CRC_ERROR)) 00138 { 00139 _rxBad++; 00140 } 00141 else if (_mode == RHModeRx && irq_flags & RH_RF95_RX_DONE) 00142 { 00143 // Have received a packet 00144 uint8_t len = spiRead(RH_RF95_REG_13_RX_NB_BYTES); 00145 00146 // Reset the fifo read ptr to the beginning of the packet 00147 spiWrite(RH_RF95_REG_0D_FIFO_ADDR_PTR, spiRead(RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR)); 00148 spiBurstRead(RH_RF95_REG_00_FIFO, _buf, len); 00149 _bufLen = len; 00150 spiWrite(RH_RF95_REG_12_IRQ_FLAGS, 0xff); // Clear all IRQ flags 00151 00152 // Remember the RSSI of this packet 00153 // this is according to the doc, but is it really correct? 00154 // weakest receiveable signals are reported RSSI at about -66 00155 _lastRssi = spiRead(RH_RF95_REG_1A_PKT_RSSI_VALUE) - 137; 00156 00157 // We have received a message. 00158 validateRxBuf(); 00159 if (_rxBufValid) 00160 setModeIdle(); // Got one 00161 } 00162 else if (_mode == RHModeTx && irq_flags & RH_RF95_TX_DONE) 00163 { 00164 _txGood++; 00165 setModeIdle(); 00166 } 00167 00168 spiWrite(RH_RF95_REG_12_IRQ_FLAGS, 0xff); // Clear all IRQ flags 00169 } 00170 00171 // These are low level functions that call the interrupt handler for the correct 00172 // instance of RH_RF95. 00173 // 3 interrupts allows us to have 3 different devices 00174 void RH_RF95::isr0() 00175 { 00176 if (_deviceForInterrupt[0]) 00177 _deviceForInterrupt[0]->handleInterrupt(); 00178 } 00179 void RH_RF95::isr1() 00180 { 00181 if (_deviceForInterrupt[1]) 00182 _deviceForInterrupt[1]->handleInterrupt(); 00183 } 00184 void RH_RF95::isr2() 00185 { 00186 if (_deviceForInterrupt[2]) 00187 _deviceForInterrupt[2]->handleInterrupt(); 00188 } 00189 00190 // Check whether the latest received message is complete and uncorrupted 00191 void RH_RF95::validateRxBuf() 00192 { 00193 if (_bufLen < 4) 00194 return; // Too short to be a real message 00195 // Extract the 4 headers 00196 _rxHeaderTo = _buf[0]; 00197 _rxHeaderFrom = _buf[1]; 00198 _rxHeaderId = _buf[2]; 00199 _rxHeaderFlags = _buf[3]; 00200 if (_promiscuous || 00201 _rxHeaderTo == _thisAddress || 00202 _rxHeaderTo == RH_BROADCAST_ADDRESS) 00203 { 00204 _rxGood++; 00205 _rxBufValid = true; 00206 } 00207 } 00208 00209 bool RH_RF95::available() 00210 { 00211 if (_mode == RHModeTx) 00212 return false; 00213 setModeRx(); 00214 return _rxBufValid; // Will be set by the interrupt handler when a good message is received 00215 } 00216 00217 void RH_RF95::clearRxBuf() 00218 { 00219 ATOMIC_BLOCK_START; 00220 _rxBufValid = false; 00221 _bufLen = 0; 00222 ATOMIC_BLOCK_END; 00223 } 00224 00225 bool RH_RF95::recv(uint8_t* buf, uint8_t* len) 00226 { 00227 if (!available()) 00228 return false; 00229 if (buf && len) 00230 { 00231 ATOMIC_BLOCK_START; 00232 // Skip the 4 headers that are at the beginning of the rxBuf 00233 if (*len > _bufLen-RH_RF95_HEADER_LEN) 00234 *len = _bufLen-RH_RF95_HEADER_LEN; 00235 memcpy(buf, _buf+RH_RF95_HEADER_LEN, *len); 00236 ATOMIC_BLOCK_END; 00237 } 00238 clearRxBuf(); // This message accepted and cleared 00239 return true; 00240 } 00241 00242 bool RH_RF95::send(const uint8_t* data, uint8_t len) 00243 { 00244 if (len > RH_RF95_MAX_MESSAGE_LEN) 00245 return false; 00246 00247 waitPacketSent(); // Make sure we dont interrupt an outgoing message 00248 setModeIdle(); 00249 00250 // Position at the beginning of the FIFO 00251 spiWrite(RH_RF95_REG_0D_FIFO_ADDR_PTR, 0); 00252 // The headers 00253 spiWrite(RH_RF95_REG_00_FIFO, _txHeaderTo); 00254 spiWrite(RH_RF95_REG_00_FIFO, _txHeaderFrom); 00255 spiWrite(RH_RF95_REG_00_FIFO, _txHeaderId); 00256 spiWrite(RH_RF95_REG_00_FIFO, _txHeaderFlags); 00257 // The message data 00258 spiBurstWrite(RH_RF95_REG_00_FIFO, data, len); 00259 spiWrite(RH_RF95_REG_22_PAYLOAD_LENGTH, len + RH_RF95_HEADER_LEN); 00260 00261 setModeTx(); // Start the transmitter 00262 // when Tx is done, interruptHandler will fire and radio mode will return to STANDBY 00263 return true; 00264 } 00265 00266 bool RH_RF95::printRegisters() 00267 { 00268 #ifdef RH_HAVE_SERIAL 00269 uint8_t registers[] = { 0x01, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x014, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27}; 00270 00271 uint8_t i; 00272 for (i = 0; i < sizeof(registers); i++) 00273 { 00274 Serial.print(registers[i], HEX); 00275 Serial.print(": "); 00276 Serial.println(spiRead(registers[i]), HEX); 00277 } 00278 #endif 00279 return true; 00280 } 00281 00282 uint8_t RH_RF95::maxMessageLength() 00283 { 00284 return RH_RF95_MAX_MESSAGE_LEN; 00285 } 00286 00287 bool RH_RF95::setFrequency(float centre) 00288 { 00289 // Frf = FRF / FSTEP 00290 uint32_t frf = (centre * 1000000.0) / RH_RF95_FSTEP; 00291 spiWrite(RH_RF95_REG_06_FRF_MSB, (frf >> 16) & 0xff); 00292 spiWrite(RH_RF95_REG_07_FRF_MID, (frf >> 8) & 0xff); 00293 spiWrite(RH_RF95_REG_08_FRF_LSB, frf & 0xff); 00294 00295 return true; 00296 } 00297 00298 void RH_RF95::setModeIdle() 00299 { 00300 if (_mode != RHModeIdle) 00301 { 00302 spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_STDBY); 00303 _mode = RHModeIdle; 00304 } 00305 } 00306 00307 bool RH_RF95::sleep() 00308 { 00309 if (_mode != RHModeSleep) 00310 { 00311 spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_SLEEP); 00312 _mode = RHModeSleep; 00313 } 00314 return true; 00315 } 00316 00317 void RH_RF95::setModeRx() 00318 { 00319 if (_mode != RHModeRx) 00320 { 00321 spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_RXCONTINUOUS); 00322 spiWrite(RH_RF95_REG_40_DIO_MAPPING1, 0x00); // Interrupt on RxDone 00323 _mode = RHModeRx; 00324 } 00325 } 00326 00327 void RH_RF95::setModeTx() 00328 { 00329 if (_mode != RHModeTx) 00330 { 00331 spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_TX); 00332 spiWrite(RH_RF95_REG_40_DIO_MAPPING1, 0x40); // Interrupt on TxDone 00333 _mode = RHModeTx; 00334 } 00335 } 00336 00337 void RH_RF95::setTxPower(int8_t power) 00338 { 00339 if (power > 23) 00340 power = 23; 00341 if (power < 5) 00342 power = 5; 00343 00344 // For RH_RF95_PA_DAC_ENABLE, manual says '+20dBm on PA_BOOST when OutputPower=0xf' 00345 // RH_RF95_PA_DAC_ENABLE actually adds about 3dBm to all power levels. We will us it 00346 // for 21, 22 and 23dBm 00347 if (power > 20) 00348 { 00349 spiWrite(RH_RF95_REG_4D_PA_DAC, RH_RF95_PA_DAC_ENABLE); 00350 power -= 3; 00351 } 00352 else 00353 { 00354 spiWrite(RH_RF95_REG_4D_PA_DAC, RH_RF95_PA_DAC_DISABLE); 00355 } 00356 00357 // RFM95/96/97/98 does not have RFO pins connected to anything. Only PA_BOOST 00358 // pin is connected, so must use PA_BOOST 00359 // Pout = 2 + OutputPower. 00360 // The documentation is pretty confusing on this topic: PaSelect says the max power is 20dBm, 00361 // but OutputPower claims it would be 17dBm. 00362 // My measurements show 20dBm is correct 00363 spiWrite(RH_RF95_REG_09_PA_CONFIG, RH_RF95_PA_SELECT | (power-5)); 00364 } 00365 00366 // Sets registers from a canned modem configuration structure 00367 void RH_RF95::setModemRegisters(const ModemConfig* config) 00368 { 00369 spiWrite(RH_RF95_REG_1D_MODEM_CONFIG1, config->reg_1d); 00370 spiWrite(RH_RF95_REG_1E_MODEM_CONFIG2, config->reg_1e); 00371 spiWrite(RH_RF95_REG_26_MODEM_CONFIG3, config->reg_26); 00372 } 00373 00374 // Set one of the canned FSK Modem configs 00375 // Returns true if its a valid choice 00376 bool RH_RF95::setModemConfig(ModemConfigChoice index) 00377 { 00378 if (index > (signed int)(sizeof(MODEM_CONFIG_TABLE) / sizeof(ModemConfig))) 00379 return false; 00380 00381 ModemConfig cfg; 00382 memcpy_P(&cfg, &MODEM_CONFIG_TABLE[index], sizeof(RH_RF95::ModemConfig)); 00383 setModemRegisters(&cfg); 00384 00385 return true; 00386 } 00387 00388 void RH_RF95::setPreambleLength(uint16_t bytes) 00389 { 00390 spiWrite(RH_RF95_REG_20_PREAMBLE_MSB, bytes >> 8); 00391 spiWrite(RH_RF95_REG_21_PREAMBLE_LSB, bytes & 0xff); 00392 } 00393
Generated on Tue Jul 12 2022 18:05:56 by
1.7.2