diff --git a/CMakeLists.txt b/CMakeLists.txt index cb5f71c..e179e76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ set(LIBPTOUCH_SOURCES src/lib/libptouch_usb.c src/lib/libptouch_protocol.c src/lib/libptouch_layout.c + src/lib/libptouch_family_config.c src/lib/libptouch_media_info.c src/lib/libptouch_trim.c src/lib/libptouch_print.c @@ -82,6 +83,8 @@ add_executable(ptouch-protocol-regression-test ) target_include_directories(ptouch-protocol-regression-test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/lib" + "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_BINARY_DIR}/include" ) if(NOT MSVC) target_compile_options(ptouch-protocol-regression-test PRIVATE -Wall -Wextra -Wpedantic) @@ -96,3 +99,6 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/libptouch.h" "${CMAKE_CURRENT_BINARY_DIR}/include/libptouch_version.h" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") +install(FILES + "${CMAKE_CURRENT_SOURCE_DIR}/config/printer_families.json" + DESTINATION "${CMAKE_INSTALL_DATADIR}/ptouch_label") diff --git a/config/printer_families.json b/config/printer_families.json new file mode 100644 index 0000000..4906096 --- /dev/null +++ b/config/printer_families.json @@ -0,0 +1,18 @@ +{ + "families": { + "p700": { + "comment": "PT-P750W / PT-P710BT(cv_ptp750w_710bt_jpn_raster_102.pdf 系)", + "print_dpi": 180, + "margin_feed_dpi": 180, + "margin_feed_max_dots": 900, + "send_esc_ia_cut_each": false + }, + "p900": { + "comment": "PT-P900 / P900W / P950NW / P910BT(cv_ptp900_jpn_raster_102.pdf 系)", + "print_dpi": 360, + "margin_feed_dpi": 360, + "margin_feed_max_dots": 1800, + "send_esc_ia_cut_each": true + } + } +} diff --git a/include/libptouch.h b/include/libptouch.h index e4637a9..3a71ccf 100644 --- a/include/libptouch.h +++ b/include/libptouch.h @@ -39,6 +39,18 @@ typedef enum { LIBPTOUCH_ERR_IMAGE = 7, } libptouch_err_t; +/** + * リファレンス上の系統(PT-P750W/P710BT = P700、PT-P900 系 = P900)。 + * DPI の値で分岐する代わりに、この系統を使う。 + */ +typedef enum { + LIBPTOUCH_FAMILY_UNKNOWN = 0, + /** PT-P750W / PT-P710BT(cv_ptp750w_710bt_jpn_raster_102.pdf 系) */ + LIBPTOUCH_FAMILY_P700 = 1, + /** PT-P900 / P900W / P950NW / P910BT 等(cv_ptp900_jpn_raster_102.pdf 系) */ + LIBPTOUCH_FAMILY_P900 = 2, +} libptouch_printer_family_t; + /** lsusb 例: PT-P900W — Brother Industries, Ltd (04f9:2085) */ #define LIBPTOUCH_USB_VID_BROTHER 0x04f9u #define LIBPTOUCH_USB_PID_PTP900W 0x2085u @@ -49,6 +61,11 @@ typedef enum { libptouch_ctx *libptouch_create(void); void libptouch_destroy(libptouch_ctx *ctx); +/** + * 系統の短い英語ラベル("p700" / "p900" / "unknown")。UI やログ用。 + */ +const char *libptouch_printer_family_label(libptouch_printer_family_t family); + /** 人が読める英語メッセージ(スレッド非安全: ctx ごと) */ const char *libptouch_strerror(const libptouch_ctx *ctx); libptouch_err_t libptouch_last_error(const libptouch_ctx *ctx); @@ -76,7 +93,7 @@ typedef struct { typedef struct { uint8_t media_width_code; /**< status[10] */ uint8_t media_kind_code; /**< status[11] */ - double print_dpi; /**< 印字幅方向 DPI(現状 180 or 360) */ + double print_dpi; /**< 印字幅方向 DPI(系統既定または設定ファイル上書き) */ double feed_dpi; /**< 送り方向 DPI(ESC i d の基準) */ double tape_width_mm; /**< 装着テープ幅(mm)。例: 3.5, 6, 9, 12, 18, 24, 36 */ uint16_t printable_dots; /**< 現在テープで印字可能な幅(ドット) */ @@ -84,6 +101,8 @@ typedef struct { uint16_t right_margin_dots; /**< 右余白(ドット) */ uint16_t min_feed_dots; /**< 仕様上の最小送り量(ドット)。現在は 14 */ double min_feed_mm; /**< 最小送り量(mm) */ + /** @ref libptouch_printer_family_t(系統不明時は @ref LIBPTOUCH_FAMILY_UNKNOWN) */ + uint32_t printer_family; } libptouch_media_info_t; /** @@ -113,8 +132,8 @@ libptouch_err_t libptouch_trim_right_blank_columns( /** * 1 ビット packed ラスターを USB で印刷(各機種のラスター PDF 準拠)。 * 印字前にステータスでテープ幅を読み、印刷可能ドット内に画像を中央配置する。 - * width_dots は装着テープの印刷可能幅以下であること。PT-P900 系は幅 360dpi、 - * PT-P750W / PT-P710BT は幅 180dpi(cv_ptp750w_710bt_jpn_raster_102.pdf)のドット列を想定。 + * width_dots は装着テープの印刷可能幅以下であること。系統は @ref libptouch_get_current_media_info + * の printer_family で判別できる(P900 系は主に 360dpi 相当ドット列、P700 系は 180dpi 相当)。 * @param margin_mm 余白(フィード)量。0 のとき PDF の最小 1mm(14 ドット)相当を送る。 * 印刷時は内部でドット列を転置する(テープ幅方向とバッファの縦横の対応)。 * @param data 1 行あたり width_dots ビットを ceil(width_dots/8) バイトで並べた連続領域 diff --git a/reference/ptp_raster_ref.adoc b/reference/ptp_raster_ref.adoc new file mode 100644 index 0000000..087734a --- /dev/null +++ b/reference/ptp_raster_ref.adoc @@ -0,0 +1,14 @@ += P-Toouch Raster コマンド リファレンスメモ + +== 印字データ + +印刷データは大きく分けて、初期化コマンド、制御コード、ラスターデータ、印字指令から構成される。 +ジョブが複数ページからなる場合には、制御コード~ラスターデータを繰り返します。 + +=== 初期化コマンド + +印刷開始時に一度送信 + +1. 無効指令: NULL(0x00) × 200バイト +2. 初期化: ESC @ (0x1B 0x40) + diff --git a/ruby/lib/libptouch.rb b/ruby/lib/libptouch.rb index 563c17a..dcbcede 100644 --- a/ruby/lib/libptouch.rb +++ b/ruby/lib/libptouch.rb @@ -27,4 +27,9 @@ module Libptouch STATUS_LENGTH = 32 PNG_DEFAULT_THRESHOLD = 128 + + # libptouch_printer_family_t(C API と同じ値) + FAMILY_UNKNOWN = 0 + FAMILY_P700 = 1 + FAMILY_P900 = 2 end diff --git a/ruby/lib/libptouch/binding.rb b/ruby/lib/libptouch/binding.rb index ae8e29f..87f3f09 100644 --- a/ruby/lib/libptouch/binding.rb +++ b/ruby/lib/libptouch/binding.rb @@ -39,7 +39,8 @@ module Libptouch :left_margin_dots, :uint16, :right_margin_dots, :uint16, :min_feed_dots, :uint16, - :min_feed_mm, :double + :min_feed_mm, :double, + :printer_family, :uint32 end class PngOptions < FFI::Struct @@ -51,6 +52,7 @@ module Libptouch end attach_function :libptouch_create, [], :pointer + attach_function :libptouch_printer_family_label, [:uint32], :string attach_function :libptouch_destroy, [:pointer], :void attach_function :libptouch_strerror, [:pointer], :string attach_function :libptouch_last_error, [:pointer], :int diff --git a/ruby/lib/libptouch/context.rb b/ruby/lib/libptouch/context.rb index 823b986..5dc0eea 100644 --- a/ruby/lib/libptouch/context.rb +++ b/ruby/lib/libptouch/context.rb @@ -151,6 +151,7 @@ module Libptouch def current_media_info info = Binding::MediaInfo.new raise_on_error(Binding.libptouch_get_current_media_info(@native, info.pointer)) + fam = info[:printer_family] { media_width_code: info[:media_width_code], media_kind_code: info[:media_kind_code], @@ -161,7 +162,9 @@ module Libptouch left_margin_dots: info[:left_margin_dots], right_margin_dots: info[:right_margin_dots], min_feed_dots: info[:min_feed_dots], - min_feed_mm: info[:min_feed_mm] + min_feed_mm: info[:min_feed_mm], + printer_family: fam, + printer_family_label: Binding.libptouch_printer_family_label(fam) } end end diff --git a/src/cli/main.c b/src/cli/main.c index 1cf1ea1..caafcf0 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -124,6 +124,10 @@ static void verbose_print_pre_print_info(libptouch_ctx *ctx, printf("printable dots: %u\n", (unsigned)mi.printable_dots); printf("left/right margins: %u/%u dots\n", (unsigned)mi.left_margin_dots, (unsigned)mi.right_margin_dots); + printf("printer family: %s (%u)\n", + libptouch_printer_family_label( + (libptouch_printer_family_t)mi.printer_family), + (unsigned)mi.printer_family); printf("print/feed dpi: %.1f/%.1f\n", mi.print_dpi, mi.feed_dpi); } else { printf("media info: unavailable (%s)\n", libptouch_strerror(ctx)); diff --git a/src/lib/libptouch_core.c b/src/lib/libptouch_core.c index 2b5473e..034c06e 100644 --- a/src/lib/libptouch_core.c +++ b/src/lib/libptouch_core.c @@ -6,6 +6,7 @@ */ #include "libptouch_internal.h" +#include "libptouch_family_config.h" #include #include @@ -33,6 +34,8 @@ void ptouch_set_error_usb(libptouch_ctx *ctx, int libusb_err, const char *what) libptouch_ctx *libptouch_create(void) { + ptouch_family_config_init_once(); + libptouch_ctx *ctx = calloc(1, sizeof(*ctx)); if (!ctx) return NULL; diff --git a/src/lib/libptouch_family_config.c b/src/lib/libptouch_family_config.c new file mode 100644 index 0000000..1cb897c --- /dev/null +++ b/src/lib/libptouch_family_config.c @@ -0,0 +1,302 @@ +/* + * libptouch — optional JSON overrides for P700/P900 family parameters + * + * 検索順: 環境変数 LIBPTOUCH_CONFIG、カレントの printer_families.json、 + * config/printer_families.json(リポジトリ配置用) + */ + +#include "libptouch_family_config.h" + +#include +#include +#include +#include + +enum { + OV_PRINT_DPI = 1 << 0, + OV_MARGIN_FEED_DPI = 1 << 1, + OV_MARGIN_MAX = 1 << 2, + OV_ESC_IA = 1 << 3, +}; + +typedef struct { + unsigned mask; + double print_dpi; + double margin_feed_dpi; + unsigned margin_feed_max_dots; + int send_esc_ia; +} family_override_t; + +static family_override_t g_p700; +static family_override_t g_p900; +static int g_loaded; + +static const char *skip_ws(const char *p) +{ + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') + p++; + return p; +} + +static int read_file_all(const char *path, char **out, size_t *out_len) +{ + FILE *fp = fopen(path, "rb"); + if (!fp) + return -1; + if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return -1; + } + long sz = ftell(fp); + if (sz < 0 || sz > 65536) { + fclose(fp); + return -1; + } + rewind(fp); + char *buf = (char *)malloc((size_t)sz + 1u); + if (!buf) { + fclose(fp); + return -1; + } + size_t n = fread(buf, 1, (size_t)sz, fp); + fclose(fp); + buf[n] = '\0'; + *out = buf; + *out_len = n; + return 0; +} + +static const char *find_quoted_key(const char *json, const char *key) +{ + char pat[48]; + snprintf(pat, sizeof(pat), "\"%s\"", key); + return strstr(json, pat); +} + +static int extract_object_after_key(const char *json, const char *key, + char *out, size_t out_sz) +{ + const char *p = find_quoted_key(json, key); + if (!p) + return -1; + p += strlen(key) + 2u; + p = skip_ws(p); + if (*p != ':') + return -1; + p++; + p = skip_ws(p); + if (*p != '{') + return -1; + int depth = 0; + const char *start = p; + for (; *p; p++) { + if (*p == '{') + depth++; + else if (*p == '}') { + depth--; + if (depth == 0) { + size_t n = (size_t)(p - start + 1u); + if (n >= out_sz) + return -1; + memcpy(out, start, n); + out[n] = '\0'; + return 0; + } + } + } + return -1; +} + +static int parse_bool_val(const char *s, int *out) +{ + s = skip_ws(s); + if (strncmp(s, "true", 4) == 0) { + *out = 1; + return 0; + } + if (strncmp(s, "false", 5) == 0) { + *out = 0; + return 0; + } + return -1; +} + +static int parse_field_double(const char *obj, const char *key, double *dst) +{ + const char *p = find_quoted_key(obj, key); + if (!p) + return -1; + p += strlen(key) + 2u; + p = skip_ws(p); + if (*p != ':') + return -1; + p++; + p = skip_ws(p); + char *end = NULL; + double v = strtod(p, &end); + if (end == p) + return -1; + *dst = v; + return 0; +} + +static int parse_field_uint(const char *obj, const char *key, unsigned *dst) +{ + const char *p = find_quoted_key(obj, key); + if (!p) + return -1; + p += strlen(key) + 2u; + p = skip_ws(p); + if (*p != ':') + return -1; + p++; + p = skip_ws(p); + char *end = NULL; + unsigned long v = strtoul(p, &end, 10); + if (end == p) + return -1; + *dst = (unsigned)v; + return 0; +} + +static int parse_field_bool(const char *obj, const char *key, int *dst) +{ + const char *p = find_quoted_key(obj, key); + if (!p) + return -1; + p += strlen(key) + 2u; + p = skip_ws(p); + if (*p != ':') + return -1; + p++; + p = skip_ws(p); + return parse_bool_val(p, dst); +} + +static void apply_family_block(const char *block, family_override_t *o) +{ + double d; + unsigned u; + int b; + + if (parse_field_double(block, "print_dpi", &d) == 0) { + o->print_dpi = d; + o->mask |= OV_PRINT_DPI; + } + if (parse_field_double(block, "margin_feed_dpi", &d) == 0) { + o->margin_feed_dpi = d; + o->mask |= OV_MARGIN_FEED_DPI; + } + if (parse_field_uint(block, "margin_feed_max_dots", &u) == 0) { + o->margin_feed_max_dots = u; + o->mask |= OV_MARGIN_MAX; + } + if (parse_field_bool(block, "send_esc_ia_cut_each", &b) == 0) { + o->send_esc_ia = b; + o->mask |= OV_ESC_IA; + } +} + +static void parse_config_json(const char *json) +{ + char inner[4096]; + const char *families = json; + + if (extract_object_after_key(json, "families", inner, sizeof(inner)) == 0) + families = inner; + + char block[2048]; + if (extract_object_after_key(families, "p700", block, sizeof(block)) == 0) + apply_family_block(block, &g_p700); + if (extract_object_after_key(families, "p900", block, sizeof(block)) == 0) + apply_family_block(block, &g_p900); +} + +static void try_load_path(const char *path) +{ + char *buf = NULL; + size_t len = 0; + if (read_file_all(path, &buf, &len) != 0) + return; + parse_config_json(buf); + free(buf); +} + +void ptouch_family_config_init_once(void) +{ + if (g_loaded) + return; + g_loaded = 1; + memset(&g_p700, 0, sizeof(g_p700)); + memset(&g_p900, 0, sizeof(g_p900)); + + const char *env = getenv("LIBPTOUCH_CONFIG"); + if (env && env[0]) + try_load_path(env); + try_load_path("printer_families.json"); + try_load_path("config/printer_families.json"); +} + +double ptouch_effective_print_dpi(const ptouch_printer_profile_t *prof) +{ + if (!prof) + return 0.0; + if (prof->family == LIBPTOUCH_FAMILY_P700 && + (g_p700.mask & OV_PRINT_DPI)) + return g_p700.print_dpi; + if (prof->family == LIBPTOUCH_FAMILY_P900 && + (g_p900.mask & OV_PRINT_DPI)) + return g_p900.print_dpi; + return prof->print_dpi; +} + +double ptouch_effective_margin_feed_dpi(const ptouch_printer_profile_t *prof) +{ + if (!prof) + return 0.0; + if (prof->family == LIBPTOUCH_FAMILY_P700 && + (g_p700.mask & OV_MARGIN_FEED_DPI)) + return g_p700.margin_feed_dpi; + if (prof->family == LIBPTOUCH_FAMILY_P900 && + (g_p900.mask & OV_MARGIN_FEED_DPI)) + return g_p900.margin_feed_dpi; + return prof->margin_feed_dpi; +} + +unsigned ptouch_effective_margin_feed_max_dots(const ptouch_printer_profile_t *prof) +{ + if (!prof) + return 0u; + if (prof->family == LIBPTOUCH_FAMILY_P700 && + (g_p700.mask & OV_MARGIN_MAX)) + return g_p700.margin_feed_max_dots; + if (prof->family == LIBPTOUCH_FAMILY_P900 && + (g_p900.mask & OV_MARGIN_MAX)) + return g_p900.margin_feed_max_dots; + return prof->margin_feed_max_dots; +} + +int ptouch_effective_send_esc_ia_cut_each(const ptouch_printer_profile_t *prof) +{ + if (!prof) + return 0; + if (prof->family == LIBPTOUCH_FAMILY_P700 && + (g_p700.mask & OV_ESC_IA)) + return g_p700.send_esc_ia; + if (prof->family == LIBPTOUCH_FAMILY_P900 && + (g_p900.mask & OV_ESC_IA)) + return g_p900.send_esc_ia; + return (int)prof->send_esc_ia_cut_each; +} + +const char *libptouch_printer_family_label(libptouch_printer_family_t family) +{ + switch (family) { + case LIBPTOUCH_FAMILY_P700: + return "p700"; + case LIBPTOUCH_FAMILY_P900: + return "p900"; + default: + return "unknown"; + } +} diff --git a/src/lib/libptouch_family_config.h b/src/lib/libptouch_family_config.h new file mode 100644 index 0000000..e794a93 --- /dev/null +++ b/src/lib/libptouch_family_config.h @@ -0,0 +1,19 @@ +/* + * libptouch — printer family overrides (JSON config, optional) + */ + +#ifndef LIBPTOUCH_FAMILY_CONFIG_H +#define LIBPTOUCH_FAMILY_CONFIG_H + +#include "libptouch_layout.h" + +#include + +void ptouch_family_config_init_once(void); + +double ptouch_effective_print_dpi(const ptouch_printer_profile_t *prof); +double ptouch_effective_margin_feed_dpi(const ptouch_printer_profile_t *prof); +unsigned ptouch_effective_margin_feed_max_dots(const ptouch_printer_profile_t *prof); +int ptouch_effective_send_esc_ia_cut_each(const ptouch_printer_profile_t *prof); + +#endif /* LIBPTOUCH_FAMILY_CONFIG_H */ diff --git a/src/lib/libptouch_layout.c b/src/lib/libptouch_layout.c index bc8fd85..51b2375 100644 --- a/src/lib/libptouch_layout.c +++ b/src/lib/libptouch_layout.c @@ -61,9 +61,12 @@ static const ptouch_printer_profile_t ptouch_layout_profiles[] = { .usb_pids = pids_128pin, .model_codes = models_128pin, .is_default = 0, + .family = LIBPTOUCH_FAMILY_P700, .head_width_dots = 128u, + .print_dpi = 180.0, .margin_feed_dpi = 180.0, .margin_feed_max_dots = 900u, + .send_esc_ia_cut_each = 0u, .tze = layout_tze_128, .tze_count = sizeof(layout_tze_128) / sizeof(layout_tze_128[0]), .hs = layout_hs_128, @@ -74,9 +77,12 @@ static const ptouch_printer_profile_t ptouch_layout_profiles[] = { .usb_pids = NULL, .model_codes = NULL, .is_default = 1, + .family = LIBPTOUCH_FAMILY_P900, .head_width_dots = 560u, + .print_dpi = 360.0, .margin_feed_dpi = 360.0, .margin_feed_max_dots = 1800u, + .send_esc_ia_cut_each = 1u, .tze = layout_tze_560, .tze_count = sizeof(layout_tze_560) / sizeof(layout_tze_560[0]), .hs = layout_hs_560, diff --git a/src/lib/libptouch_layout.h b/src/lib/libptouch_layout.h index 35d87fb..e554ff3 100644 --- a/src/lib/libptouch_layout.h +++ b/src/lib/libptouch_layout.h @@ -29,9 +29,13 @@ typedef struct ptouch_printer_profile { const uint16_t *usb_pids; /* 0-terminated; NULL = do not match on PID */ const uint8_t *model_codes; /* 0-terminated; NULL = do not match on status[4] */ int is_default; /* 1 = fallback when no other profile matches */ + libptouch_printer_family_t family; /**< P700 / P900 系統(コマンド差の条件分岐の基準) */ unsigned head_width_dots; /* 128 or 560; full raster width for pack/GF payload */ + double print_dpi; /* 印字幅方向 DPI(PDF・ラスター解像度の目安) */ double margin_feed_dpi; /* ESC i d feed dots per inch (PDF) */ unsigned margin_feed_max_dots; + /** ESC i A(各 n 枚でカット)を送るか(P700 系では送らない) */ + unsigned char send_esc_ia_cut_each; const ptouch_layout_row_t *tze; size_t tze_count; const ptouch_layout_row_t *hs; diff --git a/src/lib/libptouch_media_info.c b/src/lib/libptouch_media_info.c index ffac354..23129df 100644 --- a/src/lib/libptouch_media_info.c +++ b/src/lib/libptouch_media_info.c @@ -6,6 +6,7 @@ */ #include "libptouch_internal.h" +#include "libptouch_family_config.h" #include "libptouch_layout.h" #include @@ -34,15 +35,6 @@ static double tape_width_mm_from_code(uint8_t media_w) } } -static double print_dpi_from_profile(const ptouch_printer_profile_t *prof) -{ - if (!prof) - return 0.0; - if (prof->head_width_dots <= 128u) - return 180.0; - return 360.0; -} - libptouch_err_t libptouch_get_current_media_info(libptouch_ctx *ctx, libptouch_media_info_t *out_info) { @@ -53,6 +45,7 @@ libptouch_err_t libptouch_get_current_media_info(libptouch_ctx *ctx, } memset(out_info, 0, sizeof(*out_info)); + ptouch_family_config_init_once(); uint8_t st[LIBPTOUCH_STATUS_LENGTH]; libptouch_err_t v = libptouch_get_status(ctx, st); @@ -85,15 +78,16 @@ libptouch_err_t libptouch_get_current_media_info(libptouch_ctx *ctx, out_info->media_width_code = st[10]; out_info->media_kind_code = st[11]; - out_info->print_dpi = print_dpi_from_profile(prof); - out_info->feed_dpi = prof->margin_feed_dpi; + out_info->print_dpi = ptouch_effective_print_dpi(prof); + out_info->feed_dpi = ptouch_effective_margin_feed_dpi(prof); out_info->tape_width_mm = tape_mm; out_info->printable_dots = print_dots; out_info->left_margin_dots = left_dots; out_info->right_margin_dots = right_dots; out_info->min_feed_dots = 14u; - out_info->min_feed_mm = - ((double)out_info->min_feed_dots * 25.4) / prof->margin_feed_dpi; + out_info->min_feed_mm = ((double)out_info->min_feed_dots * 25.4) / + ptouch_effective_margin_feed_dpi(prof); + out_info->printer_family = (uint32_t)prof->family; ptouch_set_error(ctx, LIBPTOUCH_OK, ""); return LIBPTOUCH_OK; diff --git a/src/lib/libptouch_print.c b/src/lib/libptouch_print.c index dcc22ed..5fd300c 100644 --- a/src/lib/libptouch_print.c +++ b/src/lib/libptouch_print.c @@ -6,6 +6,7 @@ */ #include "libptouch_internal.h" +#include "libptouch_family_config.h" #include "libptouch_layout.h" #include "libptouch_protocol.h" @@ -76,6 +77,8 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx, return LIBPTOUCH_ERR_IO; } + ptouch_family_config_init_once(); + uint8_t st[LIBPTOUCH_STATUS_LENGTH]; v = libptouch_get_status(ctx, st); if (v != LIBPTOUCH_OK) @@ -126,8 +129,9 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx, return LIBPTOUCH_ERR_ARG; } - double margin_dpi = prof->margin_feed_dpi; - unsigned margin_max = prof->margin_feed_max_dots; + double margin_dpi = ptouch_effective_margin_feed_dpi(prof); + unsigned margin_max = + ptouch_effective_margin_feed_max_dots(prof); unsigned margin_dots = 14u; if (params->margin_mm > 0) { margin_dots = (unsigned)((double)params->margin_mm * margin_dpi / @@ -152,7 +156,7 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx, pos += sizeof(raster_mode); uint8_t esc_iz[13]; - ptouch_fill_esc_iz(esc_iz, media_kind, media_w, lines); + ptouch_fill_esc_iz(esc_iz, prof, media_kind, media_w, lines); memcpy(head + pos, esc_iz, sizeof(esc_iz)); pos += sizeof(esc_iz); @@ -161,11 +165,10 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx, pos += sizeof(esc_im); /* - * 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. + * ESC i A ("cut each n labels") — P700 系では送らない(通信エラーになり得る)。 + * 既定は系統フラグ、printer_families.json で上書き可。 */ - if (prof->head_width_dots > 128u) { + if (ptouch_effective_send_esc_ia_cut_each(prof)) { static const uint8_t esc_ia[] = { 0x1B, 0x69, 0x41, 0x01 }; memcpy(head + pos, esc_ia, sizeof(esc_ia)); pos += sizeof(esc_ia); @@ -217,21 +220,6 @@ 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 4c762f2..8072747 100644 --- a/src/lib/libptouch_protocol.c +++ b/src/lib/libptouch_protocol.c @@ -12,9 +12,13 @@ void ptouch_fill_gf_header(uint8_t out[3], size_t line_payload_bytes) 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) +void ptouch_fill_esc_iz(uint8_t out[13], const ptouch_printer_profile_t *prof, + uint8_t media_kind, uint8_t media_width, uint32_t raster_lines) { + uint8_t page_byte = 0x00u; + if (prof && prof->family == LIBPTOUCH_FAMILY_P900) + page_byte = 0x02u; /* 単一ラスター = 1 ページのみ → 最終ページ */ + out[0] = 0x1Bu; out[1] = 0x69u; out[2] = 0x7Au; @@ -28,7 +32,7 @@ void ptouch_fill_esc_iz(uint8_t out[13], uint8_t media_kind, uint8_t media_width 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[11] = page_byte; out[12] = 0x00u; /* fixed */ } diff --git a/src/lib/libptouch_protocol.h b/src/lib/libptouch_protocol.h index 054a86e..e3f3d72 100644 --- a/src/lib/libptouch_protocol.h +++ b/src/lib/libptouch_protocol.h @@ -1,13 +1,20 @@ #ifndef LIBPTOUCH_PROTOCOL_H #define LIBPTOUCH_PROTOCOL_H +#include "libptouch_layout.h" + #include #include 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); +/** + * ESC i z (13 バイト)。out[11] は prof の系統から決める(P900 の単一ページ印字では 02h、 + * P700 は 00h)。prof が NULL のときは 00h。 + */ +void ptouch_fill_esc_iz(uint8_t out[13], const ptouch_printer_profile_t *prof, + 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/tests/protocol_regression_test.c b/tests/protocol_regression_test.c index d495287..6228f2e 100644 --- a/tests/protocol_regression_test.c +++ b/tests/protocol_regression_test.c @@ -3,6 +3,14 @@ #include #include +static const ptouch_printer_profile_t prof_fixture_p700 = { + .family = LIBPTOUCH_FAMILY_P700, +}; + +static const ptouch_printer_profile_t prof_fixture_p900 = { + .family = LIBPTOUCH_FAMILY_P900, +}; + static int expect_int(const char *name, int got, int want) { if (got == want) @@ -30,7 +38,7 @@ int main(void) fail |= expect_int("gf70_n2", gf[2], 0x00); uint8_t iz[13]; - ptouch_fill_esc_iz(iz, 0x01u, 0x0Cu, 70u); + ptouch_fill_esc_iz(iz, &prof_fixture_p700, 0x01u, 0x0Cu, 70u); 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); @@ -38,9 +46,12 @@ int main(void) 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_page_control_p700", iz[11], 0x00); fail |= expect_int("iz_last_fixed", iz[12], 0x00); + ptouch_fill_esc_iz(iz, &prof_fixture_p900, 0x01u, 0x0Cu, 70u); + fail |= expect_int("iz_page_control_p900_single", iz[11], 0x02); + /* 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);