@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.
- package/CHANGELOG.md +144 -0
- package/LICENSE +674 -0
- package/README.md +434 -0
- package/RELEASE_GUIDE.md +419 -0
- package/docs/DOCUMENTATION_MIGRATION_PLAN.md +176 -0
- package/docs/README.md +71 -0
- package/docs/alteriom/overview.md +508 -0
- package/docs/api/core-api.md +607 -0
- package/docs/architecture/mesh-architecture.md +379 -0
- package/docs/architecture/plugin-system.md +517 -0
- package/docs/getting-started/first-mesh.md +410 -0
- package/docs/getting-started/installation.md +275 -0
- package/docs/getting-started/quickstart.md +158 -0
- package/docs/improvements/README.md +69 -0
- package/docs/troubleshooting/common-issues.md +521 -0
- package/docs/troubleshooting/faq.md +473 -0
- package/docs/tutorials/basic-examples.md +718 -0
- package/docs/wiki/API-Reference.md +246 -0
- package/docs/wiki/Complete-Documentation.md +123 -0
- package/examples/alteriom/README.md +82 -0
- package/examples/alteriom/alteriom.ino +186 -0
- package/examples/alteriom/alteriom_sensor_node.ino +184 -0
- package/examples/alteriom/alteriom_sensor_package.hpp +128 -0
- package/examples/alteriom/improved_sensor_node.ino +246 -0
- package/examples/alteriom/platformio.ini +25 -0
- package/examples/basic/basic.ino +66 -0
- package/examples/basic/platformio.ini +25 -0
- package/examples/bridge/bridge.ino +51 -0
- package/examples/bridge/platformio.ini +25 -0
- package/examples/echoNode/echoNode.ino +33 -0
- package/examples/echoNode/platformio.ini +25 -0
- package/examples/logClient/logClient.ino +109 -0
- package/examples/logClient/platformio.ini +25 -0
- package/examples/logServer/logServer.ino +81 -0
- package/examples/logServer/platformio.ini +25 -0
- package/examples/mqttBridge/mqttBridge.ino +118 -0
- package/examples/mqttBridge/platformio.ini +26 -0
- package/examples/namedMesh/namedMesh.ino +97 -0
- package/examples/namedMesh/platformio.ini +25 -0
- package/examples/otaReceiver/otaReceiver.ino +79 -0
- package/examples/otaReceiver/platformio.ini +25 -0
- package/examples/otaSender/nodemcu32s_connections.JPG +0 -0
- package/examples/otaSender/otaSender.ino +151 -0
- package/examples/otaSender/platformio.ini +25 -0
- package/examples/startHere/platformio.ini +25 -0
- package/examples/startHere/startHere.ino +159 -0
- package/examples/webServer/platformio.ini +27 -0
- package/examples/webServer/webServer.ino +89 -0
- package/keywords.txt +49 -0
- package/library.json +34 -0
- package/library.properties +11 -0
- package/package.json +78 -0
- package/src/AlteriomPainlessMesh.h +98 -0
- package/src/arduino/wifi.hpp +365 -0
- package/src/boost/asynctcp.hpp +279 -0
- package/src/painlessMesh.h +70 -0
- package/src/painlessMeshSTA.cpp +236 -0
- package/src/painlessMeshSTA.h +58 -0
- package/src/painlessTaskOptions.h +4 -0
- package/src/painlessmesh/base64.hpp +111 -0
- package/src/painlessmesh/buffer.hpp +229 -0
- package/src/painlessmesh/callback.hpp +91 -0
- package/src/painlessmesh/configuration.hpp +77 -0
- package/src/painlessmesh/connection.hpp +192 -0
- package/src/painlessmesh/layout.hpp +188 -0
- package/src/painlessmesh/logger.hpp +158 -0
- package/src/painlessmesh/memory.hpp +120 -0
- package/src/painlessmesh/mesh.hpp +560 -0
- package/src/painlessmesh/metrics.hpp +323 -0
- package/src/painlessmesh/ntp.hpp +263 -0
- package/src/painlessmesh/ota.hpp +553 -0
- package/src/painlessmesh/plugin.hpp +188 -0
- package/src/painlessmesh/protocol.hpp +813 -0
- package/src/painlessmesh/router.hpp +322 -0
- package/src/painlessmesh/tcp.hpp +71 -0
- package/src/painlessmesh/validation.hpp +239 -0
- package/src/plugin/performance.hpp +214 -0
- package/src/plugin/remote.hpp +64 -0
- package/src/scheduler.cpp +10 -0
- package/src/wifi.cpp +2 -0
|
@@ -0,0 +1,813 @@
|
|
|
1
|
+
#ifndef _PAINLESS_MESH_PROTOCOL_HPP_
|
|
2
|
+
#define _PAINLESS_MESH_PROTOCOL_HPP_
|
|
3
|
+
|
|
4
|
+
#include <cmath>
|
|
5
|
+
#include <list>
|
|
6
|
+
|
|
7
|
+
#include "Arduino.h"
|
|
8
|
+
|
|
9
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
10
|
+
#include "ArduinoJson/Deserialization/DeserializationError.hpp"
|
|
11
|
+
#include "ArduinoJson/Document/JsonDocument.hpp"
|
|
12
|
+
#endif
|
|
13
|
+
#include "painlessmesh/configuration.hpp"
|
|
14
|
+
|
|
15
|
+
namespace painlessmesh {
|
|
16
|
+
|
|
17
|
+
namespace router {
|
|
18
|
+
|
|
19
|
+
/** Different ways to route packages
|
|
20
|
+
*
|
|
21
|
+
* NEIGHBOUR packages are send to the neighbour and will be immediately
|
|
22
|
+
* handled there. The TIME_SYNC and NODE_SYNC packages are NEIGHBOUR. SINGLE
|
|
23
|
+
* messages are meant for a specific node. When another node receives this
|
|
24
|
+
* message, it will look in its routing information and send it on to the
|
|
25
|
+
* correct node, without processing the message in any other way. Only the
|
|
26
|
+
* targetted node will actually parse/handle this message (without sending it
|
|
27
|
+
* on). Finally, BROADCAST message are send to every node and
|
|
28
|
+
* processed/handled by every node.
|
|
29
|
+
* */
|
|
30
|
+
enum Type { ROUTING_ERROR = -1, NEIGHBOUR, SINGLE, BROADCAST };
|
|
31
|
+
} // namespace router
|
|
32
|
+
|
|
33
|
+
namespace protocol {
|
|
34
|
+
|
|
35
|
+
enum Type {
|
|
36
|
+
TIME_DELAY = 3,
|
|
37
|
+
TIME_SYNC = 4,
|
|
38
|
+
NODE_SYNC_REQUEST = 5,
|
|
39
|
+
NODE_SYNC_REPLY = 6,
|
|
40
|
+
CONTROL = 7, // deprecated
|
|
41
|
+
BROADCAST = 8, // application data for everyone
|
|
42
|
+
SINGLE = 9 // application data for a single node
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
enum TimeType {
|
|
46
|
+
TIME_SYNC_ERROR = -1,
|
|
47
|
+
TIME_SYNC_REQUEST,
|
|
48
|
+
TIME_REQUEST,
|
|
49
|
+
TIME_REPLY
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
class PackageInterface {
|
|
53
|
+
public:
|
|
54
|
+
virtual JsonObject addTo(JsonObject&& jsonObj) const = 0;
|
|
55
|
+
#if ARDUINOJSON_VERSION_MAJOR < 7
|
|
56
|
+
virtual size_t jsonObjectSize() const = 0;
|
|
57
|
+
#endif
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Single package
|
|
62
|
+
*
|
|
63
|
+
* Message send to a specific node
|
|
64
|
+
*/
|
|
65
|
+
class Single : public PackageInterface {
|
|
66
|
+
public:
|
|
67
|
+
int type = SINGLE;
|
|
68
|
+
uint32_t from;
|
|
69
|
+
uint32_t dest;
|
|
70
|
+
TSTRING msg = "";
|
|
71
|
+
|
|
72
|
+
Single() {}
|
|
73
|
+
Single(uint32_t fromID, uint32_t destID, TSTRING& message) {
|
|
74
|
+
from = fromID;
|
|
75
|
+
dest = destID;
|
|
76
|
+
msg = message;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
Single(JsonObject jsonObj) {
|
|
80
|
+
dest = jsonObj["dest"].as<uint32_t>();
|
|
81
|
+
from = jsonObj["from"].as<uint32_t>();
|
|
82
|
+
msg = jsonObj["msg"].as<TSTRING>();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
JsonObject addTo(JsonObject&& jsonObj) const {
|
|
86
|
+
jsonObj["type"] = type;
|
|
87
|
+
jsonObj["dest"] = dest;
|
|
88
|
+
jsonObj["from"] = from;
|
|
89
|
+
jsonObj["msg"] = msg;
|
|
90
|
+
return jsonObj;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
#if ARDUINOJSON_VERSION_MAJOR < 7
|
|
94
|
+
size_t jsonObjectSize() const {
|
|
95
|
+
return JSON_OBJECT_SIZE(4) + ceil(1.1 * msg.length());
|
|
96
|
+
}
|
|
97
|
+
#endif
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Broadcast package
|
|
102
|
+
*/
|
|
103
|
+
class Broadcast : public Single {
|
|
104
|
+
public:
|
|
105
|
+
int type = BROADCAST;
|
|
106
|
+
|
|
107
|
+
using Single::Single;
|
|
108
|
+
|
|
109
|
+
JsonObject addTo(JsonObject&& jsonObj) const {
|
|
110
|
+
jsonObj = Single::addTo(std::move(jsonObj));
|
|
111
|
+
jsonObj["type"] = type;
|
|
112
|
+
return jsonObj;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
#if ARDUINOJSON_VERSION_MAJOR < 7
|
|
116
|
+
size_t jsonObjectSize() const {
|
|
117
|
+
return JSON_OBJECT_SIZE(4) + ceil(1.1 * msg.length());
|
|
118
|
+
}
|
|
119
|
+
#endif
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
class NodeTree : public PackageInterface {
|
|
123
|
+
public:
|
|
124
|
+
uint32_t nodeId = 0;
|
|
125
|
+
bool root = false;
|
|
126
|
+
std::list<NodeTree> subs;
|
|
127
|
+
|
|
128
|
+
NodeTree() {}
|
|
129
|
+
virtual ~NodeTree() = default; // Add virtual destructor
|
|
130
|
+
|
|
131
|
+
NodeTree(uint32_t nodeID, bool iAmRoot) {
|
|
132
|
+
nodeId = nodeID;
|
|
133
|
+
root = iAmRoot;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
NodeTree(JsonObject jsonObj) {
|
|
137
|
+
#if ARDUINOJSON_VERSION_MAJOR < 7
|
|
138
|
+
if (jsonObj.containsKey("root")) root = jsonObj["root"].as<bool>();
|
|
139
|
+
if (jsonObj.containsKey("nodeId"))
|
|
140
|
+
#else
|
|
141
|
+
|
|
142
|
+
if (jsonObj["root"].is<bool>()) root = jsonObj["root"].as<bool>();
|
|
143
|
+
if (jsonObj["nodeId"].is<uint32_t>())
|
|
144
|
+
#endif
|
|
145
|
+
nodeId = jsonObj["nodeId"].as<uint32_t>();
|
|
146
|
+
else
|
|
147
|
+
nodeId = jsonObj["from"].as<uint32_t>();
|
|
148
|
+
|
|
149
|
+
#if ARDUINOJSON_VERSION_MAJOR < 7
|
|
150
|
+
if (jsonObj.containsKey("subs")) {
|
|
151
|
+
#else
|
|
152
|
+
if (jsonObj["subs"].is<JsonArray>()) {
|
|
153
|
+
#endif
|
|
154
|
+
auto jsonArr = jsonObj["subs"].as<JsonArray>();
|
|
155
|
+
for (size_t i = 0; i < jsonArr.size(); ++i) {
|
|
156
|
+
subs.push_back(NodeTree(jsonArr[i].as<JsonObject>()));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
JsonObject addTo(JsonObject&& jsonObj) const {
|
|
162
|
+
jsonObj["nodeId"] = nodeId;
|
|
163
|
+
if (root) jsonObj["root"] = root;
|
|
164
|
+
if (subs.size() > 0) {
|
|
165
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
166
|
+
JsonArray subsArr = jsonObj["subs"].to<JsonArray>();
|
|
167
|
+
#else
|
|
168
|
+
JsonArray subsArr = jsonObj.createNestedArray("subs");
|
|
169
|
+
#endif
|
|
170
|
+
for (auto&& s : subs) {
|
|
171
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
172
|
+
JsonObject subObj = subsArr.add<JsonObject>();
|
|
173
|
+
#else
|
|
174
|
+
JsonObject subObj = subsArr.createNestedObject();
|
|
175
|
+
#endif
|
|
176
|
+
subObj = s.addTo(std::move(subObj));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return jsonObj;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
bool operator==(const NodeTree& b) const {
|
|
183
|
+
if (!(this->nodeId == b.nodeId && this->root == b.root &&
|
|
184
|
+
this->subs.size() == b.subs.size()))
|
|
185
|
+
return false;
|
|
186
|
+
auto itA = this->subs.begin();
|
|
187
|
+
auto itB = b.subs.begin();
|
|
188
|
+
for (size_t i = 0; i < this->subs.size(); ++i) {
|
|
189
|
+
if ((*itA) != (*itB)) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
++itA;
|
|
193
|
+
++itB;
|
|
194
|
+
}
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
bool operator!=(const NodeTree& b) const { return !this->operator==(b); }
|
|
199
|
+
|
|
200
|
+
TSTRING toString(bool pretty = false);
|
|
201
|
+
|
|
202
|
+
#if ARDUINOJSON_VERSION_MAJOR < 7
|
|
203
|
+
size_t jsonObjectSize() const {
|
|
204
|
+
size_t base = 1;
|
|
205
|
+
if (root) ++base;
|
|
206
|
+
if (subs.size() > 0) ++base;
|
|
207
|
+
size_t size = JSON_OBJECT_SIZE(base);
|
|
208
|
+
if (subs.size() > 0) size += JSON_ARRAY_SIZE(subs.size());
|
|
209
|
+
for (auto&& s : subs) size += s.jsonObjectSize();
|
|
210
|
+
return size;
|
|
211
|
+
}
|
|
212
|
+
#endif
|
|
213
|
+
|
|
214
|
+
void clear() {
|
|
215
|
+
nodeId = 0;
|
|
216
|
+
subs.clear();
|
|
217
|
+
root = false;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* NodeSyncRequest package
|
|
223
|
+
*/
|
|
224
|
+
class NodeSyncRequest : public NodeTree {
|
|
225
|
+
public:
|
|
226
|
+
int type = NODE_SYNC_REQUEST;
|
|
227
|
+
uint32_t from;
|
|
228
|
+
uint32_t dest;
|
|
229
|
+
|
|
230
|
+
NodeSyncRequest() {}
|
|
231
|
+
NodeSyncRequest(uint32_t fromID, uint32_t destID, std::list<NodeTree> subTree,
|
|
232
|
+
bool iAmRoot = false) {
|
|
233
|
+
from = fromID;
|
|
234
|
+
dest = destID;
|
|
235
|
+
subs = subTree;
|
|
236
|
+
nodeId = fromID;
|
|
237
|
+
root = iAmRoot;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
NodeSyncRequest(JsonObject jsonObj) : NodeTree(jsonObj) {
|
|
241
|
+
dest = jsonObj["dest"].as<uint32_t>();
|
|
242
|
+
from = jsonObj["from"].as<uint32_t>();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
JsonObject addTo(JsonObject&& jsonObj) const {
|
|
246
|
+
jsonObj = NodeTree::addTo(std::move(jsonObj));
|
|
247
|
+
jsonObj["type"] = type;
|
|
248
|
+
jsonObj["dest"] = dest;
|
|
249
|
+
jsonObj["from"] = from;
|
|
250
|
+
return jsonObj;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
bool operator==(const NodeSyncRequest& b) const {
|
|
254
|
+
if (!(this->from == b.from && this->dest == b.dest)) return false;
|
|
255
|
+
return NodeTree::operator==(b);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
bool operator!=(const NodeSyncRequest& b) const {
|
|
259
|
+
return !this->operator==(b);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
#if ARDUINOJSON_VERSION_MAJOR < 7
|
|
263
|
+
size_t jsonObjectSize() const {
|
|
264
|
+
size_t base = 4;
|
|
265
|
+
if (root) ++base;
|
|
266
|
+
if (subs.size() > 0) ++base;
|
|
267
|
+
size_t size = JSON_OBJECT_SIZE(base);
|
|
268
|
+
if (subs.size() > 0) size += JSON_ARRAY_SIZE(subs.size());
|
|
269
|
+
for (auto&& s : subs) size += s.jsonObjectSize();
|
|
270
|
+
return size;
|
|
271
|
+
}
|
|
272
|
+
#endif
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* NodeSyncReply package
|
|
277
|
+
*/
|
|
278
|
+
class NodeSyncReply : public NodeSyncRequest {
|
|
279
|
+
public:
|
|
280
|
+
int type = NODE_SYNC_REPLY;
|
|
281
|
+
|
|
282
|
+
using NodeSyncRequest::NodeSyncRequest;
|
|
283
|
+
|
|
284
|
+
JsonObject addTo(JsonObject&& jsonObj) const {
|
|
285
|
+
jsonObj = NodeSyncRequest::addTo(std::move(jsonObj));
|
|
286
|
+
jsonObj["type"] = type;
|
|
287
|
+
return jsonObj;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
struct time_sync_msg_t {
|
|
292
|
+
int type = TIME_SYNC_ERROR;
|
|
293
|
+
uint32_t t0 = 0;
|
|
294
|
+
uint32_t t1 = 0;
|
|
295
|
+
uint32_t t2 = 0;
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* TimeSync package
|
|
300
|
+
*/
|
|
301
|
+
class TimeSync : public PackageInterface {
|
|
302
|
+
public:
|
|
303
|
+
int type = TIME_SYNC;
|
|
304
|
+
uint32_t dest;
|
|
305
|
+
uint32_t from;
|
|
306
|
+
time_sync_msg_t msg;
|
|
307
|
+
|
|
308
|
+
TimeSync() {}
|
|
309
|
+
|
|
310
|
+
TimeSync(uint32_t fromID, uint32_t destID) {
|
|
311
|
+
from = fromID;
|
|
312
|
+
dest = destID;
|
|
313
|
+
msg.type = TIME_SYNC_REQUEST;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
TimeSync(uint32_t fromID, uint32_t destID, uint32_t t0) {
|
|
317
|
+
from = fromID;
|
|
318
|
+
dest = destID;
|
|
319
|
+
msg.type = TIME_REQUEST;
|
|
320
|
+
msg.t0 = t0;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
TimeSync(uint32_t fromID, uint32_t destID, uint32_t t0, uint32_t t1) {
|
|
324
|
+
from = fromID;
|
|
325
|
+
dest = destID;
|
|
326
|
+
msg.type = TIME_REPLY;
|
|
327
|
+
msg.t0 = t0;
|
|
328
|
+
msg.t1 = t1;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
TimeSync(uint32_t fromID, uint32_t destID, uint32_t t0, uint32_t t1,
|
|
332
|
+
uint32_t t2) {
|
|
333
|
+
from = fromID;
|
|
334
|
+
dest = destID;
|
|
335
|
+
msg.type = TIME_REPLY;
|
|
336
|
+
msg.t0 = t0;
|
|
337
|
+
msg.t1 = t1;
|
|
338
|
+
msg.t2 = t2;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
TimeSync(JsonObject jsonObj) {
|
|
342
|
+
dest = jsonObj["dest"].as<uint32_t>();
|
|
343
|
+
from = jsonObj["from"].as<uint32_t>();
|
|
344
|
+
msg.type = jsonObj["msg"]["type"].as<int>();
|
|
345
|
+
#if ARDUINOJSON_VERSION_MAJOR < 7
|
|
346
|
+
if (jsonObj["msg"].containsKey("t0"))
|
|
347
|
+
msg.t0 = jsonObj["msg"]["t0"].as<uint32_t>();
|
|
348
|
+
if (jsonObj["msg"].containsKey("t1"))
|
|
349
|
+
msg.t1 = jsonObj["msg"]["t1"].as<uint32_t>();
|
|
350
|
+
if (jsonObj["msg"].containsKey("t2"))
|
|
351
|
+
msg.t2 = jsonObj["msg"]["t2"].as<uint32_t>();
|
|
352
|
+
#else
|
|
353
|
+
if (jsonObj["msg"]["t0"].is<uint32_t>())
|
|
354
|
+
msg.t0 = jsonObj["msg"]["t0"].as<uint32_t>();
|
|
355
|
+
if (jsonObj["msg"]["t1"].is<uint32_t>())
|
|
356
|
+
msg.t1 = jsonObj["msg"]["t1"].as<uint32_t>();
|
|
357
|
+
if (jsonObj["msg"]["t2"].is<uint32_t>())
|
|
358
|
+
msg.t2 = jsonObj["msg"]["t2"].as<uint32_t>();
|
|
359
|
+
#endif
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
JsonObject addTo(JsonObject&& jsonObj) const {
|
|
363
|
+
jsonObj["type"] = type;
|
|
364
|
+
jsonObj["dest"] = dest;
|
|
365
|
+
jsonObj["from"] = from;
|
|
366
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
367
|
+
auto msgObj = jsonObj["msg"].to<JsonObject>();
|
|
368
|
+
#else
|
|
369
|
+
auto msgObj = jsonObj.createNestedObject("msg");
|
|
370
|
+
#endif
|
|
371
|
+
msgObj["type"] = msg.type;
|
|
372
|
+
if (msg.type >= 1) msgObj["t0"] = msg.t0;
|
|
373
|
+
if (msg.type >= 2) {
|
|
374
|
+
msgObj["t1"] = msg.t1;
|
|
375
|
+
msgObj["t2"] = msg.t2;
|
|
376
|
+
}
|
|
377
|
+
return jsonObj;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Create a reply to the current message with the new time set
|
|
382
|
+
*/
|
|
383
|
+
void reply(uint newT0) {
|
|
384
|
+
msg.t0 = newT0;
|
|
385
|
+
++msg.type;
|
|
386
|
+
std::swap(from, dest);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Create a reply to the current message with the new time set
|
|
391
|
+
*/
|
|
392
|
+
void reply(uint32_t newT1, uint32_t newT2) {
|
|
393
|
+
msg.t1 = newT1;
|
|
394
|
+
msg.t2 = newT2;
|
|
395
|
+
++msg.type;
|
|
396
|
+
std::swap(from, dest);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
#if ARDUINOJSON_VERSION_MAJOR < 7
|
|
400
|
+
size_t jsonObjectSize() const {
|
|
401
|
+
return JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(4);
|
|
402
|
+
}
|
|
403
|
+
#endif
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* TimeDelay package
|
|
408
|
+
*/
|
|
409
|
+
class TimeDelay : public TimeSync {
|
|
410
|
+
public:
|
|
411
|
+
int type = TIME_DELAY;
|
|
412
|
+
using TimeSync::TimeSync;
|
|
413
|
+
|
|
414
|
+
JsonObject addTo(JsonObject&& jsonObj) const {
|
|
415
|
+
jsonObj = TimeSync::addTo(std::move(jsonObj));
|
|
416
|
+
jsonObj["type"] = type;
|
|
417
|
+
return jsonObj;
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Can store any package variant
|
|
423
|
+
*
|
|
424
|
+
* Internally stores packages as a JsonObject. Main use case is to convert
|
|
425
|
+
* different packages from and to Json (using ArduinoJson).
|
|
426
|
+
*/
|
|
427
|
+
class Variant {
|
|
428
|
+
// Copy operations implemented safely to address issue #521
|
|
429
|
+
// Move semantics preferred for performance
|
|
430
|
+
public:
|
|
431
|
+
// Copy constructor - implemented safely
|
|
432
|
+
Variant(const Variant& other) : error(other.error) {
|
|
433
|
+
// Deep copy the JSON buffer to avoid shared references
|
|
434
|
+
if (error == DeserializationError::Ok) {
|
|
435
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
436
|
+
jsonBuffer = JsonDocument();
|
|
437
|
+
#else
|
|
438
|
+
jsonBuffer = DynamicJsonDocument(other.jsonBuffer.capacity());
|
|
439
|
+
#endif
|
|
440
|
+
jsonBuffer.set(other.jsonBuffer);
|
|
441
|
+
jsonObj = jsonBuffer.as<JsonObject>();
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Copy assignment operator - implemented safely
|
|
446
|
+
Variant& operator=(const Variant& other) {
|
|
447
|
+
if (this != &other) {
|
|
448
|
+
error = other.error;
|
|
449
|
+
if (error == DeserializationError::Ok) {
|
|
450
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
451
|
+
jsonBuffer = JsonDocument();
|
|
452
|
+
#else
|
|
453
|
+
jsonBuffer = DynamicJsonDocument(other.jsonBuffer.capacity());
|
|
454
|
+
#endif
|
|
455
|
+
jsonBuffer.set(other.jsonBuffer);
|
|
456
|
+
jsonObj = jsonBuffer.as<JsonObject>();
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return *this;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Move constructor - preferred for performance
|
|
463
|
+
Variant(Variant&& other) noexcept
|
|
464
|
+
: error(std::move(other.error)),
|
|
465
|
+
jsonBuffer(std::move(other.jsonBuffer)) {
|
|
466
|
+
if (error == DeserializationError::Ok) {
|
|
467
|
+
jsonObj = jsonBuffer.as<JsonObject>();
|
|
468
|
+
}
|
|
469
|
+
other.error = DeserializationError::EmptyInput;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Move assignment operator - preferred for performance
|
|
473
|
+
Variant& operator=(Variant&& other) noexcept {
|
|
474
|
+
if (this != &other) {
|
|
475
|
+
error = std::move(other.error);
|
|
476
|
+
jsonBuffer = std::move(other.jsonBuffer);
|
|
477
|
+
if (error == DeserializationError::Ok) {
|
|
478
|
+
jsonObj = jsonBuffer.as<JsonObject>();
|
|
479
|
+
}
|
|
480
|
+
other.error = DeserializationError::EmptyInput;
|
|
481
|
+
}
|
|
482
|
+
return *this;
|
|
483
|
+
}
|
|
484
|
+
#ifdef ARDUINOJSON_ENABLE_STD_STRING
|
|
485
|
+
/**
|
|
486
|
+
* Create Variant object from a json string
|
|
487
|
+
*
|
|
488
|
+
* @param json The json string containing a package
|
|
489
|
+
*/
|
|
490
|
+
Variant(const std::string& json)
|
|
491
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
492
|
+
: jsonBuffer() {
|
|
493
|
+
#else
|
|
494
|
+
: jsonBuffer(JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(4) +
|
|
495
|
+
2 * json.length()) {
|
|
496
|
+
#endif
|
|
497
|
+
error = deserializeJson(jsonBuffer, json,
|
|
498
|
+
DeserializationOption::NestingLimit(255));
|
|
499
|
+
if (error == DeserializationError::Ok)
|
|
500
|
+
jsonObj = jsonBuffer.as<JsonObject>();
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Create Variant object from a json string
|
|
505
|
+
*
|
|
506
|
+
* @param json The json string containing a package
|
|
507
|
+
* @param capacity The capacity to reserve for parsing the string
|
|
508
|
+
*/
|
|
509
|
+
Variant(const std::string& json, size_t capacity)
|
|
510
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
511
|
+
: jsonBuffer() {
|
|
512
|
+
#else
|
|
513
|
+
: jsonBuffer(capacity) {
|
|
514
|
+
#endif
|
|
515
|
+
error = deserializeJson(jsonBuffer, json,
|
|
516
|
+
DeserializationOption::NestingLimit(255));
|
|
517
|
+
if (error == DeserializationError::Ok)
|
|
518
|
+
jsonObj = jsonBuffer.as<JsonObject>();
|
|
519
|
+
}
|
|
520
|
+
#endif
|
|
521
|
+
|
|
522
|
+
#ifdef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
|
523
|
+
/**
|
|
524
|
+
* Create Variant object from a json string
|
|
525
|
+
*
|
|
526
|
+
* @param json The json string containing a package
|
|
527
|
+
*/
|
|
528
|
+
Variant(String json)
|
|
529
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
530
|
+
: jsonBuffer() {
|
|
531
|
+
#else
|
|
532
|
+
: jsonBuffer(JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(4) +
|
|
533
|
+
2 * json.length()) {
|
|
534
|
+
#endif
|
|
535
|
+
error = deserializeJson(jsonBuffer, json,
|
|
536
|
+
DeserializationOption::NestingLimit(255));
|
|
537
|
+
|
|
538
|
+
if (error == DeserializationError::Ok)
|
|
539
|
+
jsonObj = jsonBuffer.as<JsonObject>();
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Create Variant object from a json string
|
|
544
|
+
*
|
|
545
|
+
* @param json The json string containing a package
|
|
546
|
+
* @param capacity The capacity to reserve for parsing the string
|
|
547
|
+
*/
|
|
548
|
+
Variant(String json, size_t capacity)
|
|
549
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
550
|
+
: jsonBuffer() {
|
|
551
|
+
#else
|
|
552
|
+
: jsonBuffer(capacity) {
|
|
553
|
+
#endif
|
|
554
|
+
error = deserializeJson(jsonBuffer, json,
|
|
555
|
+
DeserializationOption::NestingLimit(255));
|
|
556
|
+
if (!error) jsonObj = jsonBuffer.as<JsonObject>();
|
|
557
|
+
}
|
|
558
|
+
#endif
|
|
559
|
+
/**
|
|
560
|
+
* Create Variant object from any package implementing PackageInterface
|
|
561
|
+
*/
|
|
562
|
+
Variant(const PackageInterface* pkg)
|
|
563
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
564
|
+
: jsonBuffer() {
|
|
565
|
+
#else
|
|
566
|
+
: jsonBuffer(pkg->jsonObjectSize()) {
|
|
567
|
+
#endif
|
|
568
|
+
jsonObj = jsonBuffer.to<JsonObject>();
|
|
569
|
+
jsonObj = pkg->addTo(std::move(jsonObj));
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Create Variant object from a Single package
|
|
574
|
+
*
|
|
575
|
+
* @param single The single package
|
|
576
|
+
*/
|
|
577
|
+
Variant(Single single)
|
|
578
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
579
|
+
: jsonBuffer() {
|
|
580
|
+
#else
|
|
581
|
+
: jsonBuffer(single.jsonObjectSize()) {
|
|
582
|
+
#endif
|
|
583
|
+
jsonObj = jsonBuffer.to<JsonObject>();
|
|
584
|
+
jsonObj = single.addTo(std::move(jsonObj));
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Create Variant object from a Broadcast package
|
|
589
|
+
*
|
|
590
|
+
* @param broadcast The broadcast package
|
|
591
|
+
*/
|
|
592
|
+
Variant(Broadcast broadcast)
|
|
593
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
594
|
+
: jsonBuffer() {
|
|
595
|
+
#else
|
|
596
|
+
: jsonBuffer(broadcast.jsonObjectSize()) {
|
|
597
|
+
#endif
|
|
598
|
+
jsonObj = jsonBuffer.to<JsonObject>();
|
|
599
|
+
jsonObj = broadcast.addTo(std::move(jsonObj));
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Create Variant object from a NodeTree
|
|
604
|
+
*
|
|
605
|
+
* @param nodeTree The NodeTree
|
|
606
|
+
*/
|
|
607
|
+
Variant(NodeTree nodeTree)
|
|
608
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
609
|
+
: jsonBuffer() {
|
|
610
|
+
#else
|
|
611
|
+
: jsonBuffer(nodeTree.jsonObjectSize()) {
|
|
612
|
+
#endif
|
|
613
|
+
jsonObj = jsonBuffer.to<JsonObject>();
|
|
614
|
+
jsonObj = nodeTree.addTo(std::move(jsonObj));
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Create Variant object from a NodeSyncReply package
|
|
619
|
+
*
|
|
620
|
+
* @param nodeSyncReply The nodeSyncReply package
|
|
621
|
+
*/
|
|
622
|
+
Variant(NodeSyncReply nodeSyncReply)
|
|
623
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
624
|
+
: jsonBuffer() {
|
|
625
|
+
#else
|
|
626
|
+
: jsonBuffer(nodeSyncReply.jsonObjectSize()) {
|
|
627
|
+
#endif
|
|
628
|
+
jsonObj = jsonBuffer.to<JsonObject>();
|
|
629
|
+
jsonObj = nodeSyncReply.addTo(std::move(jsonObj));
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Create Variant object from a NodeSyncRequest package
|
|
634
|
+
*
|
|
635
|
+
* @param nodeSyncRequest The nodeSyncRequest package
|
|
636
|
+
*/
|
|
637
|
+
Variant(NodeSyncRequest nodeSyncRequest)
|
|
638
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
639
|
+
: jsonBuffer() {
|
|
640
|
+
#else
|
|
641
|
+
: jsonBuffer(nodeSyncRequest.jsonObjectSize()) {
|
|
642
|
+
#endif
|
|
643
|
+
jsonObj = jsonBuffer.to<JsonObject>();
|
|
644
|
+
jsonObj = nodeSyncRequest.addTo(std::move(jsonObj));
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Create Variant object from a TimeSync package
|
|
649
|
+
*
|
|
650
|
+
* @param timeSync The timeSync package
|
|
651
|
+
*/
|
|
652
|
+
Variant(TimeSync timeSync)
|
|
653
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
654
|
+
: jsonBuffer() {
|
|
655
|
+
#else
|
|
656
|
+
: jsonBuffer(timeSync.jsonObjectSize()) {
|
|
657
|
+
#endif
|
|
658
|
+
jsonObj = jsonBuffer.to<JsonObject>();
|
|
659
|
+
jsonObj = timeSync.addTo(std::move(jsonObj));
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Create Variant object from a TimeDelay package
|
|
664
|
+
*
|
|
665
|
+
* @param timeDelay The timeDelay package
|
|
666
|
+
*/
|
|
667
|
+
Variant(TimeDelay timeDelay)
|
|
668
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
669
|
+
: jsonBuffer() {
|
|
670
|
+
#else
|
|
671
|
+
: jsonBuffer(timeDelay.jsonObjectSize()) {
|
|
672
|
+
#endif
|
|
673
|
+
jsonObj = jsonBuffer.to<JsonObject>();
|
|
674
|
+
jsonObj = timeDelay.addTo(std::move(jsonObj));
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Whether this package is of the given type
|
|
679
|
+
*/
|
|
680
|
+
template <typename T>
|
|
681
|
+
inline bool is() {
|
|
682
|
+
return false;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Convert Variant to the given type
|
|
687
|
+
*/
|
|
688
|
+
template <typename T>
|
|
689
|
+
inline T to() {
|
|
690
|
+
return T(jsonObj);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Return package type
|
|
695
|
+
*/
|
|
696
|
+
int type() { return jsonObj["type"].as<int>(); }
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Package routing method
|
|
700
|
+
*/
|
|
701
|
+
router::Type routing() {
|
|
702
|
+
#if ARDUINOJSON_VERSION_MAJOR < 7
|
|
703
|
+
if (jsonObj.containsKey("routing"))
|
|
704
|
+
#else
|
|
705
|
+
if (jsonObj["routing"].is<int>())
|
|
706
|
+
#endif
|
|
707
|
+
return (router::Type)jsonObj["routing"].as<int>();
|
|
708
|
+
|
|
709
|
+
auto type = this->type();
|
|
710
|
+
if (type == SINGLE || type == TIME_DELAY) return router::SINGLE;
|
|
711
|
+
if (type == BROADCAST) return router::BROADCAST;
|
|
712
|
+
if (type == NODE_SYNC_REQUEST || type == NODE_SYNC_REPLY ||
|
|
713
|
+
type == TIME_SYNC)
|
|
714
|
+
return router::NEIGHBOUR;
|
|
715
|
+
return router::ROUTING_ERROR;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Destination node of the package
|
|
720
|
+
*/
|
|
721
|
+
uint32_t dest() {
|
|
722
|
+
#if ARDUINOJSON_VERSION_MAJOR < 7
|
|
723
|
+
if (jsonObj.containsKey("dest")) return jsonObj["dest"].as<uint32_t>();
|
|
724
|
+
#else
|
|
725
|
+
if (jsonObj["dest"].is<uint32_t>()) return jsonObj["dest"].as<uint32_t>();
|
|
726
|
+
#endif
|
|
727
|
+
return 0;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
#ifdef ARDUINOJSON_ENABLE_STD_STRING
|
|
731
|
+
/**
|
|
732
|
+
* Print a variant to a string
|
|
733
|
+
*
|
|
734
|
+
* @return A json representation of the string
|
|
735
|
+
*/
|
|
736
|
+
void printTo(std::string& str, bool pretty = false) {
|
|
737
|
+
if (pretty)
|
|
738
|
+
serializeJsonPretty(jsonObj, str);
|
|
739
|
+
else
|
|
740
|
+
serializeJson(jsonObj, str);
|
|
741
|
+
}
|
|
742
|
+
#endif
|
|
743
|
+
|
|
744
|
+
#ifdef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
|
745
|
+
/**
|
|
746
|
+
* Print a variant to a string
|
|
747
|
+
*
|
|
748
|
+
* @return A json representation of the string
|
|
749
|
+
*/
|
|
750
|
+
void printTo(String& str, bool pretty = false) {
|
|
751
|
+
if (pretty)
|
|
752
|
+
serializeJsonPretty(jsonObj, str);
|
|
753
|
+
else
|
|
754
|
+
serializeJson(jsonObj, str);
|
|
755
|
+
}
|
|
756
|
+
#endif
|
|
757
|
+
|
|
758
|
+
DeserializationError error = DeserializationError::Ok;
|
|
759
|
+
|
|
760
|
+
private:
|
|
761
|
+
#if ARDUINOJSON_VERSION_MAJOR == 7
|
|
762
|
+
JsonDocument jsonBuffer;
|
|
763
|
+
#else
|
|
764
|
+
DynamicJsonDocument jsonBuffer;
|
|
765
|
+
#endif
|
|
766
|
+
JsonObject jsonObj;
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
template <>
|
|
770
|
+
inline bool Variant::is<Single>() {
|
|
771
|
+
return jsonObj["type"].as<int>() == SINGLE;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
template <>
|
|
775
|
+
inline bool Variant::is<Broadcast>() {
|
|
776
|
+
return jsonObj["type"].as<int>() == BROADCAST;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
template <>
|
|
780
|
+
inline bool Variant::is<NodeSyncReply>() {
|
|
781
|
+
return jsonObj["type"].as<int>() == NODE_SYNC_REPLY;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
template <>
|
|
785
|
+
inline bool Variant::is<NodeSyncRequest>() {
|
|
786
|
+
return jsonObj["type"].as<int>() == NODE_SYNC_REQUEST;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
template <>
|
|
790
|
+
inline bool Variant::is<TimeSync>() {
|
|
791
|
+
return jsonObj["type"].as<int>() == TIME_SYNC;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
template <>
|
|
795
|
+
inline bool Variant::is<TimeDelay>() {
|
|
796
|
+
return jsonObj["type"].as<int>() == TIME_DELAY;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
template <>
|
|
800
|
+
inline JsonObject Variant::to<JsonObject>() {
|
|
801
|
+
return jsonObj;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
inline TSTRING NodeTree::toString(bool pretty) {
|
|
805
|
+
TSTRING str;
|
|
806
|
+
auto variant = Variant(*this);
|
|
807
|
+
variant.printTo(str, pretty);
|
|
808
|
+
return str;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
} // namespace protocol
|
|
812
|
+
} // namespace painlessmesh
|
|
813
|
+
#endif
|