Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5df6c20171 | ||
|
|
7d7893cf08 | ||
|
|
db707ffd8c | ||
|
|
9eb386095d | ||
|
|
7fec5d9fb5 | ||
|
|
32280a7ea3 | ||
|
|
5988668026 | ||
|
|
4f2700d59a |
@@ -1,3 +1,49 @@
|
||||
Version 1.9.11:
|
||||
- Endlose Startschleife behoben: Beleuchtung an, nie ein Bild. Der P4 startet sich nach dem
|
||||
Einschalten absichtlich einmal neu, weil das Panel sonst schwarz bleibt. Die Absicherung
|
||||
dagegen verließ sich darauf, dass der zweite Start kein Kaltstart mehr ist - der Chip
|
||||
meldet aber auch nach dem selbst ausgelösten Neustart wieder einen Kaltstart. Damit griff
|
||||
die Bedingung erneut, endlos.
|
||||
- Der Neustart wird jetzt vermerkt und beim zweiten Durchlauf erkannt, unabhängig davon, was
|
||||
der Chip als Startgrund meldet. Beim nächsten echten Einschalten erfolgt wieder genau ein
|
||||
Neustart.
|
||||
- Die Meldung über diesen Neustart lief bisher über die USB-Verbindung und war im seriellen
|
||||
Monitor nicht zu sehen - deshalb war von der Schleife nichts zu erkennen. Sie läuft jetzt
|
||||
denselben Weg wie die übrigen Panel-Meldungen.
|
||||
|
||||
Version 1.9.10:
|
||||
- Alle Messzeilen laufen jetzt auf derselben Uhr. Die des Zeichenablaufs startete später als
|
||||
die des Hauptablaufs; die Zeiten ließen sich nur mit Umrechnung vergleichen.
|
||||
- Der Touch meldet jetzt, wenn er Rohwerte verwirft, weil sie außerhalb des gültigen
|
||||
Bereichs liegen, und nennt bei jeder erkannten Berührung, wie viele vorher verworfen
|
||||
wurden. Eine Berührung, deren Rohwerte lange verworfen werden, sieht von außen genauso aus
|
||||
wie ein Display, das nicht reagiert - das war bisher nicht zu unterscheiden.
|
||||
|
||||
Version 1.9.9:
|
||||
- Die kleinen Kacheln unten im Dashboard behalten beim Bezug ihre Höhe. Bisher bekam die
|
||||
untere Zeile während des Bezugs deutlich mehr Platz - die Kacheln wurden enorm hoch und
|
||||
das Dashboard sprang bei jedem Bezugsbeginn sichtbar um.
|
||||
- Die Messzeilen gingen bisher teils über die USB-Verbindung hinaus und waren im seriellen
|
||||
Monitor gar nicht zu sehen - die Messung der Helligkeit lief damit ins Leere. Alle
|
||||
Messzeilen laufen jetzt über denselben Weg wie die Panel-Meldungen.
|
||||
- Jede Messzeile trägt jetzt eine Zeitmarke. Nur so sind die Lücken zu sehen, in denen die
|
||||
fünf Sekunden vergehen.
|
||||
- Der Wechsel in den und aus dem Standby wird an jeder Station vermessen: Ankunft der
|
||||
Meldung, Warten auf die Anzeigesperre, Dauer der Aktualisierung. Ebenso der Weg vom Tippen
|
||||
auf die Standby-Uhr bis zur fertig aufgebauten Rückfrage.
|
||||
|
||||
Version 1.9.8:
|
||||
- Der Stillstand beim Wechsel in den Standby ist gefunden und behoben. LVGL legt für JEDE
|
||||
Textglyphe einen eigenen Zwischenpuffer an - bei der großen Uhr rund 48 KB pro Ziffer, mit
|
||||
zwei parallel arbeitenden Zeicheneinheiten fast 100 KB gleichzeitig. Der interne
|
||||
LVGL-Speicher hatte nur rund 98 KB am Stück frei; es reichte knapp nicht. Schlägt die
|
||||
Anforderung fehl, hält LVGL per Zusicherung in einer Endlosschleife an - kein Absturz,
|
||||
keine Meldung, das Display steht einfach. Deshalb brach der Mitschnitt ohne Fehler ab.
|
||||
- Große Glyphenpuffer liegen jetzt im externen Speicher (PSRAM, 32 MB frei). Kleine bleiben
|
||||
im internen, der ist schneller - sonst würde jeder Text langsamer.
|
||||
- Hält LVGL künftig wegen einer verletzten Zusicherung an, sagt es das jetzt, statt stumm
|
||||
stehen zu bleiben.
|
||||
|
||||
Version 1.9.7:
|
||||
- Messpunkte für den Stillstand beim Wechsel in den Standby: Beide Abläufe - der Haupt- und
|
||||
der Zeichenablauf - melden jetzt alle zwei Sekunden einen Herzschlag mit Speicherstand.
|
||||
|
||||
@@ -47,10 +47,23 @@ static bool g_bootCountCleared = false;
|
||||
|
||||
// --- Protokoll-Callbacks ---------------------------------------------------------------
|
||||
static void onState(const MachineState& st) {
|
||||
// Vermessen: Zwischen dem Umschalten und dem sichtbaren Ergebnis vergehen rund fuenf
|
||||
// Sekunden. Jede Station bekommt eine Zeitmarke, damit die Luecke zu sehen ist.
|
||||
static bool s_lastStandby = false;
|
||||
bool wechsel = (st.standbyActive != s_lastStandby);
|
||||
s_lastStandby = st.standbyActive;
|
||||
uint32_t t0 = millis();
|
||||
if (wechsel) esp_rom_printf("[Zustand] %u ms: Standby jetzt %s - Meldung angekommen\n",
|
||||
(unsigned)t0, st.standbyActive ? "an" : "aus");
|
||||
// LVGL laeuft im realen Modus in einem eigenen Task -> UI-Zugriff sperren.
|
||||
hal_lock();
|
||||
uint32_t t1 = millis();
|
||||
ui_update(st);
|
||||
uint32_t t2 = millis();
|
||||
hal_unlock();
|
||||
if (wechsel || (t2 - t0) > 200)
|
||||
esp_rom_printf("[Zustand] %u ms: Sperre %u ms, Anzeige aktualisiert %u ms\n",
|
||||
(unsigned)millis(), (unsigned)(t1 - t0), (unsigned)(t2 - t1));
|
||||
|
||||
// Display im Standby aus; ist "Uhrzeit im Standby anzeigen" aktiv, bleibt es an,
|
||||
// aber abgedunkelt (nicht blendend bei Nacht). Helligkeiten kommen von der S3
|
||||
@@ -72,7 +85,8 @@ static void onState(const MachineState& st) {
|
||||
uint32_t t0 = millis();
|
||||
hal_backlight(bl);
|
||||
uint32_t dt = millis() - t0;
|
||||
if (dt > 50) Serial.printf("[HAL] Helligkeit %d %% gesetzt, %u ms\n", bl, (unsigned)dt);
|
||||
if (dt > 50) esp_rom_printf("[HAL] %u ms: Helligkeit %d %% gesetzt, brauchte %u ms\n",
|
||||
(unsigned)millis(), bl, (unsigned)dt);
|
||||
s_lastBacklight = bl;
|
||||
}
|
||||
}
|
||||
@@ -83,7 +97,8 @@ static void main_heartbeat() {
|
||||
static uint32_t s_last = 0;
|
||||
if (millis() - s_last < 2000) return;
|
||||
s_last = millis();
|
||||
Serial.printf("[Haupt] Herzschlag, freier Speicher %u Byte\n", (unsigned)ESP.getFreeHeap());
|
||||
esp_rom_printf("[Haupt] %u ms: Herzschlag, freier Speicher %u Byte\n",
|
||||
(unsigned)millis(), (unsigned)ESP.getFreeHeap());
|
||||
}
|
||||
|
||||
static void onAck(uint32_t id, bool ok, const String& message) {
|
||||
@@ -321,19 +336,36 @@ void setup() {
|
||||
// nicht (siehe WS7_DSI_RESTART).
|
||||
//
|
||||
// Deshalb startet der P4 sich nach einem Kaltstart genau einmal selbst neu, nachdem
|
||||
// der erste Hochlauf durch ist. Beim zweiten Durchlauf ist der Startgrund kein
|
||||
// Kaltstart mehr, die Bedingung greift also nicht erneut - eine Schleife ist
|
||||
// ausgeschlossen. Kostet rund drei Sekunden, aber nur beim Einschalten.
|
||||
// der erste Hochlauf durch ist. Kostet rund drei Sekunden, aber nur beim Einschalten.
|
||||
//
|
||||
// Frueher stuetzte sich die Absicherung dagegen allein auf den Startgrund: Beim zweiten
|
||||
// Durchlauf sei es kein Kaltstart mehr, eine Schleife also ausgeschlossen. Das stimmt
|
||||
// nicht - der Chip meldet auch nach dem selbst ausgeloesten Neustart wieder einen
|
||||
// Kaltstart, und dann startet er endlos neu. Genau das ist aufgetreten: Beleuchtung an,
|
||||
// nie ein Bild. Deshalb wird jetzt zusaetzlich vermerkt, dass der Neustart schon
|
||||
// stattgefunden hat; darauf ist Verlass, unabhaengig vom gemeldeten Startgrund.
|
||||
#if (JC_PANEL_TYPE == WS_PANEL_7H) && WS7_COLD_BOOT_RESTART
|
||||
if (esp_reset_reason() == ESP_RST_POWERON) {
|
||||
// Der Fruehstart-Zaehler wurde oben bereits erhoeht. Diesen gewollten Neustart
|
||||
// darf er nicht mitzaehlen, sonst laeuft die Absturzsicherung nach ein paar
|
||||
// Einschaltvorgaengen in den Update-Modus.
|
||||
{ Preferences p; p.begin("bootguard", false); p.putUShort("early", 0); p.end(); }
|
||||
DBG_SERIAL.println(F("[Panel] Kaltstart - einmaliger Neustart fuer das Displaypanel"));
|
||||
DBG_SERIAL.flush();
|
||||
delay(50);
|
||||
esp_restart();
|
||||
Preferences p;
|
||||
p.begin("bootguard", false);
|
||||
bool schonNeugestartet = p.getUChar("kaltneu", 0) != 0;
|
||||
if (schonNeugestartet) {
|
||||
// Zweiter Durchlauf: Vermerk loeschen, damit beim naechsten echten Einschalten
|
||||
// wieder genau ein Neustart erfolgt.
|
||||
p.putUChar("kaltneu", 0);
|
||||
p.end();
|
||||
esp_rom_printf("[Panel] Neustart bereits erfolgt - Hochlauf wird fortgesetzt\n");
|
||||
} else {
|
||||
p.putUChar("kaltneu", 1);
|
||||
// Der Fruehstart-Zaehler wurde oben bereits erhoeht. Diesen gewollten Neustart
|
||||
// darf er nicht mitzaehlen, sonst laeuft die Absturzsicherung nach ein paar
|
||||
// Einschaltvorgaengen in den Update-Modus.
|
||||
p.putUShort("early", 0);
|
||||
p.end();
|
||||
esp_rom_printf("[Panel] Kaltstart - einmaliger Neustart fuer das Displaypanel\n");
|
||||
delay(50);
|
||||
esp_restart();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
g_client.begin(); // UART starten, hello folgt automatisch in loop()
|
||||
|
||||
@@ -310,14 +310,26 @@ static bool ws7_touch_get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y
|
||||
bool got = s_touch_get_xy_orig(tp, x, y, strength, point_num, max_point_num);
|
||||
int64_t now = esp_timer_get_time();
|
||||
|
||||
// Unplausible Rohwerte gelten als Aussetzer, nicht als Beruehrung.
|
||||
// Unplausible Rohwerte gelten als Aussetzer, nicht als Beruehrung. Wie viele davon
|
||||
// anfallen, war bisher nirgends zu sehen - eine Beruehrung, deren Rohwerte lange
|
||||
// verworfen werden, sieht von aussen wie ein Display aus, das nicht reagiert.
|
||||
static uint32_t s_verworfen = 0;
|
||||
if (got && *point_num > 0 &&
|
||||
(x[0] > WS7_TOUCH_RAW_X_MAX || y[0] > WS7_TOUCH_RAW_Y_MAX)) {
|
||||
if (s_verworfen == 0)
|
||||
esp_rom_printf("[Touch] %u ms: Rohwert verworfen (x %u, y %u liegen ausserhalb)\n",
|
||||
(unsigned)(now / 1000), (unsigned)x[0], (unsigned)y[0]);
|
||||
s_verworfen++;
|
||||
got = false;
|
||||
*point_num = 0;
|
||||
}
|
||||
|
||||
if (got && *point_num > 0) {
|
||||
if (!s_touch_down)
|
||||
esp_rom_printf("[Touch] %u ms: Beruehrung erkannt bei x %u, y %u; %u Rohwerte vorher verworfen\n",
|
||||
(unsigned)(now / 1000), (unsigned)x[0], (unsigned)y[0],
|
||||
(unsigned)s_verworfen);
|
||||
s_verworfen = 0;
|
||||
s_touch_last_x = x[0];
|
||||
s_touch_last_y = y[0];
|
||||
s_touch_last_us = now;
|
||||
|
||||
@@ -374,8 +374,10 @@
|
||||
#define LV_USE_ASSERT_OBJ 0 /*Check the object's type and existence (e.g. not deleted). (Slow)*/
|
||||
|
||||
/*Add a custom handler when assert happens e.g. to restart the MCU*/
|
||||
#define LV_ASSERT_HANDLER_INCLUDE <stdint.h>
|
||||
#define LV_ASSERT_HANDLER while(1); /*Halt by default*/
|
||||
#define LV_ASSERT_HANDLER_INCLUDE <esp_rom_sys.h>
|
||||
// Frueher hielt LVGL hier stumm in einer Endlosschleife an - das Display stand, ohne dass
|
||||
// irgendwo etwas davon zu sehen war. Jetzt sagt es wenigstens, dass es angehalten hat.
|
||||
#define LV_ASSERT_HANDLER esp_rom_printf("[LVGL] Zusicherung verletzt - Zeichenablauf haelt an\n"); while(1);
|
||||
|
||||
/*-------------
|
||||
* Debug
|
||||
|
||||
+57
-12
@@ -18,6 +18,7 @@
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <Preferences.h> // Dashboard-Design P4-lokal merken (NVS)
|
||||
#include <esp_memory_utils.h> // esp_ptr_external_ram(): welcher Speicher einen Puffer traegt
|
||||
#include <esp_heap_caps.h> // Verlaufs-Historie im PSRAM allozieren (interner RAM ist knapp)
|
||||
#include "ui.h"
|
||||
#include <Preferences.h>
|
||||
@@ -929,7 +930,14 @@ static bool wake_choice_offered() {
|
||||
return g_state.cxWakeChoice ||
|
||||
(g_state.cxEnabled && g_state.cxArmable && g_state.cxAskOnWake);
|
||||
}
|
||||
static void standby_screen_cb(lv_event_t*) { wake_confirm_show(); } // Tipp auf Standby-Uhr -> nachfragen
|
||||
static void standby_screen_cb(lv_event_t*) { // Tipp auf Standby-Uhr -> nachfragen
|
||||
// Vermessen: Vom Tippen bis zur sichtbaren Rueckfrage vergehen rund fuenf Sekunden.
|
||||
uint32_t t0 = millis();
|
||||
esp_rom_printf("[Touch] %u ms: Tipp auf die Standby-Uhr erkannt\n", (unsigned)t0);
|
||||
wake_confirm_show();
|
||||
esp_rom_printf("[Touch] %u ms: Rueckfrage aufgebaut, brauchte %u ms\n",
|
||||
(unsigned)millis(), (unsigned)(millis() - t0));
|
||||
}
|
||||
static void wake_cancel() { // Abbrechen -> zurueck in die Standby-Helligkeit
|
||||
wake_timeout_stop();
|
||||
wake_confirm_hide();
|
||||
@@ -3555,7 +3563,7 @@ static void refr_ready_cb(lv_event_t*) {
|
||||
uint32_t d = lv_tick_get() - g_refrStart;
|
||||
if (d < REFR_WARN_MS) return;
|
||||
unsigned pct = (unsigned)((uint64_t)g_refrPixels * 100ULL / ((uint64_t)LCD_H_RES * LCD_V_RES));
|
||||
esp_rom_printf("[UI] Bildaufbau %u ms, %u Bereiche, %u %% der Flaeche\n",
|
||||
esp_rom_printf("[UI] %u ms: Bildaufbau %u ms, %u Bereiche, %u %% der Flaeche\n", (unsigned)millis(),
|
||||
(unsigned)d, (unsigned)g_refrAreas, pct);
|
||||
// Lage der Bereiche mit ausgeben. Erst daran ist zu erkennen, WELCHER Teil der
|
||||
// Oberflaeche das Neuzeichnen ausloest - die Groesse allein sagt das nicht.
|
||||
@@ -3567,8 +3575,39 @@ static void refr_ready_cb(lv_event_t*) {
|
||||
|
||||
static void ui_heartbeat_cb(lv_timer_t*) {
|
||||
lv_mem_monitor_t m; lv_mem_monitor(&m);
|
||||
esp_rom_printf("[UI] Herzschlag, LVGL-Speicher frei %u von %u Byte, groesster Block %u\n",
|
||||
(unsigned)m.free_size, (unsigned)m.total_size, (unsigned)m.free_biggest_size);
|
||||
esp_rom_printf("[UI] %u ms: Herzschlag, LVGL-Speicher frei %u von %u Byte, groesster Block %u\n",
|
||||
(unsigned)millis(), (unsigned)m.free_size, (unsigned)m.total_size,
|
||||
(unsigned)m.free_biggest_size);
|
||||
}
|
||||
|
||||
// LVGL legt fuer JEDE Textglyphe einen eigenen Zwischenpuffer an - Breite mal Hoehe, ein
|
||||
// Byte je Bildpunkt. Bei der grossen Standby-Uhr sind das 190 x 256 = rund 48 KB pro Ziffer,
|
||||
// und mit zwei parallel arbeitenden Zeicheneinheiten fast 100 KB gleichzeitig. Der interne
|
||||
// LVGL-Speicher fasst nur 245 KB, wovon rund 98 KB am Stueck frei sind - es reichte knapp
|
||||
// nicht. Schlaegt die Anforderung fehl, haelt LVGL per Zusicherung in einer Endlosschleife
|
||||
// an: kein Absturz, keine Meldung, das Display steht einfach. Genau das war der Stillstand
|
||||
// beim Wechsel in den Standby.
|
||||
//
|
||||
// Diese Puffer wandern daher in den externen Speicher (PSRAM, 32 MB frei). Kleine Glyphen
|
||||
// bleiben im internen Speicher, weil der schneller ist und Text sonst ueberall langsamer
|
||||
// wuerde; nur die grossen gehen nach aussen.
|
||||
#define FONT_BUF_EXTERN_AB 16384 // ab dieser Groesse in den externen Speicher
|
||||
|
||||
static void* font_buf_malloc(size_t size, lv_color_format_t cf) {
|
||||
LV_UNUSED(cf);
|
||||
size += LV_DRAW_BUF_ALIGN - 1;
|
||||
if (size >= FONT_BUF_EXTERN_AB) {
|
||||
void* p = heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if (p) return p;
|
||||
}
|
||||
return lv_malloc(size);
|
||||
}
|
||||
|
||||
static void font_buf_free(void* buf) {
|
||||
// Der externe Speicher liegt ausserhalb des LVGL-Bereichs; daran ist zu erkennen,
|
||||
// welcher der beiden Wege den Puffer vergeben hat.
|
||||
if (esp_ptr_external_ram(buf)) heap_caps_free(buf);
|
||||
else lv_free(buf);
|
||||
}
|
||||
|
||||
static void refr_monitor_install() {
|
||||
@@ -3981,6 +4020,10 @@ void ui_init(ProtocolClient* client) {
|
||||
show_page(PG_DASH);
|
||||
if (g_client) g_client->sendListProfiles();
|
||||
|
||||
// Glyphenpuffer umlenken, bevor der erste Text gezeichnet wird.
|
||||
lv_draw_buf_handlers_t* fh = lv_draw_buf_get_font_handlers();
|
||||
fh->buf_malloc_cb = font_buf_malloc;
|
||||
fh->buf_free_cb = font_buf_free;
|
||||
refr_monitor_install();
|
||||
lv_timer_create(ui_heartbeat_cb, 2000, nullptr);
|
||||
g_uiReady = true;
|
||||
@@ -4079,12 +4122,14 @@ static void dash_brew_mode(bool on) {
|
||||
if (on == g_dashBrewMode) return; // nur bei echtem Wechsel neu anordnen
|
||||
g_dashBrewMode = on;
|
||||
if (!g_tempRow || !g_infoRow) return;
|
||||
lv_obj_set_flex_grow(g_tempRow, on ? 1 : 3);
|
||||
lv_obj_set_flex_grow(g_infoRow, on ? 3 : 2);
|
||||
// Die Schrift von Shot-Timer und Waage bleibt unveraendert. Frueher wechselte sie
|
||||
// waehrend des Bezugs auf den grossen fetten Schnitt - das wirkte gegenueber dem
|
||||
// restlichen Dashboard zu laut. Der Bereich bekommt weiterhin mehr Platz, die Zahlen
|
||||
// stehen dadurch freier, aber in derselben Schrift wie sonst auch.
|
||||
// Die Zeilenhoehen bleiben unveraendert. Frueher bekam die untere Zeile waehrend des
|
||||
// Bezugs deutlich mehr Platz - die kleinen Kacheln wurden dadurch enorm hoch und das
|
||||
// Dashboard sprang bei jedem Bezugsbeginn sichtbar um. Der Bezug hebt sich jetzt allein
|
||||
// ueber seine Inhalte hervor, nicht ueber die Groesse.
|
||||
(void)on;
|
||||
// Die Schrift von Shot-Timer und Waage bleibt ebenfalls unveraendert. Frueher wechselte
|
||||
// sie waehrend des Bezugs auf den grossen fetten Schnitt - das wirkte gegenueber dem
|
||||
// restlichen Dashboard zu laut.
|
||||
}
|
||||
|
||||
static void dash_brew_mode_tick(const MachineState& st) {
|
||||
@@ -4175,11 +4220,11 @@ void ui_update(const MachineState& st) {
|
||||
// Vermessen: Das Einblenden der Uhr ist der Moment, in dem das Display
|
||||
// zuletzt stehen geblieben ist. Bleibt die zweite Zeile aus, haengt es hier.
|
||||
esp_rom_printf("[UI] Standby-Uhr wird eingeblendet\n");
|
||||
uint32_t t0 = lv_tick_get();
|
||||
uint32_t t0 = millis();
|
||||
ui_fade_in(g_standbyScreen, UI_FADE_MS); // Einschlaf-Animation
|
||||
g_standbyShown = true;
|
||||
esp_rom_printf("[UI] Standby-Uhr eingeblendet, %u ms\n",
|
||||
(unsigned)(lv_tick_get() - t0));
|
||||
(unsigned)(millis() - t0));
|
||||
}
|
||||
// Frueher wurde die Uhr hier bei JEDER Zustandsmeldung nach vorn geholt. Das
|
||||
// ordnet die Ebenen neu und laesst LVGL den gesamten Bildschirm neu zeichnen -
|
||||
|
||||
Reference in New Issue
Block a user