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;
#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
#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
} else {
radio_online = true;
+ init_channel_stats();
+
setTXPower();
setBandwidth();
setSpreadingFactor();
queue_height = 0;
queued_bytes = 0;
+ #if MCU_VARIANT == MCU_ESP32
+ update_airtime();
+ #endif
queue_flushing = false;
}
longterm_channel_util_sum += longterm_bins[bin];
}
longterm_channel_util = (float)longterm_channel_util_sum/(float)AIRTIME_BINS;
+
+ kiss_indicate_channel_stats();
#endif
}
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) {
if (dcd_led) {
led_rx_on();
} else {
- led_rx_off();
+ if (airtime_lock) {
+ led_indicate_airtime_lock();
+ } else {
+ led_rx_off();
+ }
}
}
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();
}
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;
+ }
}
}
#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
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);
}
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