mirror of
https://github.com/meshtastic/firmware.git
synced 2025-07-30 02:15:41 +00:00
Initial Burning Man 2025 coordinates support. (#7252)
Some checks are pending
CI / setup (check) (push) Waiting to run
CI / setup (esp32) (push) Waiting to run
CI / setup (esp32c3) (push) Waiting to run
CI / setup (esp32c6) (push) Waiting to run
CI / setup (esp32s3) (push) Waiting to run
CI / setup (nrf52840) (push) Waiting to run
CI / setup (rp2040) (push) Waiting to run
CI / setup (stm32) (push) Waiting to run
CI / check (push) Blocked by required conditions
CI / build-esp32 (push) Blocked by required conditions
CI / build-esp32-s3 (push) Blocked by required conditions
CI / build-esp32-c3 (push) Blocked by required conditions
CI / build-esp32-c6 (push) Blocked by required conditions
CI / build-nrf52 (push) Blocked by required conditions
CI / build-rpi2040 (push) Blocked by required conditions
CI / build-stm32 (push) Blocked by required conditions
CI / build-debian-src (push) Waiting to run
CI / package-pio-deps-native-tft (push) Waiting to run
CI / test-native (push) Waiting to run
CI / docker-deb-amd64 (push) Waiting to run
CI / docker-deb-amd64-tft (push) Waiting to run
CI / docker-alp-amd64 (push) Waiting to run
CI / docker-alp-amd64-tft (push) Waiting to run
CI / docker-deb-arm64 (push) Waiting to run
CI / docker-deb-armv7 (push) Waiting to run
CI / gather-artifacts (esp32) (push) Blocked by required conditions
CI / gather-artifacts (esp32c3) (push) Blocked by required conditions
CI / gather-artifacts (esp32c6) (push) Blocked by required conditions
CI / gather-artifacts (esp32s3) (push) Blocked by required conditions
CI / gather-artifacts (nrf52840) (push) Blocked by required conditions
CI / gather-artifacts (rp2040) (push) Blocked by required conditions
CI / gather-artifacts (stm32) (push) Blocked by required conditions
CI / release-artifacts (push) Blocked by required conditions
CI / release-firmware (esp32) (push) Blocked by required conditions
CI / release-firmware (esp32c3) (push) Blocked by required conditions
CI / release-firmware (esp32c6) (push) Blocked by required conditions
CI / release-firmware (esp32s3) (push) Blocked by required conditions
CI / release-firmware (nrf52840) (push) Blocked by required conditions
CI / release-firmware (rp2040) (push) Blocked by required conditions
CI / release-firmware (stm32) (push) Blocked by required conditions
CI / publish-firmware (push) Blocked by required conditions
Some checks are pending
CI / setup (check) (push) Waiting to run
CI / setup (esp32) (push) Waiting to run
CI / setup (esp32c3) (push) Waiting to run
CI / setup (esp32c6) (push) Waiting to run
CI / setup (esp32s3) (push) Waiting to run
CI / setup (nrf52840) (push) Waiting to run
CI / setup (rp2040) (push) Waiting to run
CI / setup (stm32) (push) Waiting to run
CI / check (push) Blocked by required conditions
CI / build-esp32 (push) Blocked by required conditions
CI / build-esp32-s3 (push) Blocked by required conditions
CI / build-esp32-c3 (push) Blocked by required conditions
CI / build-esp32-c6 (push) Blocked by required conditions
CI / build-nrf52 (push) Blocked by required conditions
CI / build-rpi2040 (push) Blocked by required conditions
CI / build-stm32 (push) Blocked by required conditions
CI / build-debian-src (push) Waiting to run
CI / package-pio-deps-native-tft (push) Waiting to run
CI / test-native (push) Waiting to run
CI / docker-deb-amd64 (push) Waiting to run
CI / docker-deb-amd64-tft (push) Waiting to run
CI / docker-alp-amd64 (push) Waiting to run
CI / docker-alp-amd64-tft (push) Waiting to run
CI / docker-deb-arm64 (push) Waiting to run
CI / docker-deb-armv7 (push) Waiting to run
CI / gather-artifacts (esp32) (push) Blocked by required conditions
CI / gather-artifacts (esp32c3) (push) Blocked by required conditions
CI / gather-artifacts (esp32c6) (push) Blocked by required conditions
CI / gather-artifacts (esp32s3) (push) Blocked by required conditions
CI / gather-artifacts (nrf52840) (push) Blocked by required conditions
CI / gather-artifacts (rp2040) (push) Blocked by required conditions
CI / gather-artifacts (stm32) (push) Blocked by required conditions
CI / release-artifacts (push) Blocked by required conditions
CI / release-firmware (esp32) (push) Blocked by required conditions
CI / release-firmware (esp32c3) (push) Blocked by required conditions
CI / release-firmware (esp32c6) (push) Blocked by required conditions
CI / release-firmware (esp32s3) (push) Blocked by required conditions
CI / release-firmware (nrf52840) (push) Blocked by required conditions
CI / release-firmware (rp2040) (push) Blocked by required conditions
CI / release-firmware (stm32) (push) Blocked by required conditions
CI / publish-firmware (push) Blocked by required conditions
* BRC 2024 Golden Spike Data * Configurable units, based on pull #1 Not exactly the same change; the interim number must be feet for use with golden spike data as-is. * update meshtastic 2.6 with BRC 2025 Golden Spike * add performance improvements * fixed roads + script to make roads * refactored string generation to allow getting hour & street separately for multi-line display * Display BRC location on self location page * formatting fixes via `trunk fmt` * Show BRC location of favorite node --------- Co-authored-by: Gaetan Gueraud <exadeci@gmail.com>
This commit is contained in:
parent
0dcd612a60
commit
94b769e123
149
src/graphics/BRC.h
Normal file
149
src/graphics/BRC.h
Normal file
@ -0,0 +1,149 @@
|
||||
#pragma once
|
||||
|
||||
#include "GPSStatus.h"
|
||||
#include "gps/GeoCoord.h"
|
||||
#include "graphics/Screen.h"
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
class BRCAddress
|
||||
{
|
||||
public:
|
||||
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 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 annular(char *buf, size_t len)
|
||||
{
|
||||
const char *unit = "m";
|
||||
float unitMultiplier = FEET_TO_METER;
|
||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
unitMultiplier = 1.0;
|
||||
unit = "ft";
|
||||
}
|
||||
|
||||
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 full(char *buf, size_t len)
|
||||
{
|
||||
auto l = radial(buf, len - 4);
|
||||
buf += l;
|
||||
*(buf++) = ' ';
|
||||
*(buf++) = '&';
|
||||
*(buf++) = ' ';
|
||||
buf += annular(buf, len - l - 4);
|
||||
buf[l] = 0; // always null terminated
|
||||
return l;
|
||||
};
|
||||
|
||||
private:
|
||||
float bearing;
|
||||
float distance;
|
||||
};
|
@ -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"
|
||||
@ -311,23 +312,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) ===
|
||||
@ -924,7 +914,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 +935,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 +1222,4 @@ std::string UIRenderer::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t mi
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
#endif // HAS_SCREEN
|
||||
#endif // HAS_SCREEN
|
||||
|
Loading…
Reference in New Issue
Block a user