diff --git a/EpsonTest/Program.cs b/EpsonTest/Program.cs
index d58c249..4db06c5 100644
--- a/EpsonTest/Program.cs
+++ b/EpsonTest/Program.cs
@@ -18,8 +18,8 @@ if (args.Length > 0)
return;
}
- int pt = args.Length > 1 && args[1].Equals("epson", StringComparison.OrdinalIgnoreCase) ? 1 : 0;
- Console.WriteLine($"Running {GetReceiptTypeName(rt)} on {(pt == 0 ? "HTML" : "Epson")} printer...\n");
+ int pt = ParsePrinterTargetArg(args.Length > 1 ? args[1] : "html");
+ Console.WriteLine($"Running {GetReceiptTypeName(rt)} on {GetPrinterTargetName(pt)} printer...\n");
await RunTest(rt, pt);
Console.WriteLine("\nDone.");
return;
@@ -46,11 +46,12 @@ while (true)
var printerTarget = ShowMenu("Select printer target:", new[]
{
"HTML Printer (local file)",
- "Epson Printer (real hardware)"
+ "Epson Printer (real hardware)",
+ "POS895 (real hardware, via IPrinter adapter)"
});
Console.Clear();
- Console.WriteLine($"Running {GetReceiptTypeName(receiptType)} on {(printerTarget == 0 ? "HTML" : "Epson")} printer...\n");
+ Console.WriteLine($"Running {GetReceiptTypeName(receiptType)} on {GetPrinterTargetName(printerTarget)} printer...\n");
try
{
@@ -109,6 +110,21 @@ static int ShowMenu(string prompt, string[] options)
}
}
+static string GetPrinterTargetName(int index) => index switch
+{
+ 0 => "HTML",
+ 1 => "Epson",
+ 2 => "POS895",
+ _ => "Unknown"
+};
+
+static int ParsePrinterTargetArg(string arg) => arg.ToLowerInvariant() switch
+{
+ "1" or "epson" => 1,
+ "2" or "pos895" or "pos" => 2,
+ _ => 0
+};
+
static string GetReceiptTypeName(int index) => index switch
{
0 => "KitchenReceipt",
@@ -163,11 +179,19 @@ static async Task RunKitchenReceiptTest(int printerTarget)
await TestHelpers.PrintKitchenCommandsToHtmlPrinterAsync(printer, printCommands);
Console.WriteLine("Output written to: kitchen_test.html");
}
- else
+ else if (printerTarget == 1)
{
var printer = await TestHelpers.CreateEpsonPrinterAsync(paperWidth: TestHelpers.KitchenPaperWidth);
await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands, useDelay: true);
}
+ else
+ {
+ // Routes through PrinterWrapperFactory and the model adapter, the way
+ // EpsonPrintService does for a real job. The Epson branch above drives
+ // EpsonPrinter directly and feeds with ESC d, which the POS895 ignores.
+ var printer = await TestHelpers.CreateEpsonPrinterAsync();
+ await TestHelpers.PrintCommandsViaAdapterAsync(printer, printCommands);
+ }
}
static async Task RunFinalReceiptTest(int printerTarget)
@@ -189,11 +213,20 @@ static async Task RunFinalReceiptTest(int printerTarget)
logoPath: "ristorante-klinglers.ch-logo_white_bg.png");
Console.WriteLine("Output written to: test.html");
}
- else
+ else if (printerTarget == 1)
{
var printer = await TestHelpers.CreateEpsonPrinterAsync();
await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands);
}
+ else
+ {
+ // Routes through PrinterWrapperFactory and the model adapter, the way
+ // EpsonPrintService does for a real job. The Epson branch above drives
+ // EpsonPrinter directly and feeds with ESC d, which the POS895 ignores.
+ var printer = await TestHelpers.CreateEpsonPrinterAsync();
+ await TestHelpers.PrintCommandsViaAdapterAsync(printer, printCommands,
+ logoPath: "ristorante-klinglers.ch-logo_white_bg.png");
+ }
}
static async Task RunInvoiceReceiptTest(int printerTarget)
@@ -215,11 +248,20 @@ static async Task RunInvoiceReceiptTest(int printerTarget)
logoPath: "ristorante-klinglers.ch-logo_white_bg.png");
Console.WriteLine("Output written to: invoice_test.html");
}
- else
+ else if (printerTarget == 1)
{
var printer = await TestHelpers.CreateEpsonPrinterAsync();
await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands);
}
+ else
+ {
+ // Routes through PrinterWrapperFactory and the model adapter, the way
+ // EpsonPrintService does for a real job. The Epson branch above drives
+ // EpsonPrinter directly and feeds with ESC d, which the POS895 ignores.
+ var printer = await TestHelpers.CreateEpsonPrinterAsync();
+ await TestHelpers.PrintCommandsViaAdapterAsync(printer, printCommands,
+ logoPath: "ristorante-klinglers.ch-logo_white_bg.png");
+ }
}
static async Task RunBarReceiptTest(int printerTarget)
@@ -239,11 +281,19 @@ static async Task RunBarReceiptTest(int printerTarget)
await TestHelpers.PrintKitchenCommandsToHtmlPrinterAsync(printer, printCommands);
Console.WriteLine("Output written to: bar_test.html");
}
- else
+ else if (printerTarget == 1)
{
var printer = await TestHelpers.CreateEpsonPrinterAsync(paperWidth: TestHelpers.KitchenPaperWidth);
await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands, useDelay: true);
}
+ else
+ {
+ // Routes through PrinterWrapperFactory and the model adapter, the way
+ // EpsonPrintService does for a real job. The Epson branch above drives
+ // EpsonPrinter directly and feeds with ESC d, which the POS895 ignores.
+ var printer = await TestHelpers.CreateEpsonPrinterAsync();
+ await TestHelpers.PrintCommandsViaAdapterAsync(printer, printCommands);
+ }
}
static async Task RunOrderItemsTest(int printerTarget)
@@ -262,11 +312,19 @@ static async Task RunOrderItemsTest(int printerTarget)
await TestHelpers.PrintCommandsToHtmlPrinterAsync(printer, printCommands);
Console.WriteLine("Output written to: order_items.html");
}
- else
+ else if (printerTarget == 1)
{
var printer = await TestHelpers.CreateEpsonPrinterAsync();
await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands);
}
+ else
+ {
+ // Routes through PrinterWrapperFactory and the model adapter, the way
+ // EpsonPrintService does for a real job. The Epson branch above drives
+ // EpsonPrinter directly and feeds with ESC d, which the POS895 ignores.
+ var printer = await TestHelpers.CreateEpsonPrinterAsync();
+ await TestHelpers.PrintCommandsViaAdapterAsync(printer, printCommands);
+ }
}
static async Task RunMoneyReturnReceiptTest(int printerTarget)
@@ -288,9 +346,18 @@ static async Task RunMoneyReturnReceiptTest(int printerTarget)
logoPath: "ristorante-klinglers.ch-logo_white_bg.png");
Console.WriteLine("Output written to: money_return_test.html");
}
- else
+ else if (printerTarget == 1)
{
var printer = await TestHelpers.CreateEpsonPrinterAsync();
await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands);
}
+ else
+ {
+ // Routes through PrinterWrapperFactory and the model adapter, the way
+ // EpsonPrintService does for a real job. The Epson branch above drives
+ // EpsonPrinter directly and feeds with ESC d, which the POS895 ignores.
+ var printer = await TestHelpers.CreateEpsonPrinterAsync();
+ await TestHelpers.PrintCommandsViaAdapterAsync(printer, printCommands,
+ logoPath: "ristorante-klinglers.ch-logo_white_bg.png");
+ }
}
diff --git a/EpsonTest/TestHelpers.cs b/EpsonTest/TestHelpers.cs
index 0209d9d..c8010b0 100644
--- a/EpsonTest/TestHelpers.cs
+++ b/EpsonTest/TestHelpers.cs
@@ -1,5 +1,7 @@
using System.Diagnostics;
using Inspectron.Epson;
+using Inspectron.Epson.PrintServer.Printers;
+using Inspectron.Epson.PrintServer.PrintServices;
using Inspectron.Epson.PrintServer.Printers.Utils;
using Inspectron.Epson.PrintServer.Printers.Utils.BarReceipt;
using Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe;
@@ -577,6 +579,48 @@ public static class TestHelpers
await printer.CutAsync();
}
+ ///
+ /// Prints through the production IPrinter adapter chain instead of driving
+ /// EpsonPrinter directly: query the model byte, let PrinterWrapperFactory pick
+ /// the adapter from it, then print the logo and commands through that adapter.
+ /// This is what EpsonPrintService does for a real job, so it exercises the
+ /// model dispatch and the adapter's own ESC/POS dialect.
+ ///
+ /// Use this for the POS895. PrintCommandsToEpsonPrinterAsync above predates the
+ /// adapter layer and feeds with ESC d, which that firmware ignores - every cut
+ /// would slice through the last printed line.
+ ///
+ public static async Task PrintCommandsViaAdapterAsync(
+ EpsonPrinter printer,
+ IEnumerable commands,
+ string? logoPath = null)
+ {
+ byte? printerId = await printer.GetPrinterIdAsync();
+ if (printerId is null)
+ {
+ throw new InvalidOperationException(
+ "Printer did not answer GS I 1, so no adapter can be chosen for it.");
+ }
+
+ Console.WriteLine($"Printer reported model id 0x{printerId.Value:X2}");
+
+ IPrinter adapter = new PrinterWrapperFactory()
+ .CreatePrinterFromId(printerId.Value, printer);
+
+ Console.WriteLine($"Using adapter {adapter.GetType().Name}");
+
+ await adapter.InitAsync();
+
+ if (logoPath is not null)
+ {
+ Console.WriteLine($"Printing logo {logoPath}");
+ await adapter.PrintImageAsync(logoPath);
+ }
+
+ await adapter.PrintAsync(commands.ToList());
+ await adapter.Cut();
+ }
+
public static async Task PrintKitchenCommandsToHtmlPrinterAsync(
HtmlPrinter printer,
IEnumerable commands)
diff --git a/EpsonTest/test.html b/EpsonTest/test.html
new file mode 100644
index 0000000..4b2f947
--- /dev/null
+++ b/EpsonTest/test.html
@@ -0,0 +1,173 @@
+
+
+
+
+
+ Epson Printer Output
+
+
+
+
+
+
Klingler Gastro AG
+
Münzplatz 3
+
CH-8001 Zürich
+
043 321 22 22
+
+
+
Debitorenrechnung
+
14:58 16.12.2025
+
Guests: 2
+
+
1x San Pellegrino 50cl 6.50 6.50 A
+
1x Panna 50cl 6.50 6.50 A
+
1x An item with really long 5.50 5.50 A
+
description that should wrap
+
2x Business Lunch Menu Seco 44.00 88.00 A
+
- Tomato Soup
+
- Grilled Salmon
+
- Tiramisu
+
2x Brunello di Montalcino 1 16.00 32.00 A
+
2x Espresso 5.50 11.00 A
+
1x Tip 10.50 10.50 B
+
+
---------
+
+
Summe: 160.00 CHF
+
+
172.80 EUR
+
+
Fine Dine -50.00 CHF
+
+
Cash: 50.00 CHF
+
Card: 110.00 CHF
+
+
MASTER 160.00 CHF
+
+
MwSt % Brutto Netto MwSt
+
A: 8.1% 149.50 CHF 138.30 CHF 11.20 CHF
+
B: 0% 10.50 CHF 10.50 CHF 0.00 CHF
+
+
Bedient von: Yves
+
Terminal: Hauptkasse ZH
+
Tisch: 12
+
+
+
CHE-449.635.880 MWST
+
+
*** Kundenbeleg ***
+
Buchung
+
TWINT
+
XXXXXXXXXXXXXXX1494
+
11.11.2025 12:34:49
+
Trm-Id: 31108834
+
AID: A0000015749E
+
Trx. Seq-Cnt: 6127
+
Trx. Ref-No: 99036644599
+
Auth. Code: 0d3396
+
Acq-Id: 2
+
EFT CHF: 67.00
+
Trinkgeld CHF: 6.70
+
Total-EFT CHF: 73.70
+
------------------------------------------------
+
+
*** Kundenbeleg ***
+
Buchung
+
MASTER
+
XXXXXXXXXXXXXXX2587
+
11.11.2025 12:36:12
+
Trm-Id: 31108834
+
AID: A0000000041010
+
Trx. Seq-Cnt: 6128
+
Trx. Ref-No: 99036644600
+
Auth. Code: 1a4b2c
+
Acq-Id: 1
+
EFT CHF: 93.00
+
Trinkgeld CHF: 0.00
+
Total-EFT CHF: 93.00
+
------------------------------------------------
+
+
Das Team bedankt sich herzlich für Ihren
+
Besuch.
+
Auf Wiedersehen.
+
+
+
+
------------------------------------------------
+
Unterschrift
+
+
+
+
\ No newline at end of file
diff --git a/EpsonTest/test_images/image_0001.png b/EpsonTest/test_images/image_0001.png
new file mode 100644
index 0000000..ec48947
Binary files /dev/null and b/EpsonTest/test_images/image_0001.png differ