diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5045453 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,19 @@ +# Changelog + +## Unreleased + +- Fix PT-P710BT/PT-P900W print completion flow and protocol bytes. + - Correct `G` raster transfer header length (`n1/n2`) from per-model payload size. + - Fix `ESC i z` page index (`n9`) and adjust print-information flags/media kind handling. + - Keep `ESC i A` disabled on 128-dot family and split `ESC i K` by head width. + - Use `0x0C -> 0x1A` end sequence on 560-dot family to complete feed/cut reliably. +- Improve status handling around print completion. + - Retry status reads with backoff and safer command ordering. + - Add verbose post-print short polling until print-end status is observed. + - Add small wait before `--status` command retrieval. +- Add protocol regression safeguards. + - Introduce `libptouch_protocol` helpers for shared command-byte generation. + - Add `protocol_regression_test` and wire it into CTest. +- Update documentation. + - Add `ctest` step to build instructions. + - Link to changelog from README. diff --git a/README.md b/README.md index 2fc2188..1886f1b 100644 --- a/README.md +++ b/README.md @@ -120,4 +120,8 @@ sudo usermod -aG plugdev "$USER" ## ライセンス -[MIT License](LICENSE)(`LICENSE` ファイルを参照)。 \ No newline at end of file +[MIT License](LICENSE)(`LICENSE` ファイルを参照)。 + +## 変更履歴 + +リリース間の変更点は `CHANGELOG.md` を参照してください。 \ No newline at end of file diff --git a/src/cli/main.c b/src/cli/main.c index 4ed60e1..1cf1ea1 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -13,6 +13,7 @@ #include #include #include +#include static void usage(const char *argv0) { @@ -141,12 +142,28 @@ static void verbose_print_post_print_status(libptouch_ctx *ctx, const char *labe if (!ctx) return; printf("=== verbose: post-print status (%s) ===\n", label); - uint8_t st[LIBPTOUCH_STATUS_LENGTH]; - if (libptouch_get_status(ctx, st) == LIBPTOUCH_OK) { - libptouch_status_fprint(stdout, st); - } else { - printf("status: unavailable (%s)\n", libptouch_strerror(ctx)); + /* + * 印刷直後は phase change (status[18] != 0x00) が続くことがあるため、 + * 短時間ポーリングで最終状態まで追跡する。 + */ + const int max_polls = 12; /* ~2.4s */ + const useconds_t poll_interval_us = 200000; + for (int i = 0; i < max_polls; i++) { + uint8_t st[LIBPTOUCH_STATUS_LENGTH]; + if (libptouch_get_status(ctx, st) != LIBPTOUCH_OK) { + printf("status poll %d/%d: unavailable (%s)\n", i + 1, + max_polls, libptouch_strerror(ctx)); + } else { + printf("status poll %d/%d:\n", i + 1, max_polls); + libptouch_status_fprint(stdout, st); + if (st[18] == 0x00u) { + printf("post-print polling settled: print end.\n"); + return; + } + } + usleep(poll_interval_us); } + printf("post-print polling timeout: phase did not settle.\n"); } int main(int argc, char **argv) @@ -261,6 +278,10 @@ int main(int argc, char **argv) libptouch_destroy(sctx); return 1; } + /* 印刷直後などは内部処理中で最初のステータス応答が不安定なことがあるため、 + * 少し待ってからステータスを取りに行く。 */ + usleep(300000); /* 300ms */ + uint8_t st[LIBPTOUCH_STATUS_LENGTH]; se = libptouch_get_status(sctx, st); if (se != LIBPTOUCH_OK) { diff --git a/src/lib/libptouch_print.c b/src/lib/libptouch_print.c index c9bcbc1..dcc22ed 100644 --- a/src/lib/libptouch_print.c +++ b/src/lib/libptouch_print.c @@ -171,8 +171,7 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx, 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 }; + uint8_t esc_ik[] = { 0x1B, 0x69, 0x4B, ptouch_esc_ik_value(head_dots) }; memcpy(head + pos, esc_ik, sizeof(esc_ik)); pos += sizeof(esc_ik); @@ -218,6 +217,21 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx, } free(gbuf); + /* + * Some 560-dot family devices are sensitive to end-of-page sequencing. + * Send FF (0x0C) then Control-Z (0x1A) on that family to explicitly + * terminate page and final feed/cut. + */ + if (head_dots > 128u) { + static const uint8_t page_end[] = { 0x0C }; + v = ptouch_bulk_send_job(ctx, page_end, sizeof(page_end), + "print page end"); + if (v != LIBPTOUCH_OK) { + free(transposed); + return v; + } + } + static const uint8_t print_end[] = { 0x1A }; v = ptouch_bulk_send_job(ctx, print_end, sizeof(print_end), "print end"); if (v != LIBPTOUCH_OK) { diff --git a/src/lib/libptouch_protocol.c b/src/lib/libptouch_protocol.c index 15b767e..4c762f2 100644 --- a/src/lib/libptouch_protocol.c +++ b/src/lib/libptouch_protocol.c @@ -15,21 +15,13 @@ 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) { - 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; + /* PI flags: enable media/width/length with quality bit for broad compatibility. */ + out[3] = 0x8Eu; + /* Use status media-kind byte directly (e.g., 0x01 laminated, 0x03 non-laminate). */ + out[4] = media_kind; out[5] = media_width; out[6] = 0x00u; out[7] = (uint8_t)(raster_lines & 0xFFu); @@ -39,3 +31,9 @@ void ptouch_fill_esc_iz(uint8_t out[13], uint8_t media_kind, uint8_t media_width out[11] = 0x00u; /* first page */ out[12] = 0x00u; /* fixed */ } + +uint8_t ptouch_esc_ik_value(unsigned head_dots) +{ + /* Preserve legacy 560-dot behaviour (0x0C), 128-dot uses 0x08. */ + return head_dots > 128u ? 0x0Cu : 0x08u; +} diff --git a/src/lib/libptouch_protocol.h b/src/lib/libptouch_protocol.h index 702e6be..054a86e 100644 --- a/src/lib/libptouch_protocol.h +++ b/src/lib/libptouch_protocol.h @@ -8,5 +8,6 @@ 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); +uint8_t ptouch_esc_ik_value(unsigned head_dots); #endif /* LIBPTOUCH_PROTOCOL_H */ diff --git a/src/lib/libptouch_status.c b/src/lib/libptouch_status.c index 07d37b8..bddf738 100644 --- a/src/lib/libptouch_status.c +++ b/src/lib/libptouch_status.c @@ -36,13 +36,21 @@ libptouch_err_t libptouch_get_status(libptouch_ctx *ctx, uint8_t *status) if (attempt > 0) { 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; + /* + * Avoid unconditional ESC @ here: + * some models can be in phase-change right after print end, and + * re-initializing there may disturb cutter/feed completion. + * Try plain ESC i S first, use ESC @ only on retry paths. + */ + if (attempt > 0) { + 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) { diff --git a/tests/protocol_regression_test.c b/tests/protocol_regression_test.c index 1ac0ba2..d495287 100644 --- a/tests/protocol_regression_test.c +++ b/tests/protocol_regression_test.c @@ -34,11 +34,16 @@ int main(void) fail |= expect_int("iz_cmd_0", iz[0], 0x1B); fail |= expect_int("iz_cmd_1", iz[1], 0x69); fail |= expect_int("iz_cmd_2", iz[2], 0x7A); - fail |= expect_int("iz_media_kind_map", iz[4], 0x09); + fail |= expect_int("iz_n1_flags", iz[3], 0x8E); + fail |= expect_int("iz_media_kind_passthrough", iz[4], 0x01); fail |= expect_int("iz_media_width", iz[5], 0x0C); fail |= expect_int("iz_lines_lsb", iz[7], 70); fail |= expect_int("iz_page_index", iz[11], 0x00); fail |= expect_int("iz_last_fixed", iz[12], 0x00); + /* ESC i K mode byte: 128-dot vs 560-dot families */ + fail |= expect_int("esc_ik_128", ptouch_esc_ik_value(128u), 0x08); + fail |= expect_int("esc_ik_560", ptouch_esc_ik_value(560u), 0x0C); + return fail ? EXIT_FAILURE : EXIT_SUCCESS; }