Skip to content

Commit 802dc84

Browse files
committed
ease net defaults and live pacing
1 parent e56f3f1 commit 802dc84

File tree

5 files changed

+100
-68
lines changed

5 files changed

+100
-68
lines changed

examples/LiveNetworkNode/LiveNetworkNode.ino

Lines changed: 28 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ namespace {
2626
const unsigned long kSamplePeriodUs = 100000UL;
2727
#if defined(ARDUINO_ARCH_ESP8266)
2828
const unsigned long kSampleTaskIntervalMs = 100UL;
29-
const unsigned long kDispatchPeriodMs = 1000UL;
30-
const unsigned long kHttpIoTimeoutMs = 250UL;
29+
const unsigned long kHttpDispatchPeriodMs = 1500UL;
30+
const unsigned long kMqttDispatchPeriodMs = 1000UL;
31+
const unsigned long kHttpIoTimeoutMs = 200UL;
3132
#else
3233
const unsigned long kSampleTaskIntervalMs = 1UL;
33-
const unsigned long kDispatchPeriodMs = 500UL;
34+
const unsigned long kHttpDispatchPeriodMs = 500UL;
35+
const unsigned long kMqttDispatchPeriodMs = 500UL;
3436
const unsigned long kHttpIoTimeoutMs = 500UL;
3537
#endif
3638
const unsigned long kSummaryPeriodMs = 10000UL;
@@ -63,7 +65,8 @@ uint8_t g_httpStatusLineLength = 0;
6365

6466
unsigned long g_startedAtMs = 0;
6567
unsigned long g_lastSummaryAtMs = 0;
66-
unsigned long g_lastDispatchAtMs = 0;
68+
unsigned long g_lastHttpDispatchAtMs = 0;
69+
unsigned long g_lastMqttDispatchAtMs = 0;
6770
unsigned long g_nextExpectedUs = 0;
6871
unsigned long g_sampleRuns = 0;
6972
unsigned long g_lagAccumUs = 0;
@@ -254,16 +257,12 @@ void sampleTask() {
254257

255258
void dispatchTask() {
256259
const unsigned long nowMs = millis();
257-
#if defined(ARDUINO_ARCH_ESP8266)
258-
if ((nowMs - g_lastDispatchAtMs) < kDispatchPeriodMs) {
259-
#else
260-
if (g_lastDispatchAtMs != 0 && (nowMs - g_lastDispatchAtMs) < kDispatchPeriodMs) {
261-
#endif
262-
return;
263-
}
264-
g_lastDispatchAtMs = nowMs;
265260

266-
if (g_httpPump.queuedCount() == 0 && !g_httpPump.isBusy()) {
261+
const bool httpDue = (nowMs - g_lastHttpDispatchAtMs) >= kHttpDispatchPeriodMs;
262+
const bool mqttDue = (nowMs - g_lastMqttDispatchAtMs) >= kMqttDispatchPeriodMs;
263+
264+
if (httpDue && g_httpPump.queuedCount() == 0 && !g_httpPump.isBusy()) {
265+
g_lastHttpDispatchAtMs = nowMs;
267266
const int written = snprintf(g_httpPayload, sizeof(g_httpPayload),
268267
"{\"seq\":%lu,\"sensor\":%lu,\"board\":\"module\"}",
269268
g_sampleRuns, g_sensorValue);
@@ -277,8 +276,11 @@ void dispatchTask() {
277276
}
278277
}
279278

280-
if (g_mqttPump.queuedCount() < ZeroMqttPump::kQueueCapacity) {
281-
g_mqttPump.enqueue(kTelemetryTopic, Kernel::EventValue::fromUnsigned(g_sensorValue), 1);
279+
if (mqttDue) {
280+
g_lastMqttDispatchAtMs = nowMs;
281+
if (g_mqttPump.queuedCount() < ZeroMqttPump::kQueueCapacity) {
282+
g_mqttPump.enqueue(kTelemetryTopic, Kernel::EventValue::fromUnsigned(g_sensorValue), 1);
283+
}
282284
}
283285
}
284286

@@ -371,48 +373,27 @@ void setup() {
371373
ZeroKernel.subscribeTypedFast(kMqttStateTopic, onTypedState);
372374

373375
ZeroWiFiMaintainer::Config wifiConfig;
374-
wifiConfig.pollIntervalMs = 500;
375376
#if defined(ARDUINO_ARCH_ESP8266)
376-
wifiConfig.retryBaseMs = 3000;
377-
wifiConfig.retryMaxMs = 15000;
378-
wifiConfig.retryJitterMs = 500;
379-
#else
380-
wifiConfig.retryBaseMs = 1000;
381-
wifiConfig.retryMaxMs = 10000;
382-
wifiConfig.retryJitterMs = 300;
377+
wifiConfig.retryBaseMs = 1500;
378+
wifiConfig.retryMaxMs = 8000;
379+
wifiConfig.retryJitterMs = 250;
380+
wifiConfig.stablePollMultiplier = 2;
383381
#endif
384-
wifiConfig.stablePollMultiplier = 4;
385-
wifiConfig.stableThreshold = 6;
386382
wifiConfig.manageCapabilities = true;
387383
wifiConfig.capabilityMask = Kernel::kCapNetwork;
388384
wifiConfig.stateTopicKey = kWiFiStateTopic;
389385
g_wifiMaintainer.begin(ZeroKernel, isWiFiConnected, connectWiFi, disconnectWiFi, wifiConfig);
390386

391387
ZeroHttpPump::Config httpConfig;
392-
httpConfig.pollIntervalMs = 100;
393-
httpConfig.retryBaseMs = 500;
394-
httpConfig.retryMaxMs = 3000;
395-
httpConfig.retryJitterMs = 150;
396-
httpConfig.maxRetries = 2;
397-
#if defined(ARDUINO_ARCH_ESP8266)
398-
httpConfig.phaseTimeoutMs = 300;
399-
#else
400-
httpConfig.phaseTimeoutMs = 600;
401-
#endif
402388
g_httpPump.begin(ZeroKernel,
403389
httpConnectStep,
404390
httpWriteStep,
405391
httpReadStep,
406392
httpCloseStep,
407393
httpConfig);
394+
g_httpPump.setLinkProbe(isWiFiConnected);
408395

409396
ZeroMqttPump::Config mqttConfig;
410-
mqttConfig.pollIntervalMs = 100;
411-
mqttConfig.retryBaseMs = 500;
412-
mqttConfig.retryMaxMs = 3000;
413-
mqttConfig.retryJitterMs = 200;
414-
mqttConfig.maxRetries = 2;
415-
mqttConfig.idleLoopIntervalMs = 250;
416397
mqttConfig.stateTopicKey = kMqttStateTopic;
417398
g_mqttPump.begin(ZeroKernel,
418399
mqttLinkProbe,
@@ -423,16 +404,16 @@ void setup() {
423404

424405
#if defined(ARDUINO_ARCH_ESP8266)
425406
ZeroKernel.addTask("Sample", sampleTask, 100, 0);
426-
ZeroKernel.addTask("WiFiMaint", wifiMaintainerTask, 250, 0);
427-
ZeroKernel.addTask("HttpPump", httpPumpTask, 200, 0);
428-
ZeroKernel.addTask("MqttPump", mqttPumpTask, 200, 0);
429-
ZeroKernel.addTask("Dispatch", dispatchTask, 250, 0);
407+
ZeroKernel.addTask("WiFiMaint", wifiMaintainerTask, 100, 0);
408+
ZeroKernel.addTask("HttpPump", httpPumpTask, 100, 0);
409+
ZeroKernel.addTask("MqttPump", mqttPumpTask, 100, 0);
410+
ZeroKernel.addTask("Dispatch", dispatchTask, 100, 0);
430411
#else
431412
ZeroKernel.addTask("Sample", sampleTask, kSampleTaskIntervalMs, 0);
432-
ZeroKernel.addTask("WiFiMaint", wifiMaintainerTask, 250, kWiFiMaintStartDelayMs);
413+
ZeroKernel.addTask("WiFiMaint", wifiMaintainerTask, 100, kWiFiMaintStartDelayMs);
433414
ZeroKernel.addTask("HttpPump", httpPumpTask, 100, kHttpPumpStartDelayMs);
434415
ZeroKernel.addTask("MqttPump", mqttPumpTask, 100, kMqttPumpStartDelayMs);
435-
ZeroKernel.addTask("Dispatch", dispatchTask, kDispatchPeriodMs, kDispatchStartDelayMs);
416+
ZeroKernel.addTask("Dispatch", dispatchTask, 100, kDispatchStartDelayMs);
436417
#endif
437418
ZeroKernel.addTask("Report", reportTask, 250, kReportStartDelayMs);
438419

src/modules/net/ZeroHttpPump.h

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class ZeroHttpPump {
1818
kStepComplete = 1
1919
};
2020

21+
typedef bool (*LinkProbe)();
22+
2123
enum Phase : uint8_t {
2224
kPhaseIdle = 0,
2325
kPhaseConnecting = 1,
@@ -58,11 +60,23 @@ class ZeroHttpPump {
5860
bool emitCompletionEvents;
5961

6062
Config()
61-
: pollIntervalMs(0),
62-
retryBaseMs(250),
63-
retryMaxMs(2000),
64-
retryJitterMs(0),
65-
phaseTimeoutMs(0),
63+
: pollIntervalMs(100),
64+
#if defined(ARDUINO_ARCH_ESP8266)
65+
retryBaseMs(500),
66+
retryMaxMs(3000),
67+
retryJitterMs(150),
68+
phaseTimeoutMs(200),
69+
#elif defined(ARDUINO_ARCH_ESP32)
70+
retryBaseMs(500),
71+
retryMaxMs(3000),
72+
retryJitterMs(150),
73+
phaseTimeoutMs(400),
74+
#else
75+
retryBaseMs(500),
76+
retryMaxMs(3000),
77+
retryJitterMs(100),
78+
phaseTimeoutMs(300),
79+
#endif
6680
maxRetries(2),
6781
dropOldestOnFull(true),
6882
emitCompletionEvents(true) {}
@@ -73,6 +87,7 @@ class ZeroHttpPump {
7387

7488
ZeroHttpPump()
7589
: kernel_(NULL),
90+
linkProbe_(NULL),
7691
connectStep_(NULL),
7792
writeStep_(NULL),
7893
readStep_(NULL),
@@ -112,6 +127,10 @@ class ZeroHttpPump {
112127
currentRetryMs_ = config.retryBaseMs;
113128
}
114129

130+
void setLinkProbe(LinkProbe linkProbe) {
131+
linkProbe_ = linkProbe;
132+
}
133+
115134
void reset() {
116135
metrics_.reset();
117136
started_ = false;
@@ -177,13 +196,22 @@ class ZeroHttpPump {
177196
return;
178197
}
179198

199+
if (linkProbe_ != NULL && !linkProbe_()) {
200+
return;
201+
}
202+
180203
startNextRequest_(nowMs);
181204
}
182205

183206
if (phase_ == kPhaseConnecting && nextRetryAtMs_ != 0 && nowMs < nextRetryAtMs_) {
184207
return;
185208
}
186209

210+
if (phase_ == kPhaseConnecting && linkProbe_ != NULL && !linkProbe_()) {
211+
handlePhaseFailure_(nowMs);
212+
return;
213+
}
214+
187215
if (config_.phaseTimeoutMs > 0 && phaseStartedAtMs_ != 0 &&
188216
(nowMs - phaseStartedAtMs_) > config_.phaseTimeoutMs) {
189217
metrics_.recordPhaseTimeout();
@@ -366,6 +394,7 @@ class ZeroHttpPump {
366394
}
367395

368396
Kernel* kernel_;
397+
LinkProbe linkProbe_;
369398
StepCallback connectStep_;
370399
StepCallback writeStep_;
371400
StepCallback readStep_;

src/modules/net/ZeroMqttPump.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ class ZeroMqttPump {
4343
Kernel::TopicKey stateTopicKey;
4444

4545
Config()
46-
: pollIntervalMs(50),
46+
: pollIntervalMs(100),
4747
retryBaseMs(500),
48-
retryMaxMs(5000),
49-
retryJitterMs(0),
50-
idleLoopIntervalMs(0),
48+
retryMaxMs(3000),
49+
retryJitterMs(200),
50+
idleLoopIntervalMs(250),
5151
maxRetries(2),
5252
dropOldestOnFull(true),
5353
stateTopicKey(0) {}

src/modules/net/ZeroWiFiMaintainer.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,18 @@ class ZeroWiFiMaintainer {
2929
Kernel::TopicKey stateTopicKey;
3030

3131
Config()
32-
: pollIntervalMs(250),
32+
: pollIntervalMs(500),
33+
#if defined(ARDUINO_ARCH_ESP8266)
34+
retryBaseMs(3000),
35+
retryMaxMs(15000),
36+
retryJitterMs(500),
37+
#else
3338
retryBaseMs(1000),
3439
retryMaxMs(10000),
35-
retryJitterMs(0),
36-
stablePollMultiplier(1),
37-
stableThreshold(4),
40+
retryJitterMs(300),
41+
#endif
42+
stablePollMultiplier(4),
43+
stableThreshold(6),
3844
emitStateChangesOnly(true),
3945
manageCapabilities(false),
4046
capabilityMask(Kernel::kCapNetwork),

tests/desktop/KernelTests.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,10 @@ bool wifiLinkProbe() {
193193
return g_wifiLinkUp;
194194
}
195195

196+
bool httpLinkProbe() {
197+
return g_wifiLinkUp;
198+
}
199+
196200
void wifiConnectStep() {
197201
++g_wifiConnectCalls;
198202
}
@@ -915,8 +919,10 @@ int testHttpPumpModule() {
915919
zerokernel::Kernel::makeTopicKey("http.done");
916920

917921
zerokernel::modules::net::ZeroHttpPump::Config config;
922+
config.pollIntervalMs = 0;
918923
config.retryBaseMs = 20;
919924
config.retryMaxMs = 40;
925+
config.retryJitterMs = 0;
920926
config.maxRetries = 1;
921927
config.emitCompletionEvents = true;
922928

@@ -927,6 +933,7 @@ int testHttpPumpModule() {
927933
g_httpCloseCalls = 0;
928934
g_httpCompletionEvents = 0;
929935
g_httpLastCompletion = false;
936+
g_wifiLinkUp = false;
930937

931938
isolatedKernel.begin(fakeClock);
932939
expectTrue(isolatedKernel.subscribeTypedFast(completionKey, onHttpCompletionEvent),
@@ -937,6 +944,7 @@ int testHttpPumpModule() {
937944
httpReadStep,
938945
httpCloseStep,
939946
config);
947+
pump.setLinkProbe(httpLinkProbe);
940948

941949
zerokernel::modules::net::ZeroHttpPump::Request request;
942950
request.path = "/api/data";
@@ -949,40 +957,42 @@ int testHttpPumpModule() {
949957
g_fakeNowMs = 1;
950958
isolatedKernel.tick();
951959
pump.tick();
960+
expectTrue(!pump.isBusy(), "http pump waits for link before starting");
961+
962+
g_wifiLinkUp = true;
963+
g_fakeNowMs = 2;
964+
isolatedKernel.tick();
965+
pump.tick();
952966
expectTrue(pump.isBusy(), "http pump becomes busy");
953967
expectTrue(pump.phase() == zerokernel::modules::net::ZeroHttpPump::kPhaseConnecting,
954968
"http pump starts in connect phase");
955969

956-
g_fakeNowMs = 2;
970+
g_fakeNowMs = 3;
957971
isolatedKernel.tick();
958972
pump.tick();
959973
expectTrue(pump.phase() == zerokernel::modules::net::ZeroHttpPump::kPhaseWriting,
960974
"http pump advances to write after connect");
961975
expectTrue(g_httpWriteCalls == 0, "http pump defers write until next tick");
962976

963-
g_fakeNowMs = 3;
977+
g_fakeNowMs = 4;
964978
isolatedKernel.tick();
965979
pump.tick();
966980
expectTrue(g_httpWriteCalls == 1, "http pump executes write phase");
967981
expectTrue(pump.phase() == zerokernel::modules::net::ZeroHttpPump::kPhaseReading,
968982
"http pump advances to read after write");
969983

970-
g_fakeNowMs = 4;
984+
g_fakeNowMs = 5;
971985
isolatedKernel.tick();
972986
pump.tick();
973987
expectTrue(g_httpReadCalls == 1, "http pump executes read phase");
974988
expectTrue(pump.phase() == zerokernel::modules::net::ZeroHttpPump::kPhaseConnecting,
975989
"http pump retries after read failure");
976990

977-
g_fakeNowMs = 10;
991+
g_fakeNowMs = 11;
978992
isolatedKernel.tick();
979993
pump.tick();
980994
expectTrue(g_httpConnectCalls == 2, "http pump waits for retry window");
981995

982-
g_fakeNowMs = 24;
983-
isolatedKernel.tick();
984-
pump.tick();
985-
986996
g_fakeNowMs = 25;
987997
isolatedKernel.tick();
988998
pump.tick();
@@ -995,6 +1005,10 @@ int testHttpPumpModule() {
9951005
isolatedKernel.tick();
9961006
pump.tick();
9971007

1008+
g_fakeNowMs = 28;
1009+
isolatedKernel.tick();
1010+
pump.tick();
1011+
9981012
const zerokernel::modules::net::ZeroTransportMetrics::Snapshot httpMetrics =
9991013
pump.metrics().snapshot();
10001014
expectTrue(!pump.isBusy(), "http pump returns idle after success");
@@ -1034,6 +1048,8 @@ int testMqttPumpModule() {
10341048
config.pollIntervalMs = 0;
10351049
config.retryBaseMs = 5;
10361050
config.retryMaxMs = 10;
1051+
config.retryJitterMs = 0;
1052+
config.idleLoopIntervalMs = 0;
10371053
config.maxRetries = 1;
10381054
config.stateTopicKey = stateKey;
10391055

0 commit comments

Comments
 (0)