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:
rlanders73
Date:
Fri Apr 30 15:16:24 2021 +0000
Revision:
1:dfeb5e8b199a
Parent:
0:ab4e012489ef
Child:
3:6ffa8c82a713
making this work for Geneva;

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