Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
15 changes: 10 additions & 5 deletions dmc-docs/custom-cli.de.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,21 @@ ACL-Kontaktpakete werden übersprungen. Der Zustand wird in `/filter_prefs` gesp

## Duty-Cycle-Region-Gating

`dc.gate.*`. Standardmäßig **aus**. Wirft Inter-Regions-Flood-Verkehr ab, wenn der eigene
TX-Duty-Cycle des Repeaters hoch ist. Transient: wird nie in die Regionskonfiguration
geschrieben. Läuft vor dem Packet-Filter, daher erscheinen diese Drops nicht in
`filter stats`.
`dc.gate.*`. Standardmäßig **aus**. Wirft Inter-Regions-Flood-Verkehr ab, wenn der
Repeater den größten Teil seines Duty-Cycle-Budgets verbraucht hat. Transient: wird nie in
die Regionskonfiguration geschrieben. Läuft vor dem Packet-Filter, daher erscheinen diese
Drops nicht in `filter stats`.

- `set dc.gate <0|1>` / `get dc.gate`
- `set dc.gate <on|off>` / `get dc.gate` (`1`/`0` funktionieren auch)
- `set dc.gate.thresh <1-100>` / `get dc.gate.thresh` (Standard 70)
- `set dc.gate.hyst <0-50>` / `get dc.gate.hyst` (Standard 10)
- `get dc.gate.status` (z. B. `duty 74%, gate level 2/4`)

Schwelle, Hysterese und `duty` sind ein Prozentsatz des **Duty-Cycle-Budgets**
(`set dutycycle`), nicht der Uhrzeit. Mit `dutycycle 10` darf der Repeater 360 Sekunden
pro Stunde senden; `dc.gate.thresh 70` beginnt mit dem Gating, sobald 252 dieser Sekunden
verbraucht sind. Die Schwelle muss also nicht unter dem Duty-Cycle-Limit liegen.

## Duty-Cycle

DMC ergänzte `auto` und änderte die Vorgabe von 50% auf `auto`.
Expand Down
13 changes: 9 additions & 4 deletions dmc-docs/custom-cli.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,20 @@ packets bypass it. State is persisted to `/filter_prefs`.

## Duty-cycle region gating

`dc.gate.*`. **Off** by default. Sheds inter-region flood traffic when the repeater's own
TX duty cycle is high. Transient: never written to the region config. Runs before the
packet filter, so these drops do not appear in `filter stats`.
`dc.gate.*`. **Off** by default. Sheds inter-region flood traffic when the repeater has
used up most of its duty-cycle budget. Transient: never written to the region config. Runs
before the packet filter, so these drops do not appear in `filter stats`.

- `set dc.gate <0|1>` / `get dc.gate`
- `set dc.gate <on|off>` / `get dc.gate` (`1`/`0` work too)
- `set dc.gate.thresh <1-100>` / `get dc.gate.thresh` (default 70)
- `set dc.gate.hyst <0-50>` / `get dc.gate.hyst` (default 10)
- `get dc.gate.status` (e.g. `duty 74%, gate level 2/4`)

The threshold, hysteresis and `duty` are a percentage of the **duty-cycle budget**
(`set dutycycle`), not of wall-clock time. With `dutycycle 10` the repeater may transmit
for 360 seconds per hour; `dc.gate.thresh 70` starts gating once 252 of those seconds are
used. The threshold does not need to be below the duty-cycle limit.

## Duty cycle

DMC added `auto` and changed the default from 50% to `auto`.
Expand Down
15 changes: 10 additions & 5 deletions dmc-docs/custom-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,21 @@ ACL-contactpakketten worden overgeslagen. De status wordt bewaard in `/filter_pr

## Duty-cycle region gating

`dc.gate.*`. Standaard **uit**. Werpt inter-regio-floodverkeer af wanneer de eigen
TX-duty-cycle van de repeater hoog is. Transient: wordt nooit naar de regioconfiguratie
weggeschreven. Draait vóór de packet filter, dus deze drops verschijnen niet in
`filter stats`.
`dc.gate.*`. Standaard **uit**. Werpt inter-regio-floodverkeer af wanneer de repeater
het grootste deel van zijn duty-cycle-budget heeft verbruikt. Transient: wordt nooit naar
de regioconfiguratie weggeschreven. Draait vóór de packet filter, dus deze drops
verschijnen niet in `filter stats`.

- `set dc.gate <0|1>` / `get dc.gate`
- `set dc.gate <on|off>` / `get dc.gate` (`1`/`0` werkt ook)
- `set dc.gate.thresh <1-100>` / `get dc.gate.thresh` (standaard 70)
- `set dc.gate.hyst <0-50>` / `get dc.gate.hyst` (standaard 10)
- `get dc.gate.status` (bijv. `duty 74%, gate level 2/4`)

De drempel, de hysterese en `duty` zijn een percentage van het **duty-cycle-budget**
(`set dutycycle`), niet van de kloktijd. Met `dutycycle 10` mag de repeater 360 seconden
per uur zenden; `dc.gate.thresh 70` start de gating zodra 252 van die seconden zijn
verbruikt. De drempel hoeft dus niet onder de duty-cycle-limiet te liggen.

## Duty cycle

DMC voegde `auto` toe en veranderde de standaard van 50% naar `auto`.
Expand Down
45 changes: 33 additions & 12 deletions docs/cli_commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -725,34 +725,55 @@ reports which of the two is active.

#### Duty-cycle region gating

Autonomously sheds inter-region flood traffic when this repeater's own TX duty
cycle is high, protecting the local cluster during high-traffic or disruption
Autonomously sheds inter-region flood traffic when this repeater has used up most
of its duty-cycle budget, protecting the local cluster during high-traffic or disruption
events — no admin access needed once configured. Opt-in and **off by default**.

It reuses the existing [Region Management](#region-management-v110) hierarchy.
When the TX duty cycle rises above the threshold, regions are gated from the
When budget use rises above the threshold, regions are gated from the
outermost layer inward — the wildcard `*` first, then the broadest named regions
— always keeping the innermost cluster and the operator's home region open. As
the duty cycle recovers below `threshold − hysteresis`, regions re-open
budget use recovers below `threshold − hysteresis`, regions re-open
inside-out, with a small random per-step delay so nearby repeaters don't all
recover in lockstep. The gate is transient: it is never written to the region
config, so a `region save` or a reboot mid-event can never make a deny permanent.

**Usage:**
- `set dc.gate <0|1>` — enable (`1`) or disable (`0`) the feature
- `set dc.gate <on|off>` — enable or disable the feature (`1`/`0` work too)
- `get dc.gate` — show whether it is on or off
- `set dc.gate.thresh <1-100>` — TX duty-cycle % above which gating starts
- `set dc.gate.thresh <1-100>` — % of the duty-cycle budget used above which gating starts
- `get dc.gate.thresh`
- `set dc.gate.hyst <0-50>` — recovery margin %: regions re-open below `(threshold − hysteresis)`
- `set dc.gate.hyst <0-50>` — recovery margin in percentage points: regions re-open below `(threshold − hysteresis)`
- `get dc.gate.hyst`
- `get dc.gate.status` — live TX duty cycle % and current gate level (`level/max`)
- `get dc.gate.status` — live % of the duty-cycle budget used, and current gate level (`level/max`)

**Defaults:** disabled; threshold `70`; hysteresis `10` (so recovery begins below 60%).
**Defaults:** off; threshold `70`; hysteresis `10` (so recovery begins below 60%).

**What the percentage measures:**

`dc.gate.thresh`, `dc.gate.hyst` and the `duty` in `get dc.gate.status` are a
percentage of this repeater's **duty-cycle budget** (set with
[`set dutycycle`](#view-or-change-the-duty-cycle-limit)), **not** a percentage of
wall-clock time. The budget is the airtime the duty-cycle limit allows per
hour, and it refills continuously. `duty 0%` means the full budget is
available; `duty 100%` means it is used up and the repeater has to hold back
transmissions until it refills.

For example, with `set dutycycle 10` the repeater may transmit for 360 seconds
per hour. With the default threshold of `70`, gating starts once 70% of that
budget is used (252 seconds, so less than 108 seconds left), and regions
start re-opening once usage drops below 60% (216 seconds). The threshold
therefore does **not** have to be set below the duty-cycle limit: `70` or `80`
is sensible with a 1%, 10% or any other limit.

With no duty-cycle limit (`set dutycycle 100`, or `auto` outside the
863-870 MHz table) the budget is the whole hour, so the percentage then does
equal the share of wall-clock time spent transmitting.

**Examples:**
- `set dc.gate 1` — turn gating on
- `set dc.gate.thresh 80` — only start shedding above 80% duty cycle
- `set dc.gate.hyst 15` — re-open regions once duty cycle drops below 65%
- `set dc.gate on` — turn gating on
- `set dc.gate.thresh 80` — only start shedding once 80% of the duty-cycle budget is used
- `set dc.gate.hyst 15` — re-open regions once usage drops below 65% of the budget
- `get dc.gate.status` — e.g. `> duty 74%, gate level 2/4`

**Notes:**
Expand Down
14 changes: 11 additions & 3 deletions src/helpers/CommonCLI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,9 +488,17 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
strcpy(reply, "OK");
}
} else if (memcmp(config, "dc.gate ", 8) == 0) {
_prefs->dc_gate_enabled = (atoi(&config[8]) != 0) ? 1 : 0;
savePrefs();
strcpy(reply, "OK");
// accept on/off as well as 1/0; anything else is rejected instead of silently disabling
const char* v = &config[8];
bool on = strcmp(v, "on") == 0 || strcmp(v, "1") == 0;
bool off = strcmp(v, "off") == 0 || strcmp(v, "0") == 0;
if (on || off) {
_prefs->dc_gate_enabled = on ? 1 : 0;
savePrefs();
strcpy(reply, "OK");
} else {
strcpy(reply, "ERROR: dc.gate must be on/off (or 1/0)");
}
} else if (memcmp(config, "flood.advert.interval ", 22) == 0) {
int hours = _atoi(&config[22]);
if ((hours > 0 && hours < 3) || (hours > 168)) {
Expand Down
Loading