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

radio_sx127x.cpp

00001 #include "radio.h"
00002 #ifdef SX127x_H 
00003 
00004 #ifdef DEVICE_LPTICKER
00005 LowPowerTimer Radio::lpt;
00006 LowPowerTimeout TxTimeoutEvent;
00007 #else
00008 Timer Radio::lpt;
00009 Timeout TxTimeoutEvent;
00010 #endif
00011 
00012 #if (MBED_MAJOR_VERSION < 6)
00013 volatile us_timestamp_t Radio::irqAt;
00014 #else
00015 using namespace std::chrono;
00016 LowPowerClock::time_point Radio::irqAt;
00017 #endif
00018 
00019 void Radio::Sleep()
00020 {
00021     radio.set_opmode(RF_OPMODE_SLEEP);
00022 }
00023 
00024 void Radio::Standby()
00025 {
00026     radio.set_opmode(RF_OPMODE_STANDBY);
00027 }
00028 
00029 bool Radio::CheckRfFrequency(unsigned hz)
00030 {
00031     return true;
00032 }
00033 
00034 void Radio::SetChannel(unsigned hz)
00035 {
00036     radio.set_frf_MHz(hz / 1000000.0);
00037 }
00038 
00039 float Radio::getFrfMHz()
00040 {
00041     return radio.get_frf_MHz();
00042 }
00043 
00044 void SX1272OnTimeoutIrq( void )
00045 {
00046     Radio::radio.set_opmode(RF_OPMODE_STANDBY);
00047 }
00048 
00049 void Radio::SetTxContinuousWave(unsigned hz, int8_t dbm, unsigned timeout_us)
00050 {
00051     fsk.enable(true);
00052     fsk.RegPktConfig2.word = radio.read_u16(REG_FSK_PACKETCONFIG2);
00053     fsk.RegPktConfig2.bits.DataModePacket = 0; // continuous mode
00054     radio.write_u16(REG_FSK_PACKETCONFIG2, fsk.RegPktConfig2.word);
00055     fsk.set_tx_fdev_hz(0);  // unmodulated carrier, aka dead carrier
00056     SetChannel(hz);
00057     set_tx_dbm(dbm);
00058 
00059     if (timeout_us != 0) {
00060 #if (MBED_MAJOR_VERSION < 6)
00061         TxTimeoutEvent.attach_us(SX1272OnTimeoutIrq, timeout_us);
00062 #else
00063         TxTimeoutEvent.attach(SX1272OnTimeoutIrq, microseconds(timeout_us));
00064 #endif
00065     }
00066 
00067     radio.set_opmode(RF_OPMODE_TRANSMITTER);
00068 }
00069 
00070 #define LORA_MAC_PRIVATE_SYNCWORD                   0x12
00071 #define LORA_MAC_PUBLIC_SYNCWORD                    0x34
00072 void Radio::SetPublicNetwork(bool en)
00073 {
00074     radio.write_reg(REG_LR_SYNC_BYTE, en ? LORA_MAC_PUBLIC_SYNCWORD : LORA_MAC_PRIVATE_SYNCWORD);
00075 }
00076 
00077 uint32_t Radio::Random(void)
00078 {
00079     uint32_t ret = 0;
00080     unsigned i;
00081 
00082     radio.set_opmode(RF_OPMODE_RECEIVER);
00083     for (i = 0; i < 32; i++) {
00084         uint32_t r;
00085         wait_us(3000);
00086         r = radio.read_reg(REG_LR_WIDEBAND_RSSI);
00087         r <<= ((i & 7) << 2);
00088         ret ^= r;
00089     }
00090 
00091     return ret;
00092 }
00093 
00094 void Radio::LoRaPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn, bool invIQ)
00095 {
00096     lora.RegPreamble = preambleLen;
00097     radio.write_u16(REG_LR_PREAMBLEMSB, lora.RegPreamble);
00098 
00099     if (radio.type == SX1276) {
00100         lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn = fixLen;
00101         lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn = crcOn;
00102         radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet);
00103     } else if (radio.type == SX1272) {
00104         lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn = fixLen;
00105         lora.RegModemConfig.sx1272bits.RxPayloadCrcOn = crcOn;
00106     }
00107 
00108     radio.write_reg(REG_LR_MODEMCONFIG, lora.RegModemConfig.octet);
00109 
00110     lora.invert_tx(invIQ);
00111     lora.invert_rx(invIQ);
00112 }
00113 
00114 void Radio::GFSKModemConfig(unsigned bps, unsigned bw_hz, unsigned fdev_hz)
00115 {
00116     if (radio.RegOpMode.bits.LongRangeMode)
00117         fsk.enable(false);
00118 
00119     fsk.set_bitrate(bps);
00120 
00121     fsk.set_rx_dcc_bw_hz(bw_hz, 0);
00122     fsk.set_rx_dcc_bw_hz(bw_hz * 1.5, 1);
00123 
00124     fsk.set_tx_fdev_hz(fdev_hz);
00125 }
00126 
00127 
00128 void Radio::GFSKPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn)
00129 {
00130     if (radio.RegOpMode.bits.LongRangeMode)
00131         fsk.enable(false);
00132 
00133     radio.write_u16(REG_FSK_PREAMBLEMSB, preambleLen);
00134 
00135     fsk.RegPktConfig1.bits.PacketFormatVariable = fixLen ? 0 : 1;
00136     fsk.RegPktConfig1.bits.CrcOn = crcOn;
00137     radio.write_reg(REG_FSK_PACKETCONFIG1, fsk.RegPktConfig1.octet);
00138 }
00139 
00140 void Radio::SetLoRaSymbolTimeout(uint16_t symbs)
00141 {
00142     if (!radio.RegOpMode.bits.LongRangeMode)
00143         lora.enable();
00144 
00145     radio.write_reg(REG_LR_SYMBTIMEOUTLSB, symbs & 0xff);
00146     symbs >>= 8;
00147     lora.RegModemConfig2.sx1272bits.SymbTimeoutMsb = symbs;
00148     radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet);
00149 }
00150 
00151 void Radio::LoRaModemConfig(unsigned bwKHz, uint8_t sf, uint8_t coderate)
00152 {
00153     float sp;
00154     if (!radio.RegOpMode.bits.LongRangeMode)
00155         lora.enable();
00156 
00157     lora.RegModemConfig2.sx1276bits.SpreadingFactor = sf;
00158     radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet);
00159 
00160     lora.setBw_KHz(bwKHz);
00161 
00162     if (radio.type == SX1276) {
00163         lora.RegModemConfig.sx1276bits.CodingRate = coderate;
00164 
00165         sp = lora.get_symbol_period();
00166         if (sp > 16)
00167             lora.RegModemConfig3.sx1276bits.LowDataRateOptimize = 1;
00168         else
00169             lora.RegModemConfig3.sx1276bits.LowDataRateOptimize = 0;
00170 
00171         radio.write_reg(REG_LR_MODEMCONFIG3, lora.RegModemConfig3.octet);
00172     } else if (radio.type == SX1272) {
00173         lora.RegModemConfig.sx1272bits.CodingRate = coderate;
00174 
00175         if (lora.get_symbol_period() > 16)
00176             lora.RegModemConfig.sx1272bits.LowDataRateOptimize = 1;
00177         else
00178             lora.RegModemConfig.sx1272bits.LowDataRateOptimize = 0;
00179     }
00180     radio.write_reg(REG_LR_MODEMCONFIG, lora.RegModemConfig.octet);
00181 }
00182 
00183 void Radio::SetRxMaxPayloadLength(uint8_t max)
00184 {
00185     if (radio.RegOpMode.bits.LongRangeMode)
00186         radio.write_reg(REG_LR_RX_MAX_PAYLOADLENGTH, max);
00187     else
00188         radio.write_reg(REG_FSK_PAYLOADLENGTH, max);
00189 }
00190 
00191 void Radio::SetFixedPayloadLength(uint8_t len)
00192 {
00193     lora.RegPayloadLength = len;
00194     radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
00195 }
00196 
00197 const RadioEvents_t* RadioEvents;
00198 
00199 
00200 volatile struct pe {
00201     uint8_t dio0 : 1;
00202     uint8_t dio1 : 1;
00203     uint8_t txing : 1;
00204 } pinEvent;
00205 
00206 void
00207 Radio::dio0UserContext()
00208 {
00209     service_action_e act = lora.service();
00210 
00211     if (!pinEvent.txing) {
00212         if (act == SERVICE_READ_FIFO && RadioEvents->RxDone) {
00213             int8_t rssi;
00214             float snr = lora.RegPktSnrValue / 4.0;
00215             
00216             rssi = lora.get_pkt_rssi();
00217             if (snr < 0)
00218                 rssi += snr;
00219             RadioEvents->RxDone(lora.RegRxNbBytes, rssi, snr);
00220         } 
00221     } else if (act == SERVICE_TX_DONE) {
00222         if (RadioEvents->TxDone_botHalf)
00223             RadioEvents->TxDone_botHalf();
00224     }
00225 }
00226 
00227 void Radio::dio0isr()
00228 {
00229 #if (MBED_MAJOR_VERSION < 6)
00230     irqAt = lpt.read_us();
00231 #else
00232     irqAt = LowPowerClock::now();
00233 #endif
00234 
00235     if (RadioEvents->DioPin_top_half)
00236         RadioEvents->DioPin_top_half();
00237  
00238     if (pinEvent.txing) {
00239         /* TxDone handling requires low latency */
00240         if (RadioEvents->TxDone_topHalf)
00241             RadioEvents->TxDone_topHalf();    // TODO in callback read irqAt for timestamp of interrupt
00242 
00243     }
00244 
00245     pinEvent.dio0 = 1;
00246 }
00247 
00248 void Radio::dio1UserContext()
00249 {
00250     lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);
00251 
00252     if (RadioEvents->RxTimeout)
00253         RadioEvents->RxTimeout();
00254 
00255     radio.write_reg(REG_LR_IRQFLAGS, 0x80); // ensure RxTimeout is cleared
00256 }
00257 
00258 void Radio::dio1isr()
00259 {
00260     pinEvent.dio1 = 1;
00261 
00262     if (RadioEvents->DioPin_top_half)
00263         RadioEvents->DioPin_top_half();
00264 }
00265 
00266 void Radio::Init(const RadioEvents_t* e, unsigned spi_hz)
00267 {
00268     radio.m_spi.frequency(spi_hz);
00269 
00270     while (radio.dio0.read() || radio.dio1.read()) {
00271         radio.write_reg(REG_LR_IRQFLAGS, 0xff); // clear stagnant interrupt
00272     }
00273     dio0.rise(dio0isr);
00274     dio1.rise(dio1isr);
00275 
00276     radio.rf_switch = rfsw_callback;
00277     boardInit();
00278 
00279     RadioEvents = e;
00280     lpt.start();
00281 }
00282 
00283 float Radio::GetRssiInst()
00284 {
00285     return lora.get_current_rssi();
00286 }
00287 
00288 int Radio::Send(uint8_t size, timestamp_t maxListenTime, timestamp_t channelFreeTime, int rssiThresh)
00289 {
00290     if (radio.RegOpMode.bits.Mode == RF_OPMODE_SLEEP) {
00291         radio.set_opmode(RF_OPMODE_STANDBY);
00292         wait_us(1000);
00293     }
00294     radio.write_reg(REG_LR_IRQFLAGS, 0x08); // ensure TxDone is cleared
00295     lora.RegPayloadLength = size;
00296     radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
00297 
00298     if (maxListenTime > 0) {
00299         int rssi;
00300         us_timestamp_t startAt, chFreeAt, now;
00301         lora.start_rx(RF_OPMODE_RECEIVER);
00302     #if (MBED_MAJOR_VERSION < 6)
00303         startAt = lpt.read_us();
00304     #else
00305         startAt = LowPowerClock::now().time_since_epoch().count();
00306     #endif
00307 Lstart:
00308         do {
00309     #if (MBED_MAJOR_VERSION < 6)
00310             now = lpt.read_us();
00311     #else
00312             now = LowPowerClock::now().time_since_epoch().count();
00313     #endif
00314             if ((now - startAt) > maxListenTime) {
00315                 return -1;
00316             }
00317             rssi = lora.get_current_rssi();
00318         } while (rssi > rssiThresh);
00319     #if (MBED_MAJOR_VERSION < 6)
00320         chFreeAt = lpt.read_us();
00321     #else
00322         chFreeAt = LowPowerClock::now().time_since_epoch().count();
00323     #endif
00324         do {
00325     #if (MBED_MAJOR_VERSION < 6)
00326             now = lpt.read_us();
00327     #else
00328             now = LowPowerClock::now().time_since_epoch().count();
00329     #endif
00330             rssi = lora.get_current_rssi();
00331             if (rssi > rssiThresh) {
00332                 goto Lstart;
00333             }
00334         } while ((now - chFreeAt) < channelFreeTime);
00335     }
00336 
00337     lora.start_tx(size);
00338     pinEvent.txing = 1;
00339 
00340     return 0;
00341 }
00342 
00343 void Radio::Rx(unsigned timeout)
00344 {
00345     if (timeout == 0) {
00346         lora.start_rx(RF_OPMODE_RECEIVER);
00347     } else {
00348         lora.start_rx(RF_OPMODE_RECEIVER_SINGLE);
00349     }
00350 
00351     pinEvent.txing = 0;
00352 }
00353 
00354 
00355 void Radio::ocp(uint8_t ma)
00356 {
00357     if (ma < 130)
00358         radio.RegOcp.bits.OcpTrim = (ma - 45) / 5;
00359     else
00360         radio.RegOcp.bits.OcpTrim = (ma + 30) / 10;
00361     radio.write_reg(REG_OCP, radio.RegOcp.octet);
00362    
00363     radio.RegOcp.octet = radio.read_reg(REG_OCP);
00364     if (radio.RegOcp.bits.OcpTrim < 16)
00365         ma = 45 + (5 * radio.RegOcp.bits.OcpTrim);
00366     else if (radio.RegOcp.bits.OcpTrim < 28)
00367         ma = (10 * radio.RegOcp.bits.OcpTrim) - 30;
00368     else
00369         ma = 240;
00370 }
00371 
00372 
00373 #if 0
00374 void Radio::PrintStatus()
00375 {
00376 #ifdef MAC_DEBUG
00377     radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
00378     switch (radio.RegOpMode.bits.Mode) {
00379         case RF_OPMODE_SLEEP: printf("SLEEP "); break;
00380         case RF_OPMODE_STANDBY: printf("STBY "); break;
00381         case RF_OPMODE_SYNTHESIZER_TX: printf("FSTX "); break;
00382         case RF_OPMODE_TRANSMITTER: printf("TX "); break;
00383         case RF_OPMODE_SYNTHESIZER_RX: printf("FSRX "); break;
00384         case RF_OPMODE_RECEIVER: printf("RXC "); break;
00385         case RF_OPMODE_RECEIVER_SINGLE: printf("RXS "); break;
00386         case RF_OPMODE_CAD: printf("CAD "); break;
00387     }
00388 
00389     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());
00390     lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);
00391     printf("irqFlags:%02x\r\n", lora.RegIrqFlags.octet);
00392 #endif /* MAC_DEBUG */
00393 }
00394 #endif /* if 0 */
00395 
00396 #ifdef DUTY_ENABLE
00397 us_timestamp_t
00398 Radio::TimeOnAir(RadioModems_t m, uint8_t pktLen)
00399 {
00400     uint32_t airTime = 0;
00401 
00402     switch (m)
00403     {
00404     case MODEM_FSK:
00405         {
00406             /* TODO
00407             airTime = round( ( 8 * ( SX1272.Settings.Fsk.PreambleLen +
00408                                      ( ( SX1272Read( REG_SYNCCONFIG ) & ~RF_SYNCCONFIG_SYNCSIZE_MASK ) + 1 ) +
00409                                      ( ( SX1272.Settings.Fsk.FixLen == 0x01 ) ? 0.0 : 1.0 ) +
00410                                      ( ( ( SX1272Read( REG_PACKETCONFIG1 ) & ~RF_PACKETCONFIG1_ADDRSFILTERING_MASK ) != 0x00 ) ? 1.0 : 0 ) +
00411                                      pktLen +
00412                                      ( ( SX1272.Settings.Fsk.CrcOn == 0x01 ) ? 2.0 : 0 ) ) /
00413                                      SX1272.Settings.Fsk.Datarate ) * 1e3 );
00414                                      */
00415         }
00416         break;
00417     case MODEM_LORA:
00418         {
00419             double bw = 0.0;
00420             uint8_t fixLen, bandwidth, LowDatarateOptimize, coderate, crcOn ;
00421             if (radio.type == SX1276) {
00422                 coderate = lora.RegModemConfig.sx1276bits.CodingRate;
00423                 LowDatarateOptimize = lora.RegModemConfig3.sx1276bits.LowDataRateOptimize;
00424                 fixLen = lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn;
00425                 bandwidth = lora.RegModemConfig.sx1276bits.Bw - 7;
00426                 crcOn = lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn;
00427             } else if (radio.type == SX1272) {
00428                 coderate = lora.RegModemConfig.sx1272bits.CodingRate;
00429                 LowDatarateOptimize = lora.RegModemConfig.sx1272bits.LowDataRateOptimize;
00430                 fixLen = lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn;
00431                 bandwidth = lora.RegModemConfig.sx1272bits.Bw;
00432                 crcOn = lora.RegModemConfig.sx1272bits.RxPayloadCrcOn;
00433             } else
00434                 return 0;
00435 
00436             switch( bandwidth )
00437             {
00438             case 0: // 125 kHz
00439                 bw = 125;//ms: 125e3;
00440                 break;
00441             case 1: // 250 kHz
00442                 bw = 250;//ms:250e3;
00443                 break;
00444             case 2: // 500 kHz
00445                 bw = 500;//ms:500e3;
00446                 break;
00447             }
00448 
00449             // Symbol rate : time for one symbol (secs)
00450             double rs = bw / ( 1 << lora.RegModemConfig2.sx1276bits.SpreadingFactor );
00451             double ts = 1 / rs;
00452             // time of preamble
00453             double tPreamble;
00454             tPreamble = (lora.RegPreamble + 4.25 ) * ts;
00455             // Symbol length of payload and time
00456             double tmp = ceil( ( 8 * pktLen - 4 * lora.RegModemConfig2.sx1276bits.SpreadingFactor +
00457                                  28 + 16 * crcOn -
00458                                  ( fixLen ? 20 : 0 ) ) /
00459                                  ( double )( 4 * ( lora.RegModemConfig2.sx1276bits.SpreadingFactor -
00460                                  ( ( LowDatarateOptimize > 0 ) ? 2 : 0 ) ) ) ) *
00461                                  ( coderate + 4 );
00462             double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 );
00463             double tPayload = nPayload * ts;
00464             // Time on air
00465             double tOnAir = tPreamble + tPayload;
00466             // return ms secs
00467             airTime = floor( tOnAir * 1e3 + 0.999 );
00468         }
00469         break;
00470     }
00471     return airTime;
00472 
00473 }
00474 #endif /* DUTY_ENABLE */
00475 
00476 void Radio::service()
00477 {
00478     if (pinEvent.dio0) {
00479         dio0UserContext();
00480         pinEvent.txing = 0;
00481         pinEvent.dio0 = 0;
00482     } else if (radio.dio0.read()) {
00483         /* fail: missed interrupt */
00484         dio0isr();
00485     }
00486 
00487     if (pinEvent.dio1) {
00488         dio1UserContext();
00489         pinEvent.dio1 = 0;
00490     }
00491 }
00492 
00493 uint32_t Radio::lora_toa_us( uint8_t pktLen )
00494 {
00495     uint32_t airTime = 0;
00496     uint8_t chipBW = Radio::lora.getBw();
00497     double bwKHz;
00498     uint8_t LowDataRateOptimize;
00499     bool FixLen;
00500     uint8_t crcOn;
00501     uint16_t preambleLen = Radio::radio.read_u16(REG_LR_PREAMBLEMSB);
00502 
00503     Radio::lora.RegModemConfig2.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG2);
00504     Radio::lora.RegModemConfig.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG);
00505 
00506     if (Radio::radio.type == SX1276) {
00507         chipBW -= 7;
00508         Radio::lora.RegModemConfig3.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG3);
00509         LowDataRateOptimize = Radio::lora.RegModemConfig3.sx1276bits.LowDataRateOptimize;
00510         FixLen = Radio::lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn;
00511         crcOn = Radio::lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn;
00512     } else if (Radio::radio.type == SX1272) {
00513         LowDataRateOptimize = Radio::lora.RegModemConfig.sx1272bits.LowDataRateOptimize;
00514         FixLen = Radio::lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn;
00515         crcOn = Radio::lora.RegModemConfig.sx1272bits.RxPayloadCrcOn;
00516     } else
00517         return 0;
00518 
00519     switch (chipBW) {
00520         case 0: bwKHz = 125; break;
00521         case 1: bwKHz = 250; break;
00522         case 2: bwKHz = 500; break;
00523         default: return 0;
00524     }
00525 
00526     // Symbol rate : time for one symbol (secs)
00527     double rs = bwKHz / ( 1 << Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor );
00528     double ts = 1 / rs;
00529     // time of preamble
00530     double tPreamble = ( preambleLen + 4.25 ) * ts;
00531     // Symbol length of payload and time
00532     double tmp = ceil( ( 8 * pktLen - 4 * Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor +
00533                          28 + 16 * crcOn -
00534                          ( FixLen ? 20 : 0 ) ) /
00535                          ( double )( 4 * ( Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor -
00536                          ( ( LowDataRateOptimize > 0 ) ? 2 : 0 ) ) ) ) *
00537                          ( Radio::lora.getCodingRate(false) + 4 );
00538     double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 );
00539     double tPayload = nPayload * ts;
00540     // Time on air
00541     double tOnAir = tPreamble + tPayload;
00542     // return microseconds
00543     airTime = floor( tOnAir * 1000 + 0.999 );
00544 
00545     return airTime;
00546 }
00547 #endif /* ..SX127x_H */
00548