Greg Voronin
/
gammaCanary02
This version is the one to be submitted as a part the Hackster.io contest, Unleash Invisible Intelligence
LoRa.cpp@0:a761fba7f8a8, 2018-07-31 (annotated)
- Committer:
- gov1
- Date:
- Tue Jul 31 16:30:32 2018 +0000
- Revision:
- 0:a761fba7f8a8
complete version with emer. batt low check
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
gov1 | 0:a761fba7f8a8 | 1 | #include <LoRa.h> |
gov1 | 0:a761fba7f8a8 | 2 | |
gov1 | 0:a761fba7f8a8 | 3 | // registers |
gov1 | 0:a761fba7f8a8 | 4 | #define REG_FIFO 0x00 |
gov1 | 0:a761fba7f8a8 | 5 | #define REG_OP_MODE 0x01 |
gov1 | 0:a761fba7f8a8 | 6 | #define REG_FRF_MSB 0x06 |
gov1 | 0:a761fba7f8a8 | 7 | #define REG_FRF_MID 0x07 |
gov1 | 0:a761fba7f8a8 | 8 | #define REG_FRF_LSB 0x08 |
gov1 | 0:a761fba7f8a8 | 9 | #define REG_PA_CONFIG 0x09 |
gov1 | 0:a761fba7f8a8 | 10 | #define REG_LNA 0x0c |
gov1 | 0:a761fba7f8a8 | 11 | #define REG_FIFO_ADDR_PTR 0x0d |
gov1 | 0:a761fba7f8a8 | 12 | #define REG_FIFO_TX_BASE_ADDR 0x0e |
gov1 | 0:a761fba7f8a8 | 13 | #define REG_FIFO_RX_BASE_ADDR 0x0f |
gov1 | 0:a761fba7f8a8 | 14 | #define REG_FIFO_RX_CURRENT_ADDR 0x10 |
gov1 | 0:a761fba7f8a8 | 15 | #define REG_IRQ_FLAGS 0x12 |
gov1 | 0:a761fba7f8a8 | 16 | #define REG_RX_NB_BYTES 0x13 |
gov1 | 0:a761fba7f8a8 | 17 | #define REG_PKT_RSSI_VALUE 0x1a |
gov1 | 0:a761fba7f8a8 | 18 | #define REG_PKT_SNR_VALUE 0x1b |
gov1 | 0:a761fba7f8a8 | 19 | #define REG_MODEM_CONFIG_1 0x1d |
gov1 | 0:a761fba7f8a8 | 20 | #define REG_MODEM_CONFIG_2 0x1e |
gov1 | 0:a761fba7f8a8 | 21 | #define REG_PREAMBLE_MSB 0x20 |
gov1 | 0:a761fba7f8a8 | 22 | #define REG_PREAMBLE_LSB 0x21 |
gov1 | 0:a761fba7f8a8 | 23 | #define REG_PAYLOAD_LENGTH 0x22 |
gov1 | 0:a761fba7f8a8 | 24 | #define REG_MODEM_CONFIG_3 0x26 |
gov1 | 0:a761fba7f8a8 | 25 | #define REG_RSSI_WIDEBAND 0x2c |
gov1 | 0:a761fba7f8a8 | 26 | #define REG_DETECTION_OPTIMIZE 0x31 |
gov1 | 0:a761fba7f8a8 | 27 | #define REG_DETECTION_THRESHOLD 0x37 |
gov1 | 0:a761fba7f8a8 | 28 | #define REG_SYNC_WORD 0x39 |
gov1 | 0:a761fba7f8a8 | 29 | #define REG_DIO_MAPPING_1 0x40 |
gov1 | 0:a761fba7f8a8 | 30 | #define REG_VERSION 0x42 |
gov1 | 0:a761fba7f8a8 | 31 | |
gov1 | 0:a761fba7f8a8 | 32 | // modes |
gov1 | 0:a761fba7f8a8 | 33 | #define MODE_LONG_RANGE_MODE 0x80 |
gov1 | 0:a761fba7f8a8 | 34 | #define MODE_SLEEP 0x00 |
gov1 | 0:a761fba7f8a8 | 35 | #define MODE_STDBY 0x01 |
gov1 | 0:a761fba7f8a8 | 36 | #define MODE_TX 0x03 |
gov1 | 0:a761fba7f8a8 | 37 | #define MODE_RX_CONTINUOUS 0x05 |
gov1 | 0:a761fba7f8a8 | 38 | #define MODE_RX_SINGLE 0x06 |
gov1 | 0:a761fba7f8a8 | 39 | |
gov1 | 0:a761fba7f8a8 | 40 | // PA config |
gov1 | 0:a761fba7f8a8 | 41 | #define PA_BOOST 0x80 |
gov1 | 0:a761fba7f8a8 | 42 | |
gov1 | 0:a761fba7f8a8 | 43 | // IRQ masks |
gov1 | 0:a761fba7f8a8 | 44 | #define IRQ_TX_DONE_MASK 0x08 |
gov1 | 0:a761fba7f8a8 | 45 | #define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20 |
gov1 | 0:a761fba7f8a8 | 46 | #define IRQ_RX_DONE_MASK 0x40 |
gov1 | 0:a761fba7f8a8 | 47 | |
gov1 | 0:a761fba7f8a8 | 48 | #define MAX_PKT_LENGTH 255 |
gov1 | 0:a761fba7f8a8 | 49 | |
gov1 | 0:a761fba7f8a8 | 50 | SPI _spi(P5_1, P5_2, P5_0); |
gov1 | 0:a761fba7f8a8 | 51 | |
gov1 | 0:a761fba7f8a8 | 52 | LoRaClass::LoRaClass() : |
gov1 | 0:a761fba7f8a8 | 53 | spi(_spi), |
gov1 | 0:a761fba7f8a8 | 54 | _ss(LORA_DEFAULT_SS_PIN ), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), |
gov1 | 0:a761fba7f8a8 | 55 | _frequency(0), |
gov1 | 0:a761fba7f8a8 | 56 | _packetIndex(0), |
gov1 | 0:a761fba7f8a8 | 57 | _implicitHeaderMode(0), |
gov1 | 0:a761fba7f8a8 | 58 | _onReceive(NULL) |
gov1 | 0:a761fba7f8a8 | 59 | { |
gov1 | 0:a761fba7f8a8 | 60 | // overide Stream timeout value |
gov1 | 0:a761fba7f8a8 | 61 | //setTimeout(0); |
gov1 | 0:a761fba7f8a8 | 62 | } |
gov1 | 0:a761fba7f8a8 | 63 | |
gov1 | 0:a761fba7f8a8 | 64 | int LoRaClass::begin(long frequency) |
gov1 | 0:a761fba7f8a8 | 65 | { |
gov1 | 0:a761fba7f8a8 | 66 | // perform reset |
gov1 | 0:a761fba7f8a8 | 67 | _reset = 0; |
gov1 | 0:a761fba7f8a8 | 68 | wait(0.010); |
gov1 | 0:a761fba7f8a8 | 69 | _reset = 1; |
gov1 | 0:a761fba7f8a8 | 70 | wait(0.010); |
gov1 | 0:a761fba7f8a8 | 71 | |
gov1 | 0:a761fba7f8a8 | 72 | // set SS high |
gov1 | 0:a761fba7f8a8 | 73 | _ss = 1; |
gov1 | 0:a761fba7f8a8 | 74 | |
gov1 | 0:a761fba7f8a8 | 75 | // check version |
gov1 | 0:a761fba7f8a8 | 76 | uint8_t version = readRegister(REG_VERSION); |
gov1 | 0:a761fba7f8a8 | 77 | if (version != 0x12) { |
gov1 | 0:a761fba7f8a8 | 78 | return 0; |
gov1 | 0:a761fba7f8a8 | 79 | } |
gov1 | 0:a761fba7f8a8 | 80 | |
gov1 | 0:a761fba7f8a8 | 81 | // put in sleep mode |
gov1 | 0:a761fba7f8a8 | 82 | sleep(); |
gov1 | 0:a761fba7f8a8 | 83 | |
gov1 | 0:a761fba7f8a8 | 84 | // set frequency |
gov1 | 0:a761fba7f8a8 | 85 | setFrequency(frequency); |
gov1 | 0:a761fba7f8a8 | 86 | |
gov1 | 0:a761fba7f8a8 | 87 | // set base addresses |
gov1 | 0:a761fba7f8a8 | 88 | writeRegister(REG_FIFO_TX_BASE_ADDR, 0); |
gov1 | 0:a761fba7f8a8 | 89 | writeRegister(REG_FIFO_RX_BASE_ADDR, 0); |
gov1 | 0:a761fba7f8a8 | 90 | |
gov1 | 0:a761fba7f8a8 | 91 | // set LNA boost |
gov1 | 0:a761fba7f8a8 | 92 | writeRegister(REG_LNA, readRegister(REG_LNA) | 0x03); |
gov1 | 0:a761fba7f8a8 | 93 | |
gov1 | 0:a761fba7f8a8 | 94 | // set auto AGC |
gov1 | 0:a761fba7f8a8 | 95 | writeRegister(REG_MODEM_CONFIG_3, 0x04); |
gov1 | 0:a761fba7f8a8 | 96 | |
gov1 | 0:a761fba7f8a8 | 97 | // set output power to 17 dBm |
gov1 | 0:a761fba7f8a8 | 98 | setTxPower(17); |
gov1 | 0:a761fba7f8a8 | 99 | |
gov1 | 0:a761fba7f8a8 | 100 | // put in standby mode |
gov1 | 0:a761fba7f8a8 | 101 | idle(); |
gov1 | 0:a761fba7f8a8 | 102 | |
gov1 | 0:a761fba7f8a8 | 103 | return 1; |
gov1 | 0:a761fba7f8a8 | 104 | } |
gov1 | 0:a761fba7f8a8 | 105 | |
gov1 | 0:a761fba7f8a8 | 106 | void LoRaClass::end() |
gov1 | 0:a761fba7f8a8 | 107 | { |
gov1 | 0:a761fba7f8a8 | 108 | // put in sleep mode |
gov1 | 0:a761fba7f8a8 | 109 | sleep(); |
gov1 | 0:a761fba7f8a8 | 110 | } |
gov1 | 0:a761fba7f8a8 | 111 | |
gov1 | 0:a761fba7f8a8 | 112 | int LoRaClass::beginPacket(int implicitHeader) |
gov1 | 0:a761fba7f8a8 | 113 | { |
gov1 | 0:a761fba7f8a8 | 114 | // put in standby mode |
gov1 | 0:a761fba7f8a8 | 115 | idle(); |
gov1 | 0:a761fba7f8a8 | 116 | |
gov1 | 0:a761fba7f8a8 | 117 | if (implicitHeader) { |
gov1 | 0:a761fba7f8a8 | 118 | implicitHeaderMode(); |
gov1 | 0:a761fba7f8a8 | 119 | } else { |
gov1 | 0:a761fba7f8a8 | 120 | explicitHeaderMode(); |
gov1 | 0:a761fba7f8a8 | 121 | } |
gov1 | 0:a761fba7f8a8 | 122 | |
gov1 | 0:a761fba7f8a8 | 123 | // reset FIFO address and paload length |
gov1 | 0:a761fba7f8a8 | 124 | writeRegister(REG_FIFO_ADDR_PTR, 0); |
gov1 | 0:a761fba7f8a8 | 125 | writeRegister(REG_PAYLOAD_LENGTH, 0); |
gov1 | 0:a761fba7f8a8 | 126 | |
gov1 | 0:a761fba7f8a8 | 127 | return 1; |
gov1 | 0:a761fba7f8a8 | 128 | } |
gov1 | 0:a761fba7f8a8 | 129 | |
gov1 | 0:a761fba7f8a8 | 130 | int LoRaClass::endPacket() |
gov1 | 0:a761fba7f8a8 | 131 | { |
gov1 | 0:a761fba7f8a8 | 132 | // put in TX mode |
gov1 | 0:a761fba7f8a8 | 133 | writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX); |
gov1 | 0:a761fba7f8a8 | 134 | |
gov1 | 0:a761fba7f8a8 | 135 | // wait for TX done |
gov1 | 0:a761fba7f8a8 | 136 | while((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0); |
gov1 | 0:a761fba7f8a8 | 137 | |
gov1 | 0:a761fba7f8a8 | 138 | // clear IRQ's |
gov1 | 0:a761fba7f8a8 | 139 | writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); |
gov1 | 0:a761fba7f8a8 | 140 | |
gov1 | 0:a761fba7f8a8 | 141 | return 1; |
gov1 | 0:a761fba7f8a8 | 142 | } |
gov1 | 0:a761fba7f8a8 | 143 | |
gov1 | 0:a761fba7f8a8 | 144 | int LoRaClass::parsePacket(int size) |
gov1 | 0:a761fba7f8a8 | 145 | { |
gov1 | 0:a761fba7f8a8 | 146 | int packetLength = 0; |
gov1 | 0:a761fba7f8a8 | 147 | int irqFlags = readRegister(REG_IRQ_FLAGS); |
gov1 | 0:a761fba7f8a8 | 148 | |
gov1 | 0:a761fba7f8a8 | 149 | if (size > 0) { |
gov1 | 0:a761fba7f8a8 | 150 | implicitHeaderMode(); |
gov1 | 0:a761fba7f8a8 | 151 | |
gov1 | 0:a761fba7f8a8 | 152 | writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); |
gov1 | 0:a761fba7f8a8 | 153 | } else { |
gov1 | 0:a761fba7f8a8 | 154 | explicitHeaderMode(); |
gov1 | 0:a761fba7f8a8 | 155 | } |
gov1 | 0:a761fba7f8a8 | 156 | |
gov1 | 0:a761fba7f8a8 | 157 | // clear IRQ's |
gov1 | 0:a761fba7f8a8 | 158 | writeRegister(REG_IRQ_FLAGS, irqFlags); |
gov1 | 0:a761fba7f8a8 | 159 | |
gov1 | 0:a761fba7f8a8 | 160 | if ((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) { |
gov1 | 0:a761fba7f8a8 | 161 | // received a packet |
gov1 | 0:a761fba7f8a8 | 162 | _packetIndex = 0; |
gov1 | 0:a761fba7f8a8 | 163 | |
gov1 | 0:a761fba7f8a8 | 164 | // read packet length |
gov1 | 0:a761fba7f8a8 | 165 | if (_implicitHeaderMode) { |
gov1 | 0:a761fba7f8a8 | 166 | packetLength = readRegister(REG_PAYLOAD_LENGTH); |
gov1 | 0:a761fba7f8a8 | 167 | } else { |
gov1 | 0:a761fba7f8a8 | 168 | packetLength = readRegister(REG_RX_NB_BYTES); |
gov1 | 0:a761fba7f8a8 | 169 | } |
gov1 | 0:a761fba7f8a8 | 170 | |
gov1 | 0:a761fba7f8a8 | 171 | // set FIFO address to current RX address |
gov1 | 0:a761fba7f8a8 | 172 | writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); |
gov1 | 0:a761fba7f8a8 | 173 | |
gov1 | 0:a761fba7f8a8 | 174 | // put in standby mode |
gov1 | 0:a761fba7f8a8 | 175 | idle(); |
gov1 | 0:a761fba7f8a8 | 176 | } else if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) { |
gov1 | 0:a761fba7f8a8 | 177 | // not currently in RX mode |
gov1 | 0:a761fba7f8a8 | 178 | |
gov1 | 0:a761fba7f8a8 | 179 | // reset FIFO address |
gov1 | 0:a761fba7f8a8 | 180 | writeRegister(REG_FIFO_ADDR_PTR, 0); |
gov1 | 0:a761fba7f8a8 | 181 | |
gov1 | 0:a761fba7f8a8 | 182 | // put in single RX mode |
gov1 | 0:a761fba7f8a8 | 183 | writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE); |
gov1 | 0:a761fba7f8a8 | 184 | } |
gov1 | 0:a761fba7f8a8 | 185 | |
gov1 | 0:a761fba7f8a8 | 186 | return packetLength; |
gov1 | 0:a761fba7f8a8 | 187 | } |
gov1 | 0:a761fba7f8a8 | 188 | |
gov1 | 0:a761fba7f8a8 | 189 | int LoRaClass::packetRssi() |
gov1 | 0:a761fba7f8a8 | 190 | { |
gov1 | 0:a761fba7f8a8 | 191 | return (readRegister(REG_PKT_RSSI_VALUE) - (_frequency < 868E6 ? 164 : 157)); |
gov1 | 0:a761fba7f8a8 | 192 | } |
gov1 | 0:a761fba7f8a8 | 193 | |
gov1 | 0:a761fba7f8a8 | 194 | float LoRaClass::packetSnr() |
gov1 | 0:a761fba7f8a8 | 195 | { |
gov1 | 0:a761fba7f8a8 | 196 | return ((int8_t)readRegister(REG_PKT_SNR_VALUE)) * 0.25; |
gov1 | 0:a761fba7f8a8 | 197 | } |
gov1 | 0:a761fba7f8a8 | 198 | |
gov1 | 0:a761fba7f8a8 | 199 | int LoRaClass::_putc(int value) |
gov1 | 0:a761fba7f8a8 | 200 | { |
gov1 | 0:a761fba7f8a8 | 201 | char buf = (char) value; |
gov1 | 0:a761fba7f8a8 | 202 | size_t size = sizeof(buf); |
gov1 | 0:a761fba7f8a8 | 203 | int currentLength = readRegister(REG_PAYLOAD_LENGTH); |
gov1 | 0:a761fba7f8a8 | 204 | |
gov1 | 0:a761fba7f8a8 | 205 | // check size |
gov1 | 0:a761fba7f8a8 | 206 | if ((currentLength + size) > MAX_PKT_LENGTH) { |
gov1 | 0:a761fba7f8a8 | 207 | size = MAX_PKT_LENGTH - currentLength; |
gov1 | 0:a761fba7f8a8 | 208 | } |
gov1 | 0:a761fba7f8a8 | 209 | |
gov1 | 0:a761fba7f8a8 | 210 | writeRegister(REG_FIFO, buf); |
gov1 | 0:a761fba7f8a8 | 211 | |
gov1 | 0:a761fba7f8a8 | 212 | // update length |
gov1 | 0:a761fba7f8a8 | 213 | writeRegister(REG_PAYLOAD_LENGTH, currentLength + size); |
gov1 | 0:a761fba7f8a8 | 214 | |
gov1 | 0:a761fba7f8a8 | 215 | return (int) buf; |
gov1 | 0:a761fba7f8a8 | 216 | } |
gov1 | 0:a761fba7f8a8 | 217 | |
gov1 | 0:a761fba7f8a8 | 218 | int LoRaClass::available() |
gov1 | 0:a761fba7f8a8 | 219 | { |
gov1 | 0:a761fba7f8a8 | 220 | return (readRegister(REG_RX_NB_BYTES) - _packetIndex); |
gov1 | 0:a761fba7f8a8 | 221 | } |
gov1 | 0:a761fba7f8a8 | 222 | |
gov1 | 0:a761fba7f8a8 | 223 | int LoRaClass::_getc() |
gov1 | 0:a761fba7f8a8 | 224 | { |
gov1 | 0:a761fba7f8a8 | 225 | if (!available()) { |
gov1 | 0:a761fba7f8a8 | 226 | return -1; |
gov1 | 0:a761fba7f8a8 | 227 | } |
gov1 | 0:a761fba7f8a8 | 228 | |
gov1 | 0:a761fba7f8a8 | 229 | _packetIndex++; |
gov1 | 0:a761fba7f8a8 | 230 | |
gov1 | 0:a761fba7f8a8 | 231 | return readRegister(REG_FIFO); |
gov1 | 0:a761fba7f8a8 | 232 | } |
gov1 | 0:a761fba7f8a8 | 233 | |
gov1 | 0:a761fba7f8a8 | 234 | int LoRaClass::peek() |
gov1 | 0:a761fba7f8a8 | 235 | { |
gov1 | 0:a761fba7f8a8 | 236 | if (!available()) { |
gov1 | 0:a761fba7f8a8 | 237 | return -1; |
gov1 | 0:a761fba7f8a8 | 238 | } |
gov1 | 0:a761fba7f8a8 | 239 | |
gov1 | 0:a761fba7f8a8 | 240 | // store current FIFO address |
gov1 | 0:a761fba7f8a8 | 241 | int currentAddress = readRegister(REG_FIFO_ADDR_PTR); |
gov1 | 0:a761fba7f8a8 | 242 | |
gov1 | 0:a761fba7f8a8 | 243 | // read |
gov1 | 0:a761fba7f8a8 | 244 | uint8_t b = readRegister(REG_FIFO); |
gov1 | 0:a761fba7f8a8 | 245 | |
gov1 | 0:a761fba7f8a8 | 246 | // restore FIFO address |
gov1 | 0:a761fba7f8a8 | 247 | writeRegister(REG_FIFO_ADDR_PTR, currentAddress); |
gov1 | 0:a761fba7f8a8 | 248 | |
gov1 | 0:a761fba7f8a8 | 249 | return b; |
gov1 | 0:a761fba7f8a8 | 250 | } |
gov1 | 0:a761fba7f8a8 | 251 | |
gov1 | 0:a761fba7f8a8 | 252 | void LoRaClass::onReceive(void(*callback)(int)) |
gov1 | 0:a761fba7f8a8 | 253 | { |
gov1 | 0:a761fba7f8a8 | 254 | _onReceive = callback; |
gov1 | 0:a761fba7f8a8 | 255 | |
gov1 | 0:a761fba7f8a8 | 256 | if (callback) { |
gov1 | 0:a761fba7f8a8 | 257 | writeRegister(REG_DIO_MAPPING_1, 0x00); |
gov1 | 0:a761fba7f8a8 | 258 | |
gov1 | 0:a761fba7f8a8 | 259 | //attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); |
gov1 | 0:a761fba7f8a8 | 260 | _dio0.rise(&LoRaClass::onDio0Rise); |
gov1 | 0:a761fba7f8a8 | 261 | } else { |
gov1 | 0:a761fba7f8a8 | 262 | //detachInterrupt(digitalPinToInterrupt(_dio0)); |
gov1 | 0:a761fba7f8a8 | 263 | _dio0.rise(NULL); |
gov1 | 0:a761fba7f8a8 | 264 | } |
gov1 | 0:a761fba7f8a8 | 265 | } |
gov1 | 0:a761fba7f8a8 | 266 | |
gov1 | 0:a761fba7f8a8 | 267 | void LoRaClass::receive(int size) |
gov1 | 0:a761fba7f8a8 | 268 | { |
gov1 | 0:a761fba7f8a8 | 269 | if (size > 0) { |
gov1 | 0:a761fba7f8a8 | 270 | implicitHeaderMode(); |
gov1 | 0:a761fba7f8a8 | 271 | |
gov1 | 0:a761fba7f8a8 | 272 | writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); |
gov1 | 0:a761fba7f8a8 | 273 | } else { |
gov1 | 0:a761fba7f8a8 | 274 | explicitHeaderMode(); |
gov1 | 0:a761fba7f8a8 | 275 | } |
gov1 | 0:a761fba7f8a8 | 276 | |
gov1 | 0:a761fba7f8a8 | 277 | writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS); |
gov1 | 0:a761fba7f8a8 | 278 | } |
gov1 | 0:a761fba7f8a8 | 279 | |
gov1 | 0:a761fba7f8a8 | 280 | void LoRaClass::idle() |
gov1 | 0:a761fba7f8a8 | 281 | { |
gov1 | 0:a761fba7f8a8 | 282 | writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY); |
gov1 | 0:a761fba7f8a8 | 283 | } |
gov1 | 0:a761fba7f8a8 | 284 | |
gov1 | 0:a761fba7f8a8 | 285 | void LoRaClass::sleep() |
gov1 | 0:a761fba7f8a8 | 286 | { |
gov1 | 0:a761fba7f8a8 | 287 | writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP); |
gov1 | 0:a761fba7f8a8 | 288 | } |
gov1 | 0:a761fba7f8a8 | 289 | |
gov1 | 0:a761fba7f8a8 | 290 | void LoRaClass::setTxPower(int level, int outputPin) |
gov1 | 0:a761fba7f8a8 | 291 | { |
gov1 | 0:a761fba7f8a8 | 292 | if (PA_OUTPUT_RFO_PIN == outputPin) { |
gov1 | 0:a761fba7f8a8 | 293 | // RFO |
gov1 | 0:a761fba7f8a8 | 294 | if (level < 0) { |
gov1 | 0:a761fba7f8a8 | 295 | level = 0; |
gov1 | 0:a761fba7f8a8 | 296 | } else if (level > 14) { |
gov1 | 0:a761fba7f8a8 | 297 | level = 14; |
gov1 | 0:a761fba7f8a8 | 298 | } |
gov1 | 0:a761fba7f8a8 | 299 | |
gov1 | 0:a761fba7f8a8 | 300 | writeRegister(REG_PA_CONFIG, 0x70 | level); |
gov1 | 0:a761fba7f8a8 | 301 | } else { |
gov1 | 0:a761fba7f8a8 | 302 | // PA BOOST |
gov1 | 0:a761fba7f8a8 | 303 | if (level < 2) { |
gov1 | 0:a761fba7f8a8 | 304 | level = 2; |
gov1 | 0:a761fba7f8a8 | 305 | } else if (level > 17) { |
gov1 | 0:a761fba7f8a8 | 306 | level = 17; |
gov1 | 0:a761fba7f8a8 | 307 | } |
gov1 | 0:a761fba7f8a8 | 308 | |
gov1 | 0:a761fba7f8a8 | 309 | writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2)); |
gov1 | 0:a761fba7f8a8 | 310 | } |
gov1 | 0:a761fba7f8a8 | 311 | } |
gov1 | 0:a761fba7f8a8 | 312 | |
gov1 | 0:a761fba7f8a8 | 313 | void LoRaClass::setFrequency(long frequency) |
gov1 | 0:a761fba7f8a8 | 314 | { |
gov1 | 0:a761fba7f8a8 | 315 | _frequency = frequency; |
gov1 | 0:a761fba7f8a8 | 316 | |
gov1 | 0:a761fba7f8a8 | 317 | uint64_t frf = ((uint64_t)frequency << 19) / 32000000; |
gov1 | 0:a761fba7f8a8 | 318 | |
gov1 | 0:a761fba7f8a8 | 319 | writeRegister(REG_FRF_MSB, (uint8_t)(frf >> 16)); |
gov1 | 0:a761fba7f8a8 | 320 | writeRegister(REG_FRF_MID, (uint8_t)(frf >> 8)); |
gov1 | 0:a761fba7f8a8 | 321 | writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0)); |
gov1 | 0:a761fba7f8a8 | 322 | } |
gov1 | 0:a761fba7f8a8 | 323 | |
gov1 | 0:a761fba7f8a8 | 324 | void LoRaClass::setSpreadingFactor(int sf) |
gov1 | 0:a761fba7f8a8 | 325 | { |
gov1 | 0:a761fba7f8a8 | 326 | if (sf < 6) { |
gov1 | 0:a761fba7f8a8 | 327 | sf = 6; |
gov1 | 0:a761fba7f8a8 | 328 | } else if (sf > 12) { |
gov1 | 0:a761fba7f8a8 | 329 | sf = 12; |
gov1 | 0:a761fba7f8a8 | 330 | } |
gov1 | 0:a761fba7f8a8 | 331 | |
gov1 | 0:a761fba7f8a8 | 332 | if (sf == 6) { |
gov1 | 0:a761fba7f8a8 | 333 | writeRegister(REG_DETECTION_OPTIMIZE, 0xc5); |
gov1 | 0:a761fba7f8a8 | 334 | writeRegister(REG_DETECTION_THRESHOLD, 0x0c); |
gov1 | 0:a761fba7f8a8 | 335 | } else { |
gov1 | 0:a761fba7f8a8 | 336 | writeRegister(REG_DETECTION_OPTIMIZE, 0xc3); |
gov1 | 0:a761fba7f8a8 | 337 | writeRegister(REG_DETECTION_THRESHOLD, 0x0a); |
gov1 | 0:a761fba7f8a8 | 338 | } |
gov1 | 0:a761fba7f8a8 | 339 | |
gov1 | 0:a761fba7f8a8 | 340 | writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0)); |
gov1 | 0:a761fba7f8a8 | 341 | } |
gov1 | 0:a761fba7f8a8 | 342 | |
gov1 | 0:a761fba7f8a8 | 343 | void LoRaClass::setSignalBandwidth(long sbw) |
gov1 | 0:a761fba7f8a8 | 344 | { |
gov1 | 0:a761fba7f8a8 | 345 | int bw; |
gov1 | 0:a761fba7f8a8 | 346 | |
gov1 | 0:a761fba7f8a8 | 347 | if (sbw <= 7.8E3) { |
gov1 | 0:a761fba7f8a8 | 348 | bw = 0; |
gov1 | 0:a761fba7f8a8 | 349 | } else if (sbw <= 10.4E3) { |
gov1 | 0:a761fba7f8a8 | 350 | bw = 1; |
gov1 | 0:a761fba7f8a8 | 351 | } else if (sbw <= 15.6E3) { |
gov1 | 0:a761fba7f8a8 | 352 | bw = 2; |
gov1 | 0:a761fba7f8a8 | 353 | } else if (sbw <= 20.8E3) { |
gov1 | 0:a761fba7f8a8 | 354 | bw = 3; |
gov1 | 0:a761fba7f8a8 | 355 | } else if (sbw <= 31.25E3) { |
gov1 | 0:a761fba7f8a8 | 356 | bw = 4; |
gov1 | 0:a761fba7f8a8 | 357 | } else if (sbw <= 41.7E3) { |
gov1 | 0:a761fba7f8a8 | 358 | bw = 5; |
gov1 | 0:a761fba7f8a8 | 359 | } else if (sbw <= 62.5E3) { |
gov1 | 0:a761fba7f8a8 | 360 | bw = 6; |
gov1 | 0:a761fba7f8a8 | 361 | } else if (sbw <= 125E3) { |
gov1 | 0:a761fba7f8a8 | 362 | bw = 7; |
gov1 | 0:a761fba7f8a8 | 363 | } else if (sbw <= 250E3) { |
gov1 | 0:a761fba7f8a8 | 364 | bw = 8; |
gov1 | 0:a761fba7f8a8 | 365 | } else /*if (sbw <= 250E3)*/ { |
gov1 | 0:a761fba7f8a8 | 366 | bw = 9; |
gov1 | 0:a761fba7f8a8 | 367 | } |
gov1 | 0:a761fba7f8a8 | 368 | |
gov1 | 0:a761fba7f8a8 | 369 | writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4)); |
gov1 | 0:a761fba7f8a8 | 370 | } |
gov1 | 0:a761fba7f8a8 | 371 | |
gov1 | 0:a761fba7f8a8 | 372 | void LoRaClass::setCodingRate4(int denominator) |
gov1 | 0:a761fba7f8a8 | 373 | { |
gov1 | 0:a761fba7f8a8 | 374 | if (denominator < 5) { |
gov1 | 0:a761fba7f8a8 | 375 | denominator = 5; |
gov1 | 0:a761fba7f8a8 | 376 | } else if (denominator > 8) { |
gov1 | 0:a761fba7f8a8 | 377 | denominator = 8; |
gov1 | 0:a761fba7f8a8 | 378 | } |
gov1 | 0:a761fba7f8a8 | 379 | |
gov1 | 0:a761fba7f8a8 | 380 | int cr = denominator - 4; |
gov1 | 0:a761fba7f8a8 | 381 | |
gov1 | 0:a761fba7f8a8 | 382 | writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1)); |
gov1 | 0:a761fba7f8a8 | 383 | } |
gov1 | 0:a761fba7f8a8 | 384 | |
gov1 | 0:a761fba7f8a8 | 385 | void LoRaClass::setPreambleLength(long length) |
gov1 | 0:a761fba7f8a8 | 386 | { |
gov1 | 0:a761fba7f8a8 | 387 | writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8)); |
gov1 | 0:a761fba7f8a8 | 388 | writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0)); |
gov1 | 0:a761fba7f8a8 | 389 | } |
gov1 | 0:a761fba7f8a8 | 390 | |
gov1 | 0:a761fba7f8a8 | 391 | void LoRaClass::setSyncWord(int sw) |
gov1 | 0:a761fba7f8a8 | 392 | { |
gov1 | 0:a761fba7f8a8 | 393 | writeRegister(REG_SYNC_WORD, sw); |
gov1 | 0:a761fba7f8a8 | 394 | } |
gov1 | 0:a761fba7f8a8 | 395 | |
gov1 | 0:a761fba7f8a8 | 396 | void LoRaClass::enableCrc() |
gov1 | 0:a761fba7f8a8 | 397 | { |
gov1 | 0:a761fba7f8a8 | 398 | writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) | 0x04); |
gov1 | 0:a761fba7f8a8 | 399 | } |
gov1 | 0:a761fba7f8a8 | 400 | |
gov1 | 0:a761fba7f8a8 | 401 | void LoRaClass::disableCrc() |
gov1 | 0:a761fba7f8a8 | 402 | { |
gov1 | 0:a761fba7f8a8 | 403 | writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb); |
gov1 | 0:a761fba7f8a8 | 404 | } |
gov1 | 0:a761fba7f8a8 | 405 | |
gov1 | 0:a761fba7f8a8 | 406 | uint8_t LoRaClass::random() |
gov1 | 0:a761fba7f8a8 | 407 | { |
gov1 | 0:a761fba7f8a8 | 408 | return readRegister(REG_RSSI_WIDEBAND); |
gov1 | 0:a761fba7f8a8 | 409 | } |
gov1 | 0:a761fba7f8a8 | 410 | |
gov1 | 0:a761fba7f8a8 | 411 | void LoRaClass::dumpRegisters(Stream& out) |
gov1 | 0:a761fba7f8a8 | 412 | { |
gov1 | 0:a761fba7f8a8 | 413 | for (int i = 0; i < 128; i++) { |
gov1 | 0:a761fba7f8a8 | 414 | out.printf("0x%x: 0x%x", i, readRegister(i)); |
gov1 | 0:a761fba7f8a8 | 415 | } |
gov1 | 0:a761fba7f8a8 | 416 | } |
gov1 | 0:a761fba7f8a8 | 417 | |
gov1 | 0:a761fba7f8a8 | 418 | void LoRaClass::explicitHeaderMode() |
gov1 | 0:a761fba7f8a8 | 419 | { |
gov1 | 0:a761fba7f8a8 | 420 | _implicitHeaderMode = 0; |
gov1 | 0:a761fba7f8a8 | 421 | |
gov1 | 0:a761fba7f8a8 | 422 | writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) & 0xfe); |
gov1 | 0:a761fba7f8a8 | 423 | } |
gov1 | 0:a761fba7f8a8 | 424 | |
gov1 | 0:a761fba7f8a8 | 425 | void LoRaClass::implicitHeaderMode() |
gov1 | 0:a761fba7f8a8 | 426 | { |
gov1 | 0:a761fba7f8a8 | 427 | _implicitHeaderMode = 1; |
gov1 | 0:a761fba7f8a8 | 428 | |
gov1 | 0:a761fba7f8a8 | 429 | writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) | 0x01); |
gov1 | 0:a761fba7f8a8 | 430 | } |
gov1 | 0:a761fba7f8a8 | 431 | |
gov1 | 0:a761fba7f8a8 | 432 | void LoRaClass::handleDio0Rise() |
gov1 | 0:a761fba7f8a8 | 433 | { |
gov1 | 0:a761fba7f8a8 | 434 | int irqFlags = readRegister(REG_IRQ_FLAGS); |
gov1 | 0:a761fba7f8a8 | 435 | |
gov1 | 0:a761fba7f8a8 | 436 | // clear IRQ's |
gov1 | 0:a761fba7f8a8 | 437 | writeRegister(REG_IRQ_FLAGS, irqFlags); |
gov1 | 0:a761fba7f8a8 | 438 | |
gov1 | 0:a761fba7f8a8 | 439 | if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) { |
gov1 | 0:a761fba7f8a8 | 440 | // received a packet |
gov1 | 0:a761fba7f8a8 | 441 | _packetIndex = 0; |
gov1 | 0:a761fba7f8a8 | 442 | |
gov1 | 0:a761fba7f8a8 | 443 | // read packet length |
gov1 | 0:a761fba7f8a8 | 444 | int packetLength = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH) : readRegister(REG_RX_NB_BYTES); |
gov1 | 0:a761fba7f8a8 | 445 | |
gov1 | 0:a761fba7f8a8 | 446 | // set FIFO address to current RX address |
gov1 | 0:a761fba7f8a8 | 447 | writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); |
gov1 | 0:a761fba7f8a8 | 448 | |
gov1 | 0:a761fba7f8a8 | 449 | if (_onReceive) { |
gov1 | 0:a761fba7f8a8 | 450 | _onReceive(packetLength); |
gov1 | 0:a761fba7f8a8 | 451 | } |
gov1 | 0:a761fba7f8a8 | 452 | |
gov1 | 0:a761fba7f8a8 | 453 | // reset FIFO address |
gov1 | 0:a761fba7f8a8 | 454 | writeRegister(REG_FIFO_ADDR_PTR, 0); |
gov1 | 0:a761fba7f8a8 | 455 | } |
gov1 | 0:a761fba7f8a8 | 456 | } |
gov1 | 0:a761fba7f8a8 | 457 | |
gov1 | 0:a761fba7f8a8 | 458 | uint8_t LoRaClass::readRegister(uint8_t address) |
gov1 | 0:a761fba7f8a8 | 459 | { |
gov1 | 0:a761fba7f8a8 | 460 | return singleTransfer(address & 0x7f, 0x00); |
gov1 | 0:a761fba7f8a8 | 461 | } |
gov1 | 0:a761fba7f8a8 | 462 | |
gov1 | 0:a761fba7f8a8 | 463 | void LoRaClass::writeRegister(uint8_t address, uint8_t value) |
gov1 | 0:a761fba7f8a8 | 464 | { |
gov1 | 0:a761fba7f8a8 | 465 | singleTransfer(address | 0x80, value); |
gov1 | 0:a761fba7f8a8 | 466 | } |
gov1 | 0:a761fba7f8a8 | 467 | |
gov1 | 0:a761fba7f8a8 | 468 | uint8_t LoRaClass::singleTransfer(uint8_t address, uint8_t value) |
gov1 | 0:a761fba7f8a8 | 469 | { |
gov1 | 0:a761fba7f8a8 | 470 | uint8_t response; |
gov1 | 0:a761fba7f8a8 | 471 | |
gov1 | 0:a761fba7f8a8 | 472 | _ss = 0; |
gov1 | 0:a761fba7f8a8 | 473 | |
gov1 | 0:a761fba7f8a8 | 474 | spi.write(address); |
gov1 | 0:a761fba7f8a8 | 475 | response = spi.write(value); |
gov1 | 0:a761fba7f8a8 | 476 | |
gov1 | 0:a761fba7f8a8 | 477 | _ss = 1; |
gov1 | 0:a761fba7f8a8 | 478 | |
gov1 | 0:a761fba7f8a8 | 479 | return response; |
gov1 | 0:a761fba7f8a8 | 480 | } |
gov1 | 0:a761fba7f8a8 | 481 | |
gov1 | 0:a761fba7f8a8 | 482 | void LoRaClass::onDio0Rise() |
gov1 | 0:a761fba7f8a8 | 483 | { |
gov1 | 0:a761fba7f8a8 | 484 | LoRa.handleDio0Rise(); |
gov1 | 0:a761fba7f8a8 | 485 | } |
gov1 | 0:a761fba7f8a8 | 486 | |
gov1 | 0:a761fba7f8a8 | 487 | LoRaClass LoRa; |