Merge branch 'develop' into indicator-comms

This commit is contained in:
Manuel
2026-07-31 21:10:52 +02:00
committed by GitHub
10 changed files with 44 additions and 181 deletions

View File

@@ -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

View File

@@ -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: |-

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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 <DisplayFormatters.h>
#include <RadioLibInterface.h>
#include <target_specific.h>
@@ -39,111 +32,17 @@ using namespace meshtastic;
// External variables
extern std::unique_ptr<graphics::Screen> 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 *
// ****************************

View File

@@ -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);

View File

@@ -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];

View File

@@ -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);

View File

@@ -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 = {