113 lines
3.8 KiB
Python
113 lines
3.8 KiB
Python
#!/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")
|