#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;
} 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());
+ }
}
}
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()) {
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) {
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();
written++;
}
- LoRa.endPacket();
+ LoRa.endPacket(); add_airtime(written);
led_tx_off();
lora_receive();
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
}
}
if (!dcd) {
dcd_waiting = false;
-
flushQueue();
-
}
+
} else {
dcd_waiting = true;
}
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) {
if (radio_online) {
lora_bw = LoRa.getSignalBandwidth();
}
+ updateBitrate();
}
void setBandwidth() {