]> git.tnoah.ca Git - lora-radio.git/commitdiff
Accurate preamble and airtime calculations on SX1280. Fix airtime calculation on...
authorMark Qvist <mark@unsigned.io>
Sun, 5 Jan 2025 21:55:32 +0000 (22:55 +0100)
committerMark Qvist <mark@unsigned.io>
Sun, 5 Jan 2025 21:55:32 +0000 (22:55 +0100)
RNode_Firmware.ino
Utilities.h
sx126x.cpp
sx126x.h
sx127x.cpp
sx127x.h
sx128x.cpp
sx128x.h

index e476392c344baf334c22af7d271797eb7e829965..f8d5b3570af36b8fa57c9154b47e88e56b5cdede 100644 (file)
@@ -557,18 +557,44 @@ void flushQueue(void) {
   #endif
 }
 
-#define PHY_HEADER_LORA_SYMBOLS 8
+#define PHY_HEADER_LORA_SYMBOLS 20
+#define PHY_CRC_LORA_BITS       16
 void add_airtime(uint16_t written) {
   #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
+    float lora_symbols = 0;
     float packet_cost_ms = 0.0;
-    float payload_cost_ms = ((float)written * lora_us_per_byte)/1000.0;
-    packet_cost_ms += payload_cost_ms;
-    packet_cost_ms += (lora_preamble_symbols+4.25)*lora_symbol_time_ms;
-    packet_cost_ms += PHY_HEADER_LORA_SYMBOLS * lora_symbol_time_ms;
+    int ldr_opt = 0; if (lora_low_datarate) ldr_opt = 1;
+
+    #if MODEM == SX1276 || MODEM == SX1278
+      lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*lora_sf + 8 + PHY_HEADER_LORA_SYMBOLS);
+      lora_symbols /=                          4*(lora_sf-2*ldr_opt);
+      lora_symbols *= lora_cr;
+      lora_symbols += lora_preamble_symbols + 0.25 + 8;
+      packet_cost_ms += lora_symbols * lora_symbol_time_ms;
+      
+    #elif MODEM == SX1262 || MODEM == SX1280
+      if (lora_sf < 7) {
+        lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*lora_sf + PHY_HEADER_LORA_SYMBOLS);
+        lora_symbols /=                              4*lora_sf;
+        lora_symbols *= lora_cr;
+        lora_symbols += lora_preamble_symbols + 2.25 + 8;
+        packet_cost_ms += lora_symbols * lora_symbol_time_ms;
+
+      } else {
+        lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*lora_sf + 8 + PHY_HEADER_LORA_SYMBOLS);
+        lora_symbols /=                         4*(lora_sf-2*ldr_opt);
+        lora_symbols *= lora_cr;
+        lora_symbols += lora_preamble_symbols + 0.25 + 8;
+        packet_cost_ms += lora_symbols * lora_symbol_time_ms;
+      }
+    
+    #endif
+
     uint16_t cb = current_airtime_bin();
     uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
     airtime_bins[cb] += packet_cost_ms;
     airtime_bins[nb] = 0;
+
   #endif
 }
 
index aae8738236020a2d82faabcd035c23c4a34a70f6..5a981bd2a8c2d1e672c5e9054666a12df76aa3fd 100644 (file)
@@ -863,8 +863,8 @@ void kiss_indicate_phy_stats() {
        #if MCU_VARIANT == MCU_ESP32
                uint16_t lst = (uint16_t)(lora_symbol_time_ms*1000);
                uint16_t lsr = (uint16_t)(lora_symbol_rate);
-               uint16_t prs = (uint16_t)(lora_preamble_symbols+4);
-               uint16_t prt = (uint16_t)((lora_preamble_symbols+4)*lora_symbol_time_ms);
+               uint16_t prs = (uint16_t)(lora_preamble_symbols);
+               uint16_t prt = (uint16_t)((lora_preamble_symbols)*lora_symbol_time_ms);
                uint16_t cst = (uint16_t)(csma_slot_ms);
                serial_write(FEND);
                serial_write(CMD_STAT_PHYPRM);
@@ -1091,20 +1091,14 @@ void updateBitrate() {
                        lora_symbol_time_ms = (1.0/lora_symbol_rate)*1000.0;
                        lora_bitrate = (uint32_t)(lora_sf * ( (4.0/(float)lora_cr) / ((float)(pow(2, lora_sf))/((float)lora_bw/1000.0)) ) * 1000.0);
                        lora_us_per_byte = 1000000.0/((float)lora_bitrate/8.0);
-                       csma_slot_ms = lora_symbol_time_ms*12;
+                       
+                       csma_slot_ms = lora_symbol_time_ms*CSMA_SLOT_SYMBOLS;
                        if (csma_slot_ms > CSMA_SLOT_MAX_MS) { csma_slot_ms = CSMA_SLOT_MAX_MS; }
                        if (csma_slot_ms < CSMA_SLOT_MIN_MS) { csma_slot_ms = CSMA_SLOT_MIN_MS; }
-                       float target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW;
                        
-                       #if MODEM == SX1280
-                               target_preamble_symbols = 12;
-                       #else
-                               if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) {
-                                       target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN;
-                               } else {
-                                       target_preamble_symbols = ceil(target_preamble_symbols);
-                               }
-                       #endif
+                       float target_preamble_symbols = LORA_PREAMBLE_TARGET_MS/lora_symbol_time_ms;
+                       if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) { target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN; }
+                       else { target_preamble_symbols = (ceil)(target_preamble_symbols); }
                        
                        lora_preamble_symbols = (long)target_preamble_symbols;
                        setPreamble();
index cd74343c9d32606a233b4f9f0f3829d7bdc1d6db..697d97db4ef1f9910bdb5f2f4b324daf09263435 100644 (file)
@@ -252,14 +252,14 @@ void sx126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro) {
   executeOpcode(OP_MODULATION_PARAMS_6X, buf, 8);
 }
 
-void sx126x::setPacketParams(long preamble, uint8_t headermode, uint8_t length, uint8_t crc) {
+void sx126x::setPacketParams(long preamble_symbols, uint8_t headermode, uint8_t payload_length, uint8_t crc) {
   // Because there is no access to these registers on the sx1262, we have
   // to set all these parameters at once or not at all.
   uint8_t buf[9];
-  buf[0] = uint8_t((preamble & 0xFF00) >> 8);
-  buf[1] = uint8_t((preamble & 0x00FF));
+  buf[0] = uint8_t((preamble_symbols & 0xFF00) >> 8);
+  buf[1] = uint8_t((preamble_symbols & 0x00FF));
   buf[2] = headermode;
-  buf[3] = length;
+  buf[3] = payload_length;
   buf[4] = crc;
   buf[5] = 0x00; // standard IQ setting (no inversion)
   buf[6] = 0x00; // unused params
@@ -642,12 +642,14 @@ long sx126x::getSignalBandwidth() {
   return 0;
 }
 
-void sx126x::handleLowDataRate(){
-  if ( long( (1<<_sf) / (getSignalBandwidth()/1000)) > 16) { _ldro = 0x01; }
-  else { _ldro = 0x00; }
+extern bool lora_low_datarate;
+void sx126x::handleLowDataRate() {
+  if ( long( (1<<_sf) / (getSignalBandwidth()/1000)) > 16)
+         { _ldro = 0x01; lora_low_datarate = true;  }
+    else { _ldro = 0x00; lora_low_datarate = false; }
 }
 
-// TODO: check if there's anything the sx1262 can do here
+// TODO: Check if there's anything the sx1262 can do here
 void sx126x::optimizeModemSensitivity(){ }
 
 void sx126x::setSignalBandwidth(long sbw) {
@@ -675,9 +677,9 @@ void sx126x::setCodingRate4(int denominator) {
   setModulationParams(_sf, _bw, cr, _ldro);
 }
 
-void sx126x::setPreambleLength(long length) {
-  _preambleLength = length;
-  setPacketParams(length, _implicitHeaderMode, _payloadLength, _crcMode);
+void sx126x::setPreambleLength(long preamble_symbols) {
+  _preambleLength = preamble_symbols;
+  setPacketParams(preamble_symbols, _implicitHeaderMode, _payloadLength, _crcMode);
 }
 
 void sx126x::setSyncWord(uint16_t sw) {
index bec13f8355f41a69677cc291596cd03c6b2523af..1edf75089ad1346337fb971b4b0c15b348fa54f5 100644 (file)
--- a/sx126x.h
+++ b/sx126x.h
@@ -66,7 +66,7 @@ public:
   long getSignalBandwidth();
   void setSignalBandwidth(long sbw);
   void setCodingRate4(int denominator);
-  void setPreambleLength(long length);
+  void setPreambleLength(long preamble_symbols);
   void setSyncWord(uint16_t sw);
   uint8_t modemStatus();
   void enableCrc();
@@ -81,7 +81,7 @@ public:
   void executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size);
   void writeBuffer(const uint8_t* buffer, size_t size);
   void readBuffer(uint8_t* buffer, size_t size);
-  void setPacketParams(long preamble, uint8_t headermode, uint8_t length, uint8_t crc);
+  void setPacketParams(long preamble_symbols, uint8_t headermode, uint8_t payload_length, uint8_t crc);
 
   void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro);
 
index 2d562c2acafec940339fefba67f1ecdb8abaf691..8871593cbacd0350aa0220ae4dfa7e3142ca7d50 100644 (file)
@@ -440,19 +440,23 @@ void sx127x::setCodingRate4(int denominator) {
   writeRegister(REG_MODEM_CONFIG_1_7X, (readRegister(REG_MODEM_CONFIG_1_7X) & 0xf1) | (cr << 1));
 }
 
-void sx127x::setPreambleLength(long length) { 
+void sx127x::setPreambleLength(long preamble_symbols) {
+  long length = preamble_symbols - 4;
   writeRegister(REG_PREAMBLE_MSB_7X, (uint8_t)(length >> 8));
   writeRegister(REG_PREAMBLE_LSB_7X, (uint8_t)(length >> 0));
 }
 
+extern bool lora_low_datarate;
 void sx127x::handleLowDataRate() {
   int sf = (readRegister(REG_MODEM_CONFIG_2_7X) >> 4);
   if ( long( (1<<sf) / (getSignalBandwidth()/1000)) > 16) {
     // Set auto AGC and LowDataRateOptimize
     writeRegister(REG_MODEM_CONFIG_3_7X, (1<<3)|(1<<2));
+    lora_low_datarate = true;
   } else {
     // Only set auto AGC
     writeRegister(REG_MODEM_CONFIG_3_7X, (1<<2));
+    lora_low_datarate = false;
   }
 }
 
index 56ff8898758d685f1f1e8b2328c1af0287f37dc6..c87b636d210b4c0ad39d88b4749b2a88d97c3ceb 100644 (file)
--- a/sx127x.h
+++ b/sx127x.h
@@ -63,7 +63,7 @@ public:
   long getSignalBandwidth();
   void setSignalBandwidth(long sbw);
   void setCodingRate4(int denominator);
-  void setPreambleLength(long length);
+  void setPreambleLength(long preamble_symbols);
   void setSyncWord(uint8_t sw);
   uint8_t modemStatus();
   void enableCrc();
index ed7415e542f486934cd4b8f3426db7707420785c..9aa6d7ded1314fd512787c05cf5af1747255e84e 100644 (file)
@@ -269,32 +269,43 @@ void sx128x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr) {
   writeRegister(0x093C, 0x1);
 }
 
-void sx128x::setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t length, uint8_t crc) {
-  // Because there is no access to these registers on the sx1280, we have
-  // to set all these parameters at once or not at all.
-  uint8_t buf[7];
-  // calculate exponent and mantissa values for modem
-  uint8_t e = 1;
-  uint8_t m = 1;
-  uint32_t preamblelen;
-
-  while (e <= 15) {
+uint8_t preamble_e = 0;
+uint8_t preamble_m = 0;
+uint32_t last_me_result_target = 0;
+extern long lora_preamble_symbols;
+void sx128x::setPacketParams(uint32_t target_preamble_symbols, uint8_t headermode, uint8_t payload_length, uint8_t crc) {  
+  if (last_me_result_target != target_preamble_symbols) {
+    // Calculate exponent and mantissa values for modem
+    if (target_preamble_symbols >= 0xF000) target_preamble_symbols = 0xF000;
+    uint32_t calculated_preamble_symbols;
+    uint8_t e = 1;
+    uint8_t m = 1;
+    while (e <= 15) {
       while (m <= 15) {
-          preamblelen = m * (pow(2,e));
-          if (preamblelen >= preamble) break;
-          m++;
+        calculated_preamble_symbols = m * (pow(2,e));
+        if (calculated_preamble_symbols >= target_preamble_symbols-4) break;
+        m++;
       }
-      if (preamblelen >= preamble) break;
-      m = 0;
-      e++;
+
+      if (calculated_preamble_symbols >= target_preamble_symbols-4) break;
+      m = 1; e++;
+    }
+
+    last_me_result_target = target_preamble_symbols;
+    lora_preamble_symbols = calculated_preamble_symbols+4;
+    _preambleLength = lora_preamble_symbols;
+
+    preamble_e = e;
+    preamble_m = m;
   }
 
-  buf[0] = (e << 4) | m;
+  uint8_t buf[7];
+  buf[0] = (preamble_e << 4) | preamble_m;
   buf[1] = headermode;
-  buf[2] = length;
+  buf[2] = payload_length;
   buf[3] = crc;
-  buf[4] = 0x40; // standard IQ setting (no inversion)
-  buf[5] = 0x00; // unused params
+  buf[4] = 0x40; // Standard IQ setting (no inversion)
+  buf[5] = 0x00; // Unused params
   buf[6] = 0x00; 
 
   executeOpcode(OP_PACKET_PARAMS_8X, buf, 7);
@@ -847,10 +858,15 @@ void sx128x::setCodingRate4(int denominator) {
   setModulationParams(_sf, _bw, _cr);
 }
 
-void sx128x::handleLowDataRate() { } // TODO: Is this needed for SX1280?
+extern bool lora_low_datarate;
+void sx128x::handleLowDataRate() {
+  if (_sf > 10) { lora_low_datarate = true; }
+  else          { lora_low_datarate = false; }
+}
+
 void sx128x::optimizeModemSensitivity() { } // TODO: Check if there's anything the sx1280 can do here
 uint8_t sx128x::getCodingRate4() { return _cr + 4; }
-void sx128x::setPreambleLength(long length) { _preambleLength = length; setPacketParams(length, _implicitHeaderMode, _payloadLength, _crcMode); }
+void sx128x::setPreambleLength(long preamble_symbols) { setPacketParams(preamble_symbols, _implicitHeaderMode, _payloadLength, _crcMode); }
 void sx128x::setSyncWord(int sw) { } // TODO: Implement
 void sx128x::enableTCXO() { } // TODO: Need to check how to implement on sx1280
 void sx128x::disableTCXO() { } // TODO: Need to check how to implement on sx1280
index 8a3e7d1391ceb64aab69cf6edcd120b81c30cc6b..5977f7db3bc01916d3b2e2cb0014b3833eec3d35 100644 (file)
--- a/sx128x.h
+++ b/sx128x.h
@@ -67,7 +67,7 @@ public:
   void setSignalBandwidth(uint32_t sbw);
   void setCodingRate4(int denominator);
   uint8_t getCodingRate4();
-  void setPreambleLength(long length);
+  void setPreambleLength(long preamble_symbols);
   void setSyncWord(int sw);
   uint8_t modemStatus();
   void clearIRQStatus();
@@ -84,7 +84,7 @@ public:
   void executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size);
   void writeBuffer(const uint8_t* buffer, size_t size);
   void readBuffer(uint8_t* buffer, size_t size);
-  void setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t length, uint8_t crc);
+  void setPacketParams(uint32_t target_preamble_symbols, uint8_t headermode, uint8_t payload_length, uint8_t crc);
   void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr);
 
   void crc() { enableCrc(); }