Hardware Abstraction Layer, permitting any LoRa application to use any LoRa radio chip

Dependents:   alarm_slave alarm_master lora_p2p lorawan1v1 ... more

radio chip selection

Radio chip driver is not included, allowing choice of radio device.
If you're using SX1272 or SX1276, then import sx127x driver into your program.
if you're using SX1261 or SX1262, then import sx126x driver into your program.
if you're using SX1280, then import sx1280 driver into your program.
if you're using LR1110, then import LR1110 driver into your program.
If you're using NAmote72 or Murata discovery, then you must import only sx127x driver.
If you're using Type1SJ select target DISCO_L072CZ_LRWAN1 and import sx126x driver into your program.

Pin assigned to arduino LoRa radio shield form-factor

Committer:
Wayne Roberts
Date:
Thu Jun 25 12:39:08 2020 -0700
Revision:
19:94b5382d3fc6
Parent:
17:5f34cbe2ac53
Child:
20:75635d50262e
completed for sx127x unmodulated TX test function

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wayne Roberts 0:9c052ff8dd6a 1 #include "radio.h"
Wayne Roberts 0:9c052ff8dd6a 2 #ifdef SX127x_H
Wayne Roberts 0:9c052ff8dd6a 3
Wayne Roberts 17:5f34cbe2ac53 4 #ifdef DEVICE_LPTICKER
Wayne Roberts 0:9c052ff8dd6a 5 LowPowerTimer Radio::lpt;
Wayne Roberts 17:5f34cbe2ac53 6 LowPowerTimeout TxTimeoutEvent;
Wayne Roberts 17:5f34cbe2ac53 7 #else
Wayne Roberts 17:5f34cbe2ac53 8 Timer Radio::lpt;
Wayne Roberts 17:5f34cbe2ac53 9 Timeout TxTimeoutEvent;
Wayne Roberts 17:5f34cbe2ac53 10 #endif
Wayne Roberts 0:9c052ff8dd6a 11
Wayne Roberts 0:9c052ff8dd6a 12 void Radio::Sleep()
Wayne Roberts 0:9c052ff8dd6a 13 {
Wayne Roberts 0:9c052ff8dd6a 14 radio.set_opmode(RF_OPMODE_SLEEP);
Wayne Roberts 0:9c052ff8dd6a 15 }
Wayne Roberts 0:9c052ff8dd6a 16
Wayne Roberts 0:9c052ff8dd6a 17 void Radio::Standby()
Wayne Roberts 0:9c052ff8dd6a 18 {
Wayne Roberts 0:9c052ff8dd6a 19 radio.set_opmode(RF_OPMODE_STANDBY);
Wayne Roberts 0:9c052ff8dd6a 20 }
Wayne Roberts 0:9c052ff8dd6a 21
Wayne Roberts 0:9c052ff8dd6a 22 bool Radio::CheckRfFrequency(unsigned hz)
Wayne Roberts 0:9c052ff8dd6a 23 {
Wayne Roberts 0:9c052ff8dd6a 24 return true;
Wayne Roberts 0:9c052ff8dd6a 25 }
Wayne Roberts 0:9c052ff8dd6a 26
Wayne Roberts 0:9c052ff8dd6a 27 void Radio::SetChannel(unsigned hz)
Wayne Roberts 0:9c052ff8dd6a 28 {
Wayne Roberts 0:9c052ff8dd6a 29 radio.set_frf_MHz(hz / 1000000.0);
Wayne Roberts 0:9c052ff8dd6a 30 }
Wayne Roberts 0:9c052ff8dd6a 31
Wayne Roberts 0:9c052ff8dd6a 32 float Radio::getFrfMHz()
Wayne Roberts 0:9c052ff8dd6a 33 {
Wayne Roberts 0:9c052ff8dd6a 34 return radio.get_frf_MHz();
Wayne Roberts 0:9c052ff8dd6a 35 }
Wayne Roberts 0:9c052ff8dd6a 36
Wayne Roberts 0:9c052ff8dd6a 37 void SX1272OnTimeoutIrq( void )
Wayne Roberts 0:9c052ff8dd6a 38 {
Wayne Roberts 0:9c052ff8dd6a 39 Radio::radio.set_opmode(RF_OPMODE_STANDBY);
Wayne Roberts 0:9c052ff8dd6a 40 }
Wayne Roberts 0:9c052ff8dd6a 41
Wayne Roberts 0:9c052ff8dd6a 42 void Radio::SetTxContinuousWave(unsigned hz, int8_t dbm, unsigned timeout_us)
Wayne Roberts 0:9c052ff8dd6a 43 {
Wayne Roberts 19:94b5382d3fc6 44 fsk.enable(true);
Wayne Roberts 19:94b5382d3fc6 45 fsk.RegPktConfig2.word = radio.read_u16(REG_FSK_PACKETCONFIG2);
Wayne Roberts 19:94b5382d3fc6 46 fsk.RegPktConfig2.bits.DataModePacket = 0; // continuous mode
Wayne Roberts 19:94b5382d3fc6 47 radio.write_u16(REG_FSK_PACKETCONFIG2, fsk.RegPktConfig2.word);
Wayne Roberts 19:94b5382d3fc6 48 fsk.set_tx_fdev_hz(0); // unmodulated carrier, aka dead carrier
Wayne Roberts 19:94b5382d3fc6 49 SetChannel(hz);
Wayne Roberts 0:9c052ff8dd6a 50 set_tx_dbm(dbm);
Wayne Roberts 19:94b5382d3fc6 51
Wayne Roberts 19:94b5382d3fc6 52 if (timeout_us != 0)
Wayne Roberts 19:94b5382d3fc6 53 TxTimeoutEvent.attach_us(SX1272OnTimeoutIrq, timeout_us);
Wayne Roberts 19:94b5382d3fc6 54
Wayne Roberts 0:9c052ff8dd6a 55 radio.set_opmode(RF_OPMODE_TRANSMITTER);
Wayne Roberts 0:9c052ff8dd6a 56 }
Wayne Roberts 0:9c052ff8dd6a 57
Wayne Roberts 0:9c052ff8dd6a 58 #define LORA_MAC_PRIVATE_SYNCWORD 0x12
Wayne Roberts 0:9c052ff8dd6a 59 #define LORA_MAC_PUBLIC_SYNCWORD 0x34
Wayne Roberts 0:9c052ff8dd6a 60 void Radio::SetPublicNetwork(bool en)
Wayne Roberts 0:9c052ff8dd6a 61 {
Wayne Roberts 0:9c052ff8dd6a 62 radio.write_reg(REG_LR_SYNC_BYTE, en ? LORA_MAC_PUBLIC_SYNCWORD : LORA_MAC_PRIVATE_SYNCWORD);
Wayne Roberts 0:9c052ff8dd6a 63 }
Wayne Roberts 0:9c052ff8dd6a 64
Wayne Roberts 0:9c052ff8dd6a 65 uint32_t Radio::Random(void)
Wayne Roberts 0:9c052ff8dd6a 66 {
Wayne Roberts 0:9c052ff8dd6a 67 uint32_t ret = 0;
Wayne Roberts 0:9c052ff8dd6a 68 unsigned i;
Wayne Roberts 0:9c052ff8dd6a 69
Wayne Roberts 0:9c052ff8dd6a 70 radio.set_opmode(RF_OPMODE_RECEIVER);
Wayne Roberts 0:9c052ff8dd6a 71 for (i = 0; i < 32; i++) {
Wayne Roberts 0:9c052ff8dd6a 72 uint32_t r;
Wayne Roberts 0:9c052ff8dd6a 73 wait_us(3000);
Wayne Roberts 0:9c052ff8dd6a 74 r = radio.read_reg(REG_LR_WIDEBAND_RSSI);
Wayne Roberts 0:9c052ff8dd6a 75 r <<= ((i & 7) << 2);
Wayne Roberts 0:9c052ff8dd6a 76 ret ^= r;
Wayne Roberts 0:9c052ff8dd6a 77 }
Wayne Roberts 0:9c052ff8dd6a 78
Wayne Roberts 0:9c052ff8dd6a 79 return ret;
Wayne Roberts 0:9c052ff8dd6a 80 }
Wayne Roberts 0:9c052ff8dd6a 81
Wayne Roberts 0:9c052ff8dd6a 82 void Radio::LoRaPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn, bool invIQ)
Wayne Roberts 0:9c052ff8dd6a 83 {
Wayne Roberts 0:9c052ff8dd6a 84 lora.RegPreamble = preambleLen;
Wayne Roberts 0:9c052ff8dd6a 85 radio.write_u16(REG_LR_PREAMBLEMSB, lora.RegPreamble);
Wayne Roberts 0:9c052ff8dd6a 86
Wayne Roberts 0:9c052ff8dd6a 87 if (radio.type == SX1276) {
Wayne Roberts 0:9c052ff8dd6a 88 lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn = fixLen;
Wayne Roberts 0:9c052ff8dd6a 89 lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn = crcOn;
Wayne Roberts 0:9c052ff8dd6a 90 radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet);
Wayne Roberts 0:9c052ff8dd6a 91 } else if (radio.type == SX1272) {
Wayne Roberts 0:9c052ff8dd6a 92 lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn = fixLen;
Wayne Roberts 0:9c052ff8dd6a 93 lora.RegModemConfig.sx1272bits.RxPayloadCrcOn = crcOn;
Wayne Roberts 0:9c052ff8dd6a 94 }
Wayne Roberts 0:9c052ff8dd6a 95
Wayne Roberts 0:9c052ff8dd6a 96 radio.write_reg(REG_LR_MODEMCONFIG, lora.RegModemConfig.octet);
Wayne Roberts 0:9c052ff8dd6a 97
Wayne Roberts 0:9c052ff8dd6a 98 lora.invert_tx(invIQ);
Wayne Roberts 0:9c052ff8dd6a 99 lora.invert_rx(invIQ);
Wayne Roberts 0:9c052ff8dd6a 100 }
Wayne Roberts 0:9c052ff8dd6a 101
Wayne Roberts 0:9c052ff8dd6a 102 void Radio::GFSKModemConfig(unsigned bps, unsigned bw_hz, unsigned fdev_hz)
Wayne Roberts 0:9c052ff8dd6a 103 {
Wayne Roberts 0:9c052ff8dd6a 104 if (radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 0:9c052ff8dd6a 105 fsk.enable(false);
Wayne Roberts 0:9c052ff8dd6a 106
Wayne Roberts 0:9c052ff8dd6a 107 fsk.set_bitrate(bps);
Wayne Roberts 0:9c052ff8dd6a 108
Wayne Roberts 0:9c052ff8dd6a 109 fsk.set_rx_dcc_bw_hz(bw_hz, 0);
Wayne Roberts 0:9c052ff8dd6a 110 fsk.set_rx_dcc_bw_hz(bw_hz * 1.5, 1);
Wayne Roberts 0:9c052ff8dd6a 111
Wayne Roberts 0:9c052ff8dd6a 112 fsk.set_tx_fdev_hz(fdev_hz);
Wayne Roberts 0:9c052ff8dd6a 113 }
Wayne Roberts 0:9c052ff8dd6a 114
Wayne Roberts 0:9c052ff8dd6a 115
Wayne Roberts 0:9c052ff8dd6a 116 void Radio::GFSKPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn)
Wayne Roberts 0:9c052ff8dd6a 117 {
Wayne Roberts 0:9c052ff8dd6a 118 if (radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 0:9c052ff8dd6a 119 fsk.enable(false);
Wayne Roberts 0:9c052ff8dd6a 120
Wayne Roberts 0:9c052ff8dd6a 121 radio.write_u16(REG_FSK_PREAMBLEMSB, preambleLen);
Wayne Roberts 0:9c052ff8dd6a 122
Wayne Roberts 0:9c052ff8dd6a 123 fsk.RegPktConfig1.bits.PacketFormatVariable = fixLen ? 0 : 1;
Wayne Roberts 0:9c052ff8dd6a 124 fsk.RegPktConfig1.bits.CrcOn = crcOn;
Wayne Roberts 0:9c052ff8dd6a 125 radio.write_reg(REG_FSK_PACKETCONFIG1, fsk.RegPktConfig1.octet);
Wayne Roberts 0:9c052ff8dd6a 126 }
Wayne Roberts 0:9c052ff8dd6a 127
Wayne Roberts 13:a354f82d12d9 128 void Radio::SetLoRaSymbolTimeout(uint16_t symbs)
Wayne Roberts 0:9c052ff8dd6a 129 {
Wayne Roberts 0:9c052ff8dd6a 130 if (!radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 0:9c052ff8dd6a 131 lora.enable();
Wayne Roberts 0:9c052ff8dd6a 132
Wayne Roberts 13:a354f82d12d9 133 radio.write_reg(REG_LR_SYMBTIMEOUTLSB, symbs & 0xff);
Wayne Roberts 13:a354f82d12d9 134 symbs >>= 8;
Wayne Roberts 13:a354f82d12d9 135 lora.RegModemConfig2.sx1272bits.SymbTimeoutMsb = symbs;
Wayne Roberts 0:9c052ff8dd6a 136 radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet);
Wayne Roberts 0:9c052ff8dd6a 137 }
Wayne Roberts 0:9c052ff8dd6a 138
Wayne Roberts 0:9c052ff8dd6a 139 void Radio::LoRaModemConfig(unsigned bwKHz, uint8_t sf, uint8_t coderate)
Wayne Roberts 0:9c052ff8dd6a 140 {
Wayne Roberts 0:9c052ff8dd6a 141 float sp;
Wayne Roberts 0:9c052ff8dd6a 142 if (!radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 0:9c052ff8dd6a 143 lora.enable();
Wayne Roberts 0:9c052ff8dd6a 144
Wayne Roberts 0:9c052ff8dd6a 145 lora.RegModemConfig2.sx1276bits.SpreadingFactor = sf;
Wayne Roberts 0:9c052ff8dd6a 146 radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet);
Wayne Roberts 0:9c052ff8dd6a 147
Wayne Roberts 0:9c052ff8dd6a 148 lora.setBw_KHz(bwKHz);
Wayne Roberts 0:9c052ff8dd6a 149
Wayne Roberts 0:9c052ff8dd6a 150 if (radio.type == SX1276) {
Wayne Roberts 0:9c052ff8dd6a 151 lora.RegModemConfig.sx1276bits.CodingRate = coderate;
Wayne Roberts 0:9c052ff8dd6a 152
Wayne Roberts 0:9c052ff8dd6a 153 sp = lora.get_symbol_period();
Wayne Roberts 0:9c052ff8dd6a 154 if (sp > 16)
Wayne Roberts 0:9c052ff8dd6a 155 lora.RegModemConfig3.sx1276bits.LowDataRateOptimize = 1;
Wayne Roberts 0:9c052ff8dd6a 156 else
Wayne Roberts 0:9c052ff8dd6a 157 lora.RegModemConfig3.sx1276bits.LowDataRateOptimize = 0;
Wayne Roberts 0:9c052ff8dd6a 158
Wayne Roberts 0:9c052ff8dd6a 159 radio.write_reg(REG_LR_MODEMCONFIG3, lora.RegModemConfig3.octet);
Wayne Roberts 0:9c052ff8dd6a 160 } else if (radio.type == SX1272) {
Wayne Roberts 0:9c052ff8dd6a 161 lora.RegModemConfig.sx1272bits.CodingRate = coderate;
Wayne Roberts 0:9c052ff8dd6a 162
Wayne Roberts 0:9c052ff8dd6a 163 if (lora.get_symbol_period() > 16)
Wayne Roberts 0:9c052ff8dd6a 164 lora.RegModemConfig.sx1272bits.LowDataRateOptimize = 1;
Wayne Roberts 0:9c052ff8dd6a 165 else
Wayne Roberts 0:9c052ff8dd6a 166 lora.RegModemConfig.sx1272bits.LowDataRateOptimize = 0;
Wayne Roberts 0:9c052ff8dd6a 167 }
Wayne Roberts 0:9c052ff8dd6a 168 radio.write_reg(REG_LR_MODEMCONFIG, lora.RegModemConfig.octet);
Wayne Roberts 0:9c052ff8dd6a 169 }
Wayne Roberts 0:9c052ff8dd6a 170
Wayne Roberts 1:e79b0a55135f 171 void Radio::SetRxMaxPayloadLength(uint8_t max)
Wayne Roberts 0:9c052ff8dd6a 172 {
Wayne Roberts 1:e79b0a55135f 173 if (radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 1:e79b0a55135f 174 radio.write_reg(REG_LR_RX_MAX_PAYLOADLENGTH, max);
Wayne Roberts 1:e79b0a55135f 175 else
Wayne Roberts 1:e79b0a55135f 176 radio.write_reg(REG_FSK_PAYLOADLENGTH, max);
Wayne Roberts 0:9c052ff8dd6a 177 }
Wayne Roberts 0:9c052ff8dd6a 178
Wayne Roberts 6:b7bbf31e06e4 179 void Radio::SetFixedPayloadLength(uint8_t len)
Wayne Roberts 6:b7bbf31e06e4 180 {
Wayne Roberts 6:b7bbf31e06e4 181 lora.RegPayloadLength = len;
Wayne Roberts 6:b7bbf31e06e4 182 radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
Wayne Roberts 6:b7bbf31e06e4 183 }
Wayne Roberts 6:b7bbf31e06e4 184
Wayne Roberts 0:9c052ff8dd6a 185 const RadioEvents_t* RadioEvents;
Wayne Roberts 0:9c052ff8dd6a 186
Wayne Roberts 0:9c052ff8dd6a 187
Wayne Roberts 0:9c052ff8dd6a 188 volatile struct pe {
Wayne Roberts 0:9c052ff8dd6a 189 uint8_t dio0 : 1;
Wayne Roberts 0:9c052ff8dd6a 190 uint8_t dio1 : 1;
Wayne Roberts 0:9c052ff8dd6a 191 uint8_t txing : 1;
Wayne Roberts 0:9c052ff8dd6a 192 } pinEvent;
Wayne Roberts 0:9c052ff8dd6a 193
Wayne Roberts 0:9c052ff8dd6a 194 void
Wayne Roberts 0:9c052ff8dd6a 195 Radio::dio0UserContext()
Wayne Roberts 0:9c052ff8dd6a 196 {
Wayne Roberts 0:9c052ff8dd6a 197 service_action_e act = lora.service();
Wayne Roberts 0:9c052ff8dd6a 198
Wayne Roberts 0:9c052ff8dd6a 199 if (!pinEvent.txing) {
Wayne Roberts 0:9c052ff8dd6a 200 if (act == SERVICE_READ_FIFO && RadioEvents->RxDone) {
Wayne Roberts 0:9c052ff8dd6a 201 int8_t rssi;
Wayne Roberts 0:9c052ff8dd6a 202 float snr = lora.RegPktSnrValue / 4.0;
Wayne Roberts 0:9c052ff8dd6a 203
Wayne Roberts 0:9c052ff8dd6a 204 rssi = lora.get_pkt_rssi();
Wayne Roberts 0:9c052ff8dd6a 205 if (snr < 0)
Wayne Roberts 0:9c052ff8dd6a 206 rssi += snr;
Wayne Roberts 0:9c052ff8dd6a 207 RadioEvents->RxDone(lora.RegRxNbBytes, rssi, snr);
Wayne Roberts 0:9c052ff8dd6a 208 }
Wayne Roberts 0:9c052ff8dd6a 209 } else if (act == SERVICE_TX_DONE) {
Wayne Roberts 0:9c052ff8dd6a 210 if (RadioEvents->TxDone_botHalf)
Wayne Roberts 0:9c052ff8dd6a 211 RadioEvents->TxDone_botHalf();
Wayne Roberts 0:9c052ff8dd6a 212 }
Wayne Roberts 0:9c052ff8dd6a 213 }
Wayne Roberts 0:9c052ff8dd6a 214
Wayne Roberts 0:9c052ff8dd6a 215 volatile us_timestamp_t Radio::irqAt;
Wayne Roberts 0:9c052ff8dd6a 216
Wayne Roberts 0:9c052ff8dd6a 217 void Radio::dio0isr()
Wayne Roberts 0:9c052ff8dd6a 218 {
Wayne Roberts 0:9c052ff8dd6a 219 irqAt = lpt.read_us();
Wayne Roberts 14:94993ae5b164 220
Wayne Roberts 14:94993ae5b164 221 if (RadioEvents->DioPin_top_half)
Wayne Roberts 14:94993ae5b164 222 RadioEvents->DioPin_top_half();
Wayne Roberts 0:9c052ff8dd6a 223
Wayne Roberts 0:9c052ff8dd6a 224 if (pinEvent.txing) {
Wayne Roberts 0:9c052ff8dd6a 225 /* TxDone handling requires low latency */
Wayne Roberts 0:9c052ff8dd6a 226 if (RadioEvents->TxDone_topHalf)
Wayne Roberts 0:9c052ff8dd6a 227 RadioEvents->TxDone_topHalf(); // TODO in callback read irqAt for timestamp of interrupt
Wayne Roberts 0:9c052ff8dd6a 228
Wayne Roberts 0:9c052ff8dd6a 229 }
Wayne Roberts 0:9c052ff8dd6a 230
Wayne Roberts 0:9c052ff8dd6a 231 pinEvent.dio0 = 1;
Wayne Roberts 0:9c052ff8dd6a 232 }
Wayne Roberts 0:9c052ff8dd6a 233
Wayne Roberts 0:9c052ff8dd6a 234 void Radio::dio1UserContext()
Wayne Roberts 0:9c052ff8dd6a 235 {
Wayne Roberts 0:9c052ff8dd6a 236 lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);
Wayne Roberts 0:9c052ff8dd6a 237
Wayne Roberts 0:9c052ff8dd6a 238 if (RadioEvents->RxTimeout)
Wayne Roberts 0:9c052ff8dd6a 239 RadioEvents->RxTimeout();
Wayne Roberts 0:9c052ff8dd6a 240
Wayne Roberts 0:9c052ff8dd6a 241 radio.write_reg(REG_LR_IRQFLAGS, 0x80); // ensure RxTimeout is cleared
Wayne Roberts 0:9c052ff8dd6a 242 }
Wayne Roberts 0:9c052ff8dd6a 243
Wayne Roberts 0:9c052ff8dd6a 244 void Radio::dio1isr()
Wayne Roberts 0:9c052ff8dd6a 245 {
Wayne Roberts 0:9c052ff8dd6a 246 pinEvent.dio1 = 1;
Wayne Roberts 14:94993ae5b164 247
Wayne Roberts 14:94993ae5b164 248 if (RadioEvents->DioPin_top_half)
Wayne Roberts 14:94993ae5b164 249 RadioEvents->DioPin_top_half();
Wayne Roberts 0:9c052ff8dd6a 250 }
Wayne Roberts 0:9c052ff8dd6a 251
Wayne Roberts 13:a354f82d12d9 252 void Radio::Init(const RadioEvents_t* e, unsigned spi_hz)
Wayne Roberts 0:9c052ff8dd6a 253 {
Wayne Roberts 13:a354f82d12d9 254 radio.m_spi.frequency(spi_hz);
Wayne Roberts 13:a354f82d12d9 255
Wayne Roberts 8:0518c6e68b79 256 while (radio.dio0.read() || radio.dio1.read()) {
Wayne Roberts 8:0518c6e68b79 257 radio.write_reg(REG_LR_IRQFLAGS, 0xff); // clear stagnant interrupt
Wayne Roberts 8:0518c6e68b79 258 }
Wayne Roberts 0:9c052ff8dd6a 259 dio0.rise(dio0isr);
Wayne Roberts 0:9c052ff8dd6a 260 dio1.rise(dio1isr);
Wayne Roberts 0:9c052ff8dd6a 261
Wayne Roberts 0:9c052ff8dd6a 262 radio.rf_switch = rfsw_callback;
Wayne Roberts 0:9c052ff8dd6a 263 boardInit();
Wayne Roberts 0:9c052ff8dd6a 264
Wayne Roberts 0:9c052ff8dd6a 265 RadioEvents = e;
Wayne Roberts 0:9c052ff8dd6a 266 lpt.start();
Wayne Roberts 0:9c052ff8dd6a 267 }
Wayne Roberts 0:9c052ff8dd6a 268
Wayne Roberts 7:ba81f66e56d1 269 float Radio::GetRssiInst()
Wayne Roberts 7:ba81f66e56d1 270 {
Wayne Roberts 7:ba81f66e56d1 271 return lora.get_current_rssi();
Wayne Roberts 7:ba81f66e56d1 272 }
Wayne Roberts 7:ba81f66e56d1 273
Wayne Roberts 0:9c052ff8dd6a 274 int Radio::Send(uint8_t size, timestamp_t maxListenTime, timestamp_t channelFreeTime, int rssiThresh)
Wayne Roberts 0:9c052ff8dd6a 275 {
Wayne Roberts 0:9c052ff8dd6a 276 if (radio.RegOpMode.bits.Mode == RF_OPMODE_SLEEP) {
Wayne Roberts 0:9c052ff8dd6a 277 radio.set_opmode(RF_OPMODE_STANDBY);
Wayne Roberts 0:9c052ff8dd6a 278 wait_us(1000);
Wayne Roberts 0:9c052ff8dd6a 279 }
Wayne Roberts 0:9c052ff8dd6a 280 radio.write_reg(REG_LR_IRQFLAGS, 0x08); // ensure TxDone is cleared
Wayne Roberts 0:9c052ff8dd6a 281 lora.RegPayloadLength = size;
Wayne Roberts 0:9c052ff8dd6a 282 radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
Wayne Roberts 0:9c052ff8dd6a 283
Wayne Roberts 0:9c052ff8dd6a 284 if (maxListenTime > 0) {
Wayne Roberts 0:9c052ff8dd6a 285 int rssi;
Wayne Roberts 0:9c052ff8dd6a 286 us_timestamp_t startAt, chFreeAt, now;
Wayne Roberts 0:9c052ff8dd6a 287 lora.start_rx(RF_OPMODE_RECEIVER);
Wayne Roberts 0:9c052ff8dd6a 288 startAt = lpt.read_us();
Wayne Roberts 0:9c052ff8dd6a 289 Lstart:
Wayne Roberts 0:9c052ff8dd6a 290 do {
Wayne Roberts 0:9c052ff8dd6a 291 now = lpt.read_us();
Wayne Roberts 0:9c052ff8dd6a 292 if ((now - startAt) > maxListenTime) {
Wayne Roberts 0:9c052ff8dd6a 293 return -1;
Wayne Roberts 0:9c052ff8dd6a 294 }
Wayne Roberts 0:9c052ff8dd6a 295 rssi = lora.get_current_rssi();
Wayne Roberts 0:9c052ff8dd6a 296 } while (rssi > rssiThresh);
Wayne Roberts 0:9c052ff8dd6a 297 chFreeAt = lpt.read_us();
Wayne Roberts 0:9c052ff8dd6a 298 do {
Wayne Roberts 0:9c052ff8dd6a 299 now = lpt.read_us();
Wayne Roberts 0:9c052ff8dd6a 300 rssi = lora.get_current_rssi();
Wayne Roberts 0:9c052ff8dd6a 301 if (rssi > rssiThresh) {
Wayne Roberts 0:9c052ff8dd6a 302 goto Lstart;
Wayne Roberts 0:9c052ff8dd6a 303 }
Wayne Roberts 0:9c052ff8dd6a 304 } while ((now - chFreeAt) < channelFreeTime);
Wayne Roberts 0:9c052ff8dd6a 305 }
Wayne Roberts 0:9c052ff8dd6a 306
Wayne Roberts 0:9c052ff8dd6a 307 lora.start_tx(size);
Wayne Roberts 0:9c052ff8dd6a 308 pinEvent.txing = 1;
Wayne Roberts 0:9c052ff8dd6a 309
Wayne Roberts 0:9c052ff8dd6a 310 return 0;
Wayne Roberts 0:9c052ff8dd6a 311 }
Wayne Roberts 0:9c052ff8dd6a 312
Wayne Roberts 0:9c052ff8dd6a 313 void Radio::Rx(unsigned timeout)
Wayne Roberts 0:9c052ff8dd6a 314 {
Wayne Roberts 0:9c052ff8dd6a 315 if (timeout == 0) {
Wayne Roberts 0:9c052ff8dd6a 316 lora.start_rx(RF_OPMODE_RECEIVER);
Wayne Roberts 0:9c052ff8dd6a 317 } else {
Wayne Roberts 0:9c052ff8dd6a 318 lora.start_rx(RF_OPMODE_RECEIVER_SINGLE);
Wayne Roberts 0:9c052ff8dd6a 319 }
Wayne Roberts 0:9c052ff8dd6a 320
Wayne Roberts 0:9c052ff8dd6a 321 pinEvent.txing = 0;
Wayne Roberts 0:9c052ff8dd6a 322 }
Wayne Roberts 0:9c052ff8dd6a 323
Wayne Roberts 0:9c052ff8dd6a 324
Wayne Roberts 0:9c052ff8dd6a 325 void Radio::ocp(uint8_t ma)
Wayne Roberts 0:9c052ff8dd6a 326 {
Wayne Roberts 0:9c052ff8dd6a 327 if (ma < 130)
Wayne Roberts 0:9c052ff8dd6a 328 radio.RegOcp.bits.OcpTrim = (ma - 45) / 5;
Wayne Roberts 0:9c052ff8dd6a 329 else
Wayne Roberts 0:9c052ff8dd6a 330 radio.RegOcp.bits.OcpTrim = (ma + 30) / 10;
Wayne Roberts 0:9c052ff8dd6a 331 radio.write_reg(REG_OCP, radio.RegOcp.octet);
Wayne Roberts 0:9c052ff8dd6a 332
Wayne Roberts 0:9c052ff8dd6a 333 radio.RegOcp.octet = radio.read_reg(REG_OCP);
Wayne Roberts 0:9c052ff8dd6a 334 if (radio.RegOcp.bits.OcpTrim < 16)
Wayne Roberts 0:9c052ff8dd6a 335 ma = 45 + (5 * radio.RegOcp.bits.OcpTrim);
Wayne Roberts 0:9c052ff8dd6a 336 else if (radio.RegOcp.bits.OcpTrim < 28)
Wayne Roberts 0:9c052ff8dd6a 337 ma = (10 * radio.RegOcp.bits.OcpTrim) - 30;
Wayne Roberts 0:9c052ff8dd6a 338 else
Wayne Roberts 0:9c052ff8dd6a 339 ma = 240;
Wayne Roberts 0:9c052ff8dd6a 340 }
Wayne Roberts 0:9c052ff8dd6a 341
Wayne Roberts 0:9c052ff8dd6a 342
Wayne Roberts 0:9c052ff8dd6a 343 #if 0
Wayne Roberts 0:9c052ff8dd6a 344 void Radio::PrintStatus()
Wayne Roberts 0:9c052ff8dd6a 345 {
Wayne Roberts 0:9c052ff8dd6a 346 #ifdef MAC_DEBUG
Wayne Roberts 0:9c052ff8dd6a 347 radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
Wayne Roberts 0:9c052ff8dd6a 348 switch (radio.RegOpMode.bits.Mode) {
Wayne Roberts 0:9c052ff8dd6a 349 case RF_OPMODE_SLEEP: printf("SLEEP "); break;
Wayne Roberts 0:9c052ff8dd6a 350 case RF_OPMODE_STANDBY: printf("STBY "); break;
Wayne Roberts 0:9c052ff8dd6a 351 case RF_OPMODE_SYNTHESIZER_TX: printf("FSTX "); break;
Wayne Roberts 0:9c052ff8dd6a 352 case RF_OPMODE_TRANSMITTER: printf("TX "); break;
Wayne Roberts 0:9c052ff8dd6a 353 case RF_OPMODE_SYNTHESIZER_RX: printf("FSRX "); break;
Wayne Roberts 0:9c052ff8dd6a 354 case RF_OPMODE_RECEIVER: printf("RXC "); break;
Wayne Roberts 0:9c052ff8dd6a 355 case RF_OPMODE_RECEIVER_SINGLE: printf("RXS "); break;
Wayne Roberts 0:9c052ff8dd6a 356 case RF_OPMODE_CAD: printf("CAD "); break;
Wayne Roberts 0:9c052ff8dd6a 357 }
Wayne Roberts 0:9c052ff8dd6a 358
Wayne Roberts 0:9c052ff8dd6a 359 printf("dio:%u:%u opmode:%02x %.2fMHz sf%ubw%u ", radio.dio0.read(), radio.dio1.read(), radio.RegOpMode.octet, radio.get_frf_MHz(), lora.getSf(), lora.getBw());
Wayne Roberts 0:9c052ff8dd6a 360 lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);
Wayne Roberts 0:9c052ff8dd6a 361 printf("irqFlags:%02x\r\n", lora.RegIrqFlags.octet);
Wayne Roberts 0:9c052ff8dd6a 362 #endif /* MAC_DEBUG */
Wayne Roberts 0:9c052ff8dd6a 363 }
Wayne Roberts 0:9c052ff8dd6a 364 #endif /* if 0 */
Wayne Roberts 0:9c052ff8dd6a 365
Wayne Roberts 0:9c052ff8dd6a 366 #ifdef DUTY_ENABLE
Wayne Roberts 0:9c052ff8dd6a 367 us_timestamp_t
Wayne Roberts 0:9c052ff8dd6a 368 Radio::TimeOnAir(RadioModems_t m, uint8_t pktLen)
Wayne Roberts 0:9c052ff8dd6a 369 {
Wayne Roberts 0:9c052ff8dd6a 370 uint32_t airTime = 0;
Wayne Roberts 0:9c052ff8dd6a 371
Wayne Roberts 0:9c052ff8dd6a 372 switch (m)
Wayne Roberts 0:9c052ff8dd6a 373 {
Wayne Roberts 0:9c052ff8dd6a 374 case MODEM_FSK:
Wayne Roberts 0:9c052ff8dd6a 375 {
Wayne Roberts 0:9c052ff8dd6a 376 /* TODO
Wayne Roberts 0:9c052ff8dd6a 377 airTime = round( ( 8 * ( SX1272.Settings.Fsk.PreambleLen +
Wayne Roberts 0:9c052ff8dd6a 378 ( ( SX1272Read( REG_SYNCCONFIG ) & ~RF_SYNCCONFIG_SYNCSIZE_MASK ) + 1 ) +
Wayne Roberts 0:9c052ff8dd6a 379 ( ( SX1272.Settings.Fsk.FixLen == 0x01 ) ? 0.0 : 1.0 ) +
Wayne Roberts 0:9c052ff8dd6a 380 ( ( ( SX1272Read( REG_PACKETCONFIG1 ) & ~RF_PACKETCONFIG1_ADDRSFILTERING_MASK ) != 0x00 ) ? 1.0 : 0 ) +
Wayne Roberts 0:9c052ff8dd6a 381 pktLen +
Wayne Roberts 0:9c052ff8dd6a 382 ( ( SX1272.Settings.Fsk.CrcOn == 0x01 ) ? 2.0 : 0 ) ) /
Wayne Roberts 0:9c052ff8dd6a 383 SX1272.Settings.Fsk.Datarate ) * 1e3 );
Wayne Roberts 0:9c052ff8dd6a 384 */
Wayne Roberts 0:9c052ff8dd6a 385 }
Wayne Roberts 0:9c052ff8dd6a 386 break;
Wayne Roberts 0:9c052ff8dd6a 387 case MODEM_LORA:
Wayne Roberts 0:9c052ff8dd6a 388 {
Wayne Roberts 0:9c052ff8dd6a 389 double bw = 0.0;
Wayne Roberts 0:9c052ff8dd6a 390 uint8_t fixLen, bandwidth, LowDatarateOptimize, coderate, crcOn ;
Wayne Roberts 0:9c052ff8dd6a 391 if (radio.type == SX1276) {
Wayne Roberts 0:9c052ff8dd6a 392 coderate = lora.RegModemConfig.sx1276bits.CodingRate;
Wayne Roberts 0:9c052ff8dd6a 393 LowDatarateOptimize = lora.RegModemConfig3.sx1276bits.LowDataRateOptimize;
Wayne Roberts 0:9c052ff8dd6a 394 fixLen = lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn;
Wayne Roberts 0:9c052ff8dd6a 395 bandwidth = lora.RegModemConfig.sx1276bits.Bw - 7;
Wayne Roberts 0:9c052ff8dd6a 396 crcOn = lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn;
Wayne Roberts 0:9c052ff8dd6a 397 } else if (radio.type == SX1272) {
Wayne Roberts 0:9c052ff8dd6a 398 coderate = lora.RegModemConfig.sx1272bits.CodingRate;
Wayne Roberts 0:9c052ff8dd6a 399 LowDatarateOptimize = lora.RegModemConfig.sx1272bits.LowDataRateOptimize;
Wayne Roberts 0:9c052ff8dd6a 400 fixLen = lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn;
Wayne Roberts 0:9c052ff8dd6a 401 bandwidth = lora.RegModemConfig.sx1272bits.Bw;
Wayne Roberts 0:9c052ff8dd6a 402 crcOn = lora.RegModemConfig.sx1272bits.RxPayloadCrcOn;
Wayne Roberts 0:9c052ff8dd6a 403 } else
Wayne Roberts 0:9c052ff8dd6a 404 return 0;
Wayne Roberts 0:9c052ff8dd6a 405
Wayne Roberts 0:9c052ff8dd6a 406 switch( bandwidth )
Wayne Roberts 0:9c052ff8dd6a 407 {
Wayne Roberts 0:9c052ff8dd6a 408 case 0: // 125 kHz
Wayne Roberts 0:9c052ff8dd6a 409 bw = 125;//ms: 125e3;
Wayne Roberts 0:9c052ff8dd6a 410 break;
Wayne Roberts 0:9c052ff8dd6a 411 case 1: // 250 kHz
Wayne Roberts 0:9c052ff8dd6a 412 bw = 250;//ms:250e3;
Wayne Roberts 0:9c052ff8dd6a 413 break;
Wayne Roberts 0:9c052ff8dd6a 414 case 2: // 500 kHz
Wayne Roberts 0:9c052ff8dd6a 415 bw = 500;//ms:500e3;
Wayne Roberts 0:9c052ff8dd6a 416 break;
Wayne Roberts 0:9c052ff8dd6a 417 }
Wayne Roberts 0:9c052ff8dd6a 418
Wayne Roberts 0:9c052ff8dd6a 419 // Symbol rate : time for one symbol (secs)
Wayne Roberts 0:9c052ff8dd6a 420 double rs = bw / ( 1 << lora.RegModemConfig2.sx1276bits.SpreadingFactor );
Wayne Roberts 0:9c052ff8dd6a 421 double ts = 1 / rs;
Wayne Roberts 0:9c052ff8dd6a 422 // time of preamble
Wayne Roberts 0:9c052ff8dd6a 423 double tPreamble;
Wayne Roberts 0:9c052ff8dd6a 424 tPreamble = (lora.RegPreamble + 4.25 ) * ts;
Wayne Roberts 0:9c052ff8dd6a 425 // Symbol length of payload and time
Wayne Roberts 0:9c052ff8dd6a 426 double tmp = ceil( ( 8 * pktLen - 4 * lora.RegModemConfig2.sx1276bits.SpreadingFactor +
Wayne Roberts 0:9c052ff8dd6a 427 28 + 16 * crcOn -
Wayne Roberts 0:9c052ff8dd6a 428 ( fixLen ? 20 : 0 ) ) /
Wayne Roberts 0:9c052ff8dd6a 429 ( double )( 4 * ( lora.RegModemConfig2.sx1276bits.SpreadingFactor -
Wayne Roberts 0:9c052ff8dd6a 430 ( ( LowDatarateOptimize > 0 ) ? 2 : 0 ) ) ) ) *
Wayne Roberts 0:9c052ff8dd6a 431 ( coderate + 4 );
Wayne Roberts 0:9c052ff8dd6a 432 double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 );
Wayne Roberts 0:9c052ff8dd6a 433 double tPayload = nPayload * ts;
Wayne Roberts 0:9c052ff8dd6a 434 // Time on air
Wayne Roberts 0:9c052ff8dd6a 435 double tOnAir = tPreamble + tPayload;
Wayne Roberts 0:9c052ff8dd6a 436 // return ms secs
Wayne Roberts 0:9c052ff8dd6a 437 airTime = floor( tOnAir * 1e3 + 0.999 );
Wayne Roberts 0:9c052ff8dd6a 438 }
Wayne Roberts 0:9c052ff8dd6a 439 break;
Wayne Roberts 0:9c052ff8dd6a 440 }
Wayne Roberts 0:9c052ff8dd6a 441 return airTime;
Wayne Roberts 0:9c052ff8dd6a 442
Wayne Roberts 0:9c052ff8dd6a 443 }
Wayne Roberts 0:9c052ff8dd6a 444 #endif /* DUTY_ENABLE */
Wayne Roberts 0:9c052ff8dd6a 445
Wayne Roberts 0:9c052ff8dd6a 446 void Radio::service()
Wayne Roberts 0:9c052ff8dd6a 447 {
Wayne Roberts 0:9c052ff8dd6a 448 if (pinEvent.dio0) {
Wayne Roberts 17:5f34cbe2ac53 449 dio0UserContext();
Wayne Roberts 17:5f34cbe2ac53 450 pinEvent.txing = 0;
Wayne Roberts 0:9c052ff8dd6a 451 pinEvent.dio0 = 0;
Wayne Roberts 10:3303cf2867d4 452 } else if (radio.dio0.read()) {
Wayne Roberts 10:3303cf2867d4 453 /* fail: missed interrupt */
Wayne Roberts 10:3303cf2867d4 454 dio0isr();
Wayne Roberts 0:9c052ff8dd6a 455 }
Wayne Roberts 0:9c052ff8dd6a 456
Wayne Roberts 0:9c052ff8dd6a 457 if (pinEvent.dio1) {
Wayne Roberts 0:9c052ff8dd6a 458 dio1UserContext();
Wayne Roberts 0:9c052ff8dd6a 459 pinEvent.dio1 = 0;
Wayne Roberts 0:9c052ff8dd6a 460 }
Wayne Roberts 0:9c052ff8dd6a 461 }
Wayne Roberts 0:9c052ff8dd6a 462
Wayne Roberts 0:9c052ff8dd6a 463 uint32_t Radio::lora_toa_us( uint8_t pktLen )
Wayne Roberts 0:9c052ff8dd6a 464 {
Wayne Roberts 0:9c052ff8dd6a 465 uint32_t airTime = 0;
Wayne Roberts 0:9c052ff8dd6a 466 uint8_t chipBW = Radio::lora.getBw();
Wayne Roberts 0:9c052ff8dd6a 467 double bwKHz;
Wayne Roberts 0:9c052ff8dd6a 468 uint8_t LowDataRateOptimize;
Wayne Roberts 0:9c052ff8dd6a 469 bool FixLen;
Wayne Roberts 0:9c052ff8dd6a 470 uint8_t crcOn;
Wayne Roberts 0:9c052ff8dd6a 471 uint16_t preambleLen = Radio::radio.read_u16(REG_LR_PREAMBLEMSB);
Wayne Roberts 0:9c052ff8dd6a 472
Wayne Roberts 0:9c052ff8dd6a 473 Radio::lora.RegModemConfig2.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG2);
Wayne Roberts 0:9c052ff8dd6a 474 Radio::lora.RegModemConfig.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG);
Wayne Roberts 0:9c052ff8dd6a 475
Wayne Roberts 0:9c052ff8dd6a 476 if (Radio::radio.type == SX1276) {
Wayne Roberts 0:9c052ff8dd6a 477 chipBW -= 7;
Wayne Roberts 0:9c052ff8dd6a 478 Radio::lora.RegModemConfig3.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG3);
Wayne Roberts 0:9c052ff8dd6a 479 LowDataRateOptimize = Radio::lora.RegModemConfig3.sx1276bits.LowDataRateOptimize;
Wayne Roberts 0:9c052ff8dd6a 480 FixLen = Radio::lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn;
Wayne Roberts 0:9c052ff8dd6a 481 crcOn = Radio::lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn;
Wayne Roberts 0:9c052ff8dd6a 482 } else if (Radio::radio.type == SX1272) {
Wayne Roberts 0:9c052ff8dd6a 483 LowDataRateOptimize = Radio::lora.RegModemConfig.sx1272bits.LowDataRateOptimize;
Wayne Roberts 0:9c052ff8dd6a 484 FixLen = Radio::lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn;
Wayne Roberts 0:9c052ff8dd6a 485 crcOn = Radio::lora.RegModemConfig.sx1272bits.RxPayloadCrcOn;
Wayne Roberts 0:9c052ff8dd6a 486 } else
Wayne Roberts 0:9c052ff8dd6a 487 return 0;
Wayne Roberts 0:9c052ff8dd6a 488
Wayne Roberts 0:9c052ff8dd6a 489 switch (chipBW) {
Wayne Roberts 0:9c052ff8dd6a 490 case 0: bwKHz = 125; break;
Wayne Roberts 0:9c052ff8dd6a 491 case 1: bwKHz = 250; break;
Wayne Roberts 0:9c052ff8dd6a 492 case 2: bwKHz = 500; break;
Wayne Roberts 0:9c052ff8dd6a 493 default: return 0;
Wayne Roberts 0:9c052ff8dd6a 494 }
Wayne Roberts 0:9c052ff8dd6a 495
Wayne Roberts 0:9c052ff8dd6a 496 // Symbol rate : time for one symbol (secs)
Wayne Roberts 0:9c052ff8dd6a 497 double rs = bwKHz / ( 1 << Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor );
Wayne Roberts 0:9c052ff8dd6a 498 double ts = 1 / rs;
Wayne Roberts 0:9c052ff8dd6a 499 // time of preamble
Wayne Roberts 0:9c052ff8dd6a 500 double tPreamble = ( preambleLen + 4.25 ) * ts;
Wayne Roberts 0:9c052ff8dd6a 501 // Symbol length of payload and time
Wayne Roberts 0:9c052ff8dd6a 502 double tmp = ceil( ( 8 * pktLen - 4 * Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor +
Wayne Roberts 0:9c052ff8dd6a 503 28 + 16 * crcOn -
Wayne Roberts 0:9c052ff8dd6a 504 ( FixLen ? 20 : 0 ) ) /
Wayne Roberts 0:9c052ff8dd6a 505 ( double )( 4 * ( Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor -
Wayne Roberts 0:9c052ff8dd6a 506 ( ( LowDataRateOptimize > 0 ) ? 2 : 0 ) ) ) ) *
Wayne Roberts 0:9c052ff8dd6a 507 ( Radio::lora.getCodingRate(false) + 4 );
Wayne Roberts 0:9c052ff8dd6a 508 double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 );
Wayne Roberts 0:9c052ff8dd6a 509 double tPayload = nPayload * ts;
Wayne Roberts 0:9c052ff8dd6a 510 // Time on air
Wayne Roberts 0:9c052ff8dd6a 511 double tOnAir = tPreamble + tPayload;
Wayne Roberts 0:9c052ff8dd6a 512 // return microseconds
Wayne Roberts 0:9c052ff8dd6a 513 airTime = floor( tOnAir * 1000 + 0.999 );
Wayne Roberts 0:9c052ff8dd6a 514
Wayne Roberts 0:9c052ff8dd6a 515 return airTime;
Wayne Roberts 0:9c052ff8dd6a 516 }
Wayne Roberts 0:9c052ff8dd6a 517 #endif /* ..SX127x_H */
Wayne Roberts 0:9c052ff8dd6a 518