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

Dependents:   alarm_slave alarm_master lora_p2p lorawan1v1 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers radio_sx126x.cpp Source File

radio_sx126x.cpp

00001 #include "radio.h"
00002 #ifdef SX126x_H 
00003 #include "SPIu.h"
00004 
00005 #ifdef DEVICE_LPTICKER
00006 LowPowerTimer Radio::lpt;
00007 #else
00008 Timer Radio::lpt;
00009 #endif
00010 
00011 #if (MBED_MAJOR_VERSION < 6)
00012 volatile us_timestamp_t Radio::irqAt;
00013 #else
00014 LowPowerClock::time_point Radio::irqAt;
00015 #endif
00016 
00017 bool Radio::paOff;
00018 
00019 #ifdef TARGET_FF_ARDUINO
00020 #ifdef TARGET_DISCO_L072CZ_LRWAN1
00021     /* murata type1SJ */
00022     SPIu spi(PB_15, PB_14, PB_13); // mosi, miso, sclk
00023                    //spi, nss, busy, dio1
00024     SX126x Radio::radio(spi, PB_12, PC_2, PB_0);
00025 
00026     DigitalOut antswPower(PA_15);
00027     void Radio::chipModeChange() { }
00028     const uint8_t chipType = CHIP_TYPE_SX1262;
00029 #else
00030     /* sx126x arduino shield */
00031     SPIu spi(D11, D12, D13); // mosi, miso, sclk
00032                    //spi, nss, busy, dio1
00033     SX126x Radio::radio(spi, D7, D3, D5);
00034 
00035     DigitalOut antswPower(D8);
00036     AnalogIn xtalSel(A3);
00037 
00038     DigitalIn Radio::chipType(A2);
00039 
00040     #define PINNAME_NRST            A0
00041 
00042     #define LED_ON      1
00043     #define LED_OFF     0
00044     DigitalOut tx_led(A4);
00045     DigitalOut rx_led(A5);
00046 
00047     void Radio::chipModeChange()
00048     {
00049         if (radio.chipMode == CHIPMODE_NONE) {
00050             tx_led = LED_OFF;
00051             rx_led = LED_OFF;
00052         } else if (radio.chipMode == CHIPMODE_TX) {
00053             tx_led = LED_ON;
00054             rx_led = LED_OFF;
00055         } else if (radio.chipMode == CHIPMODE_RX) {
00056             tx_led = LED_OFF;
00057             rx_led = LED_ON;
00058         }
00059     }
00060 #endif /* !TARGET_DISCO_L072CZ_LRWAN1 */
00061 #endif /* TARGET_FF_ARDUINO */
00062 
00063 const RadioEvents_t* RadioEvents;
00064 PacketParams_t Radio::pp;
00065 RadioModems_t Radio::_m_;
00066 uint8_t Radio::loraTimeoutSymbols;
00067 
00068 #if defined(TARGET_FF_MORPHO) && !defined(TARGET_DISCO_L072CZ_LRWAN1)
00069     DigitalOut pc3(PC_3);   // debug RX indication, for nucleo boards
00070     #define RX_INDICATION       pc3
00071 #endif /* TARGET_FF_MORPHO */
00072 
00073 void Radio::Rx(unsigned timeout)
00074 {
00075     antswPower = 1;
00076 
00077     {
00078         uint8_t buf[8];
00079         IrqFlags_t irqEnable;
00080         irqEnable.word = 0;
00081         irqEnable.bits.RxDone = 1;
00082         irqEnable.bits.Timeout = 1;
00083 
00084         buf[0] = irqEnable.word >> 8;    // enable bits
00085         buf[1] = irqEnable.word; // enable bits
00086         buf[2] = irqEnable.word >> 8;     // dio1
00087         buf[3] = irqEnable.word;  // dio1
00088         buf[4] = 0; // dio2
00089         buf[5] = 0; // dio2
00090         buf[6] = 0; // dio3
00091         buf[7] = 0; // dio3
00092         radio.xfer(OPCODE_SET_DIO_IRQ_PARAMS, 8, 0, buf);
00093     }
00094 
00095 #ifdef RX_INDICATION
00096     RX_INDICATION = 1;
00097 #endif
00098     if (timeout == 0) {
00099         uint8_t symbs = 0;
00100         if (radio.getPacketType() == PACKET_TYPE_LORA) // shut off timeout
00101             radio.xfer(OPCODE_SET_LORA_SYMBOL_TIMEOUT, 1, 0, &symbs);
00102 
00103         radio.start_rx(RX_TIMEOUT_CONTINUOUS);
00104     } else {
00105         if (radio.getPacketType() == PACKET_TYPE_LORA)
00106             radio.xfer(OPCODE_SET_LORA_SYMBOL_TIMEOUT, 1, 0, &loraTimeoutSymbols);
00107 
00108         radio.start_rx(timeout * RC_TICKS_PER_US);
00109     }
00110 }
00111 
00112 void Radio::Standby()
00113 {
00114     radio.setStandby(STBY_RC);  // STBY_XOSC
00115 
00116     antswPower = 0;
00117 }
00118 
00119 void Radio::Sleep()
00120 {
00121     radio.setSleep(true, false);
00122 
00123     antswPower = 0;
00124 }
00125 
00126 void Radio::set_tx_dbm(int8_t dbm)
00127 {
00128     unsigned v = radio.readReg(REG_ADDR_ANACTRL16, 1);
00129 
00130     if (dbm == PA_OFF_DBM) {
00131         /* bench test: prevent overloading receiving station (very low tx power) */
00132         if ((v & 0x10) == 0) {
00133             v |= 0x10;
00134             radio.writeReg(REG_ADDR_ANACTRL16, v, 1);
00135         }
00136         paOff = true;
00137     } else {
00138         radio.set_tx_dbm(chipType == CHIP_TYPE_SX1262, dbm);
00139         if (v & 0x10) {
00140             v &= ~0x10;
00141             radio.writeReg(REG_ADDR_ANACTRL16, v, 1);
00142         }
00143         paOff = false;
00144     }
00145 }
00146 
00147 void Radio::SetTxContinuousWave(unsigned hz, int8_t dbm, unsigned timeout_us)
00148 {
00149     SetChannel(hz);
00150     radio.set_tx_dbm(chipType == CHIP_TYPE_SX1262, dbm);
00151     radio.xfer(OPCODE_SET_TX_CARRIER, 0, 0, NULL);
00152 }
00153 
00154 uint32_t Radio::Random(void)
00155 {
00156     uint32_t ret;
00157 
00158     radio.start_rx(RX_TIMEOUT_CONTINUOUS);
00159 
00160     ret = radio.readReg(REG_ADDR_RANDOM, 4);
00161 
00162     Standby();
00163 
00164     return ret;
00165 }
00166 
00167 bool Radio::CheckRfFrequency(unsigned hz)
00168 {
00169     return true;
00170 }
00171 
00172 void Radio::SetChannel(unsigned hz)
00173 {
00174     radio.setMHz(hz / 1000000.0);
00175 }
00176 
00177 float Radio::getFrfMHz()
00178 {
00179     return radio.getMHz();
00180 }
00181 
00182 void Radio::LoRaPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn, bool invIQ)
00183 {
00184     if (radio.getPacketType() != PACKET_TYPE_LORA)
00185         radio.setPacketType(PACKET_TYPE_LORA);
00186 
00187     pp.lora.PreambleLengthHi = preambleLen >> 8;
00188     pp.lora.PreambleLengthLo = preambleLen;
00189     pp.lora.HeaderType = fixLen;
00190     pp.lora.CRCType = crcOn;
00191     pp.lora.InvertIQ = invIQ;
00192 
00193     radio.xfer(OPCODE_SET_PACKET_PARAMS, 6, 0, pp.buf);
00194 }
00195 
00196 void Radio::GFSKModemConfig(unsigned bps, unsigned bw_hz, unsigned fdev_hz)
00197 {
00198     ModulationParams_t mp;
00199     uint32_t u32;
00200 
00201     if (radio.getPacketType() != PACKET_TYPE_GFSK)
00202         radio.setPacketType(PACKET_TYPE_GFSK);
00203 
00204     u32  = 32 * (XTAL_FREQ_HZ / bps);
00205     mp.gfsk.bitrateHi = u32 >> 16; // param1
00206     mp.gfsk.bitrateMid = u32 >> 8; // param2
00207     mp.gfsk.bitrateLo = u32;       // param3
00208     mp.gfsk.PulseShape = GFSK_SHAPE_BT1_0; // param4
00209     // param5:
00210     if (bw_hz < 5800)
00211         mp.gfsk.bandwidth = GFSK_RX_BW_4800;
00212     else if (bw_hz < 7300)
00213         mp.gfsk.bandwidth = GFSK_RX_BW_5800;
00214     else if (bw_hz < 9700)
00215         mp.gfsk.bandwidth = GFSK_RX_BW_7300;
00216     else if (bw_hz < 11700)
00217         mp.gfsk.bandwidth = GFSK_RX_BW_9700;
00218     else if (bw_hz < 14600)
00219         mp.gfsk.bandwidth = GFSK_RX_BW_11700;
00220     else if (bw_hz < 19500)
00221         mp.gfsk.bandwidth = GFSK_RX_BW_14600;
00222     else if (bw_hz < 23400)
00223         mp.gfsk.bandwidth = GFSK_RX_BW_19500;
00224     else if (bw_hz < 29300)
00225         mp.gfsk.bandwidth = GFSK_RX_BW_23400;
00226     else if (bw_hz < 39000)
00227         mp.gfsk.bandwidth = GFSK_RX_BW_29300;
00228     else if (bw_hz < 46900)
00229         mp.gfsk.bandwidth = GFSK_RX_BW_39000;
00230     else if (bw_hz < 58600)
00231         mp.gfsk.bandwidth = GFSK_RX_BW_46900;
00232     else if (bw_hz < 78200)
00233         mp.gfsk.bandwidth = GFSK_RX_BW_58600;
00234     else if (bw_hz < 93800)
00235         mp.gfsk.bandwidth = GFSK_RX_BW_78200;
00236     else if (bw_hz < 117300)
00237         mp.gfsk.bandwidth = GFSK_RX_BW_93800;
00238     else if (bw_hz < 156200)
00239         mp.gfsk.bandwidth = GFSK_RX_BW_117300;
00240     else if (bw_hz < 187200)
00241         mp.gfsk.bandwidth = GFSK_RX_BW_156200;
00242     else if (bw_hz < 234300)
00243         mp.gfsk.bandwidth = GFSK_RX_BW_187200;
00244     else if (bw_hz < 312000)
00245         mp.gfsk.bandwidth = GFSK_RX_BW_234300;
00246     else if (bw_hz < 373600)
00247         mp.gfsk.bandwidth = GFSK_RX_BW_312000;
00248     else if (bw_hz < 467000)
00249         mp.gfsk.bandwidth = GFSK_RX_BW_373600;
00250     else
00251         mp.gfsk.bandwidth = GFSK_RX_BW_467000;
00252 
00253     if (fdev_hz > 0) {
00254         u32 = fdev_hz / FREQ_STEP;
00255         mp.gfsk.fdevHi = u32 >> 16; // param6
00256         mp.gfsk.fdevMid = u32 >> 8;    // param7
00257         mp.gfsk.fdevLo = u32; // param8
00258     }
00259 
00260     radio.xfer(OPCODE_SET_MODULATION_PARAMS, 8, 0, mp.buf);
00261 }
00262 
00263 void Radio::GFSKPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn)
00264 {
00265     if (radio.getPacketType() != PACKET_TYPE_GFSK)
00266         radio.setPacketType(PACKET_TYPE_GFSK);
00267 
00268     pp.gfsk.PreambleLengthHi = preambleLen >> 8;
00269     pp.gfsk.PreambleLengthLo = preambleLen;
00270     pp.gfsk.PreambleDetectorLength = GFSK_PREAMBLE_DETECTOR_LENGTH_16BITS;
00271     pp.gfsk.SyncWordLength = 24; // 0xC194C1
00272     pp.gfsk.AddrComp = 0;
00273     pp.gfsk.PacketType = fixLen;
00274     if (crcOn)
00275         pp.gfsk.CRCType = GFSK_CRC_2_BYTE;
00276     else
00277         pp.gfsk.CRCType = GFSK_CRC_OFF;
00278 
00279     //TODO pp.gfsk.PayloadLength = ;
00280 
00281     radio.xfer(OPCODE_SET_PACKET_PARAMS, 8, 0, pp.buf);
00282 }
00283 
00284 void Radio::LoRaModemConfig(unsigned bwKHz, uint8_t sf, uint8_t cr)
00285 {
00286     ModulationParams_t mp;
00287     float khz, sp;
00288 
00289     if (radio.getPacketType() != PACKET_TYPE_LORA)
00290         radio.setPacketType(PACKET_TYPE_LORA);
00291 
00292     if (bwKHz > 250) {
00293         mp.lora.bandwidth = LORA_BW_500;
00294         khz = 500;
00295     } else if (bwKHz > 125) {
00296         mp.lora.bandwidth = LORA_BW_250;
00297         khz = 250;
00298     } else if (bwKHz > 63) {
00299         mp.lora.bandwidth = LORA_BW_125;
00300         khz = 125;
00301     } else if (bwKHz > 42) {
00302         mp.lora.bandwidth = LORA_BW_62;
00303         khz = 62.5;
00304     } else if (bwKHz > 32) {
00305         mp.lora.bandwidth = LORA_BW_41;
00306         khz = 41.67;
00307     } else if (bwKHz > 21) {
00308         mp.lora.bandwidth = LORA_BW_31;
00309         khz = 31.25;
00310     } else if (bwKHz > 16) {
00311         mp.lora.bandwidth = LORA_BW_20;
00312         khz = 20.83;
00313     } else if (bwKHz > 11) {
00314         mp.lora.bandwidth = LORA_BW_15;
00315         khz = 15.625;
00316     } else if (bwKHz > 11) {
00317         mp.lora.bandwidth = LORA_BW_10;
00318         khz = 10.42;
00319     } else {
00320         mp.lora.bandwidth = LORA_BW_7;
00321         khz = 7.81;
00322     }
00323 
00324     mp.lora.spreadingFactor = sf;
00325     mp.lora.codingRate = cr;
00326 
00327     sp = (1 << mp.lora.spreadingFactor) / khz;
00328     /* TCXO dependent */
00329     if (sp > 16)
00330         mp.lora.LowDatarateOptimize = 1; // param4
00331     else
00332         mp.lora.LowDatarateOptimize = 0; // param4
00333 
00334     radio.xfer(OPCODE_SET_MODULATION_PARAMS, 4, 0, mp.buf);
00335 
00336 }
00337 
00338 void Radio::SetLoRaSymbolTimeout(uint16_t symbs)
00339 {
00340     if (radio.getPacketType() != PACKET_TYPE_LORA)
00341         radio.setPacketType(PACKET_TYPE_LORA);
00342 
00343     loraTimeoutSymbols = symbs;
00344     radio.xfer(OPCODE_SET_LORA_SYMBOL_TIMEOUT, 1, 0, &loraTimeoutSymbols);
00345 }
00346 
00347 float Radio::GetRssiInst()
00348 {
00349     uint8_t buf[8];
00350 
00351     radio.xfer(OPCODE_GET_RSSIINST, 0, 2, buf);
00352     return buf[1] / -2.0;
00353 }
00354 
00355 int Radio::Send(uint8_t size, timestamp_t maxListenTime, timestamp_t channelFreeTime, int rssiThresh)
00356 {
00357     uint8_t buf[8];
00358     uint8_t pktType = radio.getPacketType();
00359 
00360     buf[0] = 0; // TX base address
00361     buf[1] = 0; // RX base address
00362     radio.xfer(OPCODE_SET_BUFFER_BASE_ADDR, 2, 0, buf);
00363 
00364     if (pktType == PACKET_TYPE_GFSK) {
00365         pp.gfsk.PayloadLength = size;
00366         radio.xfer(OPCODE_SET_PACKET_PARAMS, 8, 0, pp.buf);
00367     } else if (pktType == PACKET_TYPE_LORA) {
00368         pp.lora.PayloadLength = size;
00369         radio.xfer(OPCODE_SET_PACKET_PARAMS, 6, 0, pp.buf);
00370     }
00371 
00372     {
00373         IrqFlags_t irqEnable;
00374         irqEnable.word = 0;
00375         irqEnable.bits.TxDone = 1;
00376         irqEnable.bits.Timeout = 1;
00377 
00378         buf[0] = irqEnable.word >> 8;    // enable bits
00379         buf[1] = irqEnable.word; // enable bits
00380         buf[2] = irqEnable.word >> 8;     // dio1
00381         buf[3] = irqEnable.word;  // dio1
00382         buf[4] = 0; // dio2
00383         buf[5] = 0; // dio2
00384         buf[6] = 0; // dio3
00385         buf[7] = 0; // dio3
00386         radio.xfer(OPCODE_SET_DIO_IRQ_PARAMS, 8, 0, buf);
00387     }
00388 
00389     antswPower = 1;
00390 
00391     if (maxListenTime > 0) {
00392         int rssi;
00393         us_timestamp_t startAt, chFreeAt, now;
00394         uint8_t symbs = 0;
00395 
00396         radio.xfer(OPCODE_SET_LORA_SYMBOL_TIMEOUT, 1, 0, &symbs);
00397 
00398         radio.start_rx(RX_TIMEOUT_CONTINUOUS);
00399     #if (MBED_MAJOR_VERSION < 6)
00400         startAt = lpt.read_us();
00401     #else
00402         startAt = LowPowerClock::now().time_since_epoch().count();
00403     #endif
00404 Lstart:
00405         do {
00406     #if (MBED_MAJOR_VERSION < 6)
00407             now = lpt.read_us();
00408     #else
00409             now = LowPowerClock::now().time_since_epoch().count();
00410     #endif
00411             if ((now - startAt) > maxListenTime) {
00412                 return -1;
00413             }
00414             radio.xfer(OPCODE_GET_RSSIINST, 0, 2, buf);
00415             rssi = buf[1] / -2;
00416         } while (rssi > rssiThresh);
00417     #if (MBED_MAJOR_VERSION < 6)
00418         chFreeAt = lpt.read_us();
00419     #else
00420         chFreeAt = LowPowerClock::now().time_since_epoch().count();
00421     #endif
00422         do {
00423     #if (MBED_MAJOR_VERSION < 6)
00424             now = lpt.read_us();
00425     #else
00426             now = LowPowerClock::now().time_since_epoch().count();
00427     #endif
00428             radio.xfer(OPCODE_GET_RSSIINST, 0, 2, buf);
00429             rssi = buf[1] / -2;
00430             if (rssi > rssiThresh) {
00431                 goto Lstart;
00432             }
00433         } while ((now - chFreeAt) < channelFreeTime);
00434     } 
00435 
00436     if (paOff) {
00437         unsigned v = radio.readReg(REG_ADDR_ANACTRL16, 1);
00438         if ((v & 0x10) == 0) {
00439             v |= 0x10;
00440             radio.writeReg(REG_ADDR_ANACTRL16, v, 1);
00441         }
00442     }
00443     radio.start_tx(size);
00444 
00445     return 0;
00446 } // ..Send()
00447 
00448 void Radio::SetRxMaxPayloadLength(uint8_t max)
00449 {
00450     uint8_t pktType = radio.getPacketType();
00451 
00452     if (pktType == PACKET_TYPE_GFSK) {
00453         pp.gfsk.PayloadLength = max;
00454         radio.xfer(OPCODE_SET_PACKET_PARAMS, 8, 0, pp.buf);
00455     } else if (pktType == PACKET_TYPE_LORA) {
00456         pp.lora.PayloadLength = max;
00457         radio.xfer(OPCODE_SET_PACKET_PARAMS, 6, 0, pp.buf);
00458     }
00459 }
00460 
00461 void Radio::dio1_top_half()
00462 {
00463 #if (MBED_MAJOR_VERSION < 6)
00464     irqAt = lpt.read_us();
00465 #else
00466     irqAt = LowPowerClock::now();
00467 #endif
00468 
00469     if (RadioEvents->DioPin_top_half)
00470         RadioEvents->DioPin_top_half();
00471 
00472     if (radio.chipMode == CHIPMODE_TX) {
00473         /* TxDone handling requires low latency */
00474         if (RadioEvents->TxDone_topHalf) {
00475             RadioEvents->TxDone_topHalf();
00476         } 
00477     } else {
00478 #ifdef RX_INDICATION
00479         RX_INDICATION = 0;
00480 #endif
00481     }
00482 }
00483 
00484 void Radio::timeout_callback(bool tx)
00485 {
00486     if (!tx) {
00487         if (RadioEvents->RxTimeout)
00488             RadioEvents->RxTimeout();
00489 #ifdef RX_INDICATION
00490         RX_INDICATION = 0;
00491 #endif
00492     } // else TODO tx timeout
00493 }
00494 
00495 void Radio::rx_done(uint8_t size, float rssi, float snr)
00496 {
00497     RadioEvents->RxDone(size, rssi, snr);
00498 }
00499 
00500 void Radio::txDoneBottom()
00501 {
00502     if (RadioEvents->TxDone_botHalf)
00503         RadioEvents->TxDone_botHalf();
00504 }
00505 
00506 void to_big_endian24(uint32_t in, uint8_t *out)
00507 {
00508     out[2] = in & 0xff;
00509     in >>= 8;
00510     out[1] = in & 0xff;
00511     in >>= 8;
00512     out[0] = in & 0xff;
00513 }
00514 
00515 void Radio::Init(const RadioEvents_t* e, unsigned spi_hz)
00516 {
00517     radio.txDone = txDoneBottom;
00518     radio.rxDone = rx_done;
00519     radio.timeout = timeout_callback;
00520     radio.chipModeChange = chipModeChange;
00521     radio.dio1_topHalf = dio1_top_half;
00522 
00523     RadioEvents = e;
00524     lpt.start();
00525 
00526     spi.frequency(spi_hz);
00527     radio.SetDIO2AsRfSwitchCtrl(1);
00528 #ifdef TARGET_DISCO_L072CZ_LRWAN1
00529     /* murata type1SJ */
00530     {
00531         unsigned tcxoDelayTicks = 3200;
00532         uint8_t buf[4];
00533 
00534         radio.hw_reset(PB_1);
00535         ThisThread::sleep_for(50);
00536 
00537         buf[0] = 1; // 1 = 1.7v
00538         to_big_endian24(tcxoDelayTicks, buf+1);
00539 
00540         radio.xfer(OPCODE_SET_DIO3_AS_TCXO_CTRL, 4, 0, buf);
00541     }
00542 #endif
00543 }
00544 
00545 void Radio::service()
00546 {
00547     radio.service();
00548 }
00549 
00550 void Radio::SetPublicNetwork(bool en)
00551 {
00552     uint16_t ppg;
00553 
00554     if (en)
00555         ppg = 0x3444;
00556     else
00557         ppg = 0x1424;
00558 
00559     radio.writeReg(REG_ADDR_LORA_SYNC, ppg, 2);
00560 }
00561 
00562 uint32_t Radio::lora_toa_us( uint8_t pktLen )
00563 {
00564     double bwKHz;
00565     unsigned preambleLen;
00566     ModulationParams_t mp;
00567 
00568     {
00569         loraConfig1_t conf1;
00570         conf1.octet = radio.readReg(REG_ADDR_LORA_CONFIG1, 1);
00571         mp.lora.LowDatarateOptimize = conf1.bits.ppm_offset;
00572         pp.lora.HeaderType = conf1.bits.implicit_header;
00573         pp.lora.InvertIQ = conf1.bits.rx_invert_iq;
00574         mp.lora.codingRate = conf1.bits.tx_coding_rate;
00575     }
00576 
00577     {
00578         loraConfig2_t conf2;
00579         conf2.octet = radio.readReg(REG_ADDR_LORA_CONFIG2, 1);
00580         pp.lora.CRCType = conf2.bits.tx_payload_crc16_en;
00581     }
00582 
00583 
00584     {
00585         uint32_t val;
00586         val = radio.readReg(REG_ADDR_LORA_PREAMBLE_SYMBNB, 2);
00587         pp.lora.PreambleLengthHi = val >> 8;
00588         pp.lora.PreambleLengthLo = val;
00589     }
00590 
00591     preambleLen = (pp.lora.PreambleLengthHi << 8) + pp.lora.PreambleLengthLo;
00592 
00593     {
00594         loraConfig0_t conf0;
00595         conf0.octet = radio.readReg(REG_ADDR_LORA_CONFIG0, 1);
00596         mp.lora.spreadingFactor = conf0.bits.modem_sf;
00597         mp.lora.bandwidth = conf0.bits.modem_bw;
00598     }
00599 
00600     switch (mp.lora.bandwidth) {
00601         case LORA_BW_7: bwKHz = 7.81; break;
00602         case LORA_BW_10: bwKHz = 10.42; break;
00603         case LORA_BW_15: bwKHz = 15.625; break;
00604         case LORA_BW_20: bwKHz = 20.83; break;
00605         case LORA_BW_31: bwKHz = 31.25; break;
00606         case LORA_BW_41: bwKHz = 41.67; break;
00607         case LORA_BW_62: bwKHz = 62.5; break;
00608         case LORA_BW_125: bwKHz = 125; break;
00609         case LORA_BW_250: bwKHz = 250; break;
00610         case LORA_BW_500: bwKHz = 500; break;
00611         default: bwKHz = 0; break;
00612     }
00613 
00614     // Symbol rate : time for one symbol (secs)
00615     double rs = bwKHz / ( 1 << mp.lora.spreadingFactor );
00616     double ts = 1 / rs;
00617     // time of preamble
00618     double tPreamble = ( preambleLen + 4.25 ) * ts;
00619     // Symbol length of payload and time
00620     
00621     double tmp = ceil( ( 8 * pktLen - 4 * mp.lora.spreadingFactor +
00622                          28 + 16 * pp.lora.CRCType -
00623                          ( pp.lora.HeaderType ? 20 : 0 ) ) /
00624                          ( double )( 4 * ( mp.lora.spreadingFactor -
00625                          ( ( mp.lora.LowDatarateOptimize > 0 ) ? 2 : 0 ) ) ) ) *
00626                          ( mp.lora.codingRate + 4 );
00627     double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 );
00628     double tPayload = nPayload * ts;
00629     // Time on air
00630     double tOnAir = tPreamble + tPayload;
00631     // return microseconds
00632     return floor( tOnAir * 1000 + 0.999 );
00633 }
00634 
00635 #if 0
00636 void Radio::PrintStatus()
00637 {
00638 /*    uint8_t buf[4];
00639     status_t status;
00640     IrqFlags_t irqFlags;
00641     radio.xfer(OPCODE_GET_IRQ_STATUS, 0, 3, buf);
00642     irqFlags.word = buf[1] << 8;
00643     irqFlags.word |= buf[2];
00644 
00645     printf("dio1:%u  irqFlags:%04x\r\n", radio.getDIO1(), irqFlags.word);
00646     radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet);
00647     radio.PrintChipStatus(status);*/
00648     {
00649         loraConfig1_t conf1;
00650         conf1.octet = radio.readReg(REG_ADDR_LORA_CONFIG1, 1);
00651         printf("ldro%u %s %s cr%u\r\n",
00652             conf1.bits.ppm_offset,
00653             conf1.bits.implicit_header ? "fixed" : "var",
00654             conf1.bits.rx_invert_iq ? "inv" : "std",
00655             conf1.bits.tx_coding_rate
00656         );
00657     }
00658 
00659     {
00660         loraConfig2_t conf2;
00661         conf2.octet = radio.readReg(REG_ADDR_LORA_CONFIG2, 1);
00662         printf("crc16en:%u ", conf2.bits.tx_payload_crc16_en);
00663     }
00664 
00665 
00666     {
00667         uint32_t val;
00668         val = radio.readReg(REG_ADDR_LORA_PREAMBLE_SYMBNB, 2);
00669         printf("prelen %lu ", val);
00670     }
00671 
00672     {
00673         loraConfig0_t conf0;
00674         conf0.octet = radio.readReg(REG_ADDR_LORA_CONFIG0, 1);
00675         printf("sf%u, bw%u ", conf0.bits.modem_sf, conf0.bits.modem_bw);
00676     }
00677 
00678     printf("%.3fMHz\r\n", radio.getMHz());
00679 }
00680 #endif /* if 0 */
00681 
00682 #endif /* ..SX126x_H */