Merge branch 'master' into chatter_2_fixes

This commit is contained in:
Jason P 2025-07-03 18:30:23 -05:00 committed by GitHub
commit 8ce9c6ac77
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 108 additions and 41 deletions

@ -1 +1 @@
Subproject commit 386fa53c1596c8dfc547521f08df107f4cb3a275 Subproject commit 584f0a3a359103acf0bfce506c1b1fc32c639841

View File

@ -99,10 +99,17 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
// === Battery State === // === Battery State ===
int chargePercent = powerStatus->getBatteryChargePercent(); int chargePercent = powerStatus->getBatteryChargePercent();
bool isCharging = powerStatus->getIsCharging() == meshtastic::OptionalBool::OptTrue; bool isCharging = powerStatus->getIsCharging();
if (chargePercent == 100) { bool usbPowered = powerStatus->getHasUSB();
if (chargePercent >= 100) {
isCharging = false; isCharging = false;
} }
if (chargePercent == 101) {
usbPowered = true; // Forcing this flag on for the express purpose that some devices have no concept of having a USB cable
// plugged in
}
uint32_t now = millis(); uint32_t now = millis();
#ifndef USE_EINK #ifndef USE_EINK
@ -115,48 +122,63 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
bool useHorizontalBattery = (isHighResolution && screenW >= screenH); bool useHorizontalBattery = (isHighResolution && screenW >= screenH);
const int textY = y + (highlightHeight - FONT_HEIGHT_SMALL) / 2; const int textY = y + (highlightHeight - FONT_HEIGHT_SMALL) / 2;
int batteryX = 1;
int batteryY = HEADER_OFFSET_Y + 1;
// === Battery Icons === // === Battery Icons ===
if (useHorizontalBattery) { if (usbPowered && !isCharging) { // This is a basic check to determine USB Powered is flagged but not charging
int batteryX = 2; batteryX += 1;
int batteryY = HEADER_OFFSET_Y + 3; batteryY += 2;
display->drawXbm(batteryX, batteryY, 9, 13, batteryBitmap_h_bottom); if (isHighResolution) {
display->drawXbm(batteryX + 9, batteryY, 9, 13, batteryBitmap_h_top); display->drawXbm(batteryX, batteryY, 19, 12, imgUSB_HighResolution);
if (isCharging && isBoltVisibleShared) batteryX += 20; // Icon + 1 pixel
display->drawXbm(batteryX + 4, batteryY, 9, 13, lightning_bolt_h); } else {
else { display->drawXbm(batteryX, batteryY, 10, 8, imgUSB);
display->drawLine(batteryX + 5, batteryY, batteryX + 10, batteryY); batteryX += 11; // Icon + 1 pixel
display->drawLine(batteryX + 5, batteryY + 12, batteryX + 10, batteryY + 12);
int fillWidth = 14 * chargePercent / 100;
display->fillRect(batteryX + 1, batteryY + 1, fillWidth, 11);
} }
} else { } else {
int batteryX = 1; if (useHorizontalBattery) {
int batteryY = HEADER_OFFSET_Y + 1; batteryX += 1;
batteryY += 2;
display->drawXbm(batteryX, batteryY, 9, 13, batteryBitmap_h_bottom);
display->drawXbm(batteryX + 9, batteryY, 9, 13, batteryBitmap_h_top);
if (isCharging && isBoltVisibleShared)
display->drawXbm(batteryX + 4, batteryY, 9, 13, lightning_bolt_h);
else {
display->drawLine(batteryX + 5, batteryY, batteryX + 10, batteryY);
display->drawLine(batteryX + 5, batteryY + 12, batteryX + 10, batteryY + 12);
int fillWidth = 14 * chargePercent / 100;
display->fillRect(batteryX + 1, batteryY + 1, fillWidth, 11);
}
batteryX += 18; // Icon + 2 pixels
} else {
#ifdef USE_EINK #ifdef USE_EINK
batteryY += 2; batteryY += 2;
#endif #endif
display->drawXbm(batteryX, batteryY, 7, 11, batteryBitmap_v); display->drawXbm(batteryX, batteryY, 7, 11, batteryBitmap_v);
if (isCharging && isBoltVisibleShared) if (isCharging && isBoltVisibleShared)
display->drawXbm(batteryX + 1, batteryY + 3, 5, 5, lightning_bolt_v); display->drawXbm(batteryX + 1, batteryY + 3, 5, 5, lightning_bolt_v);
else { else {
display->drawXbm(batteryX - 1, batteryY + 4, 8, 3, batteryBitmap_sidegaps_v); display->drawXbm(batteryX - 1, batteryY + 4, 8, 3, batteryBitmap_sidegaps_v);
int fillHeight = 8 * chargePercent / 100; int fillHeight = 8 * chargePercent / 100;
int fillY = batteryY - fillHeight; int fillY = batteryY - fillHeight;
display->fillRect(batteryX + 1, fillY + 10, 5, fillHeight); display->fillRect(batteryX + 1, fillY + 10, 5, fillHeight);
}
batteryX += 9; // Icon + 2 pixels
} }
} }
// === Battery % Display === if (chargePercent != 101) {
char chargeStr[4]; // === Battery % Display ===
snprintf(chargeStr, sizeof(chargeStr), "%d", chargePercent); char chargeStr[4];
int chargeNumWidth = display->getStringWidth(chargeStr); snprintf(chargeStr, sizeof(chargeStr), "%d", chargePercent);
const int batteryOffset = useHorizontalBattery ? 19 : 9; int chargeNumWidth = display->getStringWidth(chargeStr);
const int percentX = x + batteryOffset; display->drawString(batteryX, textY, chargeStr);
display->drawString(percentX, textY, chargeStr); display->drawString(batteryX + chargeNumWidth - 1, textY, "%");
display->drawString(percentX + chargeNumWidth - 1, textY, "%"); if (isBold) {
if (isBold) { display->drawString(batteryX + 1, textY, chargeStr);
display->drawString(percentX + 1, textY, chargeStr); display->drawString(batteryX + chargeNumWidth, textY, "%");
display->drawString(percentX + chargeNumWidth, textY, "%"); }
} }
// === Time and Right-aligned Icons === // === Time and Right-aligned Icons ===

View File

@ -285,6 +285,9 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
xOffset += (isHighResolution) ? 32 : 18; xOffset += (isHighResolution) ? 32 : 18;
} }
int yOffset = (isHighResolution) ? 3 : 1; int yOffset = (isHighResolution) ? 3 : 1;
#ifdef SENSECAP_INDICATOR
yOffset -= 3;
#endif
if (config.display.use_12h_clock) { if (config.display.use_12h_clock) {
display->drawString(startingHourMinuteTextX + xOffset, (display->getHeight() - hourMinuteTextY) - yOffset - 2, display->drawString(startingHourMinuteTextX + xOffset, (display->getHeight() - hourMinuteTextY) - yOffset - 2,
isPM ? "pm" : "am"); isPM ? "pm" : "am");

View File

@ -12,7 +12,10 @@ const uint8_t imgSatellite[] PROGMEM = {
0b00000000, 0b00000000, 0b00000000, 0b00011000, 0b11011011, 0b11111111, 0b11011011, 0b00011000, 0b00000000, 0b00000000, 0b00000000, 0b00011000, 0b11011011, 0b11111111, 0b11011011, 0b00011000,
}; };
const uint8_t imgUSB[] PROGMEM = {0x60, 0x60, 0x30, 0x18, 0x18, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x24, 0x24, 0x24, 0x3C}; const uint8_t imgUSB[] PROGMEM = {0x00, 0xfc, 0xf0, 0xfc, 0x88, 0xff, 0x86, 0xfe, 0x85, 0xfe, 0x89, 0xff, 0xf1, 0xfc, 0x00, 0xfc};
const uint8_t imgUSB_HighResolution[] PROGMEM = {0x00, 0x3e, 0xf8, 0x80, 0x43, 0xf8, 0xc0, 0xc2, 0xff, 0x60, 0x42, 0xfc,
0x3c, 0xc2, 0xff, 0x22, 0x42, 0xf8, 0x3d, 0x42, 0xf8, 0x22, 0xc2, 0xff,
0x61, 0x42, 0xfc, 0xc0, 0xc2, 0xff, 0x80, 0x43, 0xf8, 0x00, 0x3e, 0xf8};
const uint8_t imgPower[] PROGMEM = {0x40, 0x40, 0x40, 0x58, 0x48, 0x08, 0x08, 0x08, const uint8_t imgPower[] PROGMEM = {0x40, 0x40, 0x40, 0x58, 0x48, 0x08, 0x08, 0x08,
0x1C, 0x22, 0x22, 0x41, 0x7F, 0x22, 0x22, 0x22}; 0x1C, 0x22, 0x22, 0x41, 0x7F, 0x22, 0x22, 0x22};
const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C}; const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C};

View File

@ -52,6 +52,40 @@ void InkHUD::LogoApplet::onRender()
setTextColor(WHITE); setTextColor(WHITE);
} }
#ifdef USERPREFS_OEM_IMAGE_DATA // Custom boot screen, if defined in userPrefs.jsonc
// Only show the custom screen at startup
// This allows us to draw the usual Meshtastic logo at shutdown
// The effect is similar to the two-stage userPrefs boot screen used by BaseUI
if (millis() < 10 * 1000UL) {
// Draw the custom logo
const uint8_t logo[] = USERPREFS_OEM_IMAGE_DATA;
drawXBitmap(logoCX - (USERPREFS_OEM_IMAGE_WIDTH / 2), // Left
logoCY - (USERPREFS_OEM_IMAGE_HEIGHT / 2), // Top
logo, // XBM data
USERPREFS_OEM_IMAGE_WIDTH, // Width
USERPREFS_OEM_IMAGE_HEIGHT, // Height
inverted ? WHITE : BLACK // Color
);
// Select the largest font which will still comfortably fit the custom text
setFont(fontLarge);
if (getTextWidth(USERPREFS_OEM_TEXT) > 0.8 * width())
setFont(fontMedium);
if (getTextWidth(USERPREFS_OEM_TEXT) > 0.8 * width())
setFont(fontSmall);
// Draw custom text below logo
int16_t logoB = logoCY + (USERPREFS_OEM_IMAGE_HEIGHT / 2); // Bottom of the logo
printAt(X(0.5), logoB + Y(0.1), USERPREFS_OEM_TEXT, CENTER, TOP);
// Don't draw the normal boot screen, we've already drawn our custom version
return;
}
#endif
drawLogo(logoCX, logoCY, logoW, logoH, inverted ? WHITE : BLACK); drawLogo(logoCX, logoCY, logoW, logoH, inverted ? WHITE : BLACK);
if (!textLeft.empty()) { if (!textLeft.empty()) {

View File

@ -285,7 +285,11 @@ typedef enum _meshtastic_Config_LoRaConfig_RegionCode {
/* Philippines 915mhz */ /* Philippines 915mhz */
meshtastic_Config_LoRaConfig_RegionCode_PH_915 = 21, meshtastic_Config_LoRaConfig_RegionCode_PH_915 = 21,
/* Australia / New Zealand 433MHz */ /* Australia / New Zealand 433MHz */
meshtastic_Config_LoRaConfig_RegionCode_ANZ_433 = 22 meshtastic_Config_LoRaConfig_RegionCode_ANZ_433 = 22,
/* Kazakhstan 433MHz */
meshtastic_Config_LoRaConfig_RegionCode_KZ_433 = 23,
/* Kazakhstan 863MHz */
meshtastic_Config_LoRaConfig_RegionCode_KZ_863 = 24
} meshtastic_Config_LoRaConfig_RegionCode; } meshtastic_Config_LoRaConfig_RegionCode;
/* Standard predefined channel settings /* Standard predefined channel settings
@ -681,8 +685,8 @@ extern "C" {
#define _meshtastic_Config_DisplayConfig_CompassOrientation_ARRAYSIZE ((meshtastic_Config_DisplayConfig_CompassOrientation)(meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED+1)) #define _meshtastic_Config_DisplayConfig_CompassOrientation_ARRAYSIZE ((meshtastic_Config_DisplayConfig_CompassOrientation)(meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED+1))
#define _meshtastic_Config_LoRaConfig_RegionCode_MIN meshtastic_Config_LoRaConfig_RegionCode_UNSET #define _meshtastic_Config_LoRaConfig_RegionCode_MIN meshtastic_Config_LoRaConfig_RegionCode_UNSET
#define _meshtastic_Config_LoRaConfig_RegionCode_MAX meshtastic_Config_LoRaConfig_RegionCode_ANZ_433 #define _meshtastic_Config_LoRaConfig_RegionCode_MAX meshtastic_Config_LoRaConfig_RegionCode_KZ_863
#define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_ANZ_433+1)) #define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_KZ_863+1))
#define _meshtastic_Config_LoRaConfig_ModemPreset_MIN meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST #define _meshtastic_Config_LoRaConfig_ModemPreset_MIN meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST
#define _meshtastic_Config_LoRaConfig_ModemPreset_MAX meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO #define _meshtastic_Config_LoRaConfig_ModemPreset_MAX meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO

View File

@ -630,6 +630,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
#if USERPREFS_EVENT_MODE #if USERPREFS_EVENT_MODE
// If we're in event mode, nobody is a Router or Repeater // If we're in event mode, nobody is a Router or Repeater
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE ||
config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT; config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT;
} }