reworked String Handling of Enums
This commit is contained in:
@@ -68,6 +68,7 @@
|
|||||||
// -> 6.90µl / Pulse
|
// -> 6.90µl / Pulse
|
||||||
#define DEFAULT_PUMP_DOSE 7
|
#define DEFAULT_PUMP_DOSE 7
|
||||||
|
|
||||||
|
// --- System status enum with sentinel ---
|
||||||
typedef enum eSystem_Status
|
typedef enum eSystem_Status
|
||||||
{
|
{
|
||||||
sysStat_Startup,
|
sysStat_Startup,
|
||||||
@@ -76,7 +77,8 @@ typedef enum eSystem_Status
|
|||||||
sysStat_Wash,
|
sysStat_Wash,
|
||||||
sysStat_Purge,
|
sysStat_Purge,
|
||||||
sysStat_Error,
|
sysStat_Error,
|
||||||
sysStat_Shutdown
|
sysStat_Shutdown,
|
||||||
|
SYSSTAT_COUNT // <- sentinel (must be last)
|
||||||
} tSystem_Status;
|
} tSystem_Status;
|
||||||
|
|
||||||
// Enum for different sources of speed input
|
// Enum for different sources of speed input
|
||||||
@@ -89,13 +91,10 @@ typedef enum SpeedSource_e
|
|||||||
SOURCE_GPS,
|
SOURCE_GPS,
|
||||||
SOURCE_CAN,
|
SOURCE_CAN,
|
||||||
SOURCE_OBD2_KLINE,
|
SOURCE_OBD2_KLINE,
|
||||||
SOURCE_OBD2_CAN
|
SOURCE_OBD2_CAN,
|
||||||
|
SPEEDSOURCE_COUNT // <- sentinel (must be last)
|
||||||
} SpeedSource_t;
|
} SpeedSource_t;
|
||||||
|
|
||||||
// String representation of SpeedSource enum
|
|
||||||
extern const char *SpeedSourceString[];
|
|
||||||
extern const size_t SpeedSourceString_Elements;
|
|
||||||
|
|
||||||
// Enum for GPS baud rates
|
// Enum for GPS baud rates
|
||||||
typedef enum GPSBaudRate_e
|
typedef enum GPSBaudRate_e
|
||||||
{
|
{
|
||||||
@@ -104,23 +103,29 @@ typedef enum GPSBaudRate_e
|
|||||||
BAUD_19200,
|
BAUD_19200,
|
||||||
BAUD_38400,
|
BAUD_38400,
|
||||||
BAUD_57600,
|
BAUD_57600,
|
||||||
BAUD_115200
|
BAUD_115200,
|
||||||
|
GPSBAUDRATE_COUNT // <- sentinel (must be last)
|
||||||
} GPSBaudRate_t;
|
} GPSBaudRate_t;
|
||||||
|
|
||||||
// String representation of GPSBaudRate enum
|
|
||||||
extern const char *GPSBaudRateString[];
|
|
||||||
extern const size_t GPSBaudRateString_Elements;
|
|
||||||
|
|
||||||
// Enum for CAN bus sources
|
// Enum for CAN bus sources
|
||||||
typedef enum CANSource_e
|
typedef enum CANSource_e
|
||||||
{
|
{
|
||||||
KTM_890_ADV_R_2021,
|
KTM_890_ADV_R_2021,
|
||||||
KTM_1290_SD_R_2023
|
KTM_1290_SD_R_2023,
|
||||||
|
CANSOURCE_COUNT // <- sentinel (must be last)
|
||||||
} CANSource_t;
|
} CANSource_t;
|
||||||
|
|
||||||
// String representation of CANSource enum
|
// String tables (kept internal to the module)
|
||||||
extern const char *CANSourceString[];
|
extern const char * const SystemStatusString[SYSSTAT_COUNT];
|
||||||
extern const size_t CANSourceString_Elements;
|
extern const char * const SpeedSourceString[SPEEDSOURCE_COUNT];
|
||||||
|
extern const char * const GPSBaudRateString[GPSBAUDRATE_COUNT];
|
||||||
|
extern const char * const CANSourceString[CANSOURCE_COUNT];
|
||||||
|
|
||||||
|
// Safe getters (centralized bounds check)
|
||||||
|
const char* ToString(SpeedSource_t v);
|
||||||
|
const char* ToString(GPSBaudRate_t v);
|
||||||
|
const char* ToString(CANSource_t v);
|
||||||
|
const char* ToString(tSystem_Status v);
|
||||||
|
|
||||||
#define STARTUP_DELAY 2500
|
#define STARTUP_DELAY 2500
|
||||||
#define SHUTDOWN_DELAY_MS 2500
|
#define SHUTDOWN_DELAY_MS 2500
|
||||||
|
@@ -22,7 +22,6 @@ typedef struct Globals_s
|
|||||||
{
|
{
|
||||||
tSystem_Status systemStatus = sysStat_Startup; /**< Current system status */
|
tSystem_Status systemStatus = sysStat_Startup; /**< Current system status */
|
||||||
tSystem_Status resumeStatus = sysStat_Startup; /**< Status to resume after rain mode */
|
tSystem_Status resumeStatus = sysStat_Startup; /**< Status to resume after rain mode */
|
||||||
char systemStatustxt[16] = ""; /**< Text representation of system status */
|
|
||||||
uint16_t purgePulses = 0; /**< Number of purge pulses */
|
uint16_t purgePulses = 0; /**< Number of purge pulses */
|
||||||
EERequest_t requestEEAction = EE_IDLE; /**< EEPROM-related request */
|
EERequest_t requestEEAction = EE_IDLE; /**< EEPROM-related request */
|
||||||
char DeviceName[33]; /**< Device name */
|
char DeviceName[33]; /**< Device name */
|
||||||
|
@@ -1,7 +1,20 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
static const char kUnknownStr[] = "Unknown";
|
||||||
|
|
||||||
|
// ---- System status string table ----
|
||||||
|
const char *const SystemStatusString[SYSSTAT_COUNT] = {
|
||||||
|
"Startup",
|
||||||
|
"Normal",
|
||||||
|
"Rain",
|
||||||
|
"Wash",
|
||||||
|
"Purge",
|
||||||
|
"Error",
|
||||||
|
"Shutdown",
|
||||||
|
};
|
||||||
|
|
||||||
// String representation of SpeedSource enum
|
// String representation of SpeedSource enum
|
||||||
const char *SpeedSourceString[] = {
|
const char *const SpeedSourceString[SPEEDSOURCE_COUNT] = {
|
||||||
#ifdef FEATURE_ENABLE_TIMER
|
#ifdef FEATURE_ENABLE_TIMER
|
||||||
"Timer",
|
"Timer",
|
||||||
#endif
|
#endif
|
||||||
@@ -12,10 +25,8 @@ const char *SpeedSourceString[] = {
|
|||||||
"OBD2 (CAN)",
|
"OBD2 (CAN)",
|
||||||
};
|
};
|
||||||
|
|
||||||
const size_t SpeedSourceString_Elements = sizeof(SpeedSourceString) / sizeof(SpeedSourceString[0]);
|
|
||||||
|
|
||||||
// String representation of GPSBaudRate enum
|
// String representation of GPSBaudRate enum
|
||||||
const char *GPSBaudRateString[] = {
|
const char *const GPSBaudRateString[GPSBAUDRATE_COUNT] = {
|
||||||
"4800",
|
"4800",
|
||||||
"9600",
|
"9600",
|
||||||
"19200",
|
"19200",
|
||||||
@@ -24,12 +35,49 @@ const char *GPSBaudRateString[] = {
|
|||||||
"115200",
|
"115200",
|
||||||
};
|
};
|
||||||
|
|
||||||
const size_t GPSBaudRateString_Elements = sizeof(GPSBaudRateString) / sizeof(GPSBaudRateString[0]);
|
|
||||||
|
|
||||||
// String representation of CANSource enum
|
// String representation of CANSource enum
|
||||||
const char *CANSourceString[] = {
|
const char *const CANSourceString[CANSOURCE_COUNT] = {
|
||||||
"KTM 890 Adventure R (2021)",
|
"KTM 890 Adventure R (2021)",
|
||||||
"KTM 1290 Superduke R (2023)",
|
"KTM 1290 Superduke R (2023)",
|
||||||
};
|
};
|
||||||
|
|
||||||
const size_t CANSourceString_Elements = sizeof(CANSourceString) / sizeof(CANSourceString[0]);
|
// ---- Centralized, safe getters ----
|
||||||
|
|
||||||
|
// ---- Local helper for range check ----
|
||||||
|
static inline bool in_range(int v, int max_exclusive)
|
||||||
|
{
|
||||||
|
return (v >= 0) && (v < max_exclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Safe getter ----
|
||||||
|
const char *ToString(tSystem_Status v)
|
||||||
|
{
|
||||||
|
const int i = static_cast<int>(v);
|
||||||
|
return in_range(i, static_cast<int>(SYSSTAT_COUNT))
|
||||||
|
? SystemStatusString[i]
|
||||||
|
: kUnknownStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ToString(SpeedSource_t v)
|
||||||
|
{
|
||||||
|
const int i = static_cast<int>(v);
|
||||||
|
return in_range(i, static_cast<int>(SPEEDSOURCE_COUNT))
|
||||||
|
? SpeedSourceString[i]
|
||||||
|
: kUnknownStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ToString(GPSBaudRate_t v)
|
||||||
|
{
|
||||||
|
const int i = static_cast<int>(v);
|
||||||
|
return in_range(i, static_cast<int>(GPSBAUDRATE_COUNT))
|
||||||
|
? GPSBaudRateString[i]
|
||||||
|
: kUnknownStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ToString(CANSource_t v)
|
||||||
|
{
|
||||||
|
const int i = static_cast<int>(v);
|
||||||
|
return in_range(i, static_cast<int>(CANSOURCE_COUNT))
|
||||||
|
? CANSourceString[i]
|
||||||
|
: kUnknownStr;
|
||||||
|
}
|
||||||
|
@@ -615,21 +615,21 @@ uint32_t ConfigSanityCheck(bool autocorrect)
|
|||||||
LubeConfig.BleedingPulses = LubeConfig_defaults.BleedingPulses;
|
LubeConfig.BleedingPulses = LubeConfig_defaults.BleedingPulses;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(LubeConfig.SpeedSource >= 0) || !(LubeConfig.SpeedSource < SpeedSourceString_Elements))
|
if (!(LubeConfig.SpeedSource >= 0) || !(LubeConfig.SpeedSource < SPEEDSOURCE_COUNT))
|
||||||
{
|
{
|
||||||
SET_BIT(setting_reset_bits, 11);
|
SET_BIT(setting_reset_bits, 11);
|
||||||
if (autocorrect)
|
if (autocorrect)
|
||||||
LubeConfig.SpeedSource = LubeConfig_defaults.SpeedSource;
|
LubeConfig.SpeedSource = LubeConfig_defaults.SpeedSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(LubeConfig.GPSBaudRate >= 0) || !(LubeConfig.GPSBaudRate < GPSBaudRateString_Elements))
|
if (!(LubeConfig.GPSBaudRate >= 0) || !(LubeConfig.GPSBaudRate < GPSBAUDRATE_COUNT))
|
||||||
{
|
{
|
||||||
SET_BIT(setting_reset_bits, 12);
|
SET_BIT(setting_reset_bits, 12);
|
||||||
if (autocorrect)
|
if (autocorrect)
|
||||||
LubeConfig.GPSBaudRate = LubeConfig_defaults.GPSBaudRate;
|
LubeConfig.GPSBaudRate = LubeConfig_defaults.GPSBaudRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(LubeConfig.CANSource >= 0) || !(LubeConfig.CANSource < CANSourceString_Elements))
|
if (!(LubeConfig.CANSource >= 0) || !(LubeConfig.CANSource < CANSOURCE_COUNT))
|
||||||
{
|
{
|
||||||
SET_BIT(setting_reset_bits, 13);
|
SET_BIT(setting_reset_bits, 13);
|
||||||
if (autocorrect)
|
if (autocorrect)
|
||||||
|
@@ -459,7 +459,6 @@ void Debug_dumpGlobals()
|
|||||||
{
|
{
|
||||||
Debug_pushMessage("systemStatus: %d\n", globals.systemStatus);
|
Debug_pushMessage("systemStatus: %d\n", globals.systemStatus);
|
||||||
Debug_pushMessage("resumeStatus: %d\n", globals.resumeStatus);
|
Debug_pushMessage("resumeStatus: %d\n", globals.resumeStatus);
|
||||||
Debug_pushMessage("systemStatustxt: %s\n", globals.systemStatustxt);
|
|
||||||
Debug_pushMessage("purgePulses: %d\n", globals.purgePulses);
|
Debug_pushMessage("purgePulses: %d\n", globals.purgePulses);
|
||||||
Debug_pushMessage("requestEEAction: %d\n", globals.requestEEAction);
|
Debug_pushMessage("requestEEAction: %d\n", globals.requestEEAction);
|
||||||
Debug_pushMessage("DeviceName: %s\n", globals.DeviceName);
|
Debug_pushMessage("DeviceName: %s\n", globals.DeviceName);
|
||||||
|
@@ -56,7 +56,6 @@ void RunLubeApp(uint32_t add_milimeters)
|
|||||||
|
|
||||||
if (lastSystemStatus != globals.systemStatus)
|
if (lastSystemStatus != globals.systemStatus)
|
||||||
{
|
{
|
||||||
strcpy_P(globals.systemStatustxt, PSTR("Startup"));
|
|
||||||
LEDControl_SetBasic(LED_STARTUP_NORMAL, LED_PATTERN_BLINK);
|
LEDControl_SetBasic(LED_STARTUP_NORMAL, LED_PATTERN_BLINK);
|
||||||
lastSystemStatus = globals.systemStatus;
|
lastSystemStatus = globals.systemStatus;
|
||||||
globals.resumeStatus = sysStat_Startup;
|
globals.resumeStatus = sysStat_Startup;
|
||||||
@@ -72,7 +71,6 @@ void RunLubeApp(uint32_t add_milimeters)
|
|||||||
case sysStat_Normal:
|
case sysStat_Normal:
|
||||||
if (lastSystemStatus != globals.systemStatus)
|
if (lastSystemStatus != globals.systemStatus)
|
||||||
{
|
{
|
||||||
strcpy_P(globals.systemStatustxt, PSTR("Normal"));
|
|
||||||
LEDControl_SetBasic(LED_NORMAL_COLOR, LED_PATTERN_ON);
|
LEDControl_SetBasic(LED_NORMAL_COLOR, LED_PATTERN_ON);
|
||||||
lastSystemStatus = globals.systemStatus;
|
lastSystemStatus = globals.systemStatus;
|
||||||
globals.resumeStatus = sysStat_Normal;
|
globals.resumeStatus = sysStat_Normal;
|
||||||
@@ -89,7 +87,6 @@ void RunLubeApp(uint32_t add_milimeters)
|
|||||||
case sysStat_Rain:
|
case sysStat_Rain:
|
||||||
if (lastSystemStatus != globals.systemStatus)
|
if (lastSystemStatus != globals.systemStatus)
|
||||||
{
|
{
|
||||||
strcpy_P(globals.systemStatustxt, PSTR("Rain"));
|
|
||||||
LEDControl_SetBasic(LED_RAIN_COLOR, LED_PATTERN_ON);
|
LEDControl_SetBasic(LED_RAIN_COLOR, LED_PATTERN_ON);
|
||||||
lastSystemStatus = globals.systemStatus;
|
lastSystemStatus = globals.systemStatus;
|
||||||
globals.resumeStatus = sysStat_Rain;
|
globals.resumeStatus = sysStat_Rain;
|
||||||
@@ -107,7 +104,6 @@ void RunLubeApp(uint32_t add_milimeters)
|
|||||||
if (lastSystemStatus != globals.systemStatus)
|
if (lastSystemStatus != globals.systemStatus)
|
||||||
{
|
{
|
||||||
washModeRemainDistance = LubeConfig.WashMode_Distance;
|
washModeRemainDistance = LubeConfig.WashMode_Distance;
|
||||||
strcpy_P(globals.systemStatustxt, PSTR("Wash"));
|
|
||||||
LEDControl_SetBasic(LED_WASH_COLOR, LED_PATTERN_BREATH);
|
LEDControl_SetBasic(LED_WASH_COLOR, LED_PATTERN_BREATH);
|
||||||
lastSystemStatus = globals.systemStatus;
|
lastSystemStatus = globals.systemStatus;
|
||||||
}
|
}
|
||||||
@@ -134,7 +130,6 @@ void RunLubeApp(uint32_t add_milimeters)
|
|||||||
if (lastSystemStatus != globals.systemStatus)
|
if (lastSystemStatus != globals.systemStatus)
|
||||||
{
|
{
|
||||||
globals.purgePulses = LubeConfig.BleedingPulses;
|
globals.purgePulses = LubeConfig.BleedingPulses;
|
||||||
strcpy_P(globals.systemStatustxt, PSTR("Purge"));
|
|
||||||
LEDControl_SetBasic(LED_PURGE_COLOR, LED_PATTERN_BLINK);
|
LEDControl_SetBasic(LED_PURGE_COLOR, LED_PATTERN_BLINK);
|
||||||
lastSystemStatus = globals.systemStatus;
|
lastSystemStatus = globals.systemStatus;
|
||||||
}
|
}
|
||||||
@@ -161,7 +156,6 @@ void RunLubeApp(uint32_t add_milimeters)
|
|||||||
|
|
||||||
if (lastSystemStatus != globals.systemStatus)
|
if (lastSystemStatus != globals.systemStatus)
|
||||||
{
|
{
|
||||||
strcpy_P(globals.systemStatustxt, PSTR("Error"));
|
|
||||||
LEDControl_SetBasic(LED_ERROR_COLOR, LED_PATTERN_BLINK_FAST);
|
LEDControl_SetBasic(LED_ERROR_COLOR, LED_PATTERN_BLINK_FAST);
|
||||||
lastSystemStatus = globals.systemStatus;
|
lastSystemStatus = globals.systemStatus;
|
||||||
}
|
}
|
||||||
@@ -173,7 +167,6 @@ void RunLubeApp(uint32_t add_milimeters)
|
|||||||
|
|
||||||
if (lastSystemStatus != globals.systemStatus)
|
if (lastSystemStatus != globals.systemStatus)
|
||||||
{
|
{
|
||||||
strcpy_P(globals.systemStatustxt, PSTR("Shutdown"));
|
|
||||||
LEDControl_SetBasic(LED_SHUTDOWN_COLOR, LED_PATTERN_BREATH_REVERSE);
|
LEDControl_SetBasic(LED_SHUTDOWN_COLOR, LED_PATTERN_BREATH_REVERSE);
|
||||||
lastSystemStatus = globals.systemStatus;
|
lastSystemStatus = globals.systemStatus;
|
||||||
}
|
}
|
||||||
|
@@ -398,7 +398,7 @@ void Display_Process()
|
|||||||
DistRemain = DistRemain - (PersistenceData.TravelDistance_highRes_mm / 1000);
|
DistRemain = DistRemain - (PersistenceData.TravelDistance_highRes_mm / 1000);
|
||||||
|
|
||||||
// Display relevant information on the OLED screen based on system status
|
// Display relevant information on the OLED screen based on system status
|
||||||
u8x8.printf(PSTR("Mode: %10s\n"), globals.systemStatustxt);
|
u8x8.printf(PSTR("Mode: %10s\n"), ToString(globals.systemStatus));
|
||||||
if (globals.systemStatus == sysStat_Error)
|
if (globals.systemStatus == sysStat_Error)
|
||||||
{
|
{
|
||||||
// Display the last Diagnostic Trouble Code (DTC) in case of an error
|
// Display the last Diagnostic Trouble Code (DTC) in case of an error
|
||||||
@@ -412,7 +412,8 @@ void Display_Process()
|
|||||||
u8x8.printf(PSTR("WiFi: %10s\n"), (WiFi.getMode() == WIFI_AP ? "AP" : WiFi.getMode() == WIFI_OFF ? "OFF"
|
u8x8.printf(PSTR("WiFi: %10s\n"), (WiFi.getMode() == WIFI_AP ? "AP" : WiFi.getMode() == WIFI_OFF ? "OFF"
|
||||||
: WiFi.getMode() == WIFI_STA ? "CLIENT"
|
: WiFi.getMode() == WIFI_STA ? "CLIENT"
|
||||||
: "UNKNOWN"));
|
: "UNKNOWN"));
|
||||||
u8x8.printf(PSTR("Source: %8s\n"), SpeedSourceString[LubeConfig.SpeedSource]);
|
u8x8.printf(PSTR("Source: %8s\n"), ToString(LubeConfig.SpeedSource));
|
||||||
|
|
||||||
u8x8.printf("%s\n", WiFi.localIP().toString().c_str());
|
u8x8.printf("%s\n", WiFi.localIP().toString().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -337,89 +337,145 @@ void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const Stri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void WebserverEERestore_Callback(AsyncWebServerRequest *request,
|
||||||
/**
|
const String &filename,
|
||||||
* @brief Callback function for handling EEPROM restore via the web server.
|
size_t index,
|
||||||
*
|
uint8_t *data,
|
||||||
* This function is invoked during the EEPROM restore process when a new EEPROM file
|
size_t len,
|
||||||
* is received. It handles the restore process by reading the data from the received file,
|
bool final)
|
||||||
* deserializing the JSON data, and updating the configuration and persistence data accordingly.
|
|
||||||
* If the restore is successful, it triggers a system shutdown.
|
|
||||||
*
|
|
||||||
* @param request Pointer to the AsyncWebServerRequest object.
|
|
||||||
* @param filename The name of the file being restored.
|
|
||||||
* @param index The index of the file being restored.
|
|
||||||
* @param data Pointer to the data buffer.
|
|
||||||
* @param len The length of the data buffer.
|
|
||||||
* @param final Boolean indicating if this is the final chunk of data.
|
|
||||||
*/
|
|
||||||
void WebserverEERestore_Callback(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final)
|
|
||||||
{
|
{
|
||||||
|
constexpr size_t kBufCap = 1536;
|
||||||
|
|
||||||
bool ee_done = false;
|
bool ee_done = false;
|
||||||
static bool validext = false;
|
static bool validext = false;
|
||||||
static char *buffer = NULL;
|
static char *buffer = nullptr;
|
||||||
static uint32_t read_ptr = 0;
|
static uint32_t read_ptr = 0;
|
||||||
DeserializationError error;
|
DeserializationError error;
|
||||||
|
|
||||||
|
// kleines Helferlein zum sicheren Kopieren & Terminieren
|
||||||
|
auto safe_copy = [](char *dst, size_t dst_sz, const char *src)
|
||||||
|
{
|
||||||
|
if (!dst || dst_sz == 0)
|
||||||
|
return;
|
||||||
|
if (!src)
|
||||||
|
{
|
||||||
|
dst[0] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strncpy(dst, src, dst_sz - 1);
|
||||||
|
dst[dst_sz - 1] = '\0';
|
||||||
|
};
|
||||||
|
|
||||||
|
// Grenzen/Hilfen für Enum-Ranges (Sentinel bevorzugt, sonst *_Elements)
|
||||||
|
const int maxSpeedSrc = static_cast<int>(SPEEDSOURCE_COUNT);
|
||||||
|
const int maxGPSBaud = static_cast<int>(GPSBAUDRATE_COUNT);
|
||||||
|
const int maxCANSrc = static_cast<int>(CANSOURCE_COUNT);
|
||||||
|
|
||||||
if (!index)
|
if (!index)
|
||||||
{
|
{
|
||||||
validext = (filename.indexOf(".ee.json") > -1);
|
validext = (filename.indexOf(".ee.json") > -1);
|
||||||
if (validext)
|
if (validext)
|
||||||
{
|
{
|
||||||
buffer = (char *)malloc(1536);
|
buffer = (char *)malloc(kBufCap);
|
||||||
read_ptr = 0;
|
read_ptr = 0;
|
||||||
if (buffer == NULL)
|
if (!buffer)
|
||||||
|
{
|
||||||
Debug_pushMessage("malloc() failed for EEPROM-Restore\n");
|
Debug_pushMessage("malloc() failed for EEPROM-Restore\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer != NULL && len > 0)
|
// Chunked receive mit Cap/Trunkierungsschutz
|
||||||
|
if (buffer && len > 0)
|
||||||
{
|
{
|
||||||
memcpy(buffer + read_ptr, data, len);
|
size_t remain = (read_ptr < kBufCap) ? (kBufCap - read_ptr) : 0;
|
||||||
read_ptr = read_ptr + len;
|
size_t to_copy = (len <= remain) ? len : remain;
|
||||||
|
if (to_copy > 0)
|
||||||
|
{
|
||||||
|
memcpy(buffer + read_ptr, data, to_copy);
|
||||||
|
read_ptr += to_copy;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug_pushMessage("EEPROM-Restore input exceeds buffer, truncating\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (final)
|
if (final)
|
||||||
{
|
{
|
||||||
if (buffer != NULL)
|
if (buffer)
|
||||||
{
|
{
|
||||||
// Ensure zero-termination just in case
|
// Null-terminieren
|
||||||
if (read_ptr >= 1536)
|
if (read_ptr == kBufCap)
|
||||||
read_ptr = 1535;
|
read_ptr = kBufCap - 1;
|
||||||
buffer[read_ptr] = '\0';
|
buffer[read_ptr] = '\0';
|
||||||
|
|
||||||
Serial.print(buffer);
|
// Parse
|
||||||
JsonDocument json;
|
JsonDocument json; // entspricht deinem bisherigen Stil
|
||||||
error = deserializeJson(json, buffer);
|
error = deserializeJson(json, buffer);
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
Debug_pushMessage("deserializeJson() failed: %s\n", error.f_str());
|
Debug_pushMessage("deserializeJson() failed: %s\n", error.f_str());
|
||||||
}
|
}
|
||||||
else
|
else if (validext)
|
||||||
{
|
{
|
||||||
|
// ---- Konfiguration sicher in RAM übernehmen ----
|
||||||
|
// clamp-Helfer passend zu deinen Sanity-Grenzen
|
||||||
|
auto clamp_u32 = [](uint32_t v, uint32_t lo, uint32_t hi)
|
||||||
|
{ return (v < lo) ? lo : (v > hi ? hi : v); };
|
||||||
|
auto clamp_u16 = [](uint16_t v, uint16_t lo, uint16_t hi)
|
||||||
|
{ return (v < lo) ? lo : (v > hi ? hi : v); };
|
||||||
|
auto clamp_u8 = [](uint8_t v, uint8_t lo, uint8_t hi)
|
||||||
|
{ return (v < lo) ? lo : (v > hi ? hi : v); };
|
||||||
|
|
||||||
LubeConfig.DistancePerLube_Default = json["config"]["DistancePerLube_Default"].as<uint32_t>();
|
// config.*
|
||||||
LubeConfig.DistancePerLube_Rain = json["config"]["DistancePerLube_Rain"].as<uint32_t>();
|
LubeConfig.DistancePerLube_Default = clamp_u32(json["config"]["DistancePerLube_Default"].as<uint32_t>(), 0, 50000);
|
||||||
LubeConfig.tankCapacity_ml = json["config"]["tankCapacity_ml"].as<uint32_t>();
|
LubeConfig.DistancePerLube_Rain = clamp_u32(json["config"]["DistancePerLube_Rain"].as<uint32_t>(), 0, 50000);
|
||||||
LubeConfig.amountPerDose_microL = json["config"]["amountPerDose_microL"].as<uint32_t>();
|
LubeConfig.tankCapacity_ml = clamp_u32(json["config"]["tankCapacity_ml"].as<uint32_t>(), 0, 5000);
|
||||||
LubeConfig.TankRemindAtPercentage = json["config"]["TankRemindAtPercentage"].as<uint8_t>();
|
LubeConfig.amountPerDose_microL = clamp_u32(json["config"]["amountPerDose_microL"].as<uint32_t>(), 0, 100);
|
||||||
LubeConfig.PulsePerRevolution = json["config"]["PulsePerRevolution"].as<uint8_t>();
|
LubeConfig.TankRemindAtPercentage = clamp_u8(json["config"]["TankRemindAtPercentage"].as<uint8_t>(), 0, 100);
|
||||||
LubeConfig.TireWidth_mm = json["config"]["TireWidth_mm"].as<uint32_t>();
|
LubeConfig.PulsePerRevolution = clamp_u8(json["config"]["PulsePerRevolution"].as<uint8_t>(), 0, 255);
|
||||||
LubeConfig.TireWidthHeight_Ratio = json["config"]["TireWidthHeight_Ratio"].as<uint32_t>();
|
LubeConfig.TireWidth_mm = clamp_u32(json["config"]["TireWidth_mm"].as<uint32_t>(), 0, 500);
|
||||||
LubeConfig.RimDiameter_Inch = json["config"]["RimDiameter_Inch"].as<uint32_t>();
|
LubeConfig.TireWidthHeight_Ratio = clamp_u32(json["config"]["TireWidthHeight_Ratio"].as<uint32_t>(), 0, 150);
|
||||||
LubeConfig.DistancePerRevolution_mm = json["config"]["DistancePerRevolution_mm"].as<uint32_t>();
|
LubeConfig.RimDiameter_Inch = clamp_u32(json["config"]["RimDiameter_Inch"].as<uint32_t>(), 0, 30);
|
||||||
LubeConfig.BleedingPulses = json["config"]["BleedingPulses"].as<uint16_t>();
|
LubeConfig.DistancePerRevolution_mm = clamp_u32(json["config"]["DistancePerRevolution_mm"].as<uint32_t>(), 0, 10000);
|
||||||
LubeConfig.SpeedSource = (SpeedSource_t)json["config"]["SpeedSource"].as<int>();
|
LubeConfig.BleedingPulses = clamp_u16(json["config"]["BleedingPulses"].as<uint16_t>(), 0, 1000);
|
||||||
LubeConfig.GPSBaudRate = (GPSBaudRate_t)json["config"]["GPSBaudRate"].as<int>();
|
LubeConfig.WashMode_Distance = json["config"]["WashMode_Distance"].as<uint16_t>(); // ggf. Grenzen anpassen
|
||||||
LubeConfig.CANSource = (CANSource_t)json["config"]["CANSource"].as<int>();
|
LubeConfig.WashMode_Interval = json["config"]["WashMode_Interval"].as<uint16_t>(); // ggf. Grenzen anpassen
|
||||||
LubeConfig.LED_Mode_Flash = json["config"]["LED_Mode_Flash"].as<bool>();
|
LubeConfig.LED_Mode_Flash = json["config"]["LED_Mode_Flash"].as<bool>();
|
||||||
LubeConfig.LED_Max_Brightness = json["config"]["LED_Max_Brightness"].as<uint8_t>();
|
LubeConfig.LED_Max_Brightness = json["config"]["LED_Max_Brightness"].as<uint8_t>();
|
||||||
LubeConfig.LED_Min_Brightness = json["config"]["LED_Min_Brightness"].as<uint8_t>();
|
LubeConfig.LED_Min_Brightness = json["config"]["LED_Min_Brightness"].as<uint8_t>();
|
||||||
strncpy(LubeConfig.wifi_ap_ssid, json["config"]["wifi_ap_ssid"].as<const char *>(), sizeof(LubeConfig.wifi_ap_ssid));
|
|
||||||
strncpy(LubeConfig.wifi_ap_password, json["config"]["wifi_ap_password"].as<const char *>(), sizeof(LubeConfig.wifi_ap_password));
|
|
||||||
strncpy(LubeConfig.wifi_client_ssid, json["config"]["wifi_client_ssid"].as<const char *>(), sizeof(LubeConfig.wifi_client_ssid));
|
|
||||||
strncpy(LubeConfig.wifi_client_password, json["config"]["wifi_client_password"].as<const char *>(), sizeof(LubeConfig.wifi_client_password));
|
|
||||||
|
|
||||||
|
// Enums nur nach Range-Check übernehmen
|
||||||
|
{
|
||||||
|
int v = json["config"]["SpeedSource"].as<int>();
|
||||||
|
if (v >= 0 && v < maxSpeedSrc)
|
||||||
|
LubeConfig.SpeedSource = (SpeedSource_t)v;
|
||||||
|
else
|
||||||
|
Debug_pushMessage("Restore: invalid SpeedSource=%d\n", v);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int v = json["config"]["GPSBaudRate"].as<int>();
|
||||||
|
if (v >= 0 && v < maxGPSBaud)
|
||||||
|
LubeConfig.GPSBaudRate = (GPSBaudRate_t)v;
|
||||||
|
else
|
||||||
|
Debug_pushMessage("Restore: invalid GPSBaudRate=%d\n", v);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int v = json["config"]["CANSource"].as<int>();
|
||||||
|
if (v >= 0 && v < maxCANSrc)
|
||||||
|
LubeConfig.CANSource = (CANSource_t)v;
|
||||||
|
else
|
||||||
|
Debug_pushMessage("Restore: invalid CANSource=%d\n", v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strings sicher kopieren (0-terminiert)
|
||||||
|
safe_copy(LubeConfig.wifi_ap_ssid, sizeof(LubeConfig.wifi_ap_ssid), json["config"]["wifi_ap_ssid"]);
|
||||||
|
safe_copy(LubeConfig.wifi_ap_password, sizeof(LubeConfig.wifi_ap_password), json["config"]["wifi_ap_password"]);
|
||||||
|
safe_copy(LubeConfig.wifi_client_ssid, sizeof(LubeConfig.wifi_client_ssid), json["config"]["wifi_client_ssid"]);
|
||||||
|
safe_copy(LubeConfig.wifi_client_password, sizeof(LubeConfig.wifi_client_password), json["config"]["wifi_client_password"]);
|
||||||
|
|
||||||
|
// persis.*
|
||||||
PersistenceData.writeCycleCounter = json["persis"]["writeCycleCounter"].as<uint16_t>();
|
PersistenceData.writeCycleCounter = json["persis"]["writeCycleCounter"].as<uint16_t>();
|
||||||
PersistenceData.tankRemain_microL = json["persis"]["tankRemain_microL"].as<uint32_t>();
|
PersistenceData.tankRemain_microL = json["persis"]["tankRemain_microL"].as<uint32_t>();
|
||||||
PersistenceData.TravelDistance_highRes_mm = json["persis"]["TravelDistance_highRes_mm"].as<uint32_t>();
|
PersistenceData.TravelDistance_highRes_mm = json["persis"]["TravelDistance_highRes_mm"].as<uint32_t>();
|
||||||
@@ -427,24 +483,33 @@ void WebserverEERestore_Callback(AsyncWebServerRequest *request, const String &f
|
|||||||
PersistenceData.odometer = json["persis"]["odometer"].as<uint32_t>();
|
PersistenceData.odometer = json["persis"]["odometer"].as<uint32_t>();
|
||||||
PersistenceData.checksum = json["persis"]["checksum"].as<uint32_t>();
|
PersistenceData.checksum = json["persis"]["checksum"].as<uint32_t>();
|
||||||
|
|
||||||
|
// Optional: Sanity-Autokorrektur im RAM (keine EEPROM-Writes hier!)
|
||||||
|
{
|
||||||
|
uint32_t sanity = ConfigSanityCheck(true);
|
||||||
|
if (sanity > 0)
|
||||||
|
{
|
||||||
|
MaintainDTC(DTC_EEPROM_CFG_SANITY, true, sanity);
|
||||||
|
Debug_pushMessage("Restore: ConfigSanity corrected (mask=0x%08lX)\n", sanity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ee_done = true;
|
ee_done = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer)
|
|
||||||
{
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
buffer = NULL;
|
buffer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncWebServerResponse *response = request->beginResponse(302, "text/plain", "Please wait while the device reboots");
|
// Browser zurückleiten & ggf. Shutdown
|
||||||
|
AsyncWebServerResponse *response =
|
||||||
|
request->beginResponse(302, "text/plain", "Please wait while the device reboots");
|
||||||
response->addHeader("Refresh", "20");
|
response->addHeader("Refresh", "20");
|
||||||
response->addHeader("Location", "/");
|
response->addHeader("Location", "/");
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|
||||||
if (ee_done)
|
if (ee_done)
|
||||||
{
|
{
|
||||||
Debug_pushMessage("Update complete\n");
|
Debug_pushMessage("EEPROM restore complete\n");
|
||||||
globals.systemStatus = sysStat_Shutdown;
|
globals.systemStatus = sysStat_Shutdown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -648,24 +713,24 @@ void Websocket_HandleSettings(uint8_t *data)
|
|||||||
}
|
}
|
||||||
else if (strcmp(identifier, "speedsource") == 0)
|
else if (strcmp(identifier, "speedsource") == 0)
|
||||||
{
|
{
|
||||||
int index = findIndexByString(value, SpeedSourceString, (int)SpeedSourceString_Elements);
|
int index = findIndexByString(value, SpeedSourceString, (int)SPEEDSOURCE_COUNT);
|
||||||
if (validIndex(index, (int)SpeedSourceString_Elements))
|
if (validIndex(index, (int)SPEEDSOURCE_COUNT))
|
||||||
speedsourcePreselect = (SpeedSource_t)index;
|
speedsourcePreselect = (SpeedSource_t)index;
|
||||||
else
|
else
|
||||||
Debug_pushMessage("Invalid speedsource '%s'\n", value);
|
Debug_pushMessage("Invalid speedsource '%s'\n", value);
|
||||||
}
|
}
|
||||||
else if (strcmp(identifier, "cansource") == 0)
|
else if (strcmp(identifier, "cansource") == 0)
|
||||||
{
|
{
|
||||||
int index = findIndexByString(value, CANSourceString, (int)CANSourceString_Elements);
|
int index = findIndexByString(value, CANSourceString, (int)CANSOURCE_COUNT);
|
||||||
if (validIndex(index, (int)CANSourceString_Elements))
|
if (validIndex(index, (int)CANSOURCE_COUNT))
|
||||||
LubeConfig.CANSource = (CANSource_t)index;
|
LubeConfig.CANSource = (CANSource_t)index;
|
||||||
else
|
else
|
||||||
Debug_pushMessage("Invalid cansource '%s'\n", value);
|
Debug_pushMessage("Invalid cansource '%s'\n", value);
|
||||||
}
|
}
|
||||||
else if (strcmp(identifier, "gpsbaud") == 0)
|
else if (strcmp(identifier, "gpsbaud") == 0)
|
||||||
{
|
{
|
||||||
int index = findIndexByString(value, GPSBaudRateString, (int)GPSBaudRateString_Elements);
|
int index = findIndexByString(value, GPSBaudRateString, (int)GPSBAUDRATE_COUNT);
|
||||||
if (validIndex(index, (int)GPSBaudRateString_Elements))
|
if (validIndex(index, (int)GPSBAUDRATE_COUNT))
|
||||||
LubeConfig.GPSBaudRate = (GPSBaudRate_t)index;
|
LubeConfig.GPSBaudRate = (GPSBaudRate_t)index;
|
||||||
else
|
else
|
||||||
Debug_pushMessage("Invalid gpsbaud '%s'\n", value);
|
Debug_pushMessage("Invalid gpsbaud '%s'\n", value);
|
||||||
@@ -801,7 +866,7 @@ void Websocket_RefreshClientData_Status(uint32_t client_id, bool send_mapping)
|
|||||||
|
|
||||||
String temp = "STATUS:";
|
String temp = "STATUS:";
|
||||||
|
|
||||||
temp.concat(String(nz(globals.systemStatustxt)) + ";");
|
temp.concat(String(ToString(globals.systemStatus)) + ";");
|
||||||
|
|
||||||
// Guard against division by zero (capacity==0)
|
// Guard against division by zero (capacity==0)
|
||||||
uint32_t cap = LubeConfig.tankCapacity_ml;
|
uint32_t cap = LubeConfig.tankCapacity_ml;
|
||||||
@@ -856,26 +921,26 @@ void Websocket_RefreshClientData_Static(uint32_t client_id, bool send_mapping)
|
|||||||
temp += String(LubeConfig.RimDiameter_Inch) + ";";
|
temp += String(LubeConfig.RimDiameter_Inch) + ";";
|
||||||
|
|
||||||
// speedsource + Optionen
|
// speedsource + Optionen
|
||||||
temp += tableStr(SpeedSourceString, (int)LubeConfig.SpeedSource, (int)SpeedSourceString_Elements) + ";";
|
temp += String(ToString(LubeConfig.SpeedSource)) + ";";
|
||||||
{
|
{
|
||||||
String csv;
|
String csv;
|
||||||
appendCsv(csv, SpeedSourceString, SpeedSourceString_Elements);
|
appendCsv(csv, SpeedSourceString, SPEEDSOURCE_COUNT);
|
||||||
temp += csv + ";";
|
temp += csv + ";";
|
||||||
}
|
}
|
||||||
|
|
||||||
// gpsbaud + Optionen
|
// gpsbaud + Optionen
|
||||||
temp += tableStr(GPSBaudRateString, (int)LubeConfig.GPSBaudRate, (int)GPSBaudRateString_Elements) + ";";
|
temp += String(ToString(LubeConfig.GPSBaudRate)) + ";";
|
||||||
{
|
{
|
||||||
String csv;
|
String csv;
|
||||||
appendCsv(csv, GPSBaudRateString, GPSBaudRateString_Elements);
|
appendCsv(csv, GPSBaudRateString, GPSBAUDRATE_COUNT);
|
||||||
temp += csv + ";";
|
temp += csv + ";";
|
||||||
}
|
}
|
||||||
|
|
||||||
// cansource + Optionen
|
// cansource + Optionen
|
||||||
temp += tableStr(CANSourceString, (int)LubeConfig.CANSource, (int)CANSourceString_Elements) + ";";
|
temp += String(ToString(LubeConfig.CANSource)) + ";";
|
||||||
{
|
{
|
||||||
String csv;
|
String csv;
|
||||||
appendCsv(csv, CANSourceString, CANSourceString_Elements);
|
appendCsv(csv, CANSourceString, CANSOURCE_COUNT);
|
||||||
temp += csv + ";";
|
temp += csv + ";";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user