diff --git a/Config.h b/Config.h index dc653c7..16b38fb 100644 --- a/Config.h +++ b/Config.h @@ -359,6 +359,9 @@ float us_per_byte = 0.0; #define current_airtime_bin(void) (millis()%AIRTIME_LONGTERM_MS)/AIRTIME_BINLEN_MS #endif + float st_airtime_limit = 0.0; + float lt_airtime_limit = 0.0; + bool airtime_lock = false; bool stat_signal_detected = false; bool stat_signal_synced = false; diff --git a/Framing.h b/Framing.h index 00732b4..79811b4 100644 --- a/Framing.h +++ b/Framing.h @@ -33,6 +33,8 @@ #define CMD_DETECT 0x08 #define CMD_IMPLICIT 0x09 #define CMD_LEAVE 0x0A + #define CMD_ST_ALOCK 0x0B + #define CMD_LT_ALOCK 0x0C #define CMD_PROMISC 0x0E #define CMD_READY 0x0F @@ -40,6 +42,7 @@ #define CMD_STAT_TX 0x22 #define CMD_STAT_RSSI 0x23 #define CMD_STAT_SNR 0x24 + #define CMD_STAT_CHTM 0x25 #define CMD_BLINK 0x30 #define CMD_RANDOM 0x40 diff --git a/RNode_Firmware.ino b/RNode_Firmware.ino index 39a27ae..4b316af 100644 --- a/RNode_Firmware.ino +++ b/RNode_Firmware.ino @@ -312,6 +312,8 @@ bool startRadio() { } else { radio_online = true; + init_channel_stats(); + setTXPower(); setBandwidth(); setSpreadingFactor(); @@ -395,6 +397,9 @@ void flushQueue(void) { queue_height = 0; queued_bytes = 0; + #if MCU_VARIANT == MCU_ESP32 + update_airtime(); + #endif queue_flushing = false; } @@ -427,6 +432,8 @@ void update_airtime() { longterm_channel_util_sum += longterm_bins[bin]; } longterm_channel_util = (float)longterm_channel_util_sum/(float)AIRTIME_BINS; + + kiss_indicate_channel_stats(); #endif } @@ -650,6 +657,52 @@ void serialCallback(uint8_t sbyte) { startRadio(); kiss_indicate_radiostate(); } + } else if (command == CMD_ST_ALOCK) { + if (sbyte == FESC) { + ESCAPE = true; + } else { + if (ESCAPE) { + if (sbyte == TFEND) sbyte = FEND; + if (sbyte == TFESC) sbyte = FESC; + ESCAPE = false; + } + if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte; + } + + if (frame_len == 2) { + uint16_t at = (uint16_t)cmdbuf[0] << 8 | (uint16_t)cmdbuf[1]; + + if (at == 0) { + st_airtime_limit = 0.0; + } else { + st_airtime_limit = (float)at/(100.0*100.0); + if (st_airtime_limit >= 1.0) { st_airtime_limit = 0.0; } + } + kiss_indicate_st_alock(); + } + } else if (command == CMD_LT_ALOCK) { + if (sbyte == FESC) { + ESCAPE = true; + } else { + if (ESCAPE) { + if (sbyte == TFEND) sbyte = FEND; + if (sbyte == TFESC) sbyte = FESC; + ESCAPE = false; + } + if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte; + } + + if (frame_len == 2) { + uint16_t at = (uint16_t)cmdbuf[0] << 8 | (uint16_t)cmdbuf[1]; + + if (at == 0) { + lt_airtime_limit = 0.0; + } else { + lt_airtime_limit = (float)at/(100.0*100.0); + if (lt_airtime_limit >= 1.0) { lt_airtime_limit = 0.0; } + } + kiss_indicate_lt_alock(); + } } else if (command == CMD_STAT_RX) { kiss_indicate_stat_rx(); } else if (command == CMD_STAT_TX) { @@ -885,7 +938,11 @@ void updateModemStatus() { if (dcd_led) { led_rx_on(); } else { - led_rx_off(); + if (airtime_lock) { + led_indicate_airtime_lock(); + } else { + led_rx_off(); + } } } @@ -905,7 +962,10 @@ void checkModemStatus() { total_channel_util = local_channel_util + airtime; if (total_channel_util > 1.0) total_channel_util = 1.0; - longterm_bins[current_airtime_bin()] = total_channel_util; + int16_t cb = current_airtime_bin(); + uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; } + if (total_channel_util > longterm_bins[cb]) longterm_bins[cb] = total_channel_util; + longterm_bins[nb] = 0.0; update_airtime(); } @@ -1047,23 +1107,29 @@ void loop() { kiss_indicate_stat_snr(); kiss_write_packet(); } + + airtime_lock = false; + if (st_airtime_limit != 0.0 && airtime >= st_airtime_limit) airtime_lock = true; + if (lt_airtime_limit != 0.0 && longterm_airtime >= lt_airtime_limit) airtime_lock = true; #endif - if (queue_height > 0) { - if (!dcd_waiting) updateModemStatus(); + if (!airtime_lock) { + if (queue_height > 0) { + if (!dcd_waiting) updateModemStatus(); - if (!dcd && !dcd_led) { - if (dcd_waiting) delay(lora_rx_turnaround_ms); + if (!dcd && !dcd_led) { + 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; } - - } else { - dcd_waiting = true; } } diff --git a/Release/console_image.bin b/Release/console_image.bin index fda0764..9321c0e 100644 Binary files a/Release/console_image.bin and b/Release/console_image.bin differ diff --git a/Utilities.h b/Utilities.h index 78afdd2..5c564bd 100644 --- a/Utilities.h +++ b/Utilities.h @@ -218,6 +218,13 @@ void led_indicate_error(int cycles) { #endif } +// LED Indication: Airtime Lock +void led_indicate_airtime_lock() { + #if HAS_NP == true + npset(32,0,2); + #endif +} + // LED Indication: Boot Error void led_indicate_boot_error() { #if HAS_NP == true @@ -687,6 +694,44 @@ void kiss_indicate_frequency() { serial_write(FEND); } +void kiss_indicate_st_alock() { + uint16_t at = (uint16_t)(st_airtime_limit*100*100); + serial_write(FEND); + serial_write(CMD_ST_ALOCK); + escaped_serial_write(at>>8); + escaped_serial_write(at); + serial_write(FEND); +} + +void kiss_indicate_lt_alock() { + uint16_t at = (uint16_t)(lt_airtime_limit*100*100); + serial_write(FEND); + serial_write(CMD_LT_ALOCK); + escaped_serial_write(at>>8); + escaped_serial_write(at); + serial_write(FEND); +} + +void kiss_indicate_channel_stats() { + #if MCU_VARIANT == MCU_ESP32 + uint16_t ats = (uint16_t)(airtime*100*100); + uint16_t atl = (uint16_t)(longterm_airtime*100*100); + uint16_t cls = (uint16_t)(total_channel_util*100*100); + uint16_t cll = (uint16_t)(longterm_channel_util*100*100); + serial_write(FEND); + serial_write(CMD_STAT_CHTM); + escaped_serial_write(ats>>8); + escaped_serial_write(ats); + escaped_serial_write(atl>>8); + escaped_serial_write(atl); + escaped_serial_write(cls>>8); + escaped_serial_write(cls); + escaped_serial_write(cll>>8); + escaped_serial_write(cll); + serial_write(FEND); + #endif +} + void kiss_indicate_btpin() { #if HAS_BLUETOOTH serial_write(FEND); @@ -1182,13 +1227,15 @@ void unlock_rom() { } void init_channel_stats() { - 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; } - for (uint16_t ai = 0; ai < AIRTIME_BINS; ai++) { longterm_bins[ai] = 0.0; } - local_channel_util = 0.0; - total_channel_util = 0.0; - airtime = 0.0; - longterm_airtime = 0.0; + #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; } + for (uint16_t ai = 0; ai < AIRTIME_BINS; ai++) { longterm_bins[ai] = 0.0; } + local_channel_util = 0.0; + total_channel_util = 0.0; + airtime = 0.0; + longterm_airtime = 0.0; + #endif } typedef struct FIFOBuffer