1

Revision:
0:9c052ff8dd6a
Child:
1:e79b0a55135f
diff -r 000000000000 -r 9c052ff8dd6a radio_sx127x.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/radio_sx127x.cpp	Thu Jul 05 17:31:54 2018 -0700
@@ -0,0 +1,481 @@
+#include "radio.h"
+#ifdef SX127x_H 
+
+LowPowerTimer Radio::lpt;
+
+void Radio::Sleep()
+{
+    radio.set_opmode(RF_OPMODE_SLEEP);
+}
+
+void Radio::Standby()
+{
+    radio.set_opmode(RF_OPMODE_STANDBY);
+}
+
+bool Radio::CheckRfFrequency(unsigned hz)
+{
+    return true;
+}
+
+void Radio::SetChannel(unsigned hz)
+{
+    radio.set_frf_MHz(hz / 1000000.0);
+}
+
+float Radio::getFrfMHz()
+{
+    return radio.get_frf_MHz();
+}
+
+LowPowerTimeout TxTimeoutEvent;
+
+void SX1272OnTimeoutIrq( void )
+{
+    Radio::radio.set_opmode(RF_OPMODE_STANDBY);
+}
+
+void Radio::SetTxContinuousWave(unsigned hz, int8_t dbm, unsigned timeout_us)
+{
+    Radio::SetChannel(hz);
+    /* TODO: fsk enable, set regPacketConfig2.datamode */
+    set_tx_dbm(dbm);
+    TxTimeoutEvent.attach_us(SX1272OnTimeoutIrq, timeout_us);
+    radio.set_opmode(RF_OPMODE_TRANSMITTER);
+}
+
+#define LORA_MAC_PRIVATE_SYNCWORD                   0x12
+#define LORA_MAC_PUBLIC_SYNCWORD                    0x34
+void Radio::SetPublicNetwork(bool en)
+{
+    radio.write_reg(REG_LR_SYNC_BYTE, en ? LORA_MAC_PUBLIC_SYNCWORD : LORA_MAC_PRIVATE_SYNCWORD);
+}
+
+uint32_t Radio::Random(void)
+{
+    uint32_t ret = 0;
+    unsigned i;
+
+    radio.set_opmode(RF_OPMODE_RECEIVER);
+    for (i = 0; i < 32; i++) {
+        uint32_t r;
+        wait_us(3000);
+        r = radio.read_reg(REG_LR_WIDEBAND_RSSI);
+        r <<= ((i & 7) << 2);
+        ret ^= r;
+    }
+
+    return ret;
+}
+
+void Radio::LoRaPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn, bool invIQ)
+{
+    lora.RegPreamble = preambleLen;
+    radio.write_u16(REG_LR_PREAMBLEMSB, lora.RegPreamble);
+
+    if (radio.type == SX1276) {
+        lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn = fixLen;
+        lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn = crcOn;
+        radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet);
+    } else if (radio.type == SX1272) {
+        lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn = fixLen;
+        lora.RegModemConfig.sx1272bits.RxPayloadCrcOn = crcOn;
+    }
+
+    radio.write_reg(REG_LR_MODEMCONFIG, lora.RegModemConfig.octet);
+
+    lora.invert_tx(invIQ);
+    lora.invert_rx(invIQ);
+}
+
+void Radio::GFSKModemConfig(unsigned bps, unsigned bw_hz, unsigned fdev_hz)
+{
+    if (radio.RegOpMode.bits.LongRangeMode)
+        fsk.enable(false);
+
+    fsk.set_bitrate(bps);
+
+    fsk.set_rx_dcc_bw_hz(bw_hz, 0);
+    fsk.set_rx_dcc_bw_hz(bw_hz * 1.5, 1);
+
+    fsk.set_tx_fdev_hz(fdev_hz);
+}
+
+
+void Radio::GFSKPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn)
+{
+    if (radio.RegOpMode.bits.LongRangeMode)
+        fsk.enable(false);
+
+    radio.write_u16(REG_FSK_PREAMBLEMSB, preambleLen);
+
+    fsk.RegPktConfig1.bits.PacketFormatVariable = fixLen ? 0 : 1;
+    fsk.RegPktConfig1.bits.CrcOn = crcOn;
+    radio.write_reg(REG_FSK_PACKETCONFIG1, fsk.RegPktConfig1.octet);
+}
+
+void Radio::SetLoRaSymbolTimeout(uint8_t symbs)
+{
+    if (!radio.RegOpMode.bits.LongRangeMode)
+        lora.enable();
+
+    lora.RegModemConfig2.sx1272bits.SymbTimeoutMsb = 0;
+    radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet);
+    radio.write_reg(REG_LR_SYMBTIMEOUTLSB, symbs);
+}
+
+void Radio::LoRaModemConfig(unsigned bwKHz, uint8_t sf, uint8_t coderate)
+{
+    float sp;
+    if (!radio.RegOpMode.bits.LongRangeMode)
+        lora.enable();
+
+    lora.RegModemConfig2.sx1276bits.SpreadingFactor = sf;
+    radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet);
+
+    lora.setBw_KHz(bwKHz);
+
+    if (radio.type == SX1276) {
+        lora.RegModemConfig.sx1276bits.CodingRate = coderate;
+
+        sp = lora.get_symbol_period();
+        if (sp > 16)
+            lora.RegModemConfig3.sx1276bits.LowDataRateOptimize = 1;
+        else
+            lora.RegModemConfig3.sx1276bits.LowDataRateOptimize = 0;
+
+        radio.write_reg(REG_LR_MODEMCONFIG3, lora.RegModemConfig3.octet);
+    } else if (radio.type == SX1272) {
+        lora.RegModemConfig.sx1272bits.CodingRate = coderate;
+
+        if (lora.get_symbol_period() > 16)
+            lora.RegModemConfig.sx1272bits.LowDataRateOptimize = 1;
+        else
+            lora.RegModemConfig.sx1272bits.LowDataRateOptimize = 0;
+    }
+    radio.write_reg(REG_LR_MODEMCONFIG, lora.RegModemConfig.octet);
+}
+
+void Radio::SetRxMaxPayloadLength(RadioModems_t modem, uint8_t max)
+{
+    /* TODO fsk */
+    radio.write_reg(REG_LR_RX_MAX_PAYLOADLENGTH, max);
+}
+
+const RadioEvents_t* RadioEvents;
+
+
+volatile struct pe {
+    uint8_t dio0 : 1;
+    uint8_t dio1 : 1;
+    uint8_t txing : 1;
+} pinEvent;
+
+void
+Radio::dio0UserContext()
+{
+    service_action_e act = lora.service();
+
+    if (!pinEvent.txing) {
+        if (act == SERVICE_READ_FIFO && RadioEvents->RxDone) {
+            int8_t rssi;
+            float snr = lora.RegPktSnrValue / 4.0;
+            
+            rssi = lora.get_pkt_rssi();
+            if (snr < 0)
+                rssi += snr;
+            RadioEvents->RxDone(lora.RegRxNbBytes, rssi, snr);
+        } 
+    } else if (act == SERVICE_TX_DONE) {
+        if (RadioEvents->TxDone_botHalf)
+            RadioEvents->TxDone_botHalf();
+    }
+}
+
+volatile us_timestamp_t Radio::irqAt;
+
+void Radio::dio0isr()
+{
+    irqAt = lpt.read_us();
+ 
+    if (pinEvent.txing) {
+        /* TxDone handling requires low latency */
+        if (RadioEvents->TxDone_topHalf)
+            RadioEvents->TxDone_topHalf();    // TODO in callback read irqAt for timestamp of interrupt
+
+    }
+
+    pinEvent.dio0 = 1;
+}
+
+void Radio::dio1UserContext()
+{
+    lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);
+
+    if (RadioEvents->RxTimeout)
+        RadioEvents->RxTimeout();
+
+    radio.write_reg(REG_LR_IRQFLAGS, 0x80); // ensure RxTimeout is cleared
+}
+
+void Radio::dio1isr()
+{
+    pinEvent.dio1 = 1;
+}
+
+void Radio::Init(const RadioEvents_t* e)
+{
+    dio0.rise(dio0isr);
+    dio1.rise(dio1isr);
+
+    radio.rf_switch = rfsw_callback;
+    boardInit();
+
+    RadioEvents = e;
+    lpt.start();
+}
+
+int Radio::Send(uint8_t size, timestamp_t maxListenTime, timestamp_t channelFreeTime, int rssiThresh)
+{
+    if (radio.RegOpMode.bits.Mode == RF_OPMODE_SLEEP) {
+        radio.set_opmode(RF_OPMODE_STANDBY);
+        wait_us(1000);
+    }
+    radio.write_reg(REG_LR_IRQFLAGS, 0x08); // ensure TxDone is cleared
+    lora.RegPayloadLength = size;
+    radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
+
+    if (maxListenTime > 0) {
+        int rssi;
+        us_timestamp_t startAt, chFreeAt, now;
+        lora.start_rx(RF_OPMODE_RECEIVER);
+        startAt = lpt.read_us();
+Lstart:
+        do {
+            now = lpt.read_us();
+            if ((now - startAt) > maxListenTime) {
+                return -1;
+            }
+            rssi = lora.get_current_rssi();
+        } while (rssi > rssiThresh);
+        chFreeAt = lpt.read_us();
+        do {
+            now = lpt.read_us();
+            rssi = lora.get_current_rssi();
+            if (rssi > rssiThresh) {
+                goto Lstart;
+            }
+        } while ((now - chFreeAt) < channelFreeTime);
+    }
+
+    lora.start_tx(size);
+    pinEvent.txing = 1;
+
+    return 0;
+}
+
+void Radio::Rx(unsigned timeout)
+{
+    if (timeout == 0) {
+        lora.start_rx(RF_OPMODE_RECEIVER);
+    } else {
+        lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);   // yyy tmp remove
+        lora.start_rx(RF_OPMODE_RECEIVER_SINGLE);
+    }
+
+    pinEvent.txing = 0;
+
+}
+
+
+void Radio::ocp(uint8_t ma)
+{
+    if (ma < 130)
+        radio.RegOcp.bits.OcpTrim = (ma - 45) / 5;
+    else
+        radio.RegOcp.bits.OcpTrim = (ma + 30) / 10;
+    radio.write_reg(REG_OCP, radio.RegOcp.octet);
+   
+    radio.RegOcp.octet = radio.read_reg(REG_OCP);
+    if (radio.RegOcp.bits.OcpTrim < 16)
+        ma = 45 + (5 * radio.RegOcp.bits.OcpTrim);
+    else if (radio.RegOcp.bits.OcpTrim < 28)
+        ma = (10 * radio.RegOcp.bits.OcpTrim) - 30;
+    else
+        ma = 240;
+}
+
+
+#if 0
+void Radio::PrintStatus()
+{
+#ifdef MAC_DEBUG
+    radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
+    switch (radio.RegOpMode.bits.Mode) {
+        case RF_OPMODE_SLEEP: printf("SLEEP "); break;
+        case RF_OPMODE_STANDBY: printf("STBY "); break;
+        case RF_OPMODE_SYNTHESIZER_TX: printf("FSTX "); break;
+        case RF_OPMODE_TRANSMITTER: printf("TX "); break;
+        case RF_OPMODE_SYNTHESIZER_RX: printf("FSRX "); break;
+        case RF_OPMODE_RECEIVER: printf("RXC "); break;
+        case RF_OPMODE_RECEIVER_SINGLE: printf("RXS "); break;
+        case RF_OPMODE_CAD: printf("CAD "); break;
+    }
+
+    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());
+    lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);
+    printf("irqFlags:%02x\r\n", lora.RegIrqFlags.octet);
+#endif /* MAC_DEBUG */
+}
+#endif /* if 0 */
+
+#ifdef DUTY_ENABLE
+us_timestamp_t
+Radio::TimeOnAir(RadioModems_t m, uint8_t pktLen)
+{
+    uint32_t airTime = 0;
+
+    switch (m)
+    {
+    case MODEM_FSK:
+        {
+            /* TODO
+            airTime = round( ( 8 * ( SX1272.Settings.Fsk.PreambleLen +
+                                     ( ( SX1272Read( REG_SYNCCONFIG ) & ~RF_SYNCCONFIG_SYNCSIZE_MASK ) + 1 ) +
+                                     ( ( SX1272.Settings.Fsk.FixLen == 0x01 ) ? 0.0 : 1.0 ) +
+                                     ( ( ( SX1272Read( REG_PACKETCONFIG1 ) & ~RF_PACKETCONFIG1_ADDRSFILTERING_MASK ) != 0x00 ) ? 1.0 : 0 ) +
+                                     pktLen +
+                                     ( ( SX1272.Settings.Fsk.CrcOn == 0x01 ) ? 2.0 : 0 ) ) /
+                                     SX1272.Settings.Fsk.Datarate ) * 1e3 );
+                                     */
+        }
+        break;
+    case MODEM_LORA:
+        {
+            double bw = 0.0;
+            uint8_t fixLen, bandwidth, LowDatarateOptimize, coderate, crcOn ;
+            if (radio.type == SX1276) {
+                coderate = lora.RegModemConfig.sx1276bits.CodingRate;
+                LowDatarateOptimize = lora.RegModemConfig3.sx1276bits.LowDataRateOptimize;
+                fixLen = lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn;
+                bandwidth = lora.RegModemConfig.sx1276bits.Bw - 7;
+                crcOn = lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn;
+            } else if (radio.type == SX1272) {
+                coderate = lora.RegModemConfig.sx1272bits.CodingRate;
+                LowDatarateOptimize = lora.RegModemConfig.sx1272bits.LowDataRateOptimize;
+                fixLen = lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn;
+                bandwidth = lora.RegModemConfig.sx1272bits.Bw;
+                crcOn = lora.RegModemConfig.sx1272bits.RxPayloadCrcOn;
+            } else
+                return 0;
+
+            switch( bandwidth )
+            {
+            case 0: // 125 kHz
+                bw = 125;//ms: 125e3;
+                break;
+            case 1: // 250 kHz
+                bw = 250;//ms:250e3;
+                break;
+            case 2: // 500 kHz
+                bw = 500;//ms:500e3;
+                break;
+            }
+
+            // Symbol rate : time for one symbol (secs)
+            double rs = bw / ( 1 << lora.RegModemConfig2.sx1276bits.SpreadingFactor );
+            double ts = 1 / rs;
+            // time of preamble
+            double tPreamble;
+            tPreamble = (lora.RegPreamble + 4.25 ) * ts;
+            // Symbol length of payload and time
+            double tmp = ceil( ( 8 * pktLen - 4 * lora.RegModemConfig2.sx1276bits.SpreadingFactor +
+                                 28 + 16 * crcOn -
+                                 ( fixLen ? 20 : 0 ) ) /
+                                 ( double )( 4 * ( lora.RegModemConfig2.sx1276bits.SpreadingFactor -
+                                 ( ( LowDatarateOptimize > 0 ) ? 2 : 0 ) ) ) ) *
+                                 ( coderate + 4 );
+            double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 );
+            double tPayload = nPayload * ts;
+            // Time on air
+            double tOnAir = tPreamble + tPayload;
+            // return ms secs
+            airTime = floor( tOnAir * 1e3 + 0.999 );
+        }
+        break;
+    }
+    return airTime;
+
+}
+#endif /* DUTY_ENABLE */
+
+void Radio::service()
+{
+    if (pinEvent.dio0) {
+        dio0UserContext();
+        pinEvent.txing = 0;
+        pinEvent.dio0 = 0;
+    }
+
+    if (pinEvent.dio1) {
+        dio1UserContext();
+        pinEvent.dio1 = 0;
+    }
+}
+
+uint32_t Radio::lora_toa_us( uint8_t pktLen )
+{
+    uint32_t airTime = 0;
+    uint8_t chipBW = Radio::lora.getBw();
+    double bwKHz;
+    uint8_t LowDataRateOptimize;
+    bool FixLen;
+    uint8_t crcOn;
+    uint16_t preambleLen = Radio::radio.read_u16(REG_LR_PREAMBLEMSB);
+
+    Radio::lora.RegModemConfig2.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG2);
+    Radio::lora.RegModemConfig.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG);
+
+    if (Radio::radio.type == SX1276) {
+        chipBW -= 7;
+        Radio::lora.RegModemConfig3.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG3);
+        LowDataRateOptimize = Radio::lora.RegModemConfig3.sx1276bits.LowDataRateOptimize;
+        FixLen = Radio::lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn;
+        crcOn = Radio::lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn;
+    } else if (Radio::radio.type == SX1272) {
+        LowDataRateOptimize = Radio::lora.RegModemConfig.sx1272bits.LowDataRateOptimize;
+        FixLen = Radio::lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn;
+        crcOn = Radio::lora.RegModemConfig.sx1272bits.RxPayloadCrcOn;
+    } else
+        return 0;
+
+    switch (chipBW) {
+        case 0: bwKHz = 125; break;
+        case 1: bwKHz = 250; break;
+        case 2: bwKHz = 500; break;
+        default: return 0;
+    }
+
+    // Symbol rate : time for one symbol (secs)
+    double rs = bwKHz / ( 1 << Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor );
+    double ts = 1 / rs;
+    // time of preamble
+    double tPreamble = ( preambleLen + 4.25 ) * ts;
+    // Symbol length of payload and time
+    double tmp = ceil( ( 8 * pktLen - 4 * Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor +
+                         28 + 16 * crcOn -
+                         ( FixLen ? 20 : 0 ) ) /
+                         ( double )( 4 * ( Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor -
+                         ( ( LowDataRateOptimize > 0 ) ? 2 : 0 ) ) ) ) *
+                         ( Radio::lora.getCodingRate(false) + 4 );
+    double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 );
+    double tPayload = nPayload * ts;
+    // Time on air
+    double tOnAir = tPreamble + tPayload;
+    // return microseconds
+    airTime = floor( tOnAir * 1000 + 0.999 );
+
+    return airTime;
+}
+#endif /* ..SX127x_H */
+