]> git.tnoah.ca Git - lora-radio.git/commitdiff
Added channel utilisation and airtime accounting
authorMark Qvist <mark@unsigned.io>
Tue, 12 Sep 2023 12:48:47 +0000 (14:48 +0200)
committerMark Qvist <mark@unsigned.io>
Tue, 12 Sep 2023 12:48:47 +0000 (14:48 +0200)
Config.h
Display.h
RNode_Firmware.ino
Utilities.h

index 4c95b864c65271cb30a41c74beaf7cda182e8390..3f3b8ba7f2168216b4a585d69d25fc367939f95e 100644 (file)
--- a/Config.h
+++ b/Config.h
@@ -22,7 +22,7 @@
        #define MIN_VERS  0x3F
 
        #define PLATFORM_AVR   0x90
-    #define PLATFORM_ESP32 0x80
+  #define PLATFORM_ESP32 0x80
 
        #define MCU_1284P 0x91
        #define MCU_2560  0x92
        int  lora_txp      = 0xFF;
        uint32_t lora_bw   = 0;
        uint32_t lora_freq = 0;
+       uint32_t lora_bitrate = 0;
 
        // Operational variables
        bool radio_locked  = true;
        uint32_t stat_rx                = 0;
        uint32_t stat_tx                = 0;
 
+       #define STATUS_INTERVAL_MS 3
+       #if MCU_VARIANT == MCU_ESP32
+         #define DCD_SAMPLES 2500
+               #define UTIL_UPDATE_INTERVAL_MS 1000
+               #define UTIL_UPDATE_INTERVAL (UTIL_UPDATE_INTERVAL_MS/STATUS_INTERVAL_MS)
+               #define AIRTIME_LONGTERM 3600
+               #define AIRTIME_LONGTERM_MS (AIRTIME_LONGTERM*1000)
+               #define AIRTIME_BINLEN_MS (STATUS_INTERVAL_MS*DCD_SAMPLES)
+               #define AIRTIME_BINS ((AIRTIME_LONGTERM*1000)/AIRTIME_BINLEN_MS)
+               bool util_samples[DCD_SAMPLES];
+               uint16_t airtime_bins[AIRTIME_BINS];
+               int dcd_sample = 0;
+               float local_channel_util = 0.0;
+               float total_channel_util = 0.0;
+               float airtime = 0.0;
+               float longterm_airtime = 0.0;
+               float us_per_byte = 0.0;
+               #define current_airtime_bin(void) (millis()%AIRTIME_LONGTERM_MS)/AIRTIME_BINLEN_MS
+       #endif
+
        bool stat_signal_detected = false;
        bool stat_signal_synced   = false;
        bool stat_rx_ongoing      = false;
        uint16_t dcd_count        = 0;
        uint16_t dcd_threshold    = 15;
 
-       uint32_t status_interval_ms = 3;
+       uint32_t status_interval_ms = STATUS_INTERVAL_MS;
        uint32_t last_status_update = 0;
 
        // Status flags
     float battery_percent = 0.0;
     uint8_t battery_state = 0x00;
     uint8_t display_intensity = 0xFF;
+    bool display_diagnostics = true;
     bool device_init_done = false;
     bool eeprom_ok = false;
     bool firmware_update_mode = false;
index 5ee487944a6c0ea41e8d2b485db57ad5144520f5..767367503e50a4032875776f9d5ae7f561f5112b 100644 (file)
--- a/Display.h
+++ b/Display.h
@@ -436,6 +436,17 @@ void draw_disp_area() {
     } else {
       disp_area.drawBitmap(0, 0, fb, disp_area.width(), disp_area.height(), SSD1306_WHITE, SSD1306_BLACK);
     }
+    if (display_diagnostics) {
+      disp_area.setCursor(0, 0);
+      disp_area.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
+      disp_area.setTextSize(1);
+      disp_area.printf("B:%.1fK\r\n", (float)lora_bitrate/1000.0);
+      disp_area.printf("U:%.1f%%\r\n", total_channel_util*100.0);
+      disp_area.printf("L:%.1f%%\r\n", local_channel_util*100.0);
+      disp_area.printf("A:%.2f%%\r\n", airtime*100.0);
+      disp_area.printf("a:%.2f%%\r\n", longterm_airtime*100.0);
+      disp_area.printf("C:%d\r\n", current_airtime_bin());
+    }
   }
 }
 
index e12121ee222723aa181acbf49d7e78322ef77444..9788b9a7a0bc99d2cd01dbdf7c1ab567ad7b1d29 100644 (file)
@@ -89,6 +89,9 @@ void setup() {
   LoRa.setPins(pin_cs, pin_reset, pin_dio);
   
   #if MCU_VARIANT == MCU_ESP32
+    for (uint16_t ai = 0; ai < DCD_SAMPLES; ai++) { util_samples[ai] = false; }
+    for (uint16_t ai = 0; ai < AIRTIME_BINS; ai++) { airtime_bins[ai] = 0; }
+
     // Check installed transceiver chip and
     // probe boot parameters.
     if (LoRa.preInit()) {
@@ -396,6 +399,27 @@ void flushQueue(void) {
   queue_flushing = false;
 }
 
+void add_airtime(uint16_t written) {
+  #if MCU_VARIANT == MCU_ESP32
+    float ms_cost = ((float)written * us_per_byte)/1000.0;
+    airtime_bins[current_airtime_bin()] += ms_cost;
+  #endif
+}
+
+void update_airtime() {
+  #if MCU_VARIANT == MCU_ESP32
+    uint16_t cb = current_airtime_bin();
+    uint16_t pb = cb-1; if (cb < 0) { cb = AIRTIME_BINS-1; }
+    airtime = (float)(airtime_bins[cb]+airtime_bins[pb])/(2.0*AIRTIME_BINLEN_MS);
+
+    uint32_t longterm_airtime_sum = 0;
+    for (uint16_t bin = 0; bin < AIRTIME_BINS; bin++) {
+      longterm_airtime_sum += airtime_bins[bin];
+    }
+    longterm_airtime = (float)longterm_airtime_sum/(float)AIRTIME_LONGTERM_MS;
+  #endif
+}
+
 void transmit(uint16_t size) {
   if (radio_online) {
     if (!promisc) {
@@ -411,19 +435,19 @@ void transmit(uint16_t size) {
       LoRa.write(header); written++;
 
       for (uint16_t i=0; i < size; i++) {
-        LoRa.write(tbuf[i]);  
+        LoRa.write(tbuf[i]);
 
         written++;
 
         if (written == 255) {
-          LoRa.endPacket();
+          LoRa.endPacket(); add_airtime(written);
           LoRa.beginPacket();
           LoRa.write(header);
           written = 1;
         }
       }
 
-      LoRa.endPacket();
+      LoRa.endPacket(); add_airtime(written);
       led_tx_off();
 
       lora_receive();
@@ -452,7 +476,7 @@ void transmit(uint16_t size) {
 
         written++;
       }
-      LoRa.endPacket();
+      LoRa.endPacket(); add_airtime(written);
       led_tx_off();
 
       lora_receive();
@@ -858,6 +882,22 @@ void updateModemStatus() {
 void checkModemStatus() {
   if (millis()-last_status_update >= status_interval_ms) {
     updateModemStatus();
+
+    #if MCU_VARIANT == MCU_ESP32
+      util_samples[dcd_sample] = dcd;
+      dcd_sample = (dcd_sample+1)%DCD_SAMPLES;
+      if (dcd_sample % UTIL_UPDATE_INTERVAL == 0) {
+        int util_count = 0;
+        for (int ui = 0; ui < DCD_SAMPLES; ui++) {
+          if (util_samples[ui]) util_count++;
+        }
+        local_channel_util = (float)util_count / (float)DCD_SAMPLES;
+        total_channel_util = local_channel_util + airtime;
+        if (total_channel_util > 1.0) total_channel_util = 1.0;
+
+        update_airtime();
+      }
+    #endif
   }
 }
 
@@ -1007,10 +1047,9 @@ void loop() {
 
         if (!dcd) {
           dcd_waiting = false;
-
           flushQueue();
-          
         }
+
       } else {
         dcd_waiting = true;
       }
index a114e06269595fa0eb8621de5df34d340924ebd7..103738b45e5207331358fecbb1b7dca30bc4686d 100644 (file)
@@ -860,12 +860,28 @@ inline uint8_t packetSequence(uint8_t header) {
        return header >> 4;
 }
 
+void updateBitrate() {
+       #if MCU_VARIANT == MCU_ESP32
+               if (radio_online) {
+                       //             self.bitrate = self.r_sf * ( (4.0/self.r_cr) / (math.pow(2,self.r_sf)/(self.r_bandwidth/1000)) ) * 1000
+                       //             self.bitrate_kbps = round(self.bitrate/1000.0, 2)
+                       lora_bitrate = (uint32_t)(lora_sf * ( (4.0/(float)lora_cr) / ((float)(pow(2, lora_sf))/((float)lora_bw/1000.0)) ) * 1000.0);
+                       us_per_byte = 1000000.0/((float)lora_bitrate/8.0);
+
+               } else {
+                       lora_bitrate = 0;
+               }
+       #endif
+}
+
 void setSpreadingFactor() {
        if (radio_online) LoRa.setSpreadingFactor(lora_sf);
+       updateBitrate();
 }
 
 void setCodingRate() {
        if (radio_online) LoRa.setCodingRate4(lora_cr);
+       updateBitrate();
 }
 
 void set_implicit_length(uint8_t len) {
@@ -912,6 +928,7 @@ void getBandwidth() {
        if (radio_online) {
                        lora_bw = LoRa.getSignalBandwidth();
        }
+       updateBitrate();
 }
 
 void setBandwidth() {