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_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 20:15:57 by
1.7.2
