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:
Mon May 31 02:49:19 2021 +0000
Revision:
3:6ffa8c82a713
Parent:
1:dfeb5e8b199a
Child:
4:61db9344ce8c
Initial working version that is focused on the RF95 radio.

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);
davidr99 0:ab4e012489ef 60 delay(10); // 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);
davidr99 0:ab4e012489ef 153 if (_mode == RHModeRx && irq_flags & (RH_RF95_RX_TIMEOUT | RH_RF95_PAYLOAD_CRC_ERROR))
davidr99 0:ab4e012489ef 154 {
davidr99 0:ab4e012489ef 155 _rxBad++;
davidr99 0:ab4e012489ef 156 }
davidr99 0:ab4e012489ef 157 else if (_mode == RHModeRx && irq_flags & RH_RF95_RX_DONE)
davidr99 0:ab4e012489ef 158 {
davidr99 0:ab4e012489ef 159 // Have received a packet
davidr99 0:ab4e012489ef 160 uint8_t len = spiRead(RH_RF95_REG_13_RX_NB_BYTES);
davidr99 0:ab4e012489ef 161
davidr99 0:ab4e012489ef 162 // Reset the fifo read ptr to the beginning of the packet
davidr99 0:ab4e012489ef 163 spiWrite(RH_RF95_REG_0D_FIFO_ADDR_PTR, spiRead(RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR));
davidr99 0:ab4e012489ef 164 spiBurstRead(RH_RF95_REG_00_FIFO, _buf, len);
davidr99 0:ab4e012489ef 165 _bufLen = len;
davidr99 0:ab4e012489ef 166 spiWrite(RH_RF95_REG_12_IRQ_FLAGS, 0xff); // Clear all IRQ flags
davidr99 0:ab4e012489ef 167
davidr99 0:ab4e012489ef 168 // Remember the RSSI of this packet
davidr99 0:ab4e012489ef 169 // this is according to the doc, but is it really correct?
davidr99 0:ab4e012489ef 170 // weakest receiveable signals are reported RSSI at about -66
davidr99 0:ab4e012489ef 171 _lastRssi = spiRead(RH_RF95_REG_1A_PKT_RSSI_VALUE) - 137;
davidr99 0:ab4e012489ef 172
davidr99 0:ab4e012489ef 173 // We have received a message.
davidr99 0:ab4e012489ef 174 validateRxBuf();
davidr99 0:ab4e012489ef 175 if (_rxBufValid)
davidr99 0:ab4e012489ef 176 setModeIdle(); // Got one
davidr99 0:ab4e012489ef 177 }
davidr99 0:ab4e012489ef 178 else if (_mode == RHModeTx && irq_flags & RH_RF95_TX_DONE)
davidr99 0:ab4e012489ef 179 {
davidr99 0:ab4e012489ef 180 _txGood++;
davidr99 0:ab4e012489ef 181 setModeIdle();
davidr99 0:ab4e012489ef 182 }
davidr99 0:ab4e012489ef 183
davidr99 0:ab4e012489ef 184 spiWrite(RH_RF95_REG_12_IRQ_FLAGS, 0xff); // Clear all IRQ flags
davidr99 0:ab4e012489ef 185 }
davidr99 0:ab4e012489ef 186
rlanders73 3:6ffa8c82a713 187 void RH_RF95::manageISR(){
rlanders73 3:6ffa8c82a713 188 while(1)
rlanders73 3:6ffa8c82a713 189 _deviceForInterrupt[0]->handleInterrupt();
rlanders73 3:6ffa8c82a713 190 }
rlanders73 3:6ffa8c82a713 191
davidr99 0:ab4e012489ef 192 // These are low level functions that call the interrupt handler for the correct
davidr99 0:ab4e012489ef 193 // instance of RH_RF95.
davidr99 0:ab4e012489ef 194 // 3 interrupts allows us to have 3 different devices
davidr99 0:ab4e012489ef 195 void RH_RF95::isr0()
davidr99 0:ab4e012489ef 196 {
davidr99 0:ab4e012489ef 197 if (_deviceForInterrupt[0])
davidr99 0:ab4e012489ef 198 _deviceForInterrupt[0]->handleInterrupt();
rlanders73 3:6ffa8c82a713 199 // doISR = true;
rlanders73 3:6ffa8c82a713 200
davidr99 0:ab4e012489ef 201 }
davidr99 0:ab4e012489ef 202 void RH_RF95::isr1()
davidr99 0:ab4e012489ef 203 {
davidr99 0:ab4e012489ef 204 if (_deviceForInterrupt[1])
davidr99 0:ab4e012489ef 205 _deviceForInterrupt[1]->handleInterrupt();
davidr99 0:ab4e012489ef 206 }
davidr99 0:ab4e012489ef 207 void RH_RF95::isr2()
davidr99 0:ab4e012489ef 208 {
davidr99 0:ab4e012489ef 209 if (_deviceForInterrupt[2])
davidr99 0:ab4e012489ef 210 _deviceForInterrupt[2]->handleInterrupt();
davidr99 0:ab4e012489ef 211 }
davidr99 0:ab4e012489ef 212
davidr99 0:ab4e012489ef 213 // Check whether the latest received message is complete and uncorrupted
davidr99 0:ab4e012489ef 214 void RH_RF95::validateRxBuf()
davidr99 0:ab4e012489ef 215 {
davidr99 0:ab4e012489ef 216 if (_bufLen < 4)
davidr99 0:ab4e012489ef 217 return; // Too short to be a real message
davidr99 0:ab4e012489ef 218 // Extract the 4 headers
davidr99 0:ab4e012489ef 219 _rxHeaderTo = _buf[0];
davidr99 0:ab4e012489ef 220 _rxHeaderFrom = _buf[1];
davidr99 0:ab4e012489ef 221 _rxHeaderId = _buf[2];
davidr99 0:ab4e012489ef 222 _rxHeaderFlags = _buf[3];
davidr99 0:ab4e012489ef 223 if (_promiscuous ||
davidr99 0:ab4e012489ef 224 _rxHeaderTo == _thisAddress ||
davidr99 0:ab4e012489ef 225 _rxHeaderTo == RH_BROADCAST_ADDRESS)
davidr99 0:ab4e012489ef 226 {
davidr99 0:ab4e012489ef 227 _rxGood++;
davidr99 0:ab4e012489ef 228 _rxBufValid = true;
davidr99 0:ab4e012489ef 229 }
davidr99 0:ab4e012489ef 230 }
davidr99 0:ab4e012489ef 231
davidr99 0:ab4e012489ef 232 bool RH_RF95::available()
davidr99 0:ab4e012489ef 233 {
rlanders73 1:dfeb5e8b199a 234 if (_mode == RHModeTx){
rlanders73 1:dfeb5e8b199a 235 return false;
rlanders73 1:dfeb5e8b199a 236 }
rlanders73 1:dfeb5e8b199a 237
davidr99 0:ab4e012489ef 238 setModeRx();
davidr99 0:ab4e012489ef 239 return _rxBufValid; // Will be set by the interrupt handler when a good message is received
davidr99 0:ab4e012489ef 240 }
davidr99 0:ab4e012489ef 241
davidr99 0:ab4e012489ef 242 void RH_RF95::clearRxBuf()
davidr99 0:ab4e012489ef 243 {
davidr99 0:ab4e012489ef 244 ATOMIC_BLOCK_START;
davidr99 0:ab4e012489ef 245 _rxBufValid = false;
davidr99 0:ab4e012489ef 246 _bufLen = 0;
davidr99 0:ab4e012489ef 247 ATOMIC_BLOCK_END;
davidr99 0:ab4e012489ef 248 }
davidr99 0:ab4e012489ef 249
davidr99 0:ab4e012489ef 250 bool RH_RF95::recv(uint8_t* buf, uint8_t* len)
davidr99 0:ab4e012489ef 251 {
davidr99 0:ab4e012489ef 252 if (!available())
davidr99 0:ab4e012489ef 253 return false;
davidr99 0:ab4e012489ef 254 if (buf && len)
davidr99 0:ab4e012489ef 255 {
davidr99 0:ab4e012489ef 256 ATOMIC_BLOCK_START;
davidr99 0:ab4e012489ef 257 // Skip the 4 headers that are at the beginning of the rxBuf
davidr99 0:ab4e012489ef 258 if (*len > _bufLen-RH_RF95_HEADER_LEN)
davidr99 0:ab4e012489ef 259 *len = _bufLen-RH_RF95_HEADER_LEN;
davidr99 0:ab4e012489ef 260 memcpy(buf, _buf+RH_RF95_HEADER_LEN, *len);
davidr99 0:ab4e012489ef 261 ATOMIC_BLOCK_END;
davidr99 0:ab4e012489ef 262 }
davidr99 0:ab4e012489ef 263 clearRxBuf(); // This message accepted and cleared
davidr99 0:ab4e012489ef 264 return true;
davidr99 0:ab4e012489ef 265 }
davidr99 0:ab4e012489ef 266
davidr99 0:ab4e012489ef 267 bool RH_RF95::send(const uint8_t* data, uint8_t len)
davidr99 0:ab4e012489ef 268 {
davidr99 0:ab4e012489ef 269 if (len > RH_RF95_MAX_MESSAGE_LEN)
davidr99 0:ab4e012489ef 270 return false;
davidr99 0:ab4e012489ef 271
davidr99 0:ab4e012489ef 272 waitPacketSent(); // Make sure we dont interrupt an outgoing message
davidr99 0:ab4e012489ef 273 setModeIdle();
davidr99 0:ab4e012489ef 274
davidr99 0:ab4e012489ef 275 // Position at the beginning of the FIFO
davidr99 0:ab4e012489ef 276 spiWrite(RH_RF95_REG_0D_FIFO_ADDR_PTR, 0);
davidr99 0:ab4e012489ef 277 // The headers
davidr99 0:ab4e012489ef 278 spiWrite(RH_RF95_REG_00_FIFO, _txHeaderTo);
davidr99 0:ab4e012489ef 279 spiWrite(RH_RF95_REG_00_FIFO, _txHeaderFrom);
davidr99 0:ab4e012489ef 280 spiWrite(RH_RF95_REG_00_FIFO, _txHeaderId);
davidr99 0:ab4e012489ef 281 spiWrite(RH_RF95_REG_00_FIFO, _txHeaderFlags);
davidr99 0:ab4e012489ef 282 // The message data
davidr99 0:ab4e012489ef 283 spiBurstWrite(RH_RF95_REG_00_FIFO, data, len);
davidr99 0:ab4e012489ef 284 spiWrite(RH_RF95_REG_22_PAYLOAD_LENGTH, len + RH_RF95_HEADER_LEN);
davidr99 0:ab4e012489ef 285
davidr99 0:ab4e012489ef 286 setModeTx(); // Start the transmitter
davidr99 0:ab4e012489ef 287 // when Tx is done, interruptHandler will fire and radio mode will return to STANDBY
davidr99 0:ab4e012489ef 288 return true;
davidr99 0:ab4e012489ef 289 }
davidr99 0:ab4e012489ef 290
davidr99 0:ab4e012489ef 291 bool RH_RF95::printRegisters()
davidr99 0:ab4e012489ef 292 {
davidr99 0:ab4e012489ef 293 #ifdef RH_HAVE_SERIAL
davidr99 0:ab4e012489ef 294 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 295
davidr99 0:ab4e012489ef 296 uint8_t i;
davidr99 0:ab4e012489ef 297 for (i = 0; i < sizeof(registers); i++)
davidr99 0:ab4e012489ef 298 {
davidr99 0:ab4e012489ef 299 Serial.print(registers[i], HEX);
davidr99 0:ab4e012489ef 300 Serial.print(": ");
davidr99 0:ab4e012489ef 301 Serial.println(spiRead(registers[i]), HEX);
davidr99 0:ab4e012489ef 302 }
davidr99 0:ab4e012489ef 303 #endif
davidr99 0:ab4e012489ef 304 return true;
davidr99 0:ab4e012489ef 305 }
davidr99 0:ab4e012489ef 306
davidr99 0:ab4e012489ef 307 uint8_t RH_RF95::maxMessageLength()
davidr99 0:ab4e012489ef 308 {
davidr99 0:ab4e012489ef 309 return RH_RF95_MAX_MESSAGE_LEN;
davidr99 0:ab4e012489ef 310 }
davidr99 0:ab4e012489ef 311
davidr99 0:ab4e012489ef 312 bool RH_RF95::setFrequency(float centre)
davidr99 0:ab4e012489ef 313 {
davidr99 0:ab4e012489ef 314 // Frf = FRF / FSTEP
davidr99 0:ab4e012489ef 315 uint32_t frf = (centre * 1000000.0) / RH_RF95_FSTEP;
davidr99 0:ab4e012489ef 316 spiWrite(RH_RF95_REG_06_FRF_MSB, (frf >> 16) & 0xff);
davidr99 0:ab4e012489ef 317 spiWrite(RH_RF95_REG_07_FRF_MID, (frf >> 8) & 0xff);
davidr99 0:ab4e012489ef 318 spiWrite(RH_RF95_REG_08_FRF_LSB, frf & 0xff);
davidr99 0:ab4e012489ef 319
davidr99 0:ab4e012489ef 320 return true;
davidr99 0:ab4e012489ef 321 }
davidr99 0:ab4e012489ef 322
davidr99 0:ab4e012489ef 323 void RH_RF95::setModeIdle()
davidr99 0:ab4e012489ef 324 {
davidr99 0:ab4e012489ef 325 if (_mode != RHModeIdle)
davidr99 0:ab4e012489ef 326 {
rlanders73 3:6ffa8c82a713 327 // printf("---- Idle\n");
rlanders73 1:dfeb5e8b199a 328 spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_STDBY);
rlanders73 3:6ffa8c82a713 329 delay(10);
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 3:6ffa8c82a713 341 delay(10);
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 3:6ffa8c82a713 354 delay(10);
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 1:dfeb5e8b199a 365 spiWrite(RH_RF95_REG_40_DIO_MAPPING1, RH_RF95_DIOMAPPING1_DIO0MAPPING_00); // Interrupt on TxDone
rlanders73 3:6ffa8c82a713 366 delay(10);
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