Quick & dirty port of the RadioHead library with minimal support for the RF95 radio. It is designed to be used with the swspi library which in turn is designed to be used on the MAX32630FTHR board.

Dependents:   Rocket

Committer:
danjulio
Date:
Sun Jun 11 04:05:05 2017 +0000
Revision:
0:e69d086cb053
Initial commit of minimally ported Radiohead library using swspi

Who changed what in which revision?

UserRevisionLine numberNew contents of line
danjulio 0:e69d086cb053 1 // RH_RF95.cpp
danjulio 0:e69d086cb053 2 //
danjulio 0:e69d086cb053 3 // Copyright (C) 2011 Mike McCauley
danjulio 0:e69d086cb053 4 // $Id: RH_RF95.cpp,v 1.14 2017/03/04 00:59:41 mikem Exp $
danjulio 0:e69d086cb053 5 //
danjulio 0:e69d086cb053 6 // Ported to mbed - support only a single radio - Dan Julio - 5/2017
danjulio 0:e69d086cb053 7 //
danjulio 0:e69d086cb053 8
danjulio 0:e69d086cb053 9 #include <RH_RF95.h>
danjulio 0:e69d086cb053 10
danjulio 0:e69d086cb053 11 // These are indexed by the values of ModemConfigChoice
danjulio 0:e69d086cb053 12 // Stored in flash (program) memory to save SRAM
danjulio 0:e69d086cb053 13 static const RH_RF95::ModemConfig MODEM_CONFIG_TABLE[] =
danjulio 0:e69d086cb053 14 {
danjulio 0:e69d086cb053 15 // 1d, 1e, 26
danjulio 0:e69d086cb053 16 { 0x72, 0x74, 0x00}, // Bw125Cr45Sf128 (the chip default)
danjulio 0:e69d086cb053 17 { 0x92, 0x74, 0x00}, // Bw500Cr45Sf128
danjulio 0:e69d086cb053 18 { 0x48, 0x94, 0x00}, // Bw31_25Cr48Sf512
danjulio 0:e69d086cb053 19 { 0x78, 0xc4, 0x00}, // Bw125Cr48Sf4096
danjulio 0:e69d086cb053 20
danjulio 0:e69d086cb053 21 };
danjulio 0:e69d086cb053 22
danjulio 0:e69d086cb053 23 RH_RF95::RH_RF95(swspi& spi, int ssNum)
danjulio 0:e69d086cb053 24 :
danjulio 0:e69d086cb053 25 _spi(spi),
danjulio 0:e69d086cb053 26 _ssn(ssNum),
danjulio 0:e69d086cb053 27 _rxBufValid(0)
danjulio 0:e69d086cb053 28 {
danjulio 0:e69d086cb053 29 }
danjulio 0:e69d086cb053 30
danjulio 0:e69d086cb053 31 bool RH_RF95::init()
danjulio 0:e69d086cb053 32 {
danjulio 0:e69d086cb053 33 // Set sleep mode, so we can also set LORA mode:
danjulio 0:e69d086cb053 34 _spi.spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_SLEEP | RH_RF95_LONG_RANGE_MODE, 0, _ssn);
danjulio 0:e69d086cb053 35 wait_ms(10); // Wait for sleep mode to take over from say, CAD
danjulio 0:e69d086cb053 36 // Check we are in sleep mode, with LORA set
danjulio 0:e69d086cb053 37 if (_spi.spiRead(RH_RF95_REG_01_OP_MODE, 0, _ssn) != (RH_RF95_MODE_SLEEP | RH_RF95_LONG_RANGE_MODE))
danjulio 0:e69d086cb053 38 {
danjulio 0:e69d086cb053 39 // printf("REG_01_OP_MODE: 0x%2x\n", _spi.spiRead(RH_RF95_REG_01_OP_MODE, 0, _ssn));
danjulio 0:e69d086cb053 40 return false; // No device present?
danjulio 0:e69d086cb053 41 }
danjulio 0:e69d086cb053 42
danjulio 0:e69d086cb053 43 // Set up FIFO
danjulio 0:e69d086cb053 44 // We configure so that we can use the entire 256 byte FIFO for either receive
danjulio 0:e69d086cb053 45 // or transmit, but not both at the same time
danjulio 0:e69d086cb053 46 _spi.spiWrite(RH_RF95_REG_0E_FIFO_TX_BASE_ADDR, 0, 0, _ssn);
danjulio 0:e69d086cb053 47 _spi.spiWrite(RH_RF95_REG_0F_FIFO_RX_BASE_ADDR, 0, 0, _ssn);
danjulio 0:e69d086cb053 48
danjulio 0:e69d086cb053 49 // Packet format is preamble + explicit-header + payload + crc
danjulio 0:e69d086cb053 50 // Explicit Header Mode
danjulio 0:e69d086cb053 51 // payload is TO + FROM + ID + FLAGS + message data
danjulio 0:e69d086cb053 52 // RX mode is implmented with RXCONTINUOUS
danjulio 0:e69d086cb053 53 // max message data length is 255 - 4 = 251 octets
danjulio 0:e69d086cb053 54
danjulio 0:e69d086cb053 55 setModeIdle();
danjulio 0:e69d086cb053 56
danjulio 0:e69d086cb053 57 // Set up default configuration
danjulio 0:e69d086cb053 58 // No Sync Words in LORA mode.
danjulio 0:e69d086cb053 59 setModemConfig(Bw125Cr45Sf128); // Radio default
danjulio 0:e69d086cb053 60 // setModemConfig(Bw125Cr48Sf4096); // slow and reliable?
danjulio 0:e69d086cb053 61 setPreambleLength(8); // Default is 8
danjulio 0:e69d086cb053 62 // An innocuous ISM frequency, same as RF22's
danjulio 0:e69d086cb053 63 setFrequency(434.0);
danjulio 0:e69d086cb053 64 // Lowish power
danjulio 0:e69d086cb053 65 setTxPower(13);
danjulio 0:e69d086cb053 66
danjulio 0:e69d086cb053 67 return true;
danjulio 0:e69d086cb053 68 }
danjulio 0:e69d086cb053 69
danjulio 0:e69d086cb053 70 // C++ level interrupt handler for this instance
danjulio 0:e69d086cb053 71 // LORA is unusual in that it has several interrupt lines, and not a single, combined one.
danjulio 0:e69d086cb053 72 // On MiniWirelessLoRa, only one of the several interrupt lines (DI0) from the RFM95 is usefuly
danjulio 0:e69d086cb053 73 // connnected to the processor.
danjulio 0:e69d086cb053 74 // We use this to get RxDone and TxDone interrupts
danjulio 0:e69d086cb053 75 void RH_RF95::handleInterrupt()
danjulio 0:e69d086cb053 76 {
danjulio 0:e69d086cb053 77 // Read the interrupt register
danjulio 0:e69d086cb053 78 uint8_t irq_flags = _spi.spiRead(RH_RF95_REG_12_IRQ_FLAGS, 0, _ssn);
danjulio 0:e69d086cb053 79 if (_mode == RHModeRx && irq_flags & (RH_RF95_RX_TIMEOUT | RH_RF95_PAYLOAD_CRC_ERROR))
danjulio 0:e69d086cb053 80 {
danjulio 0:e69d086cb053 81 _rxBad++;
danjulio 0:e69d086cb053 82 }
danjulio 0:e69d086cb053 83 else if (_mode == RHModeRx && irq_flags & RH_RF95_RX_DONE)
danjulio 0:e69d086cb053 84 {
danjulio 0:e69d086cb053 85 // Have received a packet
danjulio 0:e69d086cb053 86 uint8_t len = _spi.spiRead(RH_RF95_REG_13_RX_NB_BYTES, 0, _ssn);
danjulio 0:e69d086cb053 87
danjulio 0:e69d086cb053 88 // Reset the fifo read ptr to the beginning of the packet
danjulio 0:e69d086cb053 89 _spi.spiWrite(RH_RF95_REG_0D_FIFO_ADDR_PTR, _spi.spiRead(RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR, 0, _ssn), 0, _ssn);
danjulio 0:e69d086cb053 90 _spi.spiBurstRead(RH_RF95_REG_00_FIFO, _buf, len, 0, _ssn);
danjulio 0:e69d086cb053 91 _bufLen = len;
danjulio 0:e69d086cb053 92 _spi.spiWrite(RH_RF95_REG_12_IRQ_FLAGS, 0xff, 0, _ssn); // Clear all IRQ flags
danjulio 0:e69d086cb053 93
danjulio 0:e69d086cb053 94 // Remember the last signal to noise ratio, LORA mode
danjulio 0:e69d086cb053 95 // Per page 111, SX1276/77/78/79 datasheet
danjulio 0:e69d086cb053 96 _lastSNR = (int8_t)_spi.spiRead(RH_RF95_REG_19_PKT_SNR_VALUE, 0, _ssn) / 4;
danjulio 0:e69d086cb053 97
danjulio 0:e69d086cb053 98 // Remember the RSSI of this packet, LORA mode
danjulio 0:e69d086cb053 99 // this is according to the doc, but is it really correct?
danjulio 0:e69d086cb053 100 // weakest receiveable signals are reported RSSI at about -66
danjulio 0:e69d086cb053 101 _lastRssi = _spi.spiRead(RH_RF95_REG_1A_PKT_RSSI_VALUE, 0, _ssn);
danjulio 0:e69d086cb053 102 // Adjust the RSSI, datasheet page 87
danjulio 0:e69d086cb053 103 if (_lastSNR < 0)
danjulio 0:e69d086cb053 104 _lastRssi = _lastRssi + _lastSNR;
danjulio 0:e69d086cb053 105 else
danjulio 0:e69d086cb053 106 _lastRssi = (int)_lastRssi * 16 / 15;
danjulio 0:e69d086cb053 107 if (_usingHFport)
danjulio 0:e69d086cb053 108 _lastRssi -= 157;
danjulio 0:e69d086cb053 109 else
danjulio 0:e69d086cb053 110 _lastRssi -= 164;
danjulio 0:e69d086cb053 111
danjulio 0:e69d086cb053 112 // We have received a message.
danjulio 0:e69d086cb053 113 validateRxBuf();
danjulio 0:e69d086cb053 114 if (_rxBufValid)
danjulio 0:e69d086cb053 115 setModeIdle(); // Got one
danjulio 0:e69d086cb053 116 }
danjulio 0:e69d086cb053 117 else if (_mode == RHModeTx && irq_flags & RH_RF95_TX_DONE)
danjulio 0:e69d086cb053 118 {
danjulio 0:e69d086cb053 119 _txGood++;
danjulio 0:e69d086cb053 120 setModeIdle();
danjulio 0:e69d086cb053 121 }
danjulio 0:e69d086cb053 122 else if (_mode == RHModeCad && irq_flags & RH_RF95_CAD_DONE)
danjulio 0:e69d086cb053 123 {
danjulio 0:e69d086cb053 124 _cad = irq_flags & RH_RF95_CAD_DETECTED;
danjulio 0:e69d086cb053 125 setModeIdle();
danjulio 0:e69d086cb053 126 }
danjulio 0:e69d086cb053 127
danjulio 0:e69d086cb053 128 _spi.spiWrite(RH_RF95_REG_12_IRQ_FLAGS, 0xff, 0, _ssn); // Clear all IRQ flags
danjulio 0:e69d086cb053 129 }
danjulio 0:e69d086cb053 130
danjulio 0:e69d086cb053 131 // Check whether the latest received message is complete and uncorrupted
danjulio 0:e69d086cb053 132 void RH_RF95::validateRxBuf()
danjulio 0:e69d086cb053 133 {
danjulio 0:e69d086cb053 134 if (_bufLen < 4)
danjulio 0:e69d086cb053 135 return; // Too short to be a real message
danjulio 0:e69d086cb053 136
danjulio 0:e69d086cb053 137 // Extract the 4 headers
danjulio 0:e69d086cb053 138 _rxHeaderTo = _buf[0];
danjulio 0:e69d086cb053 139 _rxHeaderFrom = _buf[1];
danjulio 0:e69d086cb053 140 _rxHeaderId = _buf[2];
danjulio 0:e69d086cb053 141 _rxHeaderFlags = _buf[3];
danjulio 0:e69d086cb053 142 if (_promiscuous ||
danjulio 0:e69d086cb053 143 _rxHeaderTo == _thisAddress ||
danjulio 0:e69d086cb053 144 _rxHeaderTo == RH_BROADCAST_ADDRESS)
danjulio 0:e69d086cb053 145 {
danjulio 0:e69d086cb053 146 _rxGood++;
danjulio 0:e69d086cb053 147 _rxBufValid = true;
danjulio 0:e69d086cb053 148 }
danjulio 0:e69d086cb053 149 }
danjulio 0:e69d086cb053 150
danjulio 0:e69d086cb053 151 bool RH_RF95::available()
danjulio 0:e69d086cb053 152 {
danjulio 0:e69d086cb053 153 if (_mode == RHModeTx)
danjulio 0:e69d086cb053 154 return false;
danjulio 0:e69d086cb053 155
danjulio 0:e69d086cb053 156 setModeRx();
danjulio 0:e69d086cb053 157 return _rxBufValid; // Will be set by the interrupt handler when a good message is received
danjulio 0:e69d086cb053 158 }
danjulio 0:e69d086cb053 159
danjulio 0:e69d086cb053 160 void RH_RF95::clearRxBuf()
danjulio 0:e69d086cb053 161 {
danjulio 0:e69d086cb053 162 _rxBufValid = false;
danjulio 0:e69d086cb053 163 _bufLen = 0;
danjulio 0:e69d086cb053 164 }
danjulio 0:e69d086cb053 165
danjulio 0:e69d086cb053 166 bool RH_RF95::recv(uint8_t* buf, uint8_t* len)
danjulio 0:e69d086cb053 167 {
danjulio 0:e69d086cb053 168 if (!available())
danjulio 0:e69d086cb053 169 return false;
danjulio 0:e69d086cb053 170
danjulio 0:e69d086cb053 171 if (buf && len)
danjulio 0:e69d086cb053 172 {
danjulio 0:e69d086cb053 173 // Skip the 4 headers that are at the beginning of the rxBuf
danjulio 0:e69d086cb053 174 if (*len > _bufLen-RH_RF95_HEADER_LEN)
danjulio 0:e69d086cb053 175 *len = _bufLen-RH_RF95_HEADER_LEN;
danjulio 0:e69d086cb053 176 memcpy(buf, _buf+RH_RF95_HEADER_LEN, *len);
danjulio 0:e69d086cb053 177 }
danjulio 0:e69d086cb053 178 clearRxBuf(); // This message accepted and cleared
danjulio 0:e69d086cb053 179 return true;
danjulio 0:e69d086cb053 180 }
danjulio 0:e69d086cb053 181
danjulio 0:e69d086cb053 182 bool RH_RF95::send(const uint8_t* data, uint8_t len)
danjulio 0:e69d086cb053 183 {
danjulio 0:e69d086cb053 184 if (len > RH_RF95_MAX_MESSAGE_LEN)
danjulio 0:e69d086cb053 185 return false;
danjulio 0:e69d086cb053 186
danjulio 0:e69d086cb053 187 waitPacketSent(); // Make sure we dont interrupt an outgoing message
danjulio 0:e69d086cb053 188 setModeIdle();
danjulio 0:e69d086cb053 189
danjulio 0:e69d086cb053 190 if (!waitCAD())
danjulio 0:e69d086cb053 191 return false; // Check channel activity
danjulio 0:e69d086cb053 192
danjulio 0:e69d086cb053 193 // Position at the beginning of the FIFO
danjulio 0:e69d086cb053 194 _spi.spiWrite(RH_RF95_REG_0D_FIFO_ADDR_PTR, 0, 0, _ssn);
danjulio 0:e69d086cb053 195 // The headers
danjulio 0:e69d086cb053 196 _spi.spiWrite(RH_RF95_REG_00_FIFO, _txHeaderTo, 0, _ssn);
danjulio 0:e69d086cb053 197 _spi.spiWrite(RH_RF95_REG_00_FIFO, _txHeaderFrom, 0, _ssn);
danjulio 0:e69d086cb053 198 _spi.spiWrite(RH_RF95_REG_00_FIFO, _txHeaderId, 0, _ssn);
danjulio 0:e69d086cb053 199 _spi.spiWrite(RH_RF95_REG_00_FIFO, _txHeaderFlags, 0, _ssn);
danjulio 0:e69d086cb053 200 // The message data
danjulio 0:e69d086cb053 201 _spi.spiBurstWrite(RH_RF95_REG_00_FIFO, data, len, 0, _ssn);
danjulio 0:e69d086cb053 202 _spi.spiWrite(RH_RF95_REG_22_PAYLOAD_LENGTH, len + RH_RF95_HEADER_LEN, 0, _ssn);
danjulio 0:e69d086cb053 203
danjulio 0:e69d086cb053 204 setModeTx(); // Start the transmitter
danjulio 0:e69d086cb053 205 // when Tx is done, interruptHandler will fire and radio mode will return to STANDBY
danjulio 0:e69d086cb053 206 return true;
danjulio 0:e69d086cb053 207 }
danjulio 0:e69d086cb053 208
danjulio 0:e69d086cb053 209 bool RH_RF95::printRegisters()
danjulio 0:e69d086cb053 210 {
danjulio 0:e69d086cb053 211 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};
danjulio 0:e69d086cb053 212
danjulio 0:e69d086cb053 213 uint8_t i;
danjulio 0:e69d086cb053 214 for (i = 0; i < sizeof(registers); i++)
danjulio 0:e69d086cb053 215 {
danjulio 0:e69d086cb053 216 printf("0x%x: 0x%x\n\r", registers[i], _spi.spiRead(registers[i], 0, _ssn));
danjulio 0:e69d086cb053 217 }
danjulio 0:e69d086cb053 218 return true;
danjulio 0:e69d086cb053 219 }
danjulio 0:e69d086cb053 220
danjulio 0:e69d086cb053 221 uint8_t RH_RF95::maxMessageLength()
danjulio 0:e69d086cb053 222 {
danjulio 0:e69d086cb053 223 return RH_RF95_MAX_MESSAGE_LEN;
danjulio 0:e69d086cb053 224 }
danjulio 0:e69d086cb053 225
danjulio 0:e69d086cb053 226 bool RH_RF95::setFrequency(float centre)
danjulio 0:e69d086cb053 227 {
danjulio 0:e69d086cb053 228 // Frf = FRF / FSTEP
danjulio 0:e69d086cb053 229 uint32_t frf = (centre * 1000000.0f) / RH_RF95_FSTEP;
danjulio 0:e69d086cb053 230 _spi.spiWrite(RH_RF95_REG_06_FRF_MSB, (frf >> 16) & 0xff, 0, _ssn);
danjulio 0:e69d086cb053 231 _spi.spiWrite(RH_RF95_REG_07_FRF_MID, (frf >> 8) & 0xff, 0, _ssn);
danjulio 0:e69d086cb053 232 _spi.spiWrite(RH_RF95_REG_08_FRF_LSB, frf & 0xff, 0, _ssn);
danjulio 0:e69d086cb053 233 _usingHFport = (centre >= 779.0f);
danjulio 0:e69d086cb053 234
danjulio 0:e69d086cb053 235 return true;
danjulio 0:e69d086cb053 236 }
danjulio 0:e69d086cb053 237
danjulio 0:e69d086cb053 238 void RH_RF95::setModeIdle()
danjulio 0:e69d086cb053 239 {
danjulio 0:e69d086cb053 240 if (_mode != RHModeIdle)
danjulio 0:e69d086cb053 241 {
danjulio 0:e69d086cb053 242 _spi.spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_STDBY, 0, _ssn);
danjulio 0:e69d086cb053 243 _mode = RHModeIdle;
danjulio 0:e69d086cb053 244 }
danjulio 0:e69d086cb053 245 }
danjulio 0:e69d086cb053 246
danjulio 0:e69d086cb053 247 bool RH_RF95::sleep()
danjulio 0:e69d086cb053 248 {
danjulio 0:e69d086cb053 249 if (_mode != RHModeSleep)
danjulio 0:e69d086cb053 250 {
danjulio 0:e69d086cb053 251 _spi.spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_SLEEP, 0, _ssn);
danjulio 0:e69d086cb053 252 _mode = RHModeSleep;
danjulio 0:e69d086cb053 253 }
danjulio 0:e69d086cb053 254 return true;
danjulio 0:e69d086cb053 255 }
danjulio 0:e69d086cb053 256
danjulio 0:e69d086cb053 257 void RH_RF95::setModeRx()
danjulio 0:e69d086cb053 258 {
danjulio 0:e69d086cb053 259 if (_mode != RHModeRx)
danjulio 0:e69d086cb053 260 {
danjulio 0:e69d086cb053 261 _spi.spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_RXCONTINUOUS, 0, _ssn);
danjulio 0:e69d086cb053 262 _spi.spiWrite(RH_RF95_REG_40_DIO_MAPPING1, 0x00, 0, _ssn); // Interrupt on RxDone
danjulio 0:e69d086cb053 263 _mode = RHModeRx;
danjulio 0:e69d086cb053 264 }
danjulio 0:e69d086cb053 265 }
danjulio 0:e69d086cb053 266
danjulio 0:e69d086cb053 267 void RH_RF95::setModeTx()
danjulio 0:e69d086cb053 268 {
danjulio 0:e69d086cb053 269 if (_mode != RHModeTx)
danjulio 0:e69d086cb053 270 {
danjulio 0:e69d086cb053 271 _spi.spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_TX, 0, _ssn);
danjulio 0:e69d086cb053 272 _spi.spiWrite(RH_RF95_REG_40_DIO_MAPPING1, 0x40, 0, _ssn); // Interrupt on TxDone
danjulio 0:e69d086cb053 273 _mode = RHModeTx;
danjulio 0:e69d086cb053 274 }
danjulio 0:e69d086cb053 275 }
danjulio 0:e69d086cb053 276
danjulio 0:e69d086cb053 277 void RH_RF95::setTxPower(int8_t power, bool useRFO)
danjulio 0:e69d086cb053 278 {
danjulio 0:e69d086cb053 279 // Sigh, different behaviours depending on whther the module use PA_BOOST or the RFO pin
danjulio 0:e69d086cb053 280 // for the transmitter output
danjulio 0:e69d086cb053 281 if (useRFO)
danjulio 0:e69d086cb053 282 {
danjulio 0:e69d086cb053 283 if (power > 14)
danjulio 0:e69d086cb053 284 power = 14;
danjulio 0:e69d086cb053 285 if (power < -1)
danjulio 0:e69d086cb053 286 power = -1;
danjulio 0:e69d086cb053 287 _spi.spiWrite(RH_RF95_REG_09_PA_CONFIG, RH_RF95_MAX_POWER | (power + 1), 0, _ssn);
danjulio 0:e69d086cb053 288 }
danjulio 0:e69d086cb053 289 else
danjulio 0:e69d086cb053 290 {
danjulio 0:e69d086cb053 291 if (power > 23)
danjulio 0:e69d086cb053 292 power = 23;
danjulio 0:e69d086cb053 293 if (power < 5)
danjulio 0:e69d086cb053 294 power = 5;
danjulio 0:e69d086cb053 295
danjulio 0:e69d086cb053 296 // For RH_RF95_PA_DAC_ENABLE, manual says '+20dBm on PA_BOOST when OutputPower=0xf'
danjulio 0:e69d086cb053 297 // RH_RF95_PA_DAC_ENABLE actually adds about 3dBm to all power levels. We will us it
danjulio 0:e69d086cb053 298 // for 21, 22 and 23dBm
danjulio 0:e69d086cb053 299 if (power > 20)
danjulio 0:e69d086cb053 300 {
danjulio 0:e69d086cb053 301 _spi.spiWrite(RH_RF95_REG_4D_PA_DAC, RH_RF95_PA_DAC_ENABLE, 0, _ssn);
danjulio 0:e69d086cb053 302 power -= 3;
danjulio 0:e69d086cb053 303 }
danjulio 0:e69d086cb053 304 else
danjulio 0:e69d086cb053 305 {
danjulio 0:e69d086cb053 306 _spi.spiWrite(RH_RF95_REG_4D_PA_DAC, RH_RF95_PA_DAC_DISABLE, 0, _ssn);
danjulio 0:e69d086cb053 307 }
danjulio 0:e69d086cb053 308
danjulio 0:e69d086cb053 309 // RFM95/96/97/98 does not have RFO pins connected to anything. Only PA_BOOST
danjulio 0:e69d086cb053 310 // pin is connected, so must use PA_BOOST
danjulio 0:e69d086cb053 311 // Pout = 2 + OutputPower.
danjulio 0:e69d086cb053 312 // The documentation is pretty confusing on this topic: PaSelect says the max power is 20dBm,
danjulio 0:e69d086cb053 313 // but OutputPower claims it would be 17dBm.
danjulio 0:e69d086cb053 314 // My measurements show 20dBm is correct
danjulio 0:e69d086cb053 315 _spi.spiWrite(RH_RF95_REG_09_PA_CONFIG, RH_RF95_PA_SELECT | (power-5), 0, _ssn);
danjulio 0:e69d086cb053 316 }
danjulio 0:e69d086cb053 317 }
danjulio 0:e69d086cb053 318
danjulio 0:e69d086cb053 319 // Sets registers from a canned modem configuration structure
danjulio 0:e69d086cb053 320 void RH_RF95::setModemRegisters(const ModemConfig* config)
danjulio 0:e69d086cb053 321 {
danjulio 0:e69d086cb053 322 _spi.spiWrite(RH_RF95_REG_1D_MODEM_CONFIG1, config->reg_1d, 0, _ssn);
danjulio 0:e69d086cb053 323 _spi.spiWrite(RH_RF95_REG_1E_MODEM_CONFIG2, config->reg_1e, 0, _ssn);
danjulio 0:e69d086cb053 324 _spi.spiWrite(RH_RF95_REG_26_MODEM_CONFIG3, config->reg_26, 0, _ssn);
danjulio 0:e69d086cb053 325 }
danjulio 0:e69d086cb053 326
danjulio 0:e69d086cb053 327 // Set one of the canned FSK Modem configs
danjulio 0:e69d086cb053 328 // Returns true if its a valid choice
danjulio 0:e69d086cb053 329 bool RH_RF95::setModemConfig(ModemConfigChoice index)
danjulio 0:e69d086cb053 330 {
danjulio 0:e69d086cb053 331 if (index > (signed int)(sizeof(MODEM_CONFIG_TABLE) / sizeof(ModemConfig)))
danjulio 0:e69d086cb053 332 return false;
danjulio 0:e69d086cb053 333
danjulio 0:e69d086cb053 334 ModemConfig cfg;
danjulio 0:e69d086cb053 335 memcpy(&cfg, &MODEM_CONFIG_TABLE[index], sizeof(RH_RF95::ModemConfig));
danjulio 0:e69d086cb053 336 setModemRegisters(&cfg);
danjulio 0:e69d086cb053 337
danjulio 0:e69d086cb053 338 return true;
danjulio 0:e69d086cb053 339 }
danjulio 0:e69d086cb053 340
danjulio 0:e69d086cb053 341 void RH_RF95::setPreambleLength(uint16_t bytes)
danjulio 0:e69d086cb053 342 {
danjulio 0:e69d086cb053 343 _spi.spiWrite(RH_RF95_REG_20_PREAMBLE_MSB, bytes >> 8, 0, _ssn);
danjulio 0:e69d086cb053 344 _spi.spiWrite(RH_RF95_REG_21_PREAMBLE_LSB, bytes & 0xff, 0, _ssn);
danjulio 0:e69d086cb053 345 }
danjulio 0:e69d086cb053 346
danjulio 0:e69d086cb053 347 bool RH_RF95::isChannelActive()
danjulio 0:e69d086cb053 348 {
danjulio 0:e69d086cb053 349 // Set mode RHModeCad
danjulio 0:e69d086cb053 350 if (_mode != RHModeCad)
danjulio 0:e69d086cb053 351 {
danjulio 0:e69d086cb053 352 _spi.spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_CAD, 0, _ssn);
danjulio 0:e69d086cb053 353 _spi.spiWrite(RH_RF95_REG_40_DIO_MAPPING1, 0x80, 0, _ssn); // Interrupt on CadDone
danjulio 0:e69d086cb053 354 _mode = RHModeCad;
danjulio 0:e69d086cb053 355 }
danjulio 0:e69d086cb053 356
danjulio 0:e69d086cb053 357 while (_mode == RHModeCad)
danjulio 0:e69d086cb053 358 Thread::yield();
danjulio 0:e69d086cb053 359
danjulio 0:e69d086cb053 360 return _cad;
danjulio 0:e69d086cb053 361 }
danjulio 0:e69d086cb053 362
danjulio 0:e69d086cb053 363 void RH_RF95::enableTCXO()
danjulio 0:e69d086cb053 364 {
danjulio 0:e69d086cb053 365 while ((_spi.spiRead(RH_RF95_REG_4B_TCXO, 0, _ssn) & RH_RF95_TCXO_TCXO_INPUT_ON) != RH_RF95_TCXO_TCXO_INPUT_ON)
danjulio 0:e69d086cb053 366 {
danjulio 0:e69d086cb053 367 sleep();
danjulio 0:e69d086cb053 368 _spi.spiWrite(RH_RF95_REG_4B_TCXO, (_spi.spiRead(RH_RF95_REG_4B_TCXO, 0, _ssn) | RH_RF95_TCXO_TCXO_INPUT_ON), 0, _ssn);
danjulio 0:e69d086cb053 369 }
danjulio 0:e69d086cb053 370 }
danjulio 0:e69d086cb053 371
danjulio 0:e69d086cb053 372 // From section 4.1.5 of SX1276/77/78/79
danjulio 0:e69d086cb053 373 // Ferror = FreqError * 2**24 * BW / Fxtal / 500
danjulio 0:e69d086cb053 374 int RH_RF95::frequencyError()
danjulio 0:e69d086cb053 375 {
danjulio 0:e69d086cb053 376 int32_t freqerror = 0;
danjulio 0:e69d086cb053 377
danjulio 0:e69d086cb053 378 // Convert 2.5 bytes (5 nibbles, 20 bits) to 32 bit signed int
danjulio 0:e69d086cb053 379 freqerror = _spi.spiRead(RH_RF95_REG_28_FEI_MSB, 0, _ssn) << 16;
danjulio 0:e69d086cb053 380 freqerror |= _spi.spiRead(RH_RF95_REG_29_FEI_MID, 0, _ssn) << 8;
danjulio 0:e69d086cb053 381 freqerror |= _spi.spiRead(RH_RF95_REG_2A_FEI_LSB, 0, _ssn);
danjulio 0:e69d086cb053 382 // Sign extension into top 3 nibbles
danjulio 0:e69d086cb053 383 if (freqerror & 0x80000)
danjulio 0:e69d086cb053 384 freqerror |= 0xfff00000;
danjulio 0:e69d086cb053 385
danjulio 0:e69d086cb053 386 int error = 0; // In hertz
danjulio 0:e69d086cb053 387 float bw_tab[] = {7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250, 500};
danjulio 0:e69d086cb053 388 uint8_t bwindex = _spi.spiRead(RH_RF95_REG_1D_MODEM_CONFIG1, 0, _ssn) >> 4;
danjulio 0:e69d086cb053 389 if (bwindex < (sizeof(bw_tab) / sizeof(float)))
danjulio 0:e69d086cb053 390 error = (float)freqerror * bw_tab[bwindex] * ((float)(1L << 24) / (float)RH_RF95_FXOSC / 500.0f);
danjulio 0:e69d086cb053 391 // else not defined
danjulio 0:e69d086cb053 392
danjulio 0:e69d086cb053 393 return error;
danjulio 0:e69d086cb053 394 }
danjulio 0:e69d086cb053 395
danjulio 0:e69d086cb053 396 int RH_RF95::lastSNR()
danjulio 0:e69d086cb053 397 {
danjulio 0:e69d086cb053 398 return _lastSNR;
danjulio 0:e69d086cb053 399 }