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:
Fri Jul 10 10:52:39 2020 -0700
Revision:
20:75635d50262e
Parent:
19:94b5382d3fc6
support mbed-6

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