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