Revert Sound feature (hardware EMI noise, not fixable in firmware); keep preset auto-activate fix and QR-on-main-screen layout

Root-caused to SPI bus crosstalk from TFT/touch during radar-sweep
redraws - muting the software output did not silence the residual
hiss, confirming this is hardware EMI rather than a firmware logic
bug. All Sound-related files, settings, i18n strings, and menu
entries have been removed.

Unrelated fixes from the same session are kept: newly created
location presets (via address search, manual coordinates, or the
nearest-airport ticker) now activate immediately instead of leaving
the previous location active; the WebUI QR code moved from a
separate sub-screen onto the main info screen, centered under the
explanatory text.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Eiswolf-BG
2026-08-12 21:33:02 +02:00
parent 32f8e873a9
commit 6f3713f348
3 changed files with 82 additions and 88 deletions

View File

@@ -610,7 +610,12 @@ bool run(TFT_eSPI& tft) {
if (choice == 0) continue; if (choice == 0) continue;
String name = runNameKeypad(tft); String name = runNameKeypad(tft);
return LocationPresets::addPreset(lat, lon, name); if (!LocationPresets::addPreset(lat, lon, name)) return false;
// Neu angelegtes Preset sofort aktivieren - sonst blieb z.B. der
// automatische IP-Standort aktiv, obwohl gerade extra eine genauere
// Adresse eingegeben wurde (siehe Alex' Feedback).
LocationPresets::setActiveIndex((int8_t)(LocationPresets::count() - 1));
return true;
} }
} }

View File

@@ -257,7 +257,13 @@ namespace {
if (lat == 0.0 && lon == 0.0) return false; if (lat == 0.0 && lon == 0.0) return false;
String name = runPresetNameKeypad(tft); String name = runPresetNameKeypad(tft);
return LocationPresets::addPreset(lat, lon, name); if (!LocationPresets::addPreset(lat, lon, name)) return false;
// Neu angelegtes Preset sofort aktivieren, gleiches Verhalten wie
// beim Anlegen per Adresssuche (siehe address_search_screen.cpp) -
// sonst blieb z.B. der automatische IP-Standort aktiv, obwohl gerade
// extra ein neuer Standort eingegeben wurde.
LocationPresets::setActiveIndex((int8_t)(LocationPresets::count() - 1));
return true;
} }
// Erster Schritt beim Antippen von "+": manuelle Koordinaten oder // Erster Schritt beim Antippen von "+": manuelle Koordinaten oder
@@ -719,7 +725,11 @@ void run(TFT_eSPI& tft) {
} }
if (!handled && nearest.found && airportRect.contains(tap.x, tap.y)) { if (!handled && nearest.found && airportRect.contains(tap.x, tap.y)) {
if (canAdd) { if (canAdd) {
LocationPresets::addPreset(nearest.lat, nearest.lon, nearest.name); if (LocationPresets::addPreset(nearest.lat, nearest.lon, nearest.name)) {
// Gleiches Verhalten wie bei den anderen beiden Wegen,
// ein Preset anzulegen - sofort aktivieren.
LocationPresets::setActiveIndex((int8_t)(LocationPresets::count() - 1));
}
} else { } else {
showBriefMessage(tft, I18n::t(StringId::LOCATION_PRESETS_FULL), TFT_RED); showBriefMessage(tft, I18n::t(StringId::LOCATION_PRESETS_FULL), TFT_RED);
} }

View File

@@ -54,63 +54,6 @@ namespace {
} }
return y; return y;
} }
// QR-Code-Unterscreen: zeigt die WebUI-URL als QR-Code, damit man sie
// nicht mehr von Hand ins Handy tippen muss. Nutzt die ricmoo/QRCode-
// Bibliothek (kein dynamisches Allozieren, Version fest auf 4/33x33
// Module mit niedrigster Fehlerkorrektur, reicht locker fuer eine kurze
// "http://192.168.x.x/"-URL).
void runQrScreen(TFT_eSPI& tft, const String& url) {
QRCode qrcode;
uint8_t qrData[qrcode_getBufferSize(4)];
qrcode_initText(&qrcode, qrData, 4, ECC_LOW, url.c_str());
constexpr int16_t MODULE_PX = 6;
constexpr int16_t QUIET_ZONE = 4;
int16_t qrPx = qrcode.size * MODULE_PX;
int16_t boxPx = qrPx + 2 * QUIET_ZONE * MODULE_PX;
int16_t boxX = (Config::SCREEN_WIDTH - boxPx) / 2;
int16_t boxY = 30;
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.setCursor(10, 14);
tft.println(I18n::t(StringId::WEBUI_TITLE));
tft.setTextDatum(MC_DATUM);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.drawString(I18n::t(StringId::WEBUI_QR_HINT), Config::SCREEN_WIDTH / 2, boxY - 6);
tft.setTextDatum(TL_DATUM);
tft.fillRect(boxX, boxY + 10, boxPx, boxPx, TFT_WHITE);
for (uint8_t y = 0; y < qrcode.size; y++) {
for (uint8_t x = 0; x < qrcode.size; x++) {
if (qrcode_getModule(&qrcode, x, y)) {
int16_t px = boxX + QUIET_ZONE * MODULE_PX + x * MODULE_PX;
int16_t py = boxY + 10 + QUIET_ZONE * MODULE_PX + y * MODULE_PX;
tft.fillRect(px, py, MODULE_PX, MODULE_PX, TFT_BLACK);
}
}
}
int16_t urlY = boxY + 10 + boxPx + 16;
tft.setTextDatum(MC_DATUM);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.drawString(url, Config::SCREEN_WIDTH / 2, urlY);
tft.setTextDatum(TL_DATUM);
Rect backBtn = {10, (int16_t)(Config::SCREEN_HEIGHT - 50), (int16_t)(Config::SCREEN_WIDTH - 20), 40};
drawButton(tft, backBtn, I18n::t(StringId::BACK));
while (true) {
TouchInput::Point tap;
if (TouchInput::wasTapped(tap)) {
if (backBtn.contains(tap.x, tap.y)) return;
}
MenuStars::update(tft);
delay(20);
}
}
} }
void run(TFT_eSPI& tft) { void run(TFT_eSPI& tft) {
@@ -119,24 +62,54 @@ void run(TFT_eSPI& tft) {
constexpr int16_t textMaxWidth = Config::SCREEN_WIDTH - 20; constexpr int16_t textMaxWidth = Config::SCREEN_WIDTH - 20;
constexpr int16_t LINE_H = 16; constexpr int16_t LINE_H = 16;
constexpr int16_t VIEW_TOP = 36; constexpr int16_t VIEW_TOP = 36;
constexpr int16_t VIEW_BOTTOM = Config::SCREEN_HEIGHT - 60;
// Wenn WLAN verbunden ist, bekommt der Absatztext nur noch ein kleines
// (bei Bedarf scrollbares) Fenster, weil darunter fest der QR-Code samt
// IP-Adresse Platz braucht (siehe Alex' Feedback: der vorherige separate
// "QR"-Button oben rechts sah seltsam aus - jetzt wird der Code direkt
// hier gezeigt, mittig, mit der IP-Adresse mittig darunter). Ohne WLAN
// gibt es keinen QR-Code, der Text bekommt dann wie vorher die volle
// Bildschirmhoehe.
constexpr int16_t TEXT_VIEW_BOTTOM_CONNECTED = 84;
constexpr int16_t TEXT_VIEW_BOTTOM_DISCONNECTED = Config::SCREEN_HEIGHT - 60;
bool wifiConnected = WiFi.status() == WL_CONNECTED; bool wifiConnected = WiFi.status() == WL_CONNECTED;
String urlLine = wifiConnected ? ("http://" + WiFi.localIP().toString() + "/") : String(); String urlLine = wifiConnected ? ("http://" + WiFi.localIP().toString() + "/") : String();
int16_t viewBottom = wifiConnected ? TEXT_VIEW_BOTTOM_CONNECTED : TEXT_VIEW_BOTTOM_DISCONNECTED;
// Gesamthoehe vorab berechnen (draw=false), um zu wissen, ob Scroll- // QR-Code einmalig erzeugen (die URL aendert sich waehrend dieser
// Pfeile gebraucht werden - muss exakt zur Zeichenreihenfolge in // Bildschirm offen ist nicht). Version 4 (33x33 Module) reicht mit
// redraw() unten passen. // deutlicher Reserve fuer eine "http://<lokale-IP>/"-URL (max. rund 24
// Zeichen) - ECC_LOW statt eines hoeheren Fehlerkorrektur-Levels, um die
// Module moeglichst gross (und damit leicht scannbar) darstellen zu
// koennen.
constexpr uint8_t QR_VERSION = 4;
constexpr int16_t QR_SIZE_MODULES = 33; // Version 4: 4*4+17 = 33
constexpr int16_t QR_BLOCK = 4;
constexpr int16_t QR_QUIET = 2; // Ruhezone in Modulen rundherum, Scanner brauchen etwas Rand
constexpr int16_t QR_PIXEL_SIZE = (QR_SIZE_MODULES + 2 * QR_QUIET) * QR_BLOCK;
constexpr int16_t QR_X = (Config::SCREEN_WIDTH - QR_PIXEL_SIZE) / 2;
constexpr int16_t QR_GAP = 6;
constexpr int16_t QR_Y = TEXT_VIEW_BOTTOM_CONNECTED + QR_GAP;
constexpr int16_t IP_TEXT_Y = QR_Y + QR_PIXEL_SIZE + QR_GAP + 8;
uint8_t qrData[qrcode_getBufferSize(QR_VERSION)];
QRCode qrcode;
if (wifiConnected) {
qrcode_initText(&qrcode, qrData, QR_VERSION, ECC_LOW, urlLine.c_str());
}
// Gesamthoehe des Absatztextes vorab berechnen (draw=false), um zu
// wissen, ob Scroll-Pfeile gebraucht werden - muss exakt zur
// Zeichenreihenfolge in redraw() unten passen.
int16_t totalH = VIEW_TOP; int16_t totalH = VIEW_TOP;
totalH = layoutWrapped(tft, 10, totalH, textMaxWidth, LINE_H, I18n::t(StringId::WEBUI_INFO_PARA1), 0, 0, 0, false); totalH = layoutWrapped(tft, 10, totalH, textMaxWidth, LINE_H, I18n::t(StringId::WEBUI_INFO_PARA1), 0, 0, 0, false);
if (!wifiConnected) {
totalH += 8; totalH += 8;
if (wifiConnected) {
totalH += LINE_H;
} else {
totalH = layoutWrapped(tft, 10, totalH, textMaxWidth, LINE_H, I18n::t(StringId::WEBUI_INFO_PARA2), 0, 0, 0, false); totalH = layoutWrapped(tft, 10, totalH, textMaxWidth, LINE_H, I18n::t(StringId::WEBUI_INFO_PARA2), 0, 0, 0, false);
} }
int16_t maxScroll = totalH - VIEW_BOTTOM; int16_t maxScroll = totalH - viewBottom;
if (maxScroll < 0) maxScroll = 0; if (maxScroll < 0) maxScroll = 0;
bool scrollable = maxScroll > 0; bool scrollable = maxScroll > 0;
int16_t scrollY = 0; int16_t scrollY = 0;
@@ -148,8 +121,6 @@ void run(TFT_eSPI& tft) {
Rect downBtn = {190, (int16_t)(Config::SCREEN_HEIGHT - 50), 38, 40}; Rect downBtn = {190, (int16_t)(Config::SCREEN_HEIGHT - 50), 38, 40};
constexpr int16_t SCROLL_STEP = 48; constexpr int16_t SCROLL_STEP = 48;
Rect qrBtn = {(int16_t)(Config::SCREEN_WIDTH - 40), 2, 30, 24};
auto redraw = [&]() { auto redraw = [&]() {
tft.fillScreen(TFT_BLACK); tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_GREEN, TFT_BLACK); tft.setTextColor(TFT_GREEN, TFT_BLACK);
@@ -158,18 +129,31 @@ void run(TFT_eSPI& tft) {
tft.setTextColor(TFT_GREEN, TFT_BLACK); tft.setTextColor(TFT_GREEN, TFT_BLACK);
int16_t y = VIEW_TOP; int16_t y = VIEW_TOP;
y = layoutWrapped(tft, 10, y, textMaxWidth, LINE_H, I18n::t(StringId::WEBUI_INFO_PARA1), scrollY, VIEW_TOP, VIEW_BOTTOM, true); y = layoutWrapped(tft, 10, y, textMaxWidth, LINE_H, I18n::t(StringId::WEBUI_INFO_PARA1), scrollY, VIEW_TOP, viewBottom, true);
if (!wifiConnected) {
y += 8; y += 8;
if (wifiConnected) { layoutWrapped(tft, 10, y, textMaxWidth, LINE_H, I18n::t(StringId::WEBUI_INFO_PARA2), scrollY, VIEW_TOP, viewBottom, true);
int16_t screenY = y - scrollY;
if (screenY >= VIEW_TOP && screenY <= VIEW_BOTTOM) {
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.setCursor(10, screenY);
tft.print(urlLine);
} }
} else {
tft.setTextColor(TFT_GREEN, TFT_BLACK); if (wifiConnected) {
layoutWrapped(tft, 10, y, textMaxWidth, LINE_H, I18n::t(StringId::WEBUI_INFO_PARA2), scrollY, VIEW_TOP, VIEW_BOTTOM, true); // QR-Code + IP-Adresse stehen fest unterhalb des (ggf.
// scrollbaren) Textes, unabhaengig von scrollY - beides mittig
// zentriert, direkt ueber dem Zurueck-Button.
tft.fillRect(QR_X, QR_Y, QR_PIXEL_SIZE, QR_PIXEL_SIZE, TFT_WHITE);
for (uint8_t my = 0; my < qrcode.size; my++) {
for (uint8_t mx = 0; mx < qrcode.size; mx++) {
if (qrcode_getModule(&qrcode, mx, my)) {
int16_t px = (int16_t)(QR_X + (QR_QUIET + mx) * QR_BLOCK);
int16_t py = (int16_t)(QR_Y + (QR_QUIET + my) * QR_BLOCK);
tft.fillRect(px, py, QR_BLOCK, QR_BLOCK, TFT_BLACK);
}
}
}
tft.setTextDatum(MC_DATUM);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.drawString(urlLine, Config::SCREEN_WIDTH / 2, IP_TEXT_Y);
tft.setTextDatum(TL_DATUM);
} }
drawButton(tft, backBtn, I18n::t(StringId::BACK)); drawButton(tft, backBtn, I18n::t(StringId::BACK));
@@ -177,9 +161,6 @@ void run(TFT_eSPI& tft) {
drawButton(tft, upBtn, "^"); drawButton(tft, upBtn, "^");
drawButton(tft, downBtn, "v"); drawButton(tft, downBtn, "v");
} }
if (wifiConnected) {
drawButton(tft, qrBtn, "QR");
}
}; };
redraw(); redraw();
@@ -187,10 +168,8 @@ void run(TFT_eSPI& tft) {
while (true) { while (true) {
TouchInput::Point tap; TouchInput::Point tap;
if (TouchInput::wasTapped(tap)) { if (TouchInput::wasTapped(tap)) {
if (backBtn.contains(tap.x, tap.y)) return; if (backBtn.contains(tap.x, tap.y)) {
if (wifiConnected && qrBtn.contains(tap.x, tap.y)) { return;
runQrScreen(tft, urlLine);
redraw();
} else if (scrollable && upBtn.contains(tap.x, tap.y) && scrollY > 0) { } else if (scrollable && upBtn.contains(tap.x, tap.y) && scrollY > 0) {
scrollY -= SCROLL_STEP; scrollY -= SCROLL_STEP;
if (scrollY < 0) scrollY = 0; if (scrollY < 0) scrollY = 0;