#!/usr/bin/env python3 """ TM-T88V paper width fix tool. Writes directly to /dev/usb/lp0, bypassing CUPS entirely. Step 1: Direct USB test print (safe, no NV writes) Step 2: NV paper-width reset to 80mm (writes to printer NV memory) """ import sys, time ESC = b'\x1b' GS = b'\x1d' INIT = ESC + b'\x40' FONT_A = ESC + b'\x4d\x00' FONT_B = ESC + b'\x4d\x01' SIZE_NORM = GS + b'\x21\x00' SP_ZERO = ESC + b'\x20\x00' # GS W 576 = full 80mm printable area (576 = 0x0240) WIDTH_576 = GS + b'\x57\x40\x02' # GS W 512 WIDTH_512 = GS + b'\x57\x00\x02' CUT = GS + b'\x56\x00' DEV = "/dev/usb/lp0" RULER42 = "123456789|123456789|123456789|123456789|12" RULER56 = "123456789|123456789|123456789|123456789|123456789|123456" def write_dev(data: bytes): with open(DEV, "wb") as f: f.write(data) def test_print(): """Step 1 — safe diagnostic, no NV changes.""" body = ( "\n[DIRECT USB - Font A + GS W 576]\n" f"{RULER42}\n" "The quick brown fox jumps over the lazy dog\n" "\n" "[DIRECT USB - Font B + GS W 576]\n" f"{RULER56}\n" "The quick brown fox jumps over the lazy dog\n" "\n" ).encode("ascii") data = (INIT + SIZE_NORM + SP_ZERO + WIDTH_576 + FONT_A + body + b"\n\n" + CUT) write_dev(data) print("Test print sent directly via USB (no CUPS).") print("Count the ruler chars on each line and report back.") # ── NV paper-width commands ─────────────────────────────────────────────────── # GS ( E — Set customized value (persists in NV across power cycles) # Format: GS ( E pL pH fn [data...] # pL pH = little-endian length of (fn + data) # # TM-T88V firmware 30.xx: # fn=2 : Set paper type # data : 0x00 = 80mm/RP80, 0x01 = 58mm/RP58 # # This writes to NV — takes effect after power cycle. def gs_e(fn: int, data: bytes) -> bytes: payload = bytes([fn]) + data pL = len(payload) & 0xFF pH = (len(payload) >> 8) & 0xFF return GS + b'\x28\x45' + bytes([pL, pH]) + payload NV_80MM = gs_e(0x02, b'\x00') # fn=2, param=0x00 → 80mm paper NV_58MM = gs_e(0x02, b'\x01') # fn=2, param=0x01 → 58mm paper (for reference) def nv_fix(): """Step 2 — write 80mm paper width to NV memory, then test.""" print("Sending NV paper-width reset to 80mm...") # Send the NV command alone first, then reinit and test data = ( INIT + NV_80MM + # set 80mm in NV INIT + # re-init so new setting takes effect now SIZE_NORM + SP_ZERO + WIDTH_576 + FONT_A + ( "\n[NV SET: 80mm - if this is 42 chars wide, it worked]\n" f"{RULER42}\n" "The quick brown fox jumps over the lazy dog\n" "\n" ).encode("ascii") + b"\n\n" + CUT ) write_dev(data) print("NV write + test strip sent.") print("If the ruler shows 42 chars: power-cycle the printer to confirm it sticks.") print("If still 30 chars: the fn=2/0x00 command didn't apply; tell me and we'll try alternate byte sequences.") if __name__ == "__main__": cmd = sys.argv[1] if len(sys.argv) > 1 else "test" try: if cmd == "test": test_print() elif cmd == "fix": nv_fix() elif cmd == "fix58": # Emergency restore to 58mm if needed write_dev(INIT + NV_58MM + INIT + b"\n[restored to 58mm]\n\n" + CUT) print("Restored to 58mm NV setting.") else: print("Usage: fixwidth.py [test|fix|fix58]") except PermissionError: print(f"Permission denied on {DEV}") print(f"Run: sudo chmod a+rw {DEV} then retry") except FileNotFoundError: print(f"{DEV} not found — run: sudo modprobe usblp")