Gcode images, fixes to serial

This commit is contained in:
suchmememanyskill
2024-11-09 01:30:40 +01:00
parent 92b7b68dc5
commit f9444829ee
6 changed files with 151 additions and 12 deletions

1
.gitignore vendored
View File

@@ -8,3 +8,4 @@ out/
lib lib
lib64 lib64
__pycache__/

View File

@@ -110,6 +110,83 @@ bool make_serial_request(JsonDocument &out, int timeout_ms, HttpRequestType requ
return success; return success;
} }
typedef struct
{
int len;
unsigned char* data;
} BinaryResponse;
bool make_binary_request(BinaryResponse* data, 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() || timeout_ms <= 0)
{
unfreeze_serial_thread();
return false;
}
Serial.printf("HTTP_BINARY %d %s %s\n", timeout_ms, requestType == HttpGet ? "GET" : "POST", endpoint);
unsigned long _m = millis();
while (!Serial.available() && millis() < _m + timeout_ms + 10) delay(1);
if (!Serial.available())
{
Serial.println("Timeout...");
unfreeze_serial_thread();
return false;
}
Serial.readBytes(buff, 8);
buff[9] = 0;
if (buff[0] < '0' || buff[0] > '9')
{
Serial.println("Invalid length");
clear_serial_buffer();
unfreeze_serial_thread();
return false;
}
int data_length = atoi(buff);
if (data_length <= 0)
{
Serial.println("0 Length");
clear_serial_buffer();
unfreeze_serial_thread();
return false;
}
data->len = data_length;
data->data = (unsigned char*)malloc(data_length);
if (data->data == NULL)
{
Serial.println("Failed to allocate memory");
clear_serial_buffer();
unfreeze_serial_thread();
return false;
}
bool result = Serial.readBytes((char*)data->data, data_length) == data_length;
unfreeze_serial_thread();
if (!result)
{
free(data->data);
}
return result;
}
bool make_serial_request_nocontent(HttpRequestType requestType, const char* endpoint) bool make_serial_request_nocontent(HttpRequestType requestType, const char* endpoint)
{ {
JsonDocument doc; JsonDocument doc;
@@ -285,14 +362,38 @@ bool SerialKlipperPrinter::start_file(const char* filename)
{ {
JsonDocument doc; JsonDocument doc;
String request = "/printer/print/start?filename=" + urlEncode(filename); String request = "/printer/print/start?filename=" + urlEncode(filename);
return make_serial_request_nocontent(HttpGet, request.c_str());; return make_serial_request_nocontent(HttpPost, request.c_str());;
} }
Thumbnail SerialKlipperPrinter::get_32_32_png_image_thumbnail(const char* gcode_filename) Thumbnail SerialKlipperPrinter::get_32_32_png_image_thumbnail(const char* gcode_filename)
{ {
// TODO: Stubbed
Thumbnail thumbnail = {0}; Thumbnail thumbnail = {0};
thumbnail.success = false; JsonDocument doc;
char* img_filename_path = NULL;
String request = "/server/files/thumbnails?filename=" + urlEncode(gcode_filename);
if (make_serial_request(doc, 1000, HttpGet, request.c_str()))
{
img_filename_path = parse_thumbnails(doc);
unfreeze_serial_thread();
doc.clear();
}
if (img_filename_path == NULL)
{
return thumbnail;
}
request = "/server/files/gcodes/" + urlEncode(img_filename_path);
BinaryResponse data = {0};
if (make_binary_request(&data, 2000, HttpGet, request.c_str()))
{
thumbnail.png = data.data;
thumbnail.size = data.len;
thumbnail.success = true;
}
free(img_filename_path);
return thumbnail; return thumbnail;
} }
@@ -311,6 +412,30 @@ bool SerialKlipperPrinter::send_gcode(const char* gcode, bool wait)
return result; return result;
} }
bool SerialKlipperPrinter::send_emergency_stop()
{
return make_serial_request_nocontent(HttpGet, "/printer/emergency_stop");
}
int SerialKlipperPrinter::get_slicer_time_estimate_s()
{
if (printer_data.state != PrinterStatePrinting && printer_data.state != PrinterStatePaused)
return 0;
String request = "/server/files/metadata?filename=" + urlEncode(printer_data.print_filename);
JsonDocument doc;
if (!make_serial_request(doc, 2000, HttpGet, request.c_str()))
{
return 0;
}
int estimate = parse_slicer_time_estimate(doc);
unfreeze_serial_thread();
return estimate;
}
KlipperConnectionStatus connection_test_serial_klipper(PrinterConfiguration* config) KlipperConnectionStatus connection_test_serial_klipper(PrinterConfiguration* config)
{ {
serial_console::global_disable_serial_console = true; serial_console::global_disable_serial_console = true;

View File

@@ -2,6 +2,9 @@
class SerialKlipperPrinter : public KlipperPrinter class SerialKlipperPrinter : public KlipperPrinter
{ {
protected:
bool send_emergency_stop();
int get_slicer_time_estimate_s();
public: public:
SerialKlipperPrinter(int index) : KlipperPrinter(index) SerialKlipperPrinter(int index) : KlipperPrinter(index)
{} {}

View File

@@ -147,7 +147,7 @@ bool KlipperPrinter::execute_feature(PrinterFeatures feature)
return false; return false;
} }
if (get_current_printer()->printer_config->custom_filament_move_macros) if (printer_config->custom_filament_move_macros)
{ {
return send_gcode("FILAMENT_RETRACT"); return send_gcode("FILAMENT_RETRACT");
} }

View File

@@ -21,8 +21,8 @@ class KlipperPrinter : public BasePrinter
unsigned char lock_absolute_relative_mode_swap{}; unsigned char lock_absolute_relative_mode_swap{};
unsigned char klipper_request_consecutive_fail_count{}; unsigned char klipper_request_consecutive_fail_count{};
bool send_emergency_stop(); virtual bool send_emergency_stop();
int get_slicer_time_estimate_s(); virtual int get_slicer_time_estimate_s();
void init_ui_panels(); void init_ui_panels();
int parse_slicer_time_estimate(JsonDocument& in); int parse_slicer_time_estimate(JsonDocument& in);

View File

@@ -30,7 +30,7 @@ def main():
# Read a line from the serial port # Read a line from the serial port
if ser.in_waiting > 0: if ser.in_waiting > 0:
line = ser.readline().decode('utf-8').strip() line = ser.readline().decode('utf-8').strip()
if line.startswith("HTTP_REQUEST"): if line.startswith("HTTP_REQUEST") or line.startswith("HTTP_BINARY"):
print(f">>> {line}") print(f">>> {line}")
# Parse the parameters # Parse the parameters
try: try:
@@ -38,6 +38,7 @@ def main():
timeout_ms, request_type, url_path = int(parts[1]), parts[2], parts[3] timeout_ms, request_type, url_path = int(parts[1]), parts[2], parts[3]
ignore_timeout = timeout_ms <= 0 ignore_timeout = timeout_ms <= 0
binary = line.startswith("HTTP_BINARY")
if ignore_timeout: if ignore_timeout:
timeout_ms = 1000; timeout_ms = 1000;
@@ -57,10 +58,19 @@ def main():
# Send response back over serial # Send response back over serial
if response != None: if response != None:
status_code = response.status_code if binary:
body = response.text.replace('\n', ' ') # Trim and sanitize body for serial if response.status_code != 200:
message = f"{status_code} {body}" write("00000000", not ignore_timeout)
write(message, not ignore_timeout) else:
length = len(response.content)
ser.write(f"{length:>08}".encode('utf-8'))
ser.write(response.content)
print(f"<<< (Binary data of {length} bytes)")
else:
status_code = response.status_code
body = response.text.replace('\n', ' ') # Trim and sanitize body for serial
message = f"{status_code} {body}"
write(message, not ignore_timeout)
except (IndexError, ValueError) as e: except (IndexError, ValueError) as e:
write(f"400 Malformed request {str(e)}", not ignore_timeout) write(f"400 Malformed request {str(e)}", not ignore_timeout)
except requests.exceptions.ReadTimeout as e: except requests.exceptions.ReadTimeout as e: