]> git.tnoah.ca Git - lora-radio.git/commitdiff
Reworked CSMA algorithm
authorMark Qvist <mark@unsigned.io>
Tue, 7 Jan 2025 19:15:26 +0000 (20:15 +0100)
committerMark Qvist <mark@unsigned.io>
Tue, 7 Jan 2025 19:15:26 +0000 (20:15 +0100)
Boards.h
Config.h
RNode_Firmware.ino

index aa1a4f110b8afc055f74d44bfd39d2b2d323e5a5..6fb846d134bd21e3c35299e4108eb3a440685a1b 100644 (file)
--- a/Boards.h
+++ b/Boards.h
 #define PIN_DCD      5
 #define PIN_TXSIG    4
 
+// #define PIN_DIFS  7
+// #define PIN_CW    6
+// #define PIN_FLUSH 5
+
+#define PIN_DIFS  3
+#define PIN_CW    3
+#define PIN_FLUSH 3
+///////////////////////////
+
 #include "Modem.h"
 
 #ifndef BOARDS_H
index f6569b49a72a4d00e053775966baa350f75e195e..4993ccff0e6c2bd591e5885640f616a0d5bcd6a6 100644 (file)
--- a/Config.h
+++ b/Config.h
        const int  rssi_offset = 157;
 
        // Default LoRa settings
-       const int lora_rx_turnaround_ms = 66;
-       const int lora_post_tx_yield_slots = 6;
-       uint32_t post_tx_yield_timeout = 0;
        #define PHY_HEADER_LORA_SYMBOLS   20
        #define PHY_CRC_LORA_BITS         16
        #define LORA_PREAMBLE_SYMBOLS_MIN 18
        #define LORA_PREAMBLE_TARGET_MS   15
        #define LORA_CAD_SYMBOLS          3
-       #define CSMA_SLOT_SYMBOLS         12
+       long lora_preamble_symbols      = 12;
+       long lora_preamble_time_ms      = 0;
+       long lora_header_time_ms        = 0;
+       float lora_symbol_time_ms       = 0.0;
+       float lora_symbol_rate          = 0.0;
+       float lora_us_per_byte          = 0.0;
+       bool lora_low_datarate          = false;
+
+       // CSMA Parameters
+       #define CSMA_POST_TX_YIELD_SLOTS  3
        #define CSMA_SLOT_MAX_MS          100
        #define CSMA_SLOT_MIN_MS          24
-       
-       long lora_preamble_symbols = 12;
-       long lora_preamble_time_ms = 0;
-       long lora_header_time_ms   = 0;
-       float lora_symbol_time_ms  = 0.0;
-       float lora_symbol_rate     = 0.0;
-       float lora_us_per_byte     = 0.0;
-       bool lora_low_datarate     = false;
-
-       int csma_slot_ms           = 50;
+       #define CSMA_SLOT_SYMBOLS         12
+       #define CSMA_CW_MIN               0
+       #define CSMA_CW_MAX               15
+       #define CSMA_SIFS_MS              0
+       int csma_slot_ms                = CSMA_SLOT_MIN_MS;
+       long difs_ms                    = CSMA_SIFS_MS + 2*csma_slot_ms; // Distributed interframe space
+       long difs_wait_start            = -1;
+       long cw_wait_start              = -1;
+       long cw_wait_target             = -1;
+       long cw_wait_passed             = 0;
+       int csma_cw                     = -1;
+
+       ////////////////////////////////////////
        float csma_p_min           = 0.15;
        float csma_p_max           = 0.333;
        float csma_b_speed         = 0.15;
        uint8_t csma_p             = 85;
+       ////////////////////////////////////////
 
        int  lora_sf               = 0;
        int  lora_cr               = 5;
index f38162b05276c905efd2c49c60f6e32c25c72add..e6a85e8eee261a464af6682ee828b6318552c93b 100644 (file)
@@ -64,6 +64,9 @@ void setup() {
   pinMode(PIN_HEADER, OUTPUT);
   pinMode(PIN_DCD, OUTPUT);
   pinMode(PIN_TXSIG, OUTPUT);
+  pinMode(PIN_DIFS, OUTPUT);
+  pinMode(PIN_CW, OUTPUT);
+  pinMode(PIN_FLUSH, OUTPUT);
   ///////////////////////////
 
   #if MCU_VARIANT == MCU_ESP32
@@ -521,7 +524,7 @@ bool queueFull() {
 }
 
 volatile bool queue_flushing = false;
-void flushQueue(void) {
+void flush_queue(void) {
   if (!queue_flushing) {
 
     // TODO: Remove debug
@@ -554,7 +557,6 @@ void flushQueue(void) {
 
     lora_receive();
     led_tx_off();
-    post_tx_yield_timeout = millis()+(lora_post_tx_yield_slots*csma_slot_ms);
   }
 
   queue_height = 0;
@@ -628,7 +630,7 @@ void update_airtime() {
     longterm_channel_util = (float)longterm_channel_util_sum/(float)AIRTIME_BINS;
 
     #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
-      update_csma_p();
+      update_csma_parameters();
     #endif
     kiss_indicate_channel_stats();
   #endif
@@ -1199,7 +1201,9 @@ void serialCallback(uint8_t sbyte) {
   portMUX_TYPE update_lock = portMUX_INITIALIZER_UNLOCKED;
 #endif
 
-void updateModemStatus() {
+bool medium_free() { update_modem_status(); return !dcd; }
+
+void update_modem_status() {
   #if MCU_VARIANT == MCU_ESP32
     portENTER_CRITICAL(&update_lock);
   #elif MCU_VARIANT == MCU_NRF52
@@ -1225,9 +1229,9 @@ void updateModemStatus() {
                  else              { led_rx_off(); } }
 }
 
-void checkModemStatus() {
+void check_modem_status() {
   if (millis()-last_status_update >= status_interval_ms) {
-    updateModemStatus();
+    update_modem_status();
 
     #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
       util_samples[dcd_sample] = dcd;
@@ -1385,13 +1389,56 @@ void validate_status() {
   #define _e 2.71828183
   #define _S 12.5
   float csma_slope(float u) { return (pow(_e,_S*u-_S/2.0))/(pow(_e,_S*u-_S/2.0)+1.0); }
-  void update_csma_p() {
+  void update_csma_parameters() {
     csma_p = (uint8_t)((1.0-(csma_p_min+(csma_p_max-csma_p_min)*csma_slope(airtime+csma_b_speed)))*255.0);
   }
 #endif
 
+void tx_queue_handler() {
+  if (!airtime_lock && queue_height > 0) {
+    if (csma_cw == -1) {
+      csma_cw = random(CSMA_CW_MIN, CSMA_CW_MAX);
+      cw_wait_target = csma_cw * csma_slot_ms;
+    }
+
+    // TODO: Remove metering signallers
+    if (difs_wait_start == -1) { digitalWrite(PIN_DIFS, LOW); }
+    if (cw_wait_start == -1) { digitalWrite(PIN_CW, LOW); } else { digitalWrite(PIN_CW, HIGH); }
+    ////////////////////////////////
+
+    if (difs_wait_start == -1) {                                                  // DIFS wait not yet started
+      if (medium_free()) { difs_wait_start = millis(); digitalWrite(PIN_DIFS, HIGH); return; }            // Set DIFS wait start time
+      else               { return; } }                                            // Medium not yet free, continue waiting
+    
+    else {                                                                        // We are waiting for DIFS or CW to pass
+      if (!medium_free()) { difs_wait_start = -1; cw_wait_start = -1; return; }   // Medium became occupied while in DIFS wait, restart waiting when free again
+      else {                                                                      // Medium is free, so continue waiting
+        if (millis() < difs_wait_start+difs_ms) { return; }                       // DIFS has not yet passed, continue waiting
+        else {                                                                    // DIFS has passed, and we are now in CW wait
+          digitalWrite(PIN_DIFS, LOW);
+          if (cw_wait_start == -1) { cw_wait_start = millis(); digitalWrite(PIN_CW, HIGH); return; }    // If we haven't started counting CW wait time, do it from now
+          else {                                                                  // If we are already counting CW wait time, add it to the counter
+            cw_wait_passed += millis()-cw_wait_start; cw_wait_start   = millis();
+            if (cw_wait_passed < cw_wait_target) { return; }                      // Contention window wait time has not yet passed, continue waiting
+            else {                                                                // Wait time has passed, flush the queue
+              digitalWrite(PIN_FLUSH, HIGH);
+              digitalWrite(PIN_CW, LOW);
+              flush_queue();
+              digitalWrite(PIN_FLUSH, LOW);
+              digitalWrite(PIN_DIFS, LOW);
+              cw_wait_passed = 0; csma_cw = -1; difs_wait_start = -1; }
+
+          }
+        }
+      }
+    }
+  }
+}
+
 void loop() {
   if (radio_online) {
+    update_modem_status(); // TODO: Remove debug
+
     #if MCU_VARIANT == MCU_ESP32
       modem_packet_t *modem_packet = NULL;
       if(modem_packet_queue && xQueueReceive(modem_packet_queue, &modem_packet, 0) == pdTRUE && modem_packet) {
@@ -1434,50 +1481,57 @@ void loop() {
 
     #endif
 
-    checkModemStatus();
-    if (!airtime_lock) {
-      if (queue_height > 0) {
-        #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
-
-          long check_time = millis();
-          if (check_time > post_tx_yield_timeout) {
-            if (dcd_waiting && (check_time >= dcd_wait_until)) { dcd_waiting = false; }
-            if (!dcd_waiting) {
-              for (uint8_t dcd_i = 0; dcd_i < dcd_threshold*2; dcd_i++) {
-                delay(STATUS_INTERVAL_MS); updateModemStatus();
-              }
+    update_modem_status(); // TODO: Remove debug
 
-              if (!dcd) {
-                uint8_t csma_r = (uint8_t)random(256);
-                if (csma_p >= csma_r) {
-                  flushQueue();
-                } else {
-                  dcd_waiting = true;
-                  dcd_wait_until = millis()+csma_slot_ms;
-                }
-              }
-            }
-          }
+    tx_queue_handler();
+
+    update_modem_status(); // TODO: Remove debug
+
+    check_modem_status();
+
+    update_modem_status(); // TODO: Remove debug
+
+      // if (queue_height > 0) {
+      //   #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
+
+      //     long check_time = millis();
+      //     if (check_time > post_tx_yield_timeout) {
+      //       if (dcd_waiting && (check_time >= dcd_wait_until)) { dcd_waiting = false; }
+      //       if (!dcd_waiting) {
+      //         for (uint8_t dcd_i = 0; dcd_i < dcd_threshold*2; dcd_i++) {
+      //           delay(STATUS_INTERVAL_MS); updateModemStatus();
+      //         }
+
+      //         if (!dcd) {
+      //           uint8_t csma_r = (uint8_t)random(256);
+      //           if (csma_p >= csma_r) {
+      //             flushQueue();
+      //           } else {
+      //             dcd_waiting = true;
+      //             dcd_wait_until = millis()+csma_slot_ms;
+      //           }
+      //         }
+      //       }
+      //     }
           
-        #else
-          if (!dcd_waiting) updateModemStatus();
+      //   #else
+      //     if (!dcd_waiting) updateModemStatus();
 
-          if (!dcd) {
-            if (dcd_waiting) delay(lora_rx_turnaround_ms);
+      //     if (!dcd) {
+      //       if (dcd_waiting) delay(lora_rx_turnaround_ms);
 
-            updateModemStatus();
+      //       updateModemStatus();
 
-            if (!dcd) {
-              dcd_waiting = false;
-              flushQueue();
-            }
+      //       if (!dcd) {
+      //         dcd_waiting = false;
+      //         flushQueue();
+      //       }
 
-          } else {
-            dcd_waiting = true;
-          }
-        #endif
-      }
-    }
+      //     } else {
+      //       dcd_waiting = true;
+      //     }
+      //   #endif
+      // }
   
   } else {
     if (hw_ready) {
@@ -1497,27 +1551,41 @@ void loop() {
 
   #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
       buffer_serial();
+      update_modem_status(); // TODO: Remove debug
+      
       if (!fifo_isempty(&serialFIFO)) serial_poll();
+      
+      update_modem_status(); // TODO: Remove debug
   #else
     if (!fifo_isempty_locked(&serialFIFO)) serial_poll();
   #endif
 
+  update_modem_status(); // TODO: Remove debug
+
   #if HAS_DISPLAY
     if (disp_ready) update_display();
   #endif
 
+  update_modem_status(); // TODO: Remove debug
+
   #if HAS_PMU
     if (pmu_ready) update_pmu();
   #endif
 
+  update_modem_status(); // TODO: Remove debug
+
   #if HAS_BLUETOOTH || HAS_BLE == true
     if (!console_active && bt_ready) update_bt();
   #endif
 
+  update_modem_status(); // TODO: Remove debug
+
   #if HAS_INPUT
     input_read();
   #endif
 
+  update_modem_status(); // TODO: Remove debug
+
   if (memory_low) {
     #if PLATFORM == PLATFORM_ESP32
       if (esp_get_free_heap_size() < 8192) {