mirror of
https://github.com/suchmememanyskill/CYD-Klipper.git
synced 2026-03-21 05:33:24 +00:00
More work
This commit is contained in:
3
CYD-Klipper/.vscode/settings.json
vendored
3
CYD-Klipper/.vscode/settings.json
vendored
@@ -14,7 +14,8 @@
|
||||
"functional": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"cmath": "cpp",
|
||||
"system_error": "cpp"
|
||||
"system_error": "cpp",
|
||||
"random": "cpp"
|
||||
},
|
||||
"cmake.configureOnOpen": false
|
||||
}
|
||||
@@ -3,12 +3,11 @@
|
||||
#include <HTTPClient.h>
|
||||
#include <UrlEncode.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <list>
|
||||
|
||||
void KlipperPrinter::configure_http_client(HTTPClient &client, String url_part, bool stream, int timeout)
|
||||
{
|
||||
if (stream){
|
||||
client.useHTTP10(true);
|
||||
}
|
||||
client.useHTTP10(stream);
|
||||
|
||||
if (timeout > 0){
|
||||
client.setTimeout(timeout);
|
||||
@@ -29,9 +28,9 @@ int KlipperPrinter::get_slicer_time_estimate_s()
|
||||
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/server/files/metadata?filename=" + urlEncode(printer_data.print_filename), true, 5000);
|
||||
int httpCode = client.GET();
|
||||
int http_code = client.GET();
|
||||
|
||||
if (httpCode != 200)
|
||||
if (http_code != 200)
|
||||
return 0;
|
||||
|
||||
JsonDocument doc;
|
||||
@@ -165,10 +164,10 @@ bool KlipperPrinter::connect()
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/printer/info", false, 1000);
|
||||
|
||||
int httpCode;
|
||||
int http_code;
|
||||
try {
|
||||
httpCode = client.GET();
|
||||
return httpCode == 200;
|
||||
http_code = client.GET();
|
||||
return http_code == 200;
|
||||
}
|
||||
catch (...) {
|
||||
LOG_LN("Failed to connect");
|
||||
@@ -181,8 +180,8 @@ bool KlipperPrinter::fetch()
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/printer/objects/query?extruder&heater_bed&toolhead&gcode_move&virtual_sdcard&print_stats&webhooks&fan&display_status", true, 1000);
|
||||
|
||||
int httpCode = client.GET();
|
||||
if (httpCode == 200)
|
||||
int http_code = client.GET();
|
||||
if (http_code == 200)
|
||||
{
|
||||
if (printer_data.state == PrinterStateOffline)
|
||||
{
|
||||
@@ -367,7 +366,7 @@ bool KlipperPrinter::fetch()
|
||||
else
|
||||
{
|
||||
klipper_request_consecutive_fail_count++;
|
||||
LOG_F(("Failed to fetch printer data: %d\n", httpCode));
|
||||
LOG_F(("Failed to fetch printer data: %d\n", http_code));
|
||||
|
||||
if (klipper_request_consecutive_fail_count >= 5)
|
||||
{
|
||||
@@ -399,8 +398,8 @@ PrinterDataMinimal KlipperPrinter::fetch_min()
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/printer/objects/query?webhooks&print_stats&virtual_sdcard", true, 1000);
|
||||
|
||||
int httpCode = client.GET();
|
||||
if (httpCode == 200)
|
||||
int http_code = client.GET();
|
||||
if (http_code == 200)
|
||||
{
|
||||
data.state = PrinterStateIdle;
|
||||
data.power_devices = get_power_devices_count();
|
||||
@@ -459,19 +458,356 @@ PrinterDataMinimal KlipperPrinter::fetch_min()
|
||||
void KlipperPrinter::disconnect()
|
||||
{
|
||||
// Nothing to disconnect, everything is http request based
|
||||
}
|
||||
|
||||
if (printer_data.state_message != NULL)
|
||||
{
|
||||
free(printer_data.state_message);
|
||||
Macros KlipperPrinter::get_macros()
|
||||
{
|
||||
HTTPClient client;
|
||||
Macros macros;
|
||||
|
||||
configure_http_client(client, "/printer/gcode/help", true, 1000);
|
||||
int http_code = client.GET();
|
||||
|
||||
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 (printer_data.print_filename != NULL)
|
||||
if (global_config->sort_macros)
|
||||
{
|
||||
free(printer_data.print_filename);
|
||||
std::sort(macros.macros, macros.macros + macros.count, [](const char* a, const char* b) {
|
||||
return strcmp(a, b) < 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (printer_data.popup_message != NULL)
|
||||
{
|
||||
free(printer_data.popup_message);
|
||||
return macros;
|
||||
}
|
||||
|
||||
int KlipperPrinter::get_macros_count()
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/printer/gcode/help", true, 1000);
|
||||
|
||||
int http_code = client.GET();
|
||||
|
||||
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;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool KlipperPrinter::execute_macro(const char* macro)
|
||||
{
|
||||
return send_gcode(macro);
|
||||
}
|
||||
|
||||
PowerDevices KlipperPrinter::get_power_devices()
|
||||
{
|
||||
HTTPClient client;
|
||||
PowerDevices power_devices;
|
||||
configure_http_client(client, "/machine/device_power/devices", true, 1000);
|
||||
|
||||
int http_code = client.GET();
|
||||
|
||||
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 power_devices;
|
||||
}
|
||||
|
||||
int KlipperPrinter::get_power_devices_count()
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/machine/device_power/devices", true, 1000);
|
||||
|
||||
int http_code = client.GET();
|
||||
|
||||
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;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool KlipperPrinter::set_power_device_state(const char* device_name, bool state)
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/machine/device_power/device?device=" + urlEncode(device_name) + "&action=" + (state ? "on" : "off"), true, 1000);
|
||||
return client.POST("") == 200;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
float modified;
|
||||
} FileSystemFile;
|
||||
|
||||
#define KLIPPER_FILE_FETCH_LIMIT 20
|
||||
|
||||
Files KlipperPrinter::get_files()
|
||||
{
|
||||
Files files_result;
|
||||
HTTPClient client;
|
||||
LOG_F(("Heap space pre-file-parse: %d bytes\n", esp_get_free_heap_size()))
|
||||
std::list<FileSystemFile> files;
|
||||
|
||||
auto timer_request = millis();
|
||||
configure_http_client(client, "/server/files/list", true, 5000);
|
||||
|
||||
int http_code = client.GET();
|
||||
auto timer_parse = millis();
|
||||
|
||||
if (http_code == 200){
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 KlipperPrinter::start_file(const char *filename)
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/printer/print/start?filename=" + urlEncode(filename), false, 1000);
|
||||
|
||||
int httpCode = client.POST("");
|
||||
LOG_F(("Print start: HTTP %d\n", httpCode))
|
||||
}
|
||||
|
||||
bool KlipperPrinter::set_target_temperature(PrinterTemperatureDevice device, float temperature)
|
||||
{
|
||||
char gcode[64] = {0};
|
||||
|
||||
switch (device)
|
||||
{
|
||||
case PrinterTemperatureDeviceBed:
|
||||
sprintf(gcode, "M140 S%d", temperature);
|
||||
break;
|
||||
case PrinterTemperatureDeviceNozzle1:
|
||||
sprintf(gcode, "M104 S%d", temperature);
|
||||
break;
|
||||
default:
|
||||
LOG_F(("Unknown temperature device %d was requested to heat to %.2f", device, temperature));
|
||||
return false;
|
||||
}
|
||||
|
||||
return send_gcode(gcode);
|
||||
}
|
||||
|
||||
unsigned char* KlipperPrinter::get_32_32_png_image_thumbnail(const char* gcode_filename)
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/server/files/thumbnails?filename=", true, 1000);
|
||||
char* img_filename_path = NULL;
|
||||
unsigned char* data_png = NULL;
|
||||
|
||||
int http_code = 0;
|
||||
try
|
||||
{
|
||||
http_code = client.GET();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_LN("Exception while fetching gcode img location");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (http_code == 200)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_F(("Failed to fetch gcode image data: %d\n", http_code))
|
||||
}
|
||||
|
||||
if (img_filename_path == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
client.end();
|
||||
|
||||
configure_http_client(client, "/server/files/gcodes/" + urlEncode(img_filename_path), false, 2000);
|
||||
|
||||
int http_code = 0;
|
||||
try
|
||||
{
|
||||
http_code = client.GET();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_LN("Exception while fetching gcode img");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (http_code == 200)
|
||||
{
|
||||
size_t len = client.getSize();
|
||||
if (len <= 0)
|
||||
{
|
||||
LOG_LN("No gcode img data");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data_png = (unsigned char*)malloc(len + 1);
|
||||
|
||||
if (data_png != NULL)
|
||||
{
|
||||
if (len != client.getStream().readBytes(data_png, len))
|
||||
{
|
||||
LOG_LN("Failed to read gcode img data");
|
||||
free(data_png);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(img_filename_path);
|
||||
return data_png;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(img_filename_path);
|
||||
return NULL;
|
||||
}
|
||||
@@ -43,7 +43,8 @@ class KlipperPrinter : BasePrinter
|
||||
int get_power_devices_count();
|
||||
bool set_power_device_state(const char* device_name, bool state);
|
||||
Files get_files();
|
||||
bool start_file(const char* file);
|
||||
bool start_file(const char* filename);
|
||||
unsigned char* get_32_32_png_image_thumbnail(const char* gcode_filename);
|
||||
bool set_target_temperature(PrinterTemperatureDevice device, float temperature);
|
||||
bool send_gcode(const char* gcode, bool wait = true);
|
||||
int get_slicer_time_estimate_s();
|
||||
|
||||
@@ -106,14 +106,14 @@ typedef struct {
|
||||
} PrinterDataMinimal;
|
||||
|
||||
typedef struct {
|
||||
const char** macros;
|
||||
char** macros;
|
||||
unsigned int count;
|
||||
bool success;
|
||||
} Macros;
|
||||
|
||||
typedef struct {
|
||||
const char** power_devices;
|
||||
const bool* power_states;
|
||||
char** power_devices;
|
||||
bool* power_states;
|
||||
unsigned int count;
|
||||
bool success;
|
||||
} PowerDevices;
|
||||
@@ -125,8 +125,8 @@ typedef struct {
|
||||
} Files;
|
||||
|
||||
typedef struct {
|
||||
lv_event_ct_b set_label;
|
||||
lv_event_ct_b open_panel;
|
||||
lv_event_cb_t set_label;
|
||||
lv_event_cb_t open_panel;
|
||||
} PrinterUiPanel;
|
||||
|
||||
class BasePrinter
|
||||
@@ -156,7 +156,8 @@ class BasePrinter
|
||||
virtual int get_power_devices_count() = 0;
|
||||
virtual bool set_power_device_state(const char* device_name, bool state) = 0;
|
||||
virtual Files get_files() = 0;
|
||||
virtual bool start_file(const char* file) = 0;
|
||||
virtual bool start_file(const char* filename) = 0;
|
||||
virtual unsigned char* get_32_32_png_image_thumbnail(const char* gcode_filename);
|
||||
virtual bool set_target_temperature(PrinterTemperatureDevice device, float temperature) = 0;
|
||||
|
||||
BasePrinter(unsigned char index);
|
||||
|
||||
@@ -34,6 +34,17 @@ void destroy_event_user_data(lv_event_t * e){
|
||||
lv_obj_del(obj);
|
||||
}
|
||||
|
||||
void destroy_event_free_data(lv_event_t * e)
|
||||
{
|
||||
void* data = lv_event_get_user_data(e);
|
||||
free(data);
|
||||
}
|
||||
|
||||
void on_destroy_free_data(lv_obj_t * element, void* ptr)
|
||||
{
|
||||
lv_obj_add_event_cb(element, destroy_event_free_data, LV_EVENT_DELETE, ptr);
|
||||
}
|
||||
|
||||
void lv_create_fullscreen_button_matrix_popup(lv_obj_t * root, lv_event_cb_t title, lv_button_column_t* columns, int column_count){
|
||||
const auto full_panel_width = CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 3;
|
||||
const auto full_panel_inner_width = full_panel_width - CYD_SCREEN_GAP_PX * 2 - 4;
|
||||
|
||||
@@ -38,6 +38,7 @@ void lv_layout_flex_column(lv_obj_t* obj, lv_flex_align_t allign = LV_FLEX_ALIGN
|
||||
void lv_layout_flex_row(lv_obj_t* obj, lv_flex_align_t allign = LV_FLEX_ALIGN_START, lv_coord_t pad_column = CYD_SCREEN_GAP_PX, lv_coord_t pad_row = CYD_SCREEN_GAP_PX);
|
||||
void lv_create_fullscreen_button_matrix_popup(lv_obj_t * root, lv_event_cb_t title, lv_button_column_t* columns, int column_count);
|
||||
void destroy_event_user_data(lv_event_t * e);
|
||||
void on_destroy_free_data(lv_obj_t * element, void* ptr);
|
||||
void lv_create_keyboard_text_entry(lv_event_cb_t keyboard_callback, const char* title = NULL, lv_keyboard_mode_t keyboard_mode = LV_KEYBOARD_MODE_NUMBER, lv_coord_t width = CYD_SCREEN_PANEL_WIDTH_PX / 2, uint8_t max_length = 3, const char* fill_text = "", bool contain_in_panel= true);
|
||||
void lv_create_custom_menu_entry(const char* label_text, lv_obj_t* object, lv_obj_t* root_panel, bool set_height = true, const char * comment = NULL);
|
||||
void lv_create_custom_menu_button(const char *label_text, lv_obj_t* root_panel, lv_event_cb_t on_click, const char *btn_text, void * user_data = NULL, const char * comment = NULL);
|
||||
|
||||
Reference in New Issue
Block a user