Files
RTNode-HeltecV4/lib/microReticulum/src/Utilities/OS.h
James L 5ed70dcca9 v1.0.0: Boundary mode with bidirectional LoRa↔TCP transport
Vendor microReticulum library with boundary mode transport fixes:
- Two-whitelist system gates backbone traffic (local addresses +
  mentioned addresses from local devices)
- Allow control_hashes and local destinations through boundary filter
  (fixes backbone→LoRa path discovery)
- Fix get_cached_packet() to call unpack() instead of update_hash()
  (fixes empty destination_hash in path responses)
- LRPROOF Identity::recall null guard
- remaining_hops HEADER_1/BROADCAST fix for final-hop delivery
- PROOF packets excluded from boundary wrapping
- Iterator invalidation fix in transport table cleanup
- is_backbone flag replaces string matching for interface identification

Firmware changes:
- Set is_backbone(true) on backbone TCP interface
- Rename default TcpInterface name to BackboneInterface
- Update comments for dual-use TcpInterface (backbone + local AP)
- Use vendored lib/microReticulum instead of PlatformIO registry
2026-02-23 18:08:29 -05:00

235 lines
6.8 KiB
C++
Executable File

#pragma once
#include "../FileSystem.h"
#include "../FileStream.h"
#include "../Bytes.h"
#include "tlsf.h"
#include <cmath>
#include <unistd.h>
#include <time.h>
#include <stdint.h>
#include <sys/time.h>
#ifdef ARDUINO
#include <Arduino.h>
#endif
#undef round
namespace RNS { namespace Utilities {
class OS {
private:
static FileSystem _filesystem;
static uint64_t _time_offset;
public:
static tlsf_t _tlsf;
public:
static inline uint64_t getTimeOffset() { return _time_offset; }
static inline void setTimeOffset(uint64_t offset) { _time_offset = offset; }
#ifdef ARDUINO
// return current time in milliseconds since startup
static inline uint64_t ltime() {
// handle roll-over of 32-bit millis (approx. 49 days)
static uint32_t low32, high32;
uint32_t new_low32 = millis();
if (new_low32 < low32) high32++;
low32 = new_low32;
return ((uint64_t)high32 << 32 | low32) + _time_offset;
}
#else
// return current time in milliseconds since 00:00:00, January 1, 1970 (Unix Epoch)
static inline uint64_t ltime() { timeval time; ::gettimeofday(&time, NULL); return (uint64_t)(time.tv_sec * 1000) + (uint64_t)(time.tv_usec / 1000); }
#endif
#ifdef ARDUINO
// return current time in float seconds since startup
static inline double time() { return (double)(ltime() / 1000.0); }
#else
// return current time in float seconds since 00:00:00, January 1, 1970 (Unix Epoch)
static inline double time() { timeval time; ::gettimeofday(&time, NULL); return (double)time.tv_sec + ((double)time.tv_usec / 1000000); }
#endif
// sleep for specified milliseconds
//static inline void sleep(float seconds) { ::sleep(seconds); }
#ifdef ARDUINO
static inline void sleep(float seconds) { delay((uint32_t)(seconds * 1000)); }
#else
static inline void sleep(float seconds) { timespec time; time.tv_sec = (time_t)(seconds); time.tv_nsec = (seconds - (float)time.tv_sec) * 1000000000; ::nanosleep(&time, nullptr); }
#endif
//static inline void sleep(uint32_t milliseconds) { ::sleep((float)milliseconds / 1000.0); }
// round decimal number to specified precision
//static inline float round(float value, uint8_t precision) { return std::round(value / precision) * precision; }
//static inline double round(double value, uint8_t precision) { return std::round(value / precision) * precision; }
static inline double round(double value, uint8_t precision) { return std::round(value / precision) * precision; }
static inline uint64_t from_bytes_big_endian(const uint8_t* data, size_t len) {
uint64_t result = 0;
for (size_t i = 0; i < len; ++i) {
result = (result << 8) | data[i];
}
return result;
}
// Detect endianness at runtime
static int is_big_endian(void) {
uint16_t test = 0x0102;
return ((uint8_t*)&test)[0] == 0x01;
}
// Byte swap functions
static uint16_t swap16(uint16_t val) {
return (val << 8) | (val >> 8);
}
static uint32_t swap32(uint32_t val) {
return ((val << 24) & 0xFF000000) |
((val << 8) & 0x00FF0000) |
((val >> 8) & 0x0000FF00) |
((val >> 24) & 0x000000FF);
}
// Platform-independent replacements
static uint16_t portable_htons(uint16_t val) {
return is_big_endian() ? val : swap16(val);
}
static uint32_t portable_htonl(uint32_t val) {
return is_big_endian() ? val : swap32(val);
}
static uint16_t portable_ntohs(uint16_t val) {
return is_big_endian() ? val : swap16(val);
}
static uint32_t portable_ntohl(uint32_t val) {
return is_big_endian() ? val : swap32(val);
}
#if defined(RNS_USE_ALLOCATOR)
static void dump_allocator_stats();
#endif
inline static void register_filesystem(FileSystem& filesystem) {
TRACE("Registering filesystem...");
_filesystem = filesystem;
}
/*
inline static void register_filesystem(FileSystemImpl* filesystemimpl) {
TRACE("Registering filesystem...");
_filesystem = filesystemimpl;
}
*/
inline static void deregister_filesystem() {
TRACE("Deregistering filesystem...");
_filesystem = {Type::NONE};
}
inline static FileSystem& get_filesystem() {
return _filesystem;
}
inline static bool file_exists(const char* file_path) {
if (!_filesystem) {
WARNING("file_exists: filesystem not registered");
throw std::runtime_error("FileSystem has not been registered");
}
return _filesystem.file_exists(file_path);
}
inline static size_t read_file(const char* file_path, Bytes& data) {
if (!_filesystem) {
throw std::runtime_error("FileSystem has not been registered");
}
return _filesystem.read_file(file_path, data);
}
inline static size_t write_file(const char* file_path, const Bytes& data) {
if (!_filesystem) {
throw std::runtime_error("FileSystem has not been registered");
}
return _filesystem.write_file(file_path, data);
}
inline static FileStream open_file(const char* file_path, RNS::FileStream::MODE file_mode) {
if (!_filesystem) {
throw std::runtime_error("FileSystem has not been registered");
}
return _filesystem.open_file(file_path, file_mode);
}
inline static bool remove_file(const char* file_path) {
if (!_filesystem) {
throw std::runtime_error("FileSystem has not been registered");
}
return _filesystem.remove_file(file_path);
}
inline static bool rename_file(const char* from_file_path, const char* to_file_path) {
if (!_filesystem) {
throw std::runtime_error("FileSystem has not been registered");
}
return _filesystem.rename_file(from_file_path, to_file_path);
}
inline static bool directory_exists(const char* directory_path) {
if (!_filesystem) {
throw std::runtime_error("FileSystem has not been registered");
}
return _filesystem.directory_exists(directory_path);
}
inline static bool create_directory(const char* directory_path) {
if (!_filesystem) {
throw std::runtime_error("FileSystem has not been registered");
}
return _filesystem.create_directory(directory_path);
}
inline static bool remove_directory(const char* directory_path) {
if (!_filesystem) {
throw std::runtime_error("FileSystem has not been registered");
}
return _filesystem.remove_directory(directory_path);
}
inline static std::list<std::string> list_directory(const char* directory_path) {
if (!_filesystem) {
throw std::runtime_error("FileSystem has not been registered");
}
return _filesystem.list_directory(directory_path);
}
inline static size_t storage_size() {
if (!_filesystem) {
throw std::runtime_error("FileSystem has not been registered");
}
return _filesystem.storage_size();
}
inline static size_t storage_available() {
if (!_filesystem) {
throw std::runtime_error("FileSystem has not been registered");
}
return _filesystem.storage_available();
}
static size_t heap_size();
static size_t heap_available();
static void dump_heap_stats();
};
} }