Reworked CSMA algorithm

This commit is contained in:
Mark Qvist 2025-01-07 20:15:26 +01:00
parent 08651f92f7
commit 5ec063c939
3 changed files with 144 additions and 57 deletions

View File

@ -19,6 +19,15 @@
#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

View File

@ -67,31 +67,41 @@
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;
#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;
int csma_slot_ms = 50;
////////////////////////////////////////
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;

View 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
update_modem_status(); // TODO: Remove debug
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();
}
tx_queue_handler();
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;
}
}
}
}
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) {