mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-15 15:22:34 +00:00
Compare commits
8 Commits
casic-clea
...
event/burn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81f466c438 | ||
|
|
4e8fc620b1 | ||
|
|
1d926cecc3 | ||
|
|
6a74f06d57 | ||
|
|
49e8525095 | ||
|
|
cf574c71d8 | ||
|
|
abe0a34fc0 | ||
|
|
71b6508ad3 |
BIN
branding/logo_320x240.png
Normal file
BIN
branding/logo_320x240.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 75 KiB |
BIN
branding/logo_320x480.png
Normal file
BIN
branding/logo_320x480.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 151 KiB |
BIN
branding/logo_480x320.png
Normal file
BIN
branding/logo_480x320.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
BIN
branding/logo_480x480.png
Normal file
BIN
branding/logo_480x480.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 199 KiB |
BIN
branding/logo_800x480.png
Normal file
BIN
branding/logo_800x480.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 276 KiB |
@@ -1539,13 +1539,6 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
||||
if (perhapsSetRTC(RTCQualityGPS, t) == RTCSetResultInvalidTime) {
|
||||
// Clear the GPS buffer if we got an invalid time
|
||||
clearBuffer();
|
||||
// Clear the RTC from the L76K, L76B, and clones
|
||||
if (IS_ONE_OF(gnssModel, GNSS_MODEL_MTK_L76B, GNSS_MODEL_MTK)) {
|
||||
// Clear the RTC from the L76 and MTK GPS modules
|
||||
LOG_DEBUG("Clearing RTC from L76K/L76B");
|
||||
int msglen = makeCASPacket(0x06, 0x02, sizeof(_message_CAS_CFG_RST_FACTORY), _message_CAS_CFG_RST_FACTORY);
|
||||
_serial_gps->write(_message_CAS_CFG_RST_FACTORY, msglen);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else
|
||||
|
||||
@@ -226,7 +226,14 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
time_t res = gm_mktime(&t);
|
||||
struct timeval tv;
|
||||
tv.tv_sec = res;
|
||||
tv.tv_usec = 0; // time.centisecond() * (10 / 1000);
|
||||
tv.tv_usec = 0; // time.centisecond() * (10 / 1000);
|
||||
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
||||
#ifdef BUILD_EPOCH
|
||||
if (tv.tv_sec < BUILD_EPOCH) {
|
||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||
return RTCSetResultInvalidTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
// LOG_DEBUG("Got time from GPS month=%d, year=%d, unixtime=%ld", t.tm_mon, t.tm_year, tv.tv_sec);
|
||||
if (t.tm_year < 0 || t.tm_year >= 300) {
|
||||
|
||||
@@ -27,13 +27,6 @@ static const uint8_t _message_CAS_CFG_RST_FACTORY[] = {
|
||||
0x03 // Startup Mode: Factory
|
||||
};
|
||||
|
||||
// Clear RTC data
|
||||
static const uint8_t _message_CAS_CFG_RST_RTC[] = {
|
||||
0x00, 0x01, // NavBbrMask: Clear RTC data
|
||||
0x01, // Reset Mode: Controlled Software reset
|
||||
0x00 // Reserved
|
||||
};
|
||||
|
||||
// CFG_RATE (0x06, 0x01)
|
||||
// 1HZ update rate, this should always be the case after
|
||||
// factory reset but update it regardless
|
||||
|
||||
156
src/graphics/BRC.cpp
Normal file
156
src/graphics/BRC.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
#include "BRC.h"
|
||||
#include "GPSStatus.h"
|
||||
#include "gps/GeoCoord.h"
|
||||
#include "graphics/Screen.h"
|
||||
|
||||
#if HAS_SCREEN
|
||||
|
||||
using namespace meshtastic;
|
||||
|
||||
const int32_t BRC_LATI = (40.786958 * 1e7);
|
||||
const int32_t BRC_LONI = (-119.202994 * 1e7);
|
||||
const double BRC_LATF = 40.786958;
|
||||
const double BRC_LONF = -119.202994;
|
||||
const double BRC_NOON = 1.5;
|
||||
const double RAD_TO_HOUR = (6.0 / 3.14159);
|
||||
const double METER_TO_FEET = 3.28084;
|
||||
const double FEET_TO_METER = 1.0 / METER_TO_FEET;
|
||||
|
||||
// Pre-calculated street data for performance
|
||||
struct StreetInfo {
|
||||
float center;
|
||||
float width;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/*
|
||||
# python code to generate the StreetInfo
|
||||
|
||||
esp_center = 2500
|
||||
street_info = [
|
||||
# name, width, preceeding block depth
|
||||
('Esp', 40, 60), # block size is fake
|
||||
('A', 30, 400),
|
||||
('B', 30, 250),
|
||||
('C', 30, 250),
|
||||
('D', 30, 250),
|
||||
('E', 40, 250),
|
||||
('F', 30, 450), # E-F block is exra deep
|
||||
('G', 30, 250),
|
||||
('H', 30, 250),
|
||||
('I', 30, 250),
|
||||
('J', 30, 150),
|
||||
('K', 50, 150),
|
||||
]
|
||||
|
||||
street_center = esp_center - street_info[0][1] //2 - street_info[0][2]
|
||||
last_center = esp_center
|
||||
for (name, street_width, block_width) in street_info:
|
||||
offset = (street_width + block_width) // 2
|
||||
street_center += street_width //2 + block_width
|
||||
|
||||
dia = street_center * 2
|
||||
dist = street_center - last_center
|
||||
|
||||
print(f"{{{street_center}, {offset}, \"{name}\"}},\t// +{dist}ft\tdia: {dia:,}ft")
|
||||
|
||||
last_center = street_center
|
||||
street_center += street_width //2
|
||||
|
||||
street_center += 50 # extra buffer after the edge of k to include walk-in camping parking
|
||||
print(f"{{{street_center}, 0, nullptr}},\t// +{street_center-last_center}ft")
|
||||
*/
|
||||
|
||||
static const StreetInfo streets[] = {
|
||||
{2500, 50, "Esp"}, // +0ft dia: 5,000ft
|
||||
{2935, 215, "A"}, // +435ft dia: 5,870ft
|
||||
{3215, 140, "B"}, // +280ft dia: 6,430ft
|
||||
{3495, 140, "C"}, // +280ft dia: 6,990ft
|
||||
{3775, 140, "D"}, // +280ft dia: 7,550ft
|
||||
{4060, 145, "E"}, // +285ft dia: 8,120ft
|
||||
{4545, 240, "F"}, // +485ft dia: 9,090ft
|
||||
{4825, 140, "G"}, // +280ft dia: 9,650ft
|
||||
{5105, 140, "H"}, // +280ft dia: 10,210ft
|
||||
{5385, 140, "I"}, // +280ft dia: 10,770ft
|
||||
{5565, 90, "J"}, // +180ft dia: 11,130ft
|
||||
{5755, 100, "K"}, // +190ft dia: 11,510ft
|
||||
{5830, 0, nullptr}, // +75ft
|
||||
};
|
||||
|
||||
BRCAddress::BRCAddress(int32_t lat, int32_t lon)
|
||||
{
|
||||
bearing = GeoCoord::bearing(BRC_LATF, BRC_LONF, DegD(lat), DegD(lon)) * RAD_TO_HOUR;
|
||||
bearing += 12.0 - BRC_NOON;
|
||||
while (bearing > 12.0) {
|
||||
bearing -= 12.0;
|
||||
}
|
||||
|
||||
// In imperial units because that is how golden spike data is provided.
|
||||
distance = GeoCoord::latLongToMeter(BRC_LATF, BRC_LONF, DegD(lat), DegD(lon)) * METER_TO_FEET;
|
||||
};
|
||||
|
||||
int BRCAddress::radial(char *buf, size_t len)
|
||||
{
|
||||
uint8_t hour = (uint8_t)(bearing);
|
||||
uint8_t minute = (uint8_t)((bearing - hour) * 60.0);
|
||||
hour %= 12;
|
||||
if (hour == 0) {
|
||||
hour = 12;
|
||||
}
|
||||
return snprintf(buf, len, "%d:%02d", hour, minute);
|
||||
};
|
||||
|
||||
int BRCAddress::annular(char *buf, size_t len, bool noUnit)
|
||||
{
|
||||
const char *unit = "m";
|
||||
float unitMultiplier = FEET_TO_METER;
|
||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
unitMultiplier = 1.0;
|
||||
unit = "ft";
|
||||
}
|
||||
if (noUnit)
|
||||
unit = "";
|
||||
|
||||
if (bearing > 1.75 && bearing < 10.25) {
|
||||
const char *street = nullptr;
|
||||
float dist = 0;
|
||||
// Find the appropriate street based on distance
|
||||
for (const auto &s : streets) {
|
||||
if (distance > s.center - s.width) {
|
||||
street = s.name;
|
||||
dist = distance - s.center;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (street) {
|
||||
return snprintf(buf, len, "%s %d%s", street, int(dist * unitMultiplier), unit);
|
||||
}
|
||||
}
|
||||
|
||||
return snprintf(buf, len, "%d%s", int(distance * unitMultiplier), unit);
|
||||
};
|
||||
|
||||
int BRCAddress::full(char *buf, size_t len)
|
||||
{
|
||||
auto l = radial(buf, len - 4);
|
||||
buf += l;
|
||||
*(buf++) = ' ';
|
||||
*(buf++) = '&';
|
||||
*(buf++) = ' ';
|
||||
buf += annular(buf, len - l - 4, false);
|
||||
buf[l] = 0; // always null terminated
|
||||
return l;
|
||||
};
|
||||
|
||||
int BRCAddress::compact(char *buf, size_t len)
|
||||
{
|
||||
auto l = radial(buf, len - 2);
|
||||
buf += l;
|
||||
*(buf++) = '&';
|
||||
buf += annular(buf, len - l - 2, true);
|
||||
buf[l] = 0; // always null terminated
|
||||
return l;
|
||||
};
|
||||
|
||||
#endif
|
||||
21
src/graphics/BRC.h
Normal file
21
src/graphics/BRC.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
// For size_t/int32_t types on some platforms.
|
||||
#include <cstdint>
|
||||
// For size_t
|
||||
#include <cstddef>
|
||||
|
||||
class BRCAddress
|
||||
{
|
||||
public:
|
||||
BRCAddress(int32_t lat, int32_t lon);
|
||||
|
||||
int radial(char *buf, size_t len);
|
||||
int annular(char *buf, size_t len, bool noUnit);
|
||||
int full(char *buf, size_t len);
|
||||
int compact(char *buf, size_t len);
|
||||
|
||||
private:
|
||||
float bearing;
|
||||
float distance;
|
||||
};
|
||||
@@ -864,6 +864,8 @@ void Screen::setFrames(FrameFocus focus)
|
||||
uint8_t previousFrameCount = framesetInfo.frameCount;
|
||||
FramesetInfo fsi; // Location of specific frames, for applying focus parameter
|
||||
|
||||
graphics::UIRenderer::rebuildFavoritedNodes();
|
||||
|
||||
LOG_DEBUG("Show standard frames");
|
||||
showingNormalScreen = true;
|
||||
|
||||
@@ -922,6 +924,12 @@ void Screen::setFrames(FrameFocus focus)
|
||||
normalFrames[numframes++] = graphics::NodeListRenderer::drawNodeListWithCompasses;
|
||||
indicatorIcons.push_back(icon_list);
|
||||
|
||||
#if HAS_SCREEN
|
||||
fsi.positions.nodelist_brc = numframes;
|
||||
normalFrames[numframes++] = graphics::NodeListRenderer::drawBRCList;
|
||||
indicatorIcons.push_back(icon_bm);
|
||||
#endif
|
||||
|
||||
fsi.positions.gps = numframes;
|
||||
normalFrames[numframes++] = graphics::UIRenderer::drawCompassAndLocationScreen;
|
||||
indicatorIcons.push_back(icon_compass);
|
||||
@@ -1389,7 +1397,8 @@ int Screen::handleInputEvent(const InputEvent *event)
|
||||
this->ui->getUiState()->currentFrame == framesetInfo.positions.nodelist_hopsignal ||
|
||||
this->ui->getUiState()->currentFrame == framesetInfo.positions.nodelist_distance ||
|
||||
this->ui->getUiState()->currentFrame == framesetInfo.positions.nodelist_hopsignal ||
|
||||
this->ui->getUiState()->currentFrame == framesetInfo.positions.nodelist_bearings) {
|
||||
this->ui->getUiState()->currentFrame == framesetInfo.positions.nodelist_bearings ||
|
||||
this->ui->getUiState()->currentFrame == framesetInfo.positions.nodelist_brc) {
|
||||
menuHandler::nodeListMenu();
|
||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.wifi) {
|
||||
menuHandler::wifiBaseMenu();
|
||||
|
||||
@@ -662,6 +662,7 @@ class Screen : public concurrency::OSThread
|
||||
uint8_t nodelist_hopsignal = 255;
|
||||
uint8_t nodelist_distance = 255;
|
||||
uint8_t nodelist_bearings = 255;
|
||||
uint8_t nodelist_brc = 255;
|
||||
uint8_t clock = 255;
|
||||
uint8_t firstFavorite = 255;
|
||||
uint8_t lastFavorite = 255;
|
||||
|
||||
@@ -483,7 +483,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
}
|
||||
|
||||
// ****************************
|
||||
// * Memory Screen *
|
||||
// * System Screen *
|
||||
// ****************************
|
||||
void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
@@ -593,7 +593,19 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
}
|
||||
line += 1;
|
||||
char appversionstr[35];
|
||||
snprintf(appversionstr, sizeof(appversionstr), "Ver.: %s", optstr(APP_VERSION));
|
||||
snprintf(appversionstr, sizeof(appversionstr), "Ver: %s", optstr(APP_VERSION));
|
||||
char appversionstr_formatted[40];
|
||||
char *lastDot = strrchr(appversionstr, '.');
|
||||
if (lastDot) {
|
||||
size_t prefixLen = lastDot - appversionstr;
|
||||
strncpy(appversionstr_formatted, appversionstr, prefixLen);
|
||||
appversionstr_formatted[prefixLen] = '\0';
|
||||
strncat(appversionstr_formatted, " (", sizeof(appversionstr_formatted) - strlen(appversionstr_formatted) - 1);
|
||||
strncat(appversionstr_formatted, lastDot + 1, sizeof(appversionstr_formatted) - strlen(appversionstr_formatted) - 1);
|
||||
strncat(appversionstr_formatted, ")", sizeof(appversionstr_formatted) - strlen(appversionstr_formatted) - 1);
|
||||
strncpy(appversionstr, appversionstr_formatted, sizeof(appversionstr) - 1);
|
||||
appversionstr[sizeof(appversionstr) - 1] = '\0';
|
||||
}
|
||||
int textWidth = display->getStringWidth(appversionstr);
|
||||
int nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line], appversionstr);
|
||||
|
||||
@@ -375,12 +375,6 @@ void menuHandler::textMessageBaseMenu()
|
||||
|
||||
void menuHandler::systemBaseMenu()
|
||||
{
|
||||
// Check if brightness is supported
|
||||
bool hasSupportBrightness = false;
|
||||
#if defined(ST7789_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) || HAS_TFT
|
||||
hasSupportBrightness = true;
|
||||
#endif
|
||||
|
||||
enum optionsNumbers { Back, Notifications, ScreenOptions, PowerMenu, Test, enumEnd };
|
||||
static const char *optionsArray[enumEnd] = {"Back"};
|
||||
static int optionsEnumArray[enumEnd] = {Back};
|
||||
@@ -450,11 +444,11 @@ void menuHandler::favoriteBaseMenu()
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
bannerOptions.optionsCount = options;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected == 1) {
|
||||
if (selected == Preset) {
|
||||
cannedMessageModule->LaunchWithDestination(graphics::UIRenderer::currentFavoriteNodeNum);
|
||||
} else if (selected == 2 && kb_found) {
|
||||
} else if (selected == Freetext) {
|
||||
cannedMessageModule->LaunchFreetextWithDestination(graphics::UIRenderer::currentFavoriteNodeNum);
|
||||
} else if ((!kb_found && selected == 2) || (selected == 3 && kb_found)) {
|
||||
} else if (selected == Remove) {
|
||||
menuHandler::menuQueue = menuHandler::remove_favorite;
|
||||
screen->runNow();
|
||||
}
|
||||
@@ -707,6 +701,7 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 10;
|
||||
bannerOptions.bannerCallback = [display](int selected) -> void {
|
||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || HAS_TFT
|
||||
uint8_t TFT_MESH_r = 0;
|
||||
uint8_t TFT_MESH_g = 0;
|
||||
uint8_t TFT_MESH_b = 0;
|
||||
@@ -758,7 +753,6 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
|
||||
screen->runNow();
|
||||
}
|
||||
|
||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || HAS_TFT
|
||||
if (selected != 0) {
|
||||
display->setColor(BLACK);
|
||||
display->fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
@@ -856,8 +850,9 @@ void menuHandler::removeFavoriteMenu()
|
||||
bannerOptions.optionsCount = 2;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected == 1) {
|
||||
LOG_INFO("Removing %x as favorite node", graphics::UIRenderer::currentFavoriteNodeNum);
|
||||
nodeDB->set_favorite(false, graphics::UIRenderer::currentFavoriteNodeNum);
|
||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
|
||||
screen->setFrames(graphics::Screen::FOCUS_DEFAULT);
|
||||
}
|
||||
};
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "UIRenderer.h"
|
||||
#include "gps/GeoCoord.h"
|
||||
#include "gps/RTC.h" // for getTime() function
|
||||
#include "graphics/BRC.h"
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include "graphics/SharedUIDisplay.h"
|
||||
#include "graphics/images.h"
|
||||
@@ -87,6 +88,8 @@ const char *getCurrentModeTitle(int screenWidth)
|
||||
#endif
|
||||
case MODE_DISTANCE:
|
||||
return "Distance";
|
||||
case MODE_BEARING:
|
||||
return "Bearing";
|
||||
default:
|
||||
return "Nodes";
|
||||
}
|
||||
@@ -309,6 +312,9 @@ void drawEntryDynamic(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16
|
||||
case MODE_DISTANCE:
|
||||
drawNodeDistance(display, node, x, y, columnWidth);
|
||||
break;
|
||||
case MODE_BEARING:
|
||||
drawEntryCompass(display, node, x, y, columnWidth);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -335,6 +341,35 @@ void drawEntryCompass(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16
|
||||
}
|
||||
}
|
||||
|
||||
void drawEntryBRC(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth)
|
||||
{
|
||||
bool isLeftCol = (x < SCREEN_WIDTH / 2);
|
||||
|
||||
// Adjust max text width depending on column and screen width
|
||||
int nameMaxWidth = columnWidth - (isHighResolution ? (isLeftCol ? 25 : 28) : (isLeftCol ? 20 : 22));
|
||||
|
||||
const char *nodeName = getSafeNodeName(node);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
auto xText = x + ((isHighResolution) ? 6 : 3);
|
||||
display->drawString(xText, y, nodeName);
|
||||
|
||||
if (nodeDB->hasValidPosition(node)) {
|
||||
char buf[14] = "";
|
||||
BRCAddress(node->position.latitude_i, node->position.longitude_i).compact(buf, 14);
|
||||
auto nameWidth = display->getStringWidth("WWWW") - 2; // Fixed width so they are aligned.
|
||||
display->drawString(xText + nameWidth, y, buf);
|
||||
}
|
||||
|
||||
if (node->is_favorite) {
|
||||
if (isHighResolution) {
|
||||
drawScaledXBitmap16x16(x, y + 6, smallbulletpoint_width, smallbulletpoint_height, smallbulletpoint, display);
|
||||
} else {
|
||||
display->drawXbm(x, y + 5, smallbulletpoint_width, smallbulletpoint_height, smallbulletpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawCompassArrow(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth, float myHeading,
|
||||
double userLat, double userLon)
|
||||
{
|
||||
@@ -384,17 +419,46 @@ void drawCompassArrow(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16
|
||||
*/
|
||||
}
|
||||
|
||||
void drawLastSeenExtra(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth,
|
||||
float /*myHeading*/, double /*userLat*/, double /*userLon*/)
|
||||
{
|
||||
char timeStr[10];
|
||||
uint32_t seconds = sinceLastSeen(node);
|
||||
if (seconds == 0 || seconds == UINT32_MAX) {
|
||||
snprintf(timeStr, sizeof(timeStr), "?");
|
||||
} else {
|
||||
uint32_t minutes = seconds / 60, hours = minutes / 60, days = hours / 24;
|
||||
snprintf(timeStr, sizeof(timeStr), (days > 99 ? "?" : "%d%c"),
|
||||
(days ? days
|
||||
: hours ? hours
|
||||
: minutes),
|
||||
(days ? 'd'
|
||||
: hours ? 'h'
|
||||
: 'm'));
|
||||
}
|
||||
|
||||
bool isLeftCol = (x < SCREEN_WIDTH / 2);
|
||||
int timeOffset = (isHighResolution) ? (isLeftCol ? 7 : 10) : (isLeftCol ? 3 : 7);
|
||||
int rightEdge = x + columnWidth - timeOffset;
|
||||
if (timeStr[strlen(timeStr) - 1] == 'm') // Fix the fact that our fonts don't line up well all the time
|
||||
rightEdge -= 1;
|
||||
// display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
int textWidth = display->getStringWidth(timeStr);
|
||||
display->drawString(rightEdge - textWidth, y, timeStr);
|
||||
}
|
||||
|
||||
// =============================
|
||||
// Main Screen Functions
|
||||
// =============================
|
||||
|
||||
void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *title,
|
||||
EntryRenderer renderer, NodeExtrasRenderer extras, float heading, double lat, double lon)
|
||||
EntryRenderer renderer, NodeExtrasRenderer extras, float heading, double lat, double lon,
|
||||
int totalColumns)
|
||||
{
|
||||
const int COMMON_HEADER_HEIGHT = FONT_HEIGHT_SMALL - 1;
|
||||
const int rowYOffset = FONT_HEIGHT_SMALL - 3;
|
||||
|
||||
int columnWidth = display->getWidth() / 2;
|
||||
int columnWidth = display->getWidth() / totalColumns;
|
||||
|
||||
display->clear();
|
||||
|
||||
@@ -408,7 +472,6 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
int totalRowsAvailable = (display->getHeight() - y) / rowYOffset;
|
||||
|
||||
int visibleNodeRows = totalRowsAvailable;
|
||||
int totalColumns = 2;
|
||||
|
||||
int startIndex = scrollIndex * visibleNodeRows * totalColumns;
|
||||
if (nodeDB->getMeshNodeByIndex(startIndex)->num == nodeDB->getNodeNum()) {
|
||||
@@ -446,7 +509,7 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
}
|
||||
|
||||
// Draw column separator
|
||||
if (shownCount > 0) {
|
||||
if (shownCount > 0 && totalColumns > 1) {
|
||||
const int firstNodeY = y + 3;
|
||||
drawColumnSeparator(display, x, firstNodeY, lastNodeY);
|
||||
}
|
||||
@@ -482,7 +545,31 @@ void drawDynamicNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
|
||||
// Render screen based on currentMode
|
||||
const char *title = getCurrentModeTitle(display->getWidth());
|
||||
drawNodeListScreen(display, state, x, y, title, drawEntryDynamic);
|
||||
|
||||
if (currentMode == MODE_BEARING) {
|
||||
float heading = 0;
|
||||
bool validHeading = false;
|
||||
auto ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
double lat = DegD(ourNode->position.latitude_i);
|
||||
double lon = DegD(ourNode->position.longitude_i);
|
||||
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) {
|
||||
if (screen->hasHeading()) {
|
||||
heading = screen->getHeading(); // degrees
|
||||
validHeading = true;
|
||||
} else {
|
||||
heading = screen->estimatedHeading(lat, lon);
|
||||
validHeading = !isnan(heading);
|
||||
}
|
||||
if (!validHeading) {
|
||||
lastRenderedMode = MODE_COUNT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
drawNodeListScreen(display, state, x, y, title, drawEntryCompass, drawCompassArrow, heading, lat, lon);
|
||||
} else {
|
||||
drawNodeListScreen(display, state, x, y, title, drawEntryDynamic);
|
||||
}
|
||||
|
||||
// Track the last mode to avoid reinitializing modeStartTime
|
||||
lastRenderedMode = currentMode;
|
||||
@@ -539,6 +626,11 @@ void drawNodeListWithCompasses(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
drawNodeListScreen(display, state, x, y, "Bearings", drawEntryCompass, drawCompassArrow, heading, lat, lon);
|
||||
}
|
||||
|
||||
void drawBRCList(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
drawNodeListScreen(display, state, x, y, "BRC", drawEntryBRC, drawLastSeenExtra, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
/// Draw a series of fields in a column, wrapping to multiple columns if needed
|
||||
void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields)
|
||||
{
|
||||
@@ -564,4 +656,4 @@ void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields
|
||||
|
||||
} // namespace NodeListRenderer
|
||||
} // namespace graphics
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -24,12 +24,12 @@ typedef void (*EntryRenderer)(OLEDDisplay *, meshtastic_NodeInfoLite *, int16_t,
|
||||
typedef void (*NodeExtrasRenderer)(OLEDDisplay *, meshtastic_NodeInfoLite *, int16_t, int16_t, int, float, double, double);
|
||||
|
||||
// Node list mode enumeration
|
||||
enum NodeListMode { MODE_LAST_HEARD = 0, MODE_HOP_SIGNAL = 1, MODE_DISTANCE = 2, MODE_COUNT = 3 };
|
||||
enum NodeListMode { MODE_LAST_HEARD = 0, MODE_HOP_SIGNAL = 1, MODE_DISTANCE = 2, MODE_BEARING = 3, MODE_COUNT = 4 };
|
||||
|
||||
// Main node list screen function
|
||||
void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *title,
|
||||
EntryRenderer renderer, NodeExtrasRenderer extras = nullptr, float heading = 0, double lat = 0,
|
||||
double lon = 0);
|
||||
double lon = 0, int totalColumns = 2);
|
||||
|
||||
// Entry renderers
|
||||
void drawEntryLastHeard(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth);
|
||||
@@ -48,6 +48,7 @@ void drawHopSignalScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
void drawDistanceScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
void drawDynamicNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
void drawNodeListWithCompasses(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
void drawBRCList(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
|
||||
// Utility functions
|
||||
const char *getCurrentModeTitle(int screenWidth);
|
||||
|
||||
@@ -156,7 +156,7 @@ void NotificationRenderer::drawNumberPicker(OLEDDisplay *display, OLEDDisplayUiS
|
||||
resetBanner();
|
||||
return;
|
||||
}
|
||||
if (curSelected == numDigits) {
|
||||
if (curSelected == static_cast<int8_t>(numDigits)) {
|
||||
alertBannerCallback(currentNumber);
|
||||
resetBanner();
|
||||
return;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "airtime.h"
|
||||
#include "configuration.h"
|
||||
#include "gps/GeoCoord.h"
|
||||
#include "graphics/BRC.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include "graphics/SharedUIDisplay.h"
|
||||
@@ -24,6 +25,23 @@ extern graphics::Screen *screen;
|
||||
namespace graphics
|
||||
{
|
||||
NodeNum UIRenderer::currentFavoriteNodeNum = 0;
|
||||
std::vector<meshtastic_NodeInfoLite *> graphics::UIRenderer::favoritedNodes;
|
||||
|
||||
void graphics::UIRenderer::rebuildFavoritedNodes()
|
||||
{
|
||||
favoritedNodes.clear();
|
||||
size_t total = nodeDB->getNumMeshNodes();
|
||||
for (size_t i = 0; i < total; i++) {
|
||||
meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
|
||||
if (!n || n->num == nodeDB->getNodeNum())
|
||||
continue;
|
||||
if (n->is_favorite)
|
||||
favoritedNodes.push_back(n);
|
||||
}
|
||||
|
||||
std::sort(favoritedNodes.begin(), favoritedNodes.end(),
|
||||
[](const meshtastic_NodeInfoLite *a, const meshtastic_NodeInfoLite *b) { return a->num < b->num; });
|
||||
}
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_GPS
|
||||
// GeoCoord object for coordinate conversions
|
||||
@@ -201,27 +219,7 @@ void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const mes
|
||||
// **********************
|
||||
void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
// --- Cache favorite nodes for the current frame only, to save computation ---
|
||||
static std::vector<meshtastic_NodeInfoLite *> favoritedNodes;
|
||||
static int prevFrame = -1;
|
||||
|
||||
// --- Only rebuild favorites list if we're on a new frame ---
|
||||
if (state->currentFrame != prevFrame) {
|
||||
prevFrame = state->currentFrame;
|
||||
favoritedNodes.clear();
|
||||
size_t total = nodeDB->getNumMeshNodes();
|
||||
for (size_t i = 0; i < total; i++) {
|
||||
meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
|
||||
// Skip nulls and ourself
|
||||
if (!n || n->num == nodeDB->getNodeNum())
|
||||
continue;
|
||||
if (n->is_favorite)
|
||||
favoritedNodes.push_back(n);
|
||||
}
|
||||
// Keep a stable, consistent display order
|
||||
std::sort(favoritedNodes.begin(), favoritedNodes.end(),
|
||||
[](const meshtastic_NodeInfoLite *a, const meshtastic_NodeInfoLite *b) { return a->num < b->num; });
|
||||
}
|
||||
if (favoritedNodes.empty())
|
||||
return;
|
||||
|
||||
@@ -311,23 +309,12 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
display->drawString(x, getTextPositions(display)[line++], seenStr);
|
||||
}
|
||||
|
||||
// === 4. Uptime (only show if metric is present) ===
|
||||
char uptimeStr[32] = "";
|
||||
if (node->has_device_metrics && node->device_metrics.has_uptime_seconds) {
|
||||
uint32_t uptime = node->device_metrics.uptime_seconds;
|
||||
uint32_t days = uptime / 86400;
|
||||
uint32_t hours = (uptime % 86400) / 3600;
|
||||
uint32_t mins = (uptime % 3600) / 60;
|
||||
// Show as "Up: 2d 3h", "Up: 5h 14m", or "Up: 37m"
|
||||
if (days)
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %ud %uh", days, hours);
|
||||
else if (hours)
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %uh %um", hours, mins);
|
||||
else
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %um", mins);
|
||||
}
|
||||
if (uptimeStr[0] && line < 5) {
|
||||
display->drawString(x, getTextPositions(display)[line++], uptimeStr);
|
||||
// === 4. Burning Man location (only show if their position is known) ===
|
||||
char brcStr[32] = "";
|
||||
if (nodeDB->hasValidPosition(node) && line < 5) {
|
||||
brcStr[0] = 32; // Space before the address to align with other rows.
|
||||
BRCAddress(node->position.latitude_i, node->position.longitude_i).full(brcStr + 1, sizeof(brcStr) - 1);
|
||||
display->drawString(x, getTextPositions(display)[line++], brcStr);
|
||||
}
|
||||
|
||||
// === 5. Distance (only if both nodes have GPS position) ===
|
||||
@@ -657,7 +644,7 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
|
||||
char combinedName[50];
|
||||
snprintf(combinedName, sizeof(combinedName), "%s (%s)", longNameStr.empty() ? "" : longNameStr.c_str(), shortnameble);
|
||||
if (SCREEN_WIDTH - (display->getStringWidth(longName) + display->getStringWidth(shortnameble)) > 10) {
|
||||
if (SCREEN_WIDTH - (display->getStringWidth(combinedName)) > 10) {
|
||||
size_t len = strlen(combinedName);
|
||||
if (len >= 3 && strcmp(combinedName + len - 3, " ()") == 0) {
|
||||
combinedName[len - 3] = '\0'; // Remove the last three characters
|
||||
@@ -668,7 +655,7 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
nameX, ((rows == 4) ? getTextPositions(display)[line++] : getTextPositions(display)[line++]) + yOffset, combinedName);
|
||||
} else {
|
||||
// === LongName Centered ===
|
||||
textWidth = display->getStringWidth(longName);
|
||||
textWidth = display->getStringWidth(longNameStr.c_str());
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line++], longNameStr.c_str());
|
||||
|
||||
@@ -924,7 +911,7 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
}
|
||||
|
||||
// If GPS is off, no need to display these parts
|
||||
if (strcmp(displayLine, "GPS off") != 0 && strcmp(displayLine, "No GPS") != 0) {
|
||||
if (strcmp(displayLine, "GPS off") != 0 && strcmp(displayLine, "No GPS") != 0 && gpsStatus->getHasLock()) {
|
||||
|
||||
// === Second Row: Date ===
|
||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true);
|
||||
@@ -945,14 +932,18 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
snprintf(lonStr, sizeof(lonStr), " Lon: %.5f", geoCoord.getLongitude() * 1e-7);
|
||||
display->drawString(x, getTextPositions(display)[line++], lonStr);
|
||||
|
||||
// === Fifth Row: Altitude ===
|
||||
char DisplayLineTwo[32] = {0};
|
||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
snprintf(DisplayLineTwo, sizeof(DisplayLineTwo), " Alt: %.0fft", geoCoord.getAltitude() * METERS_TO_FEET);
|
||||
} else {
|
||||
snprintf(DisplayLineTwo, sizeof(DisplayLineTwo), " Alt: %.0im", geoCoord.getAltitude());
|
||||
// === Fifth Row: Burning Man! ===
|
||||
char addrStr[32];
|
||||
BRCAddress(geoCoord.getLatitude(), geoCoord.getLongitude()).full(addrStr, sizeof(addrStr));
|
||||
display->drawString(x, getTextPositions(display)[line++], addrStr);
|
||||
} else {
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
// from cell phone?
|
||||
if (nodeDB->hasValidPosition(ourNode)) {
|
||||
char addrStr[32];
|
||||
BRCAddress(ourNode->position.latitude_i, ourNode->position.longitude_i).full(addrStr, sizeof(addrStr));
|
||||
display->drawString(x, getTextPositions(display)[line++], addrStr);
|
||||
}
|
||||
display->drawString(x, getTextPositions(display)[line++], DisplayLineTwo);
|
||||
}
|
||||
|
||||
// === Draw Compass if heading is valid ===
|
||||
@@ -1228,4 +1219,4 @@ std::string UIRenderer::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t mi
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
#endif // HAS_SCREEN
|
||||
#endif // HAS_SCREEN
|
||||
|
||||
@@ -61,6 +61,8 @@ class UIRenderer
|
||||
static void drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
|
||||
static NodeNum currentFavoriteNodeNum;
|
||||
static std::vector<meshtastic_NodeInfoLite *> favoritedNodes;
|
||||
static void rebuildFavoritedNodes();
|
||||
|
||||
// OEM screens
|
||||
#ifdef USERPREFS_OEM_TEXT
|
||||
|
||||
@@ -156,6 +156,18 @@ const uint8_t icon_list[] PROGMEM = {
|
||||
0x82 // Row 7: #.....#.
|
||||
};
|
||||
|
||||
// ➤ The Man Icon (8x8)
|
||||
const uint8_t icon_bm[] PROGMEM = {
|
||||
0x42, // Row 0: .#....#.
|
||||
0x3C, // Row 1: ..####..
|
||||
0x3C, // Row 2: ..####..
|
||||
0x18, // Row 3: ...##...
|
||||
0x18, // Row 4: ...##...
|
||||
0x24, // Row 5: ..#..#..
|
||||
0x24, // Row 6: ..#..#..
|
||||
0x42 // Row 7: .#....#.
|
||||
};
|
||||
|
||||
// 📶 Signal Bars Icon (left to right, small to large with spacing)
|
||||
const uint8_t icon_signal[] PROGMEM = {
|
||||
0b00000000, // ░░░░░░░
|
||||
|
||||
@@ -67,4 +67,5 @@ void CardKbI2cImpl::init()
|
||||
}
|
||||
#endif
|
||||
inputBroker->registerSource(this);
|
||||
kb_found = true;
|
||||
}
|
||||
@@ -72,10 +72,11 @@ void FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p)
|
||||
|
||||
tosend->hop_limit--; // bump down the hop count
|
||||
#if USERPREFS_EVENT_MODE
|
||||
if (tosend->hop_limit > 2) {
|
||||
// BURNING MESH!
|
||||
if (tosend->hop_limit > 3) {
|
||||
// if we are "correcting" the hop_limit, "correct" the hop_start by the same amount to preserve hops away.
|
||||
tosend->hop_start -= (tosend->hop_limit - 2);
|
||||
tosend->hop_limit = 2;
|
||||
tosend->hop_start -= (tosend->hop_limit - 3);
|
||||
tosend->hop_limit = 3;
|
||||
}
|
||||
#endif
|
||||
tosend->next_hop = NO_NEXT_HOP_PREFERENCE; // this should already be the case, but just in case
|
||||
|
||||
@@ -38,7 +38,8 @@ enum RxSource {
|
||||
#define HOP_MAX 7
|
||||
|
||||
/// We normally just use max 3 hops for sending reliable messages
|
||||
#define HOP_RELIABLE 3
|
||||
// BURNING MESH!
|
||||
#define HOP_RELIABLE 4
|
||||
|
||||
// For old firmware or when falling back to flooding, there is no next-hop preference
|
||||
#define NO_NEXT_HOP_PREFERENCE 0
|
||||
|
||||
@@ -850,7 +850,13 @@ void CannedMessageModule::sendText(NodeNum dest, ChannelIndex channel, const cha
|
||||
this->waitingForAck = true;
|
||||
|
||||
// Log outgoing message
|
||||
LOG_INFO("Send message id=%d, dest=%x, msg=%.*s", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
|
||||
LOG_INFO("Send message id=%u, dest=%x, msg=%.*s", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
|
||||
|
||||
if (p->to != 0xffffffff) {
|
||||
LOG_INFO("Proactively adding %x as favorite node", p->to);
|
||||
nodeDB->set_favorite(true, p->to);
|
||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
|
||||
}
|
||||
|
||||
// Send to mesh and phone (even if no phone connected, to track ACKs)
|
||||
service->sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
// "USERPREFS_BUTTON_PIN": "36",
|
||||
// "USERPREFS_CHANNELS_TO_WRITE": "3",
|
||||
"USERPREFS_CHANNELS_TO_WRITE": "1",
|
||||
// "USERPREFS_CHANNEL_0_DOWNLINK_ENABLED": "false",
|
||||
// "USERPREFS_CHANNEL_0_NAME": "REPLACEME",
|
||||
// "USERPREFS_CHANNEL_0_PRECISION": "14",
|
||||
// "USERPREFS_CHANNEL_0_PSK": "{ 0x38, 0x4b, 0xbc, 0xc0, 0x1d, 0xc0, 0x22, 0xd1, 0x81, 0xbf, 0x36, 0xb8, 0x61, 0x21, 0xe1, 0xfb, 0x96, 0xb7, 0x2e, 0x55, 0xbf, 0x74, 0x22, 0x7e, 0x9d, 0x6a, 0xfb, 0x48, 0xd6, 0x4c, 0xb1, 0xa1 }",
|
||||
"USERPREFS_CHANNEL_0_NAME": "Everyone",
|
||||
"USERPREFS_CHANNEL_0_PRECISION": "0",
|
||||
"USERPREFS_CHANNEL_0_PSK": "{ 0x38, 0x4b, 0xbc, 0xc0, 0x1d, 0xc0, 0x22, 0xd1, 0x81, 0xbf, 0x36, 0xb8, 0x61, 0x21, 0xe1, 0xfb, 0x96, 0xb7, 0x2e, 0x55, 0xbf, 0x74, 0x22, 0x7e, 0x9d, 0x6a, 0xfb, 0x48, 0xd6, 0x4c, 0xb1, 0xa1 }",
|
||||
// "USERPREFS_CHANNEL_0_UPLINK_ENABLED": "true",
|
||||
// "USERPREFS_CHANNEL_1_DOWNLINK_ENABLED": "false",
|
||||
// "USERPREFS_CHANNEL_1_NAME": "NodeChat",
|
||||
@@ -17,12 +17,12 @@
|
||||
// "USERPREFS_CHANNEL_2_PSK": "{ 0x15, 0x6f, 0xfe, 0x46, 0xd4, 0x56, 0x63, 0x8a, 0x54, 0x43, 0x13, 0xf2, 0xef, 0x6c, 0x63, 0x89, 0xf0, 0x06, 0x30, 0x52, 0xce, 0x36, 0x5e, 0xb1, 0xe8, 0xbb, 0x86, 0xe6, 0x26, 0x5b, 0x1d, 0x58 }",
|
||||
// "USERPREFS_CHANNEL_2_UPLINK_ENABLED": "false",
|
||||
// "USERPREFS_CONFIG_GPS_MODE": "meshtastic_Config_PositionConfig_GpsMode_ENABLED",
|
||||
// "USERPREFS_CONFIG_LORA_IGNORE_MQTT": "true",
|
||||
"USERPREFS_CONFIG_LORA_IGNORE_MQTT": "true",
|
||||
// "USERPREFS_CONFIG_LORA_REGION": "meshtastic_Config_LoRaConfig_RegionCode_US",
|
||||
// "USERPREFS_CONFIG_OWNER_LONG_NAME": "My Long Name",
|
||||
// "USERPREFS_CONFIG_OWNER_SHORT_NAME": "MLN",
|
||||
// "USERPREFS_CONFIG_DEVICE_ROLE": "meshtastic_Config_DeviceConfig_Role_CLIENT", // Defaults to CLIENT. ROUTER*, LOST AND FOUND, and REPEATER roles are restricted.
|
||||
// "USERPREFS_EVENT_MODE": "1",
|
||||
"USERPREFS_EVENT_MODE": "1",
|
||||
// "USERPREFS_FIXED_BLUETOOTH": "121212",
|
||||
// "USERPREFS_FIXED_GPS": "",
|
||||
// "USERPREFS_FIXED_GPS_ALT": "0",
|
||||
@@ -32,16 +32,16 @@
|
||||
// "USERPREFS_CONFIG_GPS_UPDATE_INTERVAL": "600",
|
||||
// "USERPREFS_CONFIG_POSITION_BROADCAST_INTERVAL": "1800",
|
||||
// "USERPREFS_CONFIG_DEVICE_TELEM_UPDATE_INTERVAL": "900", // Device telemetry update interval in seconds
|
||||
// "USERPREFS_LORACONFIG_CHANNEL_NUM": "31",
|
||||
// "USERPREFS_LORACONFIG_MODEM_PRESET": "meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST",
|
||||
"USERPREFS_LORACONFIG_CHANNEL_NUM": "31",
|
||||
"USERPREFS_LORACONFIG_MODEM_PRESET": "meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO",
|
||||
// "USERPREFS_USE_ADMIN_KEY_0": "{ 0xcd, 0xc0, 0xb4, 0x3c, 0x53, 0x24, 0xdf, 0x13, 0xca, 0x5a, 0xa6, 0x0c, 0x0d, 0xec, 0x85, 0x5a, 0x4c, 0xf6, 0x1a, 0x96, 0x04, 0x1a, 0x3e, 0xfc, 0xbb, 0x8e, 0x33, 0x71, 0xe5, 0xfc, 0xff, 0x3c }",
|
||||
// "USERPREFS_USE_ADMIN_KEY_1": "{}",
|
||||
// "USERPREFS_USE_ADMIN_KEY_2": "{}",
|
||||
// "USERPREFS_OEM_TEXT": "Caterham Car Club",
|
||||
// "USERPREFS_OEM_FONT_SIZE": "0",
|
||||
// "USERPREFS_OEM_IMAGE_WIDTH": "50",
|
||||
// "USERPREFS_OEM_IMAGE_HEIGHT": "28",
|
||||
// "USERPREFS_OEM_IMAGE_DATA": "{ 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0x61, 0x00, 0x00, 0x00, 0x0C, 0xFF, 0xFF, 0xC7, 0x00, 0x00, 0x00, 0x0C, 0xFF, 0xFF, 0xC7, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0x67, 0x00, 0x00, 0x00, 0x18, 0x1F, 0xF0, 0x67, 0x00, 0x00, 0x00, 0x30, 0x1F, 0xF8, 0x33, 0x00, 0x00, 0x00, 0x30, 0x00, 0xFC, 0x31, 0x00, 0x00, 0x00, 0x60, 0x00, 0xFE, 0x18, 0x00, 0x00, 0x00, 0x60, 0x00, 0x7E, 0x18, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x3F, 0x0C, 0x00, 0x00, 0x00, 0xC0, 0x80, 0x1F, 0x0C, 0x00, 0x00, 0x00, 0x80, 0x81, 0x1F, 0x06, 0x00, 0x00, 0x00, 0x80, 0xC1, 0x0F, 0x06, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x8F, 0x01, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xC7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00}",
|
||||
"USERPREFS_OEM_TEXT": "Burning Mesh 2025",
|
||||
"USERPREFS_OEM_FONT_SIZE": "0",
|
||||
"USERPREFS_OEM_IMAGE_WIDTH": "36",
|
||||
"USERPREFS_OEM_IMAGE_HEIGHT": "56",
|
||||
"USERPREFS_OEM_IMAGE_DATA": "{ 0x06, 0x00, 0x06, 0x00, 0x06, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x1F, 0x80, 0x1F, 0x80, 0x0F, 0x1E, 0xC0, 0x3F, 0x80, 0x07, 0x3C, 0xE0, 0x7F, 0xC0, 0x03, 0x7C, 0xF0, 0xF9, 0xE0, 0x03, 0xF8, 0xF8, 0xF0, 0xF1, 0x01, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0xE0, 0xF1, 0xF0, 0x78, 0x00, 0xE0, 0xE3, 0x79, 0x7C, 0x00, 0xC0, 0xE3, 0x79, 0x3C, 0x00, 0x80, 0xC7, 0x3F, 0x1E, 0x00, 0x80, 0xC7, 0x3F, 0x1E, 0x00, 0x00, 0x8F, 0x1F, 0x0F, 0x00, 0x00, 0x8F, 0x0F, 0x0F, 0x00, 0x00, 0x1E, 0x8F, 0x07, 0x00, 0x00, 0x1E, 0x86, 0x07, 0x00, 0x00, 0x3C, 0xC0, 0x03, 0x00, 0x00, 0x3C, 0xC0, 0x03, 0x00, 0x00, 0x78, 0xE0, 0x01, 0x00, 0x00, 0x78, 0xE0, 0x01, 0x00, 0x00, 0x70, 0xE0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0xE0, 0x70, 0x00, 0x00, 0x00, 0xE0, 0x70, 0x00, 0x00, 0x00, 0xE0, 0x70, 0x00, 0x00, 0x00, 0xE0, 0x70, 0x00, 0x00, 0x00, 0xE0, 0x70, 0x00, 0x00, 0x00, 0xE0, 0x70, 0x00, 0x00, 0x00, 0xE0, 0x70, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x70, 0xE0, 0x00, 0x00, 0x00, 0x78, 0xE0, 0x01, 0x00, 0x00, 0x78, 0xE0, 0x01, 0x00, 0x00, 0x78, 0xE0, 0x01, 0x00, 0x00, 0x38, 0xC0, 0x01, 0x00, 0x00, 0x3C, 0xC0, 0x03, 0x00, 0x00, 0x3C, 0xC0, 0x03, 0x00, 0x00, 0x1C, 0x80, 0x03, 0x00, 0x00, 0x1E, 0x80, 0x07, 0x00, 0x00, 0x1E, 0x80, 0x07, 0x00, 0x00, 0x0F, 0x00, 0x07, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x80, 0x07, 0x00, 0x1E, 0x00, 0xC0, 0x03, 0x00, 0x1C, 0x00, 0xC0, 0x03, 0x00, 0x3C, 0x00, 0xC0, 0x03, 0x00, 0x3C, 0x00, 0xC0, 0x01, 0x00, 0x38, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x00 }",
|
||||
// "USERPREFS_NETWORK_ENABLED_PROTOCOLS": "1", // Enable UDP mesh
|
||||
// "USERPREFS_NETWORK_WIFI_ENABLED": "true",
|
||||
// "USERPREFS_NETWORK_WIFI_SSID": "wifi_ssid",
|
||||
@@ -52,8 +52,8 @@
|
||||
// "USERPREFS_MQTT_PASSWORD": "large4cats",
|
||||
// "USERPREFS_MQTT_ENCRYPTION_ENABLED": "true",
|
||||
// "USERPREFS_MQTT_TLS_ENABLED": "false",
|
||||
// "USERPREFS_MQTT_ROOT_TOPIC": "event/REPLACEME",
|
||||
"USERPREFS_MQTT_ROOT_TOPIC": "event/BurningMesh",
|
||||
// "USERPREFS_RINGTONE_NAG_SECS": "60",
|
||||
"USERPREFS_RINGTONE_RTTTL": "24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p",
|
||||
"USERPREFS_TZ_STRING": "tzplaceholder "
|
||||
"USERPREFS_TZ_STRING": "PST8PDT,M3.2.0,M11.1.0"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user