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_sx128x.cpp Source File

radio_sx128x.cpp

00001 #include "radio.h"
00002 #ifdef SX128x_H 
00003 #include "SPIu.h"
00004 #include <float.h>
00005 
00006 #ifdef DEVICE_LPTICKER
00007 LowPowerTimer Radio::lpt;
00008 #else
00009 Timer Radio::lpt;
00010 #endif
00011 
00012 #if (MBED_MAJOR_VERSION < 6)
00013 volatile us_timestamp_t Radio::irqAt;
00014 #else
00015 LowPowerClock::time_point Radio::irqAt;
00016 #endif
00017 
00018 #ifdef TARGET_FF_ARDUINO    /* pins of SX126xDVK1xAS board */
00019     #define NRST_PIN        A0
00020     SPIu spi(D11, D12, D13); // mosi, miso, sclk
00021     //           spi, nss, busy, dio1
00022     SX128x Radio::radio(spi,  D7,   D3,   D5, NRST_PIN);
00023 
00024     #define LED_ON      1
00025     #define LED_OFF     0
00026     DigitalOut tx_led(A4);
00027     DigitalOut rx_led(A5);
00028 
00029 
00030     DigitalOut ant_sw(A3);
00031     DigitalOut cps(D6); // SE2436L
00032 
00033     bool fe_enable; // SE2436L
00034 
00035     void Radio::chipModeChange()
00036     {
00037         if (radio.chipMode == CHIPMODE_NONE) {
00038             cps = 0;
00039             tx_led = LED_OFF;
00040             rx_led = LED_OFF;
00041         } else if (radio.chipMode == CHIPMODE_TX) {
00042             cps = fe_enable;
00043             tx_led = LED_ON;
00044             rx_led = LED_OFF;
00045         } else if (radio.chipMode == CHIPMODE_RX) {
00046             cps = fe_enable;
00047             tx_led = LED_OFF;
00048             rx_led = LED_ON;
00049         }
00050     }
00051 #endif /* TARGET_FF_ARDUINO */
00052 
00053 #ifdef TARGET_FF_MORPHO
00054     DigitalOut pc3(PC_3);   // debug RX indication, for nucleo boards
00055     #define RX_INDICATION       pc3
00056 #endif /* TARGET_FF_MORPHO */
00057 
00058 
00059 PacketParams_t Radio::ppGFSK;
00060 PacketParams_t Radio::ppLORA;
00061 PacketParams_t Radio::ppFLRC;
00062 
00063 ModulationParams_t Radio::mpBLE_GFSK;
00064 ModulationParams_t Radio::mpFLRC;
00065 ModulationParams_t Radio::mpLORA;
00066 
00067 const RadioEvents_t* RadioEvents;
00068 
00069 unsigned Radio::symbolPeriodUs;
00070 unsigned Radio::nSymbs;
00071 unsigned Radio::rxTimeoutMs;
00072 
00073 void Radio::readChip()
00074 {
00075     uint8_t reg8;
00076 
00077     reg8 = radio.readReg(REG_ADDR_PKTCTRL0, 1);
00078     ppGFSK.gfskFLRC.HeaderType = reg8 & 0x20;
00079     ppFLRC.gfskFLRC.HeaderType = reg8 & 0x20;
00080 
00081     reg8 = radio.readReg(REG_ADDR_PKTCTRL1, 1);
00082     ppGFSK.gfskFLRC.PreambleLength = reg8 & 0x70;
00083     ppFLRC.gfskFLRC.PreambleLength = reg8 & 0x70;
00084     ppGFSK.gfskFLRC.SyncWordLength = reg8 & 0x0e;
00085     ppFLRC.gfskFLRC.SyncWordLength = reg8 & 0x06;
00086     if (ppFLRC.gfskFLRC.SyncWordLength == 0x06)
00087         ppFLRC.gfskFLRC.SyncWordLength = FLRC_SYNC_WORD_LEN_P32S;
00088 
00089     reg8 = radio.readReg(REG_ADDR_PKT_SYNC_ADRS_CTRL, 1);
00090     ppGFSK.gfskFLRC.SyncWordMatch = reg8 & 0x70;
00091     ppFLRC.gfskFLRC.SyncWordMatch = reg8 & 0x70;
00092 
00093     reg8 = radio.readReg(REG_ADDR_PAYLOAD_LEN, 1);
00094     ppGFSK.gfskFLRC.PayloadLength = reg8;
00095     ppFLRC.gfskFLRC.PayloadLength = reg8;
00096 
00097     reg8 = radio.readReg(REG_ADDR_PKT_TX_HEADER, 1);    // TODO hi bit of payload length
00098     //ppBLE.ble.ConnectionState = reg8 & 0xe0;
00099     //ppBLE.ble.BleTestPayload = reg8 & 0x1c;
00100 
00101     reg8 = radio.readReg(REG_ADDR_PKT_BITSTREAM_CTRL, 1);
00102     //ppBLE.ble.CrcLength = reg8 & 0x30;
00103     //ppBLE.ble.Whitening = reg8 & 0x08;
00104     ppGFSK.gfskFLRC.CRCLength = reg8 & 0x30;
00105     ppFLRC.gfskFLRC.CRCLength = reg8 & 0x30;
00106     ppGFSK.gfskFLRC.Whitening = reg8 & 0x08;
00107     ppFLRC.gfskFLRC.Whitening = reg8 & 0x08;
00108 
00109     {
00110         LoRaPktPar0_t LoRaPktPar0;
00111         LoRaPktPar0.octet = radio.readReg(REG_ADDR_LORA_PKTPAR0, 1);
00112         switch (LoRaPktPar0.bits.modem_bw) {
00113             case 2: mpLORA.lora.bandwidth = LORA_BW_200; break;
00114             case 3: mpLORA.lora.bandwidth = LORA_BW_400; break;
00115             case 4: mpLORA.lora.bandwidth = LORA_BW_800; break;
00116             case 5: mpLORA.lora.bandwidth = LORA_BW_1600; break;
00117         }
00118         mpLORA.lora.spreadingFactor = LoRaPktPar0.bits.modem_sf << 4;
00119     }
00120 
00121     {
00122         LoRaPktPar1_t LoRaPktPar1;
00123         LoRaPktPar1.octet = radio.readReg(REG_ADDR_LORA_PKTPAR1, 1);
00124         mpLORA.lora.codingRate = LoRaPktPar1.bits.coding_rate;
00125         ppLORA.lora.InvertIQ = LoRaPktPar1.octet & LORA_IQ_STD; // LoRaPktPar1.bits.rxinvert_iq
00126         ppLORA.lora.HeaderType = LoRaPktPar1.bits.implicit_header ? IMPLICIT_HEADER : EXPLICIT_HEADER;
00127         // LoRaPktPar1.bits.ppm_offset
00128     }
00129 
00130     {
00131         LoRaPreambleReg_t LoRaPreambleReg;
00132         LoRaPreambleReg.octet = radio.readReg(REG_ADDR_LORA_PREAMBLE, 1);
00133         ppLORA.lora.PreambleLength = LoRaPreambleReg.bits.preamble_symb1_nb * (1 << LoRaPreambleReg.bits.preamble_symb_nb_exp);
00134     }
00135     ppLORA.lora.PayloadLength = radio.readReg(REG_ADDR_LORA_TX_PAYLOAD_LENGTH, 1);
00136 
00137     {
00138         LoRaLrCtl_t LoRaLrCtl;
00139         LoRaLrCtl.octet = radio.readReg(REG_ADDR_LORA_LRCTL, 1);
00140         ppLORA.lora.crc = LoRaLrCtl.octet & 0x20; // LoRaLrCtl.bits.crc_en
00141     }
00142 
00143     {
00144         RegRxBw_t RegRxBw;
00145         unsigned bps;
00146         FloraPreambleHi_t FloraPreambleHi;
00147         float mi, fdev_hz;
00148         unsigned freqDev;
00149         FskModDfH_t FskModDfH;
00150         FskModDfH.octet = radio.readReg(REG_ADDR_FSK_MODDFH, 1);
00151         freqDev = FskModDfH.bits.freqDev;
00152         freqDev <<= 8;
00153         freqDev |= radio.readReg(REG_ADDR_FSK_MODDFL, 1);
00154         fdev_hz = freqDev * PLL_STEP_HZ;
00155 
00156         FloraPreambleHi.octet = radio.readReg(REG_ADDR_FLORA_PREAMBLE_HI, 1);
00157         switch (FloraPreambleHi.bits.data_rate) {
00158             case 0:
00159                 bps = 2.0e6;
00160                 //mpFLRC.flrc.bitrateBandwidth = ??; // 2.6
00161                 break;
00162             case 1:
00163                 bps = 1.6e6;
00164                 //mpFLRC.flrc.bitrateBandwidth = ??; // 2.08
00165                 break;
00166             case 2:
00167                 bps = 1.0e6;
00168                 mpFLRC.flrc.bitrateBandwidth = FLRC_BR_1_300_BW_1_2; // 1.3
00169                 break;
00170             case 3:
00171                 bps = 0.8e6;
00172                 mpFLRC.flrc.bitrateBandwidth = FLRC_BR_1_000_BW_1_2; // 1.04
00173                 break;
00174             case 4:
00175                 bps = 0.5e6;
00176                 mpFLRC.flrc.bitrateBandwidth = FLRC_BR_0_650_BW_0_6; // 0.65
00177                 break;
00178             case 5:
00179                 bps = 0.4e6;
00180                 mpFLRC.flrc.bitrateBandwidth = FLRC_BR_0_520_BW_0_6; // 0.52
00181                 break;
00182             case 6:
00183                 bps = 0.25e6;
00184                 mpFLRC.flrc.bitrateBandwidth = FLRC_BR_0_325_BW_0_3; // 0.325
00185                 break;
00186             case 7:
00187                 bps = 0.125e6;
00188                 mpFLRC.flrc.bitrateBandwidth = FLRC_BR_0_260_BW_0_3; // 0.26
00189                 break;
00190         }
00191 
00192         mi = (fdev_hz * 2.0) / bps;
00193         if (mi > 0.35) {
00194             mi -= 0.5;
00195             mi /= 0.25;
00196             mpBLE_GFSK.gfskBle.ModulationIndex = ((uint8_t)mi) + 1;
00197         } else
00198             mpBLE_GFSK.gfskBle.ModulationIndex = 0;
00199 
00200         RegRxBw.octet = radio.readReg(REG_ADDR_RXBW, 1);
00201 
00202         switch (RegRxBw.bits.bw) {
00203             case 0:
00204                 if (FloraPreambleHi.bits.data_rate == 0)
00205                     mpBLE_GFSK.gfskBle.bitrateBandwidth = GFSK_BLE_BR_2_000_BW_2_4;
00206                 if (FloraPreambleHi.bits.data_rate == 1)
00207                     mpBLE_GFSK.gfskBle.bitrateBandwidth = GFSK_BLE_BR_1_600_BW_2_4;
00208                 if (FloraPreambleHi.bits.data_rate == 2)
00209                     mpBLE_GFSK.gfskBle.bitrateBandwidth = GFSK_BLE_BR_1_000_BW_2_4;
00210                 if (FloraPreambleHi.bits.data_rate == 3)
00211                     mpBLE_GFSK.gfskBle.bitrateBandwidth = GFSK_BLE_BR_0_800_BW_2_4;
00212                 break;
00213             case 1:
00214                 if (FloraPreambleHi.bits.data_rate == 2)
00215                     mpBLE_GFSK.gfskBle.bitrateBandwidth = GFSK_BLE_BR_1_000_BW_1_2;
00216                 if (FloraPreambleHi.bits.data_rate == 3)
00217                     mpBLE_GFSK.gfskBle.bitrateBandwidth = GFSK_BLE_BR_0_800_BW_1_2;
00218                 if (FloraPreambleHi.bits.data_rate == 4)
00219                     mpBLE_GFSK.gfskBle.bitrateBandwidth = GFSK_BLE_BR_0_500_BW_1_2;
00220                 if (FloraPreambleHi.bits.data_rate == 5)
00221                     mpBLE_GFSK.gfskBle.bitrateBandwidth = GFSK_BLE_BR_0_400_BW_1_2;
00222                 break;
00223             case 2:
00224                 if (FloraPreambleHi.bits.data_rate == 4)
00225                     mpBLE_GFSK.gfskBle.bitrateBandwidth = GFSK_BLE_BR_0_500_BW_0_6;
00226                 if (FloraPreambleHi.bits.data_rate == 5)
00227                     mpBLE_GFSK.gfskBle.bitrateBandwidth = GFSK_BLE_BR_0_400_BW_0_6;
00228                 if (FloraPreambleHi.bits.data_rate == 6)
00229                     mpBLE_GFSK.gfskBle.bitrateBandwidth = GFSK_BLE_BR_0_250_BW_0_6;
00230                 break;
00231             case 3:
00232                 if (FloraPreambleHi.bits.data_rate == 6)
00233                     mpBLE_GFSK.gfskBle.bitrateBandwidth = GFSK_BLE_BR_0_250_BW_0_3;
00234                 if (FloraPreambleHi.bits.data_rate == 7)
00235                     mpBLE_GFSK.gfskBle.bitrateBandwidth = GFSK_BLE_BR_0_125_BW_0_3;
00236                 break;
00237         }
00238         mpBLE_GFSK.gfskBle.bitrateBandwidth = reg8;
00239     }
00240 
00241     {
00242         FskCfg_t FskCfg;
00243         FskCfg.octet = radio.readReg(REG_ADDR_FSK_CFG, 1);
00244         mpBLE_GFSK.gfskBle.ModulationShaping = FskCfg.bits.gf_bt << 4;
00245         mpFLRC.flrc.ModulationShaping = mpBLE_GFSK.gfskBle.ModulationShaping;
00246     }
00247 
00248     {
00249         PktBitStreamCtrl_t PktBitStreamCtrl;
00250         PktBitStreamCtrl.octet = radio.readReg(REG_ADDR_PKT_BITSTREAM_CTRL, 1);
00251         mpFLRC.flrc.CodingRate = PktBitStreamCtrl.octet & 0x06; // PktBitStreamCtrl.bits.flora_coding_rate 
00252     }
00253 
00254 }
00255 
00256 void Radio:: diox_top_half()
00257 {
00258 #if (MBED_MAJOR_VERSION < 6)
00259     irqAt = lpt.read_us();
00260 #else
00261     irqAt = LowPowerClock::now();
00262 #endif
00263 
00264     if (RadioEvents->DioPin_top_half)
00265         RadioEvents->DioPin_top_half();
00266 
00267     if (radio.chipMode == CHIPMODE_TX) {
00268         /* TxDone handling requires low latency */
00269         if (RadioEvents->TxDone_topHalf) {
00270             RadioEvents->TxDone_topHalf();
00271         }
00272     } else {
00273 #ifdef RX_INDICATION
00274         RX_INDICATION = 0;
00275 #endif
00276     }
00277 }
00278 
00279 void Radio::rxDone(uint8_t size, const pktStatus_t* pktStatus)
00280 {
00281     float rssi, snr;
00282 
00283     if (pktStatus->ble_gfsk_flrc.sync.syncAddrsCode == 0) {
00284         int8_t s = pktStatus->lora.snr;
00285         rssi = -pktStatus->lora.rssiSync / 2.0;
00286         snr = s / 4.0;
00287     } else {
00288         rssi = -pktStatus->ble_gfsk_flrc.rssiSync / 2.0;
00289         snr = FLT_MIN;
00290     }
00291 
00292     RadioEvents->RxDone(size, rssi, snr);
00293 }
00294 
00295 void Radio::timeout_callback(bool tx)
00296 {
00297     if (!tx) {
00298         if (RadioEvents->RxTimeout)
00299             RadioEvents->RxTimeout();
00300 #ifdef RX_INDICATION
00301         RX_INDICATION = 0;
00302 #endif
00303     } // else TODO tx timeout
00304 }
00305 
00306 void Radio::txDoneBottom()
00307 {
00308     if (RadioEvents->TxDone_botHalf)
00309         RadioEvents->TxDone_botHalf();
00310 }
00311 
00312 void Radio::Init(const RadioEvents_t* e, unsigned spi_hz)
00313 {
00314     uint64_t sa;
00315 
00316     radio.txDone = txDoneBottom;
00317     radio.rxDone = rxDone;
00318     radio.timeout = timeout_callback;
00319     radio.chipModeChange = chipModeChange;
00320     radio.diox_topHalf = diox_top_half;
00321 
00322     spi.frequency(spi_hz);
00323     readChip();
00324 
00325     radio.setRegulator(0);  // default to LDO
00326 
00327     sa = 0xc194c1;
00328     radio.setSyncAddr(1, sa);
00329 
00330     RadioEvents = e;
00331     lpt.start();
00332 
00333     fe_enable = true;
00334 
00335     radio.periodBase = 2;   // 1ms resolution
00336     nSymbs = 8;
00337 }
00338 
00339 float Radio::GetRssiInst()
00340 {
00341     uint8_t buf[2];
00342     radio.xfer(OPCODE_GET_RSSIINST, 0, 2, buf);
00343     return buf[1] / -2.0;
00344 }
00345 
00346 int Radio::Send(uint8_t size, timestamp_t maxListenTime, timestamp_t channelFreeTime, int rssiThresh)
00347 {
00348     uint8_t buf[8];
00349     uint8_t pktType = radio.getPacketType();
00350 
00351     if (pktType == PACKET_TYPE_LORA) {
00352         ppLORA.lora.PayloadLength = size;
00353         radio.xfer(OPCODE_SET_PACKET_PARAMS, 5, 0, ppLORA.buf);
00354     } else if (pktType == PACKET_TYPE_GFSK) {
00355         ppGFSK.gfskFLRC.PayloadLength = size;
00356         radio.xfer(OPCODE_SET_PACKET_PARAMS, 7, 0, ppGFSK.buf);
00357     }
00358 
00359     if (maxListenTime > 0) {
00360         int rssi;
00361         us_timestamp_t startAt, chFreeAt, now;
00362         radio.start_rx(-1);
00363     #if (MBED_MAJOR_VERSION < 6)
00364         startAt = lpt.read_us();
00365     #else
00366         startAt = LowPowerClock::now().time_since_epoch().count();
00367     #endif
00368 Lstart:
00369         do {
00370     #if (MBED_MAJOR_VERSION < 6)
00371             now = lpt.read_us();
00372     #else
00373             now = LowPowerClock::now().time_since_epoch().count();
00374     #endif
00375             if ((now - startAt) > maxListenTime) {
00376                 return -1;
00377             }
00378             radio.xfer(OPCODE_GET_RSSIINST, 0, 2, buf);
00379             rssi = buf[1] / -2;
00380         } while (rssi > rssiThresh);
00381     #if (MBED_MAJOR_VERSION < 6)
00382         chFreeAt = lpt.read_us();
00383     #else
00384         chFreeAt = LowPowerClock::now().time_since_epoch().count();
00385     #endif
00386         do {
00387     #if (MBED_MAJOR_VERSION < 6)
00388             now = lpt.read_us();
00389     #else
00390             now = LowPowerClock::now().time_since_epoch().count();
00391     #endif
00392             radio.xfer(OPCODE_GET_RSSIINST, 0, 2, buf);
00393             rssi = buf[1] / -2;
00394             if (rssi > rssiThresh) {
00395                 goto Lstart;
00396             }
00397         } while ((now - chFreeAt) < channelFreeTime);
00398     }
00399 
00400     radio.start_tx(size, 4000);
00401 
00402     return 0;
00403 }
00404 
00405 void Radio::service()
00406 {
00407     radio.service();
00408 }
00409 
00410 bool Radio::CheckRfFrequency(unsigned hz)
00411 {
00412     return true;
00413 }
00414 
00415 void Radio::Sleep()
00416 {
00417     radio.setSleep(true);
00418 }
00419 
00420 void Radio::SetPublicNetwork(bool en)
00421 {
00422 /*    uint16_t ppg;
00423 
00424     if (en)
00425         ppg = 0x3444;
00426     else
00427         ppg = 0x1424;
00428 
00429     radio.writeReg(REG_ADDR_LORA_SYNC, ppg, 2);
00430 */
00431 }
00432 
00433 uint32_t Radio::lora_toa_us( uint8_t pktLen )
00434 {
00435     double bwKHz;
00436     LoRaPktPar0_t LoRaPktPar0;
00437     LoRaLrCtl_t LoRaLrCtl;
00438     LoRaPktPar1_t LoRaPktPar1;
00439     uint8_t LowDatarateOptimize;
00440 
00441     {
00442         LoRaPktPar1.octet = radio.readReg(REG_ADDR_LORA_PKTPAR1, 1);
00443         LowDatarateOptimize = LoRaPktPar1.bits.ppm_offset ? 1 : 0;
00444         ppLORA.lora.HeaderType = LoRaPktPar1.bits.implicit_header ? IMPLICIT_HEADER : EXPLICIT_HEADER;
00445         ppLORA.lora.InvertIQ = LoRaPktPar1.octet & LORA_IQ_STD; // LoRaPktPar1.bits.rxinvert_iq
00446         mpLORA.lora.codingRate = LoRaPktPar1.bits.coding_rate;
00447     }
00448 
00449     {
00450         LoRaLrCtl.octet = radio.readReg(REG_ADDR_LORA_LRCTL, 1);
00451         ppLORA.lora.crc = LoRaLrCtl.octet & 0x20; // LoRaLrCtl.bits.crc_en
00452     }
00453 
00454     {
00455         LoRaPreambleReg_t LoRaPreambleReg;
00456         LoRaPreambleReg.octet = radio.readReg(REG_ADDR_LORA_PREAMBLE, 1);
00457         ppLORA.lora.PreambleLength = LoRaPreambleReg.bits.preamble_symb1_nb * (1 << LoRaPreambleReg.bits.preamble_symb_nb_exp);
00458     }
00459 
00460     {
00461         LoRaPktPar0.octet = radio.readReg(REG_ADDR_LORA_PKTPAR0, 1);
00462         switch (LoRaPktPar0.bits.modem_bw) {
00463             case 0: bwKHz = 50; break;
00464             case 1: bwKHz = 100; break;
00465             case 2: mpLORA.lora.bandwidth = LORA_BW_200; bwKHz = 200; break;
00466             case 3: mpLORA.lora.bandwidth = LORA_BW_400; bwKHz = 400; break;
00467             case 4: mpLORA.lora.bandwidth = LORA_BW_800; bwKHz = 800; break;
00468             case 5: mpLORA.lora.bandwidth = LORA_BW_1600; bwKHz = 1600; break;
00469             default: bwKHz = 0; break;
00470         }
00471         mpLORA.lora.spreadingFactor = LoRaPktPar0.bits.modem_sf << 4;
00472     }
00473 
00474     // Symbol rate : time for one symbol (secs)
00475     double rs = bwKHz / (1 << LoRaPktPar0.bits.modem_sf);
00476     double ts = 1 / rs;
00477     // time of preamble
00478     //
00479     double tPreamble = ( ppLORA.lora.PreambleLength + 4.25 ) * ts;
00480     // Symbol length of payload and time
00481     
00482     double tmp = ceil( ( 8 * pktLen - 4 * LoRaPktPar0.bits.modem_sf +
00483                          28 + 16 * LoRaLrCtl.bits.crc_en -
00484                          ( LoRaPktPar1.bits.implicit_header ? 20 : 0 ) ) /
00485                          ( double )( 4 * ( LoRaPktPar0.bits.modem_sf -
00486                          ( ( LowDatarateOptimize > 0 ) ? 2 : 0 ) ) ) ) *
00487                          ( LoRaPktPar1.bits.coding_rate + 4 );
00488 
00489     double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 );
00490     double tPayload = nPayload * ts;
00491     // Time on air
00492     double tOnAir = tPreamble + tPayload;
00493     // return microseconds
00494     return floor( tOnAir * 1000 + 0.999 );
00495 }
00496 
00497 void Radio::GFSKModemConfig(unsigned bps, unsigned bw_hz, unsigned fdev_hz)
00498 {
00499     uint8_t u8;
00500     float mi, Mbps = bps / 1000000.0;
00501 
00502     if (Mbps > 1.6) {
00503         /* 2.0Mbps */
00504         u8 = GFSK_BLE_BR_2_000_BW_2_4;
00505     } else if (Mbps > 1.0) {
00506         /* 1.6Mbps */
00507         u8 = GFSK_BLE_BR_1_600_BW_2_4;
00508     } else if (Mbps > 0.8) {
00509         /* 1.0Mbps */
00510         /*if (bwMHz > 1.2)
00511             u8 = GFSK_BLE_BR_1_000_BW_2_4;
00512         else*/
00513             u8 = GFSK_BLE_BR_1_000_BW_1_2;
00514     } else if (Mbps > 0.5) {
00515         /* 0.8Mbps */
00516         /*if (bwMHz > 1.2)
00517             u8 = GFSK_BLE_BR_0_800_BW_2_4;
00518         else*/
00519             u8 = GFSK_BLE_BR_0_800_BW_1_2;
00520     } else if (Mbps > 0.4) {
00521         /* 0.5Mbps */
00522         /*if (bwMHz > 0.6)
00523             u8 = GFSK_BLE_BR_0_500_BW_1_2;
00524         else*/
00525             u8 = GFSK_BLE_BR_0_500_BW_0_6;
00526     } else if (Mbps > 0.25) {
00527         /* 0.4Mbps */
00528         /*if (bwMHz > 0.6)
00529             u8 = GFSK_BLE_BR_0_400_BW_1_2;
00530         else*/
00531             u8 = GFSK_BLE_BR_0_400_BW_0_6;
00532     } else if (Mbps > 0.125) {
00533         /* 0.25Mbps */
00534         /*if (bwMHz > 0.3)
00535             u8 = GFSK_BLE_BR_0_250_BW_0_6;
00536         else*/
00537             u8 = GFSK_BLE_BR_0_250_BW_0_3;
00538     } else {
00539         /* 0.125Mbps */
00540         u8 = GFSK_BLE_BR_0_125_BW_0_3;
00541     }
00542 
00543     mpBLE_GFSK.gfskBle.bitrateBandwidth = u8;
00544 
00545     mpBLE_GFSK.gfskBle.ModulationShaping = BT_OFF;
00546 
00547     mi = (fdev_hz * 2.0) / bps;
00548     if (mi > 0.35) {
00549         mi -= 0.5;
00550         mi /= 0.25;
00551         mpBLE_GFSK.gfskBle.ModulationIndex = ((uint8_t)mi) + 1;
00552     } else
00553         mpBLE_GFSK.gfskBle.ModulationIndex = 0;
00554 
00555     radio.xfer(OPCODE_SET_MODULATION_PARAMS, 3, 0, mpBLE_GFSK.buf);
00556 }
00557 
00558 void Radio::GFSKPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn)
00559 {
00560     ppGFSK.gfskFLRC.PreambleLength = (preambleLen - 4) / 4;
00561     ppGFSK.gfskFLRC.PreambleLength <<= 4;
00562     ppGFSK.gfskFLRC.SyncWordLength = (3 - 1) << 1;  // 3 byte 0xc194c1
00563     ppGFSK.gfskFLRC.HeaderType = fixLen ? RADIO_PACKET_FIXED_LENGTH : RADIO_PACKET_VARIABLE_LENGTH;
00564     ppGFSK.gfskFLRC.CRCLength = crcOn ? RADIO_CRC_2_BYTES : RADIO_CRC_OFF;
00565 
00566     // TODO ppGFSK.gfskFLRC.PayloadLength = ;
00567 
00568     radio.xfer(OPCODE_SET_PACKET_PARAMS, 7, 0, ppGFSK.buf);
00569 }
00570 
00571 void Radio::SetLoRaSymbolTimeout(uint16_t symbs)
00572 {
00573     nSymbs = symbs;
00574     rxTimeoutMs = nSymbs * (symbolPeriodUs / 1000.0);
00575 }
00576 
00577 void Radio::LoRaModemConfig(unsigned bwKHz, uint8_t sf, uint8_t cr)
00578 {
00579     if (radio.getPacketType() != PACKET_TYPE_LORA)
00580         radio.setPacketType(PACKET_TYPE_LORA);
00581 
00582     if (bwKHz > 800)
00583         mpLORA.lora.bandwidth = LORA_BW_1600;
00584     else if (bwKHz > 400)
00585         mpLORA.lora.bandwidth = LORA_BW_800;
00586     else if (bwKHz > 200)
00587         mpLORA.lora.bandwidth = LORA_BW_400;
00588     else if (bwKHz > 100)
00589         mpLORA.lora.bandwidth = LORA_BW_200;
00590     else if (bwKHz > 50)
00591         mpLORA.lora.bandwidth = LORA_BW_100;
00592     else
00593         mpLORA.lora.bandwidth = LORA_BW_50;
00594 
00595     mpLORA.lora.codingRate = cr;
00596 
00597     mpLORA.lora.spreadingFactor = sf << 4;
00598 
00599     radio.xfer(OPCODE_SET_MODULATION_PARAMS, 3, 0, mpLORA.buf);
00600 
00601     symbolPeriodUs = (1 << sf) / (bwKHz / 1000.0);   // bw in MHz gives microseconds
00602     rxTimeoutMs = nSymbs * (symbolPeriodUs / 1000.0);
00603 }
00604 
00605 void Radio::LoRaPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn, bool invIQ)
00606 {
00607     if (radio.getPacketType() != PACKET_TYPE_LORA)
00608         radio.setPacketType(PACKET_TYPE_LORA);
00609 
00610     ppLORA.lora.PreambleLength = preambleLen;
00611     ppLORA.lora.HeaderType = fixLen ? IMPLICIT_HEADER : EXPLICIT_HEADER;
00612     ppLORA.lora.crc = crcOn ? LORA_CRC_ENABLE : LORA_CRC_DISABLE;
00613     ppLORA.lora.InvertIQ = invIQ ? LORA_IQ_INVERTED : LORA_IQ_STD;
00614 
00615     radio.xfer(OPCODE_SET_PACKET_PARAMS, 5, 0, ppLORA.buf);
00616 }
00617 
00618 void Radio::SetChannel(unsigned hz)
00619 {
00620     radio.setMHz(hz / 1000000.0);
00621 }
00622 
00623 uint32_t Radio::Random(void)
00624 {
00625     uint8_t buf[2];
00626     uint32_t ret = 0;
00627     unsigned n;
00628 
00629     radio.start_rx(-1);
00630 
00631     for (n = 0; n < 8; n++) {
00632         uint32_t r, s;
00633         wait_us(5000);
00634         radio.xfer(OPCODE_GET_RSSIINST, 0, 2, buf);
00635         r = buf[1];
00636         s = n * 4;
00637         r <<= s;
00638         ret ^= r;
00639     }
00640 
00641     radio.setStandby(STDBY_RC);
00642 
00643     return ret;
00644 }
00645 
00646 void Radio::Rx(unsigned timeout)
00647 {
00648 #ifdef RX_INDICATION
00649     RX_INDICATION = 1;
00650 #endif
00651     if (timeout == 0)
00652         radio.start_rx(0);  // continuous rx
00653     else {
00654         radio.start_rx(rxTimeoutMs);
00655     }
00656 }
00657 
00658 void Radio::Standby()
00659 {
00660     radio.setStandby(STDBY_RC);
00661 }
00662 
00663 #define TX_PWR_OFFSET           18
00664 void Radio::set_tx_dbm(int8_t dbm)
00665 {
00666     if (dbm == PA_OFF_DBM) {
00667         /* TODO: shut off PA */
00668         radio.set_tx_dbm(0);
00669     } else {
00670         /* power range -18dBm to +13dBm */
00671         radio.set_tx_dbm(dbm + TX_PWR_OFFSET);
00672     }
00673 }
00674 
00675 void Radio::SetTxContinuousWave(unsigned hz, int8_t dbm, unsigned timeout_us)
00676 {
00677     SetChannel(hz);
00678     radio.set_tx_dbm(dbm);
00679     radio.xfer(OPCODE_SET_TX_CARRIER, 0, 0, NULL);
00680 }
00681 
00682 void Radio::SetRxMaxPayloadLength(uint8_t max)
00683 {
00684     uint8_t pktType = radio.getPacketType();
00685 
00686     if (pktType == PACKET_TYPE_GFSK)
00687         ppGFSK.gfskFLRC.PayloadLength = max;
00688     else if (pktType == PACKET_TYPE_LORA)
00689         ppLORA.lora.PayloadLength = max;
00690 }
00691 
00692 #endif /* ..SX126x_H */