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:
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
totalH += 8;
|
if (!wifiConnected) {
|
||||||
if (wifiConnected) {
|
totalH += 8;
|
||||||
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);
|
||||||
y += 8;
|
if (!wifiConnected) {
|
||||||
|
y += 8;
|
||||||
|
layoutWrapped(tft, 10, y, textMaxWidth, LINE_H, I18n::t(StringId::WEBUI_INFO_PARA2), scrollY, VIEW_TOP, viewBottom, true);
|
||||||
|
}
|
||||||
|
|
||||||
if (wifiConnected) {
|
if (wifiConnected) {
|
||||||
int16_t screenY = y - scrollY;
|
// QR-Code + IP-Adresse stehen fest unterhalb des (ggf.
|
||||||
if (screenY >= VIEW_TOP && screenY <= VIEW_BOTTOM) {
|
// scrollbaren) Textes, unabhaengig von scrollY - beides mittig
|
||||||
tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
// zentriert, direkt ueber dem Zurueck-Button.
|
||||||
tft.setCursor(10, screenY);
|
tft.fillRect(QR_X, QR_Y, QR_PIXEL_SIZE, QR_PIXEL_SIZE, TFT_WHITE);
|
||||||
tft.print(urlLine);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
tft.setTextColor(TFT_GREEN, TFT_BLACK);
|
tft.setTextDatum(MC_DATUM);
|
||||||
layoutWrapped(tft, 10, y, textMaxWidth, LINE_H, I18n::t(StringId::WEBUI_INFO_PARA2), scrollY, VIEW_TOP, VIEW_BOTTOM, true);
|
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;
|
||||||
|
|||||||
Reference in New Issue
Block a user