From b1138d95100b3c0fc23abe321fe9029b75f8a370 Mon Sep 17 00:00:00 2001 From: suchmememanyskill <38142618+suchmememanyskill@users.noreply.github.com> Date: Mon, 28 Oct 2024 15:33:17 +0100 Subject: [PATCH] Split json parsing from printer impl --- CYD-Klipper/.vscode/settings.json | 30 +- .../klipper/klipper_printer_integration.cpp | 380 ++--------------- .../klipper/klipper_printer_integration.hpp | 26 +- .../core/klipper/klipper_printer_parsers.cpp | 394 ++++++++++++++++++ 4 files changed, 476 insertions(+), 354 deletions(-) create mode 100644 CYD-Klipper/src/core/klipper/klipper_printer_parsers.cpp diff --git a/CYD-Klipper/.vscode/settings.json b/CYD-Klipper/.vscode/settings.json index 425aa19..e1ffb15 100644 --- a/CYD-Klipper/.vscode/settings.json +++ b/CYD-Klipper/.vscode/settings.json @@ -20,7 +20,35 @@ "limits": "cpp", "memory": "cpp", "new": "cpp", - "type_traits": "cpp" + "type_traits": "cpp", + "atomic": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cstdarg": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "exception": "cpp", + "iterator": "cpp", + "map": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "tuple": "cpp", + "utility": "cpp", + "fstream": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp" }, "cmake.configureOnOpen": false } \ No newline at end of file diff --git a/CYD-Klipper/src/core/klipper/klipper_printer_integration.cpp b/CYD-Klipper/src/core/klipper/klipper_printer_integration.cpp index ae60526..9b91c34 100644 --- a/CYD-Klipper/src/core/klipper/klipper_printer_integration.cpp +++ b/CYD-Klipper/src/core/klipper/klipper_printer_integration.cpp @@ -35,9 +35,7 @@ int KlipperPrinter::get_slicer_time_estimate_s() JsonDocument doc; deserializeJson(doc, client.getStream()); - int time_estimate_s = doc["result"]["estimated_time"]; - LOG_F(("Got slicer time estimate: %ds\n", time_estimate_s)) - return time_estimate_s; + return parse_slicer_time_estimate(doc); } bool KlipperPrinter::send_gcode(const char *gcode, bool wait) @@ -89,6 +87,22 @@ bool KlipperPrinter::move_printer(const char* axis, float amount, bool relative) return true; } +bool KlipperPrinter::send_emergency_stop() +{ + HTTPClient client; + configure_http_client(client, "/printer/emergency_stop", false, 5000); + + try + { + return client.GET() == 200; + } + catch (...) + { + LOG_LN("Failed to send estop"); + return false; + } +} + bool KlipperPrinter::execute_feature(PrinterFeatures feature) { HTTPClient client; @@ -112,16 +126,7 @@ bool KlipperPrinter::execute_feature(PrinterFeatures feature) case PrinterFeatureEmergencyStop: LOG_LN("Sending estop"); send_gcode("M112", false); - configure_http_client(client, "/printer/emergency_stop", false, 5000); - - try - { - client.GET(); - } - catch (...) - { - LOG_LN("Failed to send estop"); - } + send_emergency_stop(); return true; case PrinterFeatureExtrude: @@ -182,177 +187,7 @@ bool KlipperPrinter::fetch() klipper_request_consecutive_fail_count = 0; JsonDocument doc; deserializeJson(doc, client.getStream()); - auto status = doc["result"]["status"]; - bool emit_state_update = false; - - if (status.containsKey("webhooks")) - { - const char* state = status["webhooks"]["state"]; - const char* message = status["webhooks"]["state_message"]; - - if (strcmp(state, "ready") == 0 && printer_data.state == PrinterStateError) - { - printer_data.state = PrinterStateIdle; - } - else if ((strcmp(state, "shutdown") == 0 || strcmp(state, "error") == 0) && printer_data.state != PrinterStateError) - { - printer_data.state = PrinterStateError; - } - - if (message != NULL && (printer_data.state_message == NULL || strcmp(printer_data.state_message, message))) - { - printer_data.state_message = (char *)malloc(strlen(message) + 1); - strcpy(printer_data.state_message, message); - } - } - - if (printer_data.state != PrinterStateError) - { - if (status.containsKey("extruder")) - { - printer_data.temperatures[PrinterTemperatureDeviceIndexNozzle1] = status["extruder"]["temperature"]; - printer_data.target_temperatures[PrinterTemperatureDeviceIndexNozzle1] = status["extruder"]["target"]; - bool can_extrude = status["extruder"]["can_extrude"]; - printer_data.pressure_advance = status["extruder"]["pressure_advance"]; - printer_data.smooth_time = status["extruder"]["smooth_time"]; - printer_data.can_extrude = can_extrude == true; - } - - if (status.containsKey("heater_bed")) - { - printer_data.temperatures[PrinterTemperatureDeviceIndexBed] = status["heater_bed"]["temperature"]; - printer_data.target_temperatures[PrinterTemperatureDeviceIndexBed] = status["heater_bed"]["target"]; - } - - if (status.containsKey("toolhead")) - { - const char *homed_axis = status["toolhead"]["homed_axes"]; - printer_data.homed_axis = strcmp(homed_axis, "xyz") == 0; - } - - if (status.containsKey("gcode_move")) - { - printer_data.position[0] = status["gcode_move"]["gcode_position"][0]; - printer_data.position[1] = status["gcode_move"]["gcode_position"][1]; - printer_data.position[2] = status["gcode_move"]["gcode_position"][2]; - gcode_offset[0] = status["gcode_move"]["homing_origin"][0]; - gcode_offset[1] = status["gcode_move"]["homing_origin"][1]; - gcode_offset[2] = status["gcode_move"]["homing_origin"][2]; - bool absolute_coords = status["gcode_move"]["absolute_coordinates"]; - - if (lock_absolute_relative_mode_swap > 0) - { - lock_absolute_relative_mode_swap--; - } - else - { - printer_data.absolute_coords = absolute_coords == true; - } - - printer_data.speed_mult = status["gcode_move"]["speed_factor"]; - printer_data.extrude_mult = status["gcode_move"]["extrude_factor"]; - printer_data.feedrate_mm_per_s = status["gcode_move"]["speed"]; - printer_data.feedrate_mm_per_s /= 60; // convert mm/m to mm/s - } - - if (status.containsKey("fan")) - { - printer_data.fan_speed = status["fan"]["speed"]; - } - - if (status.containsKey("virtual_sdcard")) - { - printer_data.print_progress = status["virtual_sdcard"]["progress"]; - } - - if (status.containsKey("print_stats")) - { - const char *filename = status["print_stats"]["filename"]; - - if (filename != NULL && (printer_data.print_filename == NULL || strcmp(printer_data.print_filename, filename))) - { - printer_data.print_filename = (char *)malloc(strlen(filename) + 1); - strcpy(printer_data.print_filename, filename); - } - - printer_data.elapsed_time_s = status["print_stats"]["total_duration"]; - printer_data.printed_time_s = status["print_stats"]["print_duration"]; - printer_data.filament_used_mm = status["print_stats"]["filament_used"]; - printer_data.total_layers = status["print_stats"]["info"]["total_layer"]; - printer_data.current_layer = status["print_stats"]["info"]["current_layer"]; - - const char *state = status["print_stats"]["state"]; - - if (state == nullptr) - { - // Continue - } - else if (strcmp(state, "printing") == 0) - { - printer_data.state = PrinterStatePrinting; - } - else if (strcmp(state, "paused") == 0) - { - printer_data.state = PrinterStatePaused; - } - else if (strcmp(state, "complete") == 0 || strcmp(state, "cancelled") == 0 || strcmp(state, "standby") == 0) - { - printer_data.state = PrinterStateIdle; - } - } - - if (status.containsKey("display_status")) - { - printer_data.print_progress = status["display_status"]["progress"]; - const char* message = status["display_status"]["message"]; - - if (message != NULL && (printer_data.popup_message == NULL || strcmp(printer_data.popup_message, message))) - { - printer_data.popup_message = (char*)malloc(strlen(message) + 1); - strcpy(printer_data.popup_message, message); - } - } - - if (printer_data.state == PrinterStatePrinting && printer_data.print_progress > 0) - { - float remaining_time_s_percentage = (printer_data.printed_time_s / printer_data.print_progress) - printer_data.printed_time_s; - float remaining_time_s_slicer = 0; - - if (slicer_estimated_print_time_s > 0) - { - remaining_time_s_slicer = slicer_estimated_print_time_s - printer_data.printed_time_s; - } - - if (remaining_time_s_slicer <= 0 || printer_config->remaining_time_calc_mode == REMAINING_TIME_CALC_PERCENTAGE) - { - printer_data.remaining_time_s = remaining_time_s_percentage; - } - else if (printer_config->remaining_time_calc_mode == REMAINING_TIME_CALC_INTERPOLATED) - { - printer_data.remaining_time_s = remaining_time_s_percentage * printer_data.print_progress + remaining_time_s_slicer * (1 - printer_data.print_progress); - } - else if (printer_config->remaining_time_calc_mode == REMAINING_TIME_CALC_SLICER) - { - printer_data.remaining_time_s = remaining_time_s_slicer; - } - } - - if (printer_data.remaining_time_s < 0) - { - printer_data.remaining_time_s = 0; - } - - if (printer_data.state == PrinterStateIdle) - { - slicer_estimated_print_time_s = 0; - } - } - - if (printer_data.state == PrinterStatePrinting && millis() - last_slicer_time_query > 30000 && slicer_estimated_print_time_s <= 0) - { - last_slicer_time_query = millis(); - slicer_estimated_print_time_s = get_slicer_time_estimate_s(); - } + parse_state(doc); } else { @@ -393,47 +228,7 @@ PrinterDataMinimal KlipperPrinter::fetch_min() JsonDocument doc; deserializeJson(doc, client.getStream()); - auto status = doc["result"]["status"]; - - if (status.containsKey("webhooks")) - { - const char *state = status["webhooks"]["state"]; - - if (strcmp(state, "shutdown") == 0) - { - data.state = PrinterState::PrinterStateError; - } - } - - if (data.state != PrinterStateError) - { - if (status.containsKey("virtual_sdcard")) - { - data.print_progress = status["virtual_sdcard"]["progress"]; - } - - if (status.containsKey("print_stats")) - { - const char *state = status["print_stats"]["state"]; - - if (state == nullptr) - { - data.state = PrinterState::PrinterStateError; - } - else if (strcmp(state, "printing") == 0) - { - data.state = PrinterState::PrinterStatePrinting; - } - else if (strcmp(state, "paused") == 0) - { - data.state = PrinterState::PrinterStatePaused; - } - else if (strcmp(state, "complete") == 0 || strcmp(state, "cancelled") == 0 || strcmp(state, "standby") == 0) - { - data.state = PrinterState::PrinterStateIdle; - } - } - } + return parse_state_min(doc); } else { @@ -461,27 +256,7 @@ Macros KlipperPrinter::get_macros() if (http_code == 200){ JsonDocument doc; deserializeJson(doc, client.getStream()); - auto result = doc["result"].as(); - macros.macros = (char**)malloc(sizeof(char*) * 32); - macros.count = 0; - macros.success = true; - - for (JsonPair i : result){ - const char *key = i.key().c_str(); - const char *value = i.value().as().c_str(); - if (strcmp(value, "CYD_SCREEN_MACRO") == 0) { - char* macro = (char*)malloc(strlen(key) + 1); - strcpy(macro, key); - macros.macros[macros.count++] = macro; - } - } - - if (global_config.sort_macros) - { - std::sort(macros.macros, macros.macros + macros.count, [](const char* a, const char* b) { - return strcmp(a, b) < 0; - }); - } + return parse_macros(doc); } return macros; @@ -497,18 +272,7 @@ int KlipperPrinter::get_macros_count() if (http_code == 200){ JsonDocument doc; deserializeJson(doc, client.getStream()); - auto result = doc["result"].as(); - - int count = 0; - - for (JsonPair i : result){ - const char *value = i.value().as().c_str(); - if (strcmp(value, "CYD_SCREEN_MACRO") == 0) { - count++; - } - } - - return count; + return parse_macros_count(doc); } else { return 0; @@ -531,20 +295,7 @@ PowerDevices KlipperPrinter::get_power_devices() if (http_code == 200){ JsonDocument doc; deserializeJson(doc, client.getStream()); - auto result = doc["result"]["devices"].as(); - power_devices.power_devices = (char**)malloc(sizeof(char*) * 16); - power_devices.power_states = (bool*)malloc(sizeof(bool) * 16); - power_devices.count = 0; - power_devices.success = true; - - for (auto i : result){ - const char * device_name = i["device"]; - const char * device_state = i["status"]; - power_devices.power_devices[power_devices.count] = (char*)malloc(strlen(device_name) + 1); - strcpy(power_devices.power_devices[power_devices.count], device_name); - power_devices.power_states[power_devices.count] = strcmp(device_state, "on") == 0; - power_devices.count++; - } + return parse_power_devices(doc); } return power_devices; @@ -560,15 +311,7 @@ int KlipperPrinter::get_power_devices_count() if (http_code == 200){ JsonDocument doc; deserializeJson(doc, client.getStream()); - auto result = doc["result"]["devices"].as(); - - int count = 0; - - for (auto i : result){ - count++; - } - - return count; + return parse_power_devices_count(doc); } else { return 0; @@ -582,11 +325,6 @@ bool KlipperPrinter::set_power_device_state(const char* device_name, bool state) return client.POST("") == 200; } -typedef struct { - char* name; - float modified; -} FileSystemFile; - #define KLIPPER_FILE_FETCH_LIMIT 20 Files KlipperPrinter::get_files() @@ -606,46 +344,7 @@ Files KlipperPrinter::get_files() JsonDocument doc; auto parseResult = deserializeJson(doc, client.getStream()); LOG_F(("Json parse: %s\n", parseResult.c_str())) - auto result = doc["result"].as(); - - for (auto file : result){ - FileSystemFile f = {0}; - const char* path = file["path"]; - float modified = file["modified"]; - auto file_iter = files.begin(); - - while (file_iter != files.end()){ - if ((*file_iter).modified < modified) - break; - - file_iter++; - } - - if (file_iter == files.end() && files.size() >= KLIPPER_FILE_FETCH_LIMIT) - continue; - - f.name = (char*)malloc(strlen(path) + 1); - if (f.name == NULL){ - LOG_LN("Failed to allocate memory"); - continue; - } - strcpy(f.name, path); - f.modified = modified; - - if (file_iter != files.end()) - files.insert(file_iter, f); - else - files.push_back(f); - - if (files.size() > KLIPPER_FILE_FETCH_LIMIT){ - auto last_entry = files.back(); - - if (last_entry.name != NULL) - free(last_entry.name); - - files.pop_back(); - } - } + parse_file_list(doc, files, KLIPPER_FILE_FETCH_LIMIT); } files_result.available_files = (char**)malloc(sizeof(char*) * files.size()); @@ -724,30 +423,7 @@ Thumbnail KlipperPrinter::get_32_32_png_image_thumbnail(const char* gcode_filena { JsonDocument doc; deserializeJson(doc, client.getStream()); - auto result = doc["result"].as(); - const char* chosen_thumb = NULL; - for (auto file : result){ - int width = file["width"]; - int height = file["height"]; - int size = file["size"]; - const char* thumbnail = file["thumbnail_path"]; - - if (width != height || width != 32) - continue; - - - if (strcmp(thumbnail + strlen(thumbnail) - 4, ".png")) - continue; - - chosen_thumb = thumbnail; - break; - } - - if (chosen_thumb != NULL){ - LOG_F(("Found 32x32 PNG gcode img at %s\n", gcode_filename)) - img_filename_path = (char*)malloc(strlen(chosen_thumb) + 1); - strcpy(img_filename_path, chosen_thumb); - } + img_filename_path = parse_thumbnails(doc); } else { @@ -759,6 +435,10 @@ Thumbnail KlipperPrinter::get_32_32_png_image_thumbnail(const char* gcode_filena LOG_LN("No compatible thumbnail found"); return thumbnail; } + else + { + LOG_F(("Found 32x32 PNG gcode img at %s\n", gcode_filename)); + } client.end(); diff --git a/CYD-Klipper/src/core/klipper/klipper_printer_integration.hpp b/CYD-Klipper/src/core/klipper/klipper_printer_integration.hpp index a144667..758c9ba 100644 --- a/CYD-Klipper/src/core/klipper/klipper_printer_integration.hpp +++ b/CYD-Klipper/src/core/klipper/klipper_printer_integration.hpp @@ -2,6 +2,13 @@ #include "../printer_integration.hpp" #include +#include +#include + +typedef struct { + char* name; + float modified; +} FileSystemFile; class KlipperPrinter : public BasePrinter { @@ -10,6 +17,22 @@ class KlipperPrinter : public BasePrinter unsigned char klipper_request_consecutive_fail_count{}; unsigned int slicer_estimated_print_time_s{}; unsigned int last_slicer_time_query{}; + void configure_http_client(HTTPClient &client, String url_part, bool stream, int timeout); + + protected: + bool send_emergency_stop(); + int get_slicer_time_estimate_s(); + void init_ui_panels(); + + int parse_slicer_time_estimate(JsonDocument& in); + void parse_state(JsonDocument& in); + PrinterDataMinimal parse_state_min(JsonDocument& in); + Macros parse_macros(JsonDocument &in); + int parse_macros_count(JsonDocument &in); + PowerDevices parse_power_devices(JsonDocument &in); + int parse_power_devices_count(JsonDocument &in); + void parse_file_list(JsonDocument &in, std::list &files, int fetch_limit); + char *parse_thumbnails(JsonDocument &in); public: float gcode_offset[3]{}; @@ -51,9 +74,6 @@ class KlipperPrinter : public BasePrinter Thumbnail get_32_32_png_image_thumbnail(const char* gcode_filename); bool set_target_temperature(PrinterTemperatureDevice device, unsigned int temperature); bool send_gcode(const char* gcode, bool wait = true); - int get_slicer_time_estimate_s(); - void configure_http_client(HTTPClient &client, String url_part, bool stream, int timeout); - void init_ui_panels(); }; enum ConnectionStatus { diff --git a/CYD-Klipper/src/core/klipper/klipper_printer_parsers.cpp b/CYD-Klipper/src/core/klipper/klipper_printer_parsers.cpp new file mode 100644 index 0000000..eab6d02 --- /dev/null +++ b/CYD-Klipper/src/core/klipper/klipper_printer_parsers.cpp @@ -0,0 +1,394 @@ +#include "../printer_integration.hpp" +#include "klipper_printer_integration.hpp" +#include + +int KlipperPrinter::parse_slicer_time_estimate(JsonDocument &in) +{ + int time_estimate_s = in["result"]["estimated_time"]; + LOG_F(("Got slicer time estimate: %ds\n", time_estimate_s)) + return time_estimate_s; +} + +void KlipperPrinter::parse_state(JsonDocument &in) +{ + auto status = in["result"]["status"]; + + if (status.containsKey("webhooks")) + { + const char *state = status["webhooks"]["state"]; + const char *message = status["webhooks"]["state_message"]; + + if (strcmp(state, "ready") == 0 && printer_data.state == PrinterStateError) + { + printer_data.state = PrinterStateIdle; + } + else if ((strcmp(state, "shutdown") == 0 || strcmp(state, "error") == 0) && printer_data.state != PrinterStateError) + { + printer_data.state = PrinterStateError; + } + + if (message != NULL && (printer_data.state_message == NULL || strcmp(printer_data.state_message, message))) + { + printer_data.state_message = (char *)malloc(strlen(message) + 1); + strcpy(printer_data.state_message, message); + } + } + + if (printer_data.state != PrinterStateError) + { + if (status.containsKey("extruder")) + { + printer_data.temperatures[PrinterTemperatureDeviceIndexNozzle1] = status["extruder"]["temperature"]; + printer_data.target_temperatures[PrinterTemperatureDeviceIndexNozzle1] = status["extruder"]["target"]; + bool can_extrude = status["extruder"]["can_extrude"]; + printer_data.pressure_advance = status["extruder"]["pressure_advance"]; + printer_data.smooth_time = status["extruder"]["smooth_time"]; + printer_data.can_extrude = can_extrude == true; + } + + if (status.containsKey("heater_bed")) + { + printer_data.temperatures[PrinterTemperatureDeviceIndexBed] = status["heater_bed"]["temperature"]; + printer_data.target_temperatures[PrinterTemperatureDeviceIndexBed] = status["heater_bed"]["target"]; + } + + if (status.containsKey("toolhead")) + { + const char *homed_axis = status["toolhead"]["homed_axes"]; + printer_data.homed_axis = strcmp(homed_axis, "xyz") == 0; + } + + if (status.containsKey("gcode_move")) + { + printer_data.position[0] = status["gcode_move"]["gcode_position"][0]; + printer_data.position[1] = status["gcode_move"]["gcode_position"][1]; + printer_data.position[2] = status["gcode_move"]["gcode_position"][2]; + gcode_offset[0] = status["gcode_move"]["homing_origin"][0]; + gcode_offset[1] = status["gcode_move"]["homing_origin"][1]; + gcode_offset[2] = status["gcode_move"]["homing_origin"][2]; + bool absolute_coords = status["gcode_move"]["absolute_coordinates"]; + + if (lock_absolute_relative_mode_swap > 0) + { + lock_absolute_relative_mode_swap--; + } + else + { + printer_data.absolute_coords = absolute_coords == true; + } + + printer_data.speed_mult = status["gcode_move"]["speed_factor"]; + printer_data.extrude_mult = status["gcode_move"]["extrude_factor"]; + printer_data.feedrate_mm_per_s = status["gcode_move"]["speed"]; + printer_data.feedrate_mm_per_s /= 60; // convert mm/m to mm/s + } + + if (status.containsKey("fan")) + { + printer_data.fan_speed = status["fan"]["speed"]; + } + + if (status.containsKey("virtual_sdcard")) + { + printer_data.print_progress = status["virtual_sdcard"]["progress"]; + } + + if (status.containsKey("print_stats")) + { + const char *filename = status["print_stats"]["filename"]; + + if (filename != NULL && (printer_data.print_filename == NULL || strcmp(printer_data.print_filename, filename))) + { + printer_data.print_filename = (char *)malloc(strlen(filename) + 1); + strcpy(printer_data.print_filename, filename); + } + + printer_data.elapsed_time_s = status["print_stats"]["total_duration"]; + printer_data.printed_time_s = status["print_stats"]["print_duration"]; + printer_data.filament_used_mm = status["print_stats"]["filament_used"]; + printer_data.total_layers = status["print_stats"]["info"]["total_layer"]; + printer_data.current_layer = status["print_stats"]["info"]["current_layer"]; + + const char *state = status["print_stats"]["state"]; + + if (state == nullptr) + { + // Continue + } + else if (strcmp(state, "printing") == 0) + { + printer_data.state = PrinterStatePrinting; + } + else if (strcmp(state, "paused") == 0) + { + printer_data.state = PrinterStatePaused; + } + else if (strcmp(state, "complete") == 0 || strcmp(state, "cancelled") == 0 || strcmp(state, "standby") == 0) + { + printer_data.state = PrinterStateIdle; + } + } + + if (status.containsKey("display_status")) + { + printer_data.print_progress = status["display_status"]["progress"]; + const char *message = status["display_status"]["message"]; + + if (message != NULL && (printer_data.popup_message == NULL || strcmp(printer_data.popup_message, message))) + { + printer_data.popup_message = (char *)malloc(strlen(message) + 1); + strcpy(printer_data.popup_message, message); + } + } + + if (printer_data.state == PrinterStatePrinting && printer_data.print_progress > 0) + { + float remaining_time_s_percentage = (printer_data.printed_time_s / printer_data.print_progress) - printer_data.printed_time_s; + float remaining_time_s_slicer = 0; + + if (slicer_estimated_print_time_s > 0) + { + remaining_time_s_slicer = slicer_estimated_print_time_s - printer_data.printed_time_s; + } + + if (remaining_time_s_slicer <= 0 || printer_config->remaining_time_calc_mode == REMAINING_TIME_CALC_PERCENTAGE) + { + printer_data.remaining_time_s = remaining_time_s_percentage; + } + else if (printer_config->remaining_time_calc_mode == REMAINING_TIME_CALC_INTERPOLATED) + { + printer_data.remaining_time_s = remaining_time_s_percentage * printer_data.print_progress + remaining_time_s_slicer * (1 - printer_data.print_progress); + } + else if (printer_config->remaining_time_calc_mode == REMAINING_TIME_CALC_SLICER) + { + printer_data.remaining_time_s = remaining_time_s_slicer; + } + } + + if (printer_data.remaining_time_s < 0) + { + printer_data.remaining_time_s = 0; + } + + if (printer_data.state == PrinterStateIdle) + { + slicer_estimated_print_time_s = 0; + } + } + + if (printer_data.state == PrinterStatePrinting && millis() - last_slicer_time_query > 30000 && slicer_estimated_print_time_s <= 0) + { + last_slicer_time_query = millis(); + slicer_estimated_print_time_s = get_slicer_time_estimate_s(); + } +} + +PrinterDataMinimal KlipperPrinter::parse_state_min(JsonDocument &in) +{ + auto status = in["result"]["status"]; + PrinterDataMinimal data = {}; + data.success = true; + + if (status.containsKey("webhooks")) + { + const char *state = status["webhooks"]["state"]; + + if (strcmp(state, "shutdown") == 0) + { + data.state = PrinterState::PrinterStateError; + } + } + + if (data.state != PrinterStateError) + { + if (status.containsKey("virtual_sdcard")) + { + data.print_progress = status["virtual_sdcard"]["progress"]; + } + + if (status.containsKey("print_stats")) + { + const char *state = status["print_stats"]["state"]; + + if (state == nullptr) + { + data.state = PrinterState::PrinterStateError; + } + else if (strcmp(state, "printing") == 0) + { + data.state = PrinterState::PrinterStatePrinting; + } + else if (strcmp(state, "paused") == 0) + { + data.state = PrinterState::PrinterStatePaused; + } + else if (strcmp(state, "complete") == 0 || strcmp(state, "cancelled") == 0 || strcmp(state, "standby") == 0) + { + data.state = PrinterState::PrinterStateIdle; + } + } + } + + return data; +} + +Macros KlipperPrinter::parse_macros(JsonDocument &in) +{ + auto result = in["result"].as(); + Macros macros = {0}; + macros.macros = (char **)malloc(sizeof(char *) * 32); + macros.count = 0; + macros.success = true; + + for (JsonPair i : result) + { + const char *key = i.key().c_str(); + const char *value = i.value().as().c_str(); + if (strcmp(value, "CYD_SCREEN_MACRO") == 0) + { + char *macro = (char *)malloc(strlen(key) + 1); + strcpy(macro, key); + macros.macros[macros.count++] = macro; + } + } + + if (global_config.sort_macros) + { + std::sort(macros.macros, macros.macros + macros.count, [](const char *a, const char *b) + { return strcmp(a, b) < 0; }); + } + + return macros; +} + +int KlipperPrinter::parse_macros_count(JsonDocument &in) +{ + auto result = in["result"].as(); + + int count = 0; + + for (JsonPair i : result) + { + const char *value = i.value().as().c_str(); + if (strcmp(value, "CYD_SCREEN_MACRO") == 0) + { + count++; + } + } + + return count; +} + +PowerDevices KlipperPrinter::parse_power_devices(JsonDocument &in) +{ + PowerDevices power_devices = {0}; + auto result = in["result"]["devices"].as(); + power_devices.power_devices = (char **)malloc(sizeof(char *) * 16); + power_devices.power_states = (bool *)malloc(sizeof(bool) * 16); + power_devices.count = 0; + power_devices.success = true; + + for (auto i : result) + { + const char *device_name = i["device"]; + const char *device_state = i["status"]; + power_devices.power_devices[power_devices.count] = (char *)malloc(strlen(device_name) + 1); + strcpy(power_devices.power_devices[power_devices.count], device_name); + power_devices.power_states[power_devices.count] = strcmp(device_state, "on") == 0; + power_devices.count++; + } + + return power_devices; +} + +int KlipperPrinter::parse_power_devices_count(JsonDocument &in) +{ + auto result = in["result"]["devices"].as(); + int count = 0; + + for (auto i : result) + { + count++; + } + + return count; +} + +void KlipperPrinter::parse_file_list(JsonDocument &in, std::list &files, int fetch_limit) +{ + auto result = in["result"].as(); + + for (auto file : result) + { + FileSystemFile f = {0}; + const char *path = file["path"]; + float modified = file["modified"]; + auto file_iter = files.begin(); + + while (file_iter != files.end()) + { + if ((*file_iter).modified < modified) + break; + + file_iter++; + } + + if (file_iter == files.end() && files.size() >= fetch_limit) + continue; + + f.name = (char *)malloc(strlen(path) + 1); + if (f.name == NULL) + { + LOG_LN("Failed to allocate memory"); + continue; + } + strcpy(f.name, path); + f.modified = modified; + + if (file_iter != files.end()) + files.insert(file_iter, f); + else + files.push_back(f); + + if (files.size() > fetch_limit) + { + auto last_entry = files.back(); + + if (last_entry.name != NULL) + free(last_entry.name); + + files.pop_back(); + } + } +} + +char *KlipperPrinter::parse_thumbnails(JsonDocument &in) +{ + auto result = in["result"].as(); + const char *chosen_thumb = NULL; + for (auto file : result) + { + int width = file["width"]; + int height = file["height"]; + int size = file["size"]; + const char *thumbnail = file["thumbnail_path"]; + + if (width != height || width != 32) + continue; + + if (strcmp(thumbnail + strlen(thumbnail) - 4, ".png")) + continue; + + chosen_thumb = thumbnail; + break; + } + + if (chosen_thumb != NULL) + { + char* img_filename_path = (char *)malloc(strlen(chosen_thumb) + 1); + strcpy(img_filename_path, chosen_thumb); + return img_filename_path; + } + + return NULL; +} \ No newline at end of file