Fix PT-P710BT raster protocol handling and add regression coverage.
Align print command payload generation with model-specific protocol requirements, add verbose CLI diagnostics and robust status retries, and introduce protocol regression tests to prevent future GF/ESC i z regressions. Made-with: Cursor
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "libptouch_internal.h"
|
||||
#include "libptouch_layout.h"
|
||||
#include "libptouch_protocol.h"
|
||||
|
||||
#include <libusb.h>
|
||||
#include <stdio.h>
|
||||
@@ -102,7 +103,7 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx,
|
||||
(void)right_dots;
|
||||
|
||||
unsigned head_dots = prof->head_width_dots;
|
||||
size_t line_payload = (size_t)((head_dots + 7u) / 8u);
|
||||
size_t line_payload = ptouch_line_payload_bytes(head_dots);
|
||||
size_t gf_packet = 3u + line_payload;
|
||||
|
||||
uint32_t wd = params->width_dots;
|
||||
@@ -139,21 +140,6 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx,
|
||||
}
|
||||
|
||||
uint32_t lines = ht;
|
||||
uint8_t n5 = (uint8_t)(lines & 0xFFu);
|
||||
uint8_t n6 = (uint8_t)((lines >> 8) & 0xFFu);
|
||||
uint8_t n7 = (uint8_t)((lines >> 16) & 0xFFu);
|
||||
uint8_t n8 = (uint8_t)((lines >> 24) & 0xFFu);
|
||||
|
||||
uint8_t n2_paper = 0x09u;
|
||||
if (media_kind == 0x03u)
|
||||
n2_paper = 0x00u;
|
||||
else if (media_kind == 0x11u)
|
||||
n2_paper = 0x11u;
|
||||
else if (media_kind == 0x17u)
|
||||
n2_paper = 0x17u;
|
||||
else if (media_kind == 0x13u)
|
||||
n2_paper = 0x13u;
|
||||
|
||||
uint8_t head[256];
|
||||
size_t pos = 0;
|
||||
memset(head + pos, 0, 200);
|
||||
@@ -165,18 +151,28 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx,
|
||||
memcpy(head + pos, raster_mode, sizeof(raster_mode));
|
||||
pos += sizeof(raster_mode);
|
||||
|
||||
uint8_t esc_iz[] = { 0x1B, 0x69, 0x7A, 0x0Eu, n2_paper, media_w,
|
||||
0x00u, n5, n6, n7, n8, 0x02u, 0x00u };
|
||||
uint8_t esc_iz[13];
|
||||
ptouch_fill_esc_iz(esc_iz, media_kind, media_w, lines);
|
||||
memcpy(head + pos, esc_iz, sizeof(esc_iz));
|
||||
pos += sizeof(esc_iz);
|
||||
|
||||
static const uint8_t esc_im[] = { 0x1B, 0x69, 0x4D, 0x40 };
|
||||
memcpy(head + pos, esc_im, sizeof(esc_im));
|
||||
pos += sizeof(esc_im);
|
||||
static const uint8_t esc_ia[] = { 0x1B, 0x69, 0x41, 0x01 };
|
||||
memcpy(head + pos, esc_ia, sizeof(esc_ia));
|
||||
pos += sizeof(esc_ia);
|
||||
static const uint8_t esc_ik[] = { 0x1B, 0x69, 0x4B, 0x0C };
|
||||
|
||||
/*
|
||||
* ESC i A ("cut each n labels") is not supported on PT-P710BT class
|
||||
* devices. Sending it can trigger a communication error (red LED blink).
|
||||
* Keep it only for 560-dot family.
|
||||
*/
|
||||
if (prof->head_width_dots > 128u) {
|
||||
static const uint8_t esc_ia[] = { 0x1B, 0x69, 0x41, 0x01 };
|
||||
memcpy(head + pos, esc_ia, sizeof(esc_ia));
|
||||
pos += sizeof(esc_ia);
|
||||
}
|
||||
|
||||
/* Chain printing off; safer default for 128-dot family as well. */
|
||||
static const uint8_t esc_ik[] = { 0x1B, 0x69, 0x4B, 0x08 };
|
||||
memcpy(head + pos, esc_ik, sizeof(esc_ik));
|
||||
pos += sizeof(esc_ik);
|
||||
|
||||
@@ -199,7 +195,6 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx,
|
||||
}
|
||||
|
||||
size_t row_b = ((size_t)wd + 7u) / 8u;
|
||||
static const uint8_t g_hdr[] = { 0x47, 0x46, 0x00 };
|
||||
|
||||
uint8_t *gbuf = (uint8_t *)malloc(gf_packet);
|
||||
if (!gbuf) {
|
||||
@@ -213,7 +208,7 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx,
|
||||
const uint8_t *row = src + (size_t)y * row_b;
|
||||
pack_line(gbuf + 3, line_payload, head_dots, row, wd, left_dots,
|
||||
print_dots);
|
||||
memcpy(gbuf, g_hdr, sizeof(g_hdr));
|
||||
ptouch_fill_gf_header(gbuf, line_payload);
|
||||
v = ptouch_bulk_send_job(ctx, gbuf, gf_packet, "raster line");
|
||||
if (v != LIBPTOUCH_OK) {
|
||||
free(gbuf);
|
||||
|
||||
41
src/lib/libptouch_protocol.c
Normal file
41
src/lib/libptouch_protocol.c
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "libptouch_protocol.h"
|
||||
|
||||
size_t ptouch_line_payload_bytes(unsigned head_dots)
|
||||
{
|
||||
return (size_t)((head_dots + 7u) / 8u);
|
||||
}
|
||||
|
||||
void ptouch_fill_gf_header(uint8_t out[3], size_t line_payload_bytes)
|
||||
{
|
||||
out[0] = 0x47u;
|
||||
out[1] = (uint8_t)(line_payload_bytes & 0xFFu);
|
||||
out[2] = (uint8_t)((line_payload_bytes >> 8) & 0xFFu);
|
||||
}
|
||||
|
||||
void ptouch_fill_esc_iz(uint8_t out[13], uint8_t media_kind, uint8_t media_width,
|
||||
uint32_t raster_lines)
|
||||
{
|
||||
uint8_t n2_paper = 0x09u;
|
||||
if (media_kind == 0x03u)
|
||||
n2_paper = 0x00u;
|
||||
else if (media_kind == 0x11u)
|
||||
n2_paper = 0x11u;
|
||||
else if (media_kind == 0x17u)
|
||||
n2_paper = 0x17u;
|
||||
else if (media_kind == 0x13u)
|
||||
n2_paper = 0x13u;
|
||||
|
||||
out[0] = 0x1Bu;
|
||||
out[1] = 0x69u;
|
||||
out[2] = 0x7Au;
|
||||
out[3] = 0x0Eu;
|
||||
out[4] = n2_paper;
|
||||
out[5] = media_width;
|
||||
out[6] = 0x00u;
|
||||
out[7] = (uint8_t)(raster_lines & 0xFFu);
|
||||
out[8] = (uint8_t)((raster_lines >> 8) & 0xFFu);
|
||||
out[9] = (uint8_t)((raster_lines >> 16) & 0xFFu);
|
||||
out[10] = (uint8_t)((raster_lines >> 24) & 0xFFu);
|
||||
out[11] = 0x00u; /* first page */
|
||||
out[12] = 0x00u; /* fixed */
|
||||
}
|
||||
12
src/lib/libptouch_protocol.h
Normal file
12
src/lib/libptouch_protocol.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef LIBPTOUCH_PROTOCOL_H
|
||||
#define LIBPTOUCH_PROTOCOL_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
size_t ptouch_line_payload_bytes(unsigned head_dots);
|
||||
void ptouch_fill_gf_header(uint8_t out[3], size_t line_payload_bytes);
|
||||
void ptouch_fill_esc_iz(uint8_t out[13], uint8_t media_kind, uint8_t media_width,
|
||||
uint32_t raster_lines);
|
||||
|
||||
#endif /* LIBPTOUCH_PROTOCOL_H */
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
libptouch_err_t libptouch_get_status(libptouch_ctx *ctx, uint8_t *status)
|
||||
{
|
||||
@@ -28,18 +29,26 @@ libptouch_err_t libptouch_get_status(libptouch_ctx *ctx, uint8_t *status)
|
||||
static const uint8_t req[] = { 0x1B, 0x69, 0x53 };
|
||||
|
||||
int r = LIBUSB_ERROR_OTHER;
|
||||
for (int attempt = 0; attempt < 2; attempt++) {
|
||||
for (int attempt = 0; attempt < 5; attempt++) {
|
||||
/* First status read after reconnect can fail on some P-touch units. */
|
||||
(void)libusb_clear_halt(h, ctx->bulk_in_ep);
|
||||
(void)libusb_clear_halt(h, ctx->bulk_out_ep);
|
||||
if (attempt > 0) {
|
||||
(void)libusb_clear_halt(h, ctx->bulk_in_ep);
|
||||
(void)libusb_clear_halt(h, ctx->bulk_out_ep);
|
||||
usleep(120000); /* 120ms backoff */
|
||||
}
|
||||
r = ptouch_bulk_out(h, ctx->bulk_out_ep, init, 2, 5000u);
|
||||
if (r != 0) {
|
||||
if (r == LIBUSB_ERROR_IO || r == LIBUSB_ERROR_PIPE ||
|
||||
r == LIBUSB_ERROR_TIMEOUT)
|
||||
continue;
|
||||
ptouch_set_error_usb(ctx, r, "bulk OUT ESC @");
|
||||
return LIBPTOUCH_ERR_USB;
|
||||
}
|
||||
r = ptouch_bulk_out(h, ctx->bulk_out_ep, req, 3, 5000u);
|
||||
if (r != 0) {
|
||||
if (r == LIBUSB_ERROR_IO || r == LIBUSB_ERROR_PIPE ||
|
||||
r == LIBUSB_ERROR_TIMEOUT)
|
||||
continue;
|
||||
ptouch_set_error_usb(ctx, r, "bulk OUT ESC i S");
|
||||
return LIBPTOUCH_ERR_USB;
|
||||
}
|
||||
@@ -47,7 +56,8 @@ libptouch_err_t libptouch_get_status(libptouch_ctx *ctx, uint8_t *status)
|
||||
(int)LIBPTOUCH_STATUS_LENGTH, 5000u);
|
||||
if (r == 0)
|
||||
break;
|
||||
if (r != LIBUSB_ERROR_IO && r != LIBUSB_ERROR_PIPE)
|
||||
if (r != LIBUSB_ERROR_IO && r != LIBUSB_ERROR_PIPE &&
|
||||
r != LIBUSB_ERROR_TIMEOUT)
|
||||
break;
|
||||
}
|
||||
if (r != 0) {
|
||||
|
||||
Reference in New Issue
Block a user