Point Labs / RadioHeadLite

Dependents:   Threaded_LoRa_Modem

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers RH_RF95.cpp Source File

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