Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/companion_radio/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe

// defaults
memset(&_prefs, 0, sizeof(_prefs));
_prefs.airtime_factor = 1.0; // one half
_prefs.airtime_factor = 1.0;
strcpy(_prefs.node_name, "NONAME");
_prefs.freq = LORA_FREQ;
_prefs.sf = LORA_SF;
Expand Down
2 changes: 1 addition & 1 deletion examples/simple_repeater/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc

// defaults
memset(&_prefs, 0, sizeof(_prefs));
_prefs.airtime_factor = 1.0; // one half
_prefs.airtime_factor = 1.0;
_prefs.rx_delay_base = 0.0f; // turn off by default, was 10.0;
_prefs.tx_delay_factor = 0.5f; // was 0.25f
_prefs.direct_tx_delay_factor = 0.2f; // was zero
Expand Down
2 changes: 1 addition & 1 deletion examples/simple_room_server/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc

// defaults
memset(&_prefs, 0, sizeof(_prefs));
_prefs.airtime_factor = 1.0; // one half
_prefs.airtime_factor = 1.0;
_prefs.rx_delay_base = 0.0f; // off by default, was 10.0
_prefs.tx_delay_factor = 0.5f; // was 0.25f;
_prefs.direct_tx_delay_factor = 0.2f; // was zero
Expand Down
2 changes: 1 addition & 1 deletion examples/simple_secure_chat/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ class MyMesh : public BaseChatMesh, ContactVisitor {
{
// defaults
memset(&_prefs, 0, sizeof(_prefs));
_prefs.airtime_factor = 2.0; // one third
_prefs.airtime_factor = 1.0;
strcpy(_prefs.node_name, "NONAME");
_prefs.freq = LORA_FREQ;
_prefs.tx_power_dbm = LORA_TX_POWER;
Expand Down
2 changes: 1 addition & 1 deletion examples/simple_sensor/SensorMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ SensorMesh::SensorMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::Millise

// defaults
memset(&_prefs, 0, sizeof(_prefs));
_prefs.airtime_factor = 1.0; // one half
_prefs.airtime_factor = 1.0;
_prefs.rx_delay_base = 0.0f; // turn off by default, was 10.0;
_prefs.tx_delay_factor = 0.5f; // was 0.25f
_prefs.direct_tx_delay_factor = 0.2f; // was zero
Expand Down
60 changes: 53 additions & 7 deletions src/Dispatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,34 @@ void Dispatcher::begin() {
_err_flags = 0;
radio_nonrx_start = _ms->getMillis();

duty_cycle_window_ms = getDutyCycleWindowMs();
float duty_cycle = 1.0f / (1.0f + getAirtimeBudgetFactor());
tx_budget_ms = (unsigned long)(duty_cycle_window_ms * duty_cycle);
last_budget_update = _ms->getMillis();

_radio->begin();
prev_isrecv_mode = _radio->isInRecvMode();
}

float Dispatcher::getAirtimeBudgetFactor() const {
return 2.0; // default, 33.3% (1/3rd)
return 1.0;
}

void Dispatcher::updateTxBudget() {
Comment thread
ViezeVingertjes marked this conversation as resolved.
unsigned long now = _ms->getMillis();
unsigned long elapsed = now - last_budget_update;

float duty_cycle = 1.0f / (1.0f + getAirtimeBudgetFactor());
unsigned long max_budget = (unsigned long)(getDutyCycleWindowMs() * duty_cycle);
unsigned long refill = (unsigned long)(elapsed * duty_cycle);

if (refill > 0) {
tx_budget_ms += refill;
if (tx_budget_ms > max_budget) {
tx_budget_ms = max_budget;
}
last_budget_update = now;
}
}

int Dispatcher::calcRxDelay(float score, uint32_t air_time) const {
Expand Down Expand Up @@ -61,11 +83,24 @@ void Dispatcher::loop() {
if (outbound) { // waiting for outbound send to be completed
if (_radio->isSendComplete()) {
long t = _ms->getMillis() - outbound_start;
total_air_time += t; // keep track of how much air time we are using
total_air_time += t;
//Serial.print(" airtime="); Serial.println(t);

// will need radio silence up to next_tx_time
next_tx_time = futureMillis(t * getAirtimeBudgetFactor());
updateTxBudget();

if (t > tx_budget_ms) {
tx_budget_ms = 0;
} else {
tx_budget_ms -= t;
}

if (tx_budget_ms < 100) {
Comment thread
ViezeVingertjes marked this conversation as resolved.
Outdated
float duty_cycle = 1.0f / (1.0f + getAirtimeBudgetFactor());
unsigned long needed = 100 - tx_budget_ms;
next_tx_time = futureMillis((unsigned long)(needed / duty_cycle));
} else {
next_tx_time = _ms->getMillis();
}

_radio->onSendFinished();
logTx(outbound, 2 + outbound->path_len + outbound->payload_len);
Expand Down Expand Up @@ -224,9 +259,20 @@ void Dispatcher::processRecvPacket(Packet* pkt) {
}

void Dispatcher::checkSend() {
if (_mgr->getOutboundCount(_ms->getMillis()) == 0) return; // nothing waiting to send
if (!millisHasNowPassed(next_tx_time)) return; // still in 'radio silence' phase (from airtime budget setting)
if (_radio->isReceiving()) { // LBT - check if radio is currently mid-receive, or if channel activity
if (_mgr->getOutboundCount(_ms->getMillis()) == 0) return;

updateTxBudget();

uint32_t est_airtime = _radio->getEstAirtimeFor(MAX_TRANS_UNIT);
if (tx_budget_ms < est_airtime / 2) {
Comment thread
ViezeVingertjes marked this conversation as resolved.
Outdated
float duty_cycle = 1.0f / (1.0f + getAirtimeBudgetFactor());
unsigned long needed = est_airtime / 2 - tx_budget_ms;
next_tx_time = futureMillis((unsigned long)(needed / duty_cycle));
return;
}

if (!millisHasNowPassed(next_tx_time)) return;
if (_radio->isReceiving()) {
if (cad_busy_start == 0) {
cad_busy_start = _ms->getMillis(); // record when CAD busy state started
}
Expand Down
11 changes: 10 additions & 1 deletion src/Dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,12 @@ class Dispatcher {
bool prev_isrecv_mode;
uint32_t n_sent_flood, n_sent_direct;
uint32_t n_recv_flood, n_recv_direct;
unsigned long tx_budget_ms;
unsigned long last_budget_update;
unsigned long duty_cycle_window_ms;

void processRecvPacket(Packet* pkt);
void updateTxBudget();

protected:
PacketManager* _mgr;
Expand All @@ -142,6 +146,9 @@ class Dispatcher {
_err_flags = 0;
radio_nonrx_start = 0;
prev_isrecv_mode = true;
tx_budget_ms = 0;
last_budget_update = 0;
duty_cycle_window_ms = 3600000;
}

virtual DispatcherAction onRecvPacket(Packet* pkt) = 0;
Expand All @@ -159,6 +166,7 @@ class Dispatcher {
virtual uint32_t getCADFailMaxDuration() const;
virtual int getInterferenceThreshold() const { return 0; } // disabled by default
virtual int getAGCResetInterval() const { return 0; } // disabled by default
virtual unsigned long getDutyCycleWindowMs() const { return 3600000; }

public:
void begin();
Expand All @@ -168,8 +176,9 @@ class Dispatcher {
void releasePacket(Packet* packet);
void sendPacket(Packet* packet, uint8_t priority, uint32_t delay_millis=0);

unsigned long getTotalAirTime() const { return total_air_time; } // in milliseconds
unsigned long getTotalAirTime() const { return total_air_time; }
unsigned long getReceiveAirTime() const {return rx_air_time; }
unsigned long getRemainingTxBudget() const { return tx_budget_ms; }
uint32_t getNumSentFlood() const { return n_sent_flood; }
uint32_t getNumSentDirect() const { return n_sent_direct; }
uint32_t getNumRecvFlood() const { return n_recv_flood; }
Expand Down