From 747ff4c79ca2c9e8e63a9f06c3e04a6c8adf18e0 Mon Sep 17 00:00:00 2001 From: suchmememanyskill <38142618+suchmememanyskill@users.noreply.github.com> Date: Sat, 9 Nov 2024 00:09:48 +0100 Subject: [PATCH] More serial --- CYD-Klipper/platformio.ini | 1 + CYD-Klipper/src/core/data_setup.cpp | 4 + .../serial_klipper_printer_integration.cpp | 167 ++++++++++++++---- .../serial_klipper_printer_integration.hpp | 8 +- CYD-Klipper/src/main.cpp | 5 - CYD-Klipper/src/ui/ip_setup.cpp | 54 ++++++ CYD-Klipper/src/ui/panels/files_panel.cpp | 2 +- CYD-Klipper/src/ui/panels/move_panel.cpp | 2 + CYD-Klipper/src/ui/serial/serial_console.cpp | 6 +- CYD-Klipper/src/ui/serial/serial_console.h | 2 + 10 files changed, 202 insertions(+), 49 deletions(-) diff --git a/CYD-Klipper/platformio.ini b/CYD-Klipper/platformio.ini index 22a63af..50bed7f 100644 --- a/CYD-Klipper/platformio.ini +++ b/CYD-Klipper/platformio.ini @@ -13,6 +13,7 @@ platform = espressif32@6.4.0 board = esp32dev framework = arduino monitor_speed = 115200 +debug_build_flags = -Os lib_deps = https://github.com/suchmememanyskill/esp32-smartdisplay#9c1d737 bblanchon/ArduinoJson@^7.0.0 diff --git a/CYD-Klipper/src/core/data_setup.cpp b/CYD-Klipper/src/core/data_setup.cpp index bbf7216..cda1c79 100644 --- a/CYD-Klipper/src/core/data_setup.cpp +++ b/CYD-Klipper/src/core/data_setup.cpp @@ -4,6 +4,7 @@ #include #include "printer_integration.hpp" #include "klipper/klipper_printer_integration.hpp" +#include "klipper-serial/serial_klipper_printer_integration.hpp" #include "bambu/bambu_printer_integration.hpp" SemaphoreHandle_t freezeRenderThreadSemaphore, freezeRequestThreadSemaphore; @@ -122,6 +123,9 @@ void data_setup() case PrinterType::PrinterTypeBambuLocal: available_printers[count++] = new BambuPrinter(i); break; + case PrinterType::PrinterTypeKlipperSerial: + available_printers[count++] = new SerialKlipperPrinter(i); + break; } } } diff --git a/CYD-Klipper/src/core/klipper-serial/serial_klipper_printer_integration.cpp b/CYD-Klipper/src/core/klipper-serial/serial_klipper_printer_integration.cpp index 1543b4e..0e2c181 100644 --- a/CYD-Klipper/src/core/klipper-serial/serial_klipper_printer_integration.cpp +++ b/CYD-Klipper/src/core/klipper-serial/serial_klipper_printer_integration.cpp @@ -1,6 +1,32 @@ #include "serial_klipper_printer_integration.hpp" #include #include +#include "../../ui/serial/serial_console.h" + +bool is_semaphores_initialized = false; +SemaphoreHandle_t freeze_serial_thread_semaphore; + +void semaphore_init_serial() +{ + if (is_semaphores_initialized) + { + return; + } + + freeze_serial_thread_semaphore = xSemaphoreCreateMutex(); + xSemaphoreGive(freeze_serial_thread_semaphore); + is_semaphores_initialized = true; +} + +void freeze_serial_thread() +{ + xSemaphoreTake(freeze_serial_thread_semaphore, portMAX_DELAY); +} + +void unfreeze_serial_thread() +{ + xSemaphoreGive(freeze_serial_thread_semaphore); +} enum HttpRequestType { @@ -18,35 +44,37 @@ void clear_serial_buffer() // Request: {timeout} {method} {endpoint} // Response: {status code} {body} -int make_serial_request(JsonDocument &out, int timeout_ms, HttpRequestType requestType, const char* endpoint) +bool make_serial_request(JsonDocument &out, int timeout_ms, HttpRequestType requestType, const char* endpoint) { + semaphore_init_serial(); + freeze_serial_thread(); + serial_console::global_disable_serial_console = true; + temporary_config.debug = false; + char buff[10]; clear_serial_buffer(); + // TODO: Add semaphore here if (!Serial.availableForWrite()) { - return -1; + unfreeze_serial_thread(); + return false; } - char buff[10]; - sprintf(buff, "%d ", timeout_ms); - - // TODO: Maybe use printf? - Serial.write(buff); - Serial.write(requestType == HttpGet ? "GET" : "POST"); - Serial.write(' '); - Serial.write(endpoint); - Serial.write('\n'); + Serial.printf("HTTP_REQUEST %d %s %s\n", timeout_ms, requestType == HttpGet ? "GET" : "POST", endpoint); if (timeout_ms <= 0) { - return 200; + unfreeze_serial_thread(); + return true; } unsigned long _m = millis(); while (!Serial.available() && millis() < _m + timeout_ms + 10) delay(1); if (!Serial.available()) { - return -2; + Serial.println("Timeout..."); + unfreeze_serial_thread(); + return false; } Serial.readBytes(buff, 4); @@ -54,26 +82,39 @@ int make_serial_request(JsonDocument &out, int timeout_ms, HttpRequestType reque if (buff[0] < '0' || buff[0] > '9') { + Serial.println("Invalid error code"); clear_serial_buffer(); - return -3; + unfreeze_serial_thread(); + return false; } int status_code = atoi(buff); if (status_code < 200 || status_code >= 300) { + Serial.println("Non-200 error code"); clear_serial_buffer(); - return -4; + unfreeze_serial_thread(); + return false; } auto result = deserializeJson(out, Serial); - return result == DeserializationError::Ok; + Serial.printf("Deserialization result: %s\n", result.c_str()); + bool success = result == DeserializationError::Ok; + + if (!success) + { + unfreeze_serial_thread(); + } + + return success; } bool make_serial_request_nocontent(HttpRequestType requestType, const char* endpoint) { JsonDocument doc; make_serial_request(doc, 0, requestType, endpoint); + unfreeze_serial_thread(); return true; } @@ -85,7 +126,7 @@ bool SerialKlipperPrinter::connect() bool SerialKlipperPrinter::fetch() { JsonDocument doc; - if (make_serial_request(doc, 1000, HttpGet, "/printer/objects/query?extruder&heater_bed&toolhead&gcode_move&virtual_sdcard&print_stats&webhooks&fan&display_status") == 200) + if (make_serial_request(doc, 1000, HttpGet, "/printer/objects/query?extruder&heater_bed&toolhead&gcode_move&virtual_sdcard&print_stats&webhooks&fan&display_status")) { if (printer_data.state == PrinterStateOffline) { @@ -94,6 +135,7 @@ bool SerialKlipperPrinter::fetch() klipper_request_consecutive_fail_count = 0; parse_state(doc); + unfreeze_serial_thread(); } else { @@ -122,11 +164,11 @@ PrinterDataMinimal SerialKlipperPrinter::fetch_min() data.success = true; - if (make_serial_request(doc, 1000, HttpGet, "/printer/objects/query?webhooks&print_stats&virtual_sdcard") == 200) + if (make_serial_request(doc, 1000, HttpGet, "/printer/objects/query?webhooks&print_stats&virtual_sdcard")) { data.state = PrinterState::PrinterStateIdle; parse_state_min(doc, &data); - doc.clear(); + unfreeze_serial_thread(); data.power_devices = get_power_devices_count(); } else @@ -142,9 +184,10 @@ Macros SerialKlipperPrinter::get_macros() { Macros macros = {0}; JsonDocument doc; - if (make_serial_request(doc, 1000, HttpGet, "/printer/gcode/help") == 200) + if (make_serial_request(doc, 1000, HttpGet, "/printer/gcode/help")) { - return parse_macros(doc); + macros = parse_macros(doc); + unfreeze_serial_thread(); } return macros; @@ -153,9 +196,11 @@ Macros SerialKlipperPrinter::get_macros() int SerialKlipperPrinter::get_macros_count() { JsonDocument doc; - if (make_serial_request(doc, 1000, HttpGet, "/printer/gcode/help") == 200) + if (make_serial_request(doc, 1000, HttpGet, "/printer/gcode/help")) { - return parse_macros_count(doc); + int count = parse_macros_count(doc); + unfreeze_serial_thread(); + return count; } return 0; @@ -165,9 +210,10 @@ PowerDevices SerialKlipperPrinter::get_power_devices() { PowerDevices power_devices = {0}; JsonDocument doc; - if (make_serial_request(doc, 1000, HttpGet, "/machine/device_power/devices") == 200) + if (make_serial_request(doc, 1000, HttpGet, "/machine/device_power/devices")) { - return parse_power_devices(doc); + power_devices = parse_power_devices(doc); + unfreeze_serial_thread(); } return power_devices; @@ -176,9 +222,11 @@ PowerDevices SerialKlipperPrinter::get_power_devices() int SerialKlipperPrinter::get_power_devices_count() { JsonDocument doc; - if (make_serial_request(doc, 1000, HttpGet, "/machine/device_power/devices") == 200) + if (make_serial_request(doc, 1000, HttpGet, "/machine/device_power/devices")) { - return parse_power_devices_count(doc); + int count = parse_power_devices_count(doc); + unfreeze_serial_thread(); + return count; } return 0; @@ -186,24 +234,58 @@ int SerialKlipperPrinter::get_power_devices_count() bool SerialKlipperPrinter::set_power_device_state(const char* device_name, bool state) { - JsonDocument doc; String request = "/machine/device_power/device?device=" + urlEncode(device_name) + "&action=" + (state ? "on" : "off"); - return make_serial_request(doc, 1000, HttpPost, request.c_str()); + return make_serial_request_nocontent(HttpGet, request.c_str()); } Files SerialKlipperPrinter::get_files() { - // TODO: Stubbed - Files files = {0}; - files.success = false; - return files; + Files files_result = {0}; + files_result.success = false; + JsonDocument doc; + LOG_F(("Heap space pre-file-parse: %d bytes\n", esp_get_free_heap_size())); + std::list files; + + auto timer_request = millis(); + bool result = make_serial_request(doc, 5000, HttpGet, "/server/files/list"); + auto timer_parse = millis(); + + if (!result) + { + return files_result; + } + + parse_file_list(doc, files, 20); + unfreeze_serial_thread(); + + files_result.available_files = (char**)malloc(sizeof(char*) * files.size()); + + if (files_result.available_files == NULL){ + LOG_LN("Failed to allocate memory"); + + for (auto file : files){ + free(file.name); + } + + return files_result; + } + + for (auto file : files){ + files_result.available_files[files_result.count++] = file.name; + } + + files_result.success = true; + + LOG_F(("Heap space post-file-parse: %d bytes\n", esp_get_free_heap_size())) + LOG_F(("Got %d files. Request took %dms, parsing took %dms\n", files.size(), timer_parse - timer_request, millis() - timer_parse)) + return files_result; } bool SerialKlipperPrinter::start_file(const char* filename) { JsonDocument doc; String request = "/printer/print/start?filename=" + urlEncode(filename); - return make_serial_request(doc, 1000, HttpPost, request.c_str()); + return make_serial_request_nocontent(HttpGet, request.c_str());; } Thumbnail SerialKlipperPrinter::get_32_32_png_image_thumbnail(const char* gcode_filename) @@ -218,16 +300,25 @@ bool SerialKlipperPrinter::send_gcode(const char* gcode, bool wait) { JsonDocument doc; String request = "/printer/gcode/script?script=" + urlEncode(gcode); - return wait - ? make_serial_request(doc, 5000, HttpGet, request.c_str()) - : make_serial_request_nocontent(HttpGet, request.c_str()); + + if (!wait) + { + return make_serial_request_nocontent(HttpGet, request.c_str()); + } + + bool result = make_serial_request(doc, 5000, HttpGet, request.c_str()); + unfreeze_serial_thread(); + return result; } KlipperConnectionStatus connection_test_serial_klipper(PrinterConfiguration* config) { + serial_console::global_disable_serial_console = true; + temporary_config.debug = false; JsonDocument doc; - if (make_serial_request(doc, 1000, HttpGet, "/printer/info") != 200) + if (make_serial_request(doc, 1000, HttpGet, "/printer/info")) { + unfreeze_serial_thread(); return KlipperConnectionStatus::ConnectOk; } diff --git a/CYD-Klipper/src/core/klipper-serial/serial_klipper_printer_integration.hpp b/CYD-Klipper/src/core/klipper-serial/serial_klipper_printer_integration.hpp index 09e680b..022de5b 100644 --- a/CYD-Klipper/src/core/klipper-serial/serial_klipper_printer_integration.hpp +++ b/CYD-Klipper/src/core/klipper-serial/serial_klipper_printer_integration.hpp @@ -4,9 +4,7 @@ class SerialKlipperPrinter : public KlipperPrinter { public: SerialKlipperPrinter(int index) : KlipperPrinter(index) - { - - } + {} bool connect(); bool fetch(); @@ -20,4 +18,6 @@ class SerialKlipperPrinter : public KlipperPrinter bool start_file(const char* filename); Thumbnail get_32_32_png_image_thumbnail(const char* gcode_filename); bool send_gcode(const char* gcode, bool wait = true); -}; \ No newline at end of file +}; + +KlipperConnectionStatus connection_test_serial_klipper(PrinterConfiguration* config); \ No newline at end of file diff --git a/CYD-Klipper/src/main.cpp b/CYD-Klipper/src/main.cpp index 900b24d..a170329 100644 --- a/CYD-Klipper/src/main.cpp +++ b/CYD-Klipper/src/main.cpp @@ -18,16 +18,11 @@ void setup() { screen_setup(); lv_setup(); LOG_LN("Screen init done"); - LOG_F(("Free heap: %d bytes\n", esp_get_free_heap_size())); wifi_init(); - LOG_F(("Free heap after wifi setup: %d bytes\n", esp_get_free_heap_size())); ota_init(); - LOG_F(("Free heap after ota setup: %d bytes\n", esp_get_free_heap_size())); ip_init(); - LOG_F(("Free heap after ip setup: %d bytes\n", esp_get_free_heap_size())); data_setup(); - LOG_F(("Free heap after data setup: %d bytes\n", esp_get_free_heap_size())); nav_style_setup(); main_ui_setup(); diff --git a/CYD-Klipper/src/ui/ip_setup.cpp b/CYD-Klipper/src/ui/ip_setup.cpp index 0f2c27d..cdf11eb 100644 --- a/CYD-Klipper/src/ui/ip_setup.cpp +++ b/CYD-Klipper/src/ui/ip_setup.cpp @@ -11,6 +11,7 @@ #include "../core/klipper/klipper_printer_integration.hpp" #include "../core/bambu/bambu_printer_integration.hpp" #include "../core/screen_driver.h" +#include "../core/klipper-serial/serial_klipper_printer_integration.hpp" void show_ip_entry(); void choose_printer_type(); @@ -57,6 +58,26 @@ static void btn_switch_printer(lv_event_t *e){ lv_obj_del(lv_obj_get_parent(lv_obj_get_parent(btn))); } +long last_request = 0; + +void serial_check_connection() +{ + if ((millis() - last_request) < 5000) + { + return; + } + + auto result = connection_test_serial_klipper(&global_config.printer_config[global_config.printer_index]); + last_request = millis(); + + if (result == KlipperConnectionStatus::ConnectOk) + { + global_config.printer_config[global_config.printer_index].setup_complete = true; + strcpy(global_config.printer_config[global_config.printer_index].klipper_host, "Serial"); + write_global_config(); + } +} + void switch_printer_init() { lv_obj_t * parent = lv_create_empty_panel(lv_scr_act()); lv_obj_set_style_bg_opa(parent, LV_OPA_100, 0); @@ -338,6 +359,20 @@ void show_ip_entry() lv_textarea_set_placeholder_text(port_entry, "Access code"); lv_textarea_set_placeholder_text(auth_entry, "Printer serial number"); break; + case PrinterType::PrinterTypeKlipperSerial: + lv_label_set_text(main_label, "Klipper (Serial) Setup"); + lv_obj_del(ip_row); + lv_obj_del(auth_row); + lv_obj_del(keyboard); + + lv_obj_t * bottom_root = lv_create_empty_panel(top_root); + lv_obj_set_width(bottom_root, CYD_SCREEN_WIDTH_PX); + lv_obj_set_flex_grow(bottom_root, 1); + + label = lv_label_create(bottom_root); + lv_obj_center(label); + lv_label_set_text(label, "Connect CYD-Klipper to a host\nrunning the CYD-Klipper server"); + break; } } @@ -353,6 +388,12 @@ static void printer_type_bambu_local(lv_event_t * e) show_ip_entry(); } +static void printer_type_serial_klipper(lv_event_t * e) +{ + global_config.printer_config[global_config.printer_index].printer_type = PrinterType::PrinterTypeKlipperSerial; + show_ip_entry(); +} + void choose_printer_type() { lv_obj_clean(lv_scr_act()); @@ -377,6 +418,14 @@ void choose_printer_type() lv_label_set_text(label, "Klipper"); lv_obj_center(label); + btn = lv_btn_create(root); + lv_obj_set_size(btn, CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 2, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX); + lv_obj_add_event_cb(btn, printer_type_serial_klipper, LV_EVENT_CLICKED, NULL); + + label = lv_label_create(btn); + lv_label_set_text(label, "Klipper (Serial)"); + lv_obj_center(label); + btn = lv_btn_create(root); lv_obj_set_size(btn, CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 2, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX); lv_obj_add_event_cb(btn, printer_type_bambu_local, LV_EVENT_CLICKED, NULL); @@ -401,6 +450,11 @@ void ip_init(){ while (!global_config.printer_config[global_config.printer_index].setup_complete) { + if (global_config.printer_config[global_config.printer_index].printer_type == PrinterType::PrinterTypeKlipperSerial) + { + serial_check_connection(); + } + lv_handler(); serial_console::run(); } diff --git a/CYD-Klipper/src/ui/panels/files_panel.cpp b/CYD-Klipper/src/ui/panels/files_panel.cpp index 87aa77e..5c312a4 100644 --- a/CYD-Klipper/src/ui/panels/files_panel.cpp +++ b/CYD-Klipper/src/ui/panels/files_panel.cpp @@ -72,7 +72,7 @@ static void btn_print_file_verify(lv_event_t * e){ lv_img_dsc_t* img_header = (lv_img_dsc_t*)malloc(sizeof(lv_img_dsc_t)); lv_obj_on_destroy_free_data(panel, img_header); - memset(img_header, 0, sizeof(img_header)); + memset(img_header, 0, sizeof(lv_img_dsc_t)); img_header->header.w = 32; img_header->header.h = 32; img_header->data_size = thumbnail.size; diff --git a/CYD-Klipper/src/ui/panels/move_panel.cpp b/CYD-Klipper/src/ui/panels/move_panel.cpp index 6952379..e4d2561 100644 --- a/CYD-Klipper/src/ui/panels/move_panel.cpp +++ b/CYD-Klipper/src/ui/panels/move_panel.cpp @@ -167,7 +167,9 @@ static void home_button_click(lv_event_t * e) { if (get_current_printer_data()->state == PrinterState::PrinterStatePrinting) return; + freeze_request_thread(); get_current_printer()->execute_feature(PrinterFeatures::PrinterFeatureHome); + unfreeze_request_thread(); } static void disable_steppers_click(lv_event_t * e) { diff --git a/CYD-Klipper/src/ui/serial/serial_console.cpp b/CYD-Klipper/src/ui/serial/serial_console.cpp index dc55551..0615cee 100644 --- a/CYD-Klipper/src/ui/serial/serial_console.cpp +++ b/CYD-Klipper/src/ui/serial/serial_console.cpp @@ -8,6 +8,7 @@ namespace serial_console { + bool global_disable_serial_console = false; /* * read_string_until: Non-blocking replacement for Serial.readStringUntil().. @@ -26,7 +27,7 @@ namespace serial_console { --cnt; - // backspace + // backspaceF if (c == 8) { if (index > 0) @@ -131,6 +132,9 @@ namespace serial_console // main "engine": non-blockingly read until newline found, parse, execute. void run() { + if (global_disable_serial_console) + return; + static char cmdline[MAX_COMDLINE_SIZE + 1] = {0}; if (!read_string_until('\n', cmdline, MAX_COMDLINE_SIZE)) return; diff --git a/CYD-Klipper/src/ui/serial/serial_console.h b/CYD-Klipper/src/ui/serial/serial_console.h index 31cd10c..e044c6e 100644 --- a/CYD-Klipper/src/ui/serial/serial_console.h +++ b/CYD-Klipper/src/ui/serial/serial_console.h @@ -5,4 +5,6 @@ namespace serial_console { void greet(); void run(); +extern bool global_disable_serial_console; + } \ No newline at end of file