# frozen_string_literal: true module Libptouch # 32 バイトのステータス応答を Hash に展開する(C の libptouch_status_fprint と同じ区分)。 module StatusHash class << self def decode(raw) unless raw.bytesize == STATUS_LENGTH raise ArgumentError, "expected #{STATUS_LENGTH} bytes, got #{raw.bytesize}" end s = raw.bytes { header_ok: s[0] == 0x80 && s[1] == 0x20, header: [s[0], s[1]], brother_code: s[2], brother_code_char: s[2] >= 32 && s[2] < 127 ? s[2].chr(Encoding::ASCII_8BIT) : nil, model: model_entry(s[4]), region_code: s[5], region_char: s[5] >= 32 && s[5] < 127 ? s[5].chr(Encoding::ASCII_8BIT) : nil, battery: labeled(BATTERY, s[6]), extended_error: extended_error_entry(s[7]), error_info1: error_info1(s[8]), error_info2: error_info2(s[9]), media_width: media_width_entry(s[10], s[17]), tape_kind: labeled(MEDIA_KIND, s[11]), color_count: s[12], font_jp: s[13], font: s[14], mode: s[15], density: s[16], status_kind: labeled(STATUS_KIND, s[18]), phase_type: s[19], phase_number: [s[20], s[21]], notification_number: s[22], extended_section_bytes: s[23], tape_color: labeled(TAPE_COLOR, s[24]), text_color: s[25], raw_hex: raw.unpack1("H*"), raw_bytes: s.dup } end private def model_entry(code) { code: code, name: MODEL_NAMES[code], ascii_char: code >= 32 && code < 127 ? code.chr(Encoding::ASCII_8BIT) : nil } end def labeled(table, byte) { code: byte, label: table[byte] } end def extended_error_entry(byte) h = { code: byte, label: EXTENDED_ERROR[byte] } h[:none] = true if byte.zero? h end def media_width_entry(w, len_byte) entry = labeled(MEDIA_WIDTH, w) if w == 0x15 && len_byte != 0 entry[:media_length_code] = len_byte entry[:media_length_note_mm] = len_byte end entry end def error_info1(b) { raw: b, media_missing: !!(b & 0x01), media_end: !!(b & 0x02), cutter_jam: !!(b & 0x04), battery_weak: !!(b & 0x08), high_voltage_adapter: !!(b & 0x40) } end def error_info2(b) { raw: b, media_mismatch: !!(b & 0x01), comm_error: !!(b & 0x04), comm_buffer_full: !!(b & 0x08), cover_open: !!(b & 0x10), heat_error: !!(b & 0x20), tip_detection_error: !!(b & 0x40), system_error: !!(b & 0x80) } end end MODEL_NAMES = { 0x6F => "PT-P900W", 0x70 => "PT-P950NW", 0x71 => "PT-P900", 0x78 => "PT-P910BT", 0x68 => "PT-P750W", 0x76 => "PT-P710BT" }.freeze MEDIA_WIDTH = { 0x00 => "テープなし / 未装着", 0x04 => "3.5 mm", 0x06 => "6 mm", 0x09 => "9 mm", 0x0C => "12 mm", 0x12 => "18 mm", 0x18 => "24 mm", 0x24 => "36 mm", 0x15 => "FLe 21 mm 幅(長さはメディア長バイト参照)" }.freeze MEDIA_KIND = { 0x00 => "テープなし", 0x01 => "ラミネートテープ", 0x03 => "ノンラミネートテープ", 0x04 => "ファブリックテープ", 0x11 => "ヒートシュリンクチューブ (HS 2:1)", 0x13 => "FLe テープ", 0x14 => "フレキシブルIDテープ", 0x15 => "サテンテープ", 0x17 => "ヒートシュリンクチューブ (HS 3:1)", 0xFF => "非対応テープ" }.freeze BATTERY = { 0x00 => "フル", 0x01 => "ハーフ", 0x02 => "ロー", 0x03 => "要充電", 0x04 => "AC アダプター使用中", 0xFF => "不明" }.freeze TAPE_COLOR = { 0x01 => "白 (White)", 0x02 => "その他 (Other)", 0x03 => "透明 (Clear)", 0x04 => "赤 (Red)", 0x05 => "青 (Blue)", 0x06 => "黄 (Yellow)", 0x07 => "緑 (Green)", 0x08 => "黒 (Black)", 0x09 => "透明(文字白)", 0x20 => "白(マット) (Matte White)", 0x21 => "透明(マット) (Matte Clear)", 0x22 => "銀(マット) (Matte Silver)", 0x23 => "金(サテン) (Satin Gold)", 0x24 => "銀(サテン) (Satin Silver)", 0x30 => "青(D)", 0x31 => "赤(D)", 0x40 => "オレンジ(蛍光)", 0x41 => "黄(蛍光)", 0x50 => "ピンク(S)", 0x51 => "グレー(S)", 0x52 => "グリーン(S)", 0x60 => "イエロー(F)", 0x61 => "ピンク(F)", 0x62 => "ブルー(F)", 0x70 => "白(チューブ)", 0x90 => "白(フレキ)", 0x91 => "黄(フレキ)", 0xF0 => "クリーニング", 0xF1 => "ステンシル", 0xFF => "非対応" }.freeze STATUS_KIND = { 0x00 => "印刷終了", 0x01 => "エラー発生", 0x02 => "IF モード終了", 0x03 => "パワーオフ(未使用扱い)", 0x04 => "通知", 0x05 => "フェーズ変更" }.freeze EXTENDED_ERROR = { 0x10 => "FLE のテープエンド", 0x1D => "高解像度/ドラフト印刷エラー", 0x1E => "アダプター抜き挿しエラー", 0x21 => "非対応メディアエラー" }.freeze end def self.parse_status(raw) StatusHash.decode(raw) end end