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
lib64
__pycache__/

View File

@@ -110,6 +110,83 @@ bool make_serial_request(JsonDocument &out, int timeout_ms, HttpRequestType requ
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)
{
JsonDocument doc;
@@ -285,14 +362,38 @@ bool SerialKlipperPrinter::start_file(const char* filename)
{
JsonDocument doc;
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)
{
// TODO: Stubbed
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;
}
@@ -311,6 +412,30 @@ bool SerialKlipperPrinter::send_gcode(const char* gcode, bool wait)
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)
{
serial_console::global_disable_serial_console = true;

View File

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

View File

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

View File

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

View File

@@ -30,7 +30,7 @@ def main():
# Read a line from the serial port
if ser.in_waiting > 0:
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}")
# Parse the parameters
try:
@@ -38,6 +38,7 @@ def main():
timeout_ms, request_type, url_path = int(parts[1]), parts[2], parts[3]
ignore_timeout = timeout_ms <= 0
binary = line.startswith("HTTP_BINARY")
if ignore_timeout:
timeout_ms = 1000;
@@ -57,6 +58,15 @@ def main():
# Send response back over serial
if response != None:
if binary:
if response.status_code != 200:
write("00000000", 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}"