mirror of
https://github.com/ratspeak/microReticulum
synced 2026-08-12 18:07:25 -04:00
Changed a few key logs to use printf-style instead of string concatenation to avoid dynamic memory allocation. Still need to move all remaining logging over to printf-style. Added option (-DRNS_USE_ALLOCATOR=1) to override new/delete operators for both allocation metrics and the ability to implement an alternate memory allocator. Added option (-DRNS_USE_TLSF=1) to use the alternate TLSF allocator (must also define RNS_USE_ALLOCATOR). This allocator is well known for reducing fragmentation and providing constant, O(1)-time allocation and deallocation for real-time embedded systems. This TLSF allocator appears to already be the default allocator for ESP32 boards, but the allocator used by NRF52 is unknown at this time so the TLSF allocator internal to microReticulum is only being used for NRF52 boards at this time. Future memory management improvements will include custom allocators for long-lived structures like the path table that will segregate them from the general pool of memory that is constantly cycling, thereby further reducing fragmentation. It will also allow these structures to use alternate memory like PSRAM present on T-Beam boards.
439 lines
12 KiB
C++
439 lines
12 KiB
C++
//#define NDEBUG
|
|
|
|
#include "Test/Test.h"
|
|
|
|
#include "Reticulum.h"
|
|
#include "Identity.h"
|
|
#include "Destination.h"
|
|
#include "Packet.h"
|
|
#include "Transport.h"
|
|
#include "Interface.h"
|
|
#include "Log.h"
|
|
#include "Bytes.h"
|
|
#include "Type.h"
|
|
#include "Interfaces/UDPInterface.h"
|
|
#include "Interfaces/LoRaInterface.h"
|
|
#include "Utilities/OS.h"
|
|
|
|
#ifdef ARDUINO
|
|
#include <Arduino.h>
|
|
#include <SPIFFS.h>
|
|
#else
|
|
#include <termios.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <functional>
|
|
//#include <sstream>
|
|
|
|
|
|
#ifndef NDEBUG
|
|
//#define RUN_TESTS
|
|
#endif
|
|
|
|
#define RUN_RETICULUM
|
|
#define UDP_INTERFACE
|
|
//#define UDP2_INTERFACE
|
|
#define LORA_INTERFACE
|
|
//#define RETICULUM_PACKET_TEST
|
|
|
|
#define BUTTON_PIN 38
|
|
//#define BUTTON_PIN_MASK GPIO_SEL_38
|
|
|
|
// Let's define an app name. We'll use this for all
|
|
// destinations we create. Since this basic example
|
|
// is part of a range of example utilities, we'll put
|
|
// them all within the app namespace "example_utilities"
|
|
const char* APP_NAME = "example_utilities";
|
|
|
|
// We initialise two lists of strings to use as app_data
|
|
const char* fruits[] = {"Peach", "Quince", "Date", "Tangerine", "Pomelo", "Carambola", "Grape"};
|
|
const char* noble_gases[] = {"Helium", "Neon", "Argon", "Krypton", "Xenon", "Radon", "Oganesson"};
|
|
|
|
double last_announce = 0.0;
|
|
bool send_announce = false;
|
|
|
|
// Test AnnounceHandler
|
|
class ExampleAnnounceHandler : public RNS::AnnounceHandler {
|
|
public:
|
|
ExampleAnnounceHandler(const char* aspect_filter = nullptr) : AnnounceHandler(aspect_filter) {}
|
|
virtual ~ExampleAnnounceHandler() {}
|
|
virtual void received_announce(const RNS::Bytes& destination_hash, const RNS::Identity& announced_identity, const RNS::Bytes& app_data) {
|
|
INFO("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
|
INFO("ExampleAnnounceHandler: destination hash: " + destination_hash.toHex());
|
|
if (announced_identity) {
|
|
INFO("ExampleAnnounceHandler: announced identity hash: " + announced_identity.hash().toHex());
|
|
INFO("ExampleAnnounceHandler: announced identity app data: " + announced_identity.app_data().toHex());
|
|
}
|
|
if (app_data) {
|
|
INFO("ExampleAnnounceHandler: app data text: \"" + app_data.toString() + "\"");
|
|
}
|
|
INFO("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
|
}
|
|
};
|
|
|
|
// Test packet receive callback
|
|
void onPacket(const RNS::Bytes& data, const RNS::Packet& packet) {
|
|
INFO("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
|
INFO("onPacket: data: " + data.toHex());
|
|
INFO("onPacket: text: \"" + data.toString() + "\"");
|
|
//TRACE("onPacket: " + packet.debugString());
|
|
INFO("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
|
}
|
|
|
|
// Ping packet receive callback
|
|
void onPingPacket(const RNS::Bytes& data, const RNS::Packet& packet) {
|
|
INFO("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
|
INFO("onPingPacket: data: " + data.toHex());
|
|
INFO("onPingPacket: text: \"" + data.toString() + "\"");
|
|
//TRACE("onPingPacket: " + packet.debugString());
|
|
INFO("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
|
}
|
|
|
|
|
|
#if defined(RUN_RETICULUM)
|
|
RNS::Reticulum reticulum({RNS::Type::NONE});
|
|
RNS::Identity identity({RNS::Type::NONE});
|
|
RNS::Destination destination({RNS::Type::NONE});
|
|
|
|
#ifdef UDP_INTERFACE
|
|
RNS::Interfaces::UDPInterface udp_interface("udp");
|
|
#endif
|
|
#ifdef UDP2_INTERFACE
|
|
RNS::Interfaces::UDPInterface udp2_interface("udp2");
|
|
#endif
|
|
#ifdef LORA_INTERFACE
|
|
RNS::Interfaces::LoRaInterface lora_interface;
|
|
#endif
|
|
|
|
//ExampleAnnounceHandler announce_handler((const char*)"example_utilities.announcesample.fruits");
|
|
//RNS::HAnnounceHandler announce_handler(new ExampleAnnounceHandler("example_utilities.announcesample.fruits"));
|
|
RNS::HAnnounceHandler announce_handler(new ExampleAnnounceHandler());
|
|
#endif
|
|
|
|
#if defined(RUN_TESTS)
|
|
void run_tests() {
|
|
|
|
try {
|
|
|
|
TRACE("Running tests...");
|
|
RNS::LogLevel loglevel = RNS::loglevel();
|
|
//RNS::loglevel(RNS::LOG_WARNING);
|
|
RNS::loglevel(RNS::LOG_TRACE);
|
|
//test();
|
|
//testReference();
|
|
//testCrypto();
|
|
testPersistence();
|
|
RNS::loglevel(loglevel);
|
|
TRACE("Finished running tests");
|
|
//return;
|
|
}
|
|
catch (std::exception& e) {
|
|
ERRORF("!!! Exception in test: %s", e.what());
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
#if defined(RUN_RETICULUM)
|
|
void reticulum_announce() {
|
|
if (destination) {
|
|
HEAD("Announcing destination...", RNS::LOG_TRACE);
|
|
//destination.announce(RNS::bytesFromString(fruits[RNS::Cryptography::randomnum() % 7]));
|
|
// test path
|
|
//destination.announce(RNS::bytesFromString(fruits[RNS::Cryptography::randomnum() % 7]), true, nullptr, RNS::bytesFromString("test_tag"));
|
|
// test packet send
|
|
destination.announce(RNS::bytesFromString(fruits[RNS::Cryptography::randomnum() % 7]));
|
|
}
|
|
}
|
|
|
|
void reticulum_setup() {
|
|
INFO("Setting up Reticulum...");
|
|
|
|
try {
|
|
|
|
//std::stringstream test;
|
|
// !!! just adding this single stringstream alone (not even using it) adds a whopping 17.1% !!!
|
|
// !!! JUST SAY NO TO STRINGSTREAM !!!
|
|
|
|
// 18.5% completely empty program
|
|
|
|
// 21.8% baseline here with serial
|
|
|
|
HEAD("Registering Interface instances with Transport...", RNS::LOG_TRACE);
|
|
#ifdef UDP_INTERFACE
|
|
udp_interface.mode(RNS::Type::Interface::MODE_GATEWAY);
|
|
RNS::Transport::register_interface(udp_interface);
|
|
#endif
|
|
#ifdef UDP2_INTERFACE
|
|
udp2_interface.mode(RNS::Type::Interface::MODE_GATEWAY);
|
|
RNS::Transport::register_interface(udp2_interface);
|
|
#endif
|
|
#ifdef LORA_INTERFACE
|
|
lora_interface.mode(RNS::Type::Interface::MODE_GATEWAY);
|
|
RNS::Transport::register_interface(lora_interface);
|
|
#endif
|
|
|
|
#ifdef UDP_INTERFACE
|
|
HEAD("Starting UDPInterface...", RNS::LOG_TRACE);
|
|
udp_interface.start("wifi_ssid", "wifi_password", 4242);
|
|
#endif
|
|
#ifdef UDP2_INTERFACE
|
|
HEAD("Starting UDPInterface...", RNS::LOG_TRACE);
|
|
udp_interface.start("wifi_ssid", "wifi_password", 2424);
|
|
#endif
|
|
#ifdef LORA_INTERFACE
|
|
HEAD("Starting LoRaInterface...", RNS::LOG_TRACE);
|
|
lora_interface.start();
|
|
#endif
|
|
|
|
HEAD("Creating Reticulum instance...", RNS::LOG_TRACE);
|
|
//RNS::Reticulum reticulum;
|
|
reticulum = RNS::Reticulum();
|
|
reticulum.transport_enabled(true);
|
|
reticulum.start();
|
|
//return;
|
|
// 21.9% (+0.1%)
|
|
|
|
HEAD("Creating Identity instance...", RNS::LOG_TRACE);
|
|
// new identity
|
|
//RNS::Identity identity;
|
|
//identity = RNS::Identity();
|
|
// predefined identity
|
|
//RNS::Identity identity(false);
|
|
identity = RNS::Identity(false);
|
|
RNS::Bytes prv_bytes;
|
|
#ifdef ARDUINO
|
|
prv_bytes.assignHex("78E7D93E28D55871608FF13329A226CABC3903A357388A035B360162FF6321570B092E0583772AB80BC425F99791DF5CA2CA0A985FF0415DAB419BBC64DDFAE8");
|
|
#else
|
|
prv_bytes.assignHex("E0D43398EDC974EBA9F4A83463691A08F4D306D4E56BA6B275B8690A2FBD9852E9EBE7C03BC45CAEC9EF8E78C830037210BFB9986F6CA2DEE2B5C28D7B4DE6B0");
|
|
#endif
|
|
identity.load_private_key(prv_bytes);
|
|
// 22.6% (+0.7%)
|
|
|
|
HEAD("Creating Destination instance...", RNS::LOG_TRACE);
|
|
//RNS::Destination destination(identity, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "app", "aspects");
|
|
destination = RNS::Destination(identity, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "app", "aspects");
|
|
// 23.0% (+0.4%)
|
|
|
|
// Register DATA packet callback
|
|
HEAD("Registering packet callback with Destination...", RNS::LOG_TRACE);
|
|
destination.set_packet_callback(onPacket);
|
|
destination.set_proof_strategy(RNS::Type::Destination::PROVE_ALL);
|
|
|
|
{
|
|
// Register PING packet callback
|
|
HEAD("Creating PING Destination instance...", RNS::LOG_TRACE);
|
|
RNS::Destination ping_destination(identity, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "example_utilities", "echo.request");
|
|
|
|
HEAD("Registering packet callback with PING Destination...", RNS::LOG_TRACE);
|
|
ping_destination.set_packet_callback(onPingPacket);
|
|
ping_destination.set_proof_strategy(RNS::Type::Destination::PROVE_ALL);
|
|
}
|
|
|
|
HEAD("Registering announce handler with Transport...", RNS::LOG_TRACE);
|
|
RNS::Transport::register_announce_handler(announce_handler);
|
|
|
|
/*
|
|
HEAD("Announcing destination...", RNS::LOG_TRACE);
|
|
//destination.announce(RNS::bytesFromString(fruits[RNS::Cryptography::randomnum() % 7]));
|
|
// test path
|
|
//destination.announce(RNS::bytesFromString(fruits[RNS::Cryptography::randomnum() % 7]), true, nullptr, RNS::bytesFromString("test_tag"));
|
|
// test packet send
|
|
destination.announce(RNS::bytesFromString(fruits[RNS::Cryptography::randomnum() % 7]));
|
|
// 23.9% (+0.8%)
|
|
*/
|
|
|
|
#if defined (RETICULUM_PACKET_TEST)
|
|
// test data send packet
|
|
HEAD("Creating send packet...", RNS::LOG_TRACE);
|
|
RNS::Packet send_packet(destination, "The quick brown fox jumps over the lazy dog");
|
|
|
|
HEAD("Sending send packet...", RNS::LOG_TRACE);
|
|
send_packet.pack();
|
|
#ifndef NDEBUG
|
|
TRACE("Test send_packet: " + send_packet.debugString());
|
|
#endif
|
|
|
|
HEAD("Creating recv packet...", RNS::LOG_TRACE);
|
|
RNS::Packet recv_packet({RNS::Type::NONE}, send_packet.raw());
|
|
recv_packet.unpack();
|
|
#ifndef NDEBUG
|
|
TRACE("Test recv_packet: " + recv_packet.debugString());
|
|
#endif
|
|
|
|
HEAD("Spoofing recv packet to destination...", RNS::LOG_TRACE);
|
|
destination.receive(recv_packet);
|
|
#endif
|
|
|
|
HEAD("Ready!", RNS::LOG_TRACE);
|
|
}
|
|
catch (std::exception& e) {
|
|
ERRORF("!!! Exception in reticulum_setup: %s", e.what());
|
|
}
|
|
}
|
|
|
|
void reticulum_teardown() {
|
|
INFO("Tearing down Reticulum...");
|
|
|
|
RNS::Transport::save_path_table();
|
|
|
|
try {
|
|
|
|
HEAD("Deregistering announce handler with Transport...", RNS::LOG_TRACE);
|
|
RNS::Transport::deregister_announce_handler(announce_handler);
|
|
|
|
HEAD("Deregistering Interface instances with Transport...", RNS::LOG_TRACE);
|
|
#ifdef UDP_INTERFACE
|
|
RNS::Transport::deregister_interface(udp_interface);
|
|
#endif
|
|
#ifdef UDP2_INTERFACE
|
|
RNS::Transport::deregister_interface(udp2_interface);
|
|
#endif
|
|
#ifdef LORA_INTERFACE
|
|
RNS::Transport::deregister_interface(lora_interface);
|
|
#endif
|
|
|
|
}
|
|
catch (std::exception& e) {
|
|
ERRORF("!!! Exception in reticulum_teardown: %s", e.what());
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef ARDUINO
|
|
void userKey(void)
|
|
{
|
|
//delay(10);
|
|
if (digitalRead(BUTTON_PIN) == LOW) {
|
|
//Serial.print("T-Beam USER button press\n");
|
|
send_announce = true;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void setup() {
|
|
|
|
#ifdef ARDUINO
|
|
Serial.begin(115200);
|
|
Serial.print("Hello from T-Beam on PlatformIO!\n");
|
|
|
|
// Setup user button
|
|
pinMode(BUTTON_PIN, INPUT);
|
|
attachInterrupt(BUTTON_PIN, userKey, FALLING);
|
|
|
|
// Setup filesystem
|
|
if (!SPIFFS.begin(true, "")){
|
|
ERROR("SPIFFS filesystem mount failed");
|
|
}
|
|
else {
|
|
DEBUG("SPIFFS filesystem is ready");
|
|
}
|
|
#endif
|
|
|
|
RNS::loglevel(RNS::LOG_TRACE);
|
|
//RNS::loglevel(RNS::LOG_MEM);
|
|
|
|
/*
|
|
{
|
|
//RNS::Reticulum reticulum_test;
|
|
RNS::Destination destination_test({RNS::Type::NONE}, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "test", "test");
|
|
}
|
|
*/
|
|
|
|
#if defined(RUN_TESTS)
|
|
run_tests();
|
|
#endif
|
|
|
|
#if defined(RUN_RETICULUM)
|
|
reticulum_setup();
|
|
#endif
|
|
|
|
#ifdef ARDUINO
|
|
//Serial.print("Goodbye from T-Beam on PlatformIO!\n");
|
|
#endif
|
|
}
|
|
|
|
void loop() {
|
|
|
|
#if defined(RUN_RETICULUM)
|
|
|
|
reticulum.loop();
|
|
#ifdef UDP_INTERFACE
|
|
udp_interface.loop();
|
|
#endif
|
|
#ifdef UDP2_INTERFACE
|
|
udp2_interface.loop();
|
|
#endif
|
|
#ifdef LORA_INTERFACE
|
|
lora_interface.loop();
|
|
#endif
|
|
|
|
#ifdef ARDUINO
|
|
/*
|
|
if ((RNS::Utilities::OS::time() - last_announce) > 10) {
|
|
reticulum_announce();
|
|
last_announce = RNS::Utilities::OS::time();
|
|
}
|
|
*/
|
|
#endif
|
|
if (send_announce) {
|
|
reticulum_announce();
|
|
send_announce = false;
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifndef ARDUINO
|
|
int getch( ) {
|
|
termios oldt;
|
|
termios newt;
|
|
tcgetattr( STDIN_FILENO, &oldt );
|
|
newt = oldt;
|
|
newt.c_lflag &= ~( ICANON | ECHO );
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
|
|
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
|
|
int ch = getchar();
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
|
|
return ch;
|
|
}
|
|
|
|
int main(void) {
|
|
printf("Hello from Native on PlatformIO!\n");
|
|
|
|
setup();
|
|
|
|
bool run = true;
|
|
while (run) {
|
|
loop();
|
|
int ch = getch();
|
|
if (ch > 0) {
|
|
switch (ch) {
|
|
case 'a':
|
|
#if defined(RUN_RETICULUM)
|
|
reticulum_announce();
|
|
#endif
|
|
break;
|
|
case 'q':
|
|
run = false;
|
|
break;
|
|
}
|
|
}
|
|
RNS::Utilities::OS::sleep(0.01);
|
|
}
|
|
|
|
#if defined(RUN_RETICULUM)
|
|
reticulum_teardown();
|
|
#endif
|
|
|
|
printf("Goodbye from Native on PlatformIO!\n");
|
|
}
|
|
#endif
|