mirror of
https://github.com/meshtastic/firmware.git
synced 2026-10-09 06:31:35 -04:00
* build(nrf52): drop unused TinyUSB classes and assert function-name strings Only the CDC class is used on nRF52. Disable the MSC, HID, MIDI, vendor and video class drivers in the Adafruit TinyUSB config, and pass an empty __ASSERT_FUNC so assert() no longer embeds __PRETTY_FUNCTION__ strings. File and line are still reported. rak4631 estimate: ~7.4 KB flash, ~2.3 KB RAM. * fix(nrf52): link only the secp256r1 cc310 curve domain CRYS_ECPKI_GetEcDomain indexes ecDomainsFuncP, which references the parameter tables of all eleven cc310 curves. Bluefruit LESC pairing only requests secp256r1, so override the lookup to return that domain alone. rak4631 estimate: ~7.4 KB flash. * fix(airtime): replace powf in the channel-utilization EMA fold foldChannelUtil was the only powf caller on nRF52. The exponent is an integer step count, so raise the EMA factor by squaring instead; a multi-day sleep still folds in at most 32 multiplications. rak4631 estimate: ~1.9 KB flash. * fix(graphics): use double sin/cos in the compass renderers The compass renderers were the only sinf/cosf callers on nRF52 screen builds, pulling in the float trig kernels next to the double ones GeoCoord already links. Call the double variants instead. rak4631 estimate: ~3.2 KB flash. * fix(motion): use double atan2 for magnetometer heading fallbacks MMC5983MA, QMC6309 and the InkHUD map centre were the remaining application atan2f callers. The double atan2 is already linked, so the float variant only added atan2f, __ieee754_atan2f and atanf. The saving lands once meshtastic/Fusion#1 removes the library's atan2f as well. rak4631 estimate: ~0.8 KB flash with Fusion#1. * fix(hopscale): trim diagnostic logging to state changes and anomalies Drop the save/restore confirmations, the hourly histogram and trend dumps, the denominator step logs and the per-packet hop_limit log (printPacket already reports HopLim). Keep the save-failure and histogram-full warnings, the congestion on/off transition and a single periodic status line, and remove lastScaledPerHop, which only fed the logs. * fix(hopscale): silence cppcheck uselessAssignmentArg on restored count * perf(crypto): use full-schedule AES128/AES256 for AES-CCM aesSetKey used AESSmall128/AESSmall256, which re-derive round keys for every block. AES128/AES256 precompute the schedule, encrypt faster and are already linked by encryptAESCtr, so the AESSmall*/AESTiny* code drops out. No change on ESP32, where AESSmall* already aliases AES128/AES256. rak4631 estimate: ~3.9 KB flash; cipher object up to 184 bytes larger. * perf(nrf52): use the shared software CTR for AES-256 and remove tiny-aes CryptoCell only accelerates AES-128, which stays on hardware. AES-256 CTR now calls CryptoEngine::encryptAESCtr (rweather CTR<AES256>, already linked) instead of the in-tree tiny-aes copy, whose sources were removed in the previous commit. Output is identical. rak4631 estimate: ~0.8 KB flash. * perf(mesh): use std::map for pending retransmissions and API port timestamps NextHopRouter::pending and PhoneAPI::lastPortNumToRadio were the only unordered_map instances linked on nRF52. Switching them to std::map, which is already linked, drops the libstdc++ hashtable, rehash policy and prime table. GlobalPacketId gains operator<; the unused hash functor is removed. rak4631 estimate: ~2.1 KB flash. * perf: parse sensor decimals without strtod The WS85 serial parser (strtof) and DFRobotLarkSensor (String::toFloat) were the only callers of newlib's strtod. Add parseDecimalFloat to meshUtils for plain [+-]digits[.digits] fields and use it at both sites. Covered by test_type_conversions against strtof. rak4631 estimate: ~4.5 KB flash. * perf(gps): compute tan from sin/cos in UTM and OSGR conversion latLongToUTM and latLongToOSGR were the only tan callers. sin and cos are already linked, so deriving tan from them drops tan and __kernel_tan. rak4631 estimate: ~1.1 KB flash. * fix(graphics): only dispatch the theme menu when TFT coloring is enabled The Theme option is only offered with GRAPHICS_TFT_COLORING_ENABLED, but handleMenuSwitch dispatched ThemeMenu unconditionally, linking kThemes and the theme accessors into monochrome builds where the menu is unreachable. rak4631 estimate: ~1 KB flash. * fix(senxx): trim diagnostic logging to errors and user-visible actions Keep all errors and warnings and a single version line; shorten the admin action messages; drop progress chatter, state save/restore confirmations and the per-reading and VOC-state debug dumps. The nested VOC restore branch collapses to one condition with the same behaviour. rak4631 estimate: ~2 KB flash. * build(nrf52): define CRYPTO_AES_NO_DECRYPT CTR and CCM only encrypt, so the AES inverse tables and round helpers are dead code on nRF52. Takes effect once the Crypto dependency includes meshtastic/Crypto#5. rak4631 estimate: ~1.0 KB flash.
257 lines
7.6 KiB
C++
257 lines
7.6 KiB
C++
#include "meshUtils.h"
|
|
#include "target_specific.h"
|
|
#include <string.h>
|
|
|
|
/*
|
|
* Find the first occurrence of find in s, where the search is limited to the
|
|
* first slen characters of s.
|
|
* -
|
|
* Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
|
|
* Copyright (c) 1990, 1993
|
|
* The Regents of the University of California. All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to Berkeley by
|
|
* Chris Torek.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
*/
|
|
char *strnstr(const char *s, const char *find, size_t slen)
|
|
{
|
|
char c;
|
|
if ((c = *find++) != '\0') {
|
|
char sc;
|
|
size_t len;
|
|
|
|
len = strlen(find);
|
|
do {
|
|
do {
|
|
if (slen-- < 1 || (sc = *s++) == '\0')
|
|
return (NULL);
|
|
} while (sc != c);
|
|
if (len > slen)
|
|
return (NULL);
|
|
} while (strncmp(s, find, len) != 0);
|
|
s--;
|
|
}
|
|
return ((char *)s);
|
|
}
|
|
|
|
void printBytes(const char *label, const uint8_t *p, size_t numbytes)
|
|
{
|
|
int labelSize = strlen(label);
|
|
char *messageBuffer = new char[labelSize + (numbytes * 3) + 2];
|
|
strncpy(messageBuffer, label, labelSize);
|
|
for (size_t i = 0; i < numbytes; i++)
|
|
snprintf(messageBuffer + labelSize + i * 3, 4, " %02x", p[i]);
|
|
strcpy(messageBuffer + labelSize + numbytes * 3, "\n");
|
|
LOG_DEBUG(messageBuffer);
|
|
delete[] messageBuffer;
|
|
}
|
|
|
|
bool memfll(const uint8_t *mem, uint8_t find, size_t numbytes)
|
|
{
|
|
for (uint8_t i = 0; i < numbytes; i++) {
|
|
if (mem[i] != find)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool getMacAddrDeviceId(uint8_t *deviceId)
|
|
{
|
|
// Zero-initialized: getMacAddr() may return without writing (e.g. Portduino with no MAC
|
|
// source), and we want that no-write case to hit the all-zeros guard below, not read garbage.
|
|
uint8_t mac[6] = {0};
|
|
getMacAddr(mac);
|
|
if (memfll(mac, 0, sizeof(mac))) {
|
|
LOG_WARN("MAC is all zeros, leaving device_id unset");
|
|
return false;
|
|
}
|
|
memcpy(deviceId, mac, sizeof(mac));
|
|
return true;
|
|
}
|
|
|
|
bool isOneOf(int item, int count, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, count);
|
|
bool found = false;
|
|
for (int i = 0; i < count; ++i) {
|
|
if (item == va_arg(args, int)) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
va_end(args);
|
|
return found;
|
|
}
|
|
|
|
const std::string vformat(const char *const zcFormat, ...)
|
|
{
|
|
va_list vaArgs;
|
|
va_start(vaArgs, zcFormat);
|
|
va_list vaArgsCopy;
|
|
va_copy(vaArgsCopy, vaArgs);
|
|
const int iLen = std::vsnprintf(NULL, 0, zcFormat, vaArgsCopy);
|
|
va_end(vaArgsCopy);
|
|
std::vector<char> zc(iLen + 1);
|
|
std::vsnprintf(zc.data(), zc.size(), zcFormat, vaArgs);
|
|
va_end(vaArgs);
|
|
return std::string(zc.data(), iLen);
|
|
}
|
|
|
|
size_t pb_string_length(const char *str, size_t max_len)
|
|
{
|
|
size_t len = 0;
|
|
for (size_t i = 0; i < max_len; i++) {
|
|
if (str[i] != '\0') {
|
|
len = i + 1;
|
|
}
|
|
}
|
|
return len;
|
|
}
|
|
|
|
bool sanitizeUtf8(char *buf, size_t bufSize)
|
|
{
|
|
if (!buf || bufSize == 0)
|
|
return false;
|
|
|
|
// Ensure null-terminated within buffer; report if we had to enforce it
|
|
bool replaced = (buf[bufSize - 1] != '\0');
|
|
buf[bufSize - 1] = '\0';
|
|
|
|
size_t i = 0;
|
|
size_t len = strlen(buf);
|
|
|
|
while (i < len) {
|
|
uint8_t b = (uint8_t)buf[i];
|
|
|
|
// Determine expected sequence length from lead byte
|
|
size_t seqLen;
|
|
uint32_t minCodepoint;
|
|
if (b <= 0x7F) {
|
|
// ASCII - valid single byte
|
|
i++;
|
|
continue;
|
|
} else if ((b & 0xE0) == 0xC0) {
|
|
seqLen = 2;
|
|
minCodepoint = 0x80; // Reject overlong
|
|
} else if ((b & 0xF0) == 0xE0) {
|
|
seqLen = 3;
|
|
minCodepoint = 0x800;
|
|
} else if ((b & 0xF8) == 0xF0) {
|
|
seqLen = 4;
|
|
minCodepoint = 0x10000;
|
|
} else {
|
|
// Invalid lead byte (0x80-0xBF or 0xF8+)
|
|
buf[i] = '?';
|
|
replaced = true;
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
// Check that we have enough bytes remaining
|
|
if (i + seqLen > len) {
|
|
// Truncated sequence at end of string - replace remaining bytes
|
|
for (size_t j = i; j < len; j++) {
|
|
buf[j] = '?';
|
|
}
|
|
replaced = true;
|
|
break;
|
|
}
|
|
|
|
// Validate continuation bytes (must be 10xxxxxx)
|
|
bool valid = true;
|
|
for (size_t j = 1; j < seqLen; j++) {
|
|
if (((uint8_t)buf[i + j] & 0xC0) != 0x80) {
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (valid) {
|
|
// Decode codepoint to check for overlong encodings and surrogates
|
|
uint32_t cp = 0;
|
|
if (seqLen == 2)
|
|
cp = b & 0x1F;
|
|
else if (seqLen == 3)
|
|
cp = b & 0x0F;
|
|
else
|
|
cp = b & 0x07;
|
|
for (size_t j = 1; j < seqLen; j++)
|
|
cp = (cp << 6) | ((uint8_t)buf[i + j] & 0x3F);
|
|
|
|
if (cp < minCodepoint || cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) {
|
|
// Overlong encoding, out of Unicode range, or surrogate half
|
|
valid = false;
|
|
}
|
|
}
|
|
|
|
if (valid) {
|
|
i += seqLen;
|
|
} else {
|
|
// Replace only the lead byte; continuation bytes will be caught on next iteration
|
|
buf[i] = '?';
|
|
replaced = true;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
return replaced;
|
|
}
|
|
|
|
float parseDecimalFloat(const char *s)
|
|
{
|
|
while (*s == ' ' || (*s >= '\t' && *s <= '\r'))
|
|
s++;
|
|
const bool negative = *s == '-';
|
|
if (*s == '-' || *s == '+')
|
|
s++;
|
|
double value = 0, scale = 1;
|
|
bool fraction = false, anyDigit = false;
|
|
for (;; s++) {
|
|
if (*s >= '0' && *s <= '9') {
|
|
value = value * 10 + (*s - '0');
|
|
if (fraction)
|
|
scale *= 10;
|
|
anyDigit = true;
|
|
} else if (*s == '.' && !fraction) {
|
|
fraction = true;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (!anyDigit)
|
|
return 0.0f;
|
|
return static_cast<float>((negative ? -value : value) / scale);
|
|
}
|
|
|
|
void clampLongName(char *longName)
|
|
{
|
|
longName[MAX_LONG_NAME_BYTES] = '\0';
|
|
sanitizeUtf8(longName, MAX_LONG_NAME_BYTES + 1);
|
|
}
|