ESC/POS status replies¶
A simulated printer answers status requests the way an Epson TM printer does. Every reply is computed from the printer's current state, so when you make the printer run out of paper with emupos fault set front paper-out, your POS reads "paper out" in the status bytes, exactly as it would from a real printer.
This page lists the bytes emupos sends back, bit by bit. The bit layouts follow the Epson ESC/POS Command Reference for TM printers:
| Command | Reference page |
|---|---|
DLE EOT |
https://download4.epson.biz/sec_pubs/pos/reference_en/escpos/dle_eot.html |
GS r |
https://download4.epson.biz/sec_pubs/pos/reference_en/escpos/gs_lr.html |
ESC v, ESC u (obsolete status requests) |
https://download4.epson.biz/sec_pubs/pos/reference_en/escpos/esc_lv.html, https://download4.epson.biz/sec_pubs/pos/reference_en/escpos/esc_lu.html |
GS a (Automatic Status Back) |
https://download4.epson.biz/sec_pubs/pos/reference_en/escpos/gs_la.html |
GS I (transmit printer ID) |
https://download4.epson.biz/sec_pubs/pos/reference_en/escpos/gs_ci.html |
ESC p (drawer kick) |
https://download4.epson.biz/sec_pubs/pos/reference_en/escpos/esc_lp.html |
DLE DC4 fn 1 (real-time drawer pulse) |
https://download4.epson.biz/sec_pubs/pos/reference_en/escpos/dle_dc4_fn1.html |
Other commands are cited in the source: src/emupos/printer/escpos/tokenizer.py names the reference page of every command it recognises (https://download4.epson.biz/sec_pubs/pos/reference_en/escpos/<page>.html).
All bytes on this page are hexadecimal.
The state behind every reply¶
| State | How you change it | Effect on printing |
|---|---|---|
paper-near-end |
emupos fault set front paper-near-end |
Still prints. |
paper-out |
emupos fault set front paper-out |
Blocks printing. |
cover-open |
emupos fault set front cover-open |
Blocks printing. |
offline |
emupos fault set front offline |
Blocks printing. |
| Drawer open or closed | Opened by the POS (ESC p, DLE DC4 fn 1); closed with emupos drawer close |
None. |
emupos fault clear front <fault> clears a fault. The same actions are available through the control API (PUT and DELETE /api/v1/devices/{id}/faults/{fault}). Faults are independent: several can be active at once.
While a blocking fault is active, the printer keeps accepting bytes but holds print data and ordinary commands, in order, without printing them. Clearing the last blocking fault processes what was held.
Real-time commands are never held. DLE EOT and DLE DC4 are answered as soon as they arrive, even while printing is blocked. GS r, ESC v, ESC u, GS a, GS I and ESC p are ordinary commands: while printing is blocked they wait with the print data. Bytes inside another command's data (for example image data that happens to contain 10 04 01) are part of that command, never a status request.
DLE EOT n — real-time status (10 04 n)¶
The reply is one byte. Bit 1 and bit 4 are always 1 and bits 0 and 7 are always 0, so a reply with nothing to report is 12.
n = 1: printer status¶
| Bit | Value | Meaning | emupos sets it when |
|---|---|---|---|
| 2 | 04 |
Drawer kick-out connector pin 3 is high | the drawer sensor is high (see Cash drawer) |
| 3 | 08 |
Offline | offline, cover-open or paper-out is active |
| 5 | 20 |
Waiting for online recovery | never |
| 6 | 40 |
Paper feed button pressed | never |
n = 2: offline cause¶
| Bit | Value | Meaning | emupos sets it when |
|---|---|---|---|
| 2 | 04 |
Cover is open | cover-open is active |
| 3 | 08 |
Paper is being fed by the feed button | never |
| 5 | 20 |
Printing stopped because of paper end | paper-out is active |
| 6 | 40 |
Error occurred | never |
n = 3: error cause¶
| Bit | Value | Meaning | emupos sets it when |
|---|---|---|---|
| 2 | 04 |
Recoverable error | never |
| 3 | 08 |
Autocutter error | never |
| 5 | 20 |
Unrecoverable error | never |
| 6 | 40 |
Automatically recoverable error | never |
No simulated fault is an error, so the reply to 10 04 03 is always 12.
n = 4: roll paper sensor¶
| Bits | Value | Meaning | emupos sets them when |
|---|---|---|---|
| 2 and 3 | 0c |
Roll paper near end | paper-near-end or paper-out is active |
| 5 and 6 | 60 |
Roll paper not present | paper-out is active |
Replies by state¶
With the drawer sensor low (the drawer closed, with the built-in profiles):
| Active fault | 10 04 01 |
10 04 02 |
10 04 03 |
10 04 04 |
|---|---|---|---|---|
| none | 12 |
12 |
12 |
12 |
paper-near-end |
12 |
12 |
12 |
1e |
paper-out |
1a |
32 |
12 |
7e |
cover-open |
1a |
16 |
12 |
12 |
offline |
1a |
12 |
12 |
12 |
When the drawer sensor is high, add 04 to the 10 04 01 reply: 16 with no faults, 1e with cover-open. The drawer bit does not depend on faults.
Other values of n¶
For any other n, emupos sends nothing and publishes a printer.command.unknown event. For example 10 04 05 followed by 10 04 01 gets exactly one byte back: the reply to 10 04 01.
GS r n — transmit status (1d 72 n)¶
The reply is one byte, with no fixed bits.
n = 1 or 49: paper sensor¶
| Bits | Value | Meaning | emupos sets them when |
|---|---|---|---|
| 0 and 1 | 03 |
Roll paper near end | paper-near-end or paper-out is active |
| 2 and 3 | 0c |
Roll paper not present | paper-out is active |
Replies: 00 with no paper fault, 03 with paper-near-end, 0f with paper-out.
n = 2 or 50: drawer kick-out connector¶
| Bit | Value | Meaning |
|---|---|---|
| 0 | 01 |
Pin 3 is high |
Replies: 00 while pin 3 is low, 01 while it is high.
Other values of n¶
Other values (for example ink status) get no reply and publish a printer.command.unknown event.
GS r is not a real-time command. While cover-open, paper-out or offline is active, its reply is sent only after the fault is cleared.
ESC v and ESC u n (obsolete)¶
Older POS software asks for the same bytes with these commands, and emupos answers them like GS r, holding them while printing is blocked:
| Request | Reply |
|---|---|
ESC v (1b 76) |
the paper sensor byte of 1d 72 01 |
ESC u n (1b 75 n), n = 0 or 48 |
the drawer byte of 1d 72 02 |
ESC u with any other n gets no reply and publishes a printer.command.unknown event.
GS I n — transmit printer ID (1d 49 n)¶
POS software and printer drivers send GS I to find out which printer they are talking to, and Epson's reference tells the host to wait for the reply before sending more data. The values differ per model, so they come from the device profile. Of the built-in profiles, only epson-tm-t20iii carries them; a profile without them answers nothing at all, which is what rongta-rp326 and xprinter-xp80t do until their manuals are read.
On epson-tm-t20iii:
| n | Meaning | Reply |
|---|---|---|
| 1, 49 | Printer model ID | 63 |
| 2, 50 | Type ID: bit 1 is the autocutter | 02 |
| 35 | Column emulation mode, as 3d 23 + the mode + 00 |
3d 23 30 00 (standard column mode) |
| 65 | Firmware version | 5f 00 |
| 66 | Maker name | 5f + EPSON + 00 |
| 67 | Model name | 5f + TM-T20III + 00 |
| 68 | Serial number | 5f 00 |
| 69 | Font of the language | 5f 00 |
A simulator has no firmware build, no serial number and no language font, so those three answer 5f 00 — the two bytes a real printer sends for a value it has not been given. Every other n, and every GS I to a profile without printer-ID values, gets no reply and publishes a printer.command.unknown event.
GS I is not a real-time command. While cover-open, paper-out or offline is active, its reply is sent only after the fault is cleared.
To give your own profile these values, see the printer_id keys in configuration.
GS a n — Automatic Status Back (1d 61 n)¶
Automatic Status Back (ASB) makes the printer push a 4-byte status by itself.
GS a nwith n other than 0 turns ASB on for the connection that sent it. emupos sends the current 4-byte status at once, then a new one each time a status category enabled by n changes.GS a 0turns it off.ESC @also turns it off, and every new connection starts with it off.- Other connections to the same printer are not affected.
The bits of n¶
| Bit of n | Value | Category | Changes in emupos when |
|---|---|---|---|
| 0 | 01 |
Drawer kick-out connector | the drawer opens or closes |
| 1 | 02 |
Online/offline | offline, cover-open or paper-out changes |
| 2 | 04 |
Errors | never |
| 3 | 08 |
Roll paper sensor | paper-near-end or paper-out changes |
| 6 | 40 |
Panel switch | never |
So 1d 61 ff reports every change, while 1d 61 01 reports only the drawer.
The four status bytes¶
| Byte | Value | Meaning | emupos sets it when |
|---|---|---|---|
| 1st | 10 |
Fixed | always |
| 1st | 04 |
Drawer kick-out connector pin 3 is high | the drawer sensor is high |
| 1st | 08 |
Offline | offline, cover-open or paper-out is active |
| 1st | 20 |
Cover is open | cover-open is active |
| 1st | 40 |
Paper being fed by the feed button | never |
| 2nd | 01 |
Waiting for online recovery | never |
| 2nd | 02 |
Paper feed button pushed | never |
| 2nd | 04 |
Recoverable error | never |
| 2nd | 08 |
Autocutter error | never |
| 2nd | 20 |
Unrecoverable error | never |
| 2nd | 40 |
Automatically recoverable error | never |
| 3rd | 03 |
Roll paper near end | paper-near-end or paper-out is active |
| 3rd | 0c |
Roll paper not present | paper-out is active |
| 4th | — | — | always 00 |
| State | ASB status |
|---|---|
| no faults, pin 3 low | 10 00 00 00 |
| pin 3 high | 14 00 00 00 |
paper-near-end |
10 00 03 00 |
paper-out |
18 00 0f 00 |
cover-open |
38 00 00 00 |
offline |
18 00 00 00 |
Example¶
> is what the POS sends, < is what emupos sends back:
> 1d 61 ff turn on ASB for everything
< 10 00 00 00 current status
(emupos fault set front cover-open)
< 38 00 00 00 offline, cover open
> 10 04 01 10 04 02 real-time status while the cover is open
< 1a 16
> 1d 72 01 GS r: held, printing is blocked
(emupos fault clear front cover-open)
< 10 00 00 00 00 the new ASB status, then the held GS r reply
Cash drawer and pin 3¶
Every printer has one cash drawer. The POS opens it with a pulse on the drawer kick-out connector:
| Command | Bytes | Pin | Pulse ON time | Held while printing is blocked? |
|---|---|---|---|---|
ESC p m t1 t2 |
1b 70 m t1 t2 |
m = 00 or 30 ("0"): pin 2; m = 01 or 31 ("1"): pin 5 |
t1 × 2 ms | Yes |
DLE DC4 fn 1 |
10 14 01 m t |
m = 00: pin 2; m = 01: pin 5; t from 1 to 8 |
t × 100 ms | No, it opens at once |
A pulse on either pin opens the same drawer. Other parameter values open nothing and publish printer.command.unknown. The drawer stays open until you close it with emupos drawer close or POST /api/v1/devices/{id}/drawer/close: it never closes by itself.
The drawer's switch is read on connector pin 3. Drawers differ in which level means "open", so the level is configurable with drawer: { sensor_open_level: high | low } in emupos.yaml. When it is not set, the printer profile decides; all built-in profiles use high.
sensor_open_level |
Drawer | Pin 3 | 10 04 01 bit 2 |
1d 72 02 |
ASB 1st byte bit 2 |
|---|---|---|---|---|---|
high |
open | high | 1 (16) |
01 |
1 (14) |
high |
closed | low | 0 (12) |
00 |
0 (10) |
low |
open | low | 0 (12) |
00 |
0 (10) |
low |
closed | high | 1 (16) |
01 |
1 (14) |
The replies in brackets assume no active fault.
What happens to each command¶
The printer recognises a command by its bytes and consumes it completely, including its parameters and data, so the next command is always found correctly. What happens next depends on the command.
Rendered or acted on¶
| Commands | What emupos does |
|---|---|
Printable text (20–ff), LF, ESC d, ESC J, ESC 2, ESC 3 |
Prints text and feeds paper; wraps text that does not fit the line |
GS T |
Returns to the start of the line: n = 1 or 49 prints the line first (like LF), n = 0 or 48 discards it; ignored at the start of a line |
ESC @ |
Resets print settings to the profile defaults and discards the unprinted line |
ESC !, ESC E, ESC G, ESC -, ESC M, GS !, GS B |
Font, bold (double-strike looks the same as bold), underline, character size, reverse printing |
ESC a, ESC { |
Justification and upside-down printing; ignored when sent in the middle of a line |
ESC t |
Selects a code page by the profile's number; see the note below |
HT, ESC D |
Tabs: moves to the next tab position (every 8 characters by default); the text dump fills the gap with spaces |
ESC SP, GS L, GS W, ESC $, ESC \ |
Right-side character spacing, left margin, print area width, absolute and relative print position |
ESC *, GS v 0 |
Bit images and raster images, dot for dot |
GS ( L / GS 8 L fn 112 and fn 50 |
Buffered graphics: store a monochrome raster image, then print it. fn 48 and fn 51 report an NV graphics capacity of zero |
GS k |
Barcodes: UPC-A, EAN-13, EAN-8, CODE39, ITF and CODE128 (m = 73) |
GS w, GS h, GS H, GS f |
Barcode module width, height, and position and font of the human-readable text |
GS ( k with cn = 49 |
QR codes: module size (fn 167), error correction (fn 169), store (fn 180), print (fn 181); always printed as model 2 |
GS V, ESC i, ESC m |
Ends the receipt (any cut form; ESC i and ESC m are Epson's obsolete partial cuts) |
ESC p, DLE DC4 fn 1 |
Opens the drawer |
DLE EOT n (n = 1–4), GS r n (n = 1, 2, 49, 50), ESC v, ESC u n (n = 0, 48), GS a n |
Status replies, as described above |
GS I n |
The printer's identity, when the profile carries it (see above) |
The code pages the built-in profiles name have glyphs: PC437, PC850, PC852, PC858, PC860, PC863, PC865, PC866, WPC1252, PC720, PC864 and WPC1256. Selecting a number missing from the profile, or a code page emupos has no glyph table for, publishes printer.codepage.unsupported, and bytes 80–ff then print as a placeholder that fills one character cell. A single byte without a glyph inside a code page that has a table prints the same placeholder, without an event. Bytes 20–7e always print as ASCII. The receipt's text dump shows the real characters for code pages emupos has a character mapping for (PC720, PC864 and WPC1256 among them), and U+FFFD otherwise.
Each byte is printed into the next character cell, in the order it arrives. Like a real ESC/POS printer, emupos does not reorder bytes and does not join Arabic letters: a POS shapes its Arabic and reverses it before sending, and what it sends is what the receipt shows.
Consumed without any effect¶
These change nothing on a receipt image, so emupos consumes them silently: CR, GS b, FS ., FS &, ESC =, ESC c 0, ESC c 1, ESC c 3, ESC c 4, ESC c 5, ESC U, GS P, ESC S, and ESC r (print colour: every built-in profile is single-colour, so text asked for in red prints in black, as on a real single-colour printer).
Consumed and reported as unknown¶
These are recognised and consumed in full, but not simulated. Each one publishes a printer.command.unknown event whose data has the bytes and the command name, and printing continues normally:
- character sets and rotation:
ESC R,ESC V - page mode:
ESC L(the printer stays in standard mode),ESC T,ESC W,GS $,GS \ - NV graphics and other function commands:
GS ( L/GS 8 Lfunctions other than 48, 50, 51 and 112, otherGS (commands,ESC (,FS ( - stored logos and bit images:
FS p,GS *,GS /(nothing is printed) GS ( ksymbols other than QR codes, such as PDF417GS kin other symbologies (UPC-E, CODABAR, CODE93, GS1-128, GS1 DataBar, CODE128 with m = 79); the event names the symbologyDLE ENQ,DLE DC4functions other than 1,DLE EOT,GS randESC uwith other values of nESC *,GS v 0,ESC M,ESC pandGS Twith a mode or parameter they do not accept
Some POS libraries send these. When one of them matters for your receipts, open a device or protocol request. Unknown commands never affect status replies.
Bytes that form no command¶
A control byte that starts no recognised command is skipped. After ESC, GS, FS or DLE, the following byte is skipped too. Each skip publishes printer.command.unknown with the skipped bytes. A command still incomplete when the connection closes is dropped the same way. No byte sequence stops the printer.