fix(P4): Verlaufs-Historie ins PSRAM verlagern — interner RAM lief über
Die 60-min-Ringpuffer der Verlauf-Seite (~29 KB) lagen als statische Arrays im internen RAM und sprengten das Board-Limit (Linker: 107 % dynamischer Speicher, Build brach ab). Historie jetzt als ein Block per heap_caps_malloc im PSRAM (Fallback MALLOC_CAP_8BIT), wie die LVGL-Framebuffer; alle Zugriffe gegen Allokationsfehler abgesichert (Chart bliebe dann leer). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
ea64e7de04
commit
fd6ec5371b
+31
-17
@@ -17,6 +17,7 @@
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <Preferences.h> // Dashboard-Design P4-lokal merken (NVS)
|
||||
#include <esp_heap_caps.h> // Verlaufs-Historie im PSRAM allozieren (interner RAM ist knapp)
|
||||
#include "ui.h"
|
||||
#include "theme.h"
|
||||
#include "config.h"
|
||||
@@ -124,11 +125,17 @@ static lv_obj_t* g_axHi = nullptr; static lv_obj_t* g_axMid = nullptr; static lv
|
||||
static const uint16_t CHART_WIN_MIN[4] = { 2, 10, 30, 60 }; // waehlbare Fenster (Minuten)
|
||||
#define CHART_HIST_MAX 3600 // Historie: 60 min à 1 s
|
||||
#define CHART_HIST_NONE INT16_MIN // Markierung "keine Probe"
|
||||
static int16_t g_histW[CHART_HIST_MAX]; // Zehntelgrad
|
||||
static int16_t g_histD[CHART_HIST_MAX];
|
||||
static int16_t g_histC[CHART_HIST_MAX];
|
||||
static uint8_t g_histDutyW[CHART_HIST_MAX]; // Heizleistung (%)
|
||||
static uint8_t g_histDutyD[CHART_HIST_MAX];
|
||||
// Die ~29 KB Historie liegen im PSRAM (heap_caps_malloc in ui_init, wie die LVGL-
|
||||
// Framebuffer) - als statische Arrays wuerden sie den knappen internen RAM sprengen
|
||||
// (Board-Limit war vor diesem Feature bereits zu ~98 % belegt).
|
||||
struct ChartHist {
|
||||
int16_t w[CHART_HIST_MAX]; // Wasser (Zehntelgrad)
|
||||
int16_t d[CHART_HIST_MAX]; // Dampf (Zehntelgrad)
|
||||
int16_t c[CHART_HIST_MAX]; // Zusatzsensor (Zehntelgrad; CHART_HIST_NONE = aus)
|
||||
uint8_t dutyW[CHART_HIST_MAX]; // Heizleistung Wasser (%)
|
||||
uint8_t dutyD[CHART_HIST_MAX]; // Heizleistung Dampf (%)
|
||||
};
|
||||
static ChartHist* g_hist = nullptr;
|
||||
static uint16_t g_histPos = 0, g_histFill = 0;
|
||||
static uint8_t g_chartWin = 0; // Index in CHART_WIN_MIN (P4-lokal in NVS, "chartwin")
|
||||
static bool g_chartDuty = false; // Heizleistung als Zusatzkurven (NVS "chartduty")
|
||||
@@ -1471,7 +1478,7 @@ static void build_chart(lv_obj_t* p) {
|
||||
// Y-Achse ueber das sichtbare Fenster (Werte < 30 Grad = kalter/inaktiver Sensor werden
|
||||
// fuer die Skala ignoriert) und positioniert die gestrichelten Soll-Linien.
|
||||
static void chart_redraw() {
|
||||
if (!g_chart) return;
|
||||
if (!g_chart || !g_hist) return;
|
||||
const int stride = (int)CHART_WIN_MIN[g_chartWin] * 60 / 120; // Sekunden je Chart-Punkt
|
||||
int32_t lo = INT32_MAX, hi = INT32_MIN; // Zehntelgrad
|
||||
bool anyW = false, anyD = false;
|
||||
@@ -1482,11 +1489,11 @@ static void chart_redraw() {
|
||||
if (age < (int)g_histFill) {
|
||||
int idx = (int)g_histPos - 1 - age;
|
||||
if (idx < 0) idx += CHART_HIST_MAX;
|
||||
vW = g_histW[idx];
|
||||
vD = g_histD[idx];
|
||||
if (g_histC[idx] != CHART_HIST_NONE) vC = g_histC[idx];
|
||||
dW = g_histDutyW[idx];
|
||||
dD = g_histDutyD[idx];
|
||||
vW = g_hist->w[idx];
|
||||
vD = g_hist->d[idx];
|
||||
if (g_hist->c[idx] != CHART_HIST_NONE) vC = g_hist->c[idx];
|
||||
dW = g_hist->dutyW[idx];
|
||||
dD = g_hist->dutyD[idx];
|
||||
if (vW > 300) { anyW = true; if (vW < lo) lo = vW; if (vW > hi) hi = vW; }
|
||||
if (vD > 300) { anyD = true; if (vD < lo) lo = vD; if (vD > hi) hi = vD; }
|
||||
if (vC != LV_CHART_POINT_NONE && vC > 300) { if (vC < lo) lo = vC; if (vC > hi) hi = vC; }
|
||||
@@ -1540,15 +1547,15 @@ static void chart_redraw() {
|
||||
lv_chart_refresh(g_chart);
|
||||
}
|
||||
static void chart_sample_cb(lv_timer_t*) {
|
||||
if (!g_chart) return;
|
||||
if (!g_chart || !g_hist) return;
|
||||
// 1-s-Probe in die 60-min-Historie (Ringpuffer); Anzeige zeichnet chart_redraw
|
||||
bool caseOn = g_state.caseSensorEnabled && g_state.hasCaseTemp;
|
||||
g_histW[g_histPos] = (int16_t)(g_state.tempW * 10.0f + 0.5f);
|
||||
g_histD[g_histPos] = (int16_t)(g_state.tempD * 10.0f + 0.5f);
|
||||
g_histC[g_histPos] = caseOn ? (int16_t)(g_state.caseTemp * 10.0f + 0.5f) : CHART_HIST_NONE;
|
||||
g_hist->w[g_histPos] = (int16_t)(g_state.tempW * 10.0f + 0.5f);
|
||||
g_hist->d[g_histPos] = (int16_t)(g_state.tempD * 10.0f + 0.5f);
|
||||
g_hist->c[g_histPos] = caseOn ? (int16_t)(g_state.caseTemp * 10.0f + 0.5f) : CHART_HIST_NONE;
|
||||
float dw = g_state.dutyW, dd = g_state.dutyD;
|
||||
g_histDutyW[g_histPos] = (uint8_t)(dw < 0.0f ? 0 : (dw > 100.0f ? 100 : (int)(dw + 0.5f)));
|
||||
g_histDutyD[g_histPos] = (uint8_t)(dd < 0.0f ? 0 : (dd > 100.0f ? 100 : (int)(dd + 0.5f)));
|
||||
g_hist->dutyW[g_histPos] = (uint8_t)(dw < 0.0f ? 0 : (dw > 100.0f ? 100 : (int)(dw + 0.5f)));
|
||||
g_hist->dutyD[g_histPos] = (uint8_t)(dd < 0.0f ? 0 : (dd > 100.0f ? 100 : (int)(dd + 0.5f)));
|
||||
g_histPos = (uint16_t)((g_histPos + 1) % CHART_HIST_MAX);
|
||||
if (g_histFill < CHART_HIST_MAX) g_histFill++;
|
||||
|
||||
@@ -2789,6 +2796,13 @@ void ui_init(ProtocolClient* client) {
|
||||
g_client = client;
|
||||
|
||||
// Gespeicherte Darstellungs-Einstellungen laden (P4-lokal; Design-Standard: Rundinstrumente)
|
||||
// Verlaufs-Historie (60 min à 1 s, ~29 KB) im PSRAM anlegen - wie die LVGL-Framebuffer.
|
||||
// Schlaegt die Allokation fehl, bleibt das Chart schlicht leer (alle Zugriffe geprueft).
|
||||
if (!g_hist) {
|
||||
g_hist = (ChartHist*)heap_caps_malloc(sizeof(ChartHist), MALLOC_CAP_SPIRAM);
|
||||
if (!g_hist) g_hist = (ChartHist*)heap_caps_malloc(sizeof(ChartHist), MALLOC_CAP_8BIT);
|
||||
}
|
||||
|
||||
{ Preferences prefs; prefs.begin("ui", false);
|
||||
g_tempDesign = prefs.getUChar("tempdsgn", TD_GAUGE);
|
||||
g_brewLiveEnabled = prefs.getBool("brewlive", true);
|
||||
|
||||
Reference in New Issue
Block a user