Customer Display Emulator

Emulate a serial customer display on your PC — test your “customer total”
code with no hardware.
Customer Display Emulator is a standalone WPF app that emulates a customer
display (pole display) and listens on a COM port, so you can test your
solution’s “customer total display” code without real hardware.
Note on naming: the repository, solution, assembly, and C# namespace use
the name LedDisplayEmulator (historical), while the app is branded
Customer Display Emulator. They refer to the same project.
Features
- Two display modes — Simple 8-Digit marquee and LED8 N-type with label indicators.
- No hardware required — pairs with your app over a virtual COM port (com0com).
- ESC/POS protocol support — standard commands used by real customer displays.
- Live hex log — inspect raw bytes received on the serial port.
- Bidirectional test — built-in Test button verifies the connection both ways.
Two Display Modes
| Mode |
Description |
| Simple 8-Digit |
Basic 8-digit marquee display (ASCII characters shift right-to-left) |
| LED8 N-type |
8-digit display + 4 label indicators (PRICE, TOTAL, COLLECT, CHANGE) with ESC/POS protocol |
Switch between modes using the Display Type dropdown.
Requirements
Build & Run
dotnet build
dotnet run
Or open LedDisplayEmulator.slnx in Visual Studio and press F5.
How It Works
┌─────────────────────┐ ┌─────────────────────┐
│ Your App │ │ Display Emulator │
│ │ │ │
│ SerialPort("COM10")├────COM0COM─────► SerialPort("COM11") │
│ │ virtual │ │
│ writes data ───────┼────────────────┼───► displays digits │
└─────────────────────┘ └─────────────────────┘
Your app writes bytes to one end of a virtual COM port pair (created with
com0com). The emulator listens on the other end, parses the protocol
(Simple or ESC/POS), and renders the data on a simulated 7-segment display.
Anything written to COM10 appears on COM11, and vice versa.
Complete Setup Guide: Testing with Your App
Step 1: Install com0com
- Download com0com from: https://sourceforge.net/projects/com0com/
- Run the installer (accept any Windows security prompts for unsigned drivers)
- After installation, open Setup Command Prompt (Start Menu → com0com → Setup)
- You’ll see a paired virtual port, for example:
CNCB0 PortName=COM10
CNCB1 PortName=COM11
- If you need different port numbers, type:
setupc CNCA0 PortName=COM10
setupc CNCB0 PortName=COM11
- Close the setup window when done
In your app code that sends data to the customer display, make sure it
targets COM10 (or whichever port you configured above).
Example configuration in your app:
// In your app's display service or config
var displayPort = new SerialPort("COM10", 9600, Parity.None, 8, StopBits.One);
Or in appsettings.json:
{
"CustomerDisplay": {
"PortName": "COM10",
"BaudRate": 9600
}
}
Step 3: Start the Emulator
- Run
dotnet run or launch from Visual Studio
- Select Display Type (Simple 8-Digit or LED8 N-type)
- Select COM11 in the COM Port dropdown (the other end of the virtual pair)
- Set Baud Rate to match your app (default: 9600)
- Click Connect
- You should see “Connected: COM11 @ 9600” in green
Step 4: Test from Your App
Trigger your “send total to customer display” code path in your app.
You should see:
- The digits light up on the emulator
- Raw hex bytes logged at the bottom of the emulator window
Click Test to send sample data from the emulator to your app (via the
virtual COM port). This verifies the connection is working both ways.
Test button behavior:
- Simple mode: Sends
CLR + "1234.56"
- LED8N mode: Sends
CLR + ESC s 2 (TOTAL) + ESC Q A 2 + "99.95" + CR
The emulator uses these serial settings (must match your app):
| Setting |
Value |
| Baud Rate |
9600 (default) or 2400 |
| Data Bits |
8 |
| Parity |
None |
| Stop Bits |
1 |
| Handshake |
None |
| DTR |
Enabled |
| RTS |
Enabled |
Display Modes Explained
Simple 8-Digit Mode
- Characters (
0-9, -, space) shift in from the right like a marquee
- A
. character sets the decimal point on the last digit shown
- Clear byte is configurable (default:
0x0C Form Feed)
Protocol:
[clear byte] [data...] → digits shift in from right
Example:
0C 31 32 2E 33 34 → CLR + "12.34" → displays: [1][2][.][3][4][ ][ ][ ]
LED8 N-type Mode
Uses standard ESC/POS commands (same as real hardware).
Supported Commands:
| Command |
Hex |
Description |
| CLR |
0C |
Clear all characters |
| CAN |
18 |
Clear cursor line |
| ESC @ |
1B 40 |
Initialize display |
| ESC s n |
1B 73 n |
Set label (0=off, 1=PRICE, 2=TOTAL, 3=COLLECT, 4=CHANGE) |
| ESC Q A … CR |
1B 51 41 ... 0D |
Send display data |
Sending a total with label:
1B 73 32 → ESC s 2 (set label to TOTAL)
1B 51 41 32 → ESC Q A + "2"
31 32 2E 33 34 0D → "12.34" + CR
Sending Data from Your POS App (C# Code Examples)
Simple 8-Digit Mode
using System.IO.Ports;
// Connect to the emulator
using var port = new SerialPort("COM10", 9600, Parity.None, 8, StopBits.One);
port.Open();
// Clear and display a total
port.Write(new byte[] { 0x0C }, 0, 1); // Clear
port.Write("12.34"); // Display shifts in from right
LED8 N-type Mode
using System.IO.Ports;
using var port = new SerialPort("COM10", 9600, Parity.None, 8, StopBits.One);
port.Open();
// Set label to TOTAL and display 12.34
port.Write(new byte[] { 0x1B, 0x73, 0x32 }, 0, 3); // ESC s 2 (TOTAL)
port.Write(new byte[] { 0x1B, 0x51, 0x41, 0x32 }, 0, 4); // ESC Q A
port.Write("12.34");
port.Write(new byte[] { 0x0D }, 0, 1); // CR
// Clear display
port.Write(new byte[] { 0x0C }, 0, 1); // CLR
Reusable Display Service Class
public class CustomerDisplayService : IDisposable
{
private SerialPort? _port;
public void Connect(string portName, int baudRate = 9600)
{
_port = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One);
_port.Open();
}
// For Simple 8-Digit mode
public void ShowSimple(string text)
{
if (_port == null || !_port.IsOpen) return;
_port.Write(new byte[] { 0x0C }, 0, 1); // Clear
_port.Write(text);
}
// For LED8 N-type mode
public void ShowLed8N(string text, int label = 0)
{
if (_port == null || !_port.IsOpen) return;
// Set label (0=none, 1=PRICE, 2=TOTAL, 3=COLLECT, 4=CHANGE)
_port.Write(new byte[] { 0x1B, 0x73, (byte)(0x30 + label) }, 0, 3);
// Send display data
_port.Write(new byte[] { 0x1B, 0x51, 0x41 }, 0, 3);
_port.Write(text);
_port.Write(new byte[] { 0x0D }, 0, 1); // CR
}
public void Clear()
{
_port?.Write(new byte[] { 0x0C }, 0, 1);
}
public void Dispose()
{
_port?.Close();
_port?.Dispose();
}
}
Usage:
var display = new CustomerDisplayService();
display.Connect("COM10");
display.ShowLed8N("12.34", label: 2); // Show 12.34 with TOTAL label
Project Structure
| File |
Description |
MainWindow.xaml |
UI layout: display area, labels, controls, log |
MainWindow.xaml.cs |
COM port handling, protocol parsers (Simple + LED8 N-type) |
SevenSegmentDigit.xaml |
Single 7-segment digit control |
SevenSegmentDigit.xaml.cs |
Procedural digit rendering |
LedDisplayEmulator.csproj |
Project file (.NET 8 / WPF, net8.0-windows) |
LedDisplayEmulator.slnx |
Solution file |
Troubleshooting
| Problem |
Solution |
| COM ports not appearing |
Restart after com0com install, or run setupc to verify ports exist |
| “Access denied” on COM port |
Close any other app using that port, or run as admin |
| Digits don’t light up |
Check baud rate matches (both apps must use same speed) |
| Wrong characters displayed |
Check you’re in the right display mode (Simple vs LED8 N-type) |
| Labels don’t appear |
Make sure you’re in LED8 N-type mode and sending ESC s n command |
| Click Test button shows “Connect first!” |
You must click Connect before testing |
| Test button shows “Send error” |
Check the COM port isn’t held open by another app |
Contributing
Contributions are welcome! Please open an issue to discuss any significant
change before submitting a pull request. Keep the code style consistent with
the existing WPF/C# codebase.
Acknowledgements
- com0com — virtual COM port driver used for testing.
- ESC/POS protocol reference for customer/pole displays.
Disclaimer
This project is not affiliated with, endorsed by, or sponsored by any POS or
display hardware vendor. It implements a subset of the ESC/POS command set for
emulation and testing purposes only.
License
Released under the MIT License.
评论