Split json parsing from printer impl

This commit is contained in:
suchmememanyskill
2024-10-28 15:33:17 +01:00
parent 572d27dc8a
commit b1138d9510
4 changed files with 476 additions and 354 deletions

View File

@@ -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
}

View File

@@ -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<JsonObject>();
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<String>().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<JsonObject>();
int count = 0;
for (JsonPair i : result){
const char *value = i.value().as<String>().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<JsonArray>();
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<JsonArray>();
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<JsonArray>();
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<JsonArray>();
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();

View File

@@ -2,6 +2,13 @@
#include "../printer_integration.hpp"
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <list>
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<FileSystemFile> &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 {

View File

@@ -0,0 +1,394 @@
#include "../printer_integration.hpp"
#include "klipper_printer_integration.hpp"
#include <ArduinoJson.h>
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<JsonObject>();
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<String>().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<JsonObject>();
int count = 0;
for (JsonPair i : result)
{
const char *value = i.value().as<String>().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<JsonArray>();
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<JsonArray>();
int count = 0;
for (auto i : result)
{
count++;
}
return count;
}
void KlipperPrinter::parse_file_list(JsonDocument &in, std::list<FileSystemFile> &files, int fetch_limit)
{
auto result = in["result"].as<JsonArray>();
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<JsonArray>();
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;
}