@alteriom/painlessmesh 1.6.1 → 1.7.2
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.
- package/CHANGELOG.md +380 -143
- package/LICENSE +674 -674
- package/README.md +477 -434
- package/RELEASE_GUIDE.md +504 -418
- package/docs/DOCUMENTATION_MIGRATION_PLAN.md +175 -175
- package/docs/IMPLEMENTATION_PLAN_MESH_TOPOLOGY.md +1062 -0
- package/docs/MESH_TOPOLOGY_GUIDE.md +992 -0
- package/docs/MESH_TOPOLOGY_PROGRESS.md +422 -0
- package/docs/MQTT_BRIDGE_COMMANDS.md +894 -0
- package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +324 -0
- package/docs/MQTT_COMMAND_SCHEMA_PROPOSAL.md +576 -0
- package/docs/MQTT_SCHEMA_COMPLIANCE.md +285 -0
- package/docs/MQTT_SCHEMA_PROPOSALS.md +446 -0
- package/docs/MQTT_SCHEMA_REVIEW.md +690 -0
- package/docs/OTA_COMMANDS_REFERENCE.md +554 -0
- package/docs/PHASE1_GUIDE.md +349 -0
- package/docs/PHASE2_GUIDE.md +543 -0
- package/docs/README.md +77 -70
- package/docs/SCHEMA_VALIDATION_CHECKLIST.md +222 -0
- package/docs/alteriom/overview.md +507 -507
- package/docs/api/core-api.md +606 -606
- package/docs/architecture/mesh-architecture.md +378 -378
- package/docs/architecture/plugin-system.md +516 -516
- package/docs/getting-started/first-mesh.md +409 -409
- package/docs/getting-started/installation.md +274 -274
- package/docs/getting-started/quickstart.md +157 -157
- package/docs/improvements/FEATURE_PROPOSALS.md +337 -0
- package/docs/improvements/PHASE1_IMPLEMENTATION.md +325 -0
- package/docs/improvements/PHASE2_IMPLEMENTATION.md +567 -0
- package/docs/improvements/README.md +86 -68
- package/docs/improvements/ota-and-status-enhancements.md +911 -0
- package/docs/improvements/ota-status-architecture-diagrams.md +658 -0
- package/docs/improvements/ota-status-quick-reference.md +284 -0
- package/docs/platformio-publishing.md +255 -0
- package/docs/platformio-setup-summary.md +121 -0
- package/docs/troubleshooting/common-issues.md +520 -520
- package/docs/troubleshooting/faq.md +472 -472
- package/docs/tutorials/basic-examples.md +717 -717
- package/docs/wiki/API-Reference.md +245 -245
- package/docs/wiki/Complete-Documentation.md +122 -122
- package/examples/alteriom/README.md +139 -81
- package/examples/alteriom/alteriom.ino +186 -185
- package/examples/alteriom/alteriom_sensor_package.hpp +240 -127
- package/examples/alteriom/platformio.ini +24 -24
- package/examples/alteriomImproved/alteriom_sensor_package.hpp +224 -0
- package/examples/{alteriom → alteriomImproved}/improved_sensor_node.ino +245 -245
- package/examples/alteriomImproved/platformio.ini +25 -0
- package/examples/alteriomPhase1/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomPhase1/phase1_features.ino +242 -0
- package/examples/alteriomPhase1/platformio.ini +25 -0
- package/examples/alteriomPhase2/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomPhase2/phase2_features.ino +186 -0
- package/examples/alteriomPhase2/platformio.ini +25 -0
- package/examples/{alteriom → alteriomSensorNode}/alteriom_sensor_node.ino +183 -183
- package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomSensorNode/platformio.ini +25 -0
- package/examples/basic/basic.ino +66 -66
- package/examples/basic/platformio.ini +25 -25
- package/examples/bridge/bridge.ino +51 -51
- package/examples/bridge/mesh_event_publisher.hpp +253 -0
- package/examples/bridge/mesh_topology_reporter.hpp +303 -0
- package/examples/bridge/mqtt_command_bridge.hpp +459 -0
- package/examples/bridge/mqtt_status_bridge.hpp +519 -0
- package/examples/bridge/platformio.ini +25 -25
- package/examples/echoNode/echoNode.ino +33 -33
- package/examples/echoNode/platformio.ini +25 -25
- package/examples/logClient/logClient.ino +109 -109
- package/examples/logClient/platformio.ini +25 -25
- package/examples/logServer/logServer.ino +81 -81
- package/examples/logServer/platformio.ini +25 -25
- package/examples/meshCommandNode/alteriom_sensor_package.hpp +235 -0
- package/examples/meshCommandNode/meshCommandNode.ino +263 -0
- package/examples/meshCommandNode/platformio.ini +25 -0
- package/examples/mqttBridge/mqttBridge.ino +118 -118
- package/examples/mqttBridge/platformio.ini +26 -26
- package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +235 -0
- package/examples/mqttCommandBridge/mesh_event_publisher.hpp +253 -0
- package/examples/mqttCommandBridge/mesh_topology_reporter.hpp +303 -0
- package/examples/mqttCommandBridge/mqttCommandBridge.ino +252 -0
- package/examples/mqttCommandBridge/mqtt_command_bridge.hpp +459 -0
- package/examples/mqttCommandBridge/platformio.ini +26 -0
- package/examples/mqttStatusBridge/mqttStatusBridge.ino +216 -0
- package/examples/mqttStatusBridge/mqtt_status_bridge.hpp +522 -0
- package/examples/mqttStatusBridge/platformio.ini +26 -0
- package/examples/mqttTopologyTest/README.md +467 -0
- package/examples/mqttTopologyTest/mqttTopologyTest.ino +748 -0
- package/examples/mqttTopologyTest/platformio.ini +26 -0
- package/examples/namedMesh/namedMesh.ino +97 -97
- package/examples/namedMesh/platformio.ini +25 -25
- package/examples/otaReceiver/otaReceiver.ino +79 -79
- package/examples/otaReceiver/platformio.ini +25 -25
- package/examples/otaSender/otaSender.ino +160 -151
- package/examples/otaSender/platformio.ini +25 -25
- package/examples/startHere/platformio.ini +25 -25
- package/examples/startHere/startHere.ino +159 -159
- package/examples/webServer/platformio.ini +27 -27
- package/examples/webServer/webServer.ino +89 -89
- package/keywords.txt +48 -48
- package/library.json +55 -34
- package/library.properties +10 -10
- package/package.json +86 -78
- package/src/AlteriomPainlessMesh.h +97 -97
- package/src/arduino/wifi.hpp +365 -365
- package/src/boost/asynctcp.hpp +279 -279
- package/src/painlessMesh.h +70 -70
- package/src/painlessMeshSTA.cpp +236 -236
- package/src/painlessMeshSTA.h +58 -58
- package/src/painlessTaskOptions.h +4 -4
- package/src/painlessmesh/base64.hpp +111 -111
- package/src/painlessmesh/buffer.hpp +229 -229
- package/src/painlessmesh/callback.hpp +91 -91
- package/src/painlessmesh/configuration.hpp +77 -77
- package/src/painlessmesh/connection.hpp +192 -192
- package/src/painlessmesh/layout.hpp +188 -188
- package/src/painlessmesh/logger.hpp +158 -158
- package/src/painlessmesh/memory.hpp +119 -119
- package/src/painlessmesh/mesh.hpp +761 -560
- package/src/painlessmesh/metrics.hpp +322 -322
- package/src/painlessmesh/ntp.hpp +263 -263
- package/src/painlessmesh/ota.hpp +582 -553
- package/src/painlessmesh/plugin.hpp +188 -188
- package/src/painlessmesh/protocol.hpp +813 -813
- package/src/painlessmesh/router.hpp +322 -322
- package/src/painlessmesh/tcp.hpp +71 -71
- package/src/painlessmesh/validation.hpp +238 -238
- package/src/plugin/performance.hpp +214 -214
- package/src/plugin/remote.hpp +64 -64
- package/src/scheduler.cpp +10 -10
- package/src/wifi.cpp +2 -2
|
@@ -1,322 +1,322 @@
|
|
|
1
|
-
#ifndef _PAINLESS_MESH_ROUTER_HPP_
|
|
2
|
-
#define _PAINLESS_MESH_ROUTER_HPP_
|
|
3
|
-
|
|
4
|
-
#include <algorithm>
|
|
5
|
-
#include <memory>
|
|
6
|
-
|
|
7
|
-
#include "painlessmesh/callback.hpp"
|
|
8
|
-
#include "painlessmesh/layout.hpp"
|
|
9
|
-
#include "painlessmesh/logger.hpp"
|
|
10
|
-
#include "painlessmesh/protocol.hpp"
|
|
11
|
-
|
|
12
|
-
extern painlessmesh::logger::LogClass Log;
|
|
13
|
-
|
|
14
|
-
namespace painlessmesh {
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Helper functions to route messages
|
|
18
|
-
*/
|
|
19
|
-
namespace router {
|
|
20
|
-
template <class T>
|
|
21
|
-
std::shared_ptr<T> findRoute(layout::Layout<T> tree,
|
|
22
|
-
std::function<bool(std::shared_ptr<T>)> func) {
|
|
23
|
-
auto route = std::find_if(tree.subs.begin(), tree.subs.end(), func);
|
|
24
|
-
if (route == tree.subs.end()) return NULL;
|
|
25
|
-
return (*route);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
template <class T>
|
|
29
|
-
std::shared_ptr<T> findRoute(layout::Layout<T> tree, uint32_t nodeId) {
|
|
30
|
-
return findRoute<T>(tree, [nodeId](std::shared_ptr<T> s) {
|
|
31
|
-
return layout::contains((*s), nodeId);
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
template <class T, class U>
|
|
36
|
-
bool send(T& package, std::shared_ptr<U> conn, bool priority = false) {
|
|
37
|
-
painlessmesh::protocol::Variant variant(package);
|
|
38
|
-
TSTRING msg;
|
|
39
|
-
variant.printTo(msg);
|
|
40
|
-
return conn->addMessage(msg, priority);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
template <class T, class U>
|
|
44
|
-
bool send(T&& package, std::shared_ptr<U> conn, bool priority = false) {
|
|
45
|
-
painlessmesh::protocol::Variant variant(package);
|
|
46
|
-
TSTRING msg;
|
|
47
|
-
variant.printTo(msg);
|
|
48
|
-
return conn->addMessage(msg, priority);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
template <class U>
|
|
52
|
-
bool send(protocol::Variant& variant, std::shared_ptr<U> conn,
|
|
53
|
-
bool priority = false) {
|
|
54
|
-
TSTRING msg;
|
|
55
|
-
variant.printTo(msg);
|
|
56
|
-
return conn->addMessage(msg, priority);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
template <class U>
|
|
60
|
-
bool send(protocol::Variant&& variant, std::shared_ptr<U> conn,
|
|
61
|
-
bool priority = false) {
|
|
62
|
-
TSTRING msg;
|
|
63
|
-
variant.printTo(msg);
|
|
64
|
-
return conn->addMessage(msg, priority);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
template <class T, class U>
|
|
68
|
-
bool send(T& package, layout::Layout<U> layout) {
|
|
69
|
-
painlessmesh::protocol::Variant variant(package);
|
|
70
|
-
TSTRING msg;
|
|
71
|
-
variant.printTo(msg);
|
|
72
|
-
auto conn = findRoute<U>(layout, variant.dest());
|
|
73
|
-
if (conn) return conn->addMessage(msg);
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
template <class U>
|
|
78
|
-
bool send(protocol::Variant& variant, layout::Layout<U> layout) {
|
|
79
|
-
TSTRING msg;
|
|
80
|
-
variant.printTo(msg);
|
|
81
|
-
auto conn = findRoute<U>(layout, variant.dest());
|
|
82
|
-
if (conn) return conn->addMessage(msg);
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
template <class T, class U>
|
|
87
|
-
bool send(T&& package, layout::Layout<U> layout) {
|
|
88
|
-
painlessmesh::protocol::Variant variant(package);
|
|
89
|
-
TSTRING msg;
|
|
90
|
-
variant.printTo(msg);
|
|
91
|
-
auto conn = findRoute<U>(layout, variant.dest());
|
|
92
|
-
if (conn) return conn->addMessage(msg);
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
template <class U>
|
|
97
|
-
bool send(protocol::Variant&& variant, layout::Layout<U> layout) {
|
|
98
|
-
TSTRING msg;
|
|
99
|
-
variant.printTo(msg);
|
|
100
|
-
auto conn = findRoute<U>(layout, variant.dest());
|
|
101
|
-
if (conn) return conn->addMessage(msg);
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
template <class T, class U>
|
|
106
|
-
size_t broadcast(T& package, layout::Layout<U> layout, uint32_t exclude) {
|
|
107
|
-
painlessmesh::protocol::Variant variant(package);
|
|
108
|
-
TSTRING msg;
|
|
109
|
-
variant.printTo(msg);
|
|
110
|
-
size_t i = 0;
|
|
111
|
-
for (auto&& conn : layout.subs) {
|
|
112
|
-
if (conn->nodeId != 0 && conn->nodeId != exclude) {
|
|
113
|
-
auto sent = conn->addMessage(msg);
|
|
114
|
-
if (sent) ++i;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return i;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
template <class T, class U>
|
|
121
|
-
size_t broadcast(T&& package, layout::Layout<U> layout, uint32_t exclude) {
|
|
122
|
-
painlessmesh::protocol::Variant variant(package);
|
|
123
|
-
TSTRING msg;
|
|
124
|
-
variant.printTo(msg);
|
|
125
|
-
size_t i = 0;
|
|
126
|
-
for (auto&& conn : layout.subs) {
|
|
127
|
-
if (conn->nodeId != 0 && conn->nodeId != exclude) {
|
|
128
|
-
auto sent = conn->addMessage(msg);
|
|
129
|
-
if (sent) ++i;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return i;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
template <class T>
|
|
136
|
-
size_t broadcast(protocol::Variant& variant, layout::Layout<T> layout,
|
|
137
|
-
uint32_t exclude) {
|
|
138
|
-
TSTRING msg;
|
|
139
|
-
variant.printTo(msg);
|
|
140
|
-
size_t i = 0;
|
|
141
|
-
for (auto&& conn : layout.subs) {
|
|
142
|
-
if (conn->nodeId != 0 && conn->nodeId != exclude) {
|
|
143
|
-
auto sent = conn->addMessage(msg);
|
|
144
|
-
if (sent) ++i;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return i;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
template <class T>
|
|
151
|
-
size_t broadcast(protocol::Variant&& variant, layout::Layout<T> layout,
|
|
152
|
-
uint32_t exclude) {
|
|
153
|
-
TSTRING msg;
|
|
154
|
-
variant.printTo(msg);
|
|
155
|
-
size_t i = 0;
|
|
156
|
-
for (auto&& conn : layout.subs) {
|
|
157
|
-
if (conn->nodeId != 0 && conn->nodeId != exclude) {
|
|
158
|
-
auto sent = conn->addMessage(msg);
|
|
159
|
-
if (sent) ++i;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return i;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
template <class T>
|
|
166
|
-
void routePackage(layout::Layout<T> layout, std::shared_ptr<T> connection,
|
|
167
|
-
const TSTRING& pkg, callback::MeshPackageCallbackList<T> cbl,
|
|
168
|
-
uint32_t receivedAt) {
|
|
169
|
-
using namespace logger;
|
|
170
|
-
Log(COMMUNICATION, "routePackage(): Recvd from %u: %s\n", connection->nodeId,
|
|
171
|
-
pkg.c_str());
|
|
172
|
-
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
173
|
-
protocol::Variant variant(pkg);
|
|
174
|
-
if (variant.error) {
|
|
175
|
-
Log(ERROR,
|
|
176
|
-
"routePackage(): parsing failed. err=%u, total_length=%d, data=%s<--\n",
|
|
177
|
-
variant.error, pkg.length(), pkg.c_str());
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (variant.routing() == SINGLE && variant.dest() != layout.getNodeId()) {
|
|
182
|
-
// Send on without further processing
|
|
183
|
-
send<T>(variant, layout);
|
|
184
|
-
return;
|
|
185
|
-
} else if (variant.routing() == BROADCAST) {
|
|
186
|
-
broadcast<T>(variant, layout, connection->nodeId);
|
|
187
|
-
}
|
|
188
|
-
auto calls = cbl.execute(variant.type(), variant, connection, receivedAt);
|
|
189
|
-
if (calls == 0)
|
|
190
|
-
Log(DEBUG, "routePackage(): No callbacks executed; %u, %s\n",
|
|
191
|
-
variant.type(), pkg.c_str());
|
|
192
|
-
#else
|
|
193
|
-
static size_t baseCapacity = 512;
|
|
194
|
-
// Using a ptr so we can overwrite it if we need to grow capacity.
|
|
195
|
-
// Bug in copy constructor with grown capacity can cause segmentation fault
|
|
196
|
-
auto variant =
|
|
197
|
-
std::make_shared<protocol::Variant>(pkg, pkg.length() + baseCapacity);
|
|
198
|
-
while (variant->error == DeserializationError::NoMemory &&
|
|
199
|
-
baseCapacity <= 20480) {
|
|
200
|
-
// Not enough memory, adapt scaling (variant::capacityScaling) and log the
|
|
201
|
-
// new value
|
|
202
|
-
Log(DEBUG,
|
|
203
|
-
"routePackage(): parsing failed. err=%u, increasing capacity: %u\n",
|
|
204
|
-
variant->error, baseCapacity);
|
|
205
|
-
baseCapacity += 256;
|
|
206
|
-
variant =
|
|
207
|
-
std::make_shared<protocol::Variant>(pkg, pkg.length() + baseCapacity);
|
|
208
|
-
}
|
|
209
|
-
if (variant->error) {
|
|
210
|
-
Log(ERROR,
|
|
211
|
-
"routePackage(): parsing failed. err=%u, total_length=%d, data=%s<--\n",
|
|
212
|
-
variant->error, pkg.length(), pkg.c_str());
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (variant->routing() == SINGLE && variant->dest() != layout.getNodeId()) {
|
|
217
|
-
// Send on without further processing
|
|
218
|
-
send<T>((*variant), layout);
|
|
219
|
-
return;
|
|
220
|
-
} else if (variant->routing() == BROADCAST) {
|
|
221
|
-
broadcast<T>((*variant), layout, connection->nodeId);
|
|
222
|
-
}
|
|
223
|
-
auto calls = cbl.execute(variant->type(), (*variant), connection, receivedAt);
|
|
224
|
-
if (calls == 0)
|
|
225
|
-
Log(DEBUG, "routePackage(): No callbacks executed; %u, %s\n",
|
|
226
|
-
variant->type(), pkg.c_str());
|
|
227
|
-
#endif
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
template <class T, class U>
|
|
231
|
-
void handleNodeSync(T& mesh, protocol::NodeTree newTree,
|
|
232
|
-
std::shared_ptr<U> conn) {
|
|
233
|
-
Log(logger::SYNC, "handleNodeSync(): with %u\n", conn->nodeId);
|
|
234
|
-
|
|
235
|
-
if (!conn->validSubs(newTree)) {
|
|
236
|
-
Log(logger::SYNC, "handleNodeSync(): invalid new connection\n");
|
|
237
|
-
Log.remote("Invalid connection to %u\n", conn->nodeId);
|
|
238
|
-
conn->close();
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (conn->newConnection) {
|
|
243
|
-
auto oldConnection = router::findRoute<U>(mesh, newTree.nodeId);
|
|
244
|
-
if (oldConnection) {
|
|
245
|
-
Log(logger::SYNC,
|
|
246
|
-
"handleNodeSync(): already connected to %u. Closing the new "
|
|
247
|
-
"connection \n",
|
|
248
|
-
newTree.nodeId);
|
|
249
|
-
Log.remote("Already connected to %u\n", newTree.nodeId);
|
|
250
|
-
conn->close();
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
auto remoteNodeId = newTree.nodeId;
|
|
254
|
-
mesh.addTask([&mesh, remoteNodeId]() {
|
|
255
|
-
Log(logger::CONNECTION, "newConnectionTask():\n");
|
|
256
|
-
Log(logger::CONNECTION, "newConnectionTask(): adding %u now= %u\n",
|
|
257
|
-
remoteNodeId, mesh.getNodeTime());
|
|
258
|
-
mesh.newConnectionCallbacks.execute(remoteNodeId);
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
// Initially interval is every 10 seconds,
|
|
262
|
-
// this will slow down to TIME_SYNC_INTERVAL
|
|
263
|
-
// after first succesfull sync
|
|
264
|
-
// TODO move it to a new connection callback and use initTimeSync from
|
|
265
|
-
// ntp.hpp
|
|
266
|
-
conn->timeSyncTask.set(10 * TASK_SECOND, TASK_FOREVER, [conn, &mesh]() {
|
|
267
|
-
Log(logger::S_TIME, "timeSyncTask(): %u\n", conn->nodeId);
|
|
268
|
-
mesh.startTimeSync(conn);
|
|
269
|
-
});
|
|
270
|
-
mesh.mScheduler->addTask(conn->timeSyncTask);
|
|
271
|
-
if (conn->station)
|
|
272
|
-
// We are STA, request time immediately
|
|
273
|
-
conn->timeSyncTask.enable();
|
|
274
|
-
else
|
|
275
|
-
// We are the AP, give STA the change to initiate time sync
|
|
276
|
-
conn->timeSyncTask.enableDelayed();
|
|
277
|
-
conn->newConnection = false;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if (conn->updateSubs(newTree)) {
|
|
281
|
-
auto nodeId = newTree.nodeId;
|
|
282
|
-
mesh.addTask(
|
|
283
|
-
[&mesh, nodeId]() { mesh.changedConnectionCallbacks.execute(nodeId); });
|
|
284
|
-
} else {
|
|
285
|
-
conn->nodeSyncTask.delay();
|
|
286
|
-
mesh.stability += std::min(1000 - mesh.stability, (size_t)25);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
template <class T, typename U>
|
|
291
|
-
callback::MeshPackageCallbackList<U> addPackageCallback(
|
|
292
|
-
callback::MeshPackageCallbackList<U>&& callbackList, T& mesh) {
|
|
293
|
-
// REQUEST type,
|
|
294
|
-
callbackList.onPackage(
|
|
295
|
-
protocol::NODE_SYNC_REQUEST,
|
|
296
|
-
[&mesh](protocol::Variant& variant, std::shared_ptr<U> connection,
|
|
297
|
-
uint32_t receivedAt) {
|
|
298
|
-
auto newTree = variant.to<protocol::NodeSyncRequest>();
|
|
299
|
-
handleNodeSync<T, U>(mesh, newTree, connection);
|
|
300
|
-
send<protocol::NodeSyncReply>(
|
|
301
|
-
connection->reply(std::move(mesh.asNodeTree())), connection, true);
|
|
302
|
-
return false;
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
// Reply type just handle it
|
|
306
|
-
callbackList.onPackage(
|
|
307
|
-
protocol::NODE_SYNC_REPLY,
|
|
308
|
-
[&mesh](protocol::Variant& variant, std::shared_ptr<U> connection,
|
|
309
|
-
uint32_t receivedAt) {
|
|
310
|
-
auto newTree = variant.to<protocol::NodeSyncReply>();
|
|
311
|
-
handleNodeSync<T, U>(mesh, newTree, connection);
|
|
312
|
-
connection->timeOutTask.disable();
|
|
313
|
-
return false;
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
return callbackList;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
} // namespace router
|
|
320
|
-
} // namespace painlessmesh
|
|
321
|
-
|
|
322
|
-
#endif
|
|
1
|
+
#ifndef _PAINLESS_MESH_ROUTER_HPP_
|
|
2
|
+
#define _PAINLESS_MESH_ROUTER_HPP_
|
|
3
|
+
|
|
4
|
+
#include <algorithm>
|
|
5
|
+
#include <memory>
|
|
6
|
+
|
|
7
|
+
#include "painlessmesh/callback.hpp"
|
|
8
|
+
#include "painlessmesh/layout.hpp"
|
|
9
|
+
#include "painlessmesh/logger.hpp"
|
|
10
|
+
#include "painlessmesh/protocol.hpp"
|
|
11
|
+
|
|
12
|
+
extern painlessmesh::logger::LogClass Log;
|
|
13
|
+
|
|
14
|
+
namespace painlessmesh {
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Helper functions to route messages
|
|
18
|
+
*/
|
|
19
|
+
namespace router {
|
|
20
|
+
template <class T>
|
|
21
|
+
std::shared_ptr<T> findRoute(layout::Layout<T> tree,
|
|
22
|
+
std::function<bool(std::shared_ptr<T>)> func) {
|
|
23
|
+
auto route = std::find_if(tree.subs.begin(), tree.subs.end(), func);
|
|
24
|
+
if (route == tree.subs.end()) return NULL;
|
|
25
|
+
return (*route);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
template <class T>
|
|
29
|
+
std::shared_ptr<T> findRoute(layout::Layout<T> tree, uint32_t nodeId) {
|
|
30
|
+
return findRoute<T>(tree, [nodeId](std::shared_ptr<T> s) {
|
|
31
|
+
return layout::contains((*s), nodeId);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
template <class T, class U>
|
|
36
|
+
bool send(T& package, std::shared_ptr<U> conn, bool priority = false) {
|
|
37
|
+
painlessmesh::protocol::Variant variant(package);
|
|
38
|
+
TSTRING msg;
|
|
39
|
+
variant.printTo(msg);
|
|
40
|
+
return conn->addMessage(msg, priority);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
template <class T, class U>
|
|
44
|
+
bool send(T&& package, std::shared_ptr<U> conn, bool priority = false) {
|
|
45
|
+
painlessmesh::protocol::Variant variant(package);
|
|
46
|
+
TSTRING msg;
|
|
47
|
+
variant.printTo(msg);
|
|
48
|
+
return conn->addMessage(msg, priority);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
template <class U>
|
|
52
|
+
bool send(protocol::Variant& variant, std::shared_ptr<U> conn,
|
|
53
|
+
bool priority = false) {
|
|
54
|
+
TSTRING msg;
|
|
55
|
+
variant.printTo(msg);
|
|
56
|
+
return conn->addMessage(msg, priority);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
template <class U>
|
|
60
|
+
bool send(protocol::Variant&& variant, std::shared_ptr<U> conn,
|
|
61
|
+
bool priority = false) {
|
|
62
|
+
TSTRING msg;
|
|
63
|
+
variant.printTo(msg);
|
|
64
|
+
return conn->addMessage(msg, priority);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
template <class T, class U>
|
|
68
|
+
bool send(T& package, layout::Layout<U> layout) {
|
|
69
|
+
painlessmesh::protocol::Variant variant(package);
|
|
70
|
+
TSTRING msg;
|
|
71
|
+
variant.printTo(msg);
|
|
72
|
+
auto conn = findRoute<U>(layout, variant.dest());
|
|
73
|
+
if (conn) return conn->addMessage(msg);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
template <class U>
|
|
78
|
+
bool send(protocol::Variant& variant, layout::Layout<U> layout) {
|
|
79
|
+
TSTRING msg;
|
|
80
|
+
variant.printTo(msg);
|
|
81
|
+
auto conn = findRoute<U>(layout, variant.dest());
|
|
82
|
+
if (conn) return conn->addMessage(msg);
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
template <class T, class U>
|
|
87
|
+
bool send(T&& package, layout::Layout<U> layout) {
|
|
88
|
+
painlessmesh::protocol::Variant variant(package);
|
|
89
|
+
TSTRING msg;
|
|
90
|
+
variant.printTo(msg);
|
|
91
|
+
auto conn = findRoute<U>(layout, variant.dest());
|
|
92
|
+
if (conn) return conn->addMessage(msg);
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
template <class U>
|
|
97
|
+
bool send(protocol::Variant&& variant, layout::Layout<U> layout) {
|
|
98
|
+
TSTRING msg;
|
|
99
|
+
variant.printTo(msg);
|
|
100
|
+
auto conn = findRoute<U>(layout, variant.dest());
|
|
101
|
+
if (conn) return conn->addMessage(msg);
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
template <class T, class U>
|
|
106
|
+
size_t broadcast(T& package, layout::Layout<U> layout, uint32_t exclude) {
|
|
107
|
+
painlessmesh::protocol::Variant variant(package);
|
|
108
|
+
TSTRING msg;
|
|
109
|
+
variant.printTo(msg);
|
|
110
|
+
size_t i = 0;
|
|
111
|
+
for (auto&& conn : layout.subs) {
|
|
112
|
+
if (conn->nodeId != 0 && conn->nodeId != exclude) {
|
|
113
|
+
auto sent = conn->addMessage(msg);
|
|
114
|
+
if (sent) ++i;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return i;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
template <class T, class U>
|
|
121
|
+
size_t broadcast(T&& package, layout::Layout<U> layout, uint32_t exclude) {
|
|
122
|
+
painlessmesh::protocol::Variant variant(package);
|
|
123
|
+
TSTRING msg;
|
|
124
|
+
variant.printTo(msg);
|
|
125
|
+
size_t i = 0;
|
|
126
|
+
for (auto&& conn : layout.subs) {
|
|
127
|
+
if (conn->nodeId != 0 && conn->nodeId != exclude) {
|
|
128
|
+
auto sent = conn->addMessage(msg);
|
|
129
|
+
if (sent) ++i;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return i;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
template <class T>
|
|
136
|
+
size_t broadcast(protocol::Variant& variant, layout::Layout<T> layout,
|
|
137
|
+
uint32_t exclude) {
|
|
138
|
+
TSTRING msg;
|
|
139
|
+
variant.printTo(msg);
|
|
140
|
+
size_t i = 0;
|
|
141
|
+
for (auto&& conn : layout.subs) {
|
|
142
|
+
if (conn->nodeId != 0 && conn->nodeId != exclude) {
|
|
143
|
+
auto sent = conn->addMessage(msg);
|
|
144
|
+
if (sent) ++i;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return i;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
template <class T>
|
|
151
|
+
size_t broadcast(protocol::Variant&& variant, layout::Layout<T> layout,
|
|
152
|
+
uint32_t exclude) {
|
|
153
|
+
TSTRING msg;
|
|
154
|
+
variant.printTo(msg);
|
|
155
|
+
size_t i = 0;
|
|
156
|
+
for (auto&& conn : layout.subs) {
|
|
157
|
+
if (conn->nodeId != 0 && conn->nodeId != exclude) {
|
|
158
|
+
auto sent = conn->addMessage(msg);
|
|
159
|
+
if (sent) ++i;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return i;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
template <class T>
|
|
166
|
+
void routePackage(layout::Layout<T> layout, std::shared_ptr<T> connection,
|
|
167
|
+
const TSTRING& pkg, callback::MeshPackageCallbackList<T> cbl,
|
|
168
|
+
uint32_t receivedAt) {
|
|
169
|
+
using namespace logger;
|
|
170
|
+
Log(COMMUNICATION, "routePackage(): Recvd from %u: %s\n", connection->nodeId,
|
|
171
|
+
pkg.c_str());
|
|
172
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
173
|
+
protocol::Variant variant(pkg);
|
|
174
|
+
if (variant.error) {
|
|
175
|
+
Log(ERROR,
|
|
176
|
+
"routePackage(): parsing failed. err=%u, total_length=%d, data=%s<--\n",
|
|
177
|
+
variant.error, pkg.length(), pkg.c_str());
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (variant.routing() == SINGLE && variant.dest() != layout.getNodeId()) {
|
|
182
|
+
// Send on without further processing
|
|
183
|
+
send<T>(variant, layout);
|
|
184
|
+
return;
|
|
185
|
+
} else if (variant.routing() == BROADCAST) {
|
|
186
|
+
broadcast<T>(variant, layout, connection->nodeId);
|
|
187
|
+
}
|
|
188
|
+
auto calls = cbl.execute(variant.type(), variant, connection, receivedAt);
|
|
189
|
+
if (calls == 0)
|
|
190
|
+
Log(DEBUG, "routePackage(): No callbacks executed; %u, %s\n",
|
|
191
|
+
variant.type(), pkg.c_str());
|
|
192
|
+
#else
|
|
193
|
+
static size_t baseCapacity = 512;
|
|
194
|
+
// Using a ptr so we can overwrite it if we need to grow capacity.
|
|
195
|
+
// Bug in copy constructor with grown capacity can cause segmentation fault
|
|
196
|
+
auto variant =
|
|
197
|
+
std::make_shared<protocol::Variant>(pkg, pkg.length() + baseCapacity);
|
|
198
|
+
while (variant->error == DeserializationError::NoMemory &&
|
|
199
|
+
baseCapacity <= 20480) {
|
|
200
|
+
// Not enough memory, adapt scaling (variant::capacityScaling) and log the
|
|
201
|
+
// new value
|
|
202
|
+
Log(DEBUG,
|
|
203
|
+
"routePackage(): parsing failed. err=%u, increasing capacity: %u\n",
|
|
204
|
+
variant->error, baseCapacity);
|
|
205
|
+
baseCapacity += 256;
|
|
206
|
+
variant =
|
|
207
|
+
std::make_shared<protocol::Variant>(pkg, pkg.length() + baseCapacity);
|
|
208
|
+
}
|
|
209
|
+
if (variant->error) {
|
|
210
|
+
Log(ERROR,
|
|
211
|
+
"routePackage(): parsing failed. err=%u, total_length=%d, data=%s<--\n",
|
|
212
|
+
variant->error, pkg.length(), pkg.c_str());
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (variant->routing() == SINGLE && variant->dest() != layout.getNodeId()) {
|
|
217
|
+
// Send on without further processing
|
|
218
|
+
send<T>((*variant), layout);
|
|
219
|
+
return;
|
|
220
|
+
} else if (variant->routing() == BROADCAST) {
|
|
221
|
+
broadcast<T>((*variant), layout, connection->nodeId);
|
|
222
|
+
}
|
|
223
|
+
auto calls = cbl.execute(variant->type(), (*variant), connection, receivedAt);
|
|
224
|
+
if (calls == 0)
|
|
225
|
+
Log(DEBUG, "routePackage(): No callbacks executed; %u, %s\n",
|
|
226
|
+
variant->type(), pkg.c_str());
|
|
227
|
+
#endif
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
template <class T, class U>
|
|
231
|
+
void handleNodeSync(T& mesh, protocol::NodeTree newTree,
|
|
232
|
+
std::shared_ptr<U> conn) {
|
|
233
|
+
Log(logger::SYNC, "handleNodeSync(): with %u\n", conn->nodeId);
|
|
234
|
+
|
|
235
|
+
if (!conn->validSubs(newTree)) {
|
|
236
|
+
Log(logger::SYNC, "handleNodeSync(): invalid new connection\n");
|
|
237
|
+
Log.remote("Invalid connection to %u\n", conn->nodeId);
|
|
238
|
+
conn->close();
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (conn->newConnection) {
|
|
243
|
+
auto oldConnection = router::findRoute<U>(mesh, newTree.nodeId);
|
|
244
|
+
if (oldConnection) {
|
|
245
|
+
Log(logger::SYNC,
|
|
246
|
+
"handleNodeSync(): already connected to %u. Closing the new "
|
|
247
|
+
"connection \n",
|
|
248
|
+
newTree.nodeId);
|
|
249
|
+
Log.remote("Already connected to %u\n", newTree.nodeId);
|
|
250
|
+
conn->close();
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
auto remoteNodeId = newTree.nodeId;
|
|
254
|
+
mesh.addTask([&mesh, remoteNodeId]() {
|
|
255
|
+
Log(logger::CONNECTION, "newConnectionTask():\n");
|
|
256
|
+
Log(logger::CONNECTION, "newConnectionTask(): adding %u now= %u\n",
|
|
257
|
+
remoteNodeId, mesh.getNodeTime());
|
|
258
|
+
mesh.newConnectionCallbacks.execute(remoteNodeId);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Initially interval is every 10 seconds,
|
|
262
|
+
// this will slow down to TIME_SYNC_INTERVAL
|
|
263
|
+
// after first succesfull sync
|
|
264
|
+
// TODO move it to a new connection callback and use initTimeSync from
|
|
265
|
+
// ntp.hpp
|
|
266
|
+
conn->timeSyncTask.set(10 * TASK_SECOND, TASK_FOREVER, [conn, &mesh]() {
|
|
267
|
+
Log(logger::S_TIME, "timeSyncTask(): %u\n", conn->nodeId);
|
|
268
|
+
mesh.startTimeSync(conn);
|
|
269
|
+
});
|
|
270
|
+
mesh.mScheduler->addTask(conn->timeSyncTask);
|
|
271
|
+
if (conn->station)
|
|
272
|
+
// We are STA, request time immediately
|
|
273
|
+
conn->timeSyncTask.enable();
|
|
274
|
+
else
|
|
275
|
+
// We are the AP, give STA the change to initiate time sync
|
|
276
|
+
conn->timeSyncTask.enableDelayed();
|
|
277
|
+
conn->newConnection = false;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (conn->updateSubs(newTree)) {
|
|
281
|
+
auto nodeId = newTree.nodeId;
|
|
282
|
+
mesh.addTask(
|
|
283
|
+
[&mesh, nodeId]() { mesh.changedConnectionCallbacks.execute(nodeId); });
|
|
284
|
+
} else {
|
|
285
|
+
conn->nodeSyncTask.delay();
|
|
286
|
+
mesh.stability += std::min(1000 - mesh.stability, (size_t)25);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
template <class T, typename U>
|
|
291
|
+
callback::MeshPackageCallbackList<U> addPackageCallback(
|
|
292
|
+
callback::MeshPackageCallbackList<U>&& callbackList, T& mesh) {
|
|
293
|
+
// REQUEST type,
|
|
294
|
+
callbackList.onPackage(
|
|
295
|
+
protocol::NODE_SYNC_REQUEST,
|
|
296
|
+
[&mesh](protocol::Variant& variant, std::shared_ptr<U> connection,
|
|
297
|
+
uint32_t receivedAt) {
|
|
298
|
+
auto newTree = variant.to<protocol::NodeSyncRequest>();
|
|
299
|
+
handleNodeSync<T, U>(mesh, newTree, connection);
|
|
300
|
+
send<protocol::NodeSyncReply>(
|
|
301
|
+
connection->reply(std::move(mesh.asNodeTree())), connection, true);
|
|
302
|
+
return false;
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// Reply type just handle it
|
|
306
|
+
callbackList.onPackage(
|
|
307
|
+
protocol::NODE_SYNC_REPLY,
|
|
308
|
+
[&mesh](protocol::Variant& variant, std::shared_ptr<U> connection,
|
|
309
|
+
uint32_t receivedAt) {
|
|
310
|
+
auto newTree = variant.to<protocol::NodeSyncReply>();
|
|
311
|
+
handleNodeSync<T, U>(mesh, newTree, connection);
|
|
312
|
+
connection->timeOutTask.disable();
|
|
313
|
+
return false;
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
return callbackList;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
} // namespace router
|
|
320
|
+
} // namespace painlessmesh
|
|
321
|
+
|
|
322
|
+
#endif
|