mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-10-23 08:44:03 +00:00
get rid of housekeeping tick and AGC reset
This commit is contained in:
1 parent
394eefec51
commit
fe6e585eb6
30 files changed
+524
-166
No files matched your search
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <mesh/Maintenance.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
@@ -43,6 +44,13 @@ public:
|
||||
/* Finalize expired entries into EMA. */
|
||||
void tick(uint32_t now_ms);
|
||||
|
||||
/* Milliseconds until tick() next has work to do, or MAINTENANCE_IDLE
|
||||
* when nothing is pending (no tracked entries, EMA already at rest).
|
||||
* Lets the event loop schedule a wake at the deadline instead of
|
||||
* polling: an idle repeater has no tracked retransmits and a decayed
|
||||
* EMA, so this returns MAINTENANCE_IDLE and costs no wakes at all. */
|
||||
uint32_t msUntilNextTick(uint32_t now_ms) const;
|
||||
|
||||
float getContentionEstimate() const;
|
||||
|
||||
/* Saturating curve: MIN + (MAX-MIN) * est/(est+HALFPOINT).
|
||||
@@ -65,6 +73,15 @@ private:
|
||||
static constexpr float DEFAULT_BACKOFF_MULT = 0.2f; /* airtime*0.2 per dupe heard */
|
||||
static constexpr uint32_t REACTIVE_HARD_CAP_MS = 2000; /* max cumulative reactive extension */
|
||||
static constexpr uint32_t STALE_MS = 300000; /* 5 min: reset EMA if no traffic */
|
||||
/* Wall-clock period of one 1/8 stale-decay step. The decay used to be
|
||||
* "one step per tick()", which silently coupled it to the 5 s
|
||||
* housekeeping cadence; pinning it to 5000 ms keeps exactly that rate
|
||||
* while making it independent of how often tick() is actually called. */
|
||||
static constexpr uint32_t DECAY_PERIOD_MS = 5000;
|
||||
/* Bound the catch-up loop when tick() is called much later than one
|
||||
* period. 8 steps takes the EMA down by ~66%; anything beyond that is
|
||||
* indistinguishable from rest given the WARMUP/read paths. */
|
||||
static constexpr int MAX_DECAY_CATCHUP = 8;
|
||||
|
||||
struct Entry {
|
||||
uint32_t hash32;
|
||||
@@ -79,6 +96,7 @@ private:
|
||||
uint32_t _ema_x256;
|
||||
int _finalized_count;
|
||||
uint32_t _last_retransmit_ms;
|
||||
uint32_t _last_decay_ms;
|
||||
float _backoff_multiplier;
|
||||
|
||||
void finalizeEntry(int idx);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <mesh/Utils.h>
|
||||
#include <mesh/Radio.h>
|
||||
#include <mesh/Clock.h>
|
||||
#include <mesh/Maintenance.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace mesh {
|
||||
@@ -29,8 +30,6 @@ public:
|
||||
virtual uint32_t getOutboundSchedule(int i) const = 0;
|
||||
virtual bool rescheduleOutbound(int i, uint32_t new_scheduled_for) = 0;
|
||||
virtual uint8_t peekNextOutboundPriority(uint32_t now) const = 0;
|
||||
virtual void queueInbound(Packet *packet, uint32_t scheduled_for) = 0;
|
||||
virtual Packet *getNextInbound(uint32_t now) = 0;
|
||||
};
|
||||
|
||||
/* Notifies event loop of pending TX so it can schedule a wake. */
|
||||
@@ -43,6 +42,9 @@ typedef uint32_t DispatcherAction;
|
||||
#define ACTION_RETRANSMIT(pri) (((uint32_t)1 + (pri))<<24)
|
||||
#define ACTION_RETRANSMIT_DELAYED(pri, _delay) ((((uint32_t)1 + (pri))<<24) | (_delay))
|
||||
|
||||
/* Radio considered stalled after this long neither receiving nor sending. */
|
||||
#define RADIO_STALL_THRESHOLD_MS 8000
|
||||
|
||||
#define ERR_EVENT_FULL (1 << 0)
|
||||
#define ERR_EVENT_CAD_TIMEOUT (1 << 1)
|
||||
#define ERR_EVENT_STARTRX_TIMEOUT (1 << 2)
|
||||
@@ -57,7 +59,6 @@ class Dispatcher {
|
||||
uint32_t last_budget_update;
|
||||
uint32_t duty_cycle_window_ms;
|
||||
uint32_t radio_nonrx_start;
|
||||
uint32_t next_agc_reset_time;
|
||||
bool prev_isrecv_mode;
|
||||
int8_t cad_offset_shadow;
|
||||
bool cad_offset_shadow_valid;
|
||||
@@ -89,7 +90,6 @@ protected:
|
||||
virtual uint32_t getCADFailRetryDelay() const;
|
||||
virtual uint32_t getCADFailMaxDuration() const;
|
||||
virtual int getInterferenceThreshold() const { return 0; }
|
||||
virtual int getAGCResetInterval() const { return 0; }
|
||||
virtual uint32_t getDutyCycleWindowMs() const { return 3600000UL; } /* 1h default */
|
||||
/* Adaptive CAD: called when the auto staircase moved the operating
|
||||
* detPeak offset — subclasses persist it to prefs. */
|
||||
@@ -99,6 +99,13 @@ public:
|
||||
void begin();
|
||||
void loop();
|
||||
void maintenanceLoop();
|
||||
|
||||
/* Milliseconds until maintenanceLoop() next has work, or
|
||||
* MAINTENANCE_IDLE if nothing is pending. Cheap and side-effect free:
|
||||
* the event loop calls it after every pass to size its next sleep.
|
||||
* Subclasses that add their own time-based work in loop() override this
|
||||
* and fold their deadlines in — see RepeaterMesh. */
|
||||
virtual uint32_t msUntilNextMaintenance();
|
||||
Packet *obtainNewPacket();
|
||||
void releasePacket(Packet *packet);
|
||||
void sendPacket(Packet *packet, uint8_t priority, uint32_t delay_millis = 0);
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* Deadline-driven maintenance scheduling.
|
||||
*
|
||||
* maintenanceLoop() used to be driven by a fixed periodic tick (the 5 s
|
||||
* "housekeeping" timer). Every item inside it is really either a deadline
|
||||
* (AGC reset, CAD probe, advert timers, tempradio revert) or a sampler with
|
||||
* its own interval (noise floor) — nothing needs a poll. The msUntilNext*()
|
||||
* queries below let the event loop ask "when does maintenance next have work?"
|
||||
* and arm a single one-shot wake for exactly that moment, so an otherwise idle
|
||||
* node sleeps until its soonest real deadline instead of waking on a fixed
|
||||
* cadence.
|
||||
*
|
||||
* Contract: every msUntilNext*() returns milliseconds from now, 0 when work is
|
||||
* due right now, and MAINTENANCE_IDLE when the item has nothing pending at all.
|
||||
* Callers combine them with maintenanceSooner().
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
/* "No deadline pending." Deliberately not UINT32_MAX so that callers can add
|
||||
* a modest slack to a returned deadline without wrapping. */
|
||||
static const uint32_t MAINTENANCE_IDLE = 0x7FFFFFFFu;
|
||||
|
||||
/* Fold one deadline into a running minimum. */
|
||||
static inline uint32_t maintenanceSooner(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
/* Milliseconds from now until `deadline` (a millisecond-clock timestamp),
|
||||
* saturating at 0 when it has already passed. Wrap-safe: the subtraction is
|
||||
* done in unsigned arithmetic and the sign is taken from the wrapped result,
|
||||
* matching Dispatcher::millisHasNowPassed(). */
|
||||
static inline uint32_t maintenanceUntil(uint32_t now_ms, uint32_t deadline_ms)
|
||||
{
|
||||
int32_t remaining = (int32_t)(deadline_ms - now_ms);
|
||||
|
||||
if (remaining <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return ((uint32_t)remaining < MAINTENANCE_IDLE) ? (uint32_t)remaining
|
||||
: MAINTENANCE_IDLE;
|
||||
}
|
||||
|
||||
} /* namespace mesh */
|
||||
@@ -80,6 +80,7 @@ public:
|
||||
void begin();
|
||||
void loop();
|
||||
void maintenanceLoop();
|
||||
uint32_t msUntilNextMaintenance() override;
|
||||
|
||||
LocalIdentity self_id;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <mesh/Maintenance.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
@@ -22,7 +23,6 @@ public:
|
||||
|
||||
virtual int getNoiseFloor() const { return 0; }
|
||||
virtual void triggerNoiseFloorCalibrate(int threshold) { (void)threshold; }
|
||||
virtual void resetAGC() {}
|
||||
|
||||
virtual bool isInRecvMode() const = 0;
|
||||
virtual bool isReceiving() { return false; }
|
||||
@@ -49,6 +49,11 @@ public:
|
||||
/* One housekeeping tick of the CAD calibrator: maybe run a probe,
|
||||
* update stats, maybe step the staircase (auto mode). */
|
||||
virtual void cadMaintenance() {}
|
||||
|
||||
/* Milliseconds until this radio's periodic work (noise floor sampling,
|
||||
* CAD probing/decay) next needs a call, or MAINTENANCE_IDLE when it has
|
||||
* nothing pending. Radios with no periodic work keep the default. */
|
||||
virtual uint32_t msUntilNextMaintenance() { return MAINTENANCE_IDLE; }
|
||||
virtual int8_t getCadOffset() const { return 0; }
|
||||
virtual void resetCadStats() {}
|
||||
/* Writes a human-readable status block; returns chars written (0 = not
|
||||
|
||||
@@ -23,8 +23,6 @@ public:
|
||||
uint32_t getOutboundSchedule(int i) const override;
|
||||
bool rescheduleOutbound(int i, uint32_t new_scheduled_for) override;
|
||||
uint8_t peekNextOutboundPriority(uint32_t now) const override;
|
||||
void queueInbound(Packet *packet, uint32_t scheduled_for) override;
|
||||
Packet *getNextInbound(uint32_t now) override;
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
Reference in new issue
Block a user