yourovo/ASSESSMENT.md
type-two b014205a5b macOS: raw-TSPL Urovo daemon — no vendor SDK needed
ASSESSMENT.md §7 assumed the RFID encode was locked inside the Windows-only
GTSPL_SDK.dll and would need a USBPcap sniff or the GTSPL Java jar to recover.
It didn't. The DLL is a managed .NET assembly, and its IL shows every RFID call
is a one-line String.Concat -> ASCII -> WritePrinter. Recovered from ldstr order
plus argument order, and confirmed by a second independent decompile:

    UHF WRITE H,2,12,E,"<24 hex>"    UHF READ/QUERY ...
    UHF GEN2 EPC|TID|USER|ACCESS|KILL <action>,"<pw>"
    SET RFID <tagType>,<rw_pos>,<void>,<try>,<err>,<speed>,<retry>   (dots, not mm)
    &DEFAULT,i    &CALIBRATE,A,R    PRINT <set>, <copy>

So the whole recipe is plain ASCII over the printer's bulk endpoint and ports to
macOS with no vendor binaries at all.

- mac/urovo.py   USB transport + full GTSPL command set, status decoding, the
                 ribbon-latch recovery, SKU<->EPC packing ported from daemon.cs.
- mac/label.py   PIL bitmap renderer -> TSPL BITMAP. Media-profile driven, so both
                 shop stocks work (small 51x19 and large 55x24 on the 24mm web),
                 with a safe-area inset so the design can't clip at the edges.
- mac/daemon.py  :7790 HTTP service, same routes/JSON/CORS as daemon.cs, plus a
                 /preview route that renders a label as PNG without printing one.

Verified on the bench from macOS: printer identifies (MODEL:UROVO-D812R), the
latched 0x08 "out of ribbon" clears with SET RIBBON OFF + FORMFEED, and labels
print correctly oriented and dark on the 24x55 stock.

NOT yet verified: the RFID encode itself. It is wired and the printer accepts the
command, but the loaded thermal stock has no inlays so nothing has been written to
a chip. Needs a PET RFID label at the antenna. The SKU<->EPC byte layout also
remains unconfirmed against existing Chafon-written tags.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 16:07:12 +10:00

13 KiB
Raw Blame History

Urovo D812R+ RFID print+encode — full assessment & handover

Session date: 2026-07-22 (Windows 11 bench machine). Goal: make the Urovo D812R+ (RFID) print a record label and program the UHF chip in one pass, driven from the PriceGod browser extension — replacing the current two-step flow (Chafon gun programs a chip → Dymo 450 prints a paper label → stick paper over chip).


TL;DR

  • Built a working Windows daemon (pricegod-urovo-daemon, C#/.NET Framework, http://localhost:7790) that drives the Urovo via the GTSPL SDK and does print + RFID-encode in one pass. Drop-in for the extension's daemon.js (same port, same JSON, CORS *).
  • Printing works — dark, correct, on real thermal stock, at the right size (54×24). The daemon even auto-clears the recurring "out of ribbon" latch on every print.
  • RFID read/encode path proven — the Urovo reads UCODE-9 chips and the writeUHF+printlabel encode sequence is wired and fires cleanly.
  • The blocker to the actual one-pass dream is the LABELS, not the printer: the shop's glossy "U9 65×35mm PET" RFID labels are not direct-thermal — a direct-thermal printer can't mark them (only a faint emboss). Need direct-thermal UHF RFID paper labels.
  • Chafon H-102 on Windows is a dead end for writing — it outputs as an HID keyboard, not serial; the SDK can't reach it to program tags without a chronically-unreliable device-side mode flip. Recommend: Chafon = scanner (reads/looks-up), Urovo = all writing.

1. What was built (in this repo)

File What
daemon.cs The service. HttpListener on :7790, CORS *, drives the Urovo via GTSPL_SDK.dll.
chafcheck.cs Probe for the Chafon reader via native UHFPrimeReader.dll (P/Invoke).
start-daemon.cmd / build.cmd Run / rebuild (rebuild uses the always-present .NET Framework csc.exeno .NET SDK needed).
README.md How to run + routes.
PROGRESS.md Running log.
*.dll Vendor binaries needed to build/run on Windows: GTSPL_SDK.dll, GTSPL_SDK_C.dll, zlib.net.dll (Urovo), UHFPrimeReader.dll, hidapi.dll (Chafon).

Build with build.cmd (rebuilds pricegod-urovo-daemon.exe; .exes are git-ignored). Run with start-daemon.cmd.

Daemon routes (:7790, JSON)

method path body returns
GET /status {ok,ready,status,statusText,printer}
POST /print-encode {sku,releaseId,artist?,title?,genre?,style?,info?,price?,condition?,w?,h?,gap?,dir?} {ok,epc,status,note,...}
POST /write-tag alias of /print-encode (the daemon.js name) same
POST /print-test same body, prints only, no RFID (safe on plain thermal)
GET /read-tag / /read-raw tag EPC / all memory banks
POST /calibrate / /recover RFID auto-cal / ribbon-off+feed clear

2. The proven Urovo print+encode recipe ( portable — this is what transfers to the Mac)

Every step below is the exact GTSPL SDK call sequence the daemon uses. Almost all of them are plain TSPL commands (sendcommand) — the only special one is the RFID write. This recipe is device knowledge, not language knowledge; it should replicate on any GTSPL binding (Windows .NET, Java/GTSPL-1.1.8.jar, Android, etc.):

detectUSB / openport                      # connect to "Urovo D812Riplus(RFID)"
SET RIBBON OFF                            # direct thermal (no ribbon). REQUIRED, repeatedly (see §3)
<if status != "00">: formfeed; SET RIBBON OFF   # clear a latched "out of ribbon"
SET TEAR ON
GAP 2 mm,0 mm                             # gapped die-cut labels (Dymo 54×24). For RFID rolls that
                                         #   blind the gap sensor: GAP 0 mm,0 mm (continuous)
SIZE 54 mm,24 mm                          # label size (was 65×35 for the PET RFID stock)
DENSITY 15                                # MAX darkness — needed; lower barely marks
DIRECTION 1                               # flip to 0 if the label prints rotated
CLS (clearbuffer)
writeUHF("H", 2, 12, "E", <24-hex EPC>)   # ⭐ THE RFID ENCODE: hex, EPC bank ("E"), word 2, 12 bytes (96-bit EPC)
TEXT/QRCODE ... (printerfont/qrcode)      # the visible label
SET RIBBON OFF                            # re-assert immediately before printing
printlabel("1","1")                       # fires PRINT + ENCODE together, one pass
<wait for status to return to "00">       # RFID+feed leaves it "busy" for ~13s (see §3)
readUHF("H",2,12,"E") / query_UHF         # optional verify (note: the encoded tag has fed past the
                                         #   antenna by now, so on-printer read-back is unreliable —
                                         #   verify with a separate reader / Chafon scan instead)

SKU ↔ EPC scheme (v1, in the Epc class): the 96-bit EPC (12 bytes) = 6 bytes 14-digit timestamp SKU + 4 bytes release_id + 2 bytes 0xEC01 marker. ⚠️ Unverified against the Mac/Chafon scheme — if existing tags use a different layout, change ONLY the Epc class; nothing else depends on the byte order. (Best check: scan an existing Chafon-written tag and compare.)


3. Hard-won gotchas (the Urovo D812R+ specifically)

  1. PET labels aren't direct-thermal. The glossy "U9 65×35mm PET" RFID labels only emboss — they will never print dark on a direct-thermal printer. This cost hours (looked like a density/ribbon/printer fault; it was the media). Scratch test: drag a nail across a blank label — direct-thermal paper leaves a gray streak, PET/plain leaves nothing. Buy direct-thermal RFID paper labels (see §5).
  2. "Out of ribbon" (status 08) is a latch. The printer defaults to thermal-transfer (expects a ribbon). SET RIBBON OFF switches to direct thermal — but a latched 08 (e.g. after opening the head / pulling the roll back) is NOT cleared by SET RIBBON OFF alone; it needs a power cycle, OR a formfeed + SET RIBBON OFF (which the daemon now does automatically on a non-00 start).
  3. The status byte lies right after a print. During the RFID-encode + feed the reader returns garbage codes (20, 31, 45, FC) for 13s, then settles to 00. Do not judge success on the immediate post-print byte — poll until 00 (the daemon's WaitReady), and verify the actual result by eye / a separate tag read.
  4. USB drops on power-off. Powering the printer off removes it from the USB bus; it re-enumerates a few seconds after power-on. If detectUSB returns null/no printer, wait or replug. (COM4/COM5 on this laptop are the Urovo's Bluetooth SPP links — ignore them.)
  5. Label-size calibration is on the printer: hold the FEED button while powering on, wait for 5 beeps — it auto-calibrates gap/label size. Needed after changing stock.
  6. Talk to it via the GTSPL SDK, not the Windows spooler. Raw TSPL through the Seagull print driver/spooler did not reliably deliver commands (esp. SET RIBBON OFF); the SDK's direct USB path does. Build without a .NET SDK using Framework64\v4.0.30319\csc.exe.

4. The Chafon H-102 situation (why it's parked)

The two CF-H102 guns, on Windows, put their tag reads on the HID keyboard channel (USB-HID, or BLE "LE GATT HID device" when paired) — not the CH340 serial the SDK needs. Proven: chafcheck (OpenDevice+GetTagUii) returns 0xFFFFFF12 (COMM_TIMEOUT, "reader not answering") at every baud on both guns; a raw serial read with DTR+RTS asserted got 0 bytes while triggering.

To write tags via the SDK the gun must be in serial/command mode, flipped device-side (config barcode / the sideloaded Android app) — which the user reports is chronically flaky (Mac too). The Windows Chafon SDK has serial / USB-HID / network paths only — no BLE — so Bluetooth isn't a path for the gun here either.

Recommendation: stop fighting it. Use the Chafon as a keyboard scanner (trigger → types the EPC → focus a search box to look up a tag; 100% reliable in the mode it's already in) and let the Urovo do all writing. Once direct-thermal RFID labels arrive, the Chafon isn't needed to program anything.


5. What to buy (unblocks the one-pass dream)

Direct-thermal UHF RFID paper labels, all of:

  • Direct thermal (⚠ not "thermal transfer", not "PET/PP") — search "direct thermal RFID label"
  • Paper face (direct-thermal coated paper)
  • UHF RFID inlay, EPC Gen2, chip NXP UCODE 9 (matches existing tags/reader)
  • 54×24 mm (or 55×25 — the Dymo size), roll compatible with the D812R
  • Ask the seller: "compatible with Urovo/TSC D812R RFID printer"

The existing PET tags aren't wasted — a reader can still program them; you'd just keep printing+sticking paper for those. New DT-RFID paper labels are what enable single-pass.


6. Two-mode design (agreed)

  • Mode A — "Separate" (today's flow, existing stock): program chip + print Dymo separately, stick paper on top. On Windows the encode step is the flaky Chafon (see §4) — recommend leaning on the Urovo instead where possible.
  • Mode B — "Combined / one-pass" (the goal): one button → Urovo prints + encodes together on DT-RFID labels. Daemon path (/print-encode) is built.

A Settings toggle picks the mode; the extension change is tiny (same daemon.js contract). Wiring the PriceGod buttons → :7790 was not done yet (next step).


7. For the Mac: getting the Urovo to program chips over there

UPDATE 2026-07-22 (later the same day) — SOLVED, and more cheaply than expected. The RFID-encode command did not need a USB sniff or the Java jar. GTSPL_SDK.dll is a managed .NET assembly, so decompiling its IL reveals every RFID call is a one-line String.Concat → ASCII → WritePrinter. writeUHF("H",2,12,"E",epc) emits exactly:

UHF WRITE H,2,12,E,"<24 hex chars>"\r\n

The whole vocabulary (UHF READ/QUERY, UHF GEN2 *, SET RFID, &DEFAULT,i, &CALIBRATE,A,R) is in mac/README.md. Option 2 below is therefore fully unblocked and option 1 (the Java jar) is unnecessary. A working macOS daemon now lives in mac/ — raw TSPL over libusb, same :7790 contract, printing verified on the 24 mm stock. Options 13 below are kept for historical context.

The daemon.cs is Windows-boundGTSPL_SDK.dll is a Windows DLL; it won't run on macOS. But the recipe in §2 is portable. Options, best first:

  1. GTSPL Java SDK (most direct). The vendor SDK ships a cross-platform Java library: Documents/Software V1.1.2/drive-download-.../20241129_GTSPL_Java_Library/lib/GTSPL-1.1.8.jar (also gtspl_sdk.jar in the Android samples). Java runs on macOS — write a small program that mirrors §2 (openport/sendcommand/writeUHF/printlabel). ⚠ Verify the jar's USB transport works on macOS (the Android build assumes Android USB; desktop USB may need a native lib or a serial/USB-CDC path). This is the cleanest port because writeUHF does the RFID encoding for you.
  2. Raw TSPL over USB (no SDK). ~90% of §2 is plain TSPL text you can send straight to the Urovo's USB device on macOS (e.g. write to the raw printer device, or CUPS -o raw). The one missing piece is the RFID-encode commandwriteUHF("H",2,12,"E",epc) is an SDK helper wrapping the printer's TSPL RFID command, and its exact bytes weren't captured this session. To get them: sniff the USB writes while writeUHF runs on Windows (USBPcap/Wireshark), or check the Urovo/Gainscha TSPL RFID command reference. Once you have that command string, the whole thing is raw TSPL and trivially portable (even into the existing Node rfid-daemon).
  3. Extend the existing Mac rfid-daemon (Node) to open the Urovo and emit the §2 sequence (needs the RFID command bytes from option 2).

Reality check for "can the Urovo program chips on Mac?": yes, mechanically — it's the same USB printer speaking TSPL. The only real work is the transport (get bytes to the printer on macOS) and the RFID-encode command (use the Java writeUHF, or capture its bytes). Everything else — ribbon-off, geometry, density, one-pass timing — is documented above and identical.


8. Open items / next steps

  • Buy direct-thermal UHF RFID paper labels (§5) — the true unblock.
  • Verify the SKU↔EPC scheme (§2) against an existing tag; adjust Epc class if needed.
  • Wire PriceGod buttons → :7790 + the Mode A/B toggle.
  • Match the label layout to the extension's labels.js design more faithfully (current TSPL layout is functional, not pixel-perfect).
  • (Optional) On Windows, decide Chafon = scanner-only vs. chase command mode.
  • (Mac) Try option 1 or 2 in §7 to program chips there. Done — see §7 update and mac/.
  • (Mac) Prove the RFID encode end-to-end: it is wired and the printer accepts the command, but no chip has been written yet (the 24 mm thermal stock has no inlays). Put a PET RFID label at the antenna and POST /print-encode, then read back.
  • Confirm SET RFID OFF is genuinely honoured by this firmware rather than silently ignored — the absence of VOID0 on the last test print is the only evidence so far.

See also the shop's memory notes: urovo-d812r-ribbon-fix, urovo-d812r-rfid-label-gap-issue, urovo-d812r-pet-labels-not-thermal, urovo-windows-print-encode-daemon, chafon-h102-windows-hid-mode.