diff --git a/Software/.gitignore b/Software/.gitignore index eda73da..0f7fc76 100644 --- a/Software/.gitignore +++ b/Software/.gitignore @@ -4,4 +4,5 @@ data/ .vscode/c_cpp_properties.json .vscode/launch.json .vscode/ipch -wifi_credentials.ini \ No newline at end of file +wifi_credentials.ini +__pycache__ \ No newline at end of file diff --git a/Software/build_dtcs.py b/Software/build_dtcs.py deleted file mode 100644 index e09672f..0000000 --- a/Software/build_dtcs.py +++ /dev/null @@ -1,127 +0,0 @@ -Import("env") # pylint: disable=undefined-variable -env.Execute("\"$PYTHONEXE\" -m pip install jinja2") - -import os -import time -from jinja2 import Environment, FileSystemLoader -import json - -# Pfad zur Eingabedatei und Ausgabedatei -input_file = "src/dtc_defs.txt" -output_file = "include/dtc_defs.h" -json_output_file = "data_src/static/dtc_table.json" - -# Überprüfen, ob das Verzeichnis existiert, andernfalls erstellen -json_output_dir = os.path.dirname(json_output_file) -if not os.path.exists(json_output_dir): - os.makedirs(json_output_dir) - -# Mehrdimensionales Array zum Speichern der Zeilen aus der Eingabedatei -dtc_lines = [] - -# Lesen und analysieren der Eingabedatei -with open(input_file, "r", encoding="utf-8") as f: - for line in f: - line = line.strip() - if not line or line.startswith("#"): - continue - - parts = line.split(";") - if len(parts) == 5: - num, dtc_name, dtc_severity, title, description = [part.strip() for part in parts] - dtc_lines.append([int(num), dtc_name, dtc_severity, title, description]) - -# Überprüfen auf Duplikate in den DTC-Nummern und DTC-Namen -num_set = set() -dtc_name_set = set() -duplicates = [] - -for line in dtc_lines: - num, dtc_name, _, _, _ = line - if num in num_set: - duplicates.append(f"DTC-Nummer {num} ist ein Duplikat.") - else: - num_set.add(num) - - if dtc_name in dtc_name_set: - duplicates.append(f"DTC-Name '{dtc_name}' ist ein Duplikat.") - else: - dtc_name_set.add(dtc_name) - -if duplicates: - for duplicate in duplicates: - print(f"Fehler: {duplicate}") - raise ValueError("Duplicate DTC Data detected") - -# Suchen nach DTC_NO_DTC und DTC_LAST_DTC -dtc_no_dtc_added = False -dtc_last_dtc_line = None - -for line in dtc_lines: - _, dtc_name, _, _, _ = line - if dtc_name == "DTC_NO_DTC": - dtc_no_dtc_added = True - elif dtc_name == "DTC_LAST_DTC": - dtc_last_dtc_line = line - -# Einen DTC für DTC_NO_DTC hinzufügen (wenn nicht vorhanden) -if not dtc_no_dtc_added: - dtc_lines.insert(0, [0, "DTC_NO_DTC", "DTC_NONE", "No Error", "No Error"]) - -# Falls DTC_LAST_DTC existiert, lösche es -if dtc_last_dtc_line: - dtc_lines.remove(dtc_last_dtc_line) - -# Einen DTC für DTC_LAST_DTC hinzufügen (mit der höchsten Nummer) -if dtc_lines: - highest_num = max([line[0] for line in dtc_lines]) -else: - highest_num = 0 - -dtc_lines.append([highest_num + 1, "DTC_LAST_DTC", "DTC_NONE", "Last Error", "Last Error"]) - -# Sortieren der Zeilen nach der Nummer aufsteigend -dtc_lines.sort(key=lambda x: x[0]) - -# DTC_NAME_CONSTANT-Makros initialisieren -dtc_macros = [] -dtc_structs = [] -dtc_table_data = [] - -# Verarbeiten der sortierten Zeilen -for i, line in enumerate(dtc_lines): - num, dtc_name, dtc_severity, title, description = line - dtc_macros.append(f"#define {dtc_name:<30} {num}") - comma = "," if i < len(dtc_lines) - 1 else " " - dtc_structs.append(f" {{ {dtc_name:<30}, {dtc_severity:<12} }}{comma} // {description}") - dtc_table_data.append({"num": num, "title": title, "description": description}) - -# Unix-Zeitstempel hinzufügen -timestamp = int(time.time()) - -env = Environment(loader=FileSystemLoader('include', encoding='utf-8')) -# Lade das Jinja2-Template aus der Datei -template = env.get_template('dtc_defs.h.j2') - -# Erstelle ein Context-Dictionary mit den erforderlichen Daten -context = { - 'timestamp_unix': timestamp, - 'timestamp' : time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp)), - 'dtc_macros': dtc_macros, # Übergebe die dtc_macros-Liste direkt - 'dtc_structs': dtc_structs, # Übergebe die dtc_structs-Liste direkt -} - -# Rendere das Template mit den Werten und erhalte den Header-Text -header_text = template.render(context) - -# Schreibe den generierten Header-Text in die Header-Datei -with open(output_file, "w", encoding='utf-8') as f: - f.write(header_text) - -print(f"Header-Datei wurde erstellt: {output_file}") - -# JSON-Datei mit UTF-8-Zeichencodierung erstellen -with open(json_output_file, 'w', encoding='utf-8') as json_f: - json.dump(dtc_table_data, json_f, ensure_ascii=False, indent=4, separators=(',', ': ')) - -print(f"JSON-Datei wurde erstellt: {json_output_file}") diff --git a/Software/codegen/dtcs.py b/Software/codegen/dtcs.py new file mode 100644 index 0000000..157ea64 --- /dev/null +++ b/Software/codegen/dtcs.py @@ -0,0 +1,127 @@ +import os +import time +from jinja2 import Environment, FileSystemLoader +import json + +def build_dtcs(): + # Pfad zur Eingabedatei und Ausgabedatei + input_file = "src/dtc_defs.txt" + output_file = "include/dtc_defs.h" + json_output_file = "data_src/static/dtc_table.json" + + # Überprüfen, ob das Verzeichnis existiert, andernfalls erstellen + json_output_dir = os.path.dirname(json_output_file) + if not os.path.exists(json_output_dir): + os.makedirs(json_output_dir) + + # Mehrdimensionales Array zum Speichern der Zeilen aus der Eingabedatei + dtc_lines = [] + + # Lesen und analysieren der Eingabedatei + with open(input_file, "r", encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line or line.startswith("#"): + continue + + parts = line.split(";") + if len(parts) == 5: + num, dtc_name, dtc_severity, title, description = [part.strip() for part in parts] + dtc_lines.append([int(num), dtc_name, dtc_severity, title, description]) + + # Überprüfen auf Duplikate in den DTC-Nummern und DTC-Namen + num_set = set() + dtc_name_set = set() + duplicates = [] + + for line in dtc_lines: + num, dtc_name, _, _, _ = line + if num in num_set: + duplicates.append(f"DTC-Nummer {num} ist ein Duplikat.") + else: + num_set.add(num) + + if dtc_name in dtc_name_set: + duplicates.append(f"DTC-Name '{dtc_name}' ist ein Duplikat.") + else: + dtc_name_set.add(dtc_name) + + if duplicates: + for duplicate in duplicates: + print(f"Fehler: {duplicate}") + raise ValueError("Duplicate DTC Data detected") + + # Suchen nach DTC_NO_DTC und DTC_LAST_DTC + dtc_no_dtc_added = False + dtc_last_dtc_line = None + + for line in dtc_lines: + _, dtc_name, _, _, _ = line + if dtc_name == "DTC_NO_DTC": + dtc_no_dtc_added = True + elif dtc_name == "DTC_LAST_DTC": + dtc_last_dtc_line = line + + # Einen DTC für DTC_NO_DTC hinzufügen (wenn nicht vorhanden) + if not dtc_no_dtc_added: + dtc_lines.insert(0, [0, "DTC_NO_DTC", "DTC_NONE", "No Error", "No Error"]) + + # Falls DTC_LAST_DTC existiert, lösche es + if dtc_last_dtc_line: + dtc_lines.remove(dtc_last_dtc_line) + + # Einen DTC für DTC_LAST_DTC hinzufügen (mit der höchsten Nummer) + if dtc_lines: + highest_num = max([line[0] for line in dtc_lines]) + else: + highest_num = 0 + + dtc_lines.append([highest_num + 1, "DTC_LAST_DTC", "DTC_NONE", "Last Error", "Last Error"]) + + # Sortieren der Zeilen nach der Nummer aufsteigend + dtc_lines.sort(key=lambda x: x[0]) + + # DTC_NAME_CONSTANT-Makros initialisieren + dtc_macros = [] + dtc_structs = [] + dtc_table_data = [] + + # Verarbeiten der sortierten Zeilen + for i, line in enumerate(dtc_lines): + num, dtc_name, dtc_severity, title, description = line + dtc_macros.append(f"#define {dtc_name:<30} {num}") + comma = "," if i < len(dtc_lines) - 1 else " " + dtc_structs.append(f" {{ {dtc_name:<30}, {dtc_severity:<12} }}{comma} // {description}") + dtc_table_data.append({"num": num, "title": title, "description": description}) + + # Unix-Zeitstempel hinzufügen + timestamp = int(time.time()) + + env = Environment(loader=FileSystemLoader('codegen/templates', encoding='utf-8')) + # Lade das Jinja2-Template aus der Datei + template = env.get_template('dtc_defs.h.j2') + + # Erstelle ein Context-Dictionary mit den erforderlichen Daten + context = { + 'timestamp_unix': timestamp, + 'timestamp' : time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp)), + 'date' : time.strftime('%d.%m.%Y', time.localtime(timestamp)), + 'dtc_macros': dtc_macros, # Übergebe die dtc_macros-Liste direkt + 'dtc_structs': dtc_structs, # Übergebe die dtc_structs-Liste direkt + } + + # Rendere das Template mit den Werten und erhalte den Header-Text + header_text = template.render(context) + + # Schreibe den generierten Header-Text in die Header-Datei + with open(output_file, "w", encoding='utf-8') as f: + f.write(header_text) + + print(f"Header-Datei wurde erstellt: {output_file}") + + # JSON-Datei mit UTF-8-Zeichencodierung erstellen + with open(json_output_file, 'w', encoding='utf-8') as json_f: + json.dump(dtc_table_data, json_f, ensure_ascii=False, indent=4, separators=(',', ': ')) + + print(f"JSON-Datei wurde erstellt: {json_output_file}") + \ No newline at end of file diff --git a/Software/git_rev_macro.py b/Software/codegen/git_rev_macro.py similarity index 100% rename from Software/git_rev_macro.py rename to Software/codegen/git_rev_macro.py diff --git a/Software/prepare_littlefs.py b/Software/codegen/prepare_littlefs.py similarity index 100% rename from Software/prepare_littlefs.py rename to Software/codegen/prepare_littlefs.py diff --git a/Software/codegen/run_pre.py b/Software/codegen/run_pre.py new file mode 100644 index 0000000..13afca6 --- /dev/null +++ b/Software/codegen/run_pre.py @@ -0,0 +1,9 @@ +Import("env") # pylint: disable=undefined-variable +env.Execute("\"$PYTHONEXE\" -m pip install jinja2") +env.Replace(PROGNAME="firmware_pcb_1.%s.fw" % env.GetProjectOption("custom_pcb_revision")) + +import struct2json +import dtcs + +struct2json.struct2json() +dtcs.build_dtcs() \ No newline at end of file diff --git a/Software/codegen/struct2json.py b/Software/codegen/struct2json.py new file mode 100644 index 0000000..f682e10 --- /dev/null +++ b/Software/codegen/struct2json.py @@ -0,0 +1,93 @@ +import os +import time +from jinja2 import Environment, FileSystemLoader +import re + +# Pfad zur Eingabedatei und Ausgabedatei +input_file = "include/config.h" +output_sourcefile = "src/struct2json.cpp" +output_headerfile = "include/struct2json.h" +# Liste der zu suchenden Variablen/Structs +variable_names = ['LubeConfig', 'PersistenceData'] + +def get_types(file_content, variable_names): + result = {} + + # Entferne Kommentare, um unerwünschte Störungen zu vermeiden + file_content = re.sub(r'\/\*.*?\*\/', '', file_content, flags=re.DOTALL) + file_content = re.sub(r'\/\/.*', '', file_content) + + for var_name in variable_names: + # Erstelle ein reguläres Ausdrucksmuster, um den Typ der Variable zu extrahieren + pattern = re.compile(r'\b(?:extern\s+)?(\w+)\s+' + re.escape(var_name) + r'\s*;') + match = pattern.search(file_content) + + if match: + # Extrahiere den Typ aus dem Treffer + type_match = match.group(1) + result[var_name] = type_match + + return result + +def extract_struct_fields(file_content, variable_types): + result = {} + + # Entferne Kommentare, um unerwünschte Störungen zu vermeiden + file_content = re.sub(r'\/\*.*?\*\/', '', file_content, flags=re.DOTALL) + file_content = re.sub(r'\/\/.*', '', file_content) + + for var_name, var_type in variable_types.items(): + # Erstelle ein reguläres Ausdrucksmuster, um das Strukturfeld zu extrahieren + pattern = re.compile(r'typedef\s+struct\s*{([^}]*)}\s*' + re.escape(var_type) + r'\s*;') + match = pattern.search(file_content) + + if match: + # Extrahiere die Felder aus dem Treffer + fields_match = re.findall(r'\b(\w+)\s+(\w+)\s*;', match.group(1)) + if fields_match: + result[var_name] = {'type': var_type, 'fields': {field_name: field_type for field_type, field_name in fields_match}} + + return result + +def struct2json(): + # Überprüfen, ob die Verzeichnisse existieren, andernfalls erstellen + output_dir_source = os.path.dirname(output_sourcefile) + if not os.path.exists(output_dir_source): + os.makedirs(output_dir_source) + output_dir_header = os.path.dirname(output_headerfile) + if not os.path.exists(output_dir_header): + os.makedirs(output_dir_header) + + # Unix-Zeitstempel hinzufügen + timestamp = int(time.time()) + + # Parse structs + with open(input_file, 'r') as file: + content = file.read() + + variable_types = get_types(content, variable_names) + structs = extract_struct_fields(content, variable_types) + + env = Environment(loader=FileSystemLoader('codegen/templates', encoding='utf-8')) + # Lade das Jinja2-Template aus der Datei + template_c = env.get_template('struct2json.cpp.j2') + template_h = env.get_template('struct2json.h.j2') + + # Erstelle ein Context-Dictionary mit den erforderlichen Daten + context = { + 'timestamp_unix': timestamp, + 'timestamp' : time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp)), + 'date' : time.strftime('%d.%m.%Y', time.localtime(timestamp)), + 'structs': structs, # Übergebe die foo-Liste direkt + } + + # Rendere das Template mit den Werten und erhalte den Source-Text + source_text = template_c.render(context) + header_text = template_h.render(context) + + # Schreibe den generierten Source-Text in die Source-Dateien + with open(output_sourcefile, "w", encoding='utf-8') as f: + f.write(source_text) + with open(output_headerfile, "w", encoding='utf-8') as f: + f.write(header_text) + print(f"Source-Dateien wurde erstellt: {output_sourcefile}, {output_headerfile}") \ No newline at end of file diff --git a/Software/include/dtc_defs.h.j2 b/Software/codegen/templates/dtc_defs.h.j2 similarity index 97% rename from Software/include/dtc_defs.h.j2 rename to Software/codegen/templates/dtc_defs.h.j2 index 2aa148e..2c947f3 100644 --- a/Software/include/dtc_defs.h.j2 +++ b/Software/codegen/templates/dtc_defs.h.j2 @@ -10,7 +10,7 @@ * @note This file is auto-generated by a script on {{ timestamp }}. * * @author Marcel Peterkau - * @date 09.01.2024 + * @date {{ date }} */ #ifndef DTC_DEFS_H diff --git a/Software/codegen/templates/struct2json.cpp.j2 b/Software/codegen/templates/struct2json.cpp.j2 new file mode 100644 index 0000000..9e87ef2 --- /dev/null +++ b/Software/codegen/templates/struct2json.cpp.j2 @@ -0,0 +1,23 @@ +/** + * @file struct2json.cpp + * + * @brief Implementation file for converting structs to JSON objects. + * + * @note This file is auto-generated by a script on {{ timestamp }}. + * + * @author Marcel Peterkau + * @date {{ date }} + */ + + +#include "struct2json.h" + +{% for var_name, var_info in structs.items() -%} +void generateJsonObject_{{ var_name }}(JsonObject& data) +{ + {% for field_name, field_type in var_info['fields'].items() -%} + data["{{ field_name }}"] = {{ var_name }}.{{ field_name }}; + {% endfor -%} +} + +{% endfor %} diff --git a/Software/codegen/templates/struct2json.h.j2 b/Software/codegen/templates/struct2json.h.j2 new file mode 100644 index 0000000..df8f222 --- /dev/null +++ b/Software/codegen/templates/struct2json.h.j2 @@ -0,0 +1,24 @@ +/** + * @file struct2json.h + * + * @brief Header file for converting structs to JSON objects. + * + * @note This file is auto-generated by a script on {{ timestamp }}. + * + * @author Marcel Peterkau + * @date {{ date }} + */ + +#ifndef _STRUCT2JSON_H_ +#define _STRUCT2JSON_H_ + +#include +#include + +#include "config.h" + +{% for var_name, var_info in structs.items() -%} +void generateJsonObject_{{ var_name }}(JsonObject& data); +{% endfor %} + +#endif /* _STRUCT2JSON_H_ */ \ No newline at end of file diff --git a/Software/include/struct2json.h b/Software/include/struct2json.h new file mode 100644 index 0000000..43316bb --- /dev/null +++ b/Software/include/struct2json.h @@ -0,0 +1,24 @@ +/** + * @file struct2json.h + * + * @brief Header file for converting structs to JSON objects. + * + * @note This file is auto-generated by a script on 2024-01-09 20:41:57. + * + * @author Marcel Peterkau + * @date 09.01.2024 + */ + +#ifndef _STRUCT2JSON_H_ +#define _STRUCT2JSON_H_ + +#include +#include + +#include "config.h" + +void generateJsonObject_LubeConfig(JsonObject& data); +void generateJsonObject_PersistenceData(JsonObject& data); + + +#endif /* _STRUCT2JSON_H_ */ \ No newline at end of file diff --git a/Software/include/webui.h b/Software/include/webui.h index badb114..66f779a 100644 --- a/Software/include/webui.h +++ b/Software/include/webui.h @@ -29,6 +29,7 @@ #include "dtc.h" #include "common.h" #include "debugger.h" +#include "struct2json.h" void initWebUI(); void Webserver_Process(); diff --git a/Software/platformio.ini b/Software/platformio.ini index adf3a43..dbd7110 100644 --- a/Software/platformio.ini +++ b/Software/platformio.ini @@ -28,7 +28,7 @@ upload_flags = build_flags = - !python git_rev_macro.py + !python codegen/git_rev_macro.py -DWIFI_SSID_CLIENT=${wifi_cred.wifi_ssid_client} -DWIFI_PASSWORD_CLIENT=${wifi_cred.wifi_password_client} -DADMIN_PASSWORD=${wifi_cred.admin_password} @@ -38,9 +38,8 @@ build_flags = board_build.filesystem = littlefs extra_scripts = - post:prepare_littlefs.py - pre:build_dtcs.py - pre:prepare_fwfiles.py + post:codegen/prepare_littlefs.py + pre:codegen/run_pre.py monitor_filters = esp8266_exception_decoder monitor_speed = 115200 diff --git a/Software/prepare_fwfiles.py b/Software/prepare_fwfiles.py deleted file mode 100644 index be1d788..0000000 --- a/Software/prepare_fwfiles.py +++ /dev/null @@ -1,3 +0,0 @@ -Import("env") - -env.Replace(PROGNAME="firmware_pcb_1.%s.fw" % env.GetProjectOption("custom_pcb_revision")) diff --git a/Software/src/struct2json.cpp b/Software/src/struct2json.cpp new file mode 100644 index 0000000..280a478 --- /dev/null +++ b/Software/src/struct2json.cpp @@ -0,0 +1,47 @@ +/** + * @file struct2json.cpp + * + * @brief Implementation file for converting structs to JSON objects. + * + * @note This file is auto-generated by a script on 2024-01-09 20:41:57. + * + * @author Marcel Peterkau + * @date 09.01.2024 + */ + + +#include "struct2json.h" + +void generateJsonObject_LubeConfig(JsonObject& data) +{ + data["EEPROM_Version"] = LubeConfig.EEPROM_Version; + data["DistancePerLube_Default"] = LubeConfig.DistancePerLube_Default; + data["DistancePerLube_Rain"] = LubeConfig.DistancePerLube_Rain; + data["tankCapacity_ml"] = LubeConfig.tankCapacity_ml; + data["amountPerDose_microL"] = LubeConfig.amountPerDose_microL; + data["TankRemindAtPercentage"] = LubeConfig.TankRemindAtPercentage; + data["PulsePerRevolution"] = LubeConfig.PulsePerRevolution; + data["TireWidth_mm"] = LubeConfig.TireWidth_mm; + data["TireWidthHeight_Ratio"] = LubeConfig.TireWidthHeight_Ratio; + data["RimDiameter_Inch"] = LubeConfig.RimDiameter_Inch; + data["DistancePerRevolution_mm"] = LubeConfig.DistancePerRevolution_mm; + data["BleedingPulses"] = LubeConfig.BleedingPulses; + data["SpeedSource"] = LubeConfig.SpeedSource; + data["GPSBaudRate"] = LubeConfig.GPSBaudRate; + data["CANSource"] = LubeConfig.CANSource; + data["LED_Mode_Flash"] = LubeConfig.LED_Mode_Flash; + data["LED_Max_Brightness"] = LubeConfig.LED_Max_Brightness; + data["LED_Min_Brightness"] = LubeConfig.LED_Min_Brightness; + data["checksum"] = LubeConfig.checksum; + } + +void generateJsonObject_PersistenceData(JsonObject& data) +{ + data["writeCycleCounter"] = PersistenceData.writeCycleCounter; + data["tankRemain_microL"] = PersistenceData.tankRemain_microL; + data["TravelDistance_highRes_mm"] = PersistenceData.TravelDistance_highRes_mm; + data["odometer_mm"] = PersistenceData.odometer_mm; + data["odometer"] = PersistenceData.odometer; + data["checksum"] = PersistenceData.checksum; + } + diff --git a/Software/src/webui.cpp b/Software/src/webui.cpp index 6838c8f..ccc2aa0 100644 --- a/Software/src/webui.cpp +++ b/Software/src/webui.cpp @@ -463,46 +463,14 @@ void WebServerEEJSON_Callback(AsyncWebServerRequest *request) fwinfo["Git-Hash"] = buffer; JsonObject config = json.createNestedObject("config"); - - config["EEPROM_Version"] = LubeConfig.EEPROM_Version; - config["DistancePerLube_Default"] = LubeConfig.DistancePerLube_Default; - config["DistancePerLube_Rain"] = LubeConfig.DistancePerLube_Rain; - config["tankCapacity_ml"] = LubeConfig.tankCapacity_ml; - config["amountPerDose_microL"] = LubeConfig.amountPerDose_microL; - config["TankRemindAtPercentage"] = LubeConfig.TankRemindAtPercentage; - config["PulsePerRevolution"] = LubeConfig.PulsePerRevolution; - config["TireWidth_mm"] = LubeConfig.TireWidth_mm; - config["TireWidthHeight_Ratio"] = LubeConfig.TireWidthHeight_Ratio; - config["RimDiameter_Inch"] = LubeConfig.RimDiameter_Inch; - config["DistancePerRevolution_mm"] = LubeConfig.DistancePerRevolution_mm; - config["BleedingPulses"] = LubeConfig.BleedingPulses; - config["SpeedSource"] = LubeConfig.SpeedSource; - config["SpeedSource_Str"] = SpeedSourceString[LubeConfig.SpeedSource]; - config["GPSBaudRate"] = LubeConfig.GPSBaudRate; - config["GPSBaudRate_Str"] = GPSBaudRateString[LubeConfig.GPSBaudRate]; - config["CANSource"] = LubeConfig.CANSource; - config["CANSource_Str"] = CANSourceString[LubeConfig.CANSource]; - config["LED_Mode_Flash"] = LubeConfig.LED_Mode_Flash; - config["LED_Max_Brightness"] = LubeConfig.LED_Max_Brightness; - config["LED_Min_Brightness"] = LubeConfig.LED_Min_Brightness; - sprintf(buffer, "0x%08X", LubeConfig.checksum); - config["checksum"] = buffer; + generateJsonObject_LubeConfig(config); + JsonObject persis = json.createNestedObject("persis"); + generateJsonObject_PersistenceData(persis); JsonObject eepart = json.createNestedObject("eepart"); - sprintf(buffer, "0x%04X", globals.eePersistanceAdress); eepart["PersistanceAddress"] = buffer; - JsonObject persis = json.createNestedObject("persis"); - - persis["writeCycleCounter"] = PersistenceData.writeCycleCounter; - persis["tankRemain_microL"] = PersistenceData.tankRemain_microL; - persis["TravelDistance_highRes_mm"] = PersistenceData.TravelDistance_highRes_mm; - persis["odometer_mm"] = PersistenceData.odometer_mm; - persis["odometer"] = PersistenceData.odometer; - sprintf(buffer, "0x%08X", PersistenceData.checksum); - persis["checksum"] = buffer; - serializeJsonPretty(json, *response); response->addHeader("Content-disposition", "attachment; filename=backup.ee.json");