Merge branch 'master' into chatter_2_fixes

This commit is contained in:
Jason P 2025-07-08 12:58:29 -05:00 committed by GitHub
commit 62f7feeea3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 154 additions and 92 deletions

View File

@ -9,14 +9,14 @@ plugins:
lint: lint:
enabled: enabled:
- checkov@3.2.447 - checkov@3.2.447
- renovate@41.17.2 - renovate@41.23.4
- prettier@3.6.2 - prettier@3.6.2
- trufflehog@3.89.2 - trufflehog@3.89.2
- yamllint@1.37.1 - yamllint@1.37.1
- bandit@1.8.5 - bandit@1.8.6
- trivy@0.64.0 - trivy@0.64.1
- taplo@0.9.3 - taplo@0.9.3
- ruff@0.12.1 - ruff@0.12.2
- isort@6.0.1 - isort@6.0.1
- markdownlint@0.45.0 - markdownlint@0.45.0
- oxipng@9.1.5 - oxipng@9.1.5

View File

@ -7,12 +7,7 @@ MCU=""
# Variant groups # Variant groups
BIGDB_8MB=( BIGDB_8MB=(
# Check if FILENAME contains "-tft-" and set target partitionScheme accordingly. "picomputer-s3"
if [[ $FILENAME == *"-tft-"* ]]; then
TFT_BUILD=true
fi
# Extract BASENAME from %FILENAME% for later use.r-s3"
"unphone" "unphone"
"seeed-sensecap-indicator" "seeed-sensecap-indicator"
"crowpanel-esp32s3" "crowpanel-esp32s3"

View File

@ -11,7 +11,8 @@
["0x239A", "0x8029"], ["0x239A", "0x8029"],
["0x239A", "0x0029"], ["0x239A", "0x0029"],
["0x239A", "0x002A"], ["0x239A", "0x002A"],
["0x239A", "0x802A"] ["0x239A", "0x802A"],
["0x2886", "0x0057"]
], ],
"usb_product": "T1000-E-BOOT", "usb_product": "T1000-E-BOOT",
"mcu": "nrf52840", "mcu": "nrf52840",

View File

@ -109,7 +109,7 @@ lib_deps =
[device-ui_base] [device-ui_base]
lib_deps = lib_deps =
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
https://github.com/meshtastic/device-ui/archive/4b7bf369adfa5a7bd419fa8293d21206576d52d0.zip https://github.com/meshtastic/device-ui/archive/8c7092c73425adfda1aac8c6960df06cd85f6d92.zip
; Common libs for environmental measurements in telemetry module ; Common libs for environmental measurements in telemetry module
[environmental_base] [environmental_base]

View File

@ -1536,7 +1536,10 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
if (t.tm_mon > -1) { if (t.tm_mon > -1) {
LOG_DEBUG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d age %d", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min, LOG_DEBUG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d age %d", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min,
t.tm_sec, ti.age()); t.tm_sec, ti.age());
perhapsSetRTC(RTCQualityGPS, t); if (perhapsSetRTC(RTCQualityGPS, t) == RTCSetResultInvalidTime) {
// Clear the GPS buffer if we got an invalid time
clearBuffer();
}
return true; return true;
} else } else
return false; return false;

View File

@ -105,7 +105,7 @@ void readFromRTC()
* *
* If we haven't yet set our RTC this boot, set it from a GPS derived time * If we haven't yet set our RTC this boot, set it from a GPS derived time
*/ */
bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate) RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
{ {
static uint32_t lastSetMsec = 0; static uint32_t lastSetMsec = 0;
uint32_t now = millis(); uint32_t now = millis();
@ -113,7 +113,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
#ifdef BUILD_EPOCH #ifdef BUILD_EPOCH
if (tv->tv_sec < BUILD_EPOCH) { if (tv->tv_sec < BUILD_EPOCH) {
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH); LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
return false; return RTCSetResultInvalidTime;
} }
#endif #endif
@ -184,9 +184,9 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
readFromRTC(); readFromRTC();
#endif #endif
return true; return RTCSetResultSuccess;
} else { } else {
return false; return RTCSetResultNotSet; // RTC was already set with a higher quality time
} }
} }
@ -215,7 +215,7 @@ const char *RtcName(RTCQuality quality)
* @param t The time to potentially set the RTC to. * @param t The time to potentially set the RTC to.
* @return True if the RTC was set to the provided time, false otherwise. * @return True if the RTC was set to the provided time, false otherwise.
*/ */
bool perhapsSetRTC(RTCQuality q, struct tm &t) RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
{ {
/* Convert to unix time /* Convert to unix time
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970 The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970
@ -231,7 +231,7 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t)
// LOG_DEBUG("Got time from GPS month=%d, year=%d, unixtime=%ld", t.tm_mon, t.tm_year, tv.tv_sec); // LOG_DEBUG("Got time from GPS month=%d, year=%d, unixtime=%ld", t.tm_mon, t.tm_year, tv.tv_sec);
if (t.tm_year < 0 || t.tm_year >= 300) { if (t.tm_year < 0 || t.tm_year >= 300) {
// LOG_DEBUG("Ignore invalid GPS month=%d, year=%d, unixtime=%ld", t.tm_mon, t.tm_year, tv.tv_sec); // LOG_DEBUG("Ignore invalid GPS month=%d, year=%d, unixtime=%ld", t.tm_mon, t.tm_year, tv.tv_sec);
return false; return RTCSetResultInvalidTime;
} else { } else {
return perhapsSetRTC(q, &tv); return perhapsSetRTC(q, &tv);
} }

View File

@ -22,13 +22,22 @@ enum RTCQuality {
RTCQualityGPS = 4 RTCQualityGPS = 4
}; };
/// The RTC set result codes
/// Used to indicate the result of an attempt to set the RTC.
enum RTCSetResult {
RTCSetResultNotSet = 0, ///< RTC was set successfully
RTCSetResultSuccess = 1, ///< RTC was set successfully
RTCSetResultInvalidTime = 3, ///< The provided time was invalid (e.g., before the build epoch)
RTCSetResultError = 4 ///< An error occurred while setting the RTC
};
RTCQuality getRTCQuality(); RTCQuality getRTCQuality();
extern uint32_t lastSetFromPhoneNtpOrGps; extern uint32_t lastSetFromPhoneNtpOrGps;
/// If we haven't yet set our RTC this boot, set it from a GPS derived time /// If we haven't yet set our RTC this boot, set it from a GPS derived time
bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate = false); RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate = false);
bool perhapsSetRTC(RTCQuality q, struct tm &t); RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t);
/// Return a string name for the quality /// Return a string name for the quality
const char *RtcName(RTCQuality quality); const char *RtcName(RTCQuality quality);

View File

@ -294,13 +294,13 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
LOG_INFO("Protobuf Value uiconfig.screen_rgb_color: %d", uiconfig.screen_rgb_color); LOG_INFO("Protobuf Value uiconfig.screen_rgb_color: %d", uiconfig.screen_rgb_color);
int32_t rawRGB = uiconfig.screen_rgb_color; int32_t rawRGB = uiconfig.screen_rgb_color;
if (rawRGB > 0 && rawRGB <= 255255255) { if (rawRGB > 0 && rawRGB <= 255255255) {
uint8_t r = (rawRGB >> 16) & 0xFF; uint8_t TFT_MESH_r = (rawRGB >> 16) & 0xFF;
uint8_t g = (rawRGB >> 8) & 0xFF; uint8_t TFT_MESH_g = (rawRGB >> 8) & 0xFF;
uint8_t b = rawRGB & 0xFF; uint8_t TFT_MESH_b = rawRGB & 0xFF;
LOG_INFO("Values of r,g,b: %d, %d, %d", r, g, b); LOG_INFO("Values of r,g,b: %d, %d, %d", TFT_MESH_r, TFT_MESH_g, TFT_MESH_b);
if (r <= 255 && g <= 255 && b <= 255) { if (TFT_MESH_r <= 255 && TFT_MESH_g <= 255 && TFT_MESH_b <= 255) {
TFT_MESH = COLOR565(r, g, b); TFT_MESH = COLOR565(TFT_MESH_r, TFT_MESH_g, TFT_MESH_b);
} }
} }
@ -313,8 +313,8 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
ST7789_MISO, ST7789_SCK); ST7789_MISO, ST7789_SCK);
#else #else
dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT); dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT);
static_cast<ST7789Spi *>(dispdev)->setRGB(TFT_MESH);
#endif #endif
static_cast<ST7789Spi *>(dispdev)->setRGB(TFT_MESH);
#elif defined(USE_SSD1306) #elif defined(USE_SSD1306)
dispdev = new SSD1306Wire(address.address, -1, -1, geometry, dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
@ -944,22 +944,6 @@ void Screen::setFrames(FrameFocus focus)
indicatorIcons.push_back(digital_icon_clock); indicatorIcons.push_back(digital_icon_clock);
#endif #endif
// We don't show the node info of our node (if we have it yet - we should)
size_t numMeshNodes = nodeDB->getNumMeshNodes();
if (numMeshNodes > 0)
numMeshNodes--;
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
if (n && n->num != nodeDB->getNodeNum() && n->is_favorite) {
if (fsi.positions.firstFavorite == 255)
fsi.positions.firstFavorite = numframes;
fsi.positions.lastFavorite = numframes;
normalFrames[numframes++] = graphics::UIRenderer::drawNodeInfo;
indicatorIcons.push_back(icon_node);
}
}
#if HAS_WIFI && !defined(ARCH_PORTDUINO) #if HAS_WIFI && !defined(ARCH_PORTDUINO)
if (!dismissedFrames.wifi && isWifiAvailable()) { if (!dismissedFrames.wifi && isWifiAvailable()) {
fsi.positions.wifi = numframes; fsi.positions.wifi = numframes;
@ -969,7 +953,7 @@ void Screen::setFrames(FrameFocus focus)
#endif #endif
// Beware of what changes you make in this code! // Beware of what changes you make in this code!
// We pass numfames into GetMeshModulesWithUIFrames() which is highly important! // We pass numframes into GetMeshModulesWithUIFrames() which is highly important!
// Inside of that callback, goes over to MeshModule.cpp and we run // Inside of that callback, goes over to MeshModule.cpp and we run
// modulesWithUIFrames.resize(startIndex, nullptr), to insert nullptr // modulesWithUIFrames.resize(startIndex, nullptr), to insert nullptr
// entries until we're ready to start building the matching entries. // entries until we're ready to start building the matching entries.
@ -998,6 +982,34 @@ void Screen::setFrames(FrameFocus focus)
LOG_DEBUG("Added modules. numframes: %d", numframes); LOG_DEBUG("Added modules. numframes: %d", numframes);
// We don't show the node info of our node (if we have it yet - we should)
size_t numMeshNodes = nodeDB->getNumMeshNodes();
if (numMeshNodes > 0)
numMeshNodes--;
// Temporary array to hold favorite node frames
std::vector<FrameCallback> favoriteFrames;
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
if (n && n->num != nodeDB->getNodeNum() && n->is_favorite) {
favoriteFrames.push_back(graphics::UIRenderer::drawNodeInfo);
}
}
// Insert favorite frames *after* collecting them all
if (!favoriteFrames.empty()) {
fsi.positions.firstFavorite = numframes;
for (auto &f : favoriteFrames) {
normalFrames[numframes++] = f;
indicatorIcons.push_back(icon_node);
}
fsi.positions.lastFavorite = numframes - 1;
} else {
fsi.positions.firstFavorite = 255;
fsi.positions.lastFavorite = 255;
}
fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE
this->frameCount = numframes; // ✅ Save frame count for use in custom overlay this->frameCount = numframes; // ✅ Save frame count for use in custom overlay
LOG_DEBUG("Finished build frames. numframes: %d", numframes); LOG_DEBUG("Finished build frames. numframes: %d", numframes);
@ -1009,8 +1021,7 @@ void Screen::setFrames(FrameFocus focus)
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback}; static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0])); ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list just changed)
// just changed)
// Focus on a specific frame, in the frame set we just created // Focus on a specific frame, in the frame set we just created
switch (focus) { switch (focus) {

View File

@ -358,6 +358,9 @@ void menuHandler::systemBaseMenu()
static int optionsEnumArray[7] = {Back}; static int optionsEnumArray[7] = {Back};
int options = 1; int options = 1;
optionsArray[options] = "Reboot";
optionsEnumArray[options++] = Reboot;
optionsArray[options] = "Beeps Action"; optionsArray[options] = "Beeps Action";
optionsEnumArray[options++] = Beeps; optionsEnumArray[options++] = Beeps;
@ -366,9 +369,6 @@ void menuHandler::systemBaseMenu()
optionsEnumArray[options++] = Brightness; optionsEnumArray[options++] = Brightness;
} }
optionsArray[options] = "Reboot";
optionsEnumArray[options++] = Reboot;
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT #if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT
optionsArray[options] = "Screen Color"; optionsArray[options] = "Screen Color";
optionsEnumArray[options++] = Color; optionsEnumArray[options++] = Color;
@ -677,52 +677,52 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
bannerOptions.optionsArrayPtr = optionsArray; bannerOptions.optionsArrayPtr = optionsArray;
bannerOptions.optionsCount = 10; bannerOptions.optionsCount = 10;
bannerOptions.bannerCallback = [display](int selected) -> void { bannerOptions.bannerCallback = [display](int selected) -> void {
uint8_t r = 0; uint8_t TFT_MESH_r = 0;
uint8_t g = 0; uint8_t TFT_MESH_g = 0;
uint8_t b = 0; uint8_t TFT_MESH_b = 0;
if (selected == 1) { if (selected == 1) {
LOG_INFO("Setting color to system default or defined variant"); LOG_INFO("Setting color to system default or defined variant");
// Given just before we set all these to zero, we will allow this to go through // Given just before we set all these to zero, we will allow this to go through
} else if (selected == 2) { } else if (selected == 2) {
LOG_INFO("Setting color to Meshtastic Green"); LOG_INFO("Setting color to Meshtastic Green");
r = 103; TFT_MESH_r = 103;
g = 234; TFT_MESH_g = 234;
b = 148; TFT_MESH_b = 148;
} else if (selected == 3) { } else if (selected == 3) {
LOG_INFO("Setting color to Yellow"); LOG_INFO("Setting color to Yellow");
r = 255; TFT_MESH_r = 255;
g = 255; TFT_MESH_g = 255;
b = 128; TFT_MESH_b = 128;
} else if (selected == 4) { } else if (selected == 4) {
LOG_INFO("Setting color to Red"); LOG_INFO("Setting color to Red");
r = 255; TFT_MESH_r = 255;
g = 64; TFT_MESH_g = 64;
b = 64; TFT_MESH_b = 64;
} else if (selected == 5) { } else if (selected == 5) {
LOG_INFO("Setting color to Orange"); LOG_INFO("Setting color to Orange");
r = 255; TFT_MESH_r = 255;
g = 160; TFT_MESH_g = 160;
b = 20; TFT_MESH_b = 20;
} else if (selected == 6) { } else if (selected == 6) {
LOG_INFO("Setting color to Purple"); LOG_INFO("Setting color to Purple");
r = 204; TFT_MESH_r = 204;
g = 153; TFT_MESH_g = 153;
b = 255; TFT_MESH_b = 255;
} else if (selected == 7) { } else if (selected == 7) {
LOG_INFO("Setting color to Teal"); LOG_INFO("Setting color to Teal");
r = 64; TFT_MESH_r = 64;
g = 224; TFT_MESH_g = 224;
b = 208; TFT_MESH_b = 208;
} else if (selected == 8) { } else if (selected == 8) {
LOG_INFO("Setting color to Pink"); LOG_INFO("Setting color to Pink");
r = 255; TFT_MESH_r = 255;
g = 105; TFT_MESH_g = 105;
b = 180; TFT_MESH_b = 180;
} else if (selected == 9) { } else if (selected == 9) {
LOG_INFO("Setting color to White"); LOG_INFO("Setting color to White");
r = 255; TFT_MESH_r = 255;
g = 255; TFT_MESH_g = 255;
b = 255; TFT_MESH_b = 255;
} }
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT #if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT
@ -731,14 +731,14 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
display->fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); display->fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
display->setColor(WHITE); display->setColor(WHITE);
if (r == 0 && g == 0 && b == 0) { if (TFT_MESH_r == 0 && TFT_MESH_g == 0 && TFT_MESH_b == 0) {
#ifdef TFT_MESH_OVERRIDE #ifdef TFT_MESH_OVERRIDE
TFT_MESH = TFT_MESH_OVERRIDE; TFT_MESH = TFT_MESH_OVERRIDE;
#else #else
TFT_MESH = COLOR565(0x67, 0xEA, 0x94); TFT_MESH = COLOR565(0x67, 0xEA, 0x94);
#endif #endif
} else { } else {
TFT_MESH = COLOR565(r, g, b); TFT_MESH = COLOR565(TFT_MESH_r, TFT_MESH_g, TFT_MESH_b);
} }
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) #if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190)
@ -746,10 +746,10 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
#endif #endif
screen->setFrames(graphics::Screen::FOCUS_SYSTEM); screen->setFrames(graphics::Screen::FOCUS_SYSTEM);
if (r == 0 && g == 0 && b == 0) { if (TFT_MESH_r == 0 && TFT_MESH_g == 0 && TFT_MESH_b == 0) {
uiconfig.screen_rgb_color = 0; uiconfig.screen_rgb_color = 0;
} else { } else {
uiconfig.screen_rgb_color = (r << 16) | (g << 8) | b; uiconfig.screen_rgb_color = (TFT_MESH_r << 16) | (TFT_MESH_g << 8) | TFT_MESH_b;
} }
LOG_INFO("Storing Value of %d to uiconfig.screen_rgb_color", uiconfig.screen_rgb_color); LOG_INFO("Storing Value of %d to uiconfig.screen_rgb_color", uiconfig.screen_rgb_color);
nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uiconfig); nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uiconfig);

View File

@ -42,7 +42,7 @@ uint32_t NotificationRenderer::currentNumber = 0;
uint32_t pow_of_10(uint32_t n) uint32_t pow_of_10(uint32_t n)
{ {
uint32_t ret = 1; uint32_t ret = 1;
for (int i = 0; i < n; i++) { for (uint32_t i = 0; i < n; i++) {
ret *= 10; ret *= 10;
} }
return ret; return ret;
@ -80,6 +80,9 @@ void NotificationRenderer::drawBannercallback(OLEDDisplay *display, OLEDDisplayU
if (!isOverlayBannerShowing() || pauseBanner) if (!isOverlayBannerShowing() || pauseBanner)
return; return;
switch (current_notification_type) { switch (current_notification_type) {
case notificationTypeEnum::none:
// Do nothing - no notification to display
break;
case notificationTypeEnum::text_banner: case notificationTypeEnum::text_banner:
case notificationTypeEnum::selection_picker: case notificationTypeEnum::selection_picker:
drawAlertBannerOverlay(display, state); drawAlertBannerOverlay(display, state);
@ -144,12 +147,12 @@ void NotificationRenderer::drawNumberPicker(OLEDDisplay *display, OLEDDisplayUiS
const char *linePointers[totalLines + 1] = {0}; // this is sort of a dynamic allocation const char *linePointers[totalLines + 1] = {0}; // this is sort of a dynamic allocation
// copy the linestarts to display to the linePointers holder // copy the linestarts to display to the linePointers holder
for (int i = 0; i < lineCount; i++) { for (uint16_t i = 0; i < lineCount; i++) {
linePointers[i] = lineStarts[i]; linePointers[i] = lineStarts[i];
} }
std::string digits = " "; std::string digits = " ";
std::string arrowPointer = " "; std::string arrowPointer = " ";
for (int i = 0; i < numDigits; i++) { for (uint16_t i = 0; i < numDigits; i++) {
// Modulo minus modulo to return just the current number // Modulo minus modulo to return just the current number
digits += std::to_string((currentNumber % (pow_of_10(numDigits - i))) / (pow_of_10(numDigits - i - 1))) + " "; digits += std::to_string((currentNumber % (pow_of_10(numDigits - i))) / (pow_of_10(numDigits - i - 1))) + " ";
if (curSelected == i) { if (curSelected == i) {

View File

@ -369,6 +369,14 @@ NodeDB::NodeDB()
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY; config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY;
} }
#if !HAS_TFT
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
// On a device without MUI, this display mode makes no sense, and will break logic.
config.display.displaymode = meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT;
config.bluetooth.enabled = true;
}
#endif
if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate))) if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate)))
saveWhat |= SEGMENT_DEVICESTATE; saveWhat |= SEGMENT_DEVICESTATE;
if (nodeDatabaseCRC != crc32Buffer(&nodeDatabase, sizeof(nodeDatabase))) if (nodeDatabaseCRC != crc32Buffer(&nodeDatabase, sizeof(nodeDatabase)))

View File

@ -645,10 +645,6 @@ void RadioInterface::limitPower(int8_t loraMaxPower)
if (power > loraMaxPower) // Clamp power to maximum defined level if (power > loraMaxPower) // Clamp power to maximum defined level
power = loraMaxPower; power = loraMaxPower;
if (TX_GAIN_LORA == 0) { // Setting power in config with defined TX_GAIN_LORA will cause decreasing power on each reboot
config.lora.tx_power = power; // Set limited power in config
}
LOG_INFO("Final Tx power: %d dBm", power); LOG_INFO("Final Tx power: %d dBm", power);
} }

View File

@ -10,6 +10,32 @@
#include "aes-ccm.h" #include "aes-ccm.h"
#if !MESHTASTIC_EXCLUDE_PKI #if !MESHTASTIC_EXCLUDE_PKI
/**
* Constant-time comparison of two byte arrays
*
* @param a First byte array to compare
* @param b Second byte array to compare
* @param len Number of bytes to compare
* @return 0 if arrays are equal, -1 if different or if inputs are invalid
*/
static int constant_time_compare(const void *a_, const void *b_, size_t len)
{
/* Cast to volatile to prevent the compiler from optimizing out their comparison. */
const volatile uint8_t *volatile a = (const volatile uint8_t *volatile)a_;
const volatile uint8_t *volatile b = (const volatile uint8_t *volatile)b_;
if (len == 0)
return 0;
if (a == NULL || b == NULL)
return -1;
size_t i;
volatile uint8_t d = 0U;
for (i = 0U; i < len; i++) {
d |= (a[i] ^ b[i]);
}
/* Constant time bit arithmetic to convert d > 0 to -1 and d = 0 to 0. */
return (1 & ((d - 1) >> 8)) - 1;
}
static void WPA_PUT_BE16(uint8_t *a, uint16_t val) static void WPA_PUT_BE16(uint8_t *a, uint16_t val)
{ {
a[0] = val >> 8; a[0] = val >> 8;
@ -146,7 +172,7 @@ bool aes_ccm_ad(const uint8_t *key, size_t key_len, const uint8_t *nonce, size_t
aes_ccm_encr(L, crypt, crypt_len, plain, a); aes_ccm_encr(L, crypt, crypt_len, plain, a);
aes_ccm_auth_start(M, L, nonce, aad, aad_len, crypt_len, x); aes_ccm_auth_start(M, L, nonce, aad, aad_len, crypt_len, x);
aes_ccm_auth(plain, crypt_len, x); aes_ccm_auth(plain, crypt_len, x);
if (memcmp(x, t, M) != 0) { // FIXME make const comp if (constant_time_compare(x, t, M) != 0) {
return false; return false;
} }
return true; return true;

View File

@ -29,6 +29,7 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread
uint8_t fromRadioBytes[meshtastic_FromRadio_size] = {0}; uint8_t fromRadioBytes[meshtastic_FromRadio_size] = {0};
size_t numBytes = 0; size_t numBytes = 0;
bool hasChecked = false; bool hasChecked = false;
bool phoneWants = false;
protected: protected:
virtual int32_t runOnce() override virtual int32_t runOnce() override
@ -38,10 +39,10 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread
for (uint8_t i = 0; i < queue_size; i++) { for (uint8_t i = 0; i < queue_size; i++) {
handleToRadio(nimble_queue.at(i).data(), nimble_queue.at(i).length()); handleToRadio(nimble_queue.at(i).data(), nimble_queue.at(i).length());
} }
LOG_WARN("Queue_size %u", queue_size); LOG_DEBUG("Queue_size %u", queue_size);
queue_size = 0; queue_size = 0;
} }
if (hasChecked == false) { if (hasChecked == false && phoneWants == true) {
numBytes = getFromRadio(fromRadioBytes); numBytes = getFromRadio(fromRadioBytes);
hasChecked = true; hasChecked = true;
} }
@ -98,9 +99,12 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks
{ {
virtual void onRead(NimBLECharacteristic *pCharacteristic) virtual void onRead(NimBLECharacteristic *pCharacteristic)
{ {
while (!bluetoothPhoneAPI->hasChecked) { int tries = 0;
bluetoothPhoneAPI->phoneWants = true;
while (!bluetoothPhoneAPI->hasChecked && tries < 100) {
bluetoothPhoneAPI->setIntervalFromNow(0); bluetoothPhoneAPI->setIntervalFromNow(0);
delay(20); delay(20);
tries++;
} }
std::lock_guard<std::mutex> guard(bluetoothPhoneAPI->nimble_mutex); std::lock_guard<std::mutex> guard(bluetoothPhoneAPI->nimble_mutex);
std::string fromRadioByteString(bluetoothPhoneAPI->fromRadioBytes, std::string fromRadioByteString(bluetoothPhoneAPI->fromRadioBytes,
@ -111,6 +115,7 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks
bluetoothPhoneAPI->setIntervalFromNow(0); bluetoothPhoneAPI->setIntervalFromNow(0);
bluetoothPhoneAPI->numBytes = 0; bluetoothPhoneAPI->numBytes = 0;
bluetoothPhoneAPI->hasChecked = false; bluetoothPhoneAPI->hasChecked = false;
bluetoothPhoneAPI->phoneWants = false;
} }
}; };
@ -186,7 +191,12 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
new meshtastic::BluetoothStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED)); new meshtastic::BluetoothStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED));
if (bluetoothPhoneAPI) { if (bluetoothPhoneAPI) {
std::lock_guard<std::mutex> guard(bluetoothPhoneAPI->nimble_mutex);
bluetoothPhoneAPI->close(); bluetoothPhoneAPI->close();
bluetoothPhoneAPI->hasChecked = false;
bluetoothPhoneAPI->phoneWants = false;
bluetoothPhoneAPI->numBytes = 0;
bluetoothPhoneAPI->queue_size = 0;
} }
} }
}; };