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:
Tue Jun 22 20:25:10 2021 +0000
Revision:
6:20187dafd325
Parent:
5:9166705eb726
changed the TX IRQ line

Who changed what in which revision?

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