feat(rest): simplify web ui and prune non-core endpoints
This commit is contained in:
115
README.md
115
README.md
@@ -10,7 +10,7 @@ ESP32-S3 works as a Wi-Fi REST controller and replaces Android App logic:
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Wi-Fi STA-only mode (configured SSID/password; no SoftAP fallback)
|
- Wi-Fi STA-only mode (configured SSID/password; no SoftAP fallback)
|
||||||
- Built-in web UI at `/` for connect/status, text print, and Z-Image prompt print
|
- Built-in minimal web UI at `/` for voice tap2talk
|
||||||
- BLE central client auto-scan/connect to printer name
|
- BLE central client auto-scan/connect to printer name
|
||||||
- Async print queue with jobs (`queued/running/success/failed/canceled`)
|
- Async print queue with jobs (`queued/running/success/failed/canceled`)
|
||||||
- Printer precheck (paper / battery / temperature)
|
- Printer precheck (paper / battery / temperature)
|
||||||
@@ -26,6 +26,8 @@ ESP32-S3 works as a Wi-Fi REST controller and replaces Android App logic:
|
|||||||
- `0x00` power off
|
- `0x00` power off
|
||||||
- `0x02` feed paper
|
- `0x02` feed paper
|
||||||
- REST APIs:
|
- REST APIs:
|
||||||
|
- Root:
|
||||||
|
- `GET /`
|
||||||
- Health/connection:
|
- Health/connection:
|
||||||
- `GET /v1/health`
|
- `GET /v1/health`
|
||||||
- `POST /v1/printer/connect`
|
- `POST /v1/printer/connect`
|
||||||
@@ -34,26 +36,10 @@ ESP32-S3 works as a Wi-Fi REST controller and replaces Android App logic:
|
|||||||
- Print:
|
- Print:
|
||||||
- `POST /v1/print/raster`
|
- `POST /v1/print/raster`
|
||||||
- `POST /v1/print/image` (JSON prompt -> generate image -> print, also compatible with direct PNG binary upload)
|
- `POST /v1/print/image` (JSON prompt -> generate image -> print, also compatible with direct PNG binary upload)
|
||||||
- `POST /v1/print/qr`
|
|
||||||
- `POST /v1/print/text`
|
- `POST /v1/print/text`
|
||||||
- `POST /v1/print/receipt`
|
|
||||||
- `POST /v1/print/label`
|
|
||||||
- Jobs:
|
- Jobs:
|
||||||
- `GET /v1/jobs`
|
- `GET /v1/jobs`
|
||||||
- `DELETE /v1/jobs`
|
|
||||||
- `GET /v1/jobs/{id}`
|
- `GET /v1/jobs/{id}`
|
||||||
- `DELETE /v1/jobs/{id}`
|
|
||||||
- Label control:
|
|
||||||
- `POST /v1/label/gap_move`
|
|
||||||
- `GET /v1/label/offset`
|
|
||||||
- `POST /v1/label/offset`
|
|
||||||
- OTA:
|
|
||||||
- `GET /v1/ota/version`
|
|
||||||
- `POST /v1/ota/jump_boot`
|
|
||||||
- `POST /v1/ota/jump_app`
|
|
||||||
- `POST /v1/ota/erase_page`
|
|
||||||
- `POST /v1/ota/write_frame`
|
|
||||||
- `POST /v1/ota/upgrade`
|
|
||||||
- Voice:
|
- Voice:
|
||||||
- `GET /v1/voice/status`
|
- `GET /v1/voice/status`
|
||||||
- `POST /v1/voice/session/start`
|
- `POST /v1/voice/session/start`
|
||||||
@@ -147,14 +133,9 @@ Open the controller IP in a browser:
|
|||||||
http://<esp-ip>/
|
http://<esp-ip>/
|
||||||
```
|
```
|
||||||
|
|
||||||
The page provides:
|
The page provides a minimal voice console:
|
||||||
- health/status check
|
- single-round tap2talk button
|
||||||
- connect/disconnect printer
|
- voice status display
|
||||||
- submit a simple text print job
|
|
||||||
- input an image prompt, then let ESP32-S3 call DashScope Z-Image, download PNG, decode/threshold/scale/raster conversion, and print
|
|
||||||
- view jobs list
|
|
||||||
|
|
||||||
If API key is enabled, input it in the page before invoking actions.
|
|
||||||
|
|
||||||
## REST Examples
|
## REST Examples
|
||||||
|
|
||||||
@@ -222,19 +203,6 @@ Request constraints:
|
|||||||
- Request body limit: 4 MB
|
- Request body limit: 4 MB
|
||||||
- Suggested image size: <= 3 MB when using direct PNG upload compatibility mode
|
- Suggested image size: <= 3 MB when using direct PNG upload compatibility mode
|
||||||
|
|
||||||
### QR print
|
|
||||||
```bash
|
|
||||||
curl -X POST http://<esp-ip>/v1/print/qr \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-d '{
|
|
||||||
"text":"https://example.com/pay/123",
|
|
||||||
"ecc":"H",
|
|
||||||
"module_scale":0,
|
|
||||||
"margin_modules":2,
|
|
||||||
"density":"中等"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Text print
|
### Text print
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://<esp-ip>/v1/print/text \
|
curl -X POST http://<esp-ip>/v1/print/text \
|
||||||
@@ -248,74 +216,10 @@ curl -X POST http://<esp-ip>/v1/print/text \
|
|||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Receipt print
|
|
||||||
```bash
|
|
||||||
curl -X POST http://<esp-ip>/v1/print/receipt \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-d '{
|
|
||||||
"title":"TQ FOOD",
|
|
||||||
"density":"中等",
|
|
||||||
"footer":"Thanks!",
|
|
||||||
"items":[
|
|
||||||
{"name":"DishA","qty":2,"price":12.5},
|
|
||||||
{"name":"DishB","qty":1,"price":8.0}
|
|
||||||
]
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Label print (with optional gap/offset)
|
|
||||||
```bash
|
|
||||||
curl -X POST http://<esp-ip>/v1/print/label \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-d '{
|
|
||||||
"width":384,
|
|
||||||
"height":260,
|
|
||||||
"encoding":"base64_msb_1bpp",
|
|
||||||
"data":"<BASE64_BYTES>",
|
|
||||||
"gap_move_before":true,
|
|
||||||
"offset_tenths_mm":128,
|
|
||||||
"density":"中等"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Jobs
|
### Jobs
|
||||||
```bash
|
```bash
|
||||||
curl http://<esp-ip>/v1/jobs
|
curl http://<esp-ip>/v1/jobs
|
||||||
curl http://<esp-ip>/v1/jobs/1
|
curl http://<esp-ip>/v1/jobs/1
|
||||||
curl -X DELETE http://<esp-ip>/v1/jobs/1
|
|
||||||
curl -X DELETE http://<esp-ip>/v1/jobs -d '{"include_success":true,"include_failed":true,"include_canceled":true}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Label control
|
|
||||||
```bash
|
|
||||||
curl -X POST http://<esp-ip>/v1/label/gap_move
|
|
||||||
curl http://<esp-ip>/v1/label/offset
|
|
||||||
curl -X POST http://<esp-ip>/v1/label/offset \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-d '{"offset_tenths_mm":128}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### OTA primitives
|
|
||||||
```bash
|
|
||||||
curl http://<esp-ip>/v1/ota/version
|
|
||||||
curl -X POST http://<esp-ip>/v1/ota/jump_boot
|
|
||||||
curl -X POST http://<esp-ip>/v1/ota/erase_page -H 'Content-Type: application/json' -d '{"page_num":0}'
|
|
||||||
curl -X POST http://<esp-ip>/v1/ota/write_frame -H 'Content-Type: application/json' -d '{"packet_num":0,"is_last_frame":false,"data":"<BASE64_<=236_BYTES>"}'
|
|
||||||
curl -X POST http://<esp-ip>/v1/ota/jump_app
|
|
||||||
```
|
|
||||||
|
|
||||||
### OTA full upgrade
|
|
||||||
```bash
|
|
||||||
curl -X POST http://<esp-ip>/v1/ota/upgrade \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-d '{
|
|
||||||
"firmware":"<BASE64_FIRMWARE>",
|
|
||||||
"jump_boot":true,
|
|
||||||
"jump_app":true,
|
|
||||||
"page_size":1024,
|
|
||||||
"packet_size":236,
|
|
||||||
"timeout_ms_per_step":5000
|
|
||||||
}'
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Voice tap2talk
|
### Voice tap2talk
|
||||||
@@ -354,13 +258,12 @@ curl -X POST http://<esp-ip>/v1/voice/session/stop
|
|||||||
- BLE side is central/client role, not printer peripheral role.
|
- BLE side is central/client role, not printer peripheral role.
|
||||||
- `base64_msb_1bpp` uses Android-compatible bit order (MSB first).
|
- `base64_msb_1bpp` uses Android-compatible bit order (MSB first).
|
||||||
- `/v1/print/image` supports two modes: JSON prompt generation (DashScope Z-Image) and raw `image/png` upload (no base64 wrapper).
|
- `/v1/print/image` supports two modes: JSON prompt generation (DashScope Z-Image) and raw `image/png` upload (no base64 wrapper).
|
||||||
|
- `/v1/print/text` supports UTF-8 Chinese via embedded 16x16 GB2312 glyphs.
|
||||||
|
- Characters outside embedded glyph set are rendered as square fallback boxes.
|
||||||
- Large buffers for image upload/decode prefer PSRAM first, then fallback to internal RAM.
|
- Large buffers for image upload/decode prefer PSRAM first, then fallback to internal RAM.
|
||||||
- Partition table uses `partitions.csv` with a 4MB `factory` app partition on 16MB flash modules.
|
- Partition table uses `partitions.csv` with a 4MB `factory` app partition on 16MB flash modules.
|
||||||
- `/v1/print/text` and `/v1/print/receipt` now support UTF-8 Chinese via embedded 16x16 GB2312 glyphs.
|
|
||||||
- Characters outside embedded glyph set are rendered as square fallback boxes.
|
|
||||||
- QR encoding uses embedded `qrcodegen` (Project Nayuki C implementation).
|
|
||||||
- Voice flow is now single-round: audio uplink stops after `SpeechEnded`, then `LocalRespondingEnded` and `Stop` are sent after local playback drain.
|
- Voice flow is now single-round: audio uplink stops after `SpeechEnded`, then `LocalRespondingEnded` and `Stop` are sent after local playback drain.
|
||||||
- Web UI blocks starting the next voice round while voice is Thinking/Responding, marker image generation is running, or printer queue is still busy.
|
- Voice flow blocks starting the next round while voice is Thinking/Responding, marker image generation is running, or printer queue is still busy.
|
||||||
|
|
||||||
## Font Assets
|
## Font Assets
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ idf_component_register(
|
|||||||
"src/rest_server_ops.c"
|
"src/rest_server_ops.c"
|
||||||
"src/rest_server_print.c"
|
"src/rest_server_print.c"
|
||||||
"src/rest_server_print_image.c"
|
"src/rest_server_print_image.c"
|
||||||
"src/rest_server_print_render.c"
|
"src/rest_server_print_text.c"
|
||||||
"src/rest_server_jobs.c"
|
"src/rest_server_jobs.c"
|
||||||
"src/rest_server_voice.c"
|
"src/rest_server_voice.c"
|
||||||
INCLUDE_DIRS
|
INCLUDE_DIRS
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ esp_err_t rest_server_send_error(httpd_req_t *req, const char *status, const cha
|
|||||||
esp_err_t rest_server_read_body(httpd_req_t *req, char **out_body);
|
esp_err_t rest_server_read_body(httpd_req_t *req, char **out_body);
|
||||||
bool rest_server_parse_uri_u32_tail(const char *uri, uint32_t *out_value);
|
bool rest_server_parse_uri_u32_tail(const char *uri, uint32_t *out_value);
|
||||||
esp_err_t rest_server_base64_decode_alloc(const char *b64, uint8_t **out_raw, size_t *out_len);
|
esp_err_t rest_server_base64_decode_alloc(const char *b64, uint8_t **out_raw, size_t *out_len);
|
||||||
void rest_server_appendf(char *dst, size_t cap, size_t *offset, const char *fmt, ...);
|
|
||||||
bool rest_server_json_bool_with_default(cJSON *item, bool default_value);
|
bool rest_server_json_bool_with_default(cJSON *item, bool default_value);
|
||||||
esp_err_t rest_server_print_submit_raster_job_and_reply(httpd_req_t *req,
|
esp_err_t rest_server_print_submit_raster_job_and_reply(httpd_req_t *req,
|
||||||
const uint8_t *raw,
|
const uint8_t *raw,
|
||||||
@@ -30,31 +29,13 @@ esp_err_t rest_server_health_get(httpd_req_t *req);
|
|||||||
esp_err_t rest_server_connect_post(httpd_req_t *req);
|
esp_err_t rest_server_connect_post(httpd_req_t *req);
|
||||||
esp_err_t rest_server_disconnect_post(httpd_req_t *req);
|
esp_err_t rest_server_disconnect_post(httpd_req_t *req);
|
||||||
esp_err_t rest_server_status_get(httpd_req_t *req);
|
esp_err_t rest_server_status_get(httpd_req_t *req);
|
||||||
esp_err_t rest_server_printer_direct_debug_get(httpd_req_t *req);
|
|
||||||
esp_err_t rest_server_printer_direct_debug_post(httpd_req_t *req);
|
|
||||||
|
|
||||||
esp_err_t rest_server_print_raster_post(httpd_req_t *req);
|
esp_err_t rest_server_print_raster_post(httpd_req_t *req);
|
||||||
esp_err_t rest_server_print_image_post(httpd_req_t *req);
|
esp_err_t rest_server_print_image_post(httpd_req_t *req);
|
||||||
esp_err_t rest_server_print_qr_post(httpd_req_t *req);
|
|
||||||
esp_err_t rest_server_print_label_post(httpd_req_t *req);
|
|
||||||
esp_err_t rest_server_print_text_post(httpd_req_t *req);
|
esp_err_t rest_server_print_text_post(httpd_req_t *req);
|
||||||
esp_err_t rest_server_print_receipt_post(httpd_req_t *req);
|
|
||||||
|
|
||||||
esp_err_t rest_server_job_get(httpd_req_t *req);
|
esp_err_t rest_server_job_get(httpd_req_t *req);
|
||||||
esp_err_t rest_server_jobs_get(httpd_req_t *req);
|
esp_err_t rest_server_jobs_get(httpd_req_t *req);
|
||||||
esp_err_t rest_server_job_delete(httpd_req_t *req);
|
|
||||||
esp_err_t rest_server_jobs_delete(httpd_req_t *req);
|
|
||||||
|
|
||||||
esp_err_t rest_server_label_gap_move_post(httpd_req_t *req);
|
|
||||||
esp_err_t rest_server_label_offset_get(httpd_req_t *req);
|
|
||||||
esp_err_t rest_server_label_offset_post(httpd_req_t *req);
|
|
||||||
|
|
||||||
esp_err_t rest_server_ota_version_get(httpd_req_t *req);
|
|
||||||
esp_err_t rest_server_ota_jump_boot_post(httpd_req_t *req);
|
|
||||||
esp_err_t rest_server_ota_jump_app_post(httpd_req_t *req);
|
|
||||||
esp_err_t rest_server_ota_erase_page_post(httpd_req_t *req);
|
|
||||||
esp_err_t rest_server_ota_write_frame_post(httpd_req_t *req);
|
|
||||||
esp_err_t rest_server_ota_upgrade_post(httpd_req_t *req);
|
|
||||||
|
|
||||||
esp_err_t rest_server_voice_status_get(httpd_req_t *req);
|
esp_err_t rest_server_voice_status_get(httpd_req_t *req);
|
||||||
esp_err_t rest_server_voice_session_start_post(httpd_req_t *req);
|
esp_err_t rest_server_voice_session_start_post(httpd_req_t *req);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,6 @@
|
|||||||
#include "rest_server_internal.h"
|
#include "rest_server_internal.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -154,28 +152,6 @@ esp_err_t rest_server_base64_decode_alloc(const char *b64, uint8_t **out_raw, si
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rest_server_appendf(char *dst, size_t cap, size_t *offset, const char *fmt, ...) {
|
|
||||||
if (dst == NULL || cap == 0 || offset == NULL || fmt == NULL || *offset >= cap) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
int n = vsnprintf(dst + *offset, cap - *offset, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
if (n <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t written = (size_t)n;
|
|
||||||
if (written >= cap - *offset) {
|
|
||||||
*offset = cap - 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*offset += written;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool rest_server_json_bool_with_default(cJSON *item, bool default_value) {
|
bool rest_server_json_bool_with_default(cJSON *item, bool default_value) {
|
||||||
if (item == NULL) {
|
if (item == NULL) {
|
||||||
return default_value;
|
return default_value;
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
#include "rest_server_internal.h"
|
#include "rest_server_internal.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "domain.h"
|
#include "domain.h"
|
||||||
|
|
||||||
esp_err_t rest_server_job_get(httpd_req_t *req) {
|
esp_err_t rest_server_job_get(httpd_req_t *req) {
|
||||||
if (!rest_server_auth_ok(req)) {
|
if (!rest_server_auth_ok(req)) {
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
||||||
@@ -84,90 +83,3 @@ esp_err_t rest_server_jobs_get(httpd_req_t *req) {
|
|||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t rest_server_job_delete(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t job_id = 0;
|
|
||||||
if (!rest_server_parse_uri_u32_tail(req->uri, &job_id)) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid job id");
|
|
||||||
}
|
|
||||||
|
|
||||||
char cancel_err[128] = {0};
|
|
||||||
esp_err_t cancel_rc = printer_protocol_cancel_job(job_id, cancel_err, sizeof(cancel_err));
|
|
||||||
if (cancel_rc == ESP_ERR_NOT_FOUND) {
|
|
||||||
return rest_server_send_error(req, "404 Not Found", "job not found");
|
|
||||||
}
|
|
||||||
if (cancel_rc == ESP_ERR_INVALID_STATE) {
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"409 Conflict",
|
|
||||||
cancel_err[0] != '\0' ? cancel_err : "job already finished");
|
|
||||||
}
|
|
||||||
if (cancel_rc != ESP_OK) {
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"409 Conflict",
|
|
||||||
cancel_err[0] != '\0' ? cancel_err : "cancel failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
print_job_info_t info;
|
|
||||||
bool ok = printer_protocol_get_job(job_id, &info);
|
|
||||||
|
|
||||||
cJSON *root = cJSON_CreateObject();
|
|
||||||
cJSON_AddBoolToObject(root, "ok", true);
|
|
||||||
cJSON_AddNumberToObject(root, "job_id", job_id);
|
|
||||||
if (ok) {
|
|
||||||
cJSON_AddStringToObject(root, "state", printer_protocol_job_state_str(info.state));
|
|
||||||
cJSON_AddStringToObject(root, "error", info.error);
|
|
||||||
} else {
|
|
||||||
cJSON_AddStringToObject(root, "state", "canceled");
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t err = rest_server_send_json(req, "200 OK", root);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_jobs_delete(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool include_success = true;
|
|
||||||
bool include_failed = true;
|
|
||||||
bool include_canceled = true;
|
|
||||||
|
|
||||||
if (req->content_len > 0) {
|
|
||||||
char *body = NULL;
|
|
||||||
esp_err_t body_err = rest_server_read_body(req, &body);
|
|
||||||
if (body_err != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid request body");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *json = cJSON_Parse(body);
|
|
||||||
free(body);
|
|
||||||
if (json == NULL) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid json");
|
|
||||||
}
|
|
||||||
|
|
||||||
include_success = rest_server_json_bool_with_default(cJSON_GetObjectItemCaseSensitive(json, "include_success"), true);
|
|
||||||
include_failed = rest_server_json_bool_with_default(cJSON_GetObjectItemCaseSensitive(json, "include_failed"), true);
|
|
||||||
include_canceled = rest_server_json_bool_with_default(cJSON_GetObjectItemCaseSensitive(json, "include_canceled"), true);
|
|
||||||
cJSON_Delete(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t removed = printer_protocol_cleanup_jobs(include_success, include_failed, include_canceled);
|
|
||||||
|
|
||||||
cJSON *root = cJSON_CreateObject();
|
|
||||||
cJSON_AddBoolToObject(root, "ok", true);
|
|
||||||
cJSON_AddNumberToObject(root, "removed", (double)removed);
|
|
||||||
cJSON_AddBoolToObject(root, "include_success", include_success);
|
|
||||||
cJSON_AddBoolToObject(root, "include_failed", include_failed);
|
|
||||||
cJSON_AddBoolToObject(root, "include_canceled", include_canceled);
|
|
||||||
|
|
||||||
esp_err_t err = rest_server_send_json(req, "200 OK", root);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
#include "rest_server_internal.h"
|
#include "rest_server_internal.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <strings.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
#include "control_plane.h"
|
#include "control_plane.h"
|
||||||
#include "domain.h"
|
#include "domain.h"
|
||||||
@@ -214,21 +213,21 @@ esp_err_t rest_server_connect_post(httpd_req_t *req) {
|
|||||||
if (err == ESP_ERR_TIMEOUT) {
|
if (err == ESP_ERR_TIMEOUT) {
|
||||||
return rest_server_send_error(req,
|
return rest_server_send_error(req,
|
||||||
"504 Gateway Timeout",
|
"504 Gateway Timeout",
|
||||||
connect_err[0] != '\0' ? connect_err : "connect timeout");
|
connect_err[0] != 0 ? connect_err : "connect timeout");
|
||||||
}
|
}
|
||||||
if (err == ESP_ERR_NOT_SUPPORTED || err == ESP_ERR_INVALID_STATE) {
|
if (err == ESP_ERR_NOT_SUPPORTED || err == ESP_ERR_INVALID_STATE) {
|
||||||
return rest_server_send_error(req,
|
return rest_server_send_error(req,
|
||||||
"409 Conflict",
|
"409 Conflict",
|
||||||
connect_err[0] != '\0' ? connect_err : "connect failed");
|
connect_err[0] != 0 ? connect_err : "connect failed");
|
||||||
}
|
}
|
||||||
if (err == ESP_ERR_INVALID_ARG) {
|
if (err == ESP_ERR_INVALID_ARG) {
|
||||||
return rest_server_send_error(req,
|
return rest_server_send_error(req,
|
||||||
"400 Bad Request",
|
"400 Bad Request",
|
||||||
connect_err[0] != '\0' ? connect_err : "invalid connect params");
|
connect_err[0] != 0 ? connect_err : "invalid connect params");
|
||||||
}
|
}
|
||||||
return rest_server_send_error(req,
|
return rest_server_send_error(req,
|
||||||
"500 Internal Server Error",
|
"500 Internal Server Error",
|
||||||
connect_err[0] != '\0' ? connect_err : "connect failed");
|
connect_err[0] != 0 ? connect_err : "connect failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
cJSON *root = cJSON_CreateObject();
|
cJSON *root = cJSON_CreateObject();
|
||||||
@@ -272,536 +271,3 @@ esp_err_t rest_server_status_get(httpd_req_t *req) {
|
|||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_direct_debug_json_fields(cJSON *root, const printer_direct_debug_config_t *cfg) {
|
|
||||||
cJSON_AddNumberToObject(root, "shift_clock_high_us", cfg->shift_clock_high_us);
|
|
||||||
cJSON_AddNumberToObject(root, "shift_clock_low_us", cfg->shift_clock_low_us);
|
|
||||||
cJSON_AddNumberToObject(root, "latch_pulse_us", cfg->latch_pulse_us);
|
|
||||||
cJSON_AddBoolToObject(root, "strobe_active_high", cfg->strobe_active_high);
|
|
||||||
cJSON_AddBoolToObject(root, "boost_active_high", cfg->boost_active_high);
|
|
||||||
cJSON_AddNumberToObject(root, "override_strobe_on_us", cfg->override_strobe_on_us);
|
|
||||||
cJSON_AddNumberToObject(root, "override_strobe_interval_us", cfg->override_strobe_interval_us);
|
|
||||||
cJSON_AddNumberToObject(root, "override_motor_step_us", cfg->override_motor_step_us);
|
|
||||||
cJSON_AddNumberToObject(root, "override_steps_per_line", cfg->override_steps_per_line);
|
|
||||||
}
|
|
||||||
|
|
||||||
static esp_err_t direct_debug_error_response(httpd_req_t *req, esp_err_t rc, const char *msg) {
|
|
||||||
if (rc == ESP_ERR_INVALID_ARG) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", msg);
|
|
||||||
}
|
|
||||||
if (rc == ESP_ERR_NOT_SUPPORTED || rc == ESP_ERR_INVALID_STATE) {
|
|
||||||
return rest_server_send_error(req, "409 Conflict", msg);
|
|
||||||
}
|
|
||||||
if (rc == ESP_ERR_TIMEOUT) {
|
|
||||||
return rest_server_send_error(req, "504 Gateway Timeout", msg);
|
|
||||||
}
|
|
||||||
return rest_server_send_error(req, "500 Internal Server Error", msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_printer_direct_debug_get(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
printer_direct_debug_config_t cfg = {0};
|
|
||||||
char get_err[128] = {0};
|
|
||||||
esp_err_t rc = printer_protocol_get_direct_debug_config(&cfg, get_err, sizeof(get_err));
|
|
||||||
if (rc != ESP_OK) {
|
|
||||||
return direct_debug_error_response(req,
|
|
||||||
rc,
|
|
||||||
get_err[0] != '\0' ? get_err : "get direct debug failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *root = cJSON_CreateObject();
|
|
||||||
cJSON_AddBoolToObject(root, "ok", true);
|
|
||||||
cJSON_AddStringToObject(root, "backend", printer_backend_str(printer_protocol_get_backend()));
|
|
||||||
add_direct_debug_json_fields(root, &cfg);
|
|
||||||
|
|
||||||
esp_err_t err = rest_server_send_json(req, "200 OK", root);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_printer_direct_debug_post(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
printer_direct_debug_config_t cfg = {0};
|
|
||||||
char get_err[128] = {0};
|
|
||||||
esp_err_t rc = printer_protocol_get_direct_debug_config(&cfg, get_err, sizeof(get_err));
|
|
||||||
if (rc != ESP_OK) {
|
|
||||||
return direct_debug_error_response(req,
|
|
||||||
rc,
|
|
||||||
get_err[0] != '\0' ? get_err : "get direct debug failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool reset_defaults = false;
|
|
||||||
bool has_update = false;
|
|
||||||
if (req->content_len > 0) {
|
|
||||||
char *body = NULL;
|
|
||||||
esp_err_t body_err = rest_server_read_body(req, &body);
|
|
||||||
if (body_err != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid request body");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *json = cJSON_Parse(body);
|
|
||||||
free(body);
|
|
||||||
if (json == NULL) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid json");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jreset = cJSON_GetObjectItemCaseSensitive(json, "reset_defaults");
|
|
||||||
if (cJSON_IsBool(jreset)) {
|
|
||||||
reset_defaults = cJSON_IsTrue(jreset);
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jshift_hi = cJSON_GetObjectItemCaseSensitive(json, "shift_clock_high_us");
|
|
||||||
if (jshift_hi != NULL) {
|
|
||||||
if (!cJSON_IsNumber(jshift_hi) || jshift_hi->valuedouble < 1 || jshift_hi->valuedouble > 50) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "shift_clock_high_us must be 1..50");
|
|
||||||
}
|
|
||||||
cfg.shift_clock_high_us = (uint16_t)jshift_hi->valuedouble;
|
|
||||||
has_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jshift_lo = cJSON_GetObjectItemCaseSensitive(json, "shift_clock_low_us");
|
|
||||||
if (jshift_lo != NULL) {
|
|
||||||
if (!cJSON_IsNumber(jshift_lo) || jshift_lo->valuedouble < 1 || jshift_lo->valuedouble > 50) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "shift_clock_low_us must be 1..50");
|
|
||||||
}
|
|
||||||
cfg.shift_clock_low_us = (uint16_t)jshift_lo->valuedouble;
|
|
||||||
has_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jlatch = cJSON_GetObjectItemCaseSensitive(json, "latch_pulse_us");
|
|
||||||
if (jlatch != NULL) {
|
|
||||||
if (!cJSON_IsNumber(jlatch) || jlatch->valuedouble < 1 || jlatch->valuedouble > 50) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "latch_pulse_us must be 1..50");
|
|
||||||
}
|
|
||||||
cfg.latch_pulse_us = (uint16_t)jlatch->valuedouble;
|
|
||||||
has_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jstb = cJSON_GetObjectItemCaseSensitive(json, "strobe_active_high");
|
|
||||||
if (cJSON_IsBool(jstb)) {
|
|
||||||
cfg.strobe_active_high = cJSON_IsTrue(jstb);
|
|
||||||
has_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jboost = cJSON_GetObjectItemCaseSensitive(json, "boost_active_high");
|
|
||||||
if (cJSON_IsBool(jboost)) {
|
|
||||||
cfg.boost_active_high = cJSON_IsTrue(jboost);
|
|
||||||
has_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jstrobe_on = cJSON_GetObjectItemCaseSensitive(json, "override_strobe_on_us");
|
|
||||||
if (jstrobe_on != NULL) {
|
|
||||||
if (!cJSON_IsNumber(jstrobe_on) || jstrobe_on->valuedouble < 0 || jstrobe_on->valuedouble > 10000) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"400 Bad Request",
|
|
||||||
"override_strobe_on_us must be 0..10000");
|
|
||||||
}
|
|
||||||
if (jstrobe_on->valuedouble > 0 && jstrobe_on->valuedouble < 100) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"400 Bad Request",
|
|
||||||
"override_strobe_on_us must be 0 or 100..10000");
|
|
||||||
}
|
|
||||||
cfg.override_strobe_on_us = (uint16_t)jstrobe_on->valuedouble;
|
|
||||||
has_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jstrobe_gap = cJSON_GetObjectItemCaseSensitive(json, "override_strobe_interval_us");
|
|
||||||
if (jstrobe_gap != NULL) {
|
|
||||||
if (!cJSON_IsNumber(jstrobe_gap) || jstrobe_gap->valuedouble < 0 || jstrobe_gap->valuedouble > 10000) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"400 Bad Request",
|
|
||||||
"override_strobe_interval_us must be 0..10000");
|
|
||||||
}
|
|
||||||
cfg.override_strobe_interval_us = (uint16_t)jstrobe_gap->valuedouble;
|
|
||||||
has_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jmotor = cJSON_GetObjectItemCaseSensitive(json, "override_motor_step_us");
|
|
||||||
if (jmotor != NULL) {
|
|
||||||
if (!cJSON_IsNumber(jmotor) || jmotor->valuedouble < 0 || jmotor->valuedouble > 20000) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"400 Bad Request",
|
|
||||||
"override_motor_step_us must be 0..20000");
|
|
||||||
}
|
|
||||||
if (jmotor->valuedouble > 0 && jmotor->valuedouble < 100) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"400 Bad Request",
|
|
||||||
"override_motor_step_us must be 0 or 100..20000");
|
|
||||||
}
|
|
||||||
cfg.override_motor_step_us = (uint16_t)jmotor->valuedouble;
|
|
||||||
has_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jsteps = cJSON_GetObjectItemCaseSensitive(json, "override_steps_per_line");
|
|
||||||
if (jsteps != NULL) {
|
|
||||||
if (!cJSON_IsNumber(jsteps) || jsteps->valuedouble < 0 || jsteps->valuedouble > 8) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"400 Bad Request",
|
|
||||||
"override_steps_per_line must be 0..8");
|
|
||||||
}
|
|
||||||
cfg.override_steps_per_line = (uint8_t)jsteps->valuedouble;
|
|
||||||
has_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON_Delete(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
char set_err[128] = {0};
|
|
||||||
rc = printer_protocol_set_direct_debug_config(has_update ? &cfg : NULL,
|
|
||||||
reset_defaults,
|
|
||||||
set_err,
|
|
||||||
sizeof(set_err));
|
|
||||||
if (rc != ESP_OK) {
|
|
||||||
return direct_debug_error_response(req,
|
|
||||||
rc,
|
|
||||||
set_err[0] != '\0' ? set_err : "set direct debug failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&cfg, 0, sizeof(cfg));
|
|
||||||
memset(get_err, 0, sizeof(get_err));
|
|
||||||
rc = printer_protocol_get_direct_debug_config(&cfg, get_err, sizeof(get_err));
|
|
||||||
if (rc != ESP_OK) {
|
|
||||||
return direct_debug_error_response(req,
|
|
||||||
rc,
|
|
||||||
get_err[0] != '\0' ? get_err : "get direct debug failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *root = cJSON_CreateObject();
|
|
||||||
cJSON_AddBoolToObject(root, "ok", true);
|
|
||||||
cJSON_AddBoolToObject(root, "reset_defaults", reset_defaults);
|
|
||||||
cJSON_AddBoolToObject(root, "updated", has_update);
|
|
||||||
cJSON_AddStringToObject(root, "backend", printer_backend_str(printer_protocol_get_backend()));
|
|
||||||
add_direct_debug_json_fields(root, &cfg);
|
|
||||||
|
|
||||||
esp_err_t err = rest_server_send_json(req, "200 OK", root);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_label_gap_move_post(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t timeout_ms = domain_policy_rest_label_timeout_ms();
|
|
||||||
if (req->content_len > 0) {
|
|
||||||
char *body = NULL;
|
|
||||||
esp_err_t body_err = rest_server_read_body(req, &body);
|
|
||||||
if (body_err != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid request body");
|
|
||||||
}
|
|
||||||
cJSON *json = cJSON_Parse(body);
|
|
||||||
free(body);
|
|
||||||
if (json == NULL) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid json");
|
|
||||||
}
|
|
||||||
cJSON *jtimeout = cJSON_GetObjectItemCaseSensitive(json, "timeout_ms");
|
|
||||||
if (jtimeout != NULL) {
|
|
||||||
if (!cJSON_IsNumber(jtimeout) ||
|
|
||||||
jtimeout->valuedouble < (double)domain_policy_rest_label_timeout_min_ms() ||
|
|
||||||
jtimeout->valuedouble > (double)domain_policy_rest_label_timeout_max_ms()) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "timeout_ms out of range");
|
|
||||||
}
|
|
||||||
timeout_ms = (uint32_t)jtimeout->valuedouble;
|
|
||||||
}
|
|
||||||
cJSON_Delete(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
char cmd_err[128] = {0};
|
|
||||||
esp_err_t rc = printer_protocol_gap_move(timeout_ms, cmd_err, sizeof(cmd_err));
|
|
||||||
if (rc != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "409 Conflict", cmd_err[0] != '\0' ? cmd_err : "gap move failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *root = cJSON_CreateObject();
|
|
||||||
cJSON_AddBoolToObject(root, "ok", true);
|
|
||||||
cJSON_AddStringToObject(root, "message", "gap move success");
|
|
||||||
cJSON_AddNumberToObject(root, "timeout_ms", timeout_ms);
|
|
||||||
esp_err_t err = rest_server_send_json(req, "200 OK", root);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_label_offset_get(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t offset = 0;
|
|
||||||
char cmd_err[128] = {0};
|
|
||||||
esp_err_t rc = printer_protocol_get_label_offset(&offset,
|
|
||||||
domain_policy_rest_label_timeout_ms(),
|
|
||||||
cmd_err,
|
|
||||||
sizeof(cmd_err));
|
|
||||||
if (rc != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "409 Conflict", cmd_err[0] != '\0' ? cmd_err : "get offset failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *root = cJSON_CreateObject();
|
|
||||||
cJSON_AddBoolToObject(root, "ok", true);
|
|
||||||
cJSON_AddNumberToObject(root, "offset_tenths_mm", offset);
|
|
||||||
cJSON_AddNumberToObject(root, "offset_mm", ((double)offset) / 10.0);
|
|
||||||
esp_err_t err = rest_server_send_json(req, "200 OK", root);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_label_offset_post(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
char *body = NULL;
|
|
||||||
esp_err_t body_err = rest_server_read_body(req, &body);
|
|
||||||
if (body_err != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid request body");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *json = cJSON_Parse(body);
|
|
||||||
free(body);
|
|
||||||
if (json == NULL) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid json");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jvalue = cJSON_GetObjectItemCaseSensitive(json, "offset_tenths_mm");
|
|
||||||
if (!cJSON_IsNumber(jvalue) || jvalue->valuedouble < 0 || jvalue->valuedouble > 254) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "offset_tenths_mm must be 0..254");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t value = (uint8_t)jvalue->valuedouble;
|
|
||||||
cJSON_Delete(json);
|
|
||||||
|
|
||||||
char cmd_err[128] = {0};
|
|
||||||
esp_err_t rc = printer_protocol_set_label_offset(value,
|
|
||||||
domain_policy_rest_label_timeout_ms(),
|
|
||||||
cmd_err,
|
|
||||||
sizeof(cmd_err));
|
|
||||||
if (rc != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "409 Conflict", cmd_err[0] != '\0' ? cmd_err : "set offset failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *root = cJSON_CreateObject();
|
|
||||||
cJSON_AddBoolToObject(root, "ok", true);
|
|
||||||
cJSON_AddNumberToObject(root, "offset_tenths_mm", value);
|
|
||||||
cJSON_AddNumberToObject(root, "offset_mm", ((double)value) / 10.0);
|
|
||||||
esp_err_t err = rest_server_send_json(req, "200 OK", root);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_ota_version_get(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
printer_ota_version_t version = {0};
|
|
||||||
char cmd_err[128] = {0};
|
|
||||||
esp_err_t rc = printer_protocol_ota_get_version(&version,
|
|
||||||
domain_policy_rest_ota_timeout_ms(),
|
|
||||||
cmd_err,
|
|
||||||
sizeof(cmd_err));
|
|
||||||
if (rc != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "409 Conflict", cmd_err[0] != '\0' ? cmd_err : "get version failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *root = cJSON_CreateObject();
|
|
||||||
cJSON_AddBoolToObject(root, "ok", true);
|
|
||||||
cJSON_AddNumberToObject(root, "major", version.major);
|
|
||||||
cJSON_AddNumberToObject(root, "minor", version.minor);
|
|
||||||
cJSON_AddNumberToObject(root, "patch", version.patch);
|
|
||||||
char version_text[32];
|
|
||||||
snprintf(version_text, sizeof(version_text), "V%u.%u.%u", version.major, version.minor, version.patch);
|
|
||||||
cJSON_AddStringToObject(root, "version", version_text);
|
|
||||||
esp_err_t err = rest_server_send_json(req, "200 OK", root);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_ota_jump_boot_post(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
char cmd_err[128] = {0};
|
|
||||||
esp_err_t rc = printer_protocol_ota_jump_boot(domain_policy_rest_ota_timeout_ms(),
|
|
||||||
cmd_err,
|
|
||||||
sizeof(cmd_err));
|
|
||||||
if (rc != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "409 Conflict", cmd_err[0] != '\0' ? cmd_err : "jump boot failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *root = cJSON_CreateObject();
|
|
||||||
cJSON_AddBoolToObject(root, "ok", true);
|
|
||||||
cJSON_AddStringToObject(root, "message", "jumped to boot");
|
|
||||||
esp_err_t err = rest_server_send_json(req, "200 OK", root);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_ota_jump_app_post(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
char cmd_err[128] = {0};
|
|
||||||
esp_err_t rc = printer_protocol_ota_jump_app(domain_policy_rest_ota_timeout_ms(),
|
|
||||||
cmd_err,
|
|
||||||
sizeof(cmd_err));
|
|
||||||
if (rc != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "409 Conflict", cmd_err[0] != '\0' ? cmd_err : "jump app failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *root = cJSON_CreateObject();
|
|
||||||
cJSON_AddBoolToObject(root, "ok", true);
|
|
||||||
cJSON_AddStringToObject(root, "message", "jumped to app");
|
|
||||||
esp_err_t err = rest_server_send_json(req, "200 OK", root);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_ota_erase_page_post(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
char *body = NULL;
|
|
||||||
esp_err_t body_err = rest_server_read_body(req, &body);
|
|
||||||
if (body_err != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid request body");
|
|
||||||
}
|
|
||||||
cJSON *json = cJSON_Parse(body);
|
|
||||||
free(body);
|
|
||||||
if (json == NULL) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid json");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jpage = cJSON_GetObjectItemCaseSensitive(json, "page_num");
|
|
||||||
cJSON *jtimeout = cJSON_GetObjectItemCaseSensitive(json, "timeout_ms");
|
|
||||||
if (!cJSON_IsNumber(jpage) || jpage->valuedouble < 0 || jpage->valuedouble > 65535) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "page_num must be 0..65535");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t timeout_ms = domain_policy_rest_ota_timeout_ms();
|
|
||||||
if (jtimeout != NULL) {
|
|
||||||
if (!cJSON_IsNumber(jtimeout) ||
|
|
||||||
jtimeout->valuedouble < (double)domain_policy_rest_ota_timeout_min_ms() ||
|
|
||||||
jtimeout->valuedouble > (double)domain_policy_rest_ota_timeout_max_ms()) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "timeout_ms out of range");
|
|
||||||
}
|
|
||||||
timeout_ms = (uint32_t)jtimeout->valuedouble;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t page_num = (uint16_t)jpage->valuedouble;
|
|
||||||
cJSON_Delete(json);
|
|
||||||
|
|
||||||
char cmd_err[128] = {0};
|
|
||||||
esp_err_t rc = printer_protocol_ota_erase_page(page_num, timeout_ms, cmd_err, sizeof(cmd_err));
|
|
||||||
if (rc != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "409 Conflict", cmd_err[0] != '\0' ? cmd_err : "erase page failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *root = cJSON_CreateObject();
|
|
||||||
cJSON_AddBoolToObject(root, "ok", true);
|
|
||||||
cJSON_AddNumberToObject(root, "page_num", page_num);
|
|
||||||
esp_err_t err = rest_server_send_json(req, "200 OK", root);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_ota_write_frame_post(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
char *body = NULL;
|
|
||||||
esp_err_t body_err = rest_server_read_body(req, &body);
|
|
||||||
if (body_err != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid request body");
|
|
||||||
}
|
|
||||||
cJSON *json = cJSON_Parse(body);
|
|
||||||
free(body);
|
|
||||||
if (json == NULL) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid json");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jpack = cJSON_GetObjectItemCaseSensitive(json, "packet_num");
|
|
||||||
cJSON *jlast = cJSON_GetObjectItemCaseSensitive(json, "is_last_frame");
|
|
||||||
cJSON *jdata = cJSON_GetObjectItemCaseSensitive(json, "data");
|
|
||||||
cJSON *jtimeout = cJSON_GetObjectItemCaseSensitive(json, "timeout_ms");
|
|
||||||
|
|
||||||
if (!cJSON_IsNumber(jpack) || jpack->valuedouble < 0 || jpack->valuedouble > 65535 ||
|
|
||||||
!cJSON_IsString(jdata) || jdata->valuestring == NULL) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "packet_num and data are required");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t timeout_ms = domain_policy_rest_ota_timeout_ms();
|
|
||||||
if (jtimeout != NULL) {
|
|
||||||
if (!cJSON_IsNumber(jtimeout) ||
|
|
||||||
jtimeout->valuedouble < (double)domain_policy_rest_ota_timeout_min_ms() ||
|
|
||||||
jtimeout->valuedouble > (double)domain_policy_rest_ota_timeout_max_ms()) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "timeout_ms out of range");
|
|
||||||
}
|
|
||||||
timeout_ms = (uint32_t)jtimeout->valuedouble;
|
|
||||||
}
|
|
||||||
bool is_last = rest_server_json_bool_with_default(jlast, false);
|
|
||||||
uint16_t packet_num = (uint16_t)jpack->valuedouble;
|
|
||||||
|
|
||||||
uint8_t *frame_data = NULL;
|
|
||||||
size_t frame_len = 0;
|
|
||||||
esp_err_t b64_rc = rest_server_base64_decode_alloc(jdata->valuestring, &frame_data, &frame_len);
|
|
||||||
cJSON_Delete(json);
|
|
||||||
if (b64_rc != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid base64 data");
|
|
||||||
}
|
|
||||||
|
|
||||||
char cmd_err[128] = {0};
|
|
||||||
esp_err_t rc = printer_protocol_ota_write_frame(packet_num,
|
|
||||||
is_last,
|
|
||||||
frame_data,
|
|
||||||
frame_len,
|
|
||||||
timeout_ms,
|
|
||||||
cmd_err,
|
|
||||||
sizeof(cmd_err));
|
|
||||||
free(frame_data);
|
|
||||||
if (rc != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "409 Conflict", cmd_err[0] != '\0' ? cmd_err : "write frame failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *root = cJSON_CreateObject();
|
|
||||||
cJSON_AddBoolToObject(root, "ok", true);
|
|
||||||
cJSON_AddNumberToObject(root, "packet_num", packet_num);
|
|
||||||
cJSON_AddBoolToObject(root, "is_last_frame", is_last);
|
|
||||||
esp_err_t err = rest_server_send_json(req, "200 OK", root);
|
|
||||||
cJSON_Delete(root);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_ota_upgrade_post(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"409 Conflict",
|
|
||||||
"bulk ota upgrade endpoint disabled; use jump/erase/write/version step APIs");
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,540 +0,0 @@
|
|||||||
#include "rest_server_internal.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <strings.h>
|
|
||||||
|
|
||||||
#include "domain.h"
|
|
||||||
|
|
||||||
static esp_err_t decode_image_json_to_raster(cJSON *json,
|
|
||||||
uint16_t *out_width,
|
|
||||||
uint16_t *out_height,
|
|
||||||
uint8_t **out_raster,
|
|
||||||
size_t *out_len,
|
|
||||||
char *err,
|
|
||||||
size_t err_len) {
|
|
||||||
if (json == NULL || out_width == NULL || out_height == NULL || out_raster == NULL || out_len == NULL) {
|
|
||||||
if (err != NULL && err_len > 0) {
|
|
||||||
snprintf(err, err_len, "invalid args");
|
|
||||||
}
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_width = 0;
|
|
||||||
*out_height = 0;
|
|
||||||
*out_raster = NULL;
|
|
||||||
*out_len = 0;
|
|
||||||
|
|
||||||
cJSON *jwidth = cJSON_GetObjectItemCaseSensitive(json, "width");
|
|
||||||
cJSON *jheight = cJSON_GetObjectItemCaseSensitive(json, "height");
|
|
||||||
cJSON *jencoding = cJSON_GetObjectItemCaseSensitive(json, "encoding");
|
|
||||||
cJSON *jdata = cJSON_GetObjectItemCaseSensitive(json, "data");
|
|
||||||
|
|
||||||
if (!cJSON_IsNumber(jwidth) || !cJSON_IsNumber(jheight) ||
|
|
||||||
!cJSON_IsString(jencoding) || !cJSON_IsString(jdata)) {
|
|
||||||
if (err != NULL && err_len > 0) {
|
|
||||||
snprintf(err, err_len, "missing required image fields");
|
|
||||||
}
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t width = (uint16_t)jwidth->valuedouble;
|
|
||||||
uint16_t height = (uint16_t)jheight->valuedouble;
|
|
||||||
if (width == 0 || height == 0) {
|
|
||||||
if (err != NULL && err_len > 0) {
|
|
||||||
snprintf(err, err_len, "invalid image size");
|
|
||||||
}
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(jencoding->valuestring, "base64_msb_1bpp") == 0) {
|
|
||||||
uint8_t *raw = NULL;
|
|
||||||
size_t raw_len = 0;
|
|
||||||
esp_err_t b64_rc = rest_server_base64_decode_alloc(jdata->valuestring, &raw, &raw_len);
|
|
||||||
if (b64_rc != ESP_OK) {
|
|
||||||
if (err != NULL && err_len > 0) {
|
|
||||||
snprintf(err, err_len, "invalid base64");
|
|
||||||
}
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
*out_width = width;
|
|
||||||
*out_height = height;
|
|
||||||
*out_raster = raw;
|
|
||||||
*out_len = raw_len;
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(jencoding->valuestring, "base64_gray8") == 0) {
|
|
||||||
uint8_t *gray = NULL;
|
|
||||||
size_t gray_len = 0;
|
|
||||||
esp_err_t b64_rc = rest_server_base64_decode_alloc(jdata->valuestring, &gray, &gray_len);
|
|
||||||
if (b64_rc != ESP_OK) {
|
|
||||||
if (err != NULL && err_len > 0) {
|
|
||||||
snprintf(err, err_len, "invalid base64");
|
|
||||||
}
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t expected = (size_t)width * height;
|
|
||||||
if (gray_len != expected) {
|
|
||||||
free(gray);
|
|
||||||
if (err != NULL && err_len > 0) {
|
|
||||||
snprintf(err, err_len, "gray8 size mismatch");
|
|
||||||
}
|
|
||||||
return ESP_ERR_INVALID_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jscale = cJSON_GetObjectItemCaseSensitive(json, "scale_to_width");
|
|
||||||
cJSON *jthreshold = cJSON_GetObjectItemCaseSensitive(json, "threshold");
|
|
||||||
cJSON *jinvert = cJSON_GetObjectItemCaseSensitive(json, "invert");
|
|
||||||
cJSON *jmaxh = cJSON_GetObjectItemCaseSensitive(json, "max_height");
|
|
||||||
|
|
||||||
bool scale_to_width = rest_server_json_bool_with_default(jscale, true);
|
|
||||||
bool invert = rest_server_json_bool_with_default(jinvert, false);
|
|
||||||
uint8_t threshold = 160;
|
|
||||||
uint16_t max_height = 2200;
|
|
||||||
if (cJSON_IsNumber(jthreshold) && jthreshold->valuedouble >= 0 && jthreshold->valuedouble <= 255) {
|
|
||||||
threshold = (uint8_t)jthreshold->valuedouble;
|
|
||||||
}
|
|
||||||
if (cJSON_IsNumber(jmaxh) && jmaxh->valuedouble >= 64 && jmaxh->valuedouble <= 3000) {
|
|
||||||
max_height = (uint16_t)jmaxh->valuedouble;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t out_w = 0;
|
|
||||||
uint16_t out_h = 0;
|
|
||||||
uint8_t *raster = NULL;
|
|
||||||
size_t raster_len = 0;
|
|
||||||
esp_err_t conv_rc = raster_tools_convert_gray8_to_raster_384(gray,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
scale_to_width,
|
|
||||||
threshold,
|
|
||||||
invert,
|
|
||||||
max_height,
|
|
||||||
&out_w,
|
|
||||||
&out_h,
|
|
||||||
&raster,
|
|
||||||
&raster_len,
|
|
||||||
err,
|
|
||||||
err_len);
|
|
||||||
free(gray);
|
|
||||||
if (conv_rc != ESP_OK) {
|
|
||||||
return conv_rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_width = out_w;
|
|
||||||
*out_height = out_h;
|
|
||||||
*out_raster = raster;
|
|
||||||
*out_len = raster_len;
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err != NULL && err_len > 0) {
|
|
||||||
snprintf(err, err_len, "unsupported encoding");
|
|
||||||
}
|
|
||||||
return ESP_ERR_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_print_qr_post(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
char *body = NULL;
|
|
||||||
esp_err_t body_err = rest_server_read_body(req, &body);
|
|
||||||
if (body_err != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid request body");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *json = cJSON_Parse(body);
|
|
||||||
free(body);
|
|
||||||
if (json == NULL) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid json");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jtext = cJSON_GetObjectItemCaseSensitive(json, "text");
|
|
||||||
cJSON *jdensity = cJSON_GetObjectItemCaseSensitive(json, "density");
|
|
||||||
cJSON *jecc = cJSON_GetObjectItemCaseSensitive(json, "ecc");
|
|
||||||
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);
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "text is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
if (strcasecmp(jecc->valuestring, "L") == 0) {
|
|
||||||
ecc_level = 0;
|
|
||||||
} else if (strcasecmp(jecc->valuestring, "M") == 0) {
|
|
||||||
ecc_level = 1;
|
|
||||||
} else if (strcasecmp(jecc->valuestring, "Q") == 0) {
|
|
||||||
ecc_level = 2;
|
|
||||||
} else if (strcasecmp(jecc->valuestring, "H") == 0) {
|
|
||||||
ecc_level = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t module_scale = 0;
|
|
||||||
uint8_t margin_modules = 2;
|
|
||||||
uint16_t max_height = 2200;
|
|
||||||
if (cJSON_IsNumber(jscale) && jscale->valuedouble >= 0 && jscale->valuedouble <= 16) {
|
|
||||||
module_scale = (uint8_t)jscale->valuedouble;
|
|
||||||
}
|
|
||||||
if (cJSON_IsNumber(jmargin) && jmargin->valuedouble >= 1 && jmargin->valuedouble <= 12) {
|
|
||||||
margin_modules = (uint8_t)jmargin->valuedouble;
|
|
||||||
}
|
|
||||||
if (cJSON_IsNumber(jmaxh) && jmaxh->valuedouble >= 64 && jmaxh->valuedouble <= 3000) {
|
|
||||||
max_height = (uint16_t)jmaxh->valuedouble;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t width = 0;
|
|
||||||
uint16_t height = 0;
|
|
||||||
uint8_t *raster = NULL;
|
|
||||||
size_t raster_len = 0;
|
|
||||||
char render_msg[128] = {0};
|
|
||||||
esp_err_t qr_rc = raster_tools_render_qr_384(jtext->valuestring,
|
|
||||||
module_scale,
|
|
||||||
margin_modules,
|
|
||||||
ecc_level,
|
|
||||||
max_height,
|
|
||||||
&width,
|
|
||||||
&height,
|
|
||||||
&raster,
|
|
||||||
&raster_len,
|
|
||||||
render_msg,
|
|
||||||
sizeof(render_msg));
|
|
||||||
cJSON_Delete(json);
|
|
||||||
if (qr_rc != ESP_OK) {
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"400 Bad Request",
|
|
||||||
render_msg[0] != '\0' ? render_msg : "qr render failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t submit_rc = rest_server_print_submit_raster_job_and_reply(req,
|
|
||||||
raster,
|
|
||||||
raster_len,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
density,
|
|
||||||
direct_ignore_precheck,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
free(raster);
|
|
||||||
return submit_rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_print_label_post(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
char *body = NULL;
|
|
||||||
esp_err_t body_err = rest_server_read_body(req, &body);
|
|
||||||
if (body_err != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid request body");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *json = cJSON_Parse(body);
|
|
||||||
free(body);
|
|
||||||
if (json == NULL) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid json");
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
uint8_t offset_value = 0;
|
|
||||||
if (has_offset) {
|
|
||||||
if (joffset->valuedouble < 0 || joffset->valuedouble > 254) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "offset_tenths_mm must be 0..254");
|
|
||||||
}
|
|
||||||
offset_value = (uint8_t)joffset->valuedouble;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
uint8_t *raster = NULL;
|
|
||||||
size_t raster_len = 0;
|
|
||||||
char decode_err[128] = {0};
|
|
||||||
esp_err_t decode_rc = decode_image_json_to_raster(json,
|
|
||||||
&width,
|
|
||||||
&height,
|
|
||||||
&raster,
|
|
||||||
&raster_len,
|
|
||||||
decode_err,
|
|
||||||
sizeof(decode_err));
|
|
||||||
cJSON_Delete(json);
|
|
||||||
if (decode_rc != ESP_OK) {
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"400 Bad Request",
|
|
||||||
decode_err[0] != '\0' ? decode_err : "decode image failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (has_offset) {
|
|
||||||
char cmd_err[128] = {0};
|
|
||||||
esp_err_t offset_rc = printer_protocol_set_label_offset(offset_value,
|
|
||||||
domain_policy_rest_label_timeout_ms(),
|
|
||||||
cmd_err,
|
|
||||||
sizeof(cmd_err));
|
|
||||||
if (offset_rc != ESP_OK) {
|
|
||||||
free(raster);
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"409 Conflict",
|
|
||||||
cmd_err[0] != '\0' ? cmd_err : "set label offset failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gap_move_before) {
|
|
||||||
char cmd_err[128] = {0};
|
|
||||||
esp_err_t gap_rc = printer_protocol_gap_move(domain_policy_rest_label_timeout_ms(),
|
|
||||||
cmd_err,
|
|
||||||
sizeof(cmd_err));
|
|
||||||
if (gap_rc != ESP_OK) {
|
|
||||||
free(raster);
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"409 Conflict",
|
|
||||||
cmd_err[0] != '\0' ? cmd_err : "gap move failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t submit_rc = rest_server_print_submit_raster_job_and_reply(req,
|
|
||||||
raster,
|
|
||||||
raster_len,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
density,
|
|
||||||
direct_ignore_precheck,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
free(raster);
|
|
||||||
return submit_rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_print_text_post(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
char *body = NULL;
|
|
||||||
esp_err_t body_err = rest_server_read_body(req, &body);
|
|
||||||
if (body_err != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid request body");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *json = cJSON_Parse(body);
|
|
||||||
free(body);
|
|
||||||
if (json == NULL) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid json");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jtext = cJSON_GetObjectItemCaseSensitive(json, "text");
|
|
||||||
cJSON *jdensity = cJSON_GetObjectItemCaseSensitive(json, "density");
|
|
||||||
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);
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "text is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (cJSON_IsNumber(jscale) && jscale->valuedouble >= 1 && jscale->valuedouble <= 6) {
|
|
||||||
scale = (uint8_t)jscale->valuedouble;
|
|
||||||
}
|
|
||||||
if (cJSON_IsNumber(jline) && jline->valuedouble >= 0 && jline->valuedouble <= 12) {
|
|
||||||
line_spacing = (uint8_t)jline->valuedouble;
|
|
||||||
}
|
|
||||||
if (cJSON_IsNumber(jmaxh) && jmaxh->valuedouble >= 64 && jmaxh->valuedouble <= 3000) {
|
|
||||||
max_height = (uint16_t)jmaxh->valuedouble;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t width = 0;
|
|
||||||
uint16_t height = 0;
|
|
||||||
uint8_t *raster = NULL;
|
|
||||||
size_t raster_len = 0;
|
|
||||||
char render_msg[128] = {0};
|
|
||||||
|
|
||||||
esp_err_t render_rc = raster_tools_render_text_384(jtext->valuestring,
|
|
||||||
scale,
|
|
||||||
line_spacing,
|
|
||||||
max_height,
|
|
||||||
&width,
|
|
||||||
&height,
|
|
||||||
&raster,
|
|
||||||
&raster_len,
|
|
||||||
render_msg,
|
|
||||||
sizeof(render_msg));
|
|
||||||
cJSON_Delete(json);
|
|
||||||
|
|
||||||
if (render_rc != ESP_OK) {
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"400 Bad Request",
|
|
||||||
render_msg[0] != '\0' ? render_msg : "text render failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t submit_rc = rest_server_print_submit_raster_job_and_reply(req,
|
|
||||||
raster,
|
|
||||||
raster_len,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
density,
|
|
||||||
direct_ignore_precheck,
|
|
||||||
render_msg,
|
|
||||||
NULL);
|
|
||||||
free(raster);
|
|
||||||
return submit_rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t rest_server_print_receipt_post(httpd_req_t *req) {
|
|
||||||
if (!rest_server_auth_ok(req)) {
|
|
||||||
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
char *body = NULL;
|
|
||||||
esp_err_t body_err = rest_server_read_body(req, &body);
|
|
||||||
if (body_err != ESP_OK) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid request body");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *json = cJSON_Parse(body);
|
|
||||||
free(body);
|
|
||||||
if (json == NULL) {
|
|
||||||
return rest_server_send_error(req, "400 Bad Request", "invalid json");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jtitle = cJSON_GetObjectItemCaseSensitive(json, "title");
|
|
||||||
cJSON *jitems = cJSON_GetObjectItemCaseSensitive(json, "items");
|
|
||||||
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
|
|
||||||
: "TQ RECEIPT";
|
|
||||||
const char *footer = (cJSON_IsString(jfooter) && jfooter->valuestring != NULL)
|
|
||||||
? jfooter->valuestring
|
|
||||||
: "Thank you";
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t text_cap = 8192;
|
|
||||||
char *text = (char *)calloc(1, text_cap);
|
|
||||||
if (text == NULL) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
return rest_server_send_error(req, "500 Internal Server Error", "no memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t off = 0;
|
|
||||||
rest_server_appendf(text, text_cap, &off, "%s\n", title);
|
|
||||||
rest_server_appendf(text, text_cap, &off, "--------------------------------\n");
|
|
||||||
|
|
||||||
double total = 0.0;
|
|
||||||
if (cJSON_IsArray(jitems)) {
|
|
||||||
int n = cJSON_GetArraySize(jitems);
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
cJSON *it = cJSON_GetArrayItem(jitems, i);
|
|
||||||
if (!cJSON_IsObject(it)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *jname = cJSON_GetObjectItemCaseSensitive(it, "name");
|
|
||||||
cJSON *jqty = cJSON_GetObjectItemCaseSensitive(it, "qty");
|
|
||||||
cJSON *jprice = cJSON_GetObjectItemCaseSensitive(it, "price");
|
|
||||||
|
|
||||||
const char *name = (cJSON_IsString(jname) && jname->valuestring != NULL)
|
|
||||||
? jname->valuestring
|
|
||||||
: "item";
|
|
||||||
int qty = cJSON_IsNumber(jqty) ? (int)jqty->valuedouble : 1;
|
|
||||||
double price = cJSON_IsNumber(jprice) ? jprice->valuedouble : 0.0;
|
|
||||||
double line_total = qty * price;
|
|
||||||
total += line_total;
|
|
||||||
|
|
||||||
rest_server_appendf(text,
|
|
||||||
text_cap,
|
|
||||||
&off,
|
|
||||||
"%-16.16s x%-3d %8.2f\n",
|
|
||||||
name,
|
|
||||||
qty,
|
|
||||||
line_total);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rest_server_appendf(text, text_cap, &off, "(no items)\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
rest_server_appendf(text, text_cap, &off, "--------------------------------\n");
|
|
||||||
rest_server_appendf(text, text_cap, &off, "TOTAL: %.2f\n", total);
|
|
||||||
rest_server_appendf(text, text_cap, &off, "%s\n", footer);
|
|
||||||
|
|
||||||
uint16_t width = 0;
|
|
||||||
uint16_t height = 0;
|
|
||||||
uint8_t *raster = NULL;
|
|
||||||
size_t raster_len = 0;
|
|
||||||
char render_msg[128] = {0};
|
|
||||||
|
|
||||||
esp_err_t render_rc = raster_tools_render_text_384(text,
|
|
||||||
scale,
|
|
||||||
2,
|
|
||||||
2200,
|
|
||||||
&width,
|
|
||||||
&height,
|
|
||||||
&raster,
|
|
||||||
&raster_len,
|
|
||||||
render_msg,
|
|
||||||
sizeof(render_msg));
|
|
||||||
free(text);
|
|
||||||
cJSON_Delete(json);
|
|
||||||
|
|
||||||
if (render_rc != ESP_OK) {
|
|
||||||
return rest_server_send_error(req,
|
|
||||||
"400 Bad Request",
|
|
||||||
render_msg[0] != '\0' ? render_msg : "receipt render failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t submit_rc = rest_server_print_submit_raster_job_and_reply(req,
|
|
||||||
raster,
|
|
||||||
raster_len,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
density,
|
|
||||||
direct_ignore_precheck,
|
|
||||||
render_msg,
|
|
||||||
NULL);
|
|
||||||
free(raster);
|
|
||||||
return submit_rc;
|
|
||||||
}
|
|
||||||
90
components/control_plane/src/rest_server_print_text.c
Normal file
90
components/control_plane/src/rest_server_print_text.c
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#include "rest_server_internal.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "domain.h"
|
||||||
|
|
||||||
|
esp_err_t rest_server_print_text_post(httpd_req_t *req) {
|
||||||
|
if (!rest_server_auth_ok(req)) {
|
||||||
|
return rest_server_send_error(req, "401 Unauthorized", "unauthorized");
|
||||||
|
}
|
||||||
|
|
||||||
|
char *body = NULL;
|
||||||
|
esp_err_t body_err = rest_server_read_body(req, &body);
|
||||||
|
if (body_err != ESP_OK) {
|
||||||
|
return rest_server_send_error(req, "400 Bad Request", "invalid request body");
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON *json = cJSON_Parse(body);
|
||||||
|
free(body);
|
||||||
|
if (json == NULL) {
|
||||||
|
return rest_server_send_error(req, "400 Bad Request", "invalid json");
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON *jtext = cJSON_GetObjectItemCaseSensitive(json, "text");
|
||||||
|
cJSON *jdensity = cJSON_GetObjectItemCaseSensitive(json, "density");
|
||||||
|
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);
|
||||||
|
return rest_server_send_error(req, "400 Bad Request", "text is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (cJSON_IsNumber(jscale) && jscale->valuedouble >= 1 && jscale->valuedouble <= 6) {
|
||||||
|
scale = (uint8_t)jscale->valuedouble;
|
||||||
|
}
|
||||||
|
if (cJSON_IsNumber(jline) && jline->valuedouble >= 0 && jline->valuedouble <= 12) {
|
||||||
|
line_spacing = (uint8_t)jline->valuedouble;
|
||||||
|
}
|
||||||
|
if (cJSON_IsNumber(jmaxh) && jmaxh->valuedouble >= 64 && jmaxh->valuedouble <= 3000) {
|
||||||
|
max_height = (uint16_t)jmaxh->valuedouble;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t width = 0;
|
||||||
|
uint16_t height = 0;
|
||||||
|
uint8_t *raster = NULL;
|
||||||
|
size_t raster_len = 0;
|
||||||
|
char render_msg[128] = {0};
|
||||||
|
|
||||||
|
esp_err_t render_rc = raster_tools_render_text_384(jtext->valuestring,
|
||||||
|
scale,
|
||||||
|
line_spacing,
|
||||||
|
max_height,
|
||||||
|
&width,
|
||||||
|
&height,
|
||||||
|
&raster,
|
||||||
|
&raster_len,
|
||||||
|
render_msg,
|
||||||
|
sizeof(render_msg));
|
||||||
|
cJSON_Delete(json);
|
||||||
|
|
||||||
|
if (render_rc != ESP_OK) {
|
||||||
|
return rest_server_send_error(req,
|
||||||
|
"400 Bad Request",
|
||||||
|
render_msg[0] != 0 ? render_msg : "text render failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t submit_rc = rest_server_print_submit_raster_job_and_reply(req,
|
||||||
|
raster,
|
||||||
|
raster_len,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
density,
|
||||||
|
direct_ignore_precheck,
|
||||||
|
render_msg,
|
||||||
|
NULL);
|
||||||
|
free(raster);
|
||||||
|
return submit_rc;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user