/* * libptouch — printer status (ESC i S) and human-readable dump * * Author: knb * Email: knb@artif.org */ #include "libptouch_internal.h" #include #include #include libptouch_err_t libptouch_get_status(libptouch_ctx *ctx, uint8_t *status) { if (!ctx || !status) { if (ctx) ptouch_set_error(ctx, LIBPTOUCH_ERR_ARG, "null argument"); return LIBPTOUCH_ERR_ARG; } if (!ctx->usb_handle || !ctx->bulk_out_ep || !ctx->bulk_in_ep) { ptouch_set_error(ctx, LIBPTOUCH_ERR_IO, "USB not open or bulk endpoints missing"); return LIBPTOUCH_ERR_IO; } libusb_device_handle *h = ctx->usb_handle; static const uint8_t init[] = { 0x1B, 0x40 }; static const uint8_t req[] = { 0x1B, 0x69, 0x53 }; int r = LIBUSB_ERROR_OTHER; 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) { 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; } r = ptouch_bulk_in_exact(h, ctx->bulk_in_ep, status, (int)LIBPTOUCH_STATUS_LENGTH, 5000u); if (r == 0) break; if (r != LIBUSB_ERROR_IO && r != LIBUSB_ERROR_PIPE && r != LIBUSB_ERROR_TIMEOUT) break; } if (r != 0) { ptouch_set_error_usb(ctx, r, "bulk IN status"); return LIBPTOUCH_ERR_USB; } ptouch_set_error(ctx, LIBPTOUCH_OK, ""); return LIBPTOUCH_OK; } static void fprint_model(FILE *fp, uint8_t code) { const char *name = "unknown"; switch (code) { case 0x6F: name = "PT-P900W"; break; case 0x70: name = "PT-P950NW"; break; case 0x71: name = "PT-P900"; break; case 0x78: name = "PT-P910BT"; break; case 0x68: name = "PT-P750W"; break; case 0x76: name = "PT-P710BT"; break; default: break; } fprintf(fp, "機種コード: 0x%02X ('%c') — %s\n", (unsigned)code, (code >= 32 && code < 127) ? (char)code : '?', name); } static void fprint_media_width(FILE *fp, uint8_t w, uint8_t len_byte) { const char *desc = NULL; switch (w) { case 0x00: desc = "テープなし / 未装着"; break; case 0x04: desc = "3.5 mm"; break; case 0x06: desc = "6 mm"; break; case 0x09: desc = "9 mm"; break; case 0x0C: desc = "12 mm"; break; case 0x12: desc = "18 mm"; break; case 0x18: desc = "24 mm"; break; case 0x24: desc = "36 mm"; break; case 0x15: desc = "FLe 21 mm 幅(長さはメディア長バイト参照)"; break; default: break; } if (desc) fprintf(fp, "メディア幅: 0x%02X — %s\n", (unsigned)w, desc); else fprintf(fp, "メディア幅: 0x%02X\n", (unsigned)w); if (w == 0x15 && len_byte != 0) fprintf(fp, "メディア長: 0x%02X (%u mm 相当の表記参照)\n", (unsigned)len_byte, (unsigned)len_byte); } static void fprint_media_kind(FILE *fp, uint8_t k) { const char *desc = NULL; switch (k) { case 0x00: desc = "テープなし"; break; case 0x01: desc = "ラミネートテープ"; break; case 0x03: desc = "ノンラミネートテープ"; break; case 0x04: desc = "ファブリックテープ"; break; case 0x11: desc = "ヒートシュリンクチューブ (HS 2:1)"; break; case 0x13: desc = "FLe テープ"; break; case 0x14: desc = "フレキシブルIDテープ"; break; case 0x15: desc = "サテンテープ"; break; case 0x17: desc = "ヒートシュリンクチューブ (HS 3:1)"; break; case 0xFF: desc = "非対応テープ"; break; default: break; } if (desc) fprintf(fp, "テープ種類: 0x%02X — %s\n", (unsigned)k, desc); else fprintf(fp, "テープ種類: 0x%02X\n", (unsigned)k); } static void fprint_battery(FILE *fp, uint8_t b) { const char *desc = NULL; switch (b) { case 0x00: desc = "フル"; break; case 0x01: desc = "ハーフ"; break; case 0x02: desc = "ロー"; break; case 0x03: desc = "要充電"; break; case 0x04: desc = "AC アダプター使用中"; break; case 0xFF: desc = "不明"; break; default: break; } if (desc) fprintf(fp, "電池残量: 0x%02X — %s\n", (unsigned)b, desc); else fprintf(fp, "電池残量: 0x%02X (PT-P910BT 等は別表参照)\n", (unsigned)b); } static void fprint_tape_color(FILE *fp, uint8_t c) { const char *desc = NULL; switch (c) { case 0x01: desc = "白 (White)"; break; case 0x02: desc = "その他 (Other)"; break; case 0x03: desc = "透明 (Clear)"; break; case 0x04: desc = "赤 (Red)"; break; case 0x05: desc = "青 (Blue)"; break; case 0x06: desc = "黄 (Yellow)"; break; case 0x07: desc = "緑 (Green)"; break; case 0x08: desc = "黒 (Black)"; break; case 0x09: desc = "透明(文字白)"; break; case 0x20: desc = "白(マット) (Matte White)"; break; case 0x21: desc = "透明(マット) (Matte Clear)"; break; case 0x22: desc = "銀(マット) (Matte Silver)"; break; case 0x23: desc = "金(サテン) (Satin Gold)"; break; case 0x24: desc = "銀(サテン) (Satin Silver)"; break; case 0x30: desc = "青(D)"; break; case 0x31: desc = "赤(D)"; break; case 0x40: desc = "オレンジ(蛍光)"; break; case 0x41: desc = "黄(蛍光)"; break; case 0x50: desc = "ピンク(S)"; break; case 0x51: desc = "グレー(S)"; break; case 0x52: desc = "グリーン(S)"; break; case 0x60: desc = "イエロー(F)"; break; case 0x61: desc = "ピンク(F)"; break; case 0x62: desc = "ブルー(F)"; break; case 0x70: desc = "白(チューブ)"; break; case 0x90: desc = "白(フレキ)"; break; case 0x91: desc = "黄(フレキ)"; break; case 0xF0: desc = "クリーニング"; break; case 0xF1: desc = "ステンシル"; break; case 0xFF: desc = "非対応"; break; default: break; } if (desc) fprintf(fp, "テープ色: 0x%02X — %s\n", (unsigned)c, desc); else fprintf(fp, "テープ色: 0x%02X\n", (unsigned)c); } static void fprint_status_kind(FILE *fp, uint8_t s) { const char *desc = NULL; switch (s) { case 0x00: desc = "印刷終了"; break; case 0x01: desc = "エラー発生"; break; case 0x02: desc = "IF モード終了"; break; case 0x03: desc = "パワーオフ(未使用扱い)"; break; case 0x04: desc = "通知"; break; case 0x05: desc = "フェーズ変更"; break; default: break; } if (desc) fprintf(fp, "ステータス種類: 0x%02X — %s\n", (unsigned)s, desc); else fprintf(fp, "ステータス種類: 0x%02X\n", (unsigned)s); } void libptouch_status_fprint(FILE *fp, const uint8_t *status) { if (!fp || !status) return; fprintf(fp, "=== P-touch ステータス (32 バイト) ===\n"); if (status[0] != 0x80u || status[1] != 0x20u) fprintf(fp, "※ 先頭マーク異常: [0]=0x%02X [1]=0x%02X (通常 80 20)\n", (unsigned)status[0], (unsigned)status[1]); fprintf(fp, "ヘッダ: 0x%02X 0x%02X\n", (unsigned)status[0], (unsigned)status[1]); fprintf(fp, "Brother コード: %c (0x%02X)\n", (status[2] >= 32 && status[2] < 127) ? (char)status[2] : '?', (unsigned)status[2]); fprint_model(fp, status[4]); fprintf(fp, "国別コード: %c\n", (status[5] >= 32 && status[5] < 127) ? (char)status[5] : '?'); fprint_battery(fp, status[6]); if (status[7] != 0) { fprintf(fp, "拡張エラー: 0x%02X", (unsigned)status[7]); switch (status[7]) { case 0x10: fprintf(fp, " — FLE のテープエンド"); break; case 0x1D: fprintf(fp, " — 高解像度/ドラフト印刷エラー"); break; case 0x1E: fprintf(fp, " — アダプター抜き挿しエラー"); break; case 0x21: fprintf(fp, " — 非対応メディアエラー"); break; default: break; } fprintf(fp, "\n"); } else { fprintf(fp, "拡張エラー: なし (0x00)\n"); } fprintf(fp, "エラー情報1: 0x%02X\n", (unsigned)status[8]); if (status[8] & 0x01) fprintf(fp, " - メディア無し\n"); if (status[8] & 0x02) fprintf(fp, " - メディア終了\n"); if (status[8] & 0x04) fprintf(fp, " - カッタージャム\n"); if (status[8] & 0x08) fprintf(fp, " - バッテリー弱\n"); if (status[8] & 0x40) fprintf(fp, " - 高圧アダプター\n"); fprintf(fp, "エラー情報2: 0x%02X\n", (unsigned)status[9]); if (status[9] & 0x01) fprintf(fp, " - メディア交換(メディア違い)\n"); if (status[9] & 0x04) fprintf(fp, " - 通信エラー\n"); if (status[9] & 0x08) fprintf(fp, " - 通信バッファーフル\n"); if (status[9] & 0x10) fprintf(fp, " - カバーオープン\n"); if (status[9] & 0x20) fprintf(fp, " - 高温エラー\n"); if (status[9] & 0x40) fprintf(fp, " - 先端検出エラー\n"); if (status[9] & 0x80) fprintf(fp, " - システムエラー\n"); fprint_media_width(fp, status[10], status[17]); fprint_media_kind(fp, status[11]); fprintf(fp, "色数: 0x%02X フォント/日本語フォント: 0x%02X / 0x%02X\n", (unsigned)status[12], (unsigned)status[13], (unsigned)status[14]); fprintf(fp, "モード: 0x%02X 濃度: 0x%02X\n", (unsigned)status[15], (unsigned)status[16]); fprint_status_kind(fp, status[18]); fprintf(fp, "フェーズ種類: 0x%02X フェーズ番号: %02X %02X\n", (unsigned)status[19], (unsigned)status[20], (unsigned)status[21]); fprintf(fp, "通知番号: 0x%02X\n", (unsigned)status[22]); fprintf(fp, "拡張部バイト数: 0x%02X\n", (unsigned)status[23]); fprint_tape_color(fp, status[24]); fprintf(fp, "文字色: 0x%02X\n", (unsigned)status[25]); fprintf(fp, "生データ: "); for (unsigned i = 0; i < LIBPTOUCH_STATUS_LENGTH; i++) fprintf(fp, "%02X%s", (unsigned)status[i], i + 1 == LIBPTOUCH_STATUS_LENGTH ? "\n" : " "); }