From 44dbcaac3d4b4ae01ac5e10d632a021b003efbd6 Mon Sep 17 00:00:00 2001 From: Austin Date: Fri, 31 Jul 2026 13:35:20 -0400 Subject: [PATCH 1/3] Actions: Add caching for PlatformIO in native tests workflow (#11309) Also switch to arm64 runners for the tests themelves. In my experience so far, they are faster (and these jobs are heavyy) --- .github/workflows/test_native.yml | 44 ++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test_native.yml b/.github/workflows/test_native.yml index c5186c9f1..2c677a544 100644 --- a/.github/workflows/test_native.yml +++ b/.github/workflows/test_native.yml @@ -7,6 +7,9 @@ on: permissions: {} env: + # Only pushes to the default branch (develop) populate the cache; PR / merge_group runs + # restore it but never save, so they stop filling up the repo's Actions cache storage. + SAVE_CACHE: ${{ github.event_name == 'push' && github.ref_name == github.event.repository.default_branch }} LCOV_CAPTURE_FLAGS: --quiet --capture --include "${PWD}/src/*" --exclude '*/src/mesh/generated/*' --directory .pio/build/coverage/src --base-directory "${PWD}" jobs: @@ -17,7 +20,7 @@ jobs: # check here and fail the PR on a mismatch, keeping the manual count honest. suite-count-check: name: Native Suite Count - runs-on: ubuntu-latest + runs-on: ubuntu-slim permissions: contents: read steps: @@ -56,7 +59,7 @@ jobs: simulator-tests: name: Native Simulator Tests - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm needs: suite-count-check steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 @@ -70,10 +73,26 @@ jobs: - name: Install simulator dependencies run: pip install -U dotmap + - name: Restore PlatformIO cache + id: pio-cache + uses: actions/cache/restore@v6 + with: + path: ~/.platformio/.cache + key: pio-simulator-tests-${{ hashFiles('platformio.ini', 'variants/native/portduino.ini', 'variants/native/portduino/platformio.ini') }} + restore-keys: | + pio-simulator-tests- + # We now run integration test before other build steps (to quickly see runtime failures) - name: Build for native/coverage run: platformio run -e coverage + - name: Save PlatformIO cache + if: env.SAVE_CACHE == 'true' && steps.pio-cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v6 + with: + path: ~/.platformio/.cache + key: pio-simulator-tests-${{ hashFiles('platformio.ini', 'variants/native/portduino.ini', 'variants/native/portduino/platformio.ini') }} + - name: Capture initial coverage information shell: bash run: | @@ -139,7 +158,7 @@ jobs: platformio-tests: name: Native PlatformIO Tests - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm needs: suite-count-check steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 @@ -159,11 +178,27 @@ jobs: - name: Disable BUILD_EPOCH run: sed -i 's/-DBUILD_EPOCH=$UNIX_TIME/#-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini + - name: Restore PlatformIO cache + id: pio-cache + uses: actions/cache/restore@v6 + with: + path: ~/.platformio/.cache + key: pio-coverage-tests-${{ hashFiles('platformio.ini', 'variants/native/portduino.ini', 'variants/native/portduino/platformio.ini') }} + restore-keys: | + pio-coverage-tests- + - name: Build test programs once # One shared build of src + every test program. This is the single source build; gcov then # accumulates coverage counts into this shared .pio/build/coverage/src as the chunks run. run: platformio test -e coverage --without-testing + - name: Save PlatformIO cache + if: env.SAVE_CACHE == 'true' && steps.pio-cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v6 + with: + path: ~/.platformio/.cache + key: pio-coverage-tests-${{ hashFiles('platformio.ini', 'variants/native/portduino.ini', 'variants/native/portduino/platformio.ini') }} + - name: Run tests one area at a time shell: bash run: | @@ -270,7 +305,8 @@ jobs: needs: - simulator-tests - platformio-tests - if: always() + # Run this job even if the previous jobs failed, but skip if the workflow was cancelled. + if: ${{ !cancelled() }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 From 3d8ff48faba7a5c7a68dfc7135f8f2a78ce729fb Mon Sep 17 00:00:00 2001 From: Jason P Date: Fri, 31 Jul 2026 12:29:21 -0500 Subject: [PATCH 2/3] BaseUI: Clean up dead code (#11306) * Clean up dead code * Fix up the WiFi macro to be more directly called --- src/graphics/Screen.cpp | 2 +- src/graphics/Screen.h | 29 -------- src/graphics/draw/DebugRenderer.cpp | 107 ---------------------------- src/graphics/draw/DebugRenderer.h | 7 +- src/graphics/draw/UIRenderer.cpp | 16 ----- src/graphics/draw/UIRenderer.h | 1 - src/graphics/images.h | 15 ---- 7 files changed, 2 insertions(+), 175 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 9c1688db4..6db6ba166 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1467,7 +1467,7 @@ void Screen::setFrames(FrameFocus focus) #if HAS_WIFI && !defined(ARCH_PORTDUINO) if (!hiddenFrames.wifi && isWifiAvailable()) { fsi.positions.wifi = numframes; - normalFrames[numframes++] = graphics::DebugRenderer::drawDebugInfoWiFiTrampoline; + normalFrames[numframes++] = graphics::DebugRenderer::drawFrameWiFi; indicatorIcons.push_back(icon_wifi); } #endif diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 776a14c58..997ec5d57 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -195,27 +195,6 @@ enum class FrameDirection { NEXT, PREVIOUS }; // Forward declarations class Screen; -/// Handles gathering and displaying debug information. -class DebugInfo -{ - public: - DebugInfo(const DebugInfo &) = delete; - DebugInfo &operator=(const DebugInfo &) = delete; - - private: - friend Screen; - - DebugInfo() {} - - /// Renders the debug screen. - void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); - void drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); - void drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); - - /// Protects all of internal state. - concurrency::Lock lock; -}; - /** * @brief This class deals with showing things on the screen of the device. * @@ -647,11 +626,6 @@ class Screen : public concurrency::OSThread // stick to standard EASCII codes) } - /// Returns a handle to the DebugInfo screen. - // - // Use this handle to set things like battery status, user count, GPS status, etc. - DebugInfo *debug_info() { return &debugInfo; } - // Handle observer events int handleStatusUpdate(const meshtastic::Status *arg); int handleUIFrameEvent(const UIFrameEvent *arg); @@ -824,9 +798,6 @@ class Screen : public concurrency::OSThread float compassHeading; uint32_t endCalibrationAt; - /// Holds state for debug information - DebugInfo debugInfo; - /// Display device #ifdef USE_ST7789 ST7789Spi *dispdev; diff --git a/src/graphics/draw/DebugRenderer.cpp b/src/graphics/draw/DebugRenderer.cpp index 95a76c0e9..8e5ec52c3 100644 --- a/src/graphics/draw/DebugRenderer.cpp +++ b/src/graphics/draw/DebugRenderer.cpp @@ -5,7 +5,6 @@ #include "FSCommon.h" #include "MeshService.h" #include "NodeDB.h" -#include "Throttle.h" #include "UIRenderer.h" #include "airtime.h" #include "gps/RTC.h" @@ -16,9 +15,6 @@ #include "graphics/TimeFormatters.h" #include "graphics/images.h" #include "main.h" -#include "mesh/Channels.h" -#include "mesh/generated/meshtastic/deviceonly.pb.h" -#include "sleep.h" #if HAS_WIFI && !defined(ARCH_PORTDUINO) #include "mesh/wifi/WiFiAPClient.h" @@ -28,9 +24,6 @@ #endif #endif -#ifdef ARCH_ESP32 -#include "modules/StoreForwardModule.h" -#endif #include #include #include @@ -39,111 +32,17 @@ using namespace meshtastic; // External variables extern std::unique_ptr screen; -extern PowerStatus *powerStatus; extern NodeStatus *nodeStatus; -extern GPSStatus *gpsStatus; -extern Channels channels; extern AirTime *airTime; // External functions from Screen.cpp extern bool heartbeat; -#ifdef ARCH_ESP32 -extern StoreForwardModule *storeForwardModule; -#endif - namespace graphics { namespace DebugRenderer { -void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -{ - display->setFont(FONT_SMALL); - - // The coordinates define the left starting point of the text - display->setTextAlignment(TEXT_ALIGN_LEFT); - - if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) { - display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); - display->setColor(BLACK); - } - - char channelStr[20]; - snprintf(channelStr, sizeof(channelStr), "#%s", channels.getName(channels.getPrimaryIndex())); - // Display nodes status - if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { - UIRenderer::drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus); - } else { - UIRenderer::drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 3, nodeStatus); - } -#if HAS_GPS - // Display GPS status - if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) { - UIRenderer::drawGpsPowerStatus(display, x, y + 2, gpsStatus); - } else { - if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { - UIRenderer::drawGps(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus); - } else { - UIRenderer::drawGps(display, x + (SCREEN_WIDTH * 0.63), y + 3, gpsStatus); - } - } -#endif - display->setColor(WHITE); - // Draw the channel name - display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr); - // Draw our hardware ID to assist with bluetooth pairing. Either prefix with Info or S&F Logo - if (moduleConfig.store_forward.enabled) { -#ifdef ARCH_ESP32 - if (!Throttle::isWithinTimespanMs(storeForwardModule->lastHeartbeat, - (storeForwardModule->heartbeatInterval * 1200))) { // no heartbeat, overlap a bit -#if (defined(USE_EINK) || defined(HAS_SPI_TFT) || ARCH_PORTDUINO) && !defined(DISPLAY_FORCE_SMALL_FONTS) - display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12, - 8, imgQuestionL1); - display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 11 + FONT_HEIGHT_SMALL, 12, - 8, imgQuestionL2); -#else - display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(screen->ourId), y + 2 + FONT_HEIGHT_SMALL, 8, - 8, imgQuestion); -#endif - } else { -#if (defined(USE_EINK) || defined(HAS_SPI_TFT)) && !defined(DISPLAY_FORCE_SMALL_FONTS) - display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 16, - 8, imgSFL1); - display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(screen->ourId), y + 11 + FONT_HEIGHT_SMALL, 16, - 8, imgSFL2); -#else - display->drawFastImage(x + SCREEN_WIDTH - 13 - display->getStringWidth(screen->ourId), y + 2 + FONT_HEIGHT_SMALL, 11, - 8, imgSF); -#endif - } -#endif - } else { - // TODO: Raspberry Pi supports more than just the one screen size -#if (defined(USE_EINK) || defined(HAS_SPI_TFT) || ARCH_PORTDUINO) && !defined(DISPLAY_FORCE_SMALL_FONTS) - display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, - imgInfoL1); - display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8, - imgInfoL2); -#else - display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(screen->ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, - imgInfo); -#endif - } - - display->drawString(x + SCREEN_WIDTH - display->getStringWidth(screen->ourId), y + FONT_HEIGHT_SMALL, screen->ourId); - - // Draw any log messages - display->drawLogBuffer(x, y + (FONT_HEIGHT_SMALL * 2)); - - /* Display a heartbeat pixel that blinks every time the frame is redrawn */ -#ifdef SHOW_REDRAWS - if (heartbeat) - display->setPixel(0, 0); - heartbeat = !heartbeat; -#endif -} - // **************************** // * WiFi Screen * // **************************** @@ -230,12 +129,6 @@ void drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, i #endif } -// Trampoline functions for DebugInfo class access -void drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -{ - drawFrameWiFi(display, state, x, y); -} - // **************************** // * LoRa Focused Screen * // **************************** diff --git a/src/graphics/draw/DebugRenderer.h b/src/graphics/draw/DebugRenderer.h index 9d28a5e9c..41b4c2bce 100644 --- a/src/graphics/draw/DebugRenderer.h +++ b/src/graphics/draw/DebugRenderer.h @@ -8,7 +8,6 @@ namespace graphics /// Forward declarations class Screen; -class DebugInfo; /** * @brief Debug and diagnostic drawing functions @@ -18,13 +17,9 @@ class DebugInfo; */ namespace DebugRenderer { -// Debug frame functions -void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); +// WiFi status display void drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); -// Trampoline functions for framework callback compatibility -void drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); - // LoRa information display void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); diff --git a/src/graphics/draw/UIRenderer.cpp b/src/graphics/draw/UIRenderer.cpp index 82baf81d8..47bbef516 100644 --- a/src/graphics/draw/UIRenderer.cpp +++ b/src/graphics/draw/UIRenderer.cpp @@ -547,22 +547,6 @@ void UIRenderer::drawGps(OLEDDisplay *display, int16_t x, int16_t y, const mesht } } -// Draw status when GPS is disabled or not present -void UIRenderer::drawGpsPowerStatus(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gps) -{ - const char *displayLine; - int pos; - if (y < FONT_HEIGHT_SMALL) { // Line 1: use short string - displayLine = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT ? "No GPS" : "GPS off"; - pos = display->getWidth() - display->getStringWidth(displayLine); - } else { - displayLine = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT ? "GPS not present" - : "GPS is disabled"; - pos = (display->getWidth() - display->getStringWidth(displayLine)) / 2; - } - display->drawString(x + pos, y, displayLine); -} - void UIRenderer::drawGpsAltitude(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gps) { char displayLine[32]; diff --git a/src/graphics/draw/UIRenderer.h b/src/graphics/draw/UIRenderer.h index 1afddea8f..d6a55dd07 100644 --- a/src/graphics/draw/UIRenderer.h +++ b/src/graphics/draw/UIRenderer.h @@ -42,7 +42,6 @@ class UIRenderer static void drawGpsCoordinates(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus, const char *mode = "line1"); static void drawGpsAltitude(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus); - static void drawGpsPowerStatus(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus); // Overlay and special screens static void drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *text); diff --git a/src/graphics/images.h b/src/graphics/images.h index 046710116..a4ae77e5f 100644 --- a/src/graphics/images.h +++ b/src/graphics/images.h @@ -29,21 +29,6 @@ const uint8_t bluetoothConnectedIcon[36] PROGMEM = {0xfe, 0x01, 0xff, 0x03, 0x03 0xf3, 0x3f, 0x33, 0x30, 0x33, 0x33, 0x33, 0x33, 0x03, 0x33, 0xff, 0x33, 0xfe, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x3f, 0xe0, 0x1f}; -#if (defined(USE_EINK) || defined(HAS_SPI_TFT) || ARCH_PORTDUINO) && !defined(DISPLAY_FORCE_SMALL_FONTS) -const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff}; -const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f}; -const uint8_t imgInfoL1[] PROGMEM = {0xff, 0x01, 0x01, 0x01, 0x1e, 0x7f, 0x1e, 0x01, 0x01, 0x01, 0x01, 0xff}; -const uint8_t imgInfoL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f}; -const uint8_t imgSFL1[] PROGMEM = {0xb6, 0x8f, 0x19, 0x11, 0x31, 0xe3, 0xc2, 0x01, - 0x01, 0xf9, 0xf9, 0x89, 0x89, 0x89, 0x09, 0xeb}; -const uint8_t imgSFL2[] PROGMEM = {0x0e, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, - 0x00, 0x0f, 0x0f, 0x00, 0x08, 0x08, 0x08, 0x0f}; -#else -const uint8_t imgInfo[] PROGMEM = {0xff, 0x81, 0x00, 0xfb, 0xfb, 0x00, 0x81, 0xff}; -const uint8_t imgQuestion[] PROGMEM = {0xbf, 0x41, 0xc0, 0x8b, 0xdb, 0x70, 0xa1, 0xdf}; -const uint8_t imgSF[] PROGMEM = {0xd2, 0xb7, 0xad, 0xbb, 0x92, 0x01, 0xfd, 0xfd, 0x15, 0x85, 0xf5}; -#endif - // === Horizontal battery === // Basic battery design and all related pieces const unsigned char batteryBitmap_h_bottom[] PROGMEM = { From 5bfad255e0723d506cf4133a4d902e9e5e105a46 Mon Sep 17 00:00:00 2001 From: Austin Date: Fri, 31 Jul 2026 13:36:13 -0400 Subject: [PATCH 3/3] Remove Ubuntu 'questing' series from PPA and release channel workflows (#11308) questing went EOL July 9th and no longer builds on PPA --- .github/workflows/daily_packaging.yml | 2 +- .github/workflows/release_channels.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/daily_packaging.yml b/.github/workflows/daily_packaging.yml index 16363f562..abbeb9fb0 100644 --- a/.github/workflows/daily_packaging.yml +++ b/.github/workflows/daily_packaging.yml @@ -35,8 +35,8 @@ jobs: series: - jammy # 22.04 LTS - noble # 24.04 LTS - - questing # 25.10 - resolute # 26.04 LTS + - stonking # 26.10 uses: ./.github/workflows/package_ppa.yml with: ppa_repo: ppa:meshtastic/daily diff --git a/.github/workflows/release_channels.yml b/.github/workflows/release_channels.yml index 3184413ef..f301030e4 100644 --- a/.github/workflows/release_channels.yml +++ b/.github/workflows/release_channels.yml @@ -23,8 +23,8 @@ jobs: series: - jammy # 22.04 LTS - noble # 24.04 LTS - - questing # 25.10 - resolute # 26.04 LTS + - stonking # 26.10 uses: ./.github/workflows/package_ppa.yml with: ppa_repo: |-