From 88f18d98a1847e0911949891084b2c2156b3a9c2 Mon Sep 17 00:00:00 2001 From: type-two Date: Fri, 4 Sep 2026 11:19:17 +1000 Subject: [PATCH] =?UTF-8?q?fix(urovo):=20status()=20falls=20back=20to=20ES?= =?UTF-8?q?C=20!S=20=E2=80=94=20firmware=20stops=20answering=20ESC=20!=3F?= =?UTF-8?q?=20after=20&CALIBRATE,A,R?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After &CALIBRATE,A,R this printer answered model() but not the one-byte !? status, for minutes, so wait_ready/recover/do_print all reported 'no response' and refused to print a printer that was in fact Ready. The extended !S is still answered: STX + 4 bytes + ETX CRLF, first byte 0x40+code, which maps one-to-one onto STATUS_TEXT (0x48 = ribbon latched, 0x40 = Ready). Seen live: !? silent, !S -> 02 40 40 40 40 03 0D 0A. Co-Authored-By: Claude Opus 5 --- mac/urovo.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/mac/urovo.py b/mac/urovo.py index 0263559..be471a6 100644 --- a/mac/urovo.py +++ b/mac/urovo.py @@ -147,11 +147,28 @@ class Urovo(object): # ---- status ---------------------------------------------------------- def status(self, wait=0.8): - """Real-time status: !? -> one byte. 0x00 = Ready.""" + """Real-time status. 0x00 = Ready. + + Asks the one-byte !? first. After &CALIBRATE,A,R this firmware stops answering + that form entirely -- the printer sat "no response" for minutes while model() kept + working over the same pipe -- and every caller that gates on status() (wait_ready, + recover, do_print) then refuses to print a printer that is in fact fine. So fall back to + the extended !S, which it does keep answering: STX + 4 status bytes + ETX CR LF, + first byte 0x40 + code. That offset maps one-to-one onto STATUS_TEXT (0x41 head open, + 0x48 ribbon latched, 0x40 ready), so the fallback returns the same codes as the primary. + Seen live: !? silent, !S -> 02 40 40 40 40 03 0D 0A = Ready.""" self.flush_in() self.write(b'\x1b!?') r = self.read(wait) - return r[-1] if r else None + if r: + return r[-1] + self.flush_in() + self.write(b'\x1b!S') + r = self.read(wait) + i = r.find(b'\x02') if r else -1 + if i >= 0 and len(r) > i + 1: + return (r[i + 1] - 0x40) & 0xFF + return None def model(self): self.flush_in()