11#if PC_ENABLE_MDNS_ADAPTIVE
13#if defined(ARDUINO) && PC_ENABLE_MDNS && PC_ENABLE_PROMISC
19uint32_t pc_mdns_refresh_interval(uint32_t ttl_s)
22 uint64_t half_ms = (uint64_t)ttl_s * 1000 / 2;
23 return half_ms > 0xFFFFFFFFu ? 0xFFFFFFFFu : (uint32_t)half_ms;
26void pc_mdns_beacon_init(MdnsBeacon *b, uint32_t base_ms, uint32_t max_ms, uint16_t hi_thresh)
33 b->max_ms = max_ms < base_ms ? base_ms : max_ms;
35 b->hi_thresh = hi_thresh ? hi_thresh : 1;
38uint32_t pc_mdns_beacon_adapt(MdnsBeacon *b, uint16_t contention)
44 if (contention >= b->hi_thresh)
46 uint32_t up = b->cur_ms << 1;
47 if (up < b->cur_ms || up > b->max_ms)
53 else if (contention == 0)
55 uint32_t down = b->cur_ms >> 1;
56 if (down < b->base_ms)
65bool pc_mdns_beacon_due(
const MdnsBeacon *b, uint32_t last_ms, uint32_t now_ms)
71 uint32_t elapsed = now_ms - last_ms;
72 return elapsed >= b->cur_ms;
75bool pc_mdns_beacon_presleep_due(
const MdnsBeacon *b, uint32_t last_ms, uint32_t now_ms, uint32_t sleep_ms)
81 uint32_t elapsed = now_ms - last_ms;
83 uint64_t after = (uint64_t)elapsed + sleep_ms;
84 return after >= b->cur_ms;
91void pc_mdns_contention_init(MdnsContentionWindow *w, uint32_t window_ms, uint32_t frames_now, uint32_t now_ms)
97 w->last_count = frames_now;
99 w->window_ms = window_ms ? window_ms : 1000;
102bool pc_mdns_contention_sample(MdnsContentionWindow *w, uint32_t frames_now, uint32_t now_ms, uint16_t *out)
108 uint32_t elapsed = now_ms - w->last_ms;
109 if (elapsed < w->window_ms)
115 uint32_t delta = frames_now - w->last_count;
116 *out = delta > 0xFFFF ? 0xFFFF : (uint16_t)delta;
117 w->last_count = frames_now;
126#if defined(ARDUINO) && PC_ENABLE_MDNS && PC_ENABLE_PROMISC
129struct MdnsAdaptiveCtx
133 MdnsContentionWindow window;
134 volatile uint32_t frames;
135 uint32_t last_announce_ms;
136 uint16_t last_contention;
141static MdnsAdaptiveCtx s_ad = {};
145static void adaptive_sink(
const uint8_t *frame, uint16_t len, int8_t rssi, uint8_t channel)
154bool pc_mdns_adaptive_begin(
const MdnsAdaptiveCfg *cfg)
156 if (!cfg || s_ad.running)
168 uint32_t base = pc_mdns_refresh_interval(cfg->ttl_s);
174 uint64_t ttl_ms = (uint64_t)cfg->ttl_s * 1000;
175 uint32_t safe_ceiling = (uint32_t)(ttl_ms - ttl_ms / 8 > 0xFFFFFFFFu ? 0xFFFFFFFFu : ttl_ms - ttl_ms / 8);
176 uint32_t ceiling = cfg->max_interval_ms < safe_ceiling ? cfg->max_interval_ms : safe_ceiling;
177 pc_mdns_beacon_init(&s_ad.beacon, base, ceiling, cfg->hi_contention);
179 pc_mdns_contention_init(&s_ad.window, cfg->window_ms, 0, now);
180 s_ad.last_announce_ms = now;
181 s_ad.last_contention = 0;
186 s_ad.running = pc_promisc_begin(ch, adaptive_sink);
190void pc_mdns_adaptive_tick(
void)
200 if (ch != 0 && ch != s_ad.channel)
202 pc_promisc_set_channel(ch);
208 if (pc_mdns_contention_sample(&s_ad.window, s_ad.frames, now, &c))
210 s_ad.last_contention = c;
211 pc_mdns_beacon_adapt(&s_ad.beacon, c);
216 if (pc_mdns_beacon_due(&s_ad.beacon, s_ad.last_announce_ms, now))
219 s_ad.last_announce_ms = now;
224void pc_mdns_adaptive_end(
void)
231 s_ad.running =
false;
234uint32_t pc_mdns_adaptive_interval_ms(
void)
236 return s_ad.beacon.cur_ms;
239uint16_t pc_mdns_adaptive_contention(
void)
241 return s_ad.last_contention;
244uint32_t pc_mdns_adaptive_announces(
void)
246 return s_ad.announces;
Pluggable monotonic clock for all library timing.
uint32_t pc_millis(void)
The library's monotonic time at 1000 Hz (milliseconds).
Adaptive mDNS beacon scheduling: RF-aware backoff, TTL refresher, auto-sleep beacon (PC_ENABLE_MDNS_A...
Optional mDNS / DNS-SD advertisement (PC_ENABLE_MDNS).
bool pc_mdns_txt(const char *key, const char *value)
Add a TXT key/value record to the advertised _http._tcp service.
uint8_t pc_net_channel(void)
Station WiFi channel (1..14), or 0 if not associated (and on host builds).
Layer 1 (Physical) - link bring-up and live egress-interface reporting.
Wi-Fi promiscuous (monitor) capture (PC_ENABLE_PROMISC) - passive 802.11 sniffing.