初始化提交
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Wrapper file, which is used to test on PC hardware
|
||||
*/
|
||||
#ifndef ARDUINO_WRAP_H
|
||||
#define ARDUINO_WRAP_H
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define F(string_literal) string_literal
|
||||
#define ARDUINO_ARCH_ESP8266
|
||||
#define PAINLESSMESH_BOOST
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
inline unsigned long millis() {
|
||||
struct timeval te;
|
||||
gettimeofday(&te, NULL); // get current time
|
||||
long long milliseconds =
|
||||
te.tv_sec * 1000LL + te.tv_usec / 1000; // calculate milliseconds
|
||||
// printf("milliseconds: %lld\n", milliseconds);
|
||||
return milliseconds;
|
||||
}
|
||||
|
||||
inline unsigned long micros() {
|
||||
struct timeval te;
|
||||
gettimeofday(&te, NULL); // get current time
|
||||
long long milliseconds = te.tv_sec * 1000000LL + te.tv_usec;
|
||||
return milliseconds;
|
||||
}
|
||||
|
||||
inline void delay(int i) { usleep(i); }
|
||||
|
||||
inline void yield() {}
|
||||
|
||||
struct IPAddress {
|
||||
IPAddress() {}
|
||||
IPAddress(int, int, int, int) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Override the configution file.
|
||||
**/
|
||||
|
||||
#ifndef _PAINLESS_MESH_CONFIGURATION_HPP_
|
||||
#define _PAINLESS_MESH_CONFIGURATION_HPP_
|
||||
|
||||
#define _TASK_PRIORITY // Support for layered scheduling priority
|
||||
#define _TASK_STD_FUNCTION
|
||||
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
#define ARDUINOJSON_USE_LONG_LONG 1
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#undef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||
|
||||
#define ICACHE_FLASH_ATTR
|
||||
|
||||
#define PAINLESSMESH_ENABLE_STD_STRING
|
||||
|
||||
// Enable OTA support
|
||||
#define PAINLESSMESH_ENABLE_OTA
|
||||
|
||||
#define NODE_TIMEOUT 5 * TASK_SECOND
|
||||
|
||||
typedef std::string TSTRING;
|
||||
|
||||
#ifdef ESP32
|
||||
#define MAX_CONN 10
|
||||
#else
|
||||
#define MAX_CONN 4
|
||||
#endif // DEBUG
|
||||
|
||||
#include "fake_asynctcp.hpp"
|
||||
#include "fake_serial.hpp"
|
||||
|
||||
extern WiFiClass WiFi;
|
||||
extern ESPClass ESP;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
#include "painlessmesh/configuration.hpp"
|
||||
|
||||
#include "painlessmesh/base64.hpp"
|
||||
|
||||
#include "catch_utils.hpp"
|
||||
|
||||
SCENARIO("Base64 encoding can succesfully be decoded") {
|
||||
using namespace painlessmesh;
|
||||
auto bindata = randomString(100);
|
||||
auto enc = base64::encode(bindata);
|
||||
auto dec = base64::decode(enc);
|
||||
REQUIRE(dec.length() > 0);
|
||||
REQUIRE(dec == bindata);
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
#define ARDUINOJSON_USE_LONG_LONG 1
|
||||
#include "ArduinoJson.h"
|
||||
#undef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||
#undef PAINLESSMESH_ENABLE_ARDUINO_STRING
|
||||
#define PAINLESSMESH_ENABLE_STD_STRING
|
||||
typedef std::string TSTRING;
|
||||
|
||||
#include "catch_utils.hpp"
|
||||
|
||||
#include "painlessmesh/buffer.hpp"
|
||||
|
||||
using namespace painlessmesh::buffer;
|
||||
|
||||
SCENARIO("ReceiveBuffer receives strings and needs to process them") {
|
||||
temp_buffer_t tmp_buffer;
|
||||
char cstring[3 * tmp_buffer.length];
|
||||
ReceiveBuffer<std::string> rBuffer = ReceiveBuffer<std::string>();
|
||||
|
||||
GIVEN("A random string of short length pushed to the received buffer") {
|
||||
REQUIRE(rBuffer.empty());
|
||||
auto length = runif(10, tmp_buffer.length - 10);
|
||||
randomCString(cstring, length);
|
||||
// Note we need to send a \0 to know this is the end
|
||||
rBuffer.push(cstring, length + 1, tmp_buffer);
|
||||
THEN("It gets copied to the front of the buffer") {
|
||||
REQUIRE(!rBuffer.empty());
|
||||
REQUIRE(rBuffer.front() == std::string(cstring));
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A random string of long length pushed to the received buffer") {
|
||||
REQUIRE(rBuffer.empty());
|
||||
auto length = runif(tmp_buffer.length + 10, 2 * tmp_buffer.length);
|
||||
randomCString(cstring, length);
|
||||
// Note we need to send a \0 to know this is the end
|
||||
rBuffer.push(cstring, length + 1, tmp_buffer);
|
||||
THEN("It gets copied to the front of the buffer") {
|
||||
REQUIRE(!rBuffer.empty());
|
||||
REQUIRE(rBuffer.front() == std::string(cstring));
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A random string we can push it in multiple parts") {
|
||||
REQUIRE(rBuffer.empty());
|
||||
auto length = runif(tmp_buffer.length + 10, 2 * tmp_buffer.length);
|
||||
size_t part_len = length / 2;
|
||||
randomCString(cstring, length);
|
||||
rBuffer.push(cstring, part_len, tmp_buffer);
|
||||
THEN("The first part doesn't get copied to the front of the buffer") {
|
||||
REQUIRE(rBuffer.empty());
|
||||
}
|
||||
|
||||
auto data_ptr = cstring + sizeof(char) * part_len;
|
||||
rBuffer.push(data_ptr, length - part_len + 1, tmp_buffer);
|
||||
THEN(
|
||||
"When getting the second part the whole thing gets copied to the front "
|
||||
"of the buffer") {
|
||||
REQUIRE(!rBuffer.empty());
|
||||
REQUIRE(rBuffer.front() == std::string(cstring));
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("ReceiveBuffer can receive multiple messages and hold them all") {
|
||||
REQUIRE(rBuffer.empty());
|
||||
for (size_t i = 0; i < 10; ++i) {
|
||||
auto length = runif(tmp_buffer.length + 10, 2 * tmp_buffer.length);
|
||||
size_t part_len = length / 2;
|
||||
randomCString(cstring, length);
|
||||
rBuffer.push(cstring, part_len, tmp_buffer);
|
||||
auto data_ptr = cstring + sizeof(char) * part_len;
|
||||
rBuffer.push(data_ptr, length - part_len + 1, tmp_buffer);
|
||||
}
|
||||
THEN(
|
||||
"When getting the second part the whole thing gets copied to the front "
|
||||
"of the buffer") {
|
||||
REQUIRE(!rBuffer.empty());
|
||||
for (size_t i = 0; i < 10; ++i) {
|
||||
REQUIRE(!rBuffer.empty());
|
||||
rBuffer.pop_front();
|
||||
}
|
||||
REQUIRE(rBuffer.empty());
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN(
|
||||
"ReceiveBuffer can receive multiple messages in one char string "
|
||||
"(separated by \0") {
|
||||
REQUIRE(rBuffer.empty());
|
||||
auto length = runif(10, tmp_buffer.length - 10);
|
||||
randomCString(cstring, length);
|
||||
auto data_ptr = cstring + sizeof(char) * (length + 1);
|
||||
auto length2 = runif(10, tmp_buffer.length - 10);
|
||||
randomCString(data_ptr, length2);
|
||||
|
||||
// Note we need to send a \0 to know this is the end
|
||||
rBuffer.push(cstring, length + length2 + 2, tmp_buffer);
|
||||
THEN("We have both strings in the buffer") {
|
||||
REQUIRE(!rBuffer.empty());
|
||||
REQUIRE(rBuffer.front() == std::string(cstring));
|
||||
rBuffer.pop_front();
|
||||
REQUIRE(!rBuffer.empty());
|
||||
REQUIRE(rBuffer.front() == std::string(data_ptr));
|
||||
rBuffer.pop_front();
|
||||
REQUIRE(rBuffer.empty());
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN(
|
||||
"ReceiveBuffer has copied the message we can overwrite the previous "
|
||||
"cstring and buffer without affecting the outcome") {
|
||||
REQUIRE(rBuffer.empty());
|
||||
cstring[0] = 'B';
|
||||
cstring[1] = 'l';
|
||||
cstring[2] = 'a';
|
||||
cstring[3] = 'a';
|
||||
cstring[4] = 't';
|
||||
cstring[5] = '\0';
|
||||
rBuffer.push(cstring, 3, tmp_buffer);
|
||||
cstring[0] = 'r';
|
||||
cstring[1] = 'n';
|
||||
cstring[2] = 'd';
|
||||
randomCString(tmp_buffer.buffer, tmp_buffer.length);
|
||||
auto data_ptr = cstring + sizeof(char) * 3;
|
||||
rBuffer.push(data_ptr, 3, tmp_buffer);
|
||||
THEN("We still have the correct result") {
|
||||
REQUIRE(rBuffer.front() == std::string("Blaat"));
|
||||
REQUIRE(std::string(cstring) != std::string("Blaat"));
|
||||
REQUIRE(std::string(tmp_buffer.buffer, 6) != std::string("Blaat"));
|
||||
REQUIRE(std::string(tmp_buffer.buffer, 5) != std::string("Blaat"));
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A buffer with multiple messages") {
|
||||
REQUIRE(rBuffer.empty());
|
||||
for (size_t i = 0; i < 10; ++i) {
|
||||
auto length = runif(tmp_buffer.length + 10, 2 * tmp_buffer.length);
|
||||
size_t part_len = length / 2;
|
||||
randomCString(cstring, length);
|
||||
rBuffer.push(cstring, part_len, tmp_buffer);
|
||||
auto data_ptr = cstring + sizeof(char) * part_len;
|
||||
rBuffer.push(data_ptr, length - part_len + 1, tmp_buffer);
|
||||
}
|
||||
THEN("We can clear it") {
|
||||
REQUIRE(!rBuffer.empty());
|
||||
rBuffer.clear();
|
||||
REQUIRE(rBuffer.empty());
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A buffer with a half written message") {
|
||||
REQUIRE(rBuffer.empty());
|
||||
for (size_t i = 0; i < 10; ++i) {
|
||||
auto length = runif(tmp_buffer.length + 10, 2 * tmp_buffer.length);
|
||||
size_t part_len = length / 2;
|
||||
randomCString(cstring, length);
|
||||
rBuffer.push(cstring, part_len, tmp_buffer);
|
||||
auto data_ptr = cstring + sizeof(char) * part_len;
|
||||
rBuffer.push(data_ptr, length - part_len + 1, tmp_buffer);
|
||||
}
|
||||
auto length = runif(tmp_buffer.length + 10, 2 * tmp_buffer.length);
|
||||
size_t part_len = length / 2;
|
||||
randomCString(cstring, length);
|
||||
rBuffer.push(cstring, part_len, tmp_buffer);
|
||||
|
||||
THEN("We can clear removes it") {
|
||||
REQUIRE(!rBuffer.empty());
|
||||
rBuffer.clear();
|
||||
REQUIRE(rBuffer.empty());
|
||||
}
|
||||
rBuffer.clear();
|
||||
randomCString(cstring, length);
|
||||
rBuffer.push(cstring, length + 1, tmp_buffer);
|
||||
THEN("Reusing it works correctly") {
|
||||
REQUIRE(rBuffer.front() == std::string(cstring));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("SentBuffer receives strings and can be read in parts") {
|
||||
temp_buffer_t tmp_buffer;
|
||||
SentBuffer<std::string> sBuffer = SentBuffer<std::string>();
|
||||
GIVEN("A SentBuffer and a string") {
|
||||
auto length = runif(0, tmp_buffer.length - 10);
|
||||
auto msg = randomString(length);
|
||||
THEN("We can pass strings to it") {
|
||||
REQUIRE(sBuffer.empty());
|
||||
sBuffer.push(msg);
|
||||
REQUIRE(!sBuffer.empty());
|
||||
}
|
||||
THEN("We can pass it and read it back") {
|
||||
REQUIRE(sBuffer.empty());
|
||||
sBuffer.push(msg);
|
||||
REQUIRE(!sBuffer.empty());
|
||||
auto rlength = sBuffer.requestLength(2 * length);
|
||||
REQUIRE(rlength <= 2 * length);
|
||||
sBuffer.read(rlength, tmp_buffer);
|
||||
if (rlength == msg.length() + 1)
|
||||
REQUIRE(std::string(tmp_buffer.buffer, msg.length()) == msg);
|
||||
|
||||
// Test free read as well
|
||||
sBuffer.freeRead();
|
||||
if (rlength == msg.length() + 1) REQUIRE(sBuffer.empty());
|
||||
}
|
||||
}
|
||||
|
||||
// We can read in multiple parts
|
||||
GIVEN("A long string passed to the SentBuffer") {
|
||||
size_t length = runif(tmp_buffer.length + 10, 2 * tmp_buffer.length - 10);
|
||||
auto msg = randomString(length);
|
||||
sBuffer.push(msg);
|
||||
char cstring[length + 1];
|
||||
auto data_ptr = cstring;
|
||||
THEN("We can read it in multiple parts") {
|
||||
while (!sBuffer.empty()) {
|
||||
auto rlength = sBuffer.requestLength(tmp_buffer.length);
|
||||
sBuffer.read(rlength, tmp_buffer);
|
||||
memcpy(data_ptr, tmp_buffer.buffer, rlength);
|
||||
data_ptr += rlength * sizeof(char);
|
||||
sBuffer.freeRead();
|
||||
}
|
||||
REQUIRE(std::string(cstring) == msg);
|
||||
}
|
||||
|
||||
THEN("We can use direct access to read it in multiple parts") {
|
||||
while (!sBuffer.empty()) {
|
||||
auto rlength = sBuffer.requestLength(tmp_buffer.length);
|
||||
auto ptr = sBuffer.readPtr(rlength);
|
||||
memcpy(data_ptr, ptr, rlength);
|
||||
data_ptr += rlength * sizeof(char);
|
||||
sBuffer.freeRead();
|
||||
}
|
||||
REQUIRE(std::string(cstring) == msg);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN(
|
||||
"We have read a message halfway, priority messages can safely be added") {
|
||||
size_t length = runif(tmp_buffer.length + 10, 2 * tmp_buffer.length - 10);
|
||||
auto msg1 = randomString(length);
|
||||
auto msg2 = randomString(length);
|
||||
auto msgH = randomString(length);
|
||||
sBuffer.push(msg1);
|
||||
char cstring[3 * length + 3];
|
||||
auto data_ptr = cstring;
|
||||
THEN("We can read it in multiple parts") {
|
||||
auto rlength = sBuffer.requestLength(tmp_buffer.length);
|
||||
|
||||
// Read first message halfway
|
||||
sBuffer.read(rlength, tmp_buffer);
|
||||
memcpy(data_ptr, tmp_buffer.buffer, rlength);
|
||||
data_ptr += rlength * sizeof(char);
|
||||
sBuffer.freeRead();
|
||||
sBuffer.push(msg2);
|
||||
sBuffer.push(msgH, true);
|
||||
|
||||
// Read the rest of the messages
|
||||
while (!sBuffer.empty()) {
|
||||
rlength = sBuffer.requestLength(tmp_buffer.length);
|
||||
sBuffer.read(rlength, tmp_buffer);
|
||||
memcpy(data_ptr, tmp_buffer.buffer, rlength);
|
||||
data_ptr += rlength * sizeof(char);
|
||||
sBuffer.freeRead();
|
||||
}
|
||||
REQUIRE(std::string(cstring) == msg1);
|
||||
REQUIRE(std::string(cstring + length + 1) == msgH);
|
||||
REQUIRE(std::string(cstring + 2 * (length + 1)) == msg2);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A SentBuffer with a message in it") {
|
||||
auto length = runif(0, tmp_buffer.length - 10);
|
||||
auto msg = randomString(length);
|
||||
sBuffer.push(msg);
|
||||
|
||||
REQUIRE(!sBuffer.empty());
|
||||
THEN("Clear will empty it") {
|
||||
sBuffer.clear();
|
||||
REQUIRE(sBuffer.empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "catch_utils.hpp"
|
||||
|
||||
#include "painlessmesh/callback.hpp"
|
||||
|
||||
using namespace painlessmesh;
|
||||
|
||||
logger::LogClass Log;
|
||||
|
||||
SCENARIO("CallbackMap should hold multiple callbacks by ID") {
|
||||
GIVEN("A callback map with added callbacks") {
|
||||
auto cbl = callback::PackageCallbackList<int>();
|
||||
|
||||
auto i = 0;
|
||||
auto j = 0;
|
||||
|
||||
cbl.onPackage(1, [&i](int z) { ++i; });
|
||||
cbl.onPackage(1, [&j](int z) { ++j; });
|
||||
|
||||
WHEN("We call execute") {
|
||||
auto cnt = cbl.execute(1, 0);
|
||||
REQUIRE(cnt == 2);
|
||||
THEN("The callbacks are called") {
|
||||
REQUIRE(i == 1);
|
||||
REQUIRE(j == 1);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We call execute on another event") {
|
||||
auto cnt = cbl.execute(2, 0);
|
||||
REQUIRE(cnt == 0);
|
||||
THEN("The callbacks are not called") {
|
||||
REQUIRE(i == 0);
|
||||
REQUIRE(j == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
#define ARDUINOJSON_USE_LONG_LONG 1
|
||||
#include "ArduinoJson.h"
|
||||
#undef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||
#undef PAINLESSMESH_ENABLE_ARDUINO_STRING
|
||||
#define PAINLESSMESH_ENABLE_STD_STRING
|
||||
typedef std::string TSTRING;
|
||||
|
||||
#include "catch_utils.hpp"
|
||||
|
||||
#include "painlessmesh/layout.hpp"
|
||||
#include "painlessmesh/protocol.hpp"
|
||||
|
||||
using namespace painlessmesh;
|
||||
|
||||
SCENARIO("isRoot returns true if the top level Node is the root of the mesh") {
|
||||
GIVEN("A nodeTree with root as a top node") {
|
||||
std::string rootJson =
|
||||
"{\"type\":6,\"root\":true,\"dest\":2428398258,\"from\":3907768579,"
|
||||
"\"subs\":[{"
|
||||
"\"nodeId\":3959373838,\"subs\":[{\"nodeId\":416992913},{\"nodeId\":"
|
||||
"1895675348}]}]}";
|
||||
auto variant = protocol::Variant(rootJson);
|
||||
auto tree1 = variant.to<protocol::NodeTree>();
|
||||
THEN("isRoot returns true") { REQUIRE(layout::isRoot(tree1)); }
|
||||
}
|
||||
GIVEN("A nodeTree without a root as a top node") {
|
||||
std::string jsonTree1 =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3907768579,\"nodeId\":"
|
||||
"3907768579,\"subs\":[{\"nodeId\":3959373838,\"subs\":[{\"nodeId\":"
|
||||
"416992913},{\"nodeId\":1895675348,\"root\":true}]}]}";
|
||||
auto variant1 = protocol::Variant(jsonTree1);
|
||||
auto tree1 = variant1.to<protocol::NodeTree>();
|
||||
std::string jsonTree2 =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3907768579,\"nodeId\":"
|
||||
"3907768579,\"subs\":[{\"nodeId\":3959373838,\"subs\":[{\"nodeId\":"
|
||||
"416992913},{\"nodeId\":1895675348,\"root\":true}]}]}";
|
||||
auto variant2 = protocol::Variant(jsonTree2);
|
||||
auto tree2 = variant2.to<protocol::NodeTree>();
|
||||
THEN("isRoot returns false") {
|
||||
REQUIRE(!layout::isRoot(tree1));
|
||||
REQUIRE(!layout::isRoot(tree2));
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A random tree with a root at top level") {
|
||||
auto tree1 = createNodeTree(runif(1, 255), 0);
|
||||
THEN("isRoot returns true") { REQUIRE(layout::isRoot(tree1)); }
|
||||
}
|
||||
|
||||
GIVEN("A random tree with no root at top level") {
|
||||
auto noNodes = runif(2, 255);
|
||||
auto tree1 = createNodeTree(noNodes, runif(1, noNodes - 1));
|
||||
auto tree2 = createNodeTree(runif(1, 255), -1);
|
||||
THEN("isRoot returns false") {
|
||||
REQUIRE(!layout::isRoot(tree1));
|
||||
REQUIRE(!layout::isRoot(tree2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("isRooted returns true if any node in the mesh is the root node") {
|
||||
GIVEN("A nodeTree with root as a top node") {
|
||||
std::string rootJson =
|
||||
"{\"type\":6,\"root\":true,\"dest\":2428398258,\"from\":3907768579,"
|
||||
"\"subs\":[{"
|
||||
"\"nodeId\":3959373838,\"subs\":[{\"nodeId\":416992913},{\"nodeId\":"
|
||||
"1895675348}]}]}";
|
||||
auto variant = protocol::Variant(rootJson);
|
||||
auto tree1 = variant.to<protocol::NodeTree>();
|
||||
THEN("isRooted returns true") { REQUIRE(layout::isRooted(tree1)); }
|
||||
}
|
||||
GIVEN("A nodeTree with a root some where else") {
|
||||
std::string jsonTree1 =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3907768579,\"nodeId\":"
|
||||
"3907768579,\"subs\":[{\"nodeId\":3959373838,\"subs\":[{\"nodeId\":"
|
||||
"416992913},{\"nodeId\":1895675348,\"root\":true}]}]}";
|
||||
auto variant1 = protocol::Variant(jsonTree1);
|
||||
auto tree1 = variant1.to<protocol::NodeTree>();
|
||||
THEN("isRooted returns true") { REQUIRE(layout::isRooted(tree1)); }
|
||||
}
|
||||
|
||||
GIVEN("A nodeTree without a root any where else") {
|
||||
std::string jsonTree2 =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3907768579,\"nodeId\":"
|
||||
"3907768579,\"subs\":[{\"nodeId\":3959373838,\"subs\":[{\"nodeId\":"
|
||||
"416992913},{\"nodeId\":1895675348,\"root\":true}]}]}";
|
||||
auto variant2 = protocol::Variant(jsonTree2);
|
||||
auto tree2 = variant2.to<protocol::NodeTree>();
|
||||
THEN("isRooted returns false") { REQUIRE(!layout::isRoot(tree2)); }
|
||||
}
|
||||
|
||||
GIVEN("A random tree with a root") {
|
||||
auto noNodes = runif(1, 255);
|
||||
auto tree1 = createNodeTree(noNodes, runif(0, noNodes - 1));
|
||||
THEN("isRooted returns true") { REQUIRE(layout::isRooted(tree1)); }
|
||||
}
|
||||
|
||||
GIVEN("A random tree without a root") {
|
||||
auto tree1 = createNodeTree(runif(1, 255), -1);
|
||||
THEN("isRooted returns false") { REQUIRE(!layout::isRooted(tree1)); }
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("We can get the size of the mesh") {
|
||||
GIVEN("A tree with a set size") {
|
||||
std::string jsonTree =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3907768579,\"nodeId\":"
|
||||
"3907768579,\"subs\":[{\"nodeId\":3959373838,\"subs\":[{\"nodeId\":"
|
||||
"416992913},{\"nodeId\":1895675348,\"root\":true}]}]}";
|
||||
auto variant = protocol::Variant(jsonTree);
|
||||
auto tree = variant.to<protocol::NodeTree>();
|
||||
THEN("Size returns the correct size") { REQUIRE(layout::size(tree) == 4); }
|
||||
}
|
||||
GIVEN("A random tree with a set size") {
|
||||
auto noNodes = runif(1, 255);
|
||||
auto tree = createNodeTree(noNodes, runif(-1, noNodes - 1));
|
||||
THEN("Size returns the correct size") {
|
||||
REQUIRE(layout::size(tree) == noNodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("We can confirm whether a mesh contains specific nodes") {
|
||||
GIVEN("A tree with known nodes") {
|
||||
std::string jsonTree =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3107768579,\"nodeId\":"
|
||||
"3907768579,\"subs\":[{\"nodeId\":3959373838,\"subs\":[{\"nodeId\":"
|
||||
"416992913},{\"nodeId\":1895675348,\"root\":true}]}]}";
|
||||
auto variant = protocol::Variant(jsonTree);
|
||||
auto tree = variant.to<protocol::NodeTree>();
|
||||
THEN(
|
||||
"contains should return the true when it contains a node, false "
|
||||
"otherwise") {
|
||||
REQUIRE(layout::contains(tree, 1895675348));
|
||||
REQUIRE(layout::contains(tree, 3907768579));
|
||||
REQUIRE(layout::contains(tree, 3959373838));
|
||||
REQUIRE(!layout::contains(tree, 0));
|
||||
REQUIRE(!layout::contains(tree, 2428398258));
|
||||
REQUIRE(!layout::contains(tree, 3107768579));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("A layout neighbour knows when to update its sub") {
|
||||
GIVEN("A Neighbour") {
|
||||
std::string jsonTree =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3107768579,\"nodeId\":"
|
||||
"3907768579,\"subs\":[{\"nodeId\":3959373838,\"subs\":[{\"nodeId\":"
|
||||
"416992913},{\"nodeId\":1895675348,\"root\":true}]}]}";
|
||||
auto variant = protocol::Variant(jsonTree);
|
||||
auto tree = variant.to<layout::Neighbour>();
|
||||
// auto neighbour = std::interpret_cast<layout::Neighbour*>(pTree);
|
||||
auto neighbour = tree;
|
||||
THEN("When passed the same tree updateSubs() will return false") {
|
||||
REQUIRE(!neighbour.updateSubs(tree));
|
||||
}
|
||||
|
||||
auto tree1 = createNodeTree(runif(2, 5), -1);
|
||||
tree1.nodeId = neighbour.nodeId;
|
||||
THEN("When passing a different tree it will get updated") {
|
||||
REQUIRE(neighbour.updateSubs(tree1));
|
||||
REQUIRE(tree1 == neighbour);
|
||||
}
|
||||
|
||||
THEN("When current nodeId is zero then updateSubs() will return true") {
|
||||
neighbour.nodeId = 0;
|
||||
REQUIRE(neighbour.updateSubs(tree));
|
||||
REQUIRE(neighbour == tree);
|
||||
REQUIRE(neighbour.nodeId == tree.nodeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "painlessmesh/logger.hpp"
|
||||
using namespace painlessmesh::logger;
|
||||
|
||||
LogClass Log;
|
||||
|
||||
SCENARIO("We can log things") {
|
||||
Log.setLogLevel(ERROR | DEBUG | COMMUNICATION);
|
||||
Log(ERROR, "We should see the next %u lines\n", 3);
|
||||
Log(DEBUG, "We should see the next %u lines\n", 2);
|
||||
Log(COMMUNICATION, "We should see the next %u lines\n", 1);
|
||||
Log(ERROR, "But not the next one\n");
|
||||
Log(S_TIME, "This should not be showing\n");
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "catch_utils.hpp"
|
||||
|
||||
#include "painlessmesh/ntp.hpp"
|
||||
|
||||
using namespace painlessmesh;
|
||||
|
||||
logger::LogClass Log;
|
||||
@@ -0,0 +1,174 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#include "catch_utils.hpp"
|
||||
|
||||
#include "painlessmesh/plugin.hpp"
|
||||
#include "plugin/performance.hpp"
|
||||
|
||||
using namespace painlessmesh;
|
||||
|
||||
logger::LogClass Log;
|
||||
|
||||
class CustomPackage : public plugin::SinglePackage {
|
||||
public:
|
||||
double sensor = 1.0;
|
||||
|
||||
CustomPackage() : SinglePackage(20) {}
|
||||
|
||||
CustomPackage(JsonObject jsonObj) : SinglePackage(jsonObj) {
|
||||
sensor = jsonObj["sensor"];
|
||||
}
|
||||
|
||||
JsonObject addTo(JsonObject&& jsonObj) const {
|
||||
jsonObj = SinglePackage::addTo(std::move(jsonObj));
|
||||
jsonObj["sensor"] = sensor;
|
||||
return jsonObj;
|
||||
}
|
||||
|
||||
size_t jsonObjectSize() const { return JSON_OBJECT_SIZE(noJsonFields + 1); }
|
||||
};
|
||||
|
||||
class BCustomPackage : public plugin::BroadcastPackage {
|
||||
public:
|
||||
double sensor = 1.0;
|
||||
|
||||
BCustomPackage() : BroadcastPackage(21) {}
|
||||
|
||||
BCustomPackage(JsonObject jsonObj) : BroadcastPackage(jsonObj) {
|
||||
sensor = jsonObj["sensor"];
|
||||
}
|
||||
|
||||
JsonObject addTo(JsonObject&& jsonObj) const {
|
||||
jsonObj = BroadcastPackage::addTo(std::move(jsonObj));
|
||||
jsonObj["sensor"] = sensor;
|
||||
return jsonObj;
|
||||
}
|
||||
|
||||
size_t jsonObjectSize() const { return JSON_OBJECT_SIZE(noJsonFields + 1); }
|
||||
};
|
||||
|
||||
class MockConnection : public layout::Neighbour {
|
||||
public:
|
||||
bool addMessage(TSTRING msg) { return true; }
|
||||
};
|
||||
|
||||
SCENARIO("We can send a custom package") {
|
||||
GIVEN("A package") {
|
||||
auto pkg = CustomPackage();
|
||||
pkg.from = 1;
|
||||
pkg.dest = 2;
|
||||
pkg.sensor = 0.5;
|
||||
REQUIRE(pkg.routing == router::SINGLE);
|
||||
REQUIRE(pkg.type == 20);
|
||||
WHEN("Converting it to and from Variant") {
|
||||
auto var = protocol::Variant(&pkg);
|
||||
auto pkg2 = var.to<CustomPackage>();
|
||||
THEN("Should result in the same values") {
|
||||
REQUIRE(pkg2.sensor == pkg.sensor);
|
||||
REQUIRE(pkg2.from == pkg.from);
|
||||
REQUIRE(pkg2.dest == pkg.dest);
|
||||
REQUIRE(pkg2.routing == pkg.routing);
|
||||
REQUIRE(pkg2.type == pkg.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A broadcast package") {
|
||||
auto pkg = BCustomPackage();
|
||||
pkg.from = 1;
|
||||
pkg.sensor = 0.5;
|
||||
REQUIRE(pkg.routing == router::BROADCAST);
|
||||
REQUIRE(pkg.type == 21);
|
||||
WHEN("Converting it to and from Variant") {
|
||||
auto var = protocol::Variant(&pkg);
|
||||
auto pkg2 = var.to<CustomPackage>();
|
||||
THEN("Should result in the same values") {
|
||||
REQUIRE(pkg2.sensor == pkg.sensor);
|
||||
REQUIRE(pkg2.from == pkg.from);
|
||||
REQUIRE(pkg2.routing == pkg.routing);
|
||||
REQUIRE(pkg2.type == pkg.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A package handler function") {
|
||||
auto handler = plugin::PackageHandler<MockConnection>();
|
||||
auto func = [](protocol::Variant variant) {
|
||||
auto pkg = variant.to<CustomPackage>();
|
||||
REQUIRE(pkg.routing == router::BROADCAST);
|
||||
return false;
|
||||
};
|
||||
THEN("We can pass it to handler") { handler.onPackage(20, func); }
|
||||
}
|
||||
|
||||
GIVEN("A package") {
|
||||
auto handler = plugin::PackageHandler<MockConnection>();
|
||||
auto pkg = CustomPackage();
|
||||
THEN("We can call sendPackage") {
|
||||
auto res = handler.sendPackage(&pkg);
|
||||
REQUIRE(!res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("We can add tasks to the taskscheduler") {
|
||||
GIVEN("A couple of tasks added") {
|
||||
Scheduler mScheduler;
|
||||
auto handler = plugin::PackageHandler<MockConnection>();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
auto task1 = handler.addTask(mScheduler, 0, 1, [&i]() { ++i; });
|
||||
auto task2 = handler.addTask(mScheduler, 0, 3, [&j]() { ++j; });
|
||||
auto task3 = handler.addTask(mScheduler, 0, 3, [&k]() { ++k; });
|
||||
auto task4 = handler.addTask(mScheduler, 0, 3, []() {});
|
||||
|
||||
WHEN("Executing the tasks") {
|
||||
THEN("They should be called and automatically removed") {
|
||||
REQUIRE(i == 0);
|
||||
REQUIRE(j == 0);
|
||||
mScheduler.execute();
|
||||
REQUIRE(i == 1);
|
||||
mScheduler.execute();
|
||||
REQUIRE(i == 1);
|
||||
REQUIRE(j == 2);
|
||||
// Still kept in handler, because hasn't been executed 3 times yet
|
||||
task3->disable();
|
||||
handler.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("We can add anonymous tasks to the taskscheduler") {
|
||||
GIVEN("A couple of tasks added") {
|
||||
Scheduler mScheduler;
|
||||
auto handler = plugin::PackageHandler<MockConnection>();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
handler.addTask(mScheduler, 0, 1, [&i]() { ++i; });
|
||||
handler.addTask(mScheduler, 0, 3, [&j]() { ++j; });
|
||||
handler.addTask(mScheduler, 0, 3, [&k]() { ++k; });
|
||||
|
||||
WHEN("Executing the tasks") {
|
||||
THEN("They should be called and automatically removed") {
|
||||
REQUIRE(i == 0);
|
||||
REQUIRE(j == 0);
|
||||
mScheduler.execute();
|
||||
REQUIRE(i == 1);
|
||||
mScheduler.execute();
|
||||
REQUIRE(i == 1);
|
||||
REQUIRE(j == 2);
|
||||
handler.addTask(mScheduler, 0, 1, [&i]() { ++i; });
|
||||
mScheduler.execute();
|
||||
REQUIRE(i == 2);
|
||||
handler.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,556 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
#define ARDUINOJSON_USE_LONG_LONG 1
|
||||
#include "ArduinoJson.h"
|
||||
#undef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||
typedef std::string TSTRING;
|
||||
|
||||
#include "catch_utils.hpp"
|
||||
#include "painlessmesh/protocol.hpp"
|
||||
|
||||
using namespace painlessmesh::protocol;
|
||||
|
||||
SCENARIO("A variant knows its type", "[Variant][protocol]") {
|
||||
GIVEN("A json string with the type 9 ") {
|
||||
std::string str = "{\"type\": 9}";
|
||||
WHEN("Passed to a Variant") {
|
||||
auto variant = Variant(str);
|
||||
|
||||
THEN("The variant is a Single type") {
|
||||
REQUIRE(variant.is<Single>());
|
||||
REQUIRE(!variant.is<Broadcast>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A json string with the type 8 ") {
|
||||
std::string str = "{\"type\": 8}";
|
||||
WHEN("Passed to a Variant") {
|
||||
auto variant = Variant(str);
|
||||
|
||||
THEN("The variant is a Broadcast type") {
|
||||
REQUIRE(!variant.is<Single>());
|
||||
REQUIRE(variant.is<Broadcast>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A json string with the type 6 ") {
|
||||
std::string str = "{\"type\": 6}";
|
||||
WHEN("Passed to a Variant") {
|
||||
auto variant = Variant(str);
|
||||
|
||||
THEN("The variant is a NodeSyncReply type") {
|
||||
REQUIRE(!variant.is<Single>());
|
||||
REQUIRE(!variant.is<Broadcast>());
|
||||
REQUIRE(variant.is<NodeSyncReply>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A json string with the type 5 ") {
|
||||
std::string str = "{\"type\": 5}";
|
||||
WHEN("Passed to a Variant") {
|
||||
auto variant = Variant(str);
|
||||
|
||||
THEN("The variant is a NodeSyncRequest type") {
|
||||
REQUIRE(!variant.is<Single>());
|
||||
REQUIRE(!variant.is<Broadcast>());
|
||||
REQUIRE(!variant.is<NodeSyncReply>());
|
||||
REQUIRE(variant.is<NodeSyncRequest>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A json string with the type 4 ") {
|
||||
std::string str = "{\"type\": 4}";
|
||||
WHEN("Passed to a Variant") {
|
||||
auto variant = Variant(str);
|
||||
|
||||
THEN("The variant is a TimeSync type") {
|
||||
REQUIRE(!variant.is<Single>());
|
||||
REQUIRE(!variant.is<Broadcast>());
|
||||
REQUIRE(!variant.is<NodeSyncReply>());
|
||||
REQUIRE(!variant.is<NodeSyncRequest>());
|
||||
REQUIRE(variant.is<TimeSync>());
|
||||
}
|
||||
}
|
||||
}
|
||||
GIVEN("A json string with the type 3 ") {
|
||||
std::string str = "{\"type\": 3}";
|
||||
WHEN("Passed to a Variant") {
|
||||
auto variant = Variant(str);
|
||||
|
||||
THEN("The variant is a TimeDelay type") {
|
||||
REQUIRE(!variant.is<Single>());
|
||||
REQUIRE(!variant.is<Broadcast>());
|
||||
REQUIRE(!variant.is<NodeSyncReply>());
|
||||
REQUIRE(!variant.is<NodeSyncRequest>());
|
||||
REQUIRE(!variant.is<TimeSync>());
|
||||
REQUIRE(variant.is<TimeDelay>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SCENARIO("A variant can take a packageinterface", "[Variant][protocol]") {
|
||||
GIVEN("A Single package") {
|
||||
auto pkg = createSingle();
|
||||
WHEN("Passed to a Variant") {
|
||||
auto variant = Variant(&pkg);
|
||||
THEN("The variant is a Single type") {
|
||||
REQUIRE(variant.is<Single>());
|
||||
REQUIRE(!variant.is<Broadcast>());
|
||||
REQUIRE(!variant.is<NodeSyncReply>());
|
||||
REQUIRE(!variant.is<NodeSyncRequest>());
|
||||
REQUIRE(!variant.is<TimeSync>());
|
||||
REQUIRE(!variant.is<TimeDelay>());
|
||||
}
|
||||
|
||||
THEN("The variant can be converted to a Single") {
|
||||
auto newPkg = variant.to<Single>();
|
||||
REQUIRE(newPkg.dest == pkg.dest);
|
||||
REQUIRE(newPkg.from == pkg.from);
|
||||
REQUIRE(newPkg.msg == pkg.msg);
|
||||
REQUIRE(newPkg.type == pkg.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("A variant can take any package", "[Variant][protocol]") {
|
||||
GIVEN("A Single package") {
|
||||
auto pkg = createSingle();
|
||||
WHEN("Passed to a Variant") {
|
||||
auto variant = Variant(pkg);
|
||||
THEN("The variant is a Single type") {
|
||||
REQUIRE(variant.is<Single>());
|
||||
REQUIRE(!variant.is<Broadcast>());
|
||||
REQUIRE(!variant.is<NodeSyncReply>());
|
||||
REQUIRE(!variant.is<NodeSyncRequest>());
|
||||
REQUIRE(!variant.is<TimeSync>());
|
||||
REQUIRE(!variant.is<TimeDelay>());
|
||||
}
|
||||
|
||||
THEN("The variant can be converted to a Single") {
|
||||
auto newPkg = variant.to<Single>();
|
||||
REQUIRE(newPkg.dest == pkg.dest);
|
||||
REQUIRE(newPkg.from == pkg.from);
|
||||
REQUIRE(newPkg.msg == pkg.msg);
|
||||
REQUIRE(newPkg.type == pkg.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A Broadcast package") {
|
||||
auto pkg = createBroadcast(5);
|
||||
WHEN("Passed to a Variant") {
|
||||
auto variant = Variant(pkg);
|
||||
THEN("The variant is a Broadcast type") {
|
||||
REQUIRE(!variant.is<Single>());
|
||||
REQUIRE(variant.is<Broadcast>());
|
||||
REQUIRE(!variant.is<NodeSyncReply>());
|
||||
REQUIRE(!variant.is<NodeSyncRequest>());
|
||||
REQUIRE(!variant.is<TimeSync>());
|
||||
REQUIRE(!variant.is<TimeDelay>());
|
||||
}
|
||||
|
||||
THEN("The variant can be converted to a Broadcast") {
|
||||
auto newPkg = variant.to<Broadcast>();
|
||||
REQUIRE(newPkg.dest == pkg.dest);
|
||||
REQUIRE(newPkg.from == pkg.from);
|
||||
REQUIRE(newPkg.msg == pkg.msg);
|
||||
REQUIRE(newPkg.type == pkg.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A NodeSyncReply package") {
|
||||
auto pkg = createNodeSyncReply(15);
|
||||
WHEN("Passed to a Variant") {
|
||||
auto variant = Variant(pkg);
|
||||
THEN("The variant is a NodeSyncReply type") {
|
||||
REQUIRE(!variant.is<Single>());
|
||||
REQUIRE(!variant.is<Broadcast>());
|
||||
REQUIRE(variant.is<NodeSyncReply>());
|
||||
REQUIRE(!variant.is<NodeSyncRequest>());
|
||||
REQUIRE(!variant.is<TimeSync>());
|
||||
REQUIRE(!variant.is<TimeDelay>());
|
||||
}
|
||||
THEN("The variant can be converted to a NodeSyncReply") {
|
||||
auto newPkg = variant.to<NodeSyncReply>();
|
||||
REQUIRE(newPkg.dest == pkg.dest);
|
||||
REQUIRE(newPkg.from == pkg.from);
|
||||
REQUIRE(newPkg.nodeId == pkg.nodeId);
|
||||
REQUIRE(newPkg.root == pkg.root);
|
||||
REQUIRE(newPkg.subs.size() == pkg.subs.size());
|
||||
REQUIRE(newPkg.type == pkg.type);
|
||||
REQUIRE(newPkg == pkg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A NodeSyncReply package of random size") {
|
||||
auto pkg = createNodeSyncReply();
|
||||
WHEN("Passed to a Variant") {
|
||||
auto variant = Variant(pkg);
|
||||
|
||||
THEN("The variant throws no error") { REQUIRE(!variant.error); }
|
||||
THEN("The variant is a NodeSyncReply type") {
|
||||
REQUIRE(!variant.is<Single>());
|
||||
REQUIRE(!variant.is<Broadcast>());
|
||||
REQUIRE(variant.is<NodeSyncReply>());
|
||||
REQUIRE(!variant.is<NodeSyncRequest>());
|
||||
REQUIRE(!variant.is<TimeSync>());
|
||||
REQUIRE(!variant.is<TimeDelay>());
|
||||
}
|
||||
THEN("The variant can be converted to a NodeSyncReply") {
|
||||
auto newPkg = variant.to<NodeSyncReply>();
|
||||
REQUIRE(newPkg.dest == pkg.dest);
|
||||
REQUIRE(newPkg.from == pkg.from);
|
||||
REQUIRE(newPkg.nodeId == pkg.nodeId);
|
||||
REQUIRE(newPkg.root == pkg.root);
|
||||
REQUIRE(newPkg.subs.size() == pkg.subs.size());
|
||||
REQUIRE(newPkg.type == pkg.type);
|
||||
REQUIRE(newPkg == pkg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A NodeSyncRequest package") {
|
||||
auto pkg = createNodeSyncRequest(5);
|
||||
WHEN("Passed to a Variant") {
|
||||
auto variant = Variant(pkg);
|
||||
THEN("The variant is a NodeSyncRequest type") {
|
||||
REQUIRE(!variant.is<Single>());
|
||||
REQUIRE(!variant.is<Broadcast>());
|
||||
REQUIRE(!variant.is<NodeSyncReply>());
|
||||
REQUIRE(variant.is<NodeSyncRequest>());
|
||||
REQUIRE(!variant.is<TimeSync>());
|
||||
REQUIRE(!variant.is<TimeDelay>());
|
||||
}
|
||||
THEN("The variant can be converted to a NodeSyncRequest") {
|
||||
auto newPkg = variant.to<NodeSyncRequest>();
|
||||
REQUIRE(newPkg.dest == pkg.dest);
|
||||
REQUIRE(newPkg.from == pkg.from);
|
||||
REQUIRE(newPkg.nodeId == pkg.nodeId);
|
||||
REQUIRE(newPkg.root == pkg.root);
|
||||
REQUIRE(newPkg.subs.size() == pkg.subs.size());
|
||||
REQUIRE(newPkg.type == pkg.type);
|
||||
REQUIRE(newPkg == pkg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A TimeSync package") {
|
||||
auto pkg = createTimeSync();
|
||||
WHEN("Passed to a Variant") {
|
||||
auto variant = Variant(pkg);
|
||||
THEN("The variant is a TimeSync type") {
|
||||
REQUIRE(!variant.is<Single>());
|
||||
REQUIRE(!variant.is<Broadcast>());
|
||||
REQUIRE(!variant.is<NodeSyncReply>());
|
||||
REQUIRE(!variant.is<NodeSyncRequest>());
|
||||
REQUIRE(variant.is<TimeSync>());
|
||||
REQUIRE(!variant.is<TimeDelay>());
|
||||
}
|
||||
|
||||
THEN("The variant can be converted to a TimeSync") {
|
||||
auto newPkg = variant.to<TimeSync>();
|
||||
REQUIRE(newPkg.dest == pkg.dest);
|
||||
REQUIRE(newPkg.from == pkg.from);
|
||||
REQUIRE(newPkg.type == pkg.type);
|
||||
REQUIRE(newPkg.msg.type == pkg.msg.type);
|
||||
REQUIRE(newPkg.msg.t0 == pkg.msg.t0);
|
||||
REQUIRE(newPkg.msg.t1 == pkg.msg.t1);
|
||||
REQUIRE(newPkg.msg.t2 == pkg.msg.t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A TimeDelay package") {
|
||||
auto pkg = createTimeDelay();
|
||||
WHEN("Passed to a Variant") {
|
||||
auto variant = Variant(pkg);
|
||||
THEN("The variant is a TimeDelay type") {
|
||||
REQUIRE(!variant.is<Single>());
|
||||
REQUIRE(!variant.is<Broadcast>());
|
||||
REQUIRE(!variant.is<NodeSyncReply>());
|
||||
REQUIRE(!variant.is<NodeSyncRequest>());
|
||||
REQUIRE(!variant.is<TimeSync>());
|
||||
REQUIRE(variant.is<TimeDelay>());
|
||||
}
|
||||
THEN("The variant can be converted to a TimeDelay") {
|
||||
auto newPkg = variant.to<TimeDelay>();
|
||||
REQUIRE(newPkg.dest == pkg.dest);
|
||||
REQUIRE(newPkg.from == pkg.from);
|
||||
REQUIRE(newPkg.type == pkg.type);
|
||||
REQUIRE(newPkg.msg.type == pkg.msg.type);
|
||||
REQUIRE(newPkg.msg.t0 == pkg.msg.t0);
|
||||
REQUIRE(newPkg.msg.t1 == pkg.msg.t1);
|
||||
REQUIRE(newPkg.msg.t2 == pkg.msg.t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("NodeSyncReply is backwards compatible", "[Variant][protocol]") {
|
||||
GIVEN("A json string without a base nodeId") {
|
||||
std::string old =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3907768579,\"subs\":[{"
|
||||
"\"nodeId\":3959373838,\"subs\":[{\"nodeId\":416992913},{\"nodeId\":"
|
||||
"1895675348,\"root\":true}]}]}";
|
||||
std::string withId =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3907768579,\"nodeId\":"
|
||||
"3907768579,\"subs\":[{\"nodeId\":3959373838,\"subs\":[{\"nodeId\":"
|
||||
"416992913},{\"nodeId\":1895675348,\"root\":true}]}]}";
|
||||
WHEN("Converted to a NodeSyncReply") {
|
||||
auto variant = Variant(old);
|
||||
auto nsr = variant.to<NodeSyncReply>();
|
||||
auto variantId = Variant(withId);
|
||||
auto nsrId = variantId.to<NodeSyncReply>();
|
||||
THEN("NodeId is set to from") {
|
||||
REQUIRE(nsr.from == nsr.nodeId);
|
||||
REQUIRE(nsr == nsrId);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("Converted to a NodeTree") {
|
||||
auto variant = Variant(old);
|
||||
auto ns = variant.to<NodeTree>();
|
||||
auto variantId = Variant(withId);
|
||||
auto nsId = variantId.to<NodeTree>();
|
||||
auto variantReply = Variant(withId);
|
||||
auto nsrId = variantId.to<NodeSyncReply>();
|
||||
THEN("NodeId is set to from value") {
|
||||
REQUIRE(nsrId.from == ns.nodeId);
|
||||
REQUIRE(nsrId.nodeId == nsId.nodeId);
|
||||
REQUIRE(nsrId.subs == ns.subs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A json string with root explicitly set to false") {
|
||||
std::string old =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3907768579,\"nodeId\":"
|
||||
"3907768579,\"subs\":[{\"nodeId\":3959373838,\"subs\":[{\"nodeId\":"
|
||||
"416992913},{\"nodeId\":1895675348,\"root\":true}]}]}";
|
||||
std::string withId =
|
||||
"{\"type\":6,\"dest\":2428398258,\"root\":false,\"from\":3907768579,"
|
||||
"\"nodeId\":3907768579,\"subs\":[{\"nodeId\":3959373838,\"subs\":[{"
|
||||
"\"nodeId\":416992913},{\"nodeId\":1895675348,\"root\":true}]}]}";
|
||||
WHEN("Converted to a NodeSyncReply") {
|
||||
auto variant = Variant(old);
|
||||
auto nsr = variant.to<NodeSyncReply>();
|
||||
auto variantId = Variant(withId);
|
||||
auto nsrId = variantId.to<NodeSyncReply>();
|
||||
THEN("NodeId is set to from") { REQUIRE(nsr == nsrId); }
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A json string with subs explicitly set to empty") {
|
||||
std::string old =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3907768579,\"nodeId\":"
|
||||
"3907768579,\"subs\":[{\"nodeId\":3959373838,\"subs\":[{\"nodeId\":"
|
||||
"416992913},{\"nodeId\":1895675348,\"root\":true,\"subs\":[]}]}]}";
|
||||
std::string withId =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3907768579,\"nodeId\":"
|
||||
"3907768579,\"subs\":[{\"nodeId\":3959373838,\"subs\":[{\"nodeId\":"
|
||||
"416992913},{\"nodeId\":1895675348,\"root\":true}]}]}";
|
||||
WHEN("Converted to a NodeSyncReply") {
|
||||
auto variant = Variant(old);
|
||||
auto nsr = variant.to<NodeSyncReply>();
|
||||
auto variantId = Variant(withId);
|
||||
auto nsrId = variantId.to<NodeSyncReply>();
|
||||
THEN("NodeId is set to from") { REQUIRE(nsr == nsrId); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("NodeSyncReply supports the == operator", "[Variant][protocol]") {
|
||||
GIVEN("Different NodeSyncReplies") {
|
||||
auto pkg1 = createNodeSyncReply(5);
|
||||
auto pkg2 = createNodeSyncReply(5);
|
||||
|
||||
// Same subs different base
|
||||
auto pkg3 = createNodeSyncReply(5);
|
||||
auto pkg4 = createNodeSyncReply(5);
|
||||
pkg4.subs = pkg3.subs;
|
||||
|
||||
// Same base different subs
|
||||
auto pkg5 = pkg4;
|
||||
pkg5.subs = pkg1.subs;
|
||||
THEN("They are not equal") {
|
||||
REQUIRE(pkg1 != pkg2);
|
||||
REQUIRE(pkg2 == pkg2);
|
||||
REQUIRE(!(pkg2 != pkg2));
|
||||
REQUIRE(!(pkg1 != pkg1));
|
||||
|
||||
REQUIRE(pkg3 != pkg4);
|
||||
REQUIRE(pkg3.subs == pkg4.subs);
|
||||
|
||||
REQUIRE(pkg5 != pkg4);
|
||||
REQUIRE(pkg5.subs != pkg4.subs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("A variant can printTo a package", "[Variant][protocol]") {
|
||||
GIVEN("A NodeSyncReply package printed to a string using Variant") {
|
||||
auto pkg = createNodeSyncReply(5);
|
||||
std::string str;
|
||||
auto variant = Variant(pkg);
|
||||
variant.printTo(str);
|
||||
THEN("It can be converted back into an identical pkg") {
|
||||
auto variant = Variant(str);
|
||||
auto pkg2 = variant.to<NodeSyncReply>();
|
||||
REQUIRE(pkg2 == pkg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("The Variant type properly carries over errors",
|
||||
"[Variant][protocol][error]") {
|
||||
GIVEN("A large and small NodeSyncReply pkg") {
|
||||
auto large_pkg = createNodeSyncReply(100);
|
||||
auto large_variant = Variant(large_pkg);
|
||||
std::string large_json;
|
||||
large_variant.printTo(large_json);
|
||||
|
||||
auto small_pkg = createNodeSyncReply(5);
|
||||
auto small_variant = Variant(small_pkg);
|
||||
std::string small_json;
|
||||
small_variant.printTo(small_json);
|
||||
|
||||
THEN("It carries over the ArduinoJson error") {
|
||||
auto large_var = Variant(large_json, 1024);
|
||||
REQUIRE(large_var.error);
|
||||
auto small_var = Variant(small_json, 1024);
|
||||
REQUIRE(!small_var.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO(
|
||||
"The construction of a Time package automatically sets the correct time "
|
||||
"sync type",
|
||||
"[protocol]") {
|
||||
GIVEN("Calling the constructor with no time") {
|
||||
auto pkg1 = TimeSync(10, 11);
|
||||
THEN("The time type is TIME_SYNC_REQUEST") {
|
||||
REQUIRE(pkg1.msg.type == TIME_SYNC_REQUEST);
|
||||
}
|
||||
}
|
||||
GIVEN("Calling the constructor with one time") {
|
||||
auto pkg1 = TimeSync(10, 11, 12);
|
||||
THEN("The time type is TIME_REQUEST") {
|
||||
REQUIRE(pkg1.msg.type == TIME_REQUEST);
|
||||
REQUIRE(pkg1.msg.t0 == 12);
|
||||
}
|
||||
}
|
||||
GIVEN("Calling the constructor with two or three times") {
|
||||
auto pkg2 = TimeSync(10, 11, 12, 13);
|
||||
auto pkg3 = TimeSync(10, 11, 12, 13, 14);
|
||||
THEN("The time type is TIME_REPLY") {
|
||||
REQUIRE(pkg2.msg.type == TIME_REPLY);
|
||||
REQUIRE(pkg2.msg.t0 == 12);
|
||||
REQUIRE(pkg2.msg.t1 == 13);
|
||||
REQUIRE(pkg3.msg.type == TIME_REPLY);
|
||||
REQUIRE(pkg3.msg.t0 == 12);
|
||||
REQUIRE(pkg3.msg.t1 == 13);
|
||||
REQUIRE(pkg3.msg.t2 == 14);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Calling the constructor with no time") {
|
||||
auto pkg1 = TimeDelay(10, 11);
|
||||
THEN("The time type is TIME_SYNC_REQUEST") {
|
||||
REQUIRE(pkg1.msg.type == TIME_SYNC_REQUEST);
|
||||
}
|
||||
}
|
||||
GIVEN("Calling the constructor with one time") {
|
||||
auto pkg1 = TimeDelay(10, 11, 12);
|
||||
THEN("The time type is TIME_REQUEST") {
|
||||
REQUIRE(pkg1.msg.type == TIME_REQUEST);
|
||||
REQUIRE(pkg1.msg.t0 == 12);
|
||||
}
|
||||
}
|
||||
GIVEN("Calling the constructor with two or three times") {
|
||||
auto pkg2 = TimeDelay(10, 11, 12, 13);
|
||||
auto pkg3 = TimeDelay(10, 11, 12, 13, 14);
|
||||
THEN("The time type is TIME_REPLY") {
|
||||
REQUIRE(pkg2.msg.type == TIME_REPLY);
|
||||
REQUIRE(pkg2.msg.t0 == 12);
|
||||
REQUIRE(pkg2.msg.t1 == 13);
|
||||
REQUIRE(pkg3.msg.type == TIME_REPLY);
|
||||
REQUIRE(pkg3.msg.t0 == 12);
|
||||
REQUIRE(pkg3.msg.t1 == 13);
|
||||
REQUIRE(pkg3.msg.t2 == 14);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("We can construct a reply to Time packages", "[protocol]") {
|
||||
GIVEN("A reply to a TIME_SYNC_REQUEST") {
|
||||
auto origPkg1 = TimeSync(10, 11);
|
||||
auto pkg1 = TimeSync(10, 11);
|
||||
pkg1.reply(12);
|
||||
auto origPkg2 = TimeDelay(10, 11);
|
||||
auto pkg2 = TimeDelay(10, 11);
|
||||
pkg2.reply(12);
|
||||
THEN("It will set t0, update type and swap from and dest.") {
|
||||
REQUIRE(pkg1.msg.type == TIME_REQUEST);
|
||||
REQUIRE(pkg2.msg.type == TIME_REQUEST);
|
||||
REQUIRE(pkg1.msg.t0 == 12);
|
||||
REQUIRE(pkg2.msg.t0 == 12);
|
||||
REQUIRE(pkg1.from == origPkg1.dest);
|
||||
REQUIRE(pkg2.from == origPkg2.dest);
|
||||
REQUIRE(pkg1.dest == origPkg1.from);
|
||||
REQUIRE(pkg2.dest == origPkg2.from);
|
||||
REQUIRE(pkg1.type == origPkg1.type);
|
||||
REQUIRE(pkg2.type == origPkg2.type);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A reply to a TIME_REQUEST") {
|
||||
auto origPkg1 = TimeSync(10, 11, 12);
|
||||
auto pkg1 = TimeSync(10, 11, 12);
|
||||
pkg1.reply(13, 14);
|
||||
auto origPkg2 = TimeDelay(10, 11, 12);
|
||||
auto pkg2 = TimeDelay(10, 11, 12);
|
||||
pkg2.reply(13, 14);
|
||||
THEN("It will set t1 and t2, update type and swap from and dest.") {
|
||||
REQUIRE(pkg1.msg.type == TIME_REPLY);
|
||||
REQUIRE(pkg2.msg.type == TIME_REPLY);
|
||||
REQUIRE(pkg1.msg.t0 == 12);
|
||||
REQUIRE(pkg2.msg.t0 == 12);
|
||||
REQUIRE(pkg1.msg.t1 == 13);
|
||||
REQUIRE(pkg2.msg.t1 == 13);
|
||||
REQUIRE(pkg1.msg.t2 == 14);
|
||||
REQUIRE(pkg2.msg.t2 == 14);
|
||||
REQUIRE(pkg1.from == origPkg1.dest);
|
||||
REQUIRE(pkg2.from == origPkg2.dest);
|
||||
REQUIRE(pkg1.dest == origPkg1.from);
|
||||
REQUIRE(pkg2.dest == origPkg2.from);
|
||||
REQUIRE(pkg1.type == origPkg1.type);
|
||||
REQUIRE(pkg2.type == origPkg2.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("Package constructors work as expected", "[protocol]") {
|
||||
GIVEN("A Single package constructed with the constructor") {
|
||||
std::string str = "Blaat";
|
||||
auto pkg = Single(10, 0, str);
|
||||
THEN("Message will be set correctly") { REQUIRE(pkg.msg == "Blaat"); }
|
||||
}
|
||||
GIVEN("A Broadcast package constructed with the constructor") {
|
||||
std::string str = "Blaat";
|
||||
auto pkg = Broadcast(10, 0, str);
|
||||
THEN("Message will be set correctly") {
|
||||
REQUIRE(pkg.msg == "Blaat");
|
||||
REQUIRE(pkg.type == BROADCAST);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "catch_utils.hpp"
|
||||
|
||||
#include "painlessmesh/router.hpp"
|
||||
|
||||
using namespace painlessmesh;
|
||||
|
||||
logger::LogClass Log;
|
||||
|
||||
/*
|
||||
class MockConnection : public protocol::NodeTree {
|
||||
public:
|
||||
void addMessage(TSTRING msg, bool priority = false) { ++cnt; }
|
||||
|
||||
int cnt = 0;
|
||||
};
|
||||
|
||||
SCENARIO("findRoute works as expected with different types of connections") {
|
||||
GIVEN("A layout with Neighbour shared ptrs") {
|
||||
auto layout = layout::Layout<layout::Neighbour>();
|
||||
std::string jsonTree1 =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3107768579,\"nodeId\":"
|
||||
"3907768579,\"subs\":[{\"nodeId\":3959373838,\"subs\":[{\"nodeId\":"
|
||||
"416992913},{\"nodeId\":1895675348}]}]}";
|
||||
auto variant1 = protocol::Variant(jsonTree1);
|
||||
auto tree1 =
|
||||
std::make_shared<layout::Neighbour>(variant1.to<layout::Neighbour>());
|
||||
|
||||
std::string jsonTree2 =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3107768579,\"nodeId\":"
|
||||
"3907768580,\"subs\":[{\"nodeId\":3959373839,\"subs\":[{\"nodeId\":"
|
||||
"416992914},{\"nodeId\":1895675349}]}]}";
|
||||
auto variant2 = protocol::Variant(jsonTree2);
|
||||
auto tree2 =
|
||||
std::make_shared<layout::Neighbour>(variant2.to<layout::Neighbour>());
|
||||
|
||||
std::string jsonTree3 =
|
||||
"{\"type\":6,\"dest\":2428398258,\"from\":3107768579,\"nodeId\":"
|
||||
"3907768581,\"subs\":[{\"nodeId\":3959373840,\"subs\":[{\"nodeId\":"
|
||||
"416992915},{\"nodeId\":1895675350}]}]}";
|
||||
auto variant3 = protocol::Variant(jsonTree3);
|
||||
auto tree3 =
|
||||
std::make_shared<layout::Neighbour>(variant3.to<layout::Neighbour>());
|
||||
|
||||
layout.subs.push_back(tree1);
|
||||
layout.subs.push_back(tree2);
|
||||
layout.subs.push_back(tree3);
|
||||
|
||||
layout.nodeId = runif(1, 1000);
|
||||
|
||||
THEN("findRoute works") {
|
||||
auto rt = router::findRoute<layout::Neighbour>(layout, 1895675350);
|
||||
REQUIRE(rt->nodeId == 3907768581);
|
||||
rt = router::findRoute<layout::Neighbour>(layout, 1895675351);
|
||||
REQUIRE(!rt);
|
||||
}
|
||||
|
||||
THEN("It can be converted to a NodeTree") {
|
||||
auto lay = layout.asNodeTree();
|
||||
auto nt = protocol::NodeTree();
|
||||
nt.nodeId = lay.nodeId;
|
||||
for (auto &&s : lay.subs) {
|
||||
nt.subs.push_back(s);
|
||||
}
|
||||
REQUIRE(nt == lay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("routePackage should route the package correctly") {
|
||||
GIVEN("A CallbackList and layout") {
|
||||
auto cbl = router::CallbackList();
|
||||
auto lay = layout::Layout<MockConnection>();
|
||||
lay.nodeId = 1;
|
||||
lay.subs.push_back(std::make_shared<MockConnection>());
|
||||
lay.subs.back()->nodeId = 2;
|
||||
lay.subs.push_back(std::make_shared<MockConnection>());
|
||||
lay.subs.back()->nodeId = 3;
|
||||
lay.subs.push_back(std::make_shared<MockConnection>());
|
||||
lay.subs.back()->nodeId = 4;
|
||||
|
||||
// void routePackage(Layout<T>, T conn, TSTRING pkg, CallbackMap)
|
||||
WHEN("Passed a package with routing NEIGHBOUR") {
|
||||
auto pkg = createTimeSync();
|
||||
TSTRING str;
|
||||
auto var = protocol::Variant(pkg);
|
||||
REQUIRE(var.routing() == router::NEIGHBOUR);
|
||||
var.printTo(str);
|
||||
// message type NEIGHBOUR should result in a callback
|
||||
}
|
||||
|
||||
// message type BROADCAST should result in a callback and being send on
|
||||
|
||||
// message type SINGLE if destination is other then send otherwise callback
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,49 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#include "catch_utils.hpp"
|
||||
|
||||
WiFiClass WiFi;
|
||||
ESPClass ESP;
|
||||
|
||||
#include "painlessmesh/logger.hpp"
|
||||
|
||||
using namespace painlessmesh;
|
||||
|
||||
logger::LogClass Log;
|
||||
|
||||
SCENARIO("Fake Async classes behave similar to real ones") {
|
||||
int i = 0;
|
||||
std::string j = "";
|
||||
auto server = AsyncServer();
|
||||
AsyncClient *conn;
|
||||
server.onClient([&conn, &i, &j](void *, AsyncClient *client) {
|
||||
conn = client;
|
||||
conn->onData([&j](void *, AsyncClient *client, void *data,
|
||||
size_t len) { j = std::string((char *)data, len); },
|
||||
NULL);
|
||||
++i;
|
||||
});
|
||||
|
||||
auto client = AsyncClient(&server);
|
||||
|
||||
std::string j2 = "";
|
||||
client.onData([&j2](void *arg, AsyncClient *client, void *data,
|
||||
size_t len) { j2 = std::string((char *)data, len); },
|
||||
NULL);
|
||||
|
||||
client.connect(IPAddress(), 0);
|
||||
|
||||
THEN("server.onConnect is called") { REQUIRE(i == 1); }
|
||||
THEN("I can send data") {
|
||||
client.write("Blaat", 5);
|
||||
REQUIRE(j == "Blaat");
|
||||
|
||||
conn->write("Blaat terug", 11);
|
||||
REQUIRE(j2 == "Blaat terug");
|
||||
}
|
||||
delete conn;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
DSM2_tx implements the serial communication protocol used for operating
|
||||
the RF modules that can be found in many DSM2-compatible transmitters.
|
||||
Copyrigt (C) 2012 Erik Elmore <erik@ironsavior.net>
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#include "fake_serial.hpp"
|
||||
|
||||
void FakeSerial::begin(unsigned long speed) { return; }
|
||||
|
||||
void FakeSerial::end() { return; }
|
||||
|
||||
size_t FakeSerial::write(const unsigned char buf[], size_t size) {
|
||||
using namespace std;
|
||||
ios_base::fmtflags oldFlags = cout.flags();
|
||||
streamsize oldPrec = cout.precision();
|
||||
char oldFill = cout.fill();
|
||||
|
||||
cout << "Serial::write: ";
|
||||
cout << internal << setfill('0');
|
||||
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
cout << setw(2) << hex << (unsigned int)buf[i] << " ";
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
cout.flags(oldFlags);
|
||||
cout.precision(oldPrec);
|
||||
cout.fill(oldFill);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void FakeSerial::print(const char* buf) { std::cout << buf; }
|
||||
|
||||
void FakeSerial::println() { std::cout << std::endl; }
|
||||
|
||||
FakeSerial Serial;
|
||||
Reference in New Issue
Block a user