V148
Fork of RadioHead-148 by
RH_RF95.cpp@0:ab4e012489ef, 2015-10-15 (annotated)
- Committer:
- davidr99
- Date:
- Thu Oct 15 01:27:00 2015 +0000
- Revision:
- 0:ab4e012489ef
Messy start, but a port for RadioHead.; Currently the SPI modulus are the only ones that work.
Who changed what in which revision?
User | Revision | Line number | New 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 |