ver1

Revision:
172:7ec44396a51b
Parent:
153:7c00843e4bba
Child:
178:8f7d93f3bbb5
diff -r 4a3957006cf2 -r 7ec44396a51b plans/ChannelPlan_US915.cpp
--- a/plans/ChannelPlan_US915.cpp	Wed Aug 08 09:33:35 2018 -0500
+++ b/plans/ChannelPlan_US915.cpp	Thu Aug 30 09:05:16 2018 -0500
@@ -28,6 +28,8 @@
 ChannelPlan_US915::ChannelPlan_US915()
 :
   ChannelPlan(NULL, NULL)
+  , _bcnFreqHop(true)
+  , _pingFreqHop(true)
 {
 
 }
@@ -35,6 +37,8 @@
 ChannelPlan_US915::ChannelPlan_US915(Settings* settings)
 :
   ChannelPlan(NULL, settings)
+  , _bcnFreqHop(true)
+  , _pingFreqHop(true)
 {
 
 }
@@ -42,6 +46,8 @@
 ChannelPlan_US915::ChannelPlan_US915(SxRadio* radio, Settings* settings)
 :
   ChannelPlan(radio, settings)
+  , _bcnFreqHop(true)
+  , _pingFreqHop(true)
 {
 
 }
@@ -87,6 +93,11 @@
     _freqDStep500k = US915_500K_DSTEP;
     GetSettings()->Session.Rx2Frequency = US915_500K_DBASE;
 
+    GetSettings()->Session.BeaconFrequency = US915_BEACON_FREQ_BASE;
+    GetSettings()->Session.BeaconDatarateIndex = US915_BEACON_DR;
+    GetSettings()->Session.PingSlotFrequency = US915_BEACON_FREQ_BASE;
+    GetSettings()->Session.PingSlotDatarateIndex = US915_BEACON_DR;
+
     _minDatarate = US915_MIN_DATARATE;
     _maxDatarate = US915_MAX_DATARATE;
     _minRx2Datarate = DR_8;
@@ -280,7 +291,7 @@
     return LORA_OK;
 }
 
-uint8_t ChannelPlan_US915::SetRxConfig(uint8_t window, bool continuous) {
+uint8_t ChannelPlan_US915::SetRxConfig(uint8_t window, bool continuous, uint16_t wnd_growth) {
 
     RxWindow rxw = GetRxWindow(window);
     GetRadio()->SetChannel(rxw.Frequency);
@@ -290,8 +301,10 @@
     uint32_t sf = rxDr.SpreadingFactor;
     uint8_t cr = rxDr.Coderate;
     uint8_t pl = rxDr.PreambleLength;
-    uint16_t sto = rxDr.SymbolTimeout();
+    uint16_t sto = rxDr.SymbolTimeout() * wnd_growth;
     uint32_t afc = 0;
+    bool fixLen = false;
+    uint8_t payloadLen = 0U;
     bool crc = false; // downlink does not use CRC according to LORAWAN
 
     if (GetSettings()->Network.DisableCRC == true)
@@ -304,6 +317,14 @@
         iq = txDr.TxIQ;
     }
 
+    // Beacon modifications - no I/Q inversion, fixed length rx, preamble
+    if (window == RX_BEACON) {
+        iq = txDr.TxIQ;
+        fixLen = true;
+        payloadLen = sizeof(BCNPayload);
+        pl = BEACON_PREAMBLE_LENGTH;
+    }
+
     SxRadio::RadioModems_t modem = SxRadio::MODEM_LORA;
 
     if (sf == SF_FSK) {
@@ -320,7 +341,7 @@
     // logTrace("Configure radio for RX%d on freq: %lu", window, rxw.Frequency);
     // logTrace("RX SF: %u BW: %u CR: %u PL: %u STO: %u CRC: %d IQ: %d", sf, bw, cr, pl, sto, crc, iq);
 
-    GetRadio()->SetRxConfig(modem, bw, sf, cr, afc, pl, sto, false, 0, crc, false, 0, iq, continuous);
+    GetRadio()->SetRxConfig(modem, bw, sf, cr, afc, pl, sto, fixLen, payloadLen, crc, false, 0, iq, continuous);
 
     return LORA_OK;
 }
@@ -410,7 +431,8 @@
         rxw.Frequency = GetSettings()->Network.TxFrequency;
         index = GetSettings()->Session.TxDatarate;
     } else {
-        if (window == 1) {
+        switch (window) {
+        case RX_1:
             if (_txChannel < _numChans125k) {
                 if (GetSettings()->Network.Mode == lora::PRIVATE_MTS)
                     rxw.Frequency = _freqDBase500k + (_txChannel / 8) * _freqDStep500k;
@@ -431,15 +453,31 @@
                 if (index < DR_8)
                     index = DR_8;
             }
-        } else {
-            if (GetSettings()->Network.Mode == lora::PRIVATE_MTS)
+
+            break;
+
+        case RX_BEACON:
+            rxw.Frequency = GetSettings()->Session.BeaconFrequency;
+            index = GetSettings()->Session.BeaconDatarateIndex;
+            break;
+
+        case RX_SLOT:
+            rxw.Frequency = GetSettings()->Session.PingSlotFrequency;
+            index = GetSettings()->Session.PingSlotDatarateIndex;
+            break;
+
+        // RX2, RXC, RX_TEST, etc..
+        default:
+            if (GetSettings()->Network.Mode == lora::PRIVATE_MTS) {
                 if (_txChannel < _numChans125k) {
                     rxw.Frequency = _freqDBase500k + (_txChannel / 8) * _freqDStep500k;
                 } else {
                     rxw.Frequency = _freqDBase500k + (_txChannel % 8) * _freqDStep500k;
                 }
-            else
+            } else {
                 rxw.Frequency = GetSettings()->Session.Rx2Frequency;
+            }
+
             index = GetSettings()->Session.Rx2DatarateIndex;
         }
     }
@@ -506,54 +544,73 @@
 }
 
 uint8_t ChannelPlan_US915::HandlePingSlotChannelReq(const uint8_t* payload, uint8_t index, uint8_t size, uint8_t& status) {
+    uint8_t datarate = 0;
+    uint32_t freq = 0;
+    bool freqHop = false;
 
-    lora::CopyFreqtoInt(payload + index, _beaconRxChannel.Frequency);
-    index += 3;
+    status = 0x03;
 
-    if (_beaconRxChannel.Frequency != 0) {
-        _beaconRxChannel.DrRange.Value = payload[index];
-    } else {
-        // TODO: set to default beacon rx channel
+    freq = payload[index++];
+    freq |= payload[index++] << 8;
+    freq |= payload[index++] << 16;
+    freq *= 100;
+
+    datarate = payload[index] & 0x0F;
+
+    if (freq == 0U) {
+        logInfo("Received request to reset ping slot frequency to default");
+        freq = US915_BEACON_FREQ_BASE;
+        freqHop = true;
+    } else if (!CheckRfFrequency(freq)) {
+        logInfo("Freq KO");
+        status &= 0xFE; // Channel frequency KO
     }
 
-    status = 0x03;
+    if (datarate < _minRx2Datarate || datarate > _maxRx2Datarate) {
+        logInfo("DR KO");
+        status &= 0xFD; // Datarate KO
+    }
+
+    if ((status & 0x03) == 0x03) {
+        logInfo("PingSlotChannelReq accepted DR: %d Freq: %d", datarate, freq);
+        GetSettings()->Session.PingSlotFrequency = freq;
+        GetSettings()->Session.PingSlotDatarateIndex = datarate;
+        _pingFreqHop = freqHop;
+    } else {
+        logInfo("PingSlotChannelReq rejected DR: %d Freq: %d", datarate, freq);
+    }
+
     return LORA_OK;
 }
 
 uint8_t ChannelPlan_US915::HandleBeaconFrequencyReq(const uint8_t* payload, uint8_t index, uint8_t size, uint8_t& status) {
+    uint32_t freq = 0;
+    bool freqHop = false;
 
-    status = 0x03;
-    Channel chParam;
+    status = 0x01;
 
-    // Skip channel index
-    index++;
+    freq = payload[index++];
+    freq |= payload[index++] << 8;
+    freq |= payload[index] << 16;
+    freq *= 100;
 
-    lora::CopyFreqtoInt(payload + index, chParam.Frequency);
-    index += 3;
-    chParam.DrRange.Value = payload[index++];
-
-    if (!GetRadio()->CheckRfFrequency(chParam.Frequency)) {
+    if (freq == 0U) {
+        logInfo("Received request to reset beacon frequency to default");
+        freq = US915_BEACON_FREQ_BASE;
+        freqHop = true;
+    } else if (!CheckRfFrequency(freq)) {
+        logInfo("Freq KO");
         status &= 0xFE; // Channel frequency KO
     }
 
-    if (chParam.DrRange.Fields.Min < chParam.DrRange.Fields.Max) {
-        status &= 0xFD; // Datarate range KO
-    } else if (chParam.DrRange.Fields.Min < _minDatarate || chParam.DrRange.Fields.Min > _maxDatarate) {
-        status &= 0xFD; // Datarate range KO
-    } else if (chParam.DrRange.Fields.Max < _minDatarate || chParam.DrRange.Fields.Max > _maxDatarate) {
-        status &= 0xFD; // Datarate range KO
+    if (status & 0x01) {
+        logInfo("BeaconFrequencyReq accepted Freq: %d", freq);
+        GetSettings()->Session.BeaconFrequency = freq;
+        _bcnFreqHop = freqHop;
+    } else {
+        logInfo("BeaconFrequencyReq rejected Freq: %d", freq);
     }
 
-    if ((status & 0x03) == 0x03) {
-        _beaconChannel = chParam;
-    }
-
-    if (_beaconChannel.Frequency == 0) {
-        // TODO: Set to default
-    }
-
-    status = 0x01;
-
     return LORA_OK;
 }
 
@@ -991,3 +1048,57 @@
 
     return LORA_OK;
 }
+
+bool ChannelPlan_US915::DecodeBeacon(const uint8_t* payload, size_t size, BeaconData_t& data) {
+    uint16_t crc1, crc1_rx, crc2, crc2_rx;
+    const BCNPayload* beacon = (const BCNPayload*)payload;
+
+    // First check the size of the packet
+    if (size != sizeof(BCNPayload))
+        return false;
+
+    // Next we verify the CRCs are correct
+    crc1 = CRC16(beacon->RFU1, sizeof(beacon->RFU1) + sizeof(beacon->Time));
+    memcpy((uint8_t*)&crc1_rx, beacon->CRC1, sizeof(uint16_t));
+
+    if (crc1 != crc1_rx)
+        return false;
+
+    crc2 = CRC16(beacon->GwSpecific, sizeof(beacon->GwSpecific) + sizeof(beacon->RFU2));
+    memcpy((uint8_t*)&crc2_rx, beacon->CRC2, sizeof(uint16_t));
+
+    if (crc2 != crc2_rx)
+        return false;
+
+    // Now that we have confirmed this packet is a beacon, parse and complete the output struct
+    memcpy(&data.Time, beacon->Time, sizeof(beacon->Time));
+    data.InfoDesc = beacon->GwSpecific[0];
+
+    // Update the GPS fields if we have a gps info descriptor
+    if (data.InfoDesc == GPS_FIRST_ANTENNA ||
+        data.InfoDesc == GPS_SECOND_ANTENNA ||
+        data.InfoDesc == GPS_THIRD_ANTENNA) {
+        // Latitude and Longitude 3 bytes in length
+        memcpy(&data.Latitude, &beacon->GwSpecific[1], 3);
+        memcpy(&data.Longitude, &beacon->GwSpecific[4], 3);
+    }
+
+    return true;
+}
+
+void ChannelPlan_US915::FrequencyHop(uint32_t time, uint32_t period, uint32_t devAddr) {
+    uint32_t channel;
+    uint32_t freq;
+
+    if (_bcnFreqHop) {
+        channel = (time / period) % US915_BEACON_CHANNELS;
+        freq = US915_BEACON_FREQ_BASE + (channel * US915_BEACON_FREQ_STEP);
+        GetSettings()->Session.BeaconFrequency = freq;
+    }
+
+    if (_pingFreqHop) {
+        channel = (time / period + devAddr) % US915_BEACON_CHANNELS;
+        freq = US915_BEACON_FREQ_BASE + (channel * US915_BEACON_FREQ_STEP);
+        GetSettings()->Session.PingSlotFrequency = freq;
+    }
+}