feat(printer): add direct thermal backend and debug controls

This commit is contained in:
admin
2026-02-26 17:48:28 +08:00
parent e7aa0e75bf
commit 2b6bcc83dc
17 changed files with 1866 additions and 86 deletions

View File

@@ -22,6 +22,7 @@ esp_err_t rest_server_print_submit_raster_job_and_reply(httpd_req_t *req,
uint16_t width,
uint16_t height,
const char *density,
bool direct_ignore_precheck,
const char *warning,
const char *trace_id);

View File

@@ -53,12 +53,31 @@ static const char *s_web_index =
"\n"
" <label>Printer Name</label>\n"
" <input id='printerName' type='text' value='TQPrinter'>\n"
" <label>Printer Backend</label>\n"
" <select id='printerBackend' style='max-width:220px'>\n"
" <option value='direct' selected>Direct (GPIO)</option>\n"
" <option value='ble'>BLE</option>\n"
" </select>\n"
" <div class='row'>\n"
" <button id='btnConnect'>Connect Printer</button>\n"
" <button id='btnAutoConnect' class='alt'>Auto Connect</button>\n"
" <button id='btnDisconnect' class='warn'>Disconnect</button>\n"
" </div>\n"
"\n"
" <label>Paper Detect</label>\n"
" <div class='row'>\n"
" <button id='btnPaperCheck' class='alt'>Check Paper</button>\n"
" </div>\n"
" <div id='paperState' class='small'>纸张状态:未知</div>\n"
" <div id='paperMeta' class='small'>Backend: -, Connected: -, Transport: -, GPIO: -, Expect: -</div>\n"
" <div class='row'>\n"
" <label style='margin:0;display:flex;align-items:center;gap:6px;'>\n"
" <input id='ignorePrecheck' type='checkbox' style='width:auto;'>\n"
" Ignore direct precheck (paper/temp/battery)\n"
" </label>\n"
" </div>\n"
" <div class='small'>Only effective on Direct backend. Use for sensor bring-up/debug.</div>\n"
"\n"
" <label>Text to Print</label>\n"
" <textarea id='printText'>Hello from ESP32-S3!\nOrder: A1024\nThank you</textarea>\n"
" <div class='row'>\n"
@@ -121,6 +140,10 @@ static const char *s_web_index =
" const out = document.getElementById('out');\n"
" const apiKeyEl = document.getElementById('apiKey');\n"
" const printerNameEl = document.getElementById('printerName');\n"
" const printerBackendEl = document.getElementById('printerBackend');\n"
" const paperStateEl = document.getElementById('paperState');\n"
" const paperMetaEl = document.getElementById('paperMeta');\n"
" const ignorePrecheckEl = document.getElementById('ignorePrecheck');\n"
" const printTextEl = document.getElementById('printText');\n"
" const imagePromptEl = document.getElementById('imagePrompt');\n"
" const imgSizeEl = document.getElementById('imgSize');\n"
@@ -168,6 +191,46 @@ static const char *s_web_index =
" return new Promise((resolve) => setTimeout(resolve, ms));\n"
" }\n"
"\n"
" function selectedPrinterBackend() {\n"
" const v = (printerBackendEl && printerBackendEl.value) ? String(printerBackendEl.value).toLowerCase() : 'ble';\n"
" return v === 'direct' ? 'direct' : 'ble';\n"
" }\n"
"\n"
" function selectedIgnorePrecheck() {\n"
" return !!(ignorePrecheckEl && ignorePrecheckEl.checked);\n"
" }\n"
"\n"
" function syncPaperUi(st) {\n"
" if (!paperStateEl || !paperMetaEl) {\n"
" return;\n"
" }\n"
" if (!st || typeof st !== 'object') {\n"
" paperStateEl.textContent = '纸张状态:未知';\n"
" paperMetaEl.textContent = 'Backend: -, Connected: -, Transport: -, GPIO: -, Expect: -';\n"
" return;\n"
" }\n"
"\n"
" const hasPaper = !!st.has_paper;\n"
" paperStateEl.textContent = hasPaper ? '纸张状态:有纸' : '纸张状态:缺纸';\n"
"\n"
" const backend = st.printer_backend ? String(st.printer_backend) : '-';\n"
" const connected = !!st.printer_connected;\n"
" const transportReady = !!st.printer_transport_ready;\n"
" const paperLevel = (st.paper_gpio_level === undefined || st.paper_gpio_level === null) ? '-' : String(st.paper_gpio_level);\n"
" const paperExpect = (st.paper_present_level === undefined || st.paper_present_level === null) ? '-' : String(st.paper_present_level);\n"
" paperMetaEl.textContent = 'Backend: ' + backend + ', Connected: ' + connected + ', Transport: ' + transportReady + ', GPIO: ' + paperLevel + ', Expect: ' + paperExpect;\n"
"\n"
" if (printerBackendEl && (backend === 'ble' || backend === 'direct')) {\n"
" printerBackendEl.value = backend;\n"
" }\n"
" }\n"
"\n"
" async function fetchPrinterStatus() {\n"
" const st = await callApi('/v1/printer/status', 'GET');\n"
" syncPaperUi(st);\n"
" return st;\n"
" }\n"
"\n"
" function voiceRoundBusy(st) {\n"
" if (!st) return false;\n"
" const state = (st.voice_dialog_state || '').toLowerCase();\n"
@@ -363,6 +426,7 @@ static const char *s_web_index =
" threshold: toInt(imgThresholdEl.value, 160, 0, 255),\n"
" max_height: toInt(imgMaxHeightEl.value, 2200, 64, 3000),\n"
" density: imgDensityEl.value || '中等',\n"
" ignore_precheck: selectedIgnorePrecheck(),\n"
" scale_to_width: imgScaleToWidthEl.checked,\n"
" invert: imgInvertEl.checked,\n"
" timeout_ms: toInt(imgTimeoutEl.value, 45000, 5000, 180000),\n"
@@ -393,24 +457,41 @@ static const char *s_web_index =
" }\n"
"\n"
" document.getElementById('btnHealth').onclick = () => run(() => callApi('/v1/health', 'GET'));\n"
" document.getElementById('btnStatus').onclick = () => run(() => callApi('/v1/printer/status', 'GET'));\n"
" document.getElementById('btnStatus').onclick = () => run(() => fetchPrinterStatus());\n"
" document.getElementById('btnJobs').onclick = () => run(() => callApi('/v1/jobs', 'GET'));\n"
"\n"
" document.getElementById('btnConnect').onclick = () => run(() => callApi('/v1/printer/connect', 'POST', {\n"
" name: printerNameEl.value.trim() || 'TQPrinter',\n"
" timeout_ms: 15000\n"
" }));\n"
" document.getElementById('btnConnect').onclick = () => run(async () => {\n"
" const data = await callApi('/v1/printer/connect', 'POST', {\n"
" backend: selectedPrinterBackend(),\n"
" name: printerNameEl.value.trim() || 'TQPrinter',\n"
" timeout_ms: 15000\n"
" });\n"
" syncPaperUi(data);\n"
" return data;\n"
" });\n"
"\n"
" document.getElementById('btnAutoConnect').onclick = () => run(() => callApi('/v1/printer/connect', 'POST', {\n"
" name: '*',\n"
" timeout_ms: 20000\n"
" }));\n"
" document.getElementById('btnAutoConnect').onclick = () => run(async () => {\n"
" const data = await callApi('/v1/printer/connect', 'POST', {\n"
" backend: selectedPrinterBackend(),\n"
" name: '*',\n"
" timeout_ms: 20000\n"
" });\n"
" syncPaperUi(data);\n"
" return data;\n"
" });\n"
"\n"
" document.getElementById('btnDisconnect').onclick = () => run(() => callApi('/v1/printer/disconnect', 'POST', {}));\n"
" document.getElementById('btnDisconnect').onclick = () => run(async () => {\n"
" const data = await callApi('/v1/printer/disconnect', 'POST', {});\n"
" try { await fetchPrinterStatus(); } catch (_) {}\n"
" return data;\n"
" });\n"
"\n"
" document.getElementById('btnPaperCheck').onclick = () => run(() => fetchPrinterStatus());\n"
"\n"
" document.getElementById('btnPrintText').onclick = () => run(() => callApi('/v1/print/text', 'POST', {\n"
" text: printTextEl.value,\n"
" density: '中等',\n"
" ignore_precheck: selectedIgnorePrecheck(),\n"
" scale: 2,\n"
" line_spacing: 2,\n"
" max_height: 1800\n"
@@ -447,6 +528,9 @@ static const char *s_web_index =
" setVoiceTalkButtonState(false);\n"
" (async () => {\n"
" try {\n"
" await fetchPrinterStatus();\n"
" } catch (_) {}\n"
" try {\n"
" await refreshVoiceStatus();\n"
" } catch (_) {}\n"
" })();\n"

View File

@@ -2,11 +2,42 @@
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include "control_plane.h"
#include "domain.h"
static const char *printer_backend_str(printer_backend_t backend) {
switch (backend) {
case PRINTER_BACKEND_BLE:
return "ble";
case PRINTER_BACKEND_DIRECT:
return "direct";
default:
return "unknown";
}
}
static bool parse_printer_backend(const cJSON *json, printer_backend_t *out_backend) {
if (json == NULL || out_backend == NULL) {
return false;
}
cJSON *jbackend = cJSON_GetObjectItemCaseSensitive((cJSON *)json, "backend");
if (!cJSON_IsString(jbackend) || jbackend->valuestring == NULL) {
return false;
}
if (strcasecmp(jbackend->valuestring, "ble") == 0) {
*out_backend = PRINTER_BACKEND_BLE;
return true;
}
if (strcasecmp(jbackend->valuestring, "direct") == 0) {
*out_backend = PRINTER_BACKEND_DIRECT;
return true;
}
return false;
}
static void fill_runtime_diag_json(cJSON *root) {
runtime_diag_snapshot_t snapshot = {0};
runtime_diag_get_snapshot(&snapshot);
@@ -54,12 +85,20 @@ static void fill_runtime_json(cJSON *root) {
cJSON_AddStringToObject(root, "wifi_mode", "sta");
cJSON_AddStringToObject(root, "ip", ip);
cJSON_AddBoolToObject(root, "ble_connected", st.connected);
cJSON_AddBoolToObject(root, "ble_notify_ready", st.notify_ready);
cJSON_AddStringToObject(root, "printer_backend", printer_backend_str(st.backend));
cJSON_AddBoolToObject(root, "printer_connected", st.connected);
cJSON_AddBoolToObject(root, "printer_transport_ready", st.transport_ready);
cJSON_AddBoolToObject(root, "ble_connected", st.backend == PRINTER_BACKEND_BLE && st.connected);
cJSON_AddBoolToObject(root, "ble_notify_ready", st.backend == PRINTER_BACKEND_BLE && st.notify_ready);
cJSON_AddBoolToObject(root, "printer_busy", st.busy);
cJSON_AddBoolToObject(root, "has_paper", st.has_paper);
cJSON_AddNumberToObject(root, "paper_gpio_level", st.paper_gpio_level);
cJSON_AddNumberToObject(root, "paper_present_level", st.paper_present_level);
cJSON_AddNumberToObject(root, "battery_percent", st.battery_percent);
cJSON_AddNumberToObject(root, "temperature", st.temperature);
cJSON_AddBoolToObject(root, "supports_gap_move", st.supports_gap_move);
cJSON_AddBoolToObject(root, "supports_label_offset", st.supports_label_offset);
cJSON_AddBoolToObject(root, "supports_ota", st.supports_ota);
cJSON_AddNumberToObject(root, "queue_depth", st.queue_depth);
cJSON_AddNumberToObject(root, "mtu", st.mtu);
cJSON_AddNumberToObject(root, "last_status_ms", (double)st.last_status_ms);
@@ -117,6 +156,8 @@ esp_err_t rest_server_connect_post(httpd_req_t *req) {
char *body = NULL;
char name[32] = "TQPrinter";
uint32_t timeout_ms = runtime_policy_rest_printer_connect_timeout_ms();
printer_backend_t backend = printer_protocol_get_backend();
bool backend_specified = false;
if (req->content_len > 0) {
esp_err_t body_err = rest_server_read_body(req, &body);
@@ -140,21 +181,53 @@ esp_err_t rest_server_connect_post(httpd_req_t *req) {
timeout_ms = (uint32_t)jtimeout->valuedouble;
}
cJSON *jbackend = cJSON_GetObjectItemCaseSensitive(json, "backend");
if (jbackend != NULL) {
backend_specified = true;
if (!parse_printer_backend(json, &backend)) {
cJSON_Delete(json);
free(body);
return rest_server_send_error(req, "400 Bad Request", "backend must be ble or direct");
}
}
cJSON_Delete(json);
free(body);
}
esp_err_t err = printer_protocol_connect(name, timeout_ms);
printer_connect_options_t opt = {
.backend = backend,
.name = backend == PRINTER_BACKEND_BLE ? name : NULL,
.timeout_ms = timeout_ms,
};
char connect_err[96] = {0};
esp_err_t err = printer_protocol_connect_ex(&opt, connect_err, sizeof(connect_err));
if (err != ESP_OK) {
if (err == ESP_ERR_TIMEOUT) {
return rest_server_send_error(req, "504 Gateway Timeout", "connect timeout");
return rest_server_send_error(req,
"504 Gateway Timeout",
connect_err[0] != '\0' ? connect_err : "connect timeout");
}
return rest_server_send_error(req, "500 Internal Server Error", "connect failed");
if (err == ESP_ERR_NOT_SUPPORTED || err == ESP_ERR_INVALID_STATE) {
return rest_server_send_error(req,
"409 Conflict",
connect_err[0] != '\0' ? connect_err : "connect failed");
}
if (err == ESP_ERR_INVALID_ARG) {
return rest_server_send_error(req,
"400 Bad Request",
connect_err[0] != '\0' ? connect_err : "invalid connect params");
}
return rest_server_send_error(req,
"500 Internal Server Error",
connect_err[0] != '\0' ? connect_err : "connect failed");
}
cJSON *root = cJSON_CreateObject();
cJSON_AddBoolToObject(root, "ok", true);
cJSON_AddStringToObject(root, "message", "connected");
cJSON_AddStringToObject(root, "backend", printer_backend_str(backend));
cJSON_AddBoolToObject(root, "backend_specified", backend_specified);
fill_runtime_json(root);
err = rest_server_send_json(req, "200 OK", root);

View File

@@ -18,27 +18,33 @@ esp_err_t rest_server_print_submit_raster_job_and_reply(httpd_req_t *req,
uint16_t width,
uint16_t height,
const char *density,
bool direct_ignore_precheck,
const char *warning,
const char *trace_id) {
const char *trace = trace_id_or_default(trace_id);
ESP_LOGI(TAG,
"print submit start, trace=%s, raster_bytes=%u, size=%ux%u, density=%s",
"print submit start, trace=%s, raster_bytes=%u, size=%ux%u, density=%s, ignore_precheck=%d",
trace,
(unsigned)raw_len,
(unsigned)width,
(unsigned)height,
density != NULL ? density : "中等");
density != NULL ? density : "中等",
direct_ignore_precheck);
char submit_err[128] = {0};
uint32_t job_id = 0;
esp_err_t submit_rc = printer_protocol_submit_raster_job(raw,
raw_len,
width,
height,
density,
&job_id,
submit_err,
sizeof(submit_err));
printer_print_options_t options = {
.direct_ignore_precheck = direct_ignore_precheck,
};
esp_err_t submit_rc = printer_protocol_submit_raster_job_ex(raw,
raw_len,
width,
height,
density,
&options,
&job_id,
submit_err,
sizeof(submit_err));
if (submit_rc != ESP_OK) {
ESP_LOGW(TAG,
"print submit failed, trace=%s, rc=0x%x, msg=%s",
@@ -56,6 +62,7 @@ esp_err_t rest_server_print_submit_raster_job_and_reply(httpd_req_t *req,
cJSON_AddBoolToObject(root, "ok", true);
cJSON_AddNumberToObject(root, "job_id", job_id);
cJSON_AddStringToObject(root, "state", "queued");
cJSON_AddBoolToObject(root, "ignore_precheck", direct_ignore_precheck);
if (warning != NULL && warning[0] != '\0') {
cJSON_AddStringToObject(root, "warning", warning);
}
@@ -87,6 +94,7 @@ esp_err_t rest_server_print_raster_post(httpd_req_t *req) {
cJSON *jencoding = cJSON_GetObjectItemCaseSensitive(json, "encoding");
cJSON *jdata = cJSON_GetObjectItemCaseSensitive(json, "data");
cJSON *jdensity = cJSON_GetObjectItemCaseSensitive(json, "density");
cJSON *jignore = cJSON_GetObjectItemCaseSensitive(json, "ignore_precheck");
if (!cJSON_IsNumber(jwidth) || !cJSON_IsNumber(jheight) ||
!cJSON_IsString(jencoding) || !cJSON_IsString(jdata)) {
@@ -102,6 +110,7 @@ esp_err_t rest_server_print_raster_post(httpd_req_t *req) {
const char *density = (cJSON_IsString(jdensity) && jdensity->valuestring != NULL)
? jdensity->valuestring
: "中等";
bool direct_ignore_precheck = rest_server_json_bool_with_default(jignore, false);
uint8_t *raw = NULL;
size_t raw_len = 0;
@@ -117,6 +126,7 @@ esp_err_t rest_server_print_raster_post(httpd_req_t *req) {
(uint16_t)jwidth->valuedouble,
(uint16_t)jheight->valuedouble,
density,
direct_ignore_precheck,
NULL,
NULL);
free(raw);

View File

@@ -16,6 +16,7 @@ typedef struct {
bool invert;
uint16_t max_height;
const char *density;
bool direct_ignore_precheck;
} image_print_options_t;
typedef struct {
@@ -68,7 +69,8 @@ static void parse_image_upload_options(httpd_req_t *req,
uint8_t *out_threshold,
bool *out_invert,
uint16_t *out_max_height,
const char **out_density) {
const char **out_density,
bool *out_direct_ignore_precheck) {
if (out_scale_to_width != NULL) {
*out_scale_to_width = true;
}
@@ -84,6 +86,9 @@ static void parse_image_upload_options(httpd_req_t *req,
if (out_density != NULL) {
*out_density = "中等";
}
if (out_direct_ignore_precheck != NULL) {
*out_direct_ignore_precheck = false;
}
if (req == NULL) {
return;
@@ -138,6 +143,14 @@ static void parse_image_upload_options(httpd_req_t *req,
*out_density = map_density_text(value);
}
if (httpd_query_key_value(query, "ignore_precheck", value, sizeof(value)) == ESP_OK &&
out_direct_ignore_precheck != NULL) {
bool parsed = *out_direct_ignore_precheck;
if (parse_bool_text(value, &parsed)) {
*out_direct_ignore_precheck = parsed;
}
}
free(query);
}
@@ -150,6 +163,7 @@ static void image_print_options_set_defaults(image_print_options_t *out) {
out->invert = false;
out->max_height = 2200;
out->density = "中等";
out->direct_ignore_precheck = false;
}
static void parse_image_print_options_from_json(cJSON *json, image_print_options_t *out) {
@@ -162,6 +176,7 @@ static void parse_image_print_options_from_json(cJSON *json, image_print_options
cJSON *jinvert = cJSON_GetObjectItemCaseSensitive(json, "invert");
cJSON *jmaxh = cJSON_GetObjectItemCaseSensitive(json, "max_height");
cJSON *jdensity = cJSON_GetObjectItemCaseSensitive(json, "density");
cJSON *jignore = cJSON_GetObjectItemCaseSensitive(json, "ignore_precheck");
out->scale_to_width = rest_server_json_bool_with_default(jscale, out->scale_to_width);
out->invert = rest_server_json_bool_with_default(jinvert, out->invert);
@@ -174,6 +189,7 @@ static void parse_image_print_options_from_json(cJSON *json, image_print_options
if (cJSON_IsString(jdensity) && jdensity->valuestring != NULL) {
out->density = map_density_text(jdensity->valuestring);
}
out->direct_ignore_precheck = rest_server_json_bool_with_default(jignore, out->direct_ignore_precheck);
}
static bool parse_image_size_text(const char *text, uint32_t *out_w, uint32_t *out_h) {
@@ -345,21 +361,24 @@ static esp_err_t rest_server_print_image_binary(httpd_req_t *req) {
bool invert = false;
uint16_t max_height = 2200;
const char *density = "中等";
bool direct_ignore_precheck = false;
parse_image_upload_options(req,
&scale_to_width,
&threshold,
&invert,
&max_height,
&density);
&density,
&direct_ignore_precheck);
ESP_LOGI(TAG,
"image process start (upload), png_bytes=%u, scale_to_width=%d, threshold=%u, invert=%d, max_height=%u, density=%s",
"image process start (upload), png_bytes=%u, scale_to_width=%d, threshold=%u, invert=%d, max_height=%u, density=%s, ignore_precheck=%d",
(unsigned)req->content_len,
scale_to_width,
(unsigned)threshold,
invert,
(unsigned)max_height,
density != NULL ? density : "中等");
density != NULL ? density : "中等",
direct_ignore_precheck);
char *body = NULL;
esp_err_t body_err = rest_server_read_body(req, &body);
@@ -407,6 +426,7 @@ static esp_err_t rest_server_print_image_binary(httpd_req_t *req) {
width,
height,
density,
direct_ignore_precheck,
NULL,
NULL);
free(raster);
@@ -458,12 +478,13 @@ static esp_err_t rest_server_print_image_generate(httpd_req_t *req) {
(unsigned)gen_opt.timeout_ms,
(unsigned)gen_opt.fetch_timeout_ms);
ESP_LOGI(TAG,
"image process config, scale_to_width=%d, threshold=%u, invert=%d, max_height=%u, density=%s",
"image process config, scale_to_width=%d, threshold=%u, invert=%d, max_height=%u, density=%s, ignore_precheck=%d",
print_opt.scale_to_width,
(unsigned)print_opt.threshold,
print_opt.invert,
(unsigned)print_opt.max_height,
print_opt.density != NULL ? print_opt.density : "中等");
print_opt.density != NULL ? print_opt.density : "中等",
print_opt.direct_ignore_precheck);
image_generation_request_t gen_req = {
.prompt = gen_opt.prompt,
@@ -553,6 +574,7 @@ static esp_err_t rest_server_print_image_generate(httpd_req_t *req) {
width,
height,
print_opt.density,
print_opt.direct_ignore_precheck,
warning,
request_id);

View File

@@ -159,6 +159,7 @@ esp_err_t rest_server_print_qr_post(httpd_req_t *req) {
cJSON *jscale = cJSON_GetObjectItemCaseSensitive(json, "module_scale");
cJSON *jmargin = cJSON_GetObjectItemCaseSensitive(json, "margin_modules");
cJSON *jmaxh = cJSON_GetObjectItemCaseSensitive(json, "max_height");
cJSON *jignore = cJSON_GetObjectItemCaseSensitive(json, "ignore_precheck");
if (!cJSON_IsString(jtext) || jtext->valuestring == NULL || jtext->valuestring[0] == '\0') {
cJSON_Delete(json);
@@ -168,6 +169,7 @@ esp_err_t rest_server_print_qr_post(httpd_req_t *req) {
const char *density = (cJSON_IsString(jdensity) && jdensity->valuestring != NULL)
? jdensity->valuestring
: "中等";
bool direct_ignore_precheck = rest_server_json_bool_with_default(jignore, false);
uint8_t ecc_level = 3; /* default H */
if (cJSON_IsString(jecc) && jecc->valuestring != NULL) {
@@ -224,6 +226,7 @@ esp_err_t rest_server_print_qr_post(httpd_req_t *req) {
width,
height,
density,
direct_ignore_precheck,
NULL,
NULL);
free(raster);
@@ -250,6 +253,7 @@ esp_err_t rest_server_print_label_post(httpd_req_t *req) {
cJSON *jdensity = cJSON_GetObjectItemCaseSensitive(json, "density");
cJSON *jgap = cJSON_GetObjectItemCaseSensitive(json, "gap_move_before");
cJSON *joffset = cJSON_GetObjectItemCaseSensitive(json, "offset_tenths_mm");
cJSON *jignore = cJSON_GetObjectItemCaseSensitive(json, "ignore_precheck");
bool gap_move_before = rest_server_json_bool_with_default(jgap, true);
bool has_offset = cJSON_IsNumber(joffset);
@@ -287,6 +291,7 @@ esp_err_t rest_server_print_label_post(httpd_req_t *req) {
const char *density = (cJSON_IsString(jdensity) && jdensity->valuestring != NULL)
? jdensity->valuestring
: "中等";
bool direct_ignore_precheck = rest_server_json_bool_with_default(jignore, false);
uint16_t width = 0;
uint16_t height = 0;
@@ -313,6 +318,7 @@ esp_err_t rest_server_print_label_post(httpd_req_t *req) {
width,
height,
density,
direct_ignore_precheck,
NULL,
NULL);
free(raster);
@@ -341,6 +347,7 @@ esp_err_t rest_server_print_text_post(httpd_req_t *req) {
cJSON *jscale = cJSON_GetObjectItemCaseSensitive(json, "scale");
cJSON *jline = cJSON_GetObjectItemCaseSensitive(json, "line_spacing");
cJSON *jmaxh = cJSON_GetObjectItemCaseSensitive(json, "max_height");
cJSON *jignore = cJSON_GetObjectItemCaseSensitive(json, "ignore_precheck");
if (!cJSON_IsString(jtext) || jtext->valuestring == NULL) {
cJSON_Delete(json);
@@ -350,6 +357,7 @@ esp_err_t rest_server_print_text_post(httpd_req_t *req) {
const char *density = (cJSON_IsString(jdensity) && jdensity->valuestring != NULL)
? jdensity->valuestring
: "中等";
bool direct_ignore_precheck = rest_server_json_bool_with_default(jignore, false);
uint8_t scale = 2;
uint8_t line_spacing = 2;
uint16_t max_height = 2000;
@@ -394,6 +402,7 @@ esp_err_t rest_server_print_text_post(httpd_req_t *req) {
width,
height,
density,
direct_ignore_precheck,
render_msg,
NULL);
free(raster);
@@ -422,6 +431,7 @@ esp_err_t rest_server_print_receipt_post(httpd_req_t *req) {
cJSON *jfooter = cJSON_GetObjectItemCaseSensitive(json, "footer");
cJSON *jdensity = cJSON_GetObjectItemCaseSensitive(json, "density");
cJSON *jscale = cJSON_GetObjectItemCaseSensitive(json, "scale");
cJSON *jignore = cJSON_GetObjectItemCaseSensitive(json, "ignore_precheck");
const char *title = (cJSON_IsString(jtitle) && jtitle->valuestring != NULL)
? jtitle->valuestring
@@ -432,6 +442,7 @@ esp_err_t rest_server_print_receipt_post(httpd_req_t *req) {
const char *density = (cJSON_IsString(jdensity) && jdensity->valuestring != NULL)
? jdensity->valuestring
: "中等";
bool direct_ignore_precheck = rest_server_json_bool_with_default(jignore, false);
uint8_t scale = 2;
if (cJSON_IsNumber(jscale) && jscale->valuedouble >= 1 && jscale->valuedouble <= 4) {
scale = (uint8_t)jscale->valuedouble;
@@ -516,6 +527,7 @@ esp_err_t rest_server_print_receipt_post(httpd_req_t *req) {
width,
height,
density,
direct_ignore_precheck,
render_msg,
NULL);
free(raster);