@alteriom/painlessmesh 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +144 -0
  2. package/LICENSE +674 -0
  3. package/README.md +434 -0
  4. package/RELEASE_GUIDE.md +419 -0
  5. package/docs/DOCUMENTATION_MIGRATION_PLAN.md +176 -0
  6. package/docs/README.md +71 -0
  7. package/docs/alteriom/overview.md +508 -0
  8. package/docs/api/core-api.md +607 -0
  9. package/docs/architecture/mesh-architecture.md +379 -0
  10. package/docs/architecture/plugin-system.md +517 -0
  11. package/docs/getting-started/first-mesh.md +410 -0
  12. package/docs/getting-started/installation.md +275 -0
  13. package/docs/getting-started/quickstart.md +158 -0
  14. package/docs/improvements/README.md +69 -0
  15. package/docs/troubleshooting/common-issues.md +521 -0
  16. package/docs/troubleshooting/faq.md +473 -0
  17. package/docs/tutorials/basic-examples.md +718 -0
  18. package/docs/wiki/API-Reference.md +246 -0
  19. package/docs/wiki/Complete-Documentation.md +123 -0
  20. package/examples/alteriom/README.md +82 -0
  21. package/examples/alteriom/alteriom.ino +186 -0
  22. package/examples/alteriom/alteriom_sensor_node.ino +184 -0
  23. package/examples/alteriom/alteriom_sensor_package.hpp +128 -0
  24. package/examples/alteriom/improved_sensor_node.ino +246 -0
  25. package/examples/alteriom/platformio.ini +25 -0
  26. package/examples/basic/basic.ino +66 -0
  27. package/examples/basic/platformio.ini +25 -0
  28. package/examples/bridge/bridge.ino +51 -0
  29. package/examples/bridge/platformio.ini +25 -0
  30. package/examples/echoNode/echoNode.ino +33 -0
  31. package/examples/echoNode/platformio.ini +25 -0
  32. package/examples/logClient/logClient.ino +109 -0
  33. package/examples/logClient/platformio.ini +25 -0
  34. package/examples/logServer/logServer.ino +81 -0
  35. package/examples/logServer/platformio.ini +25 -0
  36. package/examples/mqttBridge/mqttBridge.ino +118 -0
  37. package/examples/mqttBridge/platformio.ini +26 -0
  38. package/examples/namedMesh/namedMesh.ino +97 -0
  39. package/examples/namedMesh/platformio.ini +25 -0
  40. package/examples/otaReceiver/otaReceiver.ino +79 -0
  41. package/examples/otaReceiver/platformio.ini +25 -0
  42. package/examples/otaSender/nodemcu32s_connections.JPG +0 -0
  43. package/examples/otaSender/otaSender.ino +151 -0
  44. package/examples/otaSender/platformio.ini +25 -0
  45. package/examples/startHere/platformio.ini +25 -0
  46. package/examples/startHere/startHere.ino +159 -0
  47. package/examples/webServer/platformio.ini +27 -0
  48. package/examples/webServer/webServer.ino +89 -0
  49. package/keywords.txt +49 -0
  50. package/library.json +34 -0
  51. package/library.properties +11 -0
  52. package/package.json +78 -0
  53. package/src/AlteriomPainlessMesh.h +98 -0
  54. package/src/arduino/wifi.hpp +365 -0
  55. package/src/boost/asynctcp.hpp +279 -0
  56. package/src/painlessMesh.h +70 -0
  57. package/src/painlessMeshSTA.cpp +236 -0
  58. package/src/painlessMeshSTA.h +58 -0
  59. package/src/painlessTaskOptions.h +4 -0
  60. package/src/painlessmesh/base64.hpp +111 -0
  61. package/src/painlessmesh/buffer.hpp +229 -0
  62. package/src/painlessmesh/callback.hpp +91 -0
  63. package/src/painlessmesh/configuration.hpp +77 -0
  64. package/src/painlessmesh/connection.hpp +192 -0
  65. package/src/painlessmesh/layout.hpp +188 -0
  66. package/src/painlessmesh/logger.hpp +158 -0
  67. package/src/painlessmesh/memory.hpp +120 -0
  68. package/src/painlessmesh/mesh.hpp +560 -0
  69. package/src/painlessmesh/metrics.hpp +323 -0
  70. package/src/painlessmesh/ntp.hpp +263 -0
  71. package/src/painlessmesh/ota.hpp +553 -0
  72. package/src/painlessmesh/plugin.hpp +188 -0
  73. package/src/painlessmesh/protocol.hpp +813 -0
  74. package/src/painlessmesh/router.hpp +322 -0
  75. package/src/painlessmesh/tcp.hpp +71 -0
  76. package/src/painlessmesh/validation.hpp +239 -0
  77. package/src/plugin/performance.hpp +214 -0
  78. package/src/plugin/remote.hpp +64 -0
  79. package/src/scheduler.cpp +10 -0
  80. package/src/wifi.cpp +2 -0
@@ -0,0 +1,323 @@
1
+ #ifndef _PAINLESS_MESH_METRICS_HPP_
2
+ #define _PAINLESS_MESH_METRICS_HPP_
3
+
4
+ /**
5
+ * Performance metrics and monitoring utilities for painlessMesh
6
+ *
7
+ * This module provides comprehensive performance monitoring capabilities
8
+ * to help optimize mesh network performance and diagnose issues.
9
+ */
10
+
11
+ #include <algorithm>
12
+ #include <string>
13
+ #ifndef ARDUINO
14
+ #include <chrono>
15
+ #endif
16
+ #include "painlessmesh/configuration.hpp"
17
+
18
+ namespace painlessmesh {
19
+ namespace metrics {
20
+
21
+ /**
22
+ * High-resolution timer for performance measurements
23
+ */
24
+ class Timer {
25
+ public:
26
+ Timer() : start_time_(get_time()) {}
27
+
28
+ void reset() { start_time_ = get_time(); }
29
+
30
+ uint32_t elapsed_ms() const {
31
+ return static_cast<uint32_t>(get_time() - start_time_);
32
+ }
33
+
34
+ uint32_t elapsed_us() const {
35
+ #ifdef ESP32
36
+ return static_cast<uint32_t>((esp_timer_get_time() - start_time_us_) /
37
+ 1000);
38
+ #else
39
+ return elapsed_ms() * 1000; // Fallback to millisecond precision
40
+ #endif
41
+ }
42
+
43
+ private:
44
+ uint32_t get_time() const {
45
+ #ifdef ARDUINO
46
+ return millis();
47
+ #else
48
+ auto now = std::chrono::steady_clock::now();
49
+ auto duration = now.time_since_epoch();
50
+ return std::chrono::duration_cast<std::chrono::milliseconds>(duration)
51
+ .count();
52
+ #endif
53
+ }
54
+
55
+ uint32_t start_time_;
56
+ #ifdef ESP32
57
+ int64_t start_time_us_ = esp_timer_get_time();
58
+ #endif
59
+ };
60
+
61
+ /**
62
+ * Message statistics tracking
63
+ */
64
+ struct MessageStats {
65
+ uint32_t messages_sent = 0;
66
+ uint32_t messages_received = 0;
67
+ uint32_t messages_dropped = 0;
68
+ uint32_t messages_retransmitted = 0;
69
+ uint32_t bytes_sent = 0;
70
+ uint32_t bytes_received = 0;
71
+ uint32_t parse_errors = 0;
72
+ uint32_t validation_errors = 0;
73
+
74
+ // Latency tracking
75
+ uint32_t min_latency_ms = UINT32_MAX;
76
+ uint32_t max_latency_ms = 0;
77
+ uint32_t total_latency_ms = 0;
78
+ uint32_t latency_samples = 0;
79
+
80
+ void record_sent_message(size_t bytes) {
81
+ messages_sent++;
82
+ bytes_sent += bytes;
83
+ }
84
+
85
+ void record_received_message(size_t bytes) {
86
+ messages_received++;
87
+ bytes_received += bytes;
88
+ }
89
+
90
+ void record_dropped_message() { messages_dropped++; }
91
+
92
+ void record_retransmission() { messages_retransmitted++; }
93
+
94
+ void record_parse_error() { parse_errors++; }
95
+
96
+ void record_validation_error() { validation_errors++; }
97
+
98
+ void record_latency(uint32_t latency_ms) {
99
+ min_latency_ms = std::min(min_latency_ms, latency_ms);
100
+ max_latency_ms = std::max(max_latency_ms, latency_ms);
101
+ total_latency_ms += latency_ms;
102
+ latency_samples++;
103
+ }
104
+
105
+ uint32_t average_latency_ms() const {
106
+ return latency_samples > 0 ? total_latency_ms / latency_samples : 0;
107
+ }
108
+
109
+ double throughput_bps() const {
110
+ #ifdef ARDUINO
111
+ uint32_t uptime_s = millis() / 1000;
112
+ #else
113
+ // For non-Arduino builds, use a simpler approach or disable this feature
114
+ uint32_t uptime_s = 1; // Avoid division by zero
115
+ #endif
116
+ return uptime_s > 0 ? (bytes_sent + bytes_received) * 8.0 / uptime_s : 0.0;
117
+ }
118
+
119
+ double packet_loss_rate() const {
120
+ uint32_t total_attempted = messages_sent + messages_dropped;
121
+ return total_attempted > 0
122
+ ? static_cast<double>(messages_dropped) / total_attempted
123
+ : 0.0;
124
+ }
125
+
126
+ void reset() { *this = MessageStats{}; }
127
+ };
128
+
129
+ /**
130
+ * Memory usage tracking
131
+ */
132
+ struct MemoryStats {
133
+ uint32_t heap_free = 0;
134
+ uint32_t heap_max_alloc = 0;
135
+ uint32_t heap_min_free = UINT32_MAX;
136
+ uint32_t psram_free = 0;
137
+ uint32_t stack_high_water = 0;
138
+
139
+ void update() {
140
+ #ifdef ESP32
141
+ heap_free = ESP.getFreeHeap();
142
+ heap_max_alloc = ESP.getMaxAllocHeap();
143
+ heap_min_free = std::min(heap_min_free, heap_free);
144
+
145
+ #ifdef BOARD_HAS_PSRAM
146
+ psram_free = ESP.getFreePsram();
147
+ #endif
148
+
149
+ stack_high_water = uxTaskGetStackHighWaterMark(NULL);
150
+ #elif defined(ESP8266)
151
+ heap_free = ESP.getFreeHeap();
152
+ heap_max_alloc = ESP.getMaxFreeBlockSize();
153
+ heap_min_free = std::min(heap_min_free, heap_free);
154
+ #endif
155
+ }
156
+
157
+ bool is_memory_critical() const {
158
+ return heap_free < 10000; // Less than 10KB free is critical
159
+ }
160
+
161
+ bool is_memory_low() const {
162
+ return heap_free < 20000; // Less than 20KB free is low
163
+ }
164
+ };
165
+
166
+ /**
167
+ * Network topology metrics
168
+ */
169
+ struct TopologyStats {
170
+ uint32_t node_count = 0;
171
+ uint32_t connection_count = 0;
172
+ uint32_t max_hops = 0;
173
+ uint32_t connection_changes = 0;
174
+ uint32_t failed_connections = 0;
175
+
176
+ void record_topology_change(uint32_t nodes, uint32_t connections,
177
+ uint32_t hops) {
178
+ node_count = nodes;
179
+ connection_count = connections;
180
+ max_hops = hops;
181
+ connection_changes++;
182
+ }
183
+
184
+ void record_failed_connection() { failed_connections++; }
185
+
186
+ double connection_stability() const {
187
+ return connection_changes > 0
188
+ ? 1.0 - static_cast<double>(failed_connections) /
189
+ connection_changes
190
+ : 1.0;
191
+ }
192
+ };
193
+
194
+ /**
195
+ * Comprehensive metrics collector
196
+ */
197
+ class MetricsCollector {
198
+ public:
199
+ MetricsCollector() : start_time_(get_current_time()) {}
200
+
201
+ MessageStats& message_stats() { return message_stats_; }
202
+ MemoryStats& memory_stats() { return memory_stats_; }
203
+ TopologyStats& topology_stats() { return topology_stats_; }
204
+
205
+ const MessageStats& message_stats() const { return message_stats_; }
206
+ const MemoryStats& memory_stats() const { return memory_stats_; }
207
+ const TopologyStats& topology_stats() const { return topology_stats_; }
208
+
209
+ /**
210
+ * Update all metrics (call periodically)
211
+ */
212
+ void update() {
213
+ memory_stats_.update();
214
+ last_update_ = get_current_time();
215
+ }
216
+
217
+ /**
218
+ * Get uptime in seconds
219
+ */
220
+ uint32_t uptime_seconds() const {
221
+ return (get_current_time() - start_time_) / 1000;
222
+ }
223
+
224
+ /**
225
+ * Generate JSON status report
226
+ */
227
+ TSTRING generate_status_json() const {
228
+ TSTRING json = "{";
229
+ json += "\"uptime\":";
230
+ json += std::to_string(uptime_seconds());
231
+ json += ",";
232
+ json += "\"messages\":{";
233
+ json += "\"sent\":";
234
+ json += std::to_string(message_stats_.messages_sent);
235
+ json += ",";
236
+ json += "\"received\":";
237
+ json += std::to_string(message_stats_.messages_received);
238
+ json += ",";
239
+ json += "\"dropped\":";
240
+ json += std::to_string(message_stats_.messages_dropped);
241
+ json += ",";
242
+ json += "\"avg_latency\":";
243
+ json += std::to_string(message_stats_.average_latency_ms());
244
+ json += ",";
245
+ json += "\"throughput\":";
246
+ json += std::to_string(message_stats_.throughput_bps());
247
+ json += ",";
248
+ json += "\"packet_loss\":";
249
+ json += std::to_string(message_stats_.packet_loss_rate());
250
+ json += "},";
251
+ json += "\"memory\":{";
252
+ json += "\"heap_free\":";
253
+ json += std::to_string(memory_stats_.heap_free);
254
+ json += ",";
255
+ json += "\"heap_min\":";
256
+ json += std::to_string(memory_stats_.heap_min_free);
257
+ json += ",";
258
+ json += "\"critical\":";
259
+ json += (memory_stats_.is_memory_critical() ? "true" : "false");
260
+ json += "},";
261
+ json += "\"topology\":{";
262
+ json += "\"nodes\":";
263
+ json += std::to_string(topology_stats_.node_count);
264
+ json += ",";
265
+ json += "\"connections\":";
266
+ json += std::to_string(topology_stats_.connection_count);
267
+ json += ",";
268
+ json += "\"max_hops\":";
269
+ json += std::to_string(topology_stats_.max_hops);
270
+ json += ",";
271
+ json += "\"stability\":";
272
+ json += std::to_string(topology_stats_.connection_stability());
273
+ json += "}";
274
+ json += "}";
275
+ return json;
276
+ }
277
+
278
+ /**
279
+ * Reset all metrics
280
+ */
281
+ void reset() {
282
+ message_stats_.reset();
283
+ topology_stats_ = TopologyStats{};
284
+ start_time_ = get_current_time();
285
+ }
286
+
287
+ /**
288
+ * Check if metrics indicate performance issues
289
+ */
290
+ bool has_performance_issues() const {
291
+ return memory_stats_.is_memory_critical() ||
292
+ message_stats_.packet_loss_rate() > 0.1 || // > 10% packet loss
293
+ topology_stats_.connection_stability() < 0.8; // < 80% stability
294
+ }
295
+
296
+ private:
297
+ uint32_t get_current_time() const {
298
+ #ifdef ARDUINO
299
+ return millis();
300
+ #else
301
+ auto now = std::chrono::steady_clock::now();
302
+ auto duration = now.time_since_epoch();
303
+ return std::chrono::duration_cast<std::chrono::milliseconds>(duration)
304
+ .count();
305
+ #endif
306
+ }
307
+
308
+ MessageStats message_stats_;
309
+ MemoryStats memory_stats_;
310
+ TopologyStats topology_stats_;
311
+ uint32_t start_time_;
312
+ uint32_t last_update_ = 0;
313
+ };
314
+
315
+ // Global metrics instance (optional, can be disabled)
316
+ #ifdef PAINLESS_MESH_ENABLE_METRICS
317
+ extern MetricsCollector global_metrics;
318
+ #endif
319
+
320
+ } // namespace metrics
321
+ } // namespace painlessmesh
322
+
323
+ #endif // _PAINLESS_MESH_METRICS_HPP_
@@ -0,0 +1,263 @@
1
+ #ifndef _PAINLESS_MESH_NTP_HPP_
2
+ #define _PAINLESS_MESH_NTP_HPP_
3
+
4
+ #ifndef TIME_SYNC_INTERVAL
5
+ #define TIME_SYNC_INTERVAL 1 * TASK_MINUTE // Time resync period
6
+ #endif
7
+
8
+ #ifndef TIME_SYNC_ACCURACY
9
+ #define TIME_SYNC_ACCURACY 5000 // Minimum time sync accuracy (5ms
10
+ #endif
11
+
12
+ #ifndef MIN_LARGE_OFFSET_STEP
13
+ #define MIN_LARGE_OFFSET_STEP 500 // Minimum offset size before softening
14
+ #endif
15
+
16
+ #ifndef MAX_CPU_TRIP_RATIO
17
+ #define MAX_CPU_TRIP_RATIO \
18
+ 85 // Maximum ratio between remote cpu time and trip time for NTP calc to be
19
+ // reasonable
20
+ #endif
21
+
22
+ #include "Arduino.h"
23
+
24
+ #include "painlessmesh/callback.hpp"
25
+ #include "painlessmesh/logger.hpp"
26
+ #include "painlessmesh/router.hpp"
27
+
28
+ extern painlessmesh::logger::LogClass Log;
29
+
30
+ namespace painlessmesh {
31
+ namespace ntp {
32
+
33
+ class MeshTime {
34
+ public:
35
+ /** Returns the mesh time in microsecond precision.
36
+ *
37
+ * Time rolls over every 71 minutes.
38
+ *
39
+ * Nodes try to keep a common time base synchronizing to each other using [an
40
+ * SNTP based
41
+ * protocol](https://gitlab.com/painlessMesh/painlessMesh/wikis/mesh-protocol#time-sync)
42
+ */
43
+ uint32_t getNodeTime() { return micros() + timeOffset; }
44
+
45
+ protected:
46
+ uint32_t timeOffset = 0;
47
+ };
48
+
49
+ /**
50
+ * Calculate the offset of the local clock using the ntp algorithm
51
+ *
52
+ * See ntp overview for more information
53
+ */
54
+ inline int32_t clockOffset(uint32_t time0, uint32_t time1, uint32_t time2,
55
+ uint32_t time3) {
56
+ uint32_t offset =
57
+ ((int32_t)(time1 - time0) / 2) + ((int32_t)(time2 - time3) / 2);
58
+
59
+ // Take small steps to avoid over correction
60
+ int32_t signedOffset = (int32_t)offset;
61
+ if (abs(signedOffset) < MIN_LARGE_OFFSET_STEP && abs(signedOffset) > 4)
62
+ signedOffset = signedOffset / 4;
63
+ // Discard outliers with excessive trip to cpu ratios
64
+ if ((time3 - time0) > (time2 - time1) * MAX_CPU_TRIP_RATIO) signedOffset = 0;
65
+ return signedOffset;
66
+ }
67
+
68
+ /**
69
+ * Calculate the time it took to get reply from other node
70
+ *
71
+ * See ntp algorithm for more information
72
+ */
73
+ inline int32_t tripDelay(uint32_t time0, uint32_t time1, uint32_t time2,
74
+ uint32_t time3) {
75
+ return ((time3 - time0) - (time2 - time1)) / 2;
76
+ }
77
+
78
+ inline bool adopt(protocol::NodeTree mesh, protocol::NodeTree connection) {
79
+ auto mySubCount =
80
+ layout::size(layout::excludeRoute(std::move(mesh), connection.nodeId));
81
+ auto remoteSubCount = layout::size(connection);
82
+ if (mySubCount > remoteSubCount) return false;
83
+ if (mySubCount == remoteSubCount) {
84
+ if (connection.nodeId == 0)
85
+ Log(logger::ERROR, "Adopt called on uninitialized connection\n");
86
+ // TODO: there is a change here that a middle node also lower is than the
87
+ // two others and will start switching between both. Maybe should do it
88
+ // randomly instead?
89
+ return mesh.nodeId < connection.nodeId;
90
+ }
91
+ return true;
92
+ }
93
+
94
+ template <class T>
95
+ void initTimeSync(protocol::NodeTree mesh, std::shared_ptr<T> connection,
96
+ uint32_t nodeTime) {
97
+ using namespace painlessmesh::logger;
98
+ painlessmesh::protocol::TimeSync timeSync;
99
+ if (adopt(mesh, (*connection))) {
100
+ timeSync = painlessmesh::protocol::TimeSync(mesh.nodeId, connection->nodeId,
101
+ nodeTime);
102
+ Log(S_TIME, "initTimeSync(): Requesting time from %u\n",
103
+ connection->nodeId);
104
+ } else {
105
+ timeSync =
106
+ painlessmesh::protocol::TimeSync(mesh.nodeId, connection->nodeId);
107
+ Log(S_TIME, "initTimeSync(): Requesting %u to adopt our time\n",
108
+ connection->nodeId);
109
+ }
110
+
111
+ router::send<protocol::TimeSync, T>(timeSync, connection, true);
112
+ }
113
+
114
+ template <class T, class U>
115
+ void handleTimeSync(T& mesh, painlessmesh::protocol::TimeSync timeSync,
116
+ std::shared_ptr<U> conn, uint32_t receivedAt) {
117
+ switch (timeSync.msg.type) {
118
+ case (painlessmesh::protocol::TIME_SYNC_ERROR):
119
+ Log(logger::ERROR,
120
+ "handleTimeSync(): Received time sync error. Restarting time "
121
+ "sync.\n");
122
+ conn->timeSyncTask.forceNextIteration();
123
+ break;
124
+ case (painlessmesh::protocol::TIME_SYNC_REQUEST): // Other party request me
125
+ // to ask it for time
126
+ Log(logger::S_TIME,
127
+ "handleTimeSync(): Received requesto to start TimeSync with "
128
+ "node: %u\n",
129
+ conn->nodeId);
130
+ timeSync.reply(mesh.getNodeTime());
131
+ router::send<painlessmesh::protocol::TimeSync>(timeSync, conn, true);
132
+ break;
133
+
134
+ case (painlessmesh::protocol::TIME_REQUEST):
135
+ timeSync.reply(receivedAt, mesh.getNodeTime());
136
+ router::send<painlessmesh::protocol::TimeSync>(timeSync, conn, true);
137
+
138
+ Log(logger::S_TIME,
139
+ "handleTimeSync(): timeSyncStatus with %u completed\n", conn->nodeId);
140
+
141
+ // After response is sent I assume sync is completed
142
+ conn->timeSyncTask.delay(TIME_SYNC_INTERVAL);
143
+ break;
144
+
145
+ case (painlessmesh::protocol::TIME_REPLY): {
146
+ Log(logger::S_TIME,
147
+ "handleTimeSync(): %u adopting TIME_RESPONSE from %u\n", mesh.nodeId,
148
+ conn->nodeId);
149
+ int32_t offset = painlessmesh::ntp::clockOffset(
150
+ timeSync.msg.t0, timeSync.msg.t1, timeSync.msg.t2, receivedAt);
151
+ mesh.timeOffset += offset; // Accumulate offset
152
+
153
+ // flag all connections for re-timeSync
154
+ if (mesh.nodeTimeAdjustedCallback) {
155
+ mesh.nodeTimeAdjustedCallback(offset);
156
+ }
157
+
158
+ if ((offset < TIME_SYNC_ACCURACY) && (offset > -TIME_SYNC_ACCURACY) &&
159
+ (offset != 0)) {
160
+ // mark complete only if offset was less than 10 ms
161
+ conn->timeSyncTask.delay(TIME_SYNC_INTERVAL);
162
+ Log(logger::S_TIME,
163
+ "handleTimeSync(): timeSyncStatus with %u completed\n",
164
+ conn->nodeId);
165
+
166
+ // Time has changed, update other nodes
167
+ for (auto&& connection : mesh.subs) {
168
+ if (connection->nodeId != conn->nodeId) { // exclude this connection
169
+ connection->timeSyncTask.forceNextIteration();
170
+ Log(logger::S_TIME,
171
+ "handleTimeSync(): timeSyncStatus with %u brought forward\n",
172
+ connection->nodeId);
173
+ }
174
+ }
175
+ } else {
176
+ // Iterate sync procedure if accuracy was not enough
177
+ conn->timeSyncTask.delay(200 * TASK_MILLISECOND); // Small delay
178
+ Log(logger::S_TIME,
179
+ "handleTimeSync(): timeSyncStatus with %u needs further tries\n",
180
+ conn->nodeId);
181
+ }
182
+ break;
183
+ }
184
+ default:
185
+ Log(logger::ERROR, "handleTimeSync(): unkown type %u, %u\n",
186
+ timeSync.msg.type, painlessmesh::protocol::TIME_SYNC_REQUEST);
187
+ break;
188
+ }
189
+ Log(logger::S_TIME, "handleTimeSync(): ----------------------------------\n");
190
+ }
191
+
192
+ template <class T, class U>
193
+ void handleTimeDelay(T& mesh, painlessmesh::protocol::TimeDelay timeDelay,
194
+ std::shared_ptr<U> conn, uint32_t receivedAt) {
195
+ Log(logger::S_TIME, "handleTimeDelay(): from %u in timestamp\n",
196
+ timeDelay.from);
197
+
198
+ switch (timeDelay.msg.type) {
199
+ case (painlessmesh::protocol::TIME_SYNC_ERROR):
200
+ Log(logger::ERROR,
201
+ "handleTimeDelay(): Error in requesting time delay. Please try "
202
+ "again.\n");
203
+ break;
204
+
205
+ case (painlessmesh::protocol::TIME_REQUEST):
206
+ // conn->timeSyncStatus == IN_PROGRESS;
207
+ Log(logger::S_TIME, "handleTimeDelay(): TIME REQUEST received.\n");
208
+
209
+ // Build time response
210
+ timeDelay.reply(receivedAt, mesh.getNodeTime());
211
+ router::send<protocol::TimeDelay, U>(timeDelay, conn);
212
+ break;
213
+
214
+ case (painlessmesh::protocol::TIME_REPLY): {
215
+ Log(logger::S_TIME, "handleTimeDelay(): TIME RESPONSE received.\n");
216
+ int32_t delay = painlessmesh::ntp::tripDelay(
217
+ timeDelay.msg.t0, timeDelay.msg.t1, timeDelay.msg.t2, receivedAt);
218
+ Log(logger::S_TIME, "handleTimeDelay(): Delay is %d\n", delay);
219
+
220
+ // conn->timeSyncStatus == COMPLETE;
221
+
222
+ if (mesh.nodeDelayReceivedCallback)
223
+ mesh.nodeDelayReceivedCallback(timeDelay.from, delay);
224
+ } break;
225
+
226
+ default:
227
+ Log(logger::ERROR,
228
+ "handleTimeDelay(): Unknown timeSyncMessageType received. Ignoring "
229
+ "for now.\n");
230
+ }
231
+
232
+ Log(logger::S_TIME, "handleTimeSync(): ----------------------------------\n");
233
+ }
234
+
235
+ template <class T, typename U>
236
+ callback::MeshPackageCallbackList<U> addPackageCallback(
237
+ callback::MeshPackageCallbackList<U>&& callbackList, T& mesh) {
238
+ // TimeSync
239
+ callbackList.onPackage(
240
+ protocol::TIME_SYNC,
241
+ [&mesh](protocol::Variant& variant, std::shared_ptr<U> connection,
242
+ uint32_t receivedAt) {
243
+ auto timeSync = variant.to<protocol::TimeSync>();
244
+ handleTimeSync<T, U>(mesh, timeSync, connection, receivedAt);
245
+ return false;
246
+ });
247
+
248
+ // TimeDelay
249
+ callbackList.onPackage(
250
+ protocol::TIME_DELAY,
251
+ [&mesh](protocol::Variant& variant, std::shared_ptr<U> connection,
252
+ uint32_t receivedAt) {
253
+ auto timeDelay = variant.to<protocol::TimeDelay>();
254
+ handleTimeDelay<T, U>(mesh, timeDelay, connection, receivedAt);
255
+ return false;
256
+ });
257
+
258
+ return callbackList;
259
+ }
260
+
261
+ } // namespace ntp
262
+ } // namespace painlessmesh
263
+ #endif