This driver is a stripped down version of the Radiohead 1.45 driver, and covers fewer radios. Threading and an event queue have been added to make the ISR's more stable across architectures. Specifically The STM32L4 parts

Dependents:   Threaded_LoRa_Modem

Committer:
davidr99
Date:
Thu Oct 15 01:27:00 2015 +0000
Revision:
0:ab4e012489ef
Child:
1:dfeb5e8b199a
Messy start, but a port for RadioHead.; Currently the SPI modulus are the only ones that work.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
davidr99 0:ab4e012489ef 1 // RH_RF22.cpp
davidr99 0:ab4e012489ef 2 //
davidr99 0:ab4e012489ef 3 // Copyright (C) 2011 Mike McCauley
davidr99 0:ab4e012489ef 4 // $Id: RH_RF95.cpp,v 1.8 2015/08/12 23:18:51 mikem Exp $
davidr99 0:ab4e012489ef 5
davidr99 0:ab4e012489ef 6 #include <RH_RF95.h>
davidr99 0:ab4e012489ef 7
davidr99 0:ab4e012489ef 8 // Interrupt vectors for the 3 Arduino interrupt pins
davidr99 0:ab4e012489ef 9 // Each interrupt can be handled by a different instance of RH_RF95, allowing you to have
davidr99 0:ab4e012489ef 10 // 2 or more LORAs per Arduino
davidr99 0:ab4e012489ef 11 RH_RF95* RH_RF95::_deviceForInterrupt[RH_RF95_NUM_INTERRUPTS] = {0, 0, 0};
davidr99 0:ab4e012489ef 12 uint8_t RH_RF95::_interruptCount = 0; // Index into _deviceForInterrupt for next device
davidr99 0:ab4e012489ef 13
davidr99 0:ab4e012489ef 14 // These are indexed by the values of ModemConfigChoice
davidr99 0:ab4e012489ef 15 // Stored in flash (program) memory to save SRAM
davidr99 0:ab4e012489ef 16 PROGMEM static const RH_RF95::ModemConfig MODEM_CONFIG_TABLE[] =
davidr99 0:ab4e012489ef 17 {
davidr99 0:ab4e012489ef 18 // 1d, 1e, 26
davidr99 0:ab4e012489ef 19 { 0x72, 0x74, 0x00}, // Bw125Cr45Sf128 (the chip default)
davidr99 0:ab4e012489ef 20 { 0x92, 0x74, 0x00}, // Bw500Cr45Sf128
davidr99 0:ab4e012489ef 21 { 0x48, 0x94, 0x00}, // Bw31_25Cr48Sf512
davidr99 0:ab4e012489ef 22 { 0x78, 0xc4, 0x00}, // Bw125Cr48Sf4096
davidr99 0:ab4e012489ef 23
davidr99 0:ab4e012489ef 24 };
davidr99 0:ab4e012489ef 25
davidr99 0:ab4e012489ef 26 RH_RF95::RH_RF95(PINS slaveSelectPin, PINS interruptPin, RHGenericSPI& spi)
davidr99 0:ab4e012489ef 27 :
davidr99 0:ab4e012489ef 28 RHSPIDriver(slaveSelectPin, spi),
davidr99 0:ab4e012489ef 29 _rxBufValid(0),
davidr99 0:ab4e012489ef 30 _interruptPin(interruptPin)
davidr99 0:ab4e012489ef 31 {
davidr99 0:ab4e012489ef 32 _myInterruptIndex = 0xff; // Not allocated yet
davidr99 0:ab4e012489ef 33 }
davidr99 0:ab4e012489ef 34
davidr99 0:ab4e012489ef 35 bool RH_RF95::init()
davidr99 0:ab4e012489ef 36 {
davidr99 0:ab4e012489ef 37 if (!RHSPIDriver::init())
davidr99 0:ab4e012489ef 38 return false;
davidr99 0:ab4e012489ef 39
davidr99 0:ab4e012489ef 40 #if (RH_PLATFORM != RH_PLATFORM_MBED)
davidr99 0:ab4e012489ef 41 // Determine the interrupt number that corresponds to the interruptPin
davidr99 0:ab4e012489ef 42 int interruptNumber = digitalPinToInterrupt(_interruptPin);
davidr99 0:ab4e012489ef 43 if (interruptNumber == NOT_AN_INTERRUPT)
davidr99 0:ab4e012489ef 44 return false;
davidr99 0:ab4e012489ef 45 #endif
davidr99 0:ab4e012489ef 46
davidr99 0:ab4e012489ef 47 // No way to check the device type :-(
davidr99 0:ab4e012489ef 48
davidr99 0:ab4e012489ef 49 // Set sleep mode, so we can also set LORA mode:
davidr99 0:ab4e012489ef 50 spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_SLEEP | RH_RF95_LONG_RANGE_MODE);
davidr99 0:ab4e012489ef 51 delay(10); // Wait for sleep mode to take over from say, CAD
davidr99 0:ab4e012489ef 52 // Check we are in sleep mode, with LORA set
davidr99 0:ab4e012489ef 53 if (spiRead(RH_RF95_REG_01_OP_MODE) != (RH_RF95_MODE_SLEEP | RH_RF95_LONG_RANGE_MODE))
davidr99 0:ab4e012489ef 54 {
davidr99 0:ab4e012489ef 55 // Serial.println(spiRead(RH_RF95_REG_01_OP_MODE), HEX);
davidr99 0:ab4e012489ef 56 return false; // No device present?
davidr99 0:ab4e012489ef 57 }
davidr99 0:ab4e012489ef 58
davidr99 0:ab4e012489ef 59 #if (RH_PLATFORM != RH_PLATFORM_MBED)
davidr99 0:ab4e012489ef 60 // Add by Adrien van den Bossche <vandenbo@univ-tlse2.fr> for Teensy
davidr99 0:ab4e012489ef 61 // ARM M4 requires the below. else pin interrupt doesn't work properly.
davidr99 0:ab4e012489ef 62 // On all other platforms, its innocuous, belt and braces
davidr99 0:ab4e012489ef 63 pinMode(_interruptPin, INPUT);
davidr99 0:ab4e012489ef 64 #endif
davidr99 0:ab4e012489ef 65
davidr99 0:ab4e012489ef 66 // Set up interrupt handler
davidr99 0:ab4e012489ef 67 // Since there are a limited number of interrupt glue functions isr*() available,
davidr99 0:ab4e012489ef 68 // we can only support a limited number of devices simultaneously
davidr99 0:ab4e012489ef 69 // ON some devices, notably most Arduinos, the interrupt pin passed in is actuallt the
davidr99 0:ab4e012489ef 70 // interrupt number. You have to figure out the interruptnumber-to-interruptpin mapping
davidr99 0:ab4e012489ef 71 // yourself based on knwledge of what Arduino board you are running on.
davidr99 0:ab4e012489ef 72 if (_myInterruptIndex == 0xff)
davidr99 0:ab4e012489ef 73 {
davidr99 0:ab4e012489ef 74 // First run, no interrupt allocated yet
davidr99 0:ab4e012489ef 75 if (_interruptCount <= RH_RF95_NUM_INTERRUPTS)
davidr99 0:ab4e012489ef 76 _myInterruptIndex = _interruptCount++;
davidr99 0:ab4e012489ef 77 else
davidr99 0:ab4e012489ef 78 return false; // Too many devices, not enough interrupt vectors
davidr99 0:ab4e012489ef 79 }
davidr99 0:ab4e012489ef 80 _deviceForInterrupt[_myInterruptIndex] = this;
davidr99 0:ab4e012489ef 81
davidr99 0:ab4e012489ef 82 #if (RH_PLATFORM == RH_PLATFORM_MBED)
davidr99 0:ab4e012489ef 83 if (_myInterruptIndex == 0)
davidr99 0:ab4e012489ef 84 _interruptPin.rise(&isr0);
davidr99 0:ab4e012489ef 85 else if (_myInterruptIndex == 1)
davidr99 0:ab4e012489ef 86 _interruptPin.rise(&isr1);
davidr99 0:ab4e012489ef 87 else if (_myInterruptIndex == 2)
davidr99 0:ab4e012489ef 88 _interruptPin.rise(&isr2);
davidr99 0:ab4e012489ef 89 else
davidr99 0:ab4e012489ef 90 return false; // Too many devices, not enough interrupt vectors
davidr99 0:ab4e012489ef 91 #else
davidr99 0:ab4e012489ef 92 if (_myInterruptIndex == 0)
davidr99 0:ab4e012489ef 93 attachInterrupt(interruptNumber, isr0, RISING);
davidr99 0:ab4e012489ef 94 else if (_myInterruptIndex == 1)
davidr99 0:ab4e012489ef 95 attachInterrupt(interruptNumber, isr1, RISING);
davidr99 0:ab4e012489ef 96 else if (_myInterruptIndex == 2)
davidr99 0:ab4e012489ef 97 attachInterrupt(interruptNumber, isr2, RISING);
davidr99 0:ab4e012489ef 98 else
davidr99 0:ab4e012489ef 99 return false; // Too many devices, not enough interrupt vectors
davidr99 0:ab4e012489ef 100 #endif
davidr99 0:ab4e012489ef 101 // Set up FIFO
davidr99 0:ab4e012489ef 102 // We configure so that we can use the entire 256 byte FIFO for either receive
davidr99 0:ab4e012489ef 103 // or transmit, but not both at the same time
davidr99 0:ab4e012489ef 104 spiWrite(RH_RF95_REG_0E_FIFO_TX_BASE_ADDR, 0);
davidr99 0:ab4e012489ef 105 spiWrite(RH_RF95_REG_0F_FIFO_RX_BASE_ADDR, 0);
davidr99 0:ab4e012489ef 106
davidr99 0:ab4e012489ef 107 // Packet format is preamble + explicit-header + payload + crc
davidr99 0:ab4e012489ef 108 // Explicit Header Mode
davidr99 0:ab4e012489ef 109 // payload is TO + FROM + ID + FLAGS + message data
davidr99 0:ab4e012489ef 110 // RX mode is implmented with RXCONTINUOUS
davidr99 0:ab4e012489ef 111 // max message data length is 255 - 4 = 251 octets
davidr99 0:ab4e012489ef 112
davidr99 0:ab4e012489ef 113 setModeIdle();
davidr99 0:ab4e012489ef 114
davidr99 0:ab4e012489ef 115 // Set up default configuration
davidr99 0:ab4e012489ef 116 // No Sync Words in LORA mode.
davidr99 0:ab4e012489ef 117 setModemConfig(Bw125Cr45Sf128); // Radio default
davidr99 0:ab4e012489ef 118 // setModemConfig(Bw125Cr48Sf4096); // slow and reliable?
davidr99 0:ab4e012489ef 119 setPreambleLength(8); // Default is 8
davidr99 0:ab4e012489ef 120 // An innocuous ISM frequency, same as RF22's
davidr99 0:ab4e012489ef 121 setFrequency(434.0);
davidr99 0:ab4e012489ef 122 // Lowish power
davidr99 0:ab4e012489ef 123 setTxPower(13);
davidr99 0:ab4e012489ef 124
davidr99 0:ab4e012489ef 125 return true;
davidr99 0:ab4e012489ef 126 }
davidr99 0:ab4e012489ef 127
davidr99 0:ab4e012489ef 128 // C++ level interrupt handler for this instance
davidr99 0:ab4e012489ef 129 // LORA is unusual in that it has several interrupt lines, and not a single, combined one.
davidr99 0:ab4e012489ef 130 // On MiniWirelessLoRa, only one of the several interrupt lines (DI0) from the RFM95 is usefuly
davidr99 0:ab4e012489ef 131 // connnected to the processor.
davidr99 0:ab4e012489ef 132 // We use this to get RxDone and TxDone interrupts
davidr99 0:ab4e012489ef 133 void RH_RF95::handleInterrupt()
davidr99 0:ab4e012489ef 134 {
davidr99 0:ab4e012489ef 135 // Read the interrupt register
davidr99 0:ab4e012489ef 136 uint8_t irq_flags = spiRead(RH_RF95_REG_12_IRQ_FLAGS);
davidr99 0:ab4e012489ef 137 if (_mode == RHModeRx && irq_flags & (RH_RF95_RX_TIMEOUT | RH_RF95_PAYLOAD_CRC_ERROR))
davidr99 0:ab4e012489ef 138 {
davidr99 0:ab4e012489ef 139 _rxBad++;
davidr99 0:ab4e012489ef 140 }
davidr99 0:ab4e012489ef 141 else if (_mode == RHModeRx && irq_flags & RH_RF95_RX_DONE)
davidr99 0:ab4e012489ef 142 {
davidr99 0:ab4e012489ef 143 // Have received a packet
davidr99 0:ab4e012489ef 144 uint8_t len = spiRead(RH_RF95_REG_13_RX_NB_BYTES);
davidr99 0:ab4e012489ef 145
davidr99 0:ab4e012489ef 146 // Reset the fifo read ptr to the beginning of the packet
davidr99 0:ab4e012489ef 147 spiWrite(RH_RF95_REG_0D_FIFO_ADDR_PTR, spiRead(RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR));
davidr99 0:ab4e012489ef 148 spiBurstRead(RH_RF95_REG_00_FIFO, _buf, len);
davidr99 0:ab4e012489ef 149 _bufLen = len;
davidr99 0:ab4e012489ef 150 spiWrite(RH_RF95_REG_12_IRQ_FLAGS, 0xff); // Clear all IRQ flags
davidr99 0:ab4e012489ef 151
davidr99 0:ab4e012489ef 152 // Remember the RSSI of this packet
davidr99 0:ab4e012489ef 153 // this is according to the doc, but is it really correct?
davidr99 0:ab4e012489ef 154 // weakest receiveable signals are reported RSSI at about -66
davidr99 0:ab4e012489ef 155 _lastRssi = spiRead(RH_RF95_REG_1A_PKT_RSSI_VALUE) - 137;
davidr99 0:ab4e012489ef 156
davidr99 0:ab4e012489ef 157 // We have received a message.
davidr99 0:ab4e012489ef 158 validateRxBuf();
davidr99 0:ab4e012489ef 159 if (_rxBufValid)
davidr99 0:ab4e012489ef 160 setModeIdle(); // Got one
davidr99 0:ab4e012489ef 161 }
davidr99 0:ab4e012489ef 162 else if (_mode == RHModeTx && irq_flags & RH_RF95_TX_DONE)
davidr99 0:ab4e012489ef 163 {
davidr99 0:ab4e012489ef 164 _txGood++;
davidr99 0:ab4e012489ef 165 setModeIdle();
davidr99 0:ab4e012489ef 166 }
davidr99 0:ab4e012489ef 167
davidr99 0:ab4e012489ef 168 spiWrite(RH_RF95_REG_12_IRQ_FLAGS, 0xff); // Clear all IRQ flags
davidr99 0:ab4e012489ef 169 }
davidr99 0:ab4e012489ef 170
davidr99 0:ab4e012489ef 171 // These are low level functions that call the interrupt handler for the correct
davidr99 0:ab4e012489ef 172 // instance of RH_RF95.
davidr99 0:ab4e012489ef 173 // 3 interrupts allows us to have 3 different devices
davidr99 0:ab4e012489ef 174 void RH_RF95::isr0()
davidr99 0:ab4e012489ef 175 {
davidr99 0:ab4e012489ef 176 if (_deviceForInterrupt[0])
davidr99 0:ab4e012489ef 177 _deviceForInterrupt[0]->handleInterrupt();
davidr99 0:ab4e012489ef 178 }
davidr99 0:ab4e012489ef 179 void RH_RF95::isr1()
davidr99 0:ab4e012489ef 180 {
davidr99 0:ab4e012489ef 181 if (_deviceForInterrupt[1])
davidr99 0:ab4e012489ef 182 _deviceForInterrupt[1]->handleInterrupt();
davidr99 0:ab4e012489ef 183 }
davidr99 0:ab4e012489ef 184 void RH_RF95::isr2()
davidr99 0:ab4e012489ef 185 {
davidr99 0:ab4e012489ef 186 if (_deviceForInterrupt[2])
davidr99 0:ab4e012489ef 187 _deviceForInterrupt[2]->handleInterrupt();
davidr99 0:ab4e012489ef 188 }
davidr99 0:ab4e012489ef 189
davidr99 0:ab4e012489ef 190 // Check whether the latest received message is complete and uncorrupted
davidr99 0:ab4e012489ef 191 void RH_RF95::validateRxBuf()
davidr99 0:ab4e012489ef 192 {
davidr99 0:ab4e012489ef 193 if (_bufLen < 4)
davidr99 0:ab4e012489ef 194 return; // Too short to be a real message
davidr99 0:ab4e012489ef 195 // Extract the 4 headers
davidr99 0:ab4e012489ef 196 _rxHeaderTo = _buf[0];
davidr99 0:ab4e012489ef 197 _rxHeaderFrom = _buf[1];
davidr99 0:ab4e012489ef 198 _rxHeaderId = _buf[2];
davidr99 0:ab4e012489ef 199 _rxHeaderFlags = _buf[3];
davidr99 0:ab4e012489ef 200 if (_promiscuous ||
davidr99 0:ab4e012489ef 201 _rxHeaderTo == _thisAddress ||
davidr99 0:ab4e012489ef 202 _rxHeaderTo == RH_BROADCAST_ADDRESS)
davidr99 0:ab4e012489ef 203 {
davidr99 0:ab4e012489ef 204 _rxGood++;
davidr99 0:ab4e012489ef 205 _rxBufValid = true;
davidr99 0:ab4e012489ef 206 }
davidr99 0:ab4e012489ef 207 }
davidr99 0:ab4e012489ef 208
davidr99 0:ab4e012489ef 209 bool RH_RF95::available()
davidr99 0:ab4e012489ef 210 {
davidr99 0:ab4e012489ef 211 if (_mode == RHModeTx)
davidr99 0:ab4e012489ef 212 return false;
davidr99 0:ab4e012489ef 213 setModeRx();
davidr99 0:ab4e012489ef 214 return _rxBufValid; // Will be set by the interrupt handler when a good message is received
davidr99 0:ab4e012489ef 215 }
davidr99 0:ab4e012489ef 216
davidr99 0:ab4e012489ef 217 void RH_RF95::clearRxBuf()
davidr99 0:ab4e012489ef 218 {
davidr99 0:ab4e012489ef 219 ATOMIC_BLOCK_START;
davidr99 0:ab4e012489ef 220 _rxBufValid = false;
davidr99 0:ab4e012489ef 221 _bufLen = 0;
davidr99 0:ab4e012489ef 222 ATOMIC_BLOCK_END;
davidr99 0:ab4e012489ef 223 }
davidr99 0:ab4e012489ef 224
davidr99 0:ab4e012489ef 225 bool RH_RF95::recv(uint8_t* buf, uint8_t* len)
davidr99 0:ab4e012489ef 226 {
davidr99 0:ab4e012489ef 227 if (!available())
davidr99 0:ab4e012489ef 228 return false;
davidr99 0:ab4e012489ef 229 if (buf && len)
davidr99 0:ab4e012489ef 230 {
davidr99 0:ab4e012489ef 231 ATOMIC_BLOCK_START;
davidr99 0:ab4e012489ef 232 // Skip the 4 headers that are at the beginning of the rxBuf
davidr99 0:ab4e012489ef 233 if (*len > _bufLen-RH_RF95_HEADER_LEN)
davidr99 0:ab4e012489ef 234 *len = _bufLen-RH_RF95_HEADER_LEN;
davidr99 0:ab4e012489ef 235 memcpy(buf, _buf+RH_RF95_HEADER_LEN, *len);
davidr99 0:ab4e012489ef 236 ATOMIC_BLOCK_END;
davidr99 0:ab4e012489ef 237 }
davidr99 0:ab4e012489ef 238 clearRxBuf(); // This message accepted and cleared
davidr99 0:ab4e012489ef 239 return true;
davidr99 0:ab4e012489ef 240 }
davidr99 0:ab4e012489ef 241
davidr99 0:ab4e012489ef 242 bool RH_RF95::send(const uint8_t* data, uint8_t len)
davidr99 0:ab4e012489ef 243 {
davidr99 0:ab4e012489ef 244 if (len > RH_RF95_MAX_MESSAGE_LEN)
davidr99 0:ab4e012489ef 245 return false;
davidr99 0:ab4e012489ef 246
davidr99 0:ab4e012489ef 247 waitPacketSent(); // Make sure we dont interrupt an outgoing message
davidr99 0:ab4e012489ef 248 setModeIdle();
davidr99 0:ab4e012489ef 249
davidr99 0:ab4e012489ef 250 // Position at the beginning of the FIFO
davidr99 0:ab4e012489ef 251 spiWrite(RH_RF95_REG_0D_FIFO_ADDR_PTR, 0);
davidr99 0:ab4e012489ef 252 // The headers
davidr99 0:ab4e012489ef 253 spiWrite(RH_RF95_REG_00_FIFO, _txHeaderTo);
davidr99 0:ab4e012489ef 254 spiWrite(RH_RF95_REG_00_FIFO, _txHeaderFrom);
davidr99 0:ab4e012489ef 255 spiWrite(RH_RF95_REG_00_FIFO, _txHeaderId);
davidr99 0:ab4e012489ef 256 spiWrite(RH_RF95_REG_00_FIFO, _txHeaderFlags);
davidr99 0:ab4e012489ef 257 // The message data
davidr99 0:ab4e012489ef 258 spiBurstWrite(RH_RF95_REG_00_FIFO, data, len);
davidr99 0:ab4e012489ef 259 spiWrite(RH_RF95_REG_22_PAYLOAD_LENGTH, len + RH_RF95_HEADER_LEN);
davidr99 0:ab4e012489ef 260
davidr99 0:ab4e012489ef 261 setModeTx(); // Start the transmitter
davidr99 0:ab4e012489ef 262 // when Tx is done, interruptHandler will fire and radio mode will return to STANDBY
davidr99 0:ab4e012489ef 263 return true;
davidr99 0:ab4e012489ef 264 }
davidr99 0:ab4e012489ef 265
davidr99 0:ab4e012489ef 266 bool RH_RF95::printRegisters()
davidr99 0:ab4e012489ef 267 {
davidr99 0:ab4e012489ef 268 #ifdef RH_HAVE_SERIAL
davidr99 0:ab4e012489ef 269 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};
davidr99 0:ab4e012489ef 270
davidr99 0:ab4e012489ef 271 uint8_t i;
davidr99 0:ab4e012489ef 272 for (i = 0; i < sizeof(registers); i++)
davidr99 0:ab4e012489ef 273 {
davidr99 0:ab4e012489ef 274 Serial.print(registers[i], HEX);
davidr99 0:ab4e012489ef 275 Serial.print(": ");
davidr99 0:ab4e012489ef 276 Serial.println(spiRead(registers[i]), HEX);
davidr99 0:ab4e012489ef 277 }
davidr99 0:ab4e012489ef 278 #endif
davidr99 0:ab4e012489ef 279 return true;
davidr99 0:ab4e012489ef 280 }
davidr99 0:ab4e012489ef 281
davidr99 0:ab4e012489ef 282 uint8_t RH_RF95::maxMessageLength()
davidr99 0:ab4e012489ef 283 {
davidr99 0:ab4e012489ef 284 return RH_RF95_MAX_MESSAGE_LEN;
davidr99 0:ab4e012489ef 285 }
davidr99 0:ab4e012489ef 286
davidr99 0:ab4e012489ef 287 bool RH_RF95::setFrequency(float centre)
davidr99 0:ab4e012489ef 288 {
davidr99 0:ab4e012489ef 289 // Frf = FRF / FSTEP
davidr99 0:ab4e012489ef 290 uint32_t frf = (centre * 1000000.0) / RH_RF95_FSTEP;
davidr99 0:ab4e012489ef 291 spiWrite(RH_RF95_REG_06_FRF_MSB, (frf >> 16) & 0xff);
davidr99 0:ab4e012489ef 292 spiWrite(RH_RF95_REG_07_FRF_MID, (frf >> 8) & 0xff);
davidr99 0:ab4e012489ef 293 spiWrite(RH_RF95_REG_08_FRF_LSB, frf & 0xff);
davidr99 0:ab4e012489ef 294
davidr99 0:ab4e012489ef 295 return true;
davidr99 0:ab4e012489ef 296 }
davidr99 0:ab4e012489ef 297
davidr99 0:ab4e012489ef 298 void RH_RF95::setModeIdle()
davidr99 0:ab4e012489ef 299 {
davidr99 0:ab4e012489ef 300 if (_mode != RHModeIdle)
davidr99 0:ab4e012489ef 301 {
davidr99 0:ab4e012489ef 302 spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_STDBY);
davidr99 0:ab4e012489ef 303 _mode = RHModeIdle;
davidr99 0:ab4e012489ef 304 }
davidr99 0:ab4e012489ef 305 }
davidr99 0:ab4e012489ef 306
davidr99 0:ab4e012489ef 307 bool RH_RF95::sleep()
davidr99 0:ab4e012489ef 308 {
davidr99 0:ab4e012489ef 309 if (_mode != RHModeSleep)
davidr99 0:ab4e012489ef 310 {
davidr99 0:ab4e012489ef 311 spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_SLEEP);
davidr99 0:ab4e012489ef 312 _mode = RHModeSleep;
davidr99 0:ab4e012489ef 313 }
davidr99 0:ab4e012489ef 314 return true;
davidr99 0:ab4e012489ef 315 }
davidr99 0:ab4e012489ef 316
davidr99 0:ab4e012489ef 317 void RH_RF95::setModeRx()
davidr99 0:ab4e012489ef 318 {
davidr99 0:ab4e012489ef 319 if (_mode != RHModeRx)
davidr99 0:ab4e012489ef 320 {
davidr99 0:ab4e012489ef 321 spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_RXCONTINUOUS);
davidr99 0:ab4e012489ef 322 spiWrite(RH_RF95_REG_40_DIO_MAPPING1, 0x00); // Interrupt on RxDone
davidr99 0:ab4e012489ef 323 _mode = RHModeRx;
davidr99 0:ab4e012489ef 324 }
davidr99 0:ab4e012489ef 325 }
davidr99 0:ab4e012489ef 326
davidr99 0:ab4e012489ef 327 void RH_RF95::setModeTx()
davidr99 0:ab4e012489ef 328 {
davidr99 0:ab4e012489ef 329 if (_mode != RHModeTx)
davidr99 0:ab4e012489ef 330 {
davidr99 0:ab4e012489ef 331 spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_TX);
davidr99 0:ab4e012489ef 332 spiWrite(RH_RF95_REG_40_DIO_MAPPING1, 0x40); // Interrupt on TxDone
davidr99 0:ab4e012489ef 333 _mode = RHModeTx;
davidr99 0:ab4e012489ef 334 }
davidr99 0:ab4e012489ef 335 }
davidr99 0:ab4e012489ef 336
davidr99 0:ab4e012489ef 337 void RH_RF95::setTxPower(int8_t power)
davidr99 0:ab4e012489ef 338 {
davidr99 0:ab4e012489ef 339 if (power > 23)
davidr99 0:ab4e012489ef 340 power = 23;
davidr99 0:ab4e012489ef 341 if (power < 5)
davidr99 0:ab4e012489ef 342 power = 5;
davidr99 0:ab4e012489ef 343
davidr99 0:ab4e012489ef 344 // For RH_RF95_PA_DAC_ENABLE, manual says '+20dBm on PA_BOOST when OutputPower=0xf'
davidr99 0:ab4e012489ef 345 // RH_RF95_PA_DAC_ENABLE actually adds about 3dBm to all power levels. We will us it
davidr99 0:ab4e012489ef 346 // for 21, 22 and 23dBm
davidr99 0:ab4e012489ef 347 if (power > 20)
davidr99 0:ab4e012489ef 348 {
davidr99 0:ab4e012489ef 349 spiWrite(RH_RF95_REG_4D_PA_DAC, RH_RF95_PA_DAC_ENABLE);
davidr99 0:ab4e012489ef 350 power -= 3;
davidr99 0:ab4e012489ef 351 }
davidr99 0:ab4e012489ef 352 else
davidr99 0:ab4e012489ef 353 {
davidr99 0:ab4e012489ef 354 spiWrite(RH_RF95_REG_4D_PA_DAC, RH_RF95_PA_DAC_DISABLE);
davidr99 0:ab4e012489ef 355 }
davidr99 0:ab4e012489ef 356
davidr99 0:ab4e012489ef 357 // RFM95/96/97/98 does not have RFO pins connected to anything. Only PA_BOOST
davidr99 0:ab4e012489ef 358 // pin is connected, so must use PA_BOOST
davidr99 0:ab4e012489ef 359 // Pout = 2 + OutputPower.
davidr99 0:ab4e012489ef 360 // The documentation is pretty confusing on this topic: PaSelect says the max power is 20dBm,
davidr99 0:ab4e012489ef 361 // but OutputPower claims it would be 17dBm.
davidr99 0:ab4e012489ef 362 // My measurements show 20dBm is correct
davidr99 0:ab4e012489ef 363 spiWrite(RH_RF95_REG_09_PA_CONFIG, RH_RF95_PA_SELECT | (power-5));
davidr99 0:ab4e012489ef 364 }
davidr99 0:ab4e012489ef 365
davidr99 0:ab4e012489ef 366 // Sets registers from a canned modem configuration structure
davidr99 0:ab4e012489ef 367 void RH_RF95::setModemRegisters(const ModemConfig* config)
davidr99 0:ab4e012489ef 368 {
davidr99 0:ab4e012489ef 369 spiWrite(RH_RF95_REG_1D_MODEM_CONFIG1, config->reg_1d);
davidr99 0:ab4e012489ef 370 spiWrite(RH_RF95_REG_1E_MODEM_CONFIG2, config->reg_1e);
davidr99 0:ab4e012489ef 371 spiWrite(RH_RF95_REG_26_MODEM_CONFIG3, config->reg_26);
davidr99 0:ab4e012489ef 372 }
davidr99 0:ab4e012489ef 373
davidr99 0:ab4e012489ef 374 // Set one of the canned FSK Modem configs
davidr99 0:ab4e012489ef 375 // Returns true if its a valid choice
davidr99 0:ab4e012489ef 376 bool RH_RF95::setModemConfig(ModemConfigChoice index)
davidr99 0:ab4e012489ef 377 {
davidr99 0:ab4e012489ef 378 if (index > (signed int)(sizeof(MODEM_CONFIG_TABLE) / sizeof(ModemConfig)))
davidr99 0:ab4e012489ef 379 return false;
davidr99 0:ab4e012489ef 380
davidr99 0:ab4e012489ef 381 ModemConfig cfg;
davidr99 0:ab4e012489ef 382 memcpy_P(&cfg, &MODEM_CONFIG_TABLE[index], sizeof(RH_RF95::ModemConfig));
davidr99 0:ab4e012489ef 383 setModemRegisters(&cfg);
davidr99 0:ab4e012489ef 384
davidr99 0:ab4e012489ef 385 return true;
davidr99 0:ab4e012489ef 386 }
davidr99 0:ab4e012489ef 387
davidr99 0:ab4e012489ef 388 void RH_RF95::setPreambleLength(uint16_t bytes)
davidr99 0:ab4e012489ef 389 {
davidr99 0:ab4e012489ef 390 spiWrite(RH_RF95_REG_20_PREAMBLE_MSB, bytes >> 8);
davidr99 0:ab4e012489ef 391 spiWrite(RH_RF95_REG_21_PREAMBLE_LSB, bytes & 0xff);
davidr99 0:ab4e012489ef 392 }
davidr99 0:ab4e012489ef 393