#pragma once #include "DebugConfiguration.h" #include #include #include #include /// Keep a function out of line even when the compiler would rather inline it. Use on helpers that /// hold a large object on the stack: inlining several of them into one caller makes that caller's /// frame reserve every helper's locals at once, which on our 8 KB Arduino loopTask is enough to /// overflow the stack (see issue #11237). #if defined(__GNUC__) #define NOINLINE __attribute__((noinline)) #else #define NOINLINE #endif /// C++ v17+ clamp function, limits a given value to a range defined by lo and hi template constexpr const T &clamp(const T &v, const T &lo, const T &hi) { return (v < lo) ? lo : (hi < v) ? hi : v; } /// Return the smallest power of 2 >= n (undefined for n > 2^31) static inline uint32_t nextPowerOf2(uint32_t n) { if (n <= 1) return 1; #if defined(__GNUC__) return 1U << (32 - __builtin_clz(n - 1)); #else n--; n |= n >> 1; n |= n >> 2; n |= n >> 4; n |= n >> 8; n |= n >> 16; return n + 1; #endif } #if HAS_SCREEN #define IF_SCREEN(X) \ if (screen) { \ X; \ } #else #define IF_SCREEN(...) #endif #if (defined(ARCH_PORTDUINO) && !defined(STRNSTR)) #define STRNSTR #include char *strnstr(const char *s, const char *find, size_t slen); #endif void printBytes(const char *label, const uint8_t *p, size_t numbytes); // is the memory region filled with a single character? bool memfll(const uint8_t *mem, uint8_t find, size_t numbytes); // getDeviceId() fallback (see target_specific.h): copies the 6-byte factory MAC, or returns false // on an all-zero MAC so two blank devices don't collide on an all-zero id. bool getMacAddrDeviceId(uint8_t *deviceId); bool isOneOf(int item, int count, ...); const std::string vformat(const char *const zcFormat, ...); // Get actual string length for nanopb char array fields. size_t pb_string_length(const char *str, size_t max_len); // Sanitize a fixed-size char buffer in-place by replacing invalid UTF-8 sequences with '?'. // Ensures the result is null-terminated within bufSize. Returns true if any bytes were replaced. bool sanitizeUtf8(char *buf, size_t bufSize); // Longest User.long_name content (bytes, excluding NUL) we store or transmit. // The wire decode buffer stays at 40 so names from senders built against the // older 39-byte limit still parse; everything we keep or send is clamped to // this, matching the slim NodeInfoLite storage width in deviceonly.proto. #define MAX_LONG_NAME_BYTES 24 // Clamp a long_name buffer (at least MAX_LONG_NAME_BYTES + 1 bytes) in-place // to MAX_LONG_NAME_BYTES bytes of content, fixing any partial UTF-8 sequence // left at the cut. void clampLongName(char *longName); /// Calculate 2^n without calling pow() - used for spreading factor and other calculations inline uint32_t pow_of_2(uint32_t n) { return 1 << n; } /// Returns true if n is a power of two (n >= 1). template constexpr bool is_pow_of_2(T n) { return n >= T(1) && (n & (n - T(1))) == T(0); } #define IS_ONE_OF(item, ...) isOneOf(item, sizeof((int[]){__VA_ARGS__}) / sizeof(int), __VA_ARGS__)