Commit Graph

84 Commits

Author SHA1 Message Date
EugeneTes
fd19cd9358 fix: propagate SPRT discovery bind/broadcast failures instead of swallowing them
SprtDiscoveryService caught SocketException on the UDP 9100 bind and the
broadcast send and returned an empty list either way. That defeated the
CompositeDiscoveryService fix that rethrows only when every child discovery
service fails: on a real network fault the composite would see one child
throw (ENPC) and one child silently succeed empty (SPRT), conclude discovery
worked and found nothing, and let PrinterDiscoveryBackgroundTask expire and
deregister live Epson printers after the retention window - discarding their
queued jobs.

Move the policy decision to the composite, which already has it right: the
child now reports bind/broadcast failure honestly by rethrowing, and
CompositeDiscoveryService absorbs a single child's failure while still
rethrowing when every child fails. The per-datagram receive-loop catch is
unchanged - a single bad receive still shouldn't abort the pass.

Rewrote SprtDiscoveryServiceTests' bind-failure test to assert the throw, and
added an end-to-end CompositeDiscoveryServiceTests case with a real
SprtDiscoveryService failing to bind alongside a stub that succeeds, proving
the composite still degrades gracefully rather than losing the pass. Updated
the POS895 design doc to match the new contract.

Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 13:01:58 +02:00
EugeneTes
a4e96f3041 Fix three pre-merge review findings on POS895 branch
1. Strengthen POS895 IsCut test: add RecordingEpsonPrinter.CallOrder so
   the test can assert feeds happen BEFORE the cut, plus a LineFeedBytes
   count assertion. The prior test could not detect the FeedAsync call
   being deleted from the IsCut branch (verified: test now fails when
   that line is removed, passes when restored).

2. CompositeDiscoveryService: distinguish "some children failed" from
   "every child failed". Per-child failures are still absorbed, but if
   every discovery service throws, the composite now rethrows instead
   of silently returning an empty list. Previously a total discovery
   failure (e.g. a routeless interface) looked like "discovery
   succeeded, found nothing" to PrinterDiscoveryBackgroundTask, which
   would expire and unregister every known printer after the retention
   window, discarding their queued jobs. Also corrected a doc comment
   that overstated Task.WhenAll's timeout guarantee.

3. Update CLAUDE.md to describe the POS895/POS896 work as shipped
   rather than future work: added the Inspectron.Epson.Tests and
   Pos895Test projects, a dotnet test command, SprtDiscoveryService/
   CompositeDiscoveryService/POS895 in the architecture sections, the
   0x20 printer-ID note, and the established SPRT hardware facts.

Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 12:46:14 +02:00
EugeneTes
9680ab0ad3 bind composite discovery and add emulated POS895
Epson printers answer ENPC and POS895/POS896 answer SPRT; only the
composite discovery service sees both. Wire CompositeDiscoveryService
(wrapping DiscoveryService + SprtDiscoveryService) into production DI,
and add a 576px emulated POS895 (127.0.0.4) alongside the existing
TM-U220II/TM-T30III emulation entries so receipt layouts can be
checked without hardware.

Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 12:26:56 +02:00
EugeneTes
ca773610ad fail cleanly when a printer does not answer GS I 1
Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 12:22:14 +02:00
EugeneTes
51792fcd20 add reflection-based test coverage for DiscoveryService.GetModelNameFromId
Ensures the 0x20 => "POS895" registration is actually tested. Without this,
the line could be deleted and the whole suite would still pass.

Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 12:19:34 +02:00
EugeneTes
020c17896a register printer id 0x20 as POS895 across the three dispatch points
Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 12:13:41 +02:00
EugeneTes
cd916c2761 add POS895 printer adapter with LF feed and ESC * logo
Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 12:07:32 +02:00
EugeneTes
40a72195d3 strengthen CompositeDiscoveryService tests for deduplication and concurrency
- Replace weak deduplication test with one using distinguishable printers
  (TM-T30III/ENPC vs POS895/SPRT on same IP) to prove first-wins semantics
- Add concurrency test using SlowStubDiscovery to catch sequential regressions
  (3 * 300ms tasks must complete in < 700ms, not >= 900ms)
- Add StubDiscovery constructor accepting List<DiscoveredPrinter> for
  fully-populated test data

Test suite now 13/13 passing with proven concurrent execution.

Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 12:03:24 +02:00
EugeneTes
e93dfdc184 add CompositeDiscoveryService merging ENPC and SPRT results
Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 11:57:03 +02:00
EugeneTes
f219129ce4 add SPRT discovery service for POS895 printers
Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 11:51:05 +02:00
EugeneTes
2f26a933cb amend POS895 plan: merge discovery tasks, drop network-dependent test
Pre-flight scan found two things the plan mandated that a reviewer would
rightly flag: Task 1 committed a DiscoverPrintersAsync that threw
NotImplementedException until Task 2 replaced it, and a unit test asserted
an empty result from a real UDP broadcast, which passes on a laptop and
fails on any network with a POS895 on it.

Tasks 1 and 2 are now one task delivering the complete service, and the
network-dependent test is gone. The deterministic bind-failure test still
covers the degradation path. Six tasks now.

Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 11:46:25 +02:00
EugeneTes
84b94e8c1a add POS895 integration implementation plan
Seven TDD tasks derived from the design spec, each ending in a commit:
test project and SPRT protocol parsing, the discovery network path,
CompositeDiscoveryService, the POS895 adapter, the three switch
registrations, the nullable printer-id guard, and DI wiring plus an
emulated POS895.

Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 11:32:19 +02:00
EugeneTes
0fb4edfaab probe remaining POS895 unknowns; add integration design spec
Closes every hardware question that was blocking the integration design,
so the design now rests on measurements rather than assumptions.

Probe results, all against the real printer:

- GS I 1 returns 0x20, unique against 0x01/0x0D/0x13. This is what keeps
  the integration small: model identity stays a byte and the existing
  per-job identification flow works. Had it returned nothing or 0x01 the
  POS895 would have been indistinguishable from a TM-T30III by probe, and
  model identity would have had to come from discovery instead.
- GS I 66 and 67 are blank, so the model-name fallback the work items
  proposed is useless here. GS I 68 returns the serial, and it matches
  the SPRT discovery serial exactly, which makes it a correlation key
  between a discovered printer and a connected one.
- GS ( L prints nothing. ESC * 33 and GS v 0 both render correctly across
  the full 576 dots, so the adapter uses PrintImageBitModeAsync and the
  GS v 0 work item is dropped as redundant.
- ESC t is honoured and index 18 really is CP852; 2 and 0 also render.

That last one exposed a fleet-wide bug that is deliberately left out of
scope: PrintTextAsync hardcodes CP852 for every printer, and CP852 cannot
encode e-grave, a-grave, u-grave, e-circumflex, i-grave or o-grave, so
French and Italian accents are dropped on the Epsons too. Now known to be
fixable via ESC t 2, but it needs its own spec.

The design spec covers discovery composition, the adapter, the three
switch registrations, testing and risks. It calls out that the
ReceiptConverterFactory WorkareaTicket switch defaults to 33 columns, so
missing it yields a POS895 printing kitchen tickets at the narrow
TM-U220 layout: wrong, but not obviously broken.

Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 11:19:59 +02:00
EugeneTes
17a6eb6b39 reverse engineer POS895 discovery; add SPRT discovery probe
The POS895 does not answer Epson's ENPC broadcast, so PrintServer never
registers it and every job for it fails with "Printer not found". The
feasibility notes listed the vendor's own discovery protocol as unknown
and expected a packet capture to recover it, which is what this does.

Captured pktmon traffic while running the vendor EasySet tool on the
printer's segment. The protocol is:

  query  UDP broadcast 255.255.255.255:3289, sent FROM source port 9100
         53 50 52 54 2D 49 6E 66 6F 72 00 00 0D   "SPRT-Infor" 00 00 0D

  reply  from <printer>:3289 back to <querier>:9100, 39 ASCII bytes
         "28-0e-8b-3d-ca-f1            2608120478"
          MAC, 17 chars   12 spaces   serial, 10 chars

The printer's address is the reply's source IP. Pos895Test now sends this
probe and parses the replies; run against the real printer it returns the
same MAC and serial the vendor tool got, so the reimplementation matches.

Two useful side effects. Port 3289 is the same UDP port ENPC uses, so a
composite IDiscoveryService can share one socket. And the querying machine
and the printer sat in different /24s of one flat segment, so the /24 TCP
sweep the notes originally preferred would have missed this printer.

The print test is commented out at the bottom of Program.cs rather than
deleted; it confirmed Font A is 48 columns and that GS ! magnification
works at width 1x/2x/3x with height 2x.

Notes updated: the discovery work item is no longer the largest one, the
compatibility table records DLE EOT and GS ! as confirmed and ESC d as
apparently ignored, and the answered questions are separated from the
ones still open.

Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 10:45:35 +02:00
EugeneTes
8ca8370426 add POS895 hardware smoke test project
Pos895Test is a console app that drives a POS895 over TCP through the
existing EpsonPrinter class, to answer the first question in the
feasibility notes: does the printer accept our ESC/POS at all.

It builds the whole job as one byte array and sends that exact array, so
the hex listing it prints is the wire content by construction rather than
a reconstruction that can drift. Current job prints a "|---" column ruler
at 48/width characters per row for width magnifications 1x, 2x and 3x at
double height, so every row should end at the same right margin.

Confirmed against the hardware so far:

- DLE EOT 1..4 are answered and follow the Epson bit layout exactly, with
  the 0x12 fixed bits set on every reply, so EpsonPrinterStatus parses
  this printer unmodified.
- Font A is 48 columns on the 576-dot line, as the manuals claim.
- GS ! magnification works, verified at width 1x/2x/3x and height 2x.
- ESC ! 0x00 selects Font A.

Not yet confirmed: Font B and its claimed 64 columns, the GS I 1 model
byte, ESC d n feed (this firmware appears to ignore it, hence the literal
LF bytes before the cut), code page 18 being CP852, and raster graphics.

Deliberately does not call GS I 1: the model byte is still an open
unknown and a smoke test must not be able to fail on one.

All settings are constants at the top of Program.cs; there are no
arguments.

Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
2026-09-03 10:10:08 +02:00
EugeneTes
772982deb2 add POS895/POS896 feasibility notes and CLAUDE.md pointer
Study-only writeup of what supporting the SPRT-derived POS895/POS896
ESC/POS clones would take: no vendor SDK linking, a 576-dot IPrinter
adapter, non-ENPC discovery, a sturdier printer-ID probe, and the
hardware checks still open.

Claude-Session: https://claude.ai/code/session_01WAG8xogHxq9hDJScu386Jf
2026-09-03 09:23:55 +02:00
EugeneTes
dc9bbbe467 Merge branch 'feature/PRI-9-interactive-console-test-runner' 2026-07-20 08:21:41 +02:00
EugeneTes
db30523697 bump EpsonPrintService version to 1.0.14 2026-07-09 08:54:30 +02:00
EugeneTes
5adb8f975c bump EpsonPrintService version to 1.0.13 2026-07-09 08:48:26 +02:00
EugeneTes
a51e5cb636 adapt money return receipt to new refund payload schema 2026-07-09 08:48:26 +02:00
EugeneTes
f64d2c8f28 add pudu robot control client; drop global.json SDK pin 2026-07-06 14:51:39 +02:00
EugeneTes
b927f48260 add print-job-arrived hook system 2026-07-06 14:51:29 +02:00
EugeneTes
91d2d18c80 add money return / credit note receipt type with HTML test 2026-07-06 14:51:23 +02:00
EugeneTes
398a3e3db8 hardcoded discovery 2026-04-20 10:43:44 +02:00
006ddf12dd Merge pull request 'Interactive console test runner for EpsonTest' (#1) from feature/PRI-9-interactive-console-test-runner into master
Reviewed-on: admin/inspectron_print_server#1
2026-04-10 06:36:09 +00:00
CTO
c94acc8bf7 Fix ambiguous Gang/Dish/DishModifications references in EpsonTest build
Use fully-qualified KitchenReceipt namespace for Gang, Dish, and
DishModifications in BuildSampleKitchenReceipt and
BuildSampleKitchenReceiptNextDish to resolve CS0104 errors caused by
identical type names in BarReceipt and KitchenReceipt namespaces.
Add global.json to pin SDK to .NET 8.0 for compatibility with .slnx.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 14:55:35 +00:00
CTO
a4582ee1f8 interactive console test runner for EpsonTest
Replace commented-out code blocks with arrow-key navigation menu.
First menu selects receipt type (Kitchen/Final/Invoice/Bar/OrderItems),
second selects printer target (HTML or Epson hardware).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-09 14:18:01 +00:00
EugeneTes
2ced842242 switch to kitchen converter for thermal printer 2026-04-09 10:42:31 +02:00
EugeneTes
5ee95c8109 1.0.12 2026-04-03 08:38:32 +02:00
EugeneTes
763cd1071b web configuration 2026-04-02 09:37:18 +02:00
EugeneTes
be83fadc5f klinglers special 2026-02-25 10:35:20 +01:00
EugeneTes
11dfd6ead4 grouping in kitchen receipt 2026-02-24 11:54:19 +01:00
EugeneTes
484e6bf3e1 1.0.11
discovery retention
2026-02-23 16:08:01 +01:00
EugeneTes
def9e9b06c 1.0.10 2026-02-19 11:45:39 +01:00
EugeneTes
966121ece8 out of paper detection 2026-02-18 13:18:19 +01:00
EugeneTes
59d7bd750a fix dirty hack from reini 2026-02-18 13:18:05 +01:00
EugeneTes
59d24cff25 send status out of paper 2026-02-12 15:45:49 +01:00
EugeneTes
b63bd4e84d UI for key update 2026-02-09 16:46:48 +01:00
EugeneTes
e8d20c77c7 size to kitchen
printer logs removed
2026-02-05 11:39:06 +01:00
EugeneTes
f0ae32c9e5 fallback support 2026-02-05 09:31:38 +01:00
EugeneTes
08da2c1e3e job status reporter 2026-02-05 08:42:34 +01:00
EugeneTes
1c0c95842a template editor 2026-02-05 08:42:14 +01:00
EugeneTes
1fcaaa040b fully functional editor 2026-02-04 14:59:16 +01:00
EugeneTes
8cd04155db code completion works 2026-02-04 14:35:48 +01:00
EugeneTes
eca5ced38a editor first run 2026-02-04 14:20:08 +01:00
EugeneTes
2748c6586e job status reporting 2026-02-04 11:39:14 +01:00
EugeneTes
71ba4c1ff6 changing from columns to col formatting 2026-02-04 10:25:12 +01:00
EugeneTes
fe817b5211 templates tested 2026-02-03 16:40:25 +01:00
EugeneTes
ec5decb12e template engine 2026-02-03 14:27:13 +01:00
EugeneTes
46b648d753 removed md templates
cleanup
2026-02-03 11:30:42 +01:00