The remaining gap to a single service is the DYMO M10 postal scale (USB HID 0922:8003/8004, ~130 lines of the Node daemon) -- everything else the extension calls is already served. Scale was not plugged in today, so note that any port written before it is connected is untested. Also records the wanted Logitech C920 + cutting-mat dimension capture, and what still works with the Urovo unplugged (previews, label layout, Dymo, Chafon). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
15 KiB
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'sdaemon.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+printlabelencode 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.exe — no .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 ~1–3s (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)
- 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).
- "Out of ribbon" (status
08) is a latch. The printer defaults to thermal-transfer (expects a ribbon).SET RIBBON OFFswitches to direct thermal — but a latched08(e.g. after opening the head / pulling the roll back) is NOT cleared bySET RIBBON OFFalone; it needs a power cycle, OR a formfeed + SET RIBBON OFF (which the daemon now does automatically on a non-00start). - The status byte lies right after a print. During the RFID-encode + feed the reader returns
garbage codes (
20,31,45,FC) for 1–3s, then settles to00. Do not judge success on the immediate post-print byte — poll until00(the daemon'sWaitReady), and verify the actual result by eye / a separate tag read. - 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
detectUSBreturns null/no printer, wait or replug. (COM4/COM5 on this laptop are the Urovo's Bluetooth SPP links — ignore them.) - 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.
- 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 usingFramework64\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.dllis a managed .NET assembly, so decompiling its IL reveals every RFID call is a one-lineString.Concat→ ASCII →WritePrinter.writeUHF("H",2,12,"E",epc)emits exactly:UHF WRITE H,2,12,E,"<24 hex chars>"\r\nThe whole vocabulary (
UHF READ/QUERY,UHF GEN2 *,SET RFID,&DEFAULT,i,&CALIBRATE,A,R) is inmac/README.md. Option 2 below is therefore fully unblocked and option 1 (the Java jar) is unnecessary. A working macOS daemon now lives inmac/— raw TSPL over libusb, same:7790contract, printing verified on the 24 mm stock. Options 1–3 below are kept for historical context.
The daemon.cs is Windows-bound — GTSPL_SDK.dll is a Windows DLL; it won't run on macOS. But the
recipe in §2 is portable. Options, best first:
- 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(alsogtspl_sdk.jarin 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 becausewriteUHFdoes the RFID encoding for you. - 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 command —writeUHF("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 whilewriteUHFruns 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 Noderfid-daemon). - 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
Epcclass if needed. - Wire PriceGod buttons →
:7790+ the Mode A/B toggle. - Match the label layout to the extension's
labels.jsdesign 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 andmac/. - (Mac)
Prove the RFID encode end-to-end.Done — chip written by the Urovo and read back by the Chafon (independent reader):0000044A5600D4CDA1FAB932→sku=20260722180000, releaseId=424242. - 🔴 Fix the
Epcclass indaemon.cs— it is WRONG. The shop's real scheme (used bypliceclogs/rfid-daemonand now bymac/urovo.py) is a single 96-bit big-endian integersku * 10^9 + releaseId, not 6B sku + 4B releaseId +0xEC01. The Node daemon'sparseEpcDatarejects theEC01layout outright, so every tag the Windows daemon has written is invisible to the extension and needs rewriting. - Confirm
SET RFID OFFis genuinely honoured by this firmware rather than silently ignored — the absence ofVOID0on the last test print is the only evidence so far. - Resolve the
:7790collision betweenmac/daemon.pyand the Noderfid-daemon(both bind it; the Node one owns the Chafon write path, scale and inventory routes).
9. Next session — pick up here
The one thing standing between us and a single service. The extension calls only six
endpoints: /status, /write-tag, /read-tag (all served by mac/daemon.py) plus
/weight, /scale/start, /scale/stop (Node only). Port the DYMO M10 postal scale
— USB HID 0922:8003/0922:8004, ~130 lines around index.js:1068-1200 — and the Node
daemon retires for the extension's purposes: one process, one venv, one launchd agent.
⚠️ The scale was not plugged in on 2026-07-22, so any port written before it is
connected is untested.
Also wanted: a Logitech C920 over a cutting mat to measure record/sleeve dimensions (the mat grid gives the scale reference). Not started.
Resuming without the Urovo attached (it stays at the shop): the daemon degrades
cleanly — GET /devices reports present: false per device rather than failing, the
Dymo and Chafon paths are independent, and mac/chafon.py runs standalone. Label layout
work needs no hardware at all: GET /preview?size=large&artist=… renders a PNG, and
python label.py small large dumps both profiles to /tmp.
Don't re-litigate: the RFID encode is proven (Urovo wrote, Chafon read back
independently); the EPC scheme is settled and matches the Node daemon; the Dymo needs no
driver. All three are documented in mac/README.md.
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.