mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-08 06:02:05 +00:00
Compare commits
9 Commits
af1a734674
...
673f5d3ede
Author | SHA1 | Date | |
---|---|---|---|
![]() |
673f5d3ede | ||
![]() |
51c90be8ed | ||
![]() |
58ec9893df | ||
![]() |
3f9b116a13 | ||
![]() |
6b4f6a0cef | ||
![]() |
2b5a7ab06d | ||
![]() |
37145abbfb | ||
![]() |
ba296db701 | ||
![]() |
c0e1616382 |
@ -8,8 +8,8 @@ plugins:
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
enabled:
|
||||
- checkov@3.2.435
|
||||
- renovate@40.36.2
|
||||
- checkov@3.2.436
|
||||
- renovate@40.41.0
|
||||
- prettier@3.5.3
|
||||
- trufflehog@3.88.35
|
||||
- yamllint@1.37.1
|
||||
@ -28,7 +28,7 @@ lint:
|
||||
- shellcheck@0.10.0
|
||||
- black@25.1.0
|
||||
- git-diff-check
|
||||
- gitleaks@8.26.0
|
||||
- gitleaks@8.27.0
|
||||
- clang-format@16.0.3
|
||||
ignore:
|
||||
- linters: [ALL]
|
||||
|
@ -11,7 +11,7 @@
|
||||
#define EVENT_RECEIVED_MSG 5
|
||||
// #define EVENT_BOOT 6 // now done with a timed transition
|
||||
#define EVENT_BLUETOOTH_PAIR 7
|
||||
#define EVENT_NODEDB_UPDATED 8 // NodeDB has a big enough change that we think you should turn on the screen
|
||||
// #define EVENT_NODEDB_UPDATED 8 // Now defunct: NodeDB has a big enough change that we think you should turn on the screen
|
||||
#define EVENT_CONTACT_FROM_PHONE 9 // the phone just talked to us over bluetooth
|
||||
#define EVENT_LOW_BATTERY 10 // Battery is critically low, go to sleep
|
||||
#define EVENT_SERIAL_CONNECTED 11
|
||||
|
@ -9,27 +9,14 @@ namespace graphics
|
||||
// Shared UI Helpers
|
||||
// =======================
|
||||
|
||||
// Compact line layout
|
||||
#define compactFirstLine ((FONT_HEIGHT_SMALL - 1) * 1)
|
||||
#define compactSecondLine ((FONT_HEIGHT_SMALL - 1) * 2) - 2
|
||||
#define compactThirdLine ((FONT_HEIGHT_SMALL - 1) * 3) - 4
|
||||
#define compactFourthLine ((FONT_HEIGHT_SMALL - 1) * 4) - 6
|
||||
#define compactFifthLine ((FONT_HEIGHT_SMALL - 1) * 5) - 8
|
||||
#define compactSixthLine ((FONT_HEIGHT_SMALL - 1) * 6) - 10
|
||||
|
||||
// Standard line layout
|
||||
#define standardFirstLine (FONT_HEIGHT_SMALL + 1) * 1
|
||||
#define standardSecondLine (FONT_HEIGHT_SMALL + 1) * 2
|
||||
#define standardThirdLine (FONT_HEIGHT_SMALL + 1) * 3
|
||||
#define standardFourthLine (FONT_HEIGHT_SMALL + 1) * 4
|
||||
|
||||
// More Compact line layout
|
||||
#define moreCompactFirstLine compactFirstLine
|
||||
#define moreCompactSecondLine (moreCompactFirstLine + (FONT_HEIGHT_SMALL - 5))
|
||||
#define moreCompactThirdLine (moreCompactSecondLine + (FONT_HEIGHT_SMALL - 5))
|
||||
#define moreCompactFourthLine (moreCompactThirdLine + (FONT_HEIGHT_SMALL - 5))
|
||||
#define moreCompactFifthLine (moreCompactFourthLine + (FONT_HEIGHT_SMALL - 5))
|
||||
#define moreCompactSixthLine (moreCompactFifthLine + (FONT_HEIGHT_SMALL - 5))
|
||||
// Consistent Line Spacing
|
||||
#define textZeroLine 0
|
||||
#define textFirstLine ((FONT_HEIGHT_SMALL - 1) * 1)
|
||||
#define textSecondLine (textFirstLine + (FONT_HEIGHT_SMALL - 5))
|
||||
#define textThirdLine (textSecondLine + (FONT_HEIGHT_SMALL - 5))
|
||||
#define textFourthLine (textThirdLine + (FONT_HEIGHT_SMALL - 5))
|
||||
#define textFifthLine (textFourthLine + (FONT_HEIGHT_SMALL - 5))
|
||||
#define textSixthLine (textFifthLine + (FONT_HEIGHT_SMALL - 5))
|
||||
|
||||
// Quick screen access
|
||||
#define SCREEN_WIDTH display->getWidth()
|
||||
|
@ -39,20 +39,28 @@ struct Point {
|
||||
}
|
||||
};
|
||||
|
||||
void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading)
|
||||
void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading, int16_t radius)
|
||||
{
|
||||
// Show the compass heading (not implemented in original)
|
||||
// This could draw a "N" indicator or north arrow
|
||||
// For now, we'll draw a simple north indicator
|
||||
const float radius = 8.0f;
|
||||
// const float radius = 17.0f;
|
||||
if (display->width() > 128) {
|
||||
radius += 4;
|
||||
}
|
||||
Point north(0, -radius);
|
||||
north.rotate(-myHeading);
|
||||
north.translate(compassX, compassY);
|
||||
|
||||
// Draw a small "N" or north indicator
|
||||
display->drawCircle(north.x, north.y, 2);
|
||||
display->setFont(FONT_SMALL);
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setColor(BLACK);
|
||||
if (display->width() > 128) {
|
||||
display->fillRect(north.x - 8, north.y - 1, display->getStringWidth("N") + 3, FONT_HEIGHT_SMALL - 6);
|
||||
} else {
|
||||
display->fillRect(north.x - 4, north.y - 1, display->getStringWidth("N") + 2, FONT_HEIGHT_SMALL - 6);
|
||||
}
|
||||
display->setColor(WHITE);
|
||||
display->drawString(north.x, north.y - 3, "N");
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ class Screen;
|
||||
namespace CompassRenderer
|
||||
{
|
||||
// Compass drawing functions
|
||||
void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading);
|
||||
void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading, int16_t radius);
|
||||
void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, uint16_t compassDiam, float headingRadian);
|
||||
void drawArrowToNode(OLEDDisplay *display, int16_t x, int16_t y, int16_t size, float bearing);
|
||||
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include "mesh/generated/meshtastic/deviceonly.pb.h"
|
||||
#include "sleep.h"
|
||||
|
||||
const int textPositions[7] = {textZeroLine, textFirstLine, textSecondLine, textThirdLine,
|
||||
textFourthLine, textFifthLine, textSixthLine};
|
||||
|
||||
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#include <WiFi.h>
|
||||
@ -173,6 +176,7 @@ void drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, i
|
||||
display->clear();
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
int line = 1;
|
||||
|
||||
// === Set Title
|
||||
const char *titleStr = "WiFi";
|
||||
@ -183,13 +187,13 @@ void drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, i
|
||||
const char *wifiName = config.network.wifi_ssid;
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
display->drawString(x, moreCompactFirstLine, "WiFi: Not Connected");
|
||||
display->drawString(x, textPositions[line++], "WiFi: Not Connected");
|
||||
} else {
|
||||
display->drawString(x, moreCompactFirstLine, "WiFi: Connected");
|
||||
display->drawString(x, textPositions[line++], "WiFi: Connected");
|
||||
|
||||
char rssiStr[32];
|
||||
snprintf(rssiStr, sizeof(rssiStr), "RSSI: %d", WiFi.RSSI());
|
||||
display->drawString(x, moreCompactSecondLine, rssiStr);
|
||||
display->drawString(x, textPositions[line++], rssiStr);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -207,36 +211,36 @@ void drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, i
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
char ipStr[64];
|
||||
snprintf(ipStr, sizeof(ipStr), "IP: %s", WiFi.localIP().toString().c_str());
|
||||
display->drawString(x, moreCompactThirdLine, ipStr);
|
||||
display->drawString(x, textPositions[line++], ipStr);
|
||||
} else if (WiFi.status() == WL_NO_SSID_AVAIL) {
|
||||
display->drawString(x, moreCompactThirdLine, "SSID Not Found");
|
||||
display->drawString(x, textPositions[line++], "SSID Not Found");
|
||||
} else if (WiFi.status() == WL_CONNECTION_LOST) {
|
||||
display->drawString(x, moreCompactThirdLine, "Connection Lost");
|
||||
display->drawString(x, textPositions[line++], "Connection Lost");
|
||||
} else if (WiFi.status() == WL_IDLE_STATUS) {
|
||||
display->drawString(x, moreCompactThirdLine, "Idle ... Reconnecting");
|
||||
display->drawString(x, textPositions[line++], "Idle ... Reconnecting");
|
||||
} else if (WiFi.status() == WL_CONNECT_FAILED) {
|
||||
display->drawString(x, moreCompactThirdLine, "Connection Failed");
|
||||
display->drawString(x, textPositions[line++], "Connection Failed");
|
||||
}
|
||||
#ifdef ARCH_ESP32
|
||||
else {
|
||||
// Codes:
|
||||
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code
|
||||
display->drawString(x, moreCompactThirdLine,
|
||||
display->drawString(x, textPositions[line++],
|
||||
WiFi.disconnectReasonName(static_cast<wifi_err_reason_t>(getWifiDisconnectReason())));
|
||||
}
|
||||
#else
|
||||
else {
|
||||
char statusStr[32];
|
||||
snprintf(statusStr, sizeof(statusStr), "Unknown status: %d", WiFi.status());
|
||||
display->drawString(x, moreCompactThirdLine, statusStr);
|
||||
display->drawString(x, textPositions[line++], statusStr);
|
||||
}
|
||||
#endif
|
||||
|
||||
char ssidStr[64];
|
||||
snprintf(ssidStr, sizeof(ssidStr), "SSID: %s", wifiName);
|
||||
display->drawString(x, moreCompactFourthLine, ssidStr);
|
||||
display->drawString(x, textPositions[line++], ssidStr);
|
||||
|
||||
display->drawString(x, moreCompactFifthLine, "URL: http://meshtastic.local");
|
||||
display->drawString(x, textPositions[line++], "URL: http://meshtastic.local");
|
||||
|
||||
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
|
||||
#ifdef SHOW_REDRAWS
|
||||
@ -392,6 +396,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
display->clear();
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
int line = 1;
|
||||
|
||||
// === Set Title
|
||||
const char *titleStr = (SCREEN_WIDTH > 128) ? "LoRa Info" : "LoRa";
|
||||
@ -400,7 +405,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
graphics::drawCommonHeader(display, x, y, titleStr);
|
||||
|
||||
// === First Row: Region / BLE Name ===
|
||||
graphics::UIRenderer::drawNodes(display, x, compactFirstLine + 2, nodeStatus, 0, true, "");
|
||||
graphics::UIRenderer::drawNodes(display, x, textPositions[line] + 2, nodeStatus, 0, true, "");
|
||||
|
||||
uint8_t dmac[6];
|
||||
char shortnameble[35];
|
||||
@ -409,7 +414,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
snprintf(shortnameble, sizeof(shortnameble), "BLE: %s", screen->ourId);
|
||||
int textWidth = display->getStringWidth(shortnameble);
|
||||
int nameX = (SCREEN_WIDTH - textWidth);
|
||||
display->drawString(nameX, compactFirstLine, shortnameble);
|
||||
display->drawString(nameX, textPositions[line++], shortnameble);
|
||||
|
||||
// === Second Row: Radio Preset ===
|
||||
auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
|
||||
@ -420,7 +425,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
}
|
||||
textWidth = display->getStringWidth(regionradiopreset);
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, compactSecondLine, regionradiopreset);
|
||||
display->drawString(nameX, textPositions[line++], regionradiopreset);
|
||||
|
||||
// === Third Row: Frequency / ChanNum ===
|
||||
char frequencyslot[35];
|
||||
@ -430,11 +435,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
if (config.lora.channel_num == 0) {
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "Freq: %smhz", freqStr);
|
||||
} else {
|
||||
if (SCREEN_WIDTH > 128) {
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "Freq/Chan: %smhz (%d)", freqStr, config.lora.channel_num);
|
||||
} else {
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "Frq/Ch: %smhz (%d)", freqStr, config.lora.channel_num);
|
||||
}
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "Freq/Ch: %smhz (%d)", freqStr, config.lora.channel_num);
|
||||
}
|
||||
size_t len = strlen(frequencyslot);
|
||||
if (len >= 4 && strcmp(frequencyslot + len - 4, " (0)") == 0) {
|
||||
@ -442,7 +443,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
}
|
||||
textWidth = display->getStringWidth(frequencyslot);
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, compactThirdLine, frequencyslot);
|
||||
display->drawString(nameX, textPositions[line++], frequencyslot);
|
||||
|
||||
// === Fourth Row: Channel Utilization ===
|
||||
const char *chUtil = "ChUtil:";
|
||||
@ -450,7 +451,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
snprintf(chUtilPercentage, sizeof(chUtilPercentage), "%2.0f%%", airTime->channelUtilizationPercent());
|
||||
|
||||
int chUtil_x = (SCREEN_WIDTH > 128) ? display->getStringWidth(chUtil) + 10 : display->getStringWidth(chUtil) + 5;
|
||||
int chUtil_y = compactFourthLine + 3;
|
||||
int chUtil_y = textPositions[line] + 3;
|
||||
|
||||
int chutil_bar_width = (SCREEN_WIDTH > 128) ? 100 : 50;
|
||||
int chutil_bar_height = (SCREEN_WIDTH > 128) ? 12 : 7;
|
||||
@ -461,7 +462,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
int total_line_content_width = (chUtil_x + chutil_bar_width + display->getStringWidth(chUtilPercentage) + extraoffset) / 2;
|
||||
int starting_position = centerofscreen - total_line_content_width;
|
||||
|
||||
display->drawString(starting_position, compactFourthLine, chUtil);
|
||||
display->drawString(starting_position, textPositions[line++], chUtil);
|
||||
|
||||
// Force 56% or higher to show a full 100% bar, text would still show related percent.
|
||||
if (chutil_percent >= 61) {
|
||||
@ -498,7 +499,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
display->fillRect(starting_position + chUtil_x, chUtil_y, fillRight, chutil_bar_height);
|
||||
}
|
||||
|
||||
display->drawString(starting_position + chUtil_x + chutil_bar_width + extraoffset, compactFourthLine, chUtilPercentage);
|
||||
display->drawString(starting_position + chUtil_x + chutil_bar_width + extraoffset, textPositions[4], chUtilPercentage);
|
||||
}
|
||||
|
||||
// ****************************
|
||||
@ -517,9 +518,7 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
graphics::drawCommonHeader(display, x, y, titleStr);
|
||||
|
||||
// === Layout ===
|
||||
const int yPositions[6] = {moreCompactFirstLine, moreCompactSecondLine, moreCompactThirdLine,
|
||||
moreCompactFourthLine, moreCompactFifthLine, moreCompactSixthLine};
|
||||
int line = 0;
|
||||
int line = 1;
|
||||
const int barHeight = 6;
|
||||
const int labelX = x;
|
||||
const int barsOffset = (SCREEN_WIDTH > 128) ? 24 : 0;
|
||||
@ -548,10 +547,10 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
|
||||
// Label
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->drawString(labelX, yPositions[line], label);
|
||||
display->drawString(labelX, textPositions[line], label);
|
||||
|
||||
// Bar
|
||||
int barY = yPositions[line] + (FONT_HEIGHT_SMALL - barHeight) / 2;
|
||||
int barY = textPositions[line] + (FONT_HEIGHT_SMALL - barHeight) / 2;
|
||||
display->setColor(WHITE);
|
||||
display->drawRect(barX, barY, adjustedBarWidth, barHeight);
|
||||
|
||||
@ -560,7 +559,7 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
|
||||
// Value string
|
||||
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display->drawString(SCREEN_WIDTH - 2, yPositions[line], combinedStr);
|
||||
display->drawString(SCREEN_WIDTH - 2, textPositions[line], combinedStr);
|
||||
};
|
||||
|
||||
// === Memory values ===
|
||||
@ -614,7 +613,7 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
snprintf(appversionstr, sizeof(appversionstr), "Ver.: %s", optstr(APP_VERSION));
|
||||
int textWidth = display->getStringWidth(appversionstr);
|
||||
int nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, yPositions[line], appversionstr);
|
||||
display->drawString(nameX, textPositions[line], appversionstr);
|
||||
|
||||
if (SCREEN_HEIGHT > 64 || (SCREEN_HEIGHT <= 64 && line < 4)) { // Only show uptime if the screen can show it
|
||||
line += 1;
|
||||
@ -632,7 +631,7 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %um", mins);
|
||||
textWidth = display->getStringWidth(uptimeStr);
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, yPositions[line], uptimeStr);
|
||||
display->drawString(nameX, textPositions[line], uptimeStr);
|
||||
}
|
||||
}
|
||||
} // namespace DebugRenderer
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include "meshUtils.h"
|
||||
#include <algorithm>
|
||||
|
||||
const int textPositions[7] = {textZeroLine, textFirstLine, textSecondLine, textThirdLine,
|
||||
textFourthLine, textFifthLine, textSixthLine};
|
||||
|
||||
// Forward declarations for functions defined in Screen.cpp
|
||||
namespace graphics
|
||||
{
|
||||
@ -612,14 +615,12 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
graphics::drawCommonHeader(display, x, y, shortName);
|
||||
|
||||
// Dynamic row stacking with predefined Y positions
|
||||
const int yPositions[5] = {moreCompactFirstLine, moreCompactSecondLine, moreCompactThirdLine, moreCompactFourthLine,
|
||||
moreCompactFifthLine};
|
||||
int line = 0;
|
||||
int line = 1;
|
||||
|
||||
// 1. Long Name (always try to show first)
|
||||
const char *username = (node->has_user && node->user.long_name[0]) ? node->user.long_name : nullptr;
|
||||
if (username && line < 5) {
|
||||
display->drawString(x, yPositions[line++], username);
|
||||
display->drawString(x, textPositions[line++], username);
|
||||
}
|
||||
|
||||
// 2. Signal and Hops (combined on one line, if available)
|
||||
@ -644,7 +645,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
}
|
||||
}
|
||||
if (signalHopsStr[0] && line < 5) {
|
||||
display->drawString(x, yPositions[line++], signalHopsStr);
|
||||
display->drawString(x, textPositions[line++], signalHopsStr);
|
||||
}
|
||||
|
||||
// 3. Heard (last seen, skip if node never seen)
|
||||
@ -661,7 +662,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
: 'm'));
|
||||
}
|
||||
if (seenStr[0] && line < 5) {
|
||||
display->drawString(x, yPositions[line++], seenStr);
|
||||
display->drawString(x, textPositions[line++], seenStr);
|
||||
}
|
||||
|
||||
// 4. Uptime (only show if metric is present)
|
||||
@ -681,7 +682,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
}
|
||||
}
|
||||
if (uptimeStr[0] && line < 5) {
|
||||
display->drawString(x, yPositions[line++], uptimeStr);
|
||||
display->drawString(x, textPositions[line++], uptimeStr);
|
||||
}
|
||||
|
||||
// 5. Distance (only if both nodes have GPS position)
|
||||
@ -733,7 +734,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
}
|
||||
// Only display if we actually have a value!
|
||||
if (haveDistance && distStr[0] && line < 5) {
|
||||
display->drawString(x, yPositions[line++], distStr);
|
||||
display->drawString(x, textPositions[line++], distStr);
|
||||
}
|
||||
|
||||
// Compass rendering for different screen orientations
|
||||
@ -744,7 +745,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
showCompass = true;
|
||||
}
|
||||
if (showCompass) {
|
||||
const int16_t topY = compactFirstLine;
|
||||
const int16_t topY = textPositions[1];
|
||||
const int16_t bottomY = SCREEN_HEIGHT - (FONT_HEIGHT_SMALL - 1);
|
||||
const int16_t usableHeight = bottomY - topY - 5;
|
||||
int16_t compassRadius = usableHeight / 2;
|
||||
@ -757,7 +758,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
const auto &op = ourNode->position;
|
||||
float myHeading = screen->hasHeading() ? screen->getHeading() * PI / 180
|
||||
: screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
CompassRenderer::drawCompassNorth(display, compassX, compassY, myHeading);
|
||||
CompassRenderer::drawCompassNorth(display, compassX, compassY, myHeading, compassRadius);
|
||||
|
||||
const auto &p = node->position;
|
||||
float bearing = GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(p.latitude_i), DegD(p.longitude_i));
|
||||
@ -774,7 +775,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
showCompass = true;
|
||||
}
|
||||
if (showCompass) {
|
||||
int yBelowContent = (line > 0 && line <= 5) ? (yPositions[line - 1] + FONT_HEIGHT_SMALL + 2) : moreCompactFirstLine;
|
||||
int yBelowContent = (line > 1 && line <= 6) ? (textPositions[line - 1] + FONT_HEIGHT_SMALL + 2) : textPositions[1];
|
||||
|
||||
const int margin = 4;
|
||||
#if defined(USE_EINK)
|
||||
@ -800,7 +801,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
const auto &op = ourNode->position;
|
||||
float myHeading = screen->hasHeading() ? screen->getHeading() * PI / 180
|
||||
: screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
CompassRenderer::drawCompassNorth(display, compassX, compassY, myHeading);
|
||||
CompassRenderer::drawCompassNorth(display, compassX, compassY, myHeading, compassRadius);
|
||||
|
||||
const auto &p = node->position;
|
||||
float bearing = GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(p.latitude_i), DegD(p.longitude_i));
|
||||
|
@ -17,6 +17,9 @@
|
||||
#include <RTC.h>
|
||||
#include <cstring>
|
||||
|
||||
const int textPositions[7] = {textZeroLine, textFirstLine, textSecondLine, textThirdLine,
|
||||
textFourthLine, textFifthLine, textSixthLine};
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_GPS
|
||||
|
||||
// External variables
|
||||
@ -38,8 +41,8 @@ namespace UIRenderer
|
||||
void drawGps(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gps)
|
||||
{
|
||||
// Draw satellite image
|
||||
int yOffset = (SCREEN_WIDTH > 128) ? 4 : 2;
|
||||
display->drawFastImage(x + 1, y + yOffset, 8, 8, imgSatellite);
|
||||
int yOffset = (SCREEN_WIDTH > 128) ? 3 : 1;
|
||||
display->drawXbm(x + 1, y + yOffset, imgSatellite_width, imgSatellite_height, imgSatellite);
|
||||
char textString[10];
|
||||
|
||||
if (config.position.fixed_position) {
|
||||
@ -268,7 +271,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
// === Create the shortName and title string ===
|
||||
const char *shortName = (node->has_user && haveGlyphs(node->user.short_name)) ? node->user.short_name : "Node";
|
||||
char titlestr[32] = {0};
|
||||
snprintf(titlestr, sizeof(titlestr), (SCREEN_WIDTH > 128) ? "Fave: %s" : "Fav: %s", shortName);
|
||||
snprintf(titlestr, sizeof(titlestr), "Fav: %s", shortName);
|
||||
|
||||
// === Draw battery/time/mail header (common across screens) ===
|
||||
graphics::drawCommonHeader(display, x, y, titlestr);
|
||||
@ -280,15 +283,13 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
// 4. The first line is ALWAYS at your macro position; subsequent lines use the next available macro slot.
|
||||
|
||||
// List of available macro Y positions in order, from top to bottom.
|
||||
const int yPositions[5] = {moreCompactFirstLine, moreCompactSecondLine, moreCompactThirdLine, moreCompactFourthLine,
|
||||
moreCompactFifthLine};
|
||||
int line = 0; // which slot to use next
|
||||
int line = 1; // which slot to use next
|
||||
|
||||
// === 1. Long Name (always try to show first) ===
|
||||
const char *username = (node->has_user && node->user.long_name[0]) ? node->user.long_name : nullptr;
|
||||
if (username && line < 5) {
|
||||
// Print node's long name (e.g. "Backpack Node")
|
||||
display->drawString(x, yPositions[line++], username);
|
||||
display->drawString(x, textPositions[line++], username);
|
||||
}
|
||||
|
||||
// === 2. Signal and Hops (combined on one line, if available) ===
|
||||
@ -319,7 +320,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
}
|
||||
}
|
||||
if (signalHopsStr[0] && line < 5) {
|
||||
display->drawString(x, yPositions[line++], signalHopsStr);
|
||||
display->drawString(x, textPositions[line++], signalHopsStr);
|
||||
}
|
||||
|
||||
// === 3. Heard (last seen, skip if node never seen) ===
|
||||
@ -337,7 +338,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
: 'm'));
|
||||
}
|
||||
if (seenStr[0] && line < 5) {
|
||||
display->drawString(x, yPositions[line++], seenStr);
|
||||
display->drawString(x, textPositions[line++], seenStr);
|
||||
}
|
||||
|
||||
// === 4. Uptime (only show if metric is present) ===
|
||||
@ -356,7 +357,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %um", mins);
|
||||
}
|
||||
if (uptimeStr[0] && line < 5) {
|
||||
display->drawString(x, yPositions[line++], uptimeStr);
|
||||
display->drawString(x, textPositions[line++], uptimeStr);
|
||||
}
|
||||
|
||||
// === 5. Distance (only if both nodes have GPS position) ===
|
||||
@ -416,7 +417,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
}
|
||||
// Only display if we actually have a value!
|
||||
if (haveDistance && distStr[0] && line < 5) {
|
||||
display->drawString(x, yPositions[line++], distStr);
|
||||
display->drawString(x, textPositions[line++], distStr);
|
||||
}
|
||||
|
||||
// --- Compass Rendering: landscape (wide) screens use the original side-aligned logic ---
|
||||
@ -426,7 +427,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
showCompass = true;
|
||||
}
|
||||
if (showCompass) {
|
||||
const int16_t topY = compactFirstLine;
|
||||
const int16_t topY = textPositions[1];
|
||||
const int16_t bottomY = SCREEN_HEIGHT - (FONT_HEIGHT_SMALL - 1);
|
||||
const int16_t usableHeight = bottomY - topY - 5;
|
||||
int16_t compassRadius = usableHeight / 2;
|
||||
@ -439,7 +440,6 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
const auto &op = ourNode->position;
|
||||
float myHeading = screen->hasHeading() ? screen->getHeading() * PI / 180
|
||||
: screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
CompassRenderer::drawCompassNorth(display, compassX, compassY, myHeading);
|
||||
|
||||
const auto &p = node->position;
|
||||
/* unused
|
||||
@ -449,9 +449,10 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
float bearing = GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(p.latitude_i), DegD(p.longitude_i));
|
||||
if (!config.display.compass_north_top)
|
||||
bearing -= myHeading;
|
||||
CompassRenderer::drawNodeHeading(display, compassX, compassY, compassDiam, bearing);
|
||||
|
||||
display->drawCircle(compassX, compassY, compassRadius);
|
||||
CompassRenderer::drawCompassNorth(display, compassX, compassY, myHeading, compassRadius);
|
||||
CompassRenderer::drawNodeHeading(display, compassX, compassY, compassDiam, bearing);
|
||||
}
|
||||
// else show nothing
|
||||
} else {
|
||||
@ -461,7 +462,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
showCompass = true;
|
||||
}
|
||||
if (showCompass) {
|
||||
int yBelowContent = (line > 0 && line <= 5) ? (yPositions[line - 1] + FONT_HEIGHT_SMALL + 2) : moreCompactFirstLine;
|
||||
int yBelowContent = (line > 0 && line <= 5) ? (textPositions[line - 1] + FONT_HEIGHT_SMALL + 2) : textPositions[1];
|
||||
const int margin = 4;
|
||||
// --------- PATCH FOR EINK NAV BAR (ONLY CHANGE BELOW) -----------
|
||||
#if defined(USE_EINK)
|
||||
@ -488,7 +489,7 @@ void drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t
|
||||
const auto &op = ourNode->position;
|
||||
float myHeading = screen->hasHeading() ? screen->getHeading() * PI / 180
|
||||
: screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
graphics::CompassRenderer::drawCompassNorth(display, compassX, compassY, myHeading);
|
||||
graphics::CompassRenderer::drawCompassNorth(display, compassX, compassY, myHeading, compassRadius);
|
||||
|
||||
const auto &p = node->position;
|
||||
/* unused
|
||||
@ -514,6 +515,7 @@ void drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
display->clear();
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
int line = 1;
|
||||
|
||||
// === Header ===
|
||||
graphics::drawCommonHeader(display, x, y, "");
|
||||
@ -531,9 +533,7 @@ void drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
config.display.heading_bold = false;
|
||||
|
||||
// Display Region and Channel Utilization
|
||||
drawNodes(display, x + 1,
|
||||
((rows == 4) ? compactFirstLine : ((SCREEN_HEIGHT > 64) ? compactFirstLine : moreCompactFirstLine)) + 2, nodeStatus,
|
||||
-1, false, "online");
|
||||
drawNodes(display, x + 1, textPositions[line] + 2, nodeStatus, -1, false, "online");
|
||||
|
||||
char uptimeStr[32] = "";
|
||||
uint32_t uptime = millis() / 1000;
|
||||
@ -547,9 +547,7 @@ void drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %uh %um", hours, mins);
|
||||
else
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %um", mins);
|
||||
display->drawString(SCREEN_WIDTH - display->getStringWidth(uptimeStr),
|
||||
((rows == 4) ? compactFirstLine : ((SCREEN_HEIGHT > 64) ? compactFirstLine : moreCompactFirstLine)),
|
||||
uptimeStr);
|
||||
display->drawString(SCREEN_WIDTH - display->getStringWidth(uptimeStr), textPositions[line++], uptimeStr);
|
||||
|
||||
// === Second Row: Satellites and Voltage ===
|
||||
config.display.heading_bold = false;
|
||||
@ -562,13 +560,9 @@ void drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
} else {
|
||||
displayLine = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT ? "No GPS" : "GPS off";
|
||||
}
|
||||
display->drawString(
|
||||
0, ((rows == 4) ? compactSecondLine : ((SCREEN_HEIGHT > 64) ? compactSecondLine : moreCompactSecondLine)),
|
||||
displayLine);
|
||||
display->drawString(0, textPositions[line], displayLine);
|
||||
} else {
|
||||
UIRenderer::drawGps(
|
||||
display, 0, ((rows == 4) ? compactSecondLine : ((SCREEN_HEIGHT > 64) ? compactSecondLine : moreCompactSecondLine)),
|
||||
gpsStatus);
|
||||
UIRenderer::drawGps(display, 0, textPositions[line], gpsStatus);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -577,21 +571,16 @@ void drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
int batV = powerStatus->getBatteryVoltageMv() / 1000;
|
||||
int batCv = (powerStatus->getBatteryVoltageMv() % 1000) / 10;
|
||||
snprintf(batStr, sizeof(batStr), "%01d.%02dV", batV, batCv);
|
||||
display->drawString(
|
||||
x + SCREEN_WIDTH - display->getStringWidth(batStr),
|
||||
((rows == 4) ? compactSecondLine : ((SCREEN_HEIGHT > 64) ? compactSecondLine : moreCompactSecondLine)), batStr);
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(batStr), textPositions[line++], batStr);
|
||||
} else {
|
||||
display->drawString(
|
||||
x + SCREEN_WIDTH - display->getStringWidth("USB"),
|
||||
((rows == 4) ? compactSecondLine : ((SCREEN_HEIGHT > 64) ? compactSecondLine : moreCompactSecondLine)), "USB");
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("USB"), textPositions[line++], "USB");
|
||||
}
|
||||
|
||||
config.display.heading_bold = origBold;
|
||||
|
||||
// === Third Row: Bluetooth Off (Only If Actually Off) ===
|
||||
if (!config.bluetooth.enabled) {
|
||||
display->drawString(
|
||||
0, ((rows == 4) ? compactThirdLine : ((SCREEN_HEIGHT > 64) ? compactThirdLine : moreCompactThirdLine)), "BT off");
|
||||
display->drawString(0, textPositions[line++], "BT off");
|
||||
}
|
||||
|
||||
// === Third & Fourth Rows: Node Identity ===
|
||||
@ -619,28 +608,18 @@ void drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
}
|
||||
textWidth = display->getStringWidth(combinedName);
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(
|
||||
nameX,
|
||||
((rows == 4) ? compactThirdLine : ((SCREEN_HEIGHT > 64) ? compactFourthLine : moreCompactFourthLine)) + yOffset,
|
||||
combinedName);
|
||||
display->drawString(nameX, ((rows == 4) ? textPositions[line++] : textPositions[line++]) + yOffset, combinedName);
|
||||
} else {
|
||||
// === LongName Centered ===
|
||||
textWidth = display->getStringWidth(longName);
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
yOffset = (strcmp(shortnameble, "") == 0) ? 1 : 0;
|
||||
if (yOffset == 1) {
|
||||
yOffset = (SCREEN_WIDTH > 128) ? 0 : 7;
|
||||
}
|
||||
display->drawString(
|
||||
nameX,
|
||||
((rows == 4) ? compactThirdLine : ((SCREEN_HEIGHT > 64) ? compactFourthLine : moreCompactFourthLine)) + yOffset,
|
||||
longName);
|
||||
yOffset = (rows == 4 && SCREEN_WIDTH <= 128) ? 7 : 0;
|
||||
display->drawString(nameX, textPositions[line++] + yOffset, longName);
|
||||
|
||||
// === Fourth Row: ShortName Centered ===
|
||||
// === ShortName Centered ===
|
||||
textWidth = display->getStringWidth(shortnameble);
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX,
|
||||
((rows == 4) ? compactFourthLine : ((SCREEN_HEIGHT > 64) ? compactFifthLine : moreCompactFifthLine)),
|
||||
shortnameble);
|
||||
display->drawString(nameX, textPositions[line++] + yOffset, shortnameble);
|
||||
}
|
||||
}
|
||||
|
||||
@ -886,6 +865,7 @@ void drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
display->clear();
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
int line = 1;
|
||||
|
||||
// === Set Title
|
||||
const char *titleStr = "GPS";
|
||||
@ -905,10 +885,11 @@ void drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
} else {
|
||||
displayLine = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT ? "No GPS" : "GPS off";
|
||||
}
|
||||
display->drawFastImage(x + 1, y, 8, 8, imgSatellite);
|
||||
display->drawString(x + 11, ((SCREEN_HEIGHT > 64) ? compactFirstLine : moreCompactFirstLine), displayLine);
|
||||
int yOffset = (SCREEN_WIDTH > 128) ? 3 : 1;
|
||||
display->drawXbm(x + 1, textPositions[line] + yOffset, imgSatellite_width, imgSatellite_height, imgSatellite);
|
||||
display->drawString(x + 11, textPositions[line++], displayLine);
|
||||
} else {
|
||||
UIRenderer::drawGps(display, 0, ((SCREEN_HEIGHT > 64) ? compactFirstLine : moreCompactFirstLine), gpsStatus);
|
||||
UIRenderer::drawGps(display, 0, textPositions[line++], gpsStatus);
|
||||
}
|
||||
|
||||
config.display.heading_bold = origBold;
|
||||
@ -939,17 +920,17 @@ void drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
} else {
|
||||
snprintf(DisplayLineTwo, sizeof(DisplayLineTwo), " Alt: %.0im", geoCoord.getAltitude());
|
||||
}
|
||||
display->drawString(x, ((SCREEN_HEIGHT > 64) ? compactSecondLine : moreCompactSecondLine), DisplayLineTwo);
|
||||
display->drawString(x, textPositions[line++], DisplayLineTwo);
|
||||
|
||||
// === Third Row: Latitude ===
|
||||
char latStr[32];
|
||||
snprintf(latStr, sizeof(latStr), " Lat: %.5f", geoCoord.getLatitude() * 1e-7);
|
||||
display->drawString(x, ((SCREEN_HEIGHT > 64) ? compactThirdLine : moreCompactThirdLine), latStr);
|
||||
display->drawString(x, textPositions[line++], latStr);
|
||||
|
||||
// === Fourth Row: Longitude ===
|
||||
char lonStr[32];
|
||||
snprintf(lonStr, sizeof(lonStr), " Lon: %.5f", geoCoord.getLongitude() * 1e-7);
|
||||
display->drawString(x, ((SCREEN_HEIGHT > 64) ? compactFourthLine : moreCompactFourthLine), lonStr);
|
||||
display->drawString(x, textPositions[line++], lonStr);
|
||||
|
||||
// === Fifth Row: Date ===
|
||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true);
|
||||
@ -958,14 +939,14 @@ void drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
UIRenderer::formatDateTime(datetimeStr, sizeof(datetimeStr), rtc_sec, display, showTime);
|
||||
char fullLine[40];
|
||||
snprintf(fullLine, sizeof(fullLine), " Date: %s", datetimeStr);
|
||||
display->drawString(0, ((SCREEN_HEIGHT > 64) ? compactFifthLine : moreCompactFifthLine), fullLine);
|
||||
display->drawString(0, textPositions[line++], fullLine);
|
||||
}
|
||||
|
||||
// === Draw Compass if heading is valid ===
|
||||
if (validHeading) {
|
||||
// --- Compass Rendering: landscape (wide) screens use original side-aligned logic ---
|
||||
if (SCREEN_WIDTH > SCREEN_HEIGHT) {
|
||||
const int16_t topY = compactFirstLine;
|
||||
const int16_t topY = textPositions[1];
|
||||
const int16_t bottomY = SCREEN_HEIGHT - (FONT_HEIGHT_SMALL - 1); // nav row height
|
||||
const int16_t usableHeight = bottomY - topY - 5;
|
||||
|
||||
@ -998,7 +979,7 @@ void drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
} else {
|
||||
// Portrait or square: put compass at the bottom and centered, scaled to fit available space
|
||||
// For E-Ink screens, account for navigation bar at the bottom!
|
||||
int yBelowContent = ((SCREEN_HEIGHT > 64) ? compactFifthLine : moreCompactFifthLine) + FONT_HEIGHT_SMALL + 2;
|
||||
int yBelowContent = textPositions[5] + FONT_HEIGHT_SMALL + 2;
|
||||
const int margin = 4;
|
||||
int availableHeight =
|
||||
#if defined(USE_EINK)
|
||||
|
@ -6,7 +6,12 @@ const uint8_t SATELLITE_IMAGE[] PROGMEM = {0x00, 0x08, 0x00, 0x1C, 0x00, 0x0E, 0
|
||||
0xF8, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC8, 0x01, 0x9C, 0x54,
|
||||
0x0E, 0x52, 0x07, 0x48, 0x02, 0x26, 0x00, 0x10, 0x00, 0x0E};
|
||||
|
||||
const uint8_t imgSatellite[] PROGMEM = {0x70, 0x71, 0x22, 0xFA, 0xFA, 0x22, 0x71, 0x70};
|
||||
#define imgSatellite_width 8
|
||||
#define imgSatellite_height 8
|
||||
const uint8_t imgSatellite[] PROGMEM = {
|
||||
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 imgPower[] PROGMEM = {0x40, 0x40, 0x40, 0x58, 0x48, 0x08, 0x08, 0x08,
|
||||
0x1C, 0x22, 0x22, 0x41, 0x7F, 0x22, 0x22, 0x22};
|
||||
|
@ -5,7 +5,7 @@ E-Ink display driver
|
||||
- Manufacturer: DKE
|
||||
- Size: 2.13 inch
|
||||
- Resolution: 122px x 250px
|
||||
- Flex connector marking: FPC-7528B
|
||||
- Flex connector marking (not a unique identifier): FPC-7528B
|
||||
|
||||
Note: this is from an older generation of DKE panels, which still used Solomon Systech controller ICs.
|
||||
DKE's website suggests that the latest DEPG0213BN displays may use Fitipower controllers instead.
|
||||
|
@ -5,7 +5,7 @@ E-Ink display driver
|
||||
- Manufacturer: DKE
|
||||
- Size: 2.9 inch
|
||||
- Resolution: 128px x 296px
|
||||
- Flex connector marking: FPC-7519 rev.b
|
||||
- Flex connector marking (not a unique identifier): FPC-7519 rev.b
|
||||
|
||||
*/
|
||||
|
||||
|
@ -5,7 +5,7 @@ E-Ink display driver
|
||||
- Manufacturer: Goodisplay
|
||||
- Size: 1.54 inch
|
||||
- Resolution: 200px x 200px
|
||||
- Flex connector marking: FPC-B001
|
||||
- Flex connector marking (not a unique identifier): FPC-B001
|
||||
|
||||
*/
|
||||
|
||||
|
@ -5,7 +5,9 @@ E-Ink display driver
|
||||
- Manufacturer: Goodisplay
|
||||
- Size: 2.13 inch
|
||||
- Resolution: 250px x 122px
|
||||
- Flex connector marking: FPC-A002
|
||||
- Flex connector marking (not a unique identifier):
|
||||
- FPC-A002
|
||||
- FPC-A005 20.06.15 TRX
|
||||
|
||||
*/
|
||||
|
||||
|
@ -5,7 +5,7 @@ E-Ink display driver
|
||||
- Manufacturer: Holitech
|
||||
- Size: 4.2 inch
|
||||
- Resolution: 400px x 300px
|
||||
- Flex connector marking: HINK-E042A07-FPC-A1
|
||||
- Flex connector marking (not a unique identifier): HINK-E042A07-FPC-A1
|
||||
- Silver sticker with QR code, marked: HE042A87
|
||||
|
||||
Note: as of Feb. 2025, these panels are used for "WeActStudio 4.2in B&W" display modules
|
||||
|
@ -5,7 +5,6 @@ E-Ink display driver
|
||||
- Manufacturer: WISEVAST
|
||||
- Size: 2.13 inch
|
||||
- Resolution: 122px x 255px
|
||||
- Flex connector marking: Soldering connector, no connector is needed
|
||||
|
||||
*/
|
||||
|
||||
|
@ -5,7 +5,7 @@ E-Ink display driver
|
||||
- Manufacturer: Wisevast
|
||||
- Size: 2.13 inch
|
||||
- Resolution: 122px x 250px
|
||||
- Flex connector marking: HINK-E0213A162-FPC-A0 (Hidden, printed on back-side)
|
||||
- Flex connector marking (not a unique identifier): HINK-E0213A162-FPC-A0 (Hidden, printed on back-side)
|
||||
|
||||
Note: this display uses an uncommon controller IC, Fitipower JD79656.
|
||||
It is implemented as a "one-off", directly inheriting the EInk base class, unlike SSD16XX displays.
|
||||
|
59
src/graphics/niche/Drivers/EInk/ZJY128296_029EAAMFGN.cpp
Normal file
59
src/graphics/niche/Drivers/EInk/ZJY128296_029EAAMFGN.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include "./ZJY128296_029EAAMFGN.h"
|
||||
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
using namespace NicheGraphics::Drivers;
|
||||
|
||||
// Map the display controller IC's output to the connected panel
|
||||
void ZJY128296_029EAAMFGN::configScanning()
|
||||
{
|
||||
// "Driver output control"
|
||||
// Scan gates from 0 to 295 (vertical resolution 296px)
|
||||
sendCommand(0x01);
|
||||
sendData(0x27); // Number of gates (295, bits 0-7)
|
||||
sendData(0x01); // Number of gates (295, bit 8)
|
||||
sendData(0x00); // (Do not invert scanning order)
|
||||
}
|
||||
|
||||
// Specify which information is used to control the sequence of voltages applied to move the pixels
|
||||
// - For this display, configUpdateSequence() specifies that a suitable LUT will be loaded from
|
||||
// the controller IC's OTP memory, when the update procedure begins.
|
||||
void ZJY128296_029EAAMFGN::configWaveform()
|
||||
{
|
||||
sendCommand(0x3C); // Border waveform:
|
||||
sendData(0x05); // Screen border should follow LUT1 waveform (actively drive pixels white)
|
||||
|
||||
sendCommand(0x18); // Temperature sensor:
|
||||
sendData(0x80); // Use internal temperature sensor to select an appropriate refresh waveform
|
||||
}
|
||||
|
||||
void ZJY128296_029EAAMFGN::configUpdateSequence()
|
||||
{
|
||||
switch (updateType) {
|
||||
case FAST:
|
||||
sendCommand(0x22); // Set "update sequence"
|
||||
sendData(0xFF); // Will load LUT from OTP memory, Display mode 2 "differential refresh"
|
||||
break;
|
||||
|
||||
case FULL:
|
||||
default:
|
||||
sendCommand(0x22); // Set "update sequence"
|
||||
sendData(0xF7); // Will load LUT from OTP memory
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Once the refresh operation has been started,
|
||||
// begin periodically polling the display to check for completion, using the normal Meshtastic threading code
|
||||
// Only used when refresh is "async"
|
||||
void ZJY128296_029EAAMFGN::detachFromUpdate()
|
||||
{
|
||||
switch (updateType) {
|
||||
case FAST:
|
||||
return beginPolling(50, 300); // At least 300ms for fast refresh
|
||||
case FULL:
|
||||
default:
|
||||
return beginPolling(100, 2000); // At least 2 seconds for full refresh
|
||||
}
|
||||
}
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
44
src/graphics/niche/Drivers/EInk/ZJY128296_029EAAMFGN.h
Normal file
44
src/graphics/niche/Drivers/EInk/ZJY128296_029EAAMFGN.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
|
||||
E-Ink display driver
|
||||
- ZJY128296-029EAAMFGN
|
||||
- Manufacturer: Zhongjingyuan
|
||||
- Size: 2.9 inch
|
||||
- Resolution: 128px x 296px
|
||||
- Flex connector label (not a unique identifier): FPC-A005 20.06.15 TRX
|
||||
|
||||
Note: as of Feb. 2025, these panels are used for "WeActStudio 2.9in B&W" display modules
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#include "./SSD16XX.h"
|
||||
|
||||
namespace NicheGraphics::Drivers
|
||||
{
|
||||
class ZJY128296_029EAAMFGN : public SSD16XX
|
||||
{
|
||||
// Display properties
|
||||
private:
|
||||
static constexpr uint32_t width = 128;
|
||||
static constexpr uint32_t height = 296;
|
||||
static constexpr UpdateTypes supported = (UpdateTypes)(FULL | FAST);
|
||||
|
||||
public:
|
||||
ZJY128296_029EAAMFGN() : SSD16XX(width, height, supported) {}
|
||||
|
||||
protected:
|
||||
void configScanning() override;
|
||||
void configWaveform() override;
|
||||
void configUpdateSequence() override;
|
||||
void detachFromUpdate() override;
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::Drivers
|
||||
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
@ -1524,7 +1524,6 @@ void NodeDB::addFromContact(meshtastic_SharedContact contact)
|
||||
// Mark the node's key as manually verified to indicate trustworthiness.
|
||||
info->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
|
||||
updateGUIforNode = info;
|
||||
powerFSM.trigger(EVENT_NODEDB_UPDATED);
|
||||
notifyObservers(true); // Force an update whether or not our node counts have changed
|
||||
saveNodeDatabaseToDisk();
|
||||
}
|
||||
@ -1568,7 +1567,6 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde
|
||||
|
||||
if (changed) {
|
||||
updateGUIforNode = info;
|
||||
powerFSM.trigger(EVENT_NODEDB_UPDATED);
|
||||
notifyObservers(true); // Force an update whether or not our node counts have changed
|
||||
|
||||
// We just changed something about a User,
|
||||
|
@ -1737,7 +1737,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
const char *label = graphics::emotes[j].label;
|
||||
if (!label || !*label)
|
||||
continue;
|
||||
char *found = strstr(msg + pos, label);
|
||||
const char *found = strstr(msg + pos, label);
|
||||
if (found && (found - msg) < nextEmote) {
|
||||
nextEmote = found - msg;
|
||||
}
|
||||
@ -1929,7 +1929,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
const char *label = graphics::emotes[j].label;
|
||||
if (label[0] == 0)
|
||||
continue;
|
||||
char *found = strstr(msg + pos, label);
|
||||
const char *found = strstr(msg + pos, label);
|
||||
if (found && (found - msg) < nextEmote) {
|
||||
nextEmote = found - msg;
|
||||
}
|
||||
|
@ -22,6 +22,9 @@
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
|
||||
const int textPositions[7] = {textZeroLine, textFirstLine, textSecondLine, textThirdLine,
|
||||
textFourthLine, textFifthLine, textSixthLine};
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
|
||||
|
||||
// Sensors
|
||||
@ -343,6 +346,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
|
||||
display->clear();
|
||||
display->setFont(FONT_SMALL);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
int line = 1;
|
||||
|
||||
// === Set Title
|
||||
const char *titleStr = (SCREEN_WIDTH > 128) ? "Environment" : "Env.";
|
||||
@ -352,7 +356,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
|
||||
|
||||
// === Row spacing setup ===
|
||||
const int rowHeight = FONT_HEIGHT_SMALL - 4;
|
||||
int currentY = compactFirstLine;
|
||||
int currentY = textPositions[line++];
|
||||
|
||||
// === Show "No Telemetry" if no data available ===
|
||||
if (!lastMeasurementPacket) {
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
|
||||
const int textPositions[7] = {textZeroLine, textFirstLine, textSecondLine, textThirdLine,
|
||||
textFourthLine, textFifthLine, textSixthLine};
|
||||
|
||||
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
|
||||
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
|
||||
|
||||
@ -112,6 +115,7 @@ void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *s
|
||||
display->clear();
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
int line = 1;
|
||||
|
||||
// === Set Title
|
||||
const char *titleStr = (SCREEN_WIDTH > 128) ? "Power Telem." : "Power";
|
||||
@ -121,7 +125,7 @@ void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *s
|
||||
|
||||
if (lastMeasurementPacket == nullptr) {
|
||||
// In case of no valid packet, display "Power Telemetry", "No measurement"
|
||||
display->drawString(x, compactFirstLine, "No measurement");
|
||||
display->drawString(x, textPositions[line++], "No measurement");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -132,7 +136,7 @@ void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *s
|
||||
|
||||
const meshtastic_Data &p = lastMeasurementPacket->decoded;
|
||||
if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &lastMeasurement)) {
|
||||
display->drawString(x, compactFirstLine, "Measurement Error");
|
||||
display->drawString(x, textPositions[line++], "Measurement Error");
|
||||
LOG_ERROR("Unable to decode last packet");
|
||||
return;
|
||||
}
|
||||
@ -140,11 +144,11 @@ void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *s
|
||||
// Display "Pow. From: ..."
|
||||
char fromStr[64];
|
||||
snprintf(fromStr, sizeof(fromStr), "Pow. From: %s (%us)", lastSender, agoSecs);
|
||||
display->drawString(x, compactFirstLine, fromStr);
|
||||
display->drawString(x, textPositions[line++], fromStr);
|
||||
|
||||
// Display current and voltage based on ...power_metrics.has_[channel/voltage/current]... flags
|
||||
const auto &m = lastMeasurement.variant.power_metrics;
|
||||
int lineY = compactSecondLine;
|
||||
int lineY = textSecondLine;
|
||||
|
||||
auto drawLine = [&](const char *label, float voltage, float current) {
|
||||
char lineStr[64];
|
||||
|
@ -140,7 +140,7 @@ void WaypointModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians
|
||||
else
|
||||
myHeading = screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
graphics::CompassRenderer::drawCompassNorth(display, compassX, compassY, myHeading);
|
||||
graphics::CompassRenderer::drawCompassNorth(display, compassX, compassY, myHeading, (compassDiam / 2));
|
||||
|
||||
// Compass bearing to waypoint
|
||||
float bearingToOther =
|
||||
|
@ -115,12 +115,17 @@ int32_t PaxcounterModule::runOnce()
|
||||
#if HAS_SCREEN
|
||||
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include "graphics/SharedUIDisplay.h"
|
||||
|
||||
const int textPositions[7] = {textZeroLine, textFirstLine, textSecondLine, textThirdLine,
|
||||
textFourthLine, textFifthLine, textSixthLine};
|
||||
|
||||
void PaxcounterModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->clear();
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
int line = 1;
|
||||
|
||||
// === Set Title
|
||||
const char *titleStr = "Pax";
|
||||
@ -136,7 +141,7 @@ void PaxcounterModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawStringf(display->getWidth() / 2 + x, compactFirstLine, buffer, "WiFi: %d\nBLE: %d\nUptime: %ds",
|
||||
display->drawStringf(display->getWidth() / 2 + x, textPositions[line++], buffer, "WiFi: %d\nBLE: %d\nUptime: %ds",
|
||||
count_from_libpax.wifi_count, count_from_libpax.ble_count, millis() / 1000);
|
||||
}
|
||||
#endif // HAS_SCREEN
|
||||
|
@ -60,7 +60,7 @@ void MotionSensor::drawFrameCalibration(OLEDDisplay *display, OLEDDisplayUiState
|
||||
compassY = y + FONT_HEIGHT_SMALL + (display->getHeight() - FONT_HEIGHT_SMALL) / 2;
|
||||
}
|
||||
display->drawCircle(compassX, compassY, compassDiam / 2);
|
||||
graphics::CompassRenderer::drawCompassNorth(display, compassX, compassY, screen->getHeading() * PI / 180);
|
||||
graphics::CompassRenderer::drawCompassNorth(display, compassX, compassY, screen->getHeading() * PI / 180, (compassDiam / 2));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user