@thermal-print/escpos 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +193 -0
  3. package/dist/command-adapters/escbematech-adapter.d.ts +30 -0
  4. package/dist/command-adapters/escbematech-adapter.d.ts.map +1 -0
  5. package/dist/command-adapters/escbematech-adapter.js +175 -0
  6. package/dist/command-adapters/escpos-adapter.d.ts +25 -0
  7. package/dist/command-adapters/escpos-adapter.d.ts.map +1 -0
  8. package/dist/command-adapters/escpos-adapter.js +144 -0
  9. package/dist/command-adapters/index.d.ts +11 -0
  10. package/dist/command-adapters/index.d.ts.map +1 -0
  11. package/dist/command-adapters/index.js +14 -0
  12. package/dist/command-adapters/types.d.ts +78 -0
  13. package/dist/command-adapters/types.d.ts.map +1 -0
  14. package/dist/command-adapters/types.js +8 -0
  15. package/dist/commands/escbematech.d.ts +867 -0
  16. package/dist/commands/escbematech.d.ts.map +1 -0
  17. package/dist/commands/escbematech.js +1387 -0
  18. package/dist/commands/escpos.d.ts +582 -0
  19. package/dist/commands/escpos.d.ts.map +1 -0
  20. package/dist/commands/escpos.js +1048 -0
  21. package/dist/converter.d.ts +47 -0
  22. package/dist/converter.d.ts.map +1 -0
  23. package/dist/converter.js +92 -0
  24. package/dist/encodings/cp860.d.ts +25 -0
  25. package/dist/encodings/cp860.d.ts.map +1 -0
  26. package/dist/encodings/cp860.js +187 -0
  27. package/dist/generator.d.ts +118 -0
  28. package/dist/generator.d.ts.map +1 -0
  29. package/dist/generator.js +383 -0
  30. package/dist/index.d.ts +17 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +55 -0
  33. package/dist/styles.d.ts +72 -0
  34. package/dist/styles.d.ts.map +1 -0
  35. package/dist/styles.js +210 -0
  36. package/dist/traverser.d.ts +60 -0
  37. package/dist/traverser.d.ts.map +1 -0
  38. package/dist/traverser.js +285 -0
  39. package/dist/types.d.ts +21 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +5 -0
  42. package/package.json +31 -0
@@ -0,0 +1,1387 @@
1
+ "use strict";
2
+ /**
3
+ * ESC/Bematech Command Set
4
+ *
5
+ * Command bytes for Bematech MP-4200 TH thermal printer using ESC/Bematech protocol.
6
+ * Reference: Bematech MP-4200 TH Programmer's Manual - Revision 1.0, Chapter 3
7
+ *
8
+ * This file contains all documented ESC/Bematech commands organized by category.
9
+ * Commands follow the Bematech-specific implementation which differs from standard ESC/POS.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.PrinterLanguage = exports.setPrintingIntensityAlt = exports.setPrintingIntensity = exports.setPrinterMode = exports.PrinterMode = exports.selectDrawerSensor = exports.selectPaperSensor = exports.disablePaperNearEndSensor = exports.enablePaperNearEndSensor = exports.setPaperWidth = exports.PaperWidth = exports.printUnicodeSet = exports.PRINT_UNICODE_SETS = exports.setInternationalCharset = exports.setIdeogramMode = exports.setDefaultCodePage = exports.setCodePage = exports.CodePage = exports.GET_CURRENT_MODE = exports.returnToPreviousMode = exports.selectESCPOSModeTemp = exports.selectESCBemaModeTemp = exports.selectESCPOSMode = exports.selectESCBemaMode = exports.INIT = exports.DEL = exports.GS = exports.FS = exports.ESC = exports.CAN = exports.ETB = exports.SYN = exports.NAK = exports.DC4 = exports.DC2 = exports.SI = exports.SO = exports.CR = exports.FF = exports.LF = exports.HT = exports.BS = exports.BEL = exports.ACK = exports.ENQ = exports.EOT = exports.ETX = exports.STX = exports.SOH = exports.NUL = void 0;
13
+ exports.DOUBLE_HEIGHT_ONLINE = exports.DOUBLE_HEIGHT_OFF = exports.DOUBLE_HEIGHT_ON = exports.calculatePrintMode = exports.SCRIPT_OFF = exports.SUBSCRIPT_ON = exports.SUPERSCRIPT_ON = exports.UPSIDE_DOWN_OFF = exports.UPSIDE_DOWN_ON = exports.ITALIC_OFF = exports.ITALIC_ON = exports.UNDERLINE_OFF = exports.UNDERLINE_ON = exports.BOLD_OFF = exports.BOLD_ON = exports.ALIGN_RIGHT = exports.ALIGN_CENTER = exports.ALIGN_LEFT = exports.CLEAR_TABS = exports.setTabPositions = exports.TAB = exports.setLeftMargin = exports.setRightMargin = exports.disableAutoLineFeed = exports.enableAutoLineFeed = exports.setPageSizeMM = exports.setPageSizeLines = exports.horizontalSkip = exports.verticalSkip = exports.setLineSpacing = exports.SET_LINE_HEIGHT_DEFAULT = exports.feedPaper = exports.fineFeed = exports.FEED_PAGE = exports.FEED_LINE = exports.activateBuzzer = exports.disableBuzzerOnCut = exports.setBuzzerOnCut = exports.CUT_FULL_ALT = exports.CUT_FULL = exports.activateDrawer2 = exports.activateDrawer1 = exports.ENABLE_DUMP_MODE = exports.disablePanelKeys = exports.enablePanelKeys = exports.RESET_PRINTER = exports.PRINT_CONFIG = exports.LOAD_DEFAULT_CONFIG = exports.getPrinterInfo = exports.setPrinterLanguage = void 0;
14
+ exports.CLEAR_BUFFER = exports.EXTENDED_STATUS = exports.STATUS_ENQUIRY = exports.printBarcodePLESSEYAlt = exports.printBarcodePLESSEY = exports.printBarcodeMSIAlt = exports.printBarcodeMSI = exports.printBarcodeISBN = exports.printBarcodePDF417 = exports.printBarcodeCODE128 = exports.printBarcodeCODE93 = exports.printBarcodeCODABARAlt = exports.printBarcodeCODABAR = exports.printBarcodeITFAlt = exports.printBarcodeITF = exports.printBarcodeCODE39Alt = exports.printBarcodeCODE39 = exports.printBarcodeEAN8Alt = exports.printBarcodeEAN8 = exports.printBarcodeEAN13Alt = exports.printBarcodeEAN13 = exports.printBarcodeUPCEAlt = exports.printBarcodeUPCE = exports.printBarcodeUPCAAlt = exports.printBarcodeUPCA = exports.setBarcodeLeftMargin = exports.setBarcodeHRIFont = exports.setBarcodeHRI = exports.BarcodeHRIPosition = exports.setBarcodeWidth = exports.setBarcodeHeight = exports.printNVBitImage = exports.defineNVBitImage = exports.printDownloadedBitImage = exports.defineDownloadedBitImage = exports.printRasterBitmap = exports.RasterMode = exports.print8BitGraphics = exports.print24BitGraphics = exports.fillBlankColumns = exports.CONDENSED_OFF_DC2 = exports.CONDENSED_OFF_ALT = exports.CONDENSED_OFF = exports.CONDENSED_ON_ALT = exports.CONDENSED_ON = exports.EXPANDED_OFF = exports.EXPANDED_ONLINE_ALT = exports.EXPANDED_ONLINE = exports.DOUBLE_WIDTH_OFF = exports.DOUBLE_WIDTH_ON = void 0;
15
+ exports.validateBarcodeData = exports.encodeText = exports.setWiFi = exports.setSNMP = exports.disableDHCP = exports.enableDHCP = exports.setGateway = exports.setIPAddress = exports.CANCEL_CHAR = exports.CANCEL_LINE = exports.END_BUFFER = void 0;
16
+ // ============================================================================
17
+ // CONTROL CHARACTERS
18
+ // ============================================================================
19
+ exports.NUL = 0x00; // Null
20
+ exports.SOH = 0x01; // Start of Heading
21
+ exports.STX = 0x02; // Start of Text - Clear buffer
22
+ exports.ETX = 0x03; // End of Text - End buffer
23
+ exports.EOT = 0x04; // End of Transmission
24
+ exports.ENQ = 0x05; // Enquiry - Printer status
25
+ exports.ACK = 0x06; // Acknowledge
26
+ exports.BEL = 0x07; // Bell
27
+ exports.BS = 0x08; // Backspace
28
+ exports.HT = 0x09; // Horizontal Tab
29
+ exports.LF = 0x0a; // Line Feed
30
+ exports.FF = 0x0c; // Form Feed
31
+ exports.CR = 0x0d; // Carriage Return
32
+ exports.SO = 0x0e; // Shift Out - Enable on-line expanded mode
33
+ exports.SI = 0x0f; // Shift In - Enable condensed mode
34
+ exports.DC2 = 0x12; // Device Control 2 - Disable condensed mode
35
+ exports.DC4 = 0x14; // Device Control 4 - Disable on-line expanded print
36
+ exports.NAK = 0x15; // Negative Acknowledge
37
+ exports.SYN = 0x16; // Synchronous Idle
38
+ exports.ETB = 0x17; // End of Transmission Block
39
+ exports.CAN = 0x18; // Cancel - Cancel last line
40
+ exports.ESC = 0x1b; // Escape
41
+ exports.FS = 0x1c; // File Separator
42
+ exports.GS = 0x1d; // Group Separator
43
+ exports.DEL = 0x7f; // Delete - Cancel last character
44
+ // ============================================================================
45
+ // INITIALIZATION & CONFIGURATION
46
+ // ============================================================================
47
+ /**
48
+ * ESC @ - Initialize printer to default settings
49
+ * Hexadecimal: 1B 40
50
+ * Decimal: 27 64
51
+ *
52
+ * Cancels all printer settings including character font, line spacing,
53
+ * margins, and returns printer to initial state.
54
+ */
55
+ exports.INIT = [exports.ESC, 0x40];
56
+ // ============================================================================
57
+ // MODE SELECTION
58
+ // ============================================================================
59
+ /**
60
+ * GS F9h 5 n - Select printer operating mode (permanent)
61
+ * Saves to non-volatile memory
62
+ * n = 0 or 48: ESC/Bema mode
63
+ * n = 1 or 49: ESC/POS mode
64
+ */
65
+ const selectESCBemaMode = () => [exports.GS, 0xF9, 0x35, 0x00];
66
+ exports.selectESCBemaMode = selectESCBemaMode;
67
+ const selectESCPOSMode = () => [exports.GS, 0xF9, 0x35, 0x01];
68
+ exports.selectESCPOSMode = selectESCPOSMode;
69
+ /**
70
+ * GS F9h SP n - Select printer operating mode temporarily
71
+ * Does NOT save to memory
72
+ * n = 0 or 48: ESC/Bema mode
73
+ * n = 1 or 49: ESC/POS mode
74
+ */
75
+ const selectESCBemaModeTemp = () => [exports.GS, 0xF9, 0x20, 0x00];
76
+ exports.selectESCBemaModeTemp = selectESCBemaModeTemp;
77
+ const selectESCPOSModeTemp = () => [exports.GS, 0xF9, 0x20, 0x01];
78
+ exports.selectESCPOSModeTemp = selectESCPOSModeTemp;
79
+ /**
80
+ * GS F9h 1Fh 1 - Return to previously set mode
81
+ * Hexadecimal: 1D F9 1F 31
82
+ */
83
+ const returnToPreviousMode = () => [exports.GS, 0xF9, 0x1F, 0x31];
84
+ exports.returnToPreviousMode = returnToPreviousMode;
85
+ /**
86
+ * GS F9h C 00h - Get printer current command set
87
+ * Returns: 0 = ESC/Bema, 1 = ESC/POS
88
+ */
89
+ exports.GET_CURRENT_MODE = [exports.GS, 0xF9, 0x43, 0x00];
90
+ // ============================================================================
91
+ // CODE PAGES & CHARACTER ENCODING
92
+ // ============================================================================
93
+ /**
94
+ * Code page identifiers
95
+ */
96
+ var CodePage;
97
+ (function (CodePage) {
98
+ CodePage[CodePage["CP850"] = 2] = "CP850";
99
+ CodePage[CodePage["CP437"] = 3] = "CP437";
100
+ CodePage[CodePage["CP860"] = 4] = "CP860";
101
+ CodePage[CodePage["CP858"] = 5] = "CP858";
102
+ CodePage[CodePage["CP866"] = 6] = "CP866";
103
+ CodePage[CodePage["CP864"] = 7] = "CP864";
104
+ CodePage[CodePage["UTF8"] = 8] = "UTF8";
105
+ CodePage[CodePage["BIG5E"] = 9] = "BIG5E";
106
+ CodePage[CodePage["JIS"] = 10] = "JIS";
107
+ CodePage[CodePage["SHIFT_JIS"] = 11] = "SHIFT_JIS";
108
+ CodePage[CodePage["GB2312"] = 12] = "GB2312";
109
+ CodePage[CodePage["EUC_CN"] = 14] = "EUC_CN";
110
+ CodePage[CodePage["CP862"] = 21] = "CP862"; // CODEPAGE 862 (15h)
111
+ })(CodePage || (exports.CodePage = CodePage = {}));
112
+ /**
113
+ * ESC t n - Select code page
114
+ * Hexadecimal: 1B 74 n
115
+ * Default: CP850
116
+ */
117
+ const setCodePage = (codePage) => [exports.ESC, 0x74, codePage];
118
+ exports.setCodePage = setCodePage;
119
+ /**
120
+ * GS F9h 7 n - Set and save printer default code page
121
+ * Saves to non-volatile memory
122
+ */
123
+ const setDefaultCodePage = (codePage) => [exports.GS, 0xF9, 0x37, codePage];
124
+ exports.setDefaultCodePage = setDefaultCodePage;
125
+ /**
126
+ * GS F9h 8 n - Set and save ESC/POS ideogram mode
127
+ * n = 0: UTF8 (Unicode)
128
+ * n = 1: ESC/POS Japanese
129
+ * n = 2: ESC/POS Simplified Chinese
130
+ * n = 3: ESC/POS Traditional Chinese
131
+ */
132
+ const setIdeogramMode = (mode) => [exports.GS, 0xF9, 0x38, mode];
133
+ exports.setIdeogramMode = setIdeogramMode;
134
+ /**
135
+ * ESC R n - Select international character set
136
+ * n = 0: CODEPAGE 437
137
+ * n = 1-11: CODEPAGE 858
138
+ * n = 12: CODEPAGE 850 (default)
139
+ */
140
+ const setInternationalCharset = (n) => {
141
+ if (n < 0 || n > 12)
142
+ n = 12;
143
+ return [exports.ESC, 0x52, n];
144
+ };
145
+ exports.setInternationalCharset = setInternationalCharset;
146
+ /**
147
+ * ESC Z - Print supported Unicode sets
148
+ * Prints a chart showing all supported Unicode character sets
149
+ */
150
+ exports.PRINT_UNICODE_SETS = [exports.ESC, 0x5A];
151
+ /**
152
+ * ESC [ n - Print specific Unicode set
153
+ * Range: 0 ≤ n ≤ 255
154
+ */
155
+ const printUnicodeSet = (n) => [exports.ESC, 0x5B, Math.max(0, Math.min(255, n))];
156
+ exports.printUnicodeSet = printUnicodeSet;
157
+ // ============================================================================
158
+ // PAPER CONFIGURATION
159
+ // ============================================================================
160
+ /**
161
+ * Paper width presets (ESC/Bema mode only)
162
+ * Format: [paper width in mm, printing width in mm]
163
+ */
164
+ var PaperWidth;
165
+ (function (PaperWidth) {
166
+ PaperWidth[PaperWidth["WIDTH_58_48"] = 0] = "WIDTH_58_48";
167
+ PaperWidth[PaperWidth["WIDTH_76_72"] = 1] = "WIDTH_76_72";
168
+ PaperWidth[PaperWidth["WIDTH_80_72"] = 2] = "WIDTH_80_72";
169
+ PaperWidth[PaperWidth["WIDTH_80_76"] = 3] = "WIDTH_80_76";
170
+ PaperWidth[PaperWidth["WIDTH_82_72"] = 4] = "WIDTH_82_72";
171
+ PaperWidth[PaperWidth["WIDTH_82_76"] = 5] = "WIDTH_82_76";
172
+ PaperWidth[PaperWidth["WIDTH_82_80"] = 6] = "WIDTH_82_80"; // 82.5mm paper, 80mm print width
173
+ })(PaperWidth || (exports.PaperWidth = PaperWidth = {}));
174
+ /**
175
+ * GS F9h ! n - Set and save paper width
176
+ * Only effective in ESC/Bema mode
177
+ * In ESC/POS mode, paper width is always 80mm/73.5mm
178
+ */
179
+ const setPaperWidth = (width) => [exports.GS, 0xF9, 0x21, width];
180
+ exports.setPaperWidth = setPaperWidth;
181
+ /**
182
+ * GS F9h , n - Enable/disable paper near-end sensor (PNES)
183
+ * n = 0 or 48: Disable PNES
184
+ * n = 1 or 49: Enable PNES (default)
185
+ * Saves to non-volatile memory
186
+ */
187
+ const enablePaperNearEndSensor = () => [exports.GS, 0xF9, 0x2C, 0x01];
188
+ exports.enablePaperNearEndSensor = enablePaperNearEndSensor;
189
+ const disablePaperNearEndSensor = () => [exports.GS, 0xF9, 0x2C, 0x00];
190
+ exports.disablePaperNearEndSensor = disablePaperNearEndSensor;
191
+ /**
192
+ * ESC b n - Select paper sensor to output paper-end signal
193
+ * n = 0 or 48: PE reflects paper sensor (default)
194
+ * n = 1 or 49: PE reflects drawer sensor
195
+ */
196
+ const selectPaperSensor = () => [exports.ESC, 0x62, 0x00];
197
+ exports.selectPaperSensor = selectPaperSensor;
198
+ const selectDrawerSensor = () => [exports.ESC, 0x62, 0x01];
199
+ exports.selectDrawerSensor = selectDrawerSensor;
200
+ // ============================================================================
201
+ // PRINTER QUALITY & MODE
202
+ // ============================================================================
203
+ /**
204
+ * Printer quality modes
205
+ */
206
+ var PrinterMode;
207
+ (function (PrinterMode) {
208
+ PrinterMode[PrinterMode["NORMAL"] = 0] = "NORMAL";
209
+ PrinterMode[PrinterMode["HIGH_QUALITY"] = 1] = "HIGH_QUALITY";
210
+ PrinterMode[PrinterMode["HIGH_SPEED"] = 2] = "HIGH_SPEED"; // High speed mode
211
+ })(PrinterMode || (exports.PrinterMode = PrinterMode = {}));
212
+ /**
213
+ * GS F9h - n - Set and save printer mode
214
+ * Sets printing priority to high quality or high speed
215
+ */
216
+ const setPrinterMode = (mode) => [exports.GS, 0xF9, 0x2D, mode];
217
+ exports.setPrinterMode = setPrinterMode;
218
+ /**
219
+ * ESC N n - Select printing intensity (OBSOLETE)
220
+ * Kept for compatibility with earlier Bematech products
221
+ * Command is ignored by MP-4200 TH
222
+ */
223
+ const setPrintingIntensity = (n) => [exports.ESC, 0x4E, Math.max(0, Math.min(4, n))];
224
+ exports.setPrintingIntensity = setPrintingIntensity;
225
+ /**
226
+ * GS F9h + n - Set and save printing intensity (OBSOLETE)
227
+ * Kept for compatibility with earlier Bematech products
228
+ * Command is ignored by MP-4200 TH
229
+ */
230
+ const setPrintingIntensityAlt = (n) => [exports.GS, 0xF9, 0x2B, n];
231
+ exports.setPrintingIntensityAlt = setPrintingIntensityAlt;
232
+ // ============================================================================
233
+ // PRINTER LANGUAGE
234
+ // ============================================================================
235
+ /**
236
+ * GS FAh n - Set and save printer language
237
+ * n = 0 or 48: English
238
+ * n = 1 or 49: Portuguese
239
+ * n = 2 or 50: Spanish
240
+ * n = 3 or 51: German
241
+ */
242
+ var PrinterLanguage;
243
+ (function (PrinterLanguage) {
244
+ PrinterLanguage[PrinterLanguage["ENGLISH"] = 0] = "ENGLISH";
245
+ PrinterLanguage[PrinterLanguage["PORTUGUESE"] = 1] = "PORTUGUESE";
246
+ PrinterLanguage[PrinterLanguage["SPANISH"] = 2] = "SPANISH";
247
+ PrinterLanguage[PrinterLanguage["GERMAN"] = 3] = "GERMAN";
248
+ })(PrinterLanguage || (exports.PrinterLanguage = PrinterLanguage = {}));
249
+ const setPrinterLanguage = (lang) => [exports.GS, 0xFA, lang];
250
+ exports.setPrinterLanguage = setPrinterLanguage;
251
+ // ============================================================================
252
+ // PRINTER INFORMATION & CONFIGURATION
253
+ // ============================================================================
254
+ /**
255
+ * GS F9h ' n - Get printer information
256
+ * Returns different information based on n value:
257
+ * n = 0 or 48: Product code (10 bytes)
258
+ * n = 1 or 49: Serial number (20 bytes)
259
+ * n = 2 or 50: Manufacturing date (4 bytes)
260
+ * n = 3 or 51: Firmware version (3 bytes)
261
+ * n = 5 or 53: Manufacturing timestamp (17 bytes, "dd/mm/yy hh:mm:ss")
262
+ * n = 8 or 56: Interface type (1 byte: 0=None, 1=Serial DB-9, 2=Serial DB-25, 3=Ethernet, -1=Unknown)
263
+ */
264
+ const getPrinterInfo = (infoType) => [exports.GS, 0xF9, 0x27, infoType];
265
+ exports.getPrinterInfo = getPrinterInfo;
266
+ /**
267
+ * GS F9h ( 0 - Load default user configuration
268
+ * Reloads all configurations from non-volatile memory and dipswitches
269
+ */
270
+ exports.LOAD_DEFAULT_CONFIG = [exports.GS, 0xF9, 0x28, 0x30];
271
+ /**
272
+ * GS F9h ) 0 - Print user configuration
273
+ * Prints current user configuration on paper
274
+ */
275
+ exports.PRINT_CONFIG = [exports.GS, 0xF9, 0x29, 0x30];
276
+ /**
277
+ * GS F8h F - Printer reset
278
+ * Forces a hardware reset
279
+ */
280
+ exports.RESET_PRINTER = [exports.GS, 0xF8, 0x46];
281
+ // ============================================================================
282
+ // PANEL CONTROL
283
+ // ============================================================================
284
+ /**
285
+ * ESC y n - Enable/disable panel keys
286
+ * n = 0 or 48: Disable panel keys
287
+ * n = 1 or 49: Enable panel keys (default)
288
+ */
289
+ const enablePanelKeys = () => [exports.ESC, 0x79, 0x01];
290
+ exports.enablePanelKeys = enablePanelKeys;
291
+ const disablePanelKeys = () => [exports.ESC, 0x79, 0x00];
292
+ exports.disablePanelKeys = disablePanelKeys;
293
+ /**
294
+ * ESC x - Enable dump mode
295
+ * Prints data in hexadecimal for debugging
296
+ * WARNING: Only way to exit dump mode is to turn off printer
297
+ */
298
+ exports.ENABLE_DUMP_MODE = [exports.ESC, 0x78];
299
+ // ============================================================================
300
+ // DRAWER CONTROL
301
+ // ============================================================================
302
+ /**
303
+ * ESC v n - Activate drawer #1 for n milliseconds
304
+ * Range: 50 ≤ n ≤ 250 (actual: 50ms ≤ n ≤ 200ms)
305
+ */
306
+ const activateDrawer1 = (milliseconds) => {
307
+ const n = Math.max(50, Math.min(250, milliseconds));
308
+ return [exports.ESC, 0x76, n];
309
+ };
310
+ exports.activateDrawer1 = activateDrawer1;
311
+ /**
312
+ * ESC 80h n - Activate drawer #2 for n milliseconds
313
+ * Range: 50 ≤ n ≤ 250 (actual: 50ms ≤ n ≤ 200ms)
314
+ */
315
+ const activateDrawer2 = (milliseconds) => {
316
+ const n = Math.max(50, Math.min(250, milliseconds));
317
+ return [exports.ESC, 0x80, n];
318
+ };
319
+ exports.activateDrawer2 = activateDrawer2;
320
+ // ============================================================================
321
+ // PAPER CUTTING
322
+ // ============================================================================
323
+ /**
324
+ * ESC i - Perform full paper cut
325
+ * Hexadecimal: 1B 69
326
+ */
327
+ exports.CUT_FULL = [exports.ESC, 0x69];
328
+ /**
329
+ * ESC w - Perform full paper cut (alternate command)
330
+ * Hexadecimal: 1B 77
331
+ */
332
+ exports.CUT_FULL_ALT = [exports.ESC, 0x77];
333
+ /**
334
+ * GS F9h D m n - Activate buzzer on cut
335
+ * m: Buzzer selection (0=none, 1=internal, 2=external)
336
+ * n: Activation time (n × 100ms)
337
+ * Default: m=0, n=200
338
+ */
339
+ const setBuzzerOnCut = (buzzer, time) => {
340
+ const n = Math.max(0, Math.min(255, time));
341
+ return [exports.GS, 0xF9, 0x44, buzzer, n];
342
+ };
343
+ exports.setBuzzerOnCut = setBuzzerOnCut;
344
+ const disableBuzzerOnCut = () => [exports.GS, 0xF9, 0x44, 0x00, 0x00];
345
+ exports.disableBuzzerOnCut = disableBuzzerOnCut;
346
+ // ============================================================================
347
+ // BUZZER CONTROL
348
+ // ============================================================================
349
+ /**
350
+ * ESC ( A pL pH fn n1 n2 vol - Activate/deactivate buzzer
351
+ * pL + pH × 256 = 4 (always: pL=4, pH=0)
352
+ * fn = 1 or 49: Activate buzzer
353
+ * fn = 0 or 48: Deactivate buzzer (deprecated)
354
+ * n = (n1 + n2 × 256): Time in milliseconds
355
+ * vol = 0, 1, 48, or 49: Volume (unused)
356
+ */
357
+ const activateBuzzer = (milliseconds) => {
358
+ const n1 = milliseconds & 0xFF;
359
+ const n2 = (milliseconds >> 8) & 0xFF;
360
+ return [exports.ESC, 0x28, 0x41, 0x04, 0x00, 0x01, n1, n2, 0x00];
361
+ };
362
+ exports.activateBuzzer = activateBuzzer;
363
+ // ============================================================================
364
+ // PAPER FEEDING
365
+ // ============================================================================
366
+ /**
367
+ * LF - Feed one line
368
+ * Prints buffer contents and feeds one line according to default line spacing
369
+ */
370
+ exports.FEED_LINE = [exports.LF];
371
+ /**
372
+ * FF - Feed one page
373
+ * Moves from current position to top of next page
374
+ * Can be disabled by setting page size to zero
375
+ */
376
+ exports.FEED_PAGE = [exports.FF];
377
+ /**
378
+ * ESC J n - Perform fine line feed
379
+ * Range: 48 ≤ n ≤ 255
380
+ * Feed: (n - 48) × 0.125mm
381
+ * Widely used for graphics printing
382
+ */
383
+ const fineFeed = (n) => {
384
+ const value = Math.max(48, Math.min(255, n));
385
+ return [exports.ESC, 0x4A, value];
386
+ };
387
+ exports.fineFeed = fineFeed;
388
+ /**
389
+ * ESC A n - Feed paper by [n × 0.375]mm
390
+ * Range: 0 ≤ n ≤ 255
391
+ * Notes: n < 17 → 0mm, n > 85 → 32mm, else n × 0.375mm
392
+ */
393
+ const feedPaper = (n) => {
394
+ const value = Math.max(0, Math.min(255, n));
395
+ return [exports.ESC, 0x41, value];
396
+ };
397
+ exports.feedPaper = feedPaper;
398
+ /**
399
+ * ESC 2 - Set text line height to 1/6 inches (default)
400
+ * Hexadecimal: 1B 32
401
+ */
402
+ exports.SET_LINE_HEIGHT_DEFAULT = [exports.ESC, 0x32];
403
+ /**
404
+ * ESC 3 n - Set line feed to n/144 inches
405
+ * Range: 18 ≤ n ≤ 255
406
+ * Takes effect immediately
407
+ */
408
+ const setLineSpacing = (n) => {
409
+ const value = Math.max(18, Math.min(255, n));
410
+ return [exports.ESC, 0x33, value];
411
+ };
412
+ exports.setLineSpacing = setLineSpacing;
413
+ /**
414
+ * ESC f 1 n - Vertical skipping
415
+ * Range: 0 ≤ n ≤ 255
416
+ * Performs vertical skipping of n characters
417
+ * Alternate: 1B 66 01 n (same effect)
418
+ */
419
+ const verticalSkip = (n) => {
420
+ const value = Math.max(0, Math.min(255, n));
421
+ return [exports.ESC, 0x66, 0x31, value];
422
+ };
423
+ exports.verticalSkip = verticalSkip;
424
+ /**
425
+ * ESC f 0 n - Horizontal skipping
426
+ * Range: 0 ≤ n ≤ 255
427
+ * Performs horizontal skipping of n characters
428
+ * Alternate: 1B 66 00 n (same effect)
429
+ */
430
+ const horizontalSkip = (n) => {
431
+ const value = Math.max(0, Math.min(255, n));
432
+ return [exports.ESC, 0x66, 0x30, value];
433
+ };
434
+ exports.horizontalSkip = horizontalSkip;
435
+ // ============================================================================
436
+ // PAGE CONFIGURATION
437
+ // ============================================================================
438
+ /**
439
+ * ESC C n - Set page size in lines
440
+ * Range: 0 < n < 256
441
+ * Default: n = 12
442
+ * n represents number of single-height lines
443
+ */
444
+ const setPageSizeLines = (lines) => {
445
+ const n = Math.max(1, Math.min(255, lines));
446
+ return [exports.ESC, 0x43, n];
447
+ };
448
+ exports.setPageSizeLines = setPageSizeLines;
449
+ /**
450
+ * ESC c n1 n2 - Set page size in millimeters
451
+ * Range: 0 ≤ n1 ≤ 255, 0 ≤ n2 ≤ 255
452
+ * Page size = 0.125mm × [n1 + (256 × n2)]
453
+ */
454
+ const setPageSizeMM = (n1, n2) => {
455
+ const v1 = Math.max(0, Math.min(255, n1));
456
+ const v2 = Math.max(0, Math.min(255, n2));
457
+ return [exports.ESC, 0x63, v1, v2];
458
+ };
459
+ exports.setPageSizeMM = setPageSizeMM;
460
+ // ============================================================================
461
+ // AUTOMATIC LINE FEED
462
+ // ============================================================================
463
+ /**
464
+ * ESC z n - Enable/disable automatic line feed
465
+ * n = 0 or 48: Disable (default)
466
+ * n = 1 or 49: Enable
467
+ * When enabled, printer performs LF after receiving CR
468
+ */
469
+ const enableAutoLineFeed = () => [exports.ESC, 0x7A, 0x01];
470
+ exports.enableAutoLineFeed = enableAutoLineFeed;
471
+ const disableAutoLineFeed = () => [exports.ESC, 0x7A, 0x00];
472
+ exports.disableAutoLineFeed = disableAutoLineFeed;
473
+ // ============================================================================
474
+ // MARGINS & TABS
475
+ // ============================================================================
476
+ /**
477
+ * ESC Q n - Set right margin
478
+ * Range: 0 ≤ n ≤ 255
479
+ * Sets right margin in number of characters from default left margin
480
+ * New margin becomes valid only on next line if on right side of current position
481
+ */
482
+ const setRightMargin = (chars) => {
483
+ const n = Math.max(0, Math.min(255, chars));
484
+ return [exports.ESC, 0x51, n];
485
+ };
486
+ exports.setRightMargin = setRightMargin;
487
+ /**
488
+ * ESC l n - Set left margin
489
+ * Range: 0 ≤ n ≤ 255
490
+ * Sets left margin in number of characters from default left margin
491
+ * New margin becomes valid only on next line if on left side of current position
492
+ */
493
+ const setLeftMargin = (chars) => {
494
+ const n = Math.max(0, Math.min(255, chars));
495
+ return [exports.ESC, 0x6C, n];
496
+ };
497
+ exports.setLeftMargin = setLeftMargin;
498
+ /**
499
+ * HT - Horizontal tab
500
+ * Moves print position to next tab mark
501
+ * Default: tabs at every 8 character columns (9, 17, 25, ...)
502
+ */
503
+ exports.TAB = [exports.HT];
504
+ /**
505
+ * ESC D n1 ... nk NUL - Set horizontal tab marks
506
+ * Range: 1 ≤ n ≤ 255, 0 ≤ k ≤ 32
507
+ * Default: intervals of 8 characters for font 12x24
508
+ *
509
+ * Example: setTabPositions([8, 16, 24]) sets tabs at columns 9, 17, 25
510
+ * Must be in ascending order and terminated with NUL
511
+ */
512
+ const setTabPositions = (positions) => {
513
+ const validPositions = positions
514
+ .filter(p => p >= 1 && p <= 255)
515
+ .slice(0, 32)
516
+ .sort((a, b) => a - b);
517
+ return [exports.ESC, 0x44, ...validPositions, exports.NUL];
518
+ };
519
+ exports.setTabPositions = setTabPositions;
520
+ /**
521
+ * ESC D NUL - Cancel all horizontal tab marks
522
+ */
523
+ exports.CLEAR_TABS = [exports.ESC, 0x44, exports.NUL];
524
+ // ============================================================================
525
+ // TEXT ALIGNMENT
526
+ // ============================================================================
527
+ /**
528
+ * ESC a n - Character alignment
529
+ * n = 0 or 48: Left justified (default)
530
+ * n = 1 or 49: Center justified
531
+ * n = 2 or 50: Right justified
532
+ */
533
+ exports.ALIGN_LEFT = [exports.ESC, 0x61, 0x00];
534
+ exports.ALIGN_CENTER = [exports.ESC, 0x61, 0x01];
535
+ exports.ALIGN_RIGHT = [exports.ESC, 0x61, 0x02];
536
+ // ============================================================================
537
+ // TEXT FORMATTING - BOLD/EMPHASIZED
538
+ // ============================================================================
539
+ /**
540
+ * ESC E - Enable emphasized print mode (bold)
541
+ * Hexadecimal: 1B 45
542
+ * Emphasized mode is bolder than normal print
543
+ */
544
+ exports.BOLD_ON = [exports.ESC, 0x45];
545
+ /**
546
+ * ESC F - Disable emphasized print mode (bold)
547
+ * Hexadecimal: 1B 46
548
+ */
549
+ exports.BOLD_OFF = [exports.ESC, 0x46];
550
+ // ============================================================================
551
+ // TEXT FORMATTING - UNDERLINE
552
+ // ============================================================================
553
+ /**
554
+ * ESC - n - Enable/disable underline print mode
555
+ * n = 0 or 48: Disable (default)
556
+ * n = 1 or 49: Enable
557
+ * Underlines every character and space
558
+ */
559
+ exports.UNDERLINE_ON = [exports.ESC, 0x2D, 0x01];
560
+ exports.UNDERLINE_OFF = [exports.ESC, 0x2D, 0x00];
561
+ // ============================================================================
562
+ // TEXT FORMATTING - ITALIC
563
+ // ============================================================================
564
+ /**
565
+ * ESC 4 - Enable italic print mode
566
+ * Hexadecimal: 1B 34
567
+ * Available in all other print modes
568
+ */
569
+ exports.ITALIC_ON = [exports.ESC, 0x34];
570
+ /**
571
+ * ESC 5 - Disable italic print mode
572
+ * Hexadecimal: 1B 35
573
+ */
574
+ exports.ITALIC_OFF = [exports.ESC, 0x35];
575
+ // ============================================================================
576
+ // TEXT FORMATTING - UPSIDE DOWN
577
+ // ============================================================================
578
+ /**
579
+ * ESC } n - Turn upside-down printing mode on/off
580
+ * n = 0 or 48: Disable (default)
581
+ * n = 1 or 49: Enable
582
+ */
583
+ exports.UPSIDE_DOWN_ON = [exports.ESC, 0x7D, 0x01];
584
+ exports.UPSIDE_DOWN_OFF = [exports.ESC, 0x7D, 0x00];
585
+ // ============================================================================
586
+ // TEXT FORMATTING - SUPERSCRIPT/SUBSCRIPT
587
+ // ============================================================================
588
+ /**
589
+ * ESC S n - Enable superscript or subscript print mode
590
+ * n = 0 or 48: Superscript (print on upper side of line)
591
+ * n = 1 or 49: Subscript (print on bottom side of line)
592
+ */
593
+ exports.SUPERSCRIPT_ON = [exports.ESC, 0x53, 0x00];
594
+ exports.SUBSCRIPT_ON = [exports.ESC, 0x53, 0x01];
595
+ /**
596
+ * ESC T - Disable superscript and subscript print modes
597
+ * Hexadecimal: 1B 54
598
+ */
599
+ exports.SCRIPT_OFF = [exports.ESC, 0x54];
600
+ // ============================================================================
601
+ // TEXT FORMATTING - COMBINED MODE (ESC !)
602
+ // ============================================================================
603
+ /**
604
+ * ESC ! n - Select print mode (combined control)
605
+ * Bits:
606
+ * 0: Font selection (0=Font A, 1=Font B) - Not documented but works
607
+ * 1-2: Undefined
608
+ * 3: Emphasized (0=clear, 1=set)
609
+ * 4: Double height (0=clear, 1=set)
610
+ * 5: Double width (0=clear, 1=set)
611
+ * 6: Undefined
612
+ * 7: Underline (0=clear, 1=set)
613
+ */
614
+ const calculatePrintMode = (options) => {
615
+ // Use Font B (narrower, 9×17 dots) for consistency with ESC/POS
616
+ // Font B fits more characters per line (better for 48-char receipts)
617
+ let n = 0x01; // Bit 0 - Font B
618
+ if (options.emphasized)
619
+ n |= 0x08; // Bit 3
620
+ if (options.doubleHeight)
621
+ n |= 0x10; // Bit 4
622
+ if (options.doubleWidth)
623
+ n |= 0x20; // Bit 5
624
+ if (options.underline)
625
+ n |= 0x80; // Bit 7
626
+ return [exports.ESC, 0x21, n];
627
+ };
628
+ exports.calculatePrintMode = calculatePrintMode;
629
+ // ============================================================================
630
+ // CHARACTER SIZING - DOUBLE HEIGHT
631
+ // ============================================================================
632
+ /**
633
+ * ESC d n - Enable/disable double height print mode
634
+ * n = 0 or 48: Disable (default)
635
+ * n = 1 or 49: Enable
636
+ *
637
+ * IMPORTANT: This is different from ESC/POS where ESC d is used for line feed
638
+ */
639
+ exports.DOUBLE_HEIGHT_ON = [exports.ESC, 0x64, 0x01];
640
+ exports.DOUBLE_HEIGHT_OFF = [exports.ESC, 0x64, 0x00];
641
+ /**
642
+ * ESC V - Enable on-line double height mode
643
+ * If received at beginning of line: valid for whole line
644
+ * Otherwise: valid only for next incoming characters
645
+ * Returns to normal mode on next line
646
+ */
647
+ exports.DOUBLE_HEIGHT_ONLINE = [exports.ESC, 0x56];
648
+ // ============================================================================
649
+ // CHARACTER SIZING - DOUBLE WIDTH (EXPANDED)
650
+ // ============================================================================
651
+ /**
652
+ * ESC W n - Enable/disable expanded mode (double width)
653
+ * n = 0 or 48: Disable (default)
654
+ * n = 1 or 49: Enable
655
+ * Takes effect immediately
656
+ */
657
+ exports.DOUBLE_WIDTH_ON = [exports.ESC, 0x57, 0x01];
658
+ exports.DOUBLE_WIDTH_OFF = [exports.ESC, 0x57, 0x00];
659
+ /**
660
+ * ESC SO - Enable on-line expanded mode
661
+ * Hexadecimal: 1B 0E
662
+ * If received at beginning of line: valid for whole line
663
+ * Otherwise: valid only for next incoming characters
664
+ * Returns to normal mode on next line
665
+ */
666
+ exports.EXPANDED_ONLINE = [exports.ESC, exports.SO];
667
+ /**
668
+ * SO - Enable on-line expanded mode (alternate)
669
+ * Hexadecimal: 0E
670
+ * Same as ESC SO
671
+ */
672
+ exports.EXPANDED_ONLINE_ALT = [exports.SO];
673
+ /**
674
+ * DC4 - Disable on-line expanded print
675
+ * Hexadecimal: 14
676
+ * Disables expanded mode if previously set by ESC SO or SO
677
+ */
678
+ exports.EXPANDED_OFF = [exports.DC4];
679
+ // ============================================================================
680
+ // CHARACTER SIZING - CONDENSED
681
+ // ============================================================================
682
+ /**
683
+ * ESC SI - Enable condensed mode
684
+ * Hexadecimal: 1B 0F
685
+ */
686
+ exports.CONDENSED_ON = [exports.ESC, exports.SI];
687
+ /**
688
+ * SI - Enable condensed mode (alternate)
689
+ * Hexadecimal: 0F
690
+ * Same as ESC SI
691
+ */
692
+ exports.CONDENSED_ON_ALT = [exports.SI];
693
+ /**
694
+ * ESC H - Disable condensed mode
695
+ * Hexadecimal: 1B 48
696
+ * Same as DC2 or ESC P
697
+ */
698
+ exports.CONDENSED_OFF = [exports.ESC, 0x48];
699
+ /**
700
+ * ESC P - Disable condensed mode (alternate)
701
+ * Hexadecimal: 1B 50
702
+ * Same as DC2 or ESC H
703
+ */
704
+ exports.CONDENSED_OFF_ALT = [exports.ESC, 0x50];
705
+ /**
706
+ * DC2 - Disable condensed mode (alternate)
707
+ * Hexadecimal: 12
708
+ * Same as ESC H or ESC P
709
+ */
710
+ exports.CONDENSED_OFF_DC2 = [exports.DC2];
711
+ // ============================================================================
712
+ // GRAPHICS - BIT IMAGES
713
+ // ============================================================================
714
+ /**
715
+ * ESC $ n1 n2 - Fill in blank bit columns
716
+ * Fills blank bit columns from current column to column (n1 + n2 × 256)
717
+ * Must be ≤ printing width N
718
+ */
719
+ const fillBlankColumns = (columns) => {
720
+ const n1 = columns & 0xFF;
721
+ const n2 = (columns >> 8) & 0xFF;
722
+ return [exports.ESC, 0x24, n1, n2];
723
+ };
724
+ exports.fillBlankColumns = fillBlankColumns;
725
+ /**
726
+ * ESC * ! n1 n2 b1 ... bn - 24-bit graphics
727
+ * Hexadecimal: 1B 2A 21 n1 n2 b1 ... bn
728
+ * Downloads 24-bit image with (n1 + n2 × 256) columns
729
+ * Each column = 3 bytes (24 bits height)
730
+ * Total bytes needed = columns × 3
731
+ */
732
+ const print24BitGraphics = (columns, data) => {
733
+ const n1 = columns & 0xFF;
734
+ const n2 = (columns >> 8) & 0xFF;
735
+ return [exports.ESC, 0x2A, 0x21, n1, n2, ...data];
736
+ };
737
+ exports.print24BitGraphics = print24BitGraphics;
738
+ /**
739
+ * ESC K n1 n2 b1 ... bn - 8-bit graphics
740
+ * Hexadecimal: 1B 4B n1 n2 b1 ... bn
741
+ * Select "8 pin" bit image (compatible with dot-matrix printers)
742
+ * Columns = n1 + (n2 × 256), each column = 1 byte
743
+ * Low resolution (expanded to 3 bytes internally)
744
+ */
745
+ const print8BitGraphics = (columns, data) => {
746
+ const n1 = columns & 0xFF;
747
+ const n2 = (columns >> 8) & 0xFF;
748
+ return [exports.ESC, 0x4B, n1, n2, ...data];
749
+ };
750
+ exports.print8BitGraphics = print8BitGraphics;
751
+ // ============================================================================
752
+ // GRAPHICS - RASTER BITMAP
753
+ // ============================================================================
754
+ /**
755
+ * Raster bitmap print modes
756
+ */
757
+ var RasterMode;
758
+ (function (RasterMode) {
759
+ RasterMode[RasterMode["NORMAL"] = 0] = "NORMAL";
760
+ RasterMode[RasterMode["DOUBLE_WIDTH"] = 1] = "DOUBLE_WIDTH";
761
+ RasterMode[RasterMode["DOUBLE_HEIGHT"] = 2] = "DOUBLE_HEIGHT";
762
+ RasterMode[RasterMode["QUADRUPLE"] = 3] = "QUADRUPLE"; // 101 dpi × 101 dpi
763
+ })(RasterMode || (exports.RasterMode = RasterMode = {}));
764
+ /**
765
+ * GS v 0 m xL xH yL yH d1 ... dk - Print raster bitmap
766
+ * m: Mode (0-3 or 48-51)
767
+ * xL, xH: Horizontal bytes = xL + xH × 256
768
+ * yL, yH: Vertical bytes = yL + yH × 256
769
+ * k = (xL + xH × 256) × (yL + yH × 256)
770
+ *
771
+ * Data outside printing area is discarded
772
+ * Affected by HT, ESC $, ESC \, GS L, and ESC a
773
+ */
774
+ const printRasterBitmap = (mode, width, height, data) => {
775
+ const xL = width & 0xFF;
776
+ const xH = (width >> 8) & 0xFF;
777
+ const yL = height & 0xFF;
778
+ const yH = (height >> 8) & 0xFF;
779
+ return [exports.GS, 0x76, 0x30, mode, xL, xH, yL, yH, ...data];
780
+ };
781
+ exports.printRasterBitmap = printRasterBitmap;
782
+ // ============================================================================
783
+ // GRAPHICS - DOWNLOADED BIT IMAGE
784
+ // ============================================================================
785
+ /**
786
+ * GS * x y d1 ... d(x×y×8) - Define downloaded bit image
787
+ * Range: 1 ≤ x ≤ 255, 1 ≤ y ≤ 64
788
+ * Horizontal dots: x × 8
789
+ * Vertical dots: y × 8
790
+ *
791
+ * Cleared by: ESC @, FS q, printer restart, or power cycle
792
+ */
793
+ const defineDownloadedBitImage = (x, y, data) => {
794
+ const xVal = Math.max(1, Math.min(255, x));
795
+ const yVal = Math.max(1, Math.min(64, y));
796
+ return [exports.GS, 0x2A, xVal, yVal, ...data];
797
+ };
798
+ exports.defineDownloadedBitImage = defineDownloadedBitImage;
799
+ /**
800
+ * GS / m - Print downloaded bit image
801
+ * m: Mode (0-3 or 48-51) - same as RasterMode
802
+ * No effect if downloaded image not defined
803
+ */
804
+ const printDownloadedBitImage = (mode) => [exports.GS, 0x2F, mode];
805
+ exports.printDownloadedBitImage = printDownloadedBitImage;
806
+ // ============================================================================
807
+ // GRAPHICS - NON-VOLATILE (NV) BIT IMAGE
808
+ // ============================================================================
809
+ /**
810
+ * FS q n [xL xH yL yH d1 ... dn]1 ... [xL xH yL yH d1 ... dn]n
811
+ * Define NV bit images (stored in non-volatile memory)
812
+ *
813
+ * n: Number of NV bit images (1 ≤ n ≤ 255)
814
+ * xL, xH: Horizontal = (xL + xH × 256) × 8 dots (max 1023 × 8)
815
+ * yL, yH: Vertical = (yL + yH × 256) × 8 dots (max 288 × 8)
816
+ *
817
+ * Erases all previously defined NV images
818
+ */
819
+ const defineNVBitImage = (images) => {
820
+ const result = [exports.FS, 0x71, images.length];
821
+ for (const img of images) {
822
+ const xL = img.width & 0xFF;
823
+ const xH = (img.width >> 8) & 0xFF;
824
+ const yL = img.height & 0xFF;
825
+ const yH = (img.height >> 8) & 0xFF;
826
+ result.push(xL, xH, yL, yH, ...img.data);
827
+ }
828
+ return result;
829
+ };
830
+ exports.defineNVBitImage = defineNVBitImage;
831
+ /**
832
+ * FS p n m - Print non-volatile (NV) bit image
833
+ * n: NV bit image number (as defined by FS q)
834
+ * m: Mode (0-3 or 48-51) - same as RasterMode
835
+ * No effect if n-th NV image not defined
836
+ */
837
+ const printNVBitImage = (imageNumber, mode) => [exports.FS, 0x70, imageNumber, mode];
838
+ exports.printNVBitImage = printNVBitImage;
839
+ // ============================================================================
840
+ // BARCODES - CONFIGURATION
841
+ // ============================================================================
842
+ /**
843
+ * GS h n - Set barcode height
844
+ * Range: 1 ≤ n ≤ 255
845
+ * Default: n = 162
846
+ * Height = n × 0.125mm
847
+ */
848
+ const setBarcodeHeight = (n) => {
849
+ const height = Math.max(1, Math.min(255, n));
850
+ return [exports.GS, 0x68, height];
851
+ };
852
+ exports.setBarcodeHeight = setBarcodeHeight;
853
+ /**
854
+ * GS w n - Set barcode width
855
+ * Range: 2 ≤ n ≤ 4
856
+ * Default: n = 3
857
+ * n = 2: Normal width
858
+ * n = 3: Double width
859
+ * n = 4: Quadruple width
860
+ */
861
+ const setBarcodeWidth = (width) => [exports.GS, 0x77, width];
862
+ exports.setBarcodeWidth = setBarcodeWidth;
863
+ /**
864
+ * Human Readable Information (HRI) position
865
+ */
866
+ var BarcodeHRIPosition;
867
+ (function (BarcodeHRIPosition) {
868
+ BarcodeHRIPosition[BarcodeHRIPosition["NONE"] = 0] = "NONE";
869
+ BarcodeHRIPosition[BarcodeHRIPosition["TOP"] = 1] = "TOP";
870
+ BarcodeHRIPosition[BarcodeHRIPosition["BOTTOM"] = 2] = "BOTTOM";
871
+ BarcodeHRIPosition[BarcodeHRIPosition["BOTH"] = 3] = "BOTH"; // HRI on both top and bottom
872
+ })(BarcodeHRIPosition || (exports.BarcodeHRIPosition = BarcodeHRIPosition = {}));
873
+ /**
874
+ * GS H n - Choose HRI position in barcode
875
+ * Range: 0 ≤ n ≤ 3
876
+ * Default: n = 1 (top)
877
+ */
878
+ const setBarcodeHRI = (position) => [exports.GS, 0x48, position];
879
+ exports.setBarcodeHRI = setBarcodeHRI;
880
+ /**
881
+ * GS f n - Set HRI font
882
+ * n = 0 or 48: Normal font (default)
883
+ * n = 1 or 49: Condensed font
884
+ */
885
+ const setBarcodeHRIFont = (condensed) => [exports.GS, 0x66, condensed ? 0x01 : 0x00];
886
+ exports.setBarcodeHRIFont = setBarcodeHRIFont;
887
+ /**
888
+ * GS k 84h n1 n2 - Program barcode left margin
889
+ * Margin position = n1 + n2 × 256
890
+ */
891
+ const setBarcodeLeftMargin = (position) => {
892
+ const n1 = position & 0xFF;
893
+ const n2 = (position >> 8) & 0xFF;
894
+ return [exports.GS, 0x6B, 0x84, n1, n2];
895
+ };
896
+ exports.setBarcodeLeftMargin = setBarcodeLeftMargin;
897
+ // ============================================================================
898
+ // BARCODES - UPC-A
899
+ // ============================================================================
900
+ /**
901
+ * GS k NUL d1 ... d11 NUL - Print UPC-A barcode
902
+ * Range: 48 ≤ dn ≤ 57 (ASCII digits '0'-'9')
903
+ * Requires exactly 11 digits, checksum generated automatically
904
+ */
905
+ const printBarcodeUPCA = (data) => {
906
+ if (data.length !== 11 || !/^\d{11}$/.test(data)) {
907
+ throw new Error('UPC-A requires exactly 11 digits');
908
+ }
909
+ const bytes = data.split('').map(c => c.charCodeAt(0));
910
+ return [exports.GS, 0x6B, exports.NUL, ...bytes, exports.NUL];
911
+ };
912
+ exports.printBarcodeUPCA = printBarcodeUPCA;
913
+ /**
914
+ * GS k A VT d1 ... d11 - Print UPC-A barcode (alternate)
915
+ * Same as GS k NUL variant
916
+ */
917
+ const printBarcodeUPCAAlt = (data) => {
918
+ if (data.length !== 11 || !/^\d{11}$/.test(data)) {
919
+ throw new Error('UPC-A requires exactly 11 digits');
920
+ }
921
+ const bytes = data.split('').map(c => c.charCodeAt(0));
922
+ return [exports.GS, 0x6B, 0x41, 0x0B, ...bytes];
923
+ };
924
+ exports.printBarcodeUPCAAlt = printBarcodeUPCAAlt;
925
+ // ============================================================================
926
+ // BARCODES - UPC-E
927
+ // ============================================================================
928
+ /**
929
+ * GS k SOH d1 ... d6 NUL - Print UPC-E barcode
930
+ * Range: 48 ≤ dn ≤ 57 (ASCII digits '0'-'9')
931
+ * Requires exactly 6 digits, checksum generated automatically
932
+ */
933
+ const printBarcodeUPCE = (data) => {
934
+ if (data.length !== 6 || !/^\d{6}$/.test(data)) {
935
+ throw new Error('UPC-E requires exactly 6 digits');
936
+ }
937
+ const bytes = data.split('').map(c => c.charCodeAt(0));
938
+ return [exports.GS, 0x6B, exports.SOH, ...bytes, exports.NUL];
939
+ };
940
+ exports.printBarcodeUPCE = printBarcodeUPCE;
941
+ /**
942
+ * GS k B ACK d1 ... d6 - Print UPC-E barcode (alternate)
943
+ */
944
+ const printBarcodeUPCEAlt = (data) => {
945
+ if (data.length !== 6 || !/^\d{6}$/.test(data)) {
946
+ throw new Error('UPC-E requires exactly 6 digits');
947
+ }
948
+ const bytes = data.split('').map(c => c.charCodeAt(0));
949
+ return [exports.GS, 0x6B, 0x42, 0x06, ...bytes];
950
+ };
951
+ exports.printBarcodeUPCEAlt = printBarcodeUPCEAlt;
952
+ // ============================================================================
953
+ // BARCODES - EAN-13
954
+ // ============================================================================
955
+ /**
956
+ * GS k STX d1 ... d12 NUL - Print EAN-13 barcode
957
+ * Range: 48 ≤ dn ≤ 57 (ASCII digits '0'-'9')
958
+ * Requires exactly 12 digits, 13th digit generated automatically
959
+ */
960
+ const printBarcodeEAN13 = (data) => {
961
+ if (data.length !== 12 || !/^\d{12}$/.test(data)) {
962
+ throw new Error('EAN-13 requires exactly 12 digits');
963
+ }
964
+ const bytes = data.split('').map(c => c.charCodeAt(0));
965
+ return [exports.GS, 0x6B, exports.STX, ...bytes, exports.NUL];
966
+ };
967
+ exports.printBarcodeEAN13 = printBarcodeEAN13;
968
+ /**
969
+ * GS k C FF d1 ... d12 - Print EAN-13 barcode (alternate)
970
+ */
971
+ const printBarcodeEAN13Alt = (data) => {
972
+ if (data.length !== 12 || !/^\d{12}$/.test(data)) {
973
+ throw new Error('EAN-13 requires exactly 12 digits');
974
+ }
975
+ const bytes = data.split('').map(c => c.charCodeAt(0));
976
+ return [exports.GS, 0x6B, 0x43, 0x0C, ...bytes];
977
+ };
978
+ exports.printBarcodeEAN13Alt = printBarcodeEAN13Alt;
979
+ // ============================================================================
980
+ // BARCODES - EAN-8
981
+ // ============================================================================
982
+ /**
983
+ * GS k ETX d1 ... d7 NUL - Print EAN-8 barcode
984
+ * Range: 48 ≤ dn ≤ 57 (ASCII digits '0'-'9')
985
+ * Requires exactly 7 digits, 8th digit generated automatically
986
+ */
987
+ const printBarcodeEAN8 = (data) => {
988
+ if (data.length !== 7 || !/^\d{7}$/.test(data)) {
989
+ throw new Error('EAN-8 requires exactly 7 digits');
990
+ }
991
+ const bytes = data.split('').map(c => c.charCodeAt(0));
992
+ return [exports.GS, 0x6B, exports.ETX, ...bytes, exports.NUL];
993
+ };
994
+ exports.printBarcodeEAN8 = printBarcodeEAN8;
995
+ /**
996
+ * GS k D BEL d1 ... d7 - Print EAN-8 barcode (alternate)
997
+ */
998
+ const printBarcodeEAN8Alt = (data) => {
999
+ if (data.length !== 7 || !/^\d{7}$/.test(data)) {
1000
+ throw new Error('EAN-8 requires exactly 7 digits');
1001
+ }
1002
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1003
+ return [exports.GS, 0x6B, 0x44, 0x07, ...bytes];
1004
+ };
1005
+ exports.printBarcodeEAN8Alt = printBarcodeEAN8Alt;
1006
+ // ============================================================================
1007
+ // BARCODES - CODE 39
1008
+ // ============================================================================
1009
+ /**
1010
+ * GS k EOT d1 ... dn NUL - Print CODE 39 barcode
1011
+ * Valid characters: 32 (space), 36 ($), 37 (%), 42 (*), 43 (+), 45-57 (-, ., /, 0-9), 65-90 (A-Z)
1012
+ * Checksum generated automatically
1013
+ * Length limited by physical print width and barcode width setting
1014
+ */
1015
+ const printBarcodeCODE39 = (data) => {
1016
+ if (!/^[ $%*+\-./0-9A-Z]+$/.test(data)) {
1017
+ throw new Error('CODE 39 supports: space, $%*+-./, 0-9, A-Z');
1018
+ }
1019
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1020
+ return [exports.GS, 0x6B, exports.EOT, ...bytes, exports.NUL];
1021
+ };
1022
+ exports.printBarcodeCODE39 = printBarcodeCODE39;
1023
+ /**
1024
+ * GS k E n d1 ... dn - Print CODE 39 barcode (alternate)
1025
+ */
1026
+ const printBarcodeCODE39Alt = (data) => {
1027
+ if (!/^[ $%*+\-./0-9A-Z]+$/.test(data)) {
1028
+ throw new Error('CODE 39 supports: space, $%*+-./, 0-9, A-Z');
1029
+ }
1030
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1031
+ return [exports.GS, 0x6B, 0x45, bytes.length, ...bytes];
1032
+ };
1033
+ exports.printBarcodeCODE39Alt = printBarcodeCODE39Alt;
1034
+ // ============================================================================
1035
+ // BARCODES - ITF (Interleaved 2 of 5)
1036
+ // ============================================================================
1037
+ /**
1038
+ * GS k ENQ d1 ... dn NUL - Print ITF barcode
1039
+ * Range: 48 ≤ dn ≤ 57 (ASCII digits '0'-'9')
1040
+ * Length limited by physical print width and barcode width setting
1041
+ */
1042
+ const printBarcodeITF = (data) => {
1043
+ if (!/^\d+$/.test(data)) {
1044
+ throw new Error('ITF requires only digits 0-9');
1045
+ }
1046
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1047
+ return [exports.GS, 0x6B, exports.ENQ, ...bytes, exports.NUL];
1048
+ };
1049
+ exports.printBarcodeITF = printBarcodeITF;
1050
+ /**
1051
+ * GS k F n d1 ... dn - Print ITF barcode (alternate)
1052
+ */
1053
+ const printBarcodeITFAlt = (data) => {
1054
+ if (!/^\d+$/.test(data)) {
1055
+ throw new Error('ITF requires only digits 0-9');
1056
+ }
1057
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1058
+ return [exports.GS, 0x6B, 0x46, bytes.length, ...bytes];
1059
+ };
1060
+ exports.printBarcodeITFAlt = printBarcodeITFAlt;
1061
+ // ============================================================================
1062
+ // BARCODES - CODABAR
1063
+ // ============================================================================
1064
+ /**
1065
+ * GS k ACK d1 ... dn NUL - Print CODABAR barcode
1066
+ * Valid: 36 ($), 43 (+), 45-57 (-, ., /, 0-9), 65-68 (A-D uppercase), 97-100 (a-d lowercase)
1067
+ * Cannot mix uppercase and lowercase letters
1068
+ * If d1 is letter, dn must also be letter
1069
+ */
1070
+ const printBarcodeCODABAR = (data) => {
1071
+ if (!/^[$+\-./0-9A-D]+$/.test(data) && !/^[$+\-./0-9a-d]+$/.test(data)) {
1072
+ throw new Error('CODABAR supports: $+-./, 0-9, A-D (or a-d, not mixed)');
1073
+ }
1074
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1075
+ return [exports.GS, 0x6B, exports.ACK, ...bytes, exports.NUL];
1076
+ };
1077
+ exports.printBarcodeCODABAR = printBarcodeCODABAR;
1078
+ /**
1079
+ * GS k G n d1 ... dn - Print CODABAR barcode (alternate)
1080
+ */
1081
+ const printBarcodeCODABARAlt = (data) => {
1082
+ if (!/^[$+\-./0-9A-D]+$/.test(data) && !/^[$+\-./0-9a-d]+$/.test(data)) {
1083
+ throw new Error('CODABAR supports: $+-./, 0-9, A-D (or a-d, not mixed)');
1084
+ }
1085
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1086
+ return [exports.GS, 0x6B, 0x47, bytes.length, ...bytes];
1087
+ };
1088
+ exports.printBarcodeCODABARAlt = printBarcodeCODABARAlt;
1089
+ // ============================================================================
1090
+ // BARCODES - CODE 93
1091
+ // ============================================================================
1092
+ /**
1093
+ * GS k H n d1 ... dn - Print CODE 93 barcode
1094
+ * Range: 0 ≤ dn ≤ 127 (all ASCII characters)
1095
+ * Checksum generated automatically
1096
+ */
1097
+ const printBarcodeCODE93 = (data) => {
1098
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1099
+ if (bytes.some(b => b > 127)) {
1100
+ throw new Error('CODE 93 supports ASCII 0-127');
1101
+ }
1102
+ return [exports.GS, 0x6B, 0x48, bytes.length, ...bytes];
1103
+ };
1104
+ exports.printBarcodeCODE93 = printBarcodeCODE93;
1105
+ // ============================================================================
1106
+ // BARCODES - CODE 128
1107
+ // ============================================================================
1108
+ /**
1109
+ * GS k I n d1 ... dn - Print CODE 128 barcode
1110
+ * Range: 0 ≤ dn ≤ 127 (all ASCII characters)
1111
+ * Checksum generated automatically
1112
+ */
1113
+ const printBarcodeCODE128 = (data) => {
1114
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1115
+ if (bytes.some(b => b > 127)) {
1116
+ throw new Error('CODE 128 supports ASCII 0-127');
1117
+ }
1118
+ return [exports.GS, 0x6B, 0x49, bytes.length, ...bytes];
1119
+ };
1120
+ exports.printBarcodeCODE128 = printBarcodeCODE128;
1121
+ // ============================================================================
1122
+ // BARCODES - PDF-417
1123
+ // ============================================================================
1124
+ /**
1125
+ * GS k 80h n1 n2 n3 n4 n5 n6 d1 ... dn - Print PDF-417 barcode
1126
+ * n1: ECC level (0-8)
1127
+ * n2: Pitch height (n2 × 0.125mm)
1128
+ * n3: Pitch width (n3 × 0.125mm, range 1-4)
1129
+ * n4: Codewords per row (0 = max for pitch width)
1130
+ * n5, n6: Byte count (n5 + n6 × 256, must be < 900)
1131
+ */
1132
+ const printBarcodePDF417 = (eccLevel, pitchHeight, pitchWidth, codewordsPerRow, data) => {
1133
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1134
+ const totalBytes = bytes.length;
1135
+ if (totalBytes >= 900) {
1136
+ throw new Error('PDF-417 data must be less than 900 bytes');
1137
+ }
1138
+ const n1 = Math.max(0, Math.min(8, eccLevel));
1139
+ const n2 = Math.max(1, Math.min(8, pitchHeight));
1140
+ const n3 = Math.max(1, Math.min(4, pitchWidth));
1141
+ const n4 = Math.max(0, Math.min(255, codewordsPerRow));
1142
+ const n5 = totalBytes & 0xFF;
1143
+ const n6 = (totalBytes >> 8) & 0xFF;
1144
+ return [exports.GS, 0x6B, 0x80, n1, n2, n3, n4, n5, n6, ...bytes];
1145
+ };
1146
+ exports.printBarcodePDF417 = printBarcodePDF417;
1147
+ // ============================================================================
1148
+ // BARCODES - ISBN
1149
+ // ============================================================================
1150
+ /**
1151
+ * GS k NAK d1 ... d9 NUL - Print ISBN barcode
1152
+ * Format: X-XXXXX-XXX-X [XXXXX] (hyphens optional in data)
1153
+ * Last char before space: 'X' (88) or digit
1154
+ * After hyphen+X/digit: optional space + 5 more digits
1155
+ */
1156
+ const printBarcodeISBN = (data) => {
1157
+ // Remove hyphens for validation
1158
+ const clean = data.replace(/-/g, '');
1159
+ if (!/^[\dX][\d ]+$/.test(clean)) {
1160
+ throw new Error('ISBN format: digits, optional X, optional space + 5 digits');
1161
+ }
1162
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1163
+ return [exports.GS, 0x6B, exports.NAK, ...bytes, exports.NUL];
1164
+ };
1165
+ exports.printBarcodeISBN = printBarcodeISBN;
1166
+ // ============================================================================
1167
+ // BARCODES - MSI
1168
+ // ============================================================================
1169
+ /**
1170
+ * GS k SYN d1 ... dn NUL - Print MSI barcode
1171
+ * Range: 48 ≤ dn ≤ 57 (ASCII digits '0'-'9')
1172
+ * Checksum generated automatically
1173
+ */
1174
+ const printBarcodeMSI = (data) => {
1175
+ if (!/^\d+$/.test(data)) {
1176
+ throw new Error('MSI requires only digits 0-9');
1177
+ }
1178
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1179
+ return [exports.GS, 0x6B, exports.SYN, ...bytes, exports.NUL];
1180
+ };
1181
+ exports.printBarcodeMSI = printBarcodeMSI;
1182
+ /**
1183
+ * GS k 82h n d1 ... dn - Print MSI barcode (alternate)
1184
+ */
1185
+ const printBarcodeMSIAlt = (data) => {
1186
+ if (!/^\d+$/.test(data)) {
1187
+ throw new Error('MSI requires only digits 0-9');
1188
+ }
1189
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1190
+ return [exports.GS, 0x6B, 0x82, bytes.length, ...bytes];
1191
+ };
1192
+ exports.printBarcodeMSIAlt = printBarcodeMSIAlt;
1193
+ // ============================================================================
1194
+ // BARCODES - PLESSEY
1195
+ // ============================================================================
1196
+ /**
1197
+ * GS k ETB d1 ... dn NUL - Print PLESSEY barcode
1198
+ * Valid: 48-57 (0-9), 65-70 (A-F uppercase), 97-102 (a-f lowercase)
1199
+ * Cannot mix uppercase and lowercase letters
1200
+ * Checksum generated automatically
1201
+ */
1202
+ const printBarcodePLESSEY = (data) => {
1203
+ if (!/^[0-9A-F]+$/.test(data) && !/^[0-9a-f]+$/.test(data)) {
1204
+ throw new Error('PLESSEY supports: 0-9, A-F (or a-f, not mixed)');
1205
+ }
1206
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1207
+ return [exports.GS, 0x6B, exports.ETB, ...bytes, exports.NUL];
1208
+ };
1209
+ exports.printBarcodePLESSEY = printBarcodePLESSEY;
1210
+ /**
1211
+ * GS k 83h n d1 ... dn - Print PLESSEY barcode (alternate)
1212
+ */
1213
+ const printBarcodePLESSEYAlt = (data) => {
1214
+ if (!/^[0-9A-F]+$/.test(data) && !/^[0-9a-f]+$/.test(data)) {
1215
+ throw new Error('PLESSEY supports: 0-9, A-F (or a-f, not mixed)');
1216
+ }
1217
+ const bytes = data.split('').map(c => c.charCodeAt(0));
1218
+ return [exports.GS, 0x6B, 0x83, bytes.length, ...bytes];
1219
+ };
1220
+ exports.printBarcodePLESSEYAlt = printBarcodePLESSEYAlt;
1221
+ // ============================================================================
1222
+ // STATUS QUERIES
1223
+ // ============================================================================
1224
+ /**
1225
+ * ENQ - Printer status enquiry
1226
+ * Returns 1 byte with status bits:
1227
+ * Bit 0: 0=offline, 1=online
1228
+ * Bit 1: 0=paper present, 1=paper out
1229
+ * Bit 2: Drawer/paper status (depends on ESC b setting)
1230
+ * Bit 3: 0=print head raised, 1=print head down
1231
+ * Bit 4: 0=paper full, 1=paper near end
1232
+ * Bit 5: 0=command not executed, 1=command executed
1233
+ * Bits 6-7: Unused (always 0)
1234
+ */
1235
+ exports.STATUS_ENQUIRY = [exports.ENQ];
1236
+ /**
1237
+ * GS F8h 1 - Printer extended status enquiry
1238
+ * Returns 5 status bytes with detailed printer information
1239
+ */
1240
+ exports.EXTENDED_STATUS = [exports.GS, 0xF8, 0x31];
1241
+ // ============================================================================
1242
+ // BUFFER CONTROL
1243
+ // ============================================================================
1244
+ /**
1245
+ * STX - Clear buffer
1246
+ * Clears print buffer without restoring default printer conditions
1247
+ */
1248
+ exports.CLEAR_BUFFER = [exports.STX];
1249
+ /**
1250
+ * ETX - End buffer
1251
+ * Printer remains in BUSY state until print buffer becomes empty
1252
+ * DTR (RTS) remains deactivated while printing on serial interfaces
1253
+ */
1254
+ exports.END_BUFFER = [exports.ETX];
1255
+ /**
1256
+ * CAN - Cancel last line
1257
+ * Clears last line sent to printer
1258
+ * No action if data already dispatched to print head
1259
+ */
1260
+ exports.CANCEL_LINE = [exports.CAN];
1261
+ /**
1262
+ * DEL - Cancel last character
1263
+ * Clears last character sent to printer
1264
+ * No action if already dispatched to print head
1265
+ */
1266
+ exports.CANCEL_CHAR = [exports.DEL];
1267
+ // ============================================================================
1268
+ // NETWORK CONFIGURATION - IP ADDRESS
1269
+ // ============================================================================
1270
+ /**
1271
+ * GS F7h BS NUL " i1 i2 i3 i4 s1 s2 s3 s4 - Set IP address and subnet mask
1272
+ * i1-i4: IP address octets
1273
+ * s1-s4: Subnet mask octets
1274
+ *
1275
+ * Example: IP 10.10.1.2, Mask 255.255.0.0
1276
+ * Command: 1D F7 08 00 22 0A 0A 01 02 FF FF 00 00
1277
+ *
1278
+ * Valid only for ethernet or wi-fi interface
1279
+ */
1280
+ const setIPAddress = (ip, subnet) => {
1281
+ return [exports.GS, 0xF7, 0x08, 0x00, 0x22, ...ip, ...subnet];
1282
+ };
1283
+ exports.setIPAddress = setIPAddress;
1284
+ /**
1285
+ * GS F7h EOT NUL ' g1 g2 g3 g4 - Set default gateway IP address
1286
+ * g1-g4: Gateway IP address octets
1287
+ * Default: 0.0.0.0
1288
+ *
1289
+ * Example: Gateway 192.168.1.2
1290
+ * Command: 1D F7 04 00 27 C0 A8 01 02
1291
+ */
1292
+ const setGateway = (gateway) => {
1293
+ return [exports.GS, 0xF7, 0x04, 0x00, 0x27, ...gateway];
1294
+ };
1295
+ exports.setGateway = setGateway;
1296
+ // ============================================================================
1297
+ // NETWORK CONFIGURATION - DHCP
1298
+ // ============================================================================
1299
+ /**
1300
+ * GS F9h E n - Set DHCP usage
1301
+ * LSB of n: 0 = DHCP disabled (default), 1 = DHCP enabled
1302
+ * Saves to non-volatile memory
1303
+ * Valid only for ethernet or wi-fi interface
1304
+ */
1305
+ const enableDHCP = () => [exports.GS, 0xF9, 0x45, 0x01];
1306
+ exports.enableDHCP = enableDHCP;
1307
+ const disableDHCP = () => [exports.GS, 0xF9, 0x45, 0x00];
1308
+ exports.disableDHCP = disableDHCP;
1309
+ // ============================================================================
1310
+ // NETWORK CONFIGURATION - SNMP
1311
+ // ============================================================================
1312
+ /**
1313
+ * GS F9h S m ip1 ip2 ip3 ip4 n c1 ... cn - Set SNMP settings
1314
+ * m: 0 = disabled, non-zero = enabled
1315
+ * ip1-ip4: SNMP trap IP address
1316
+ * n: Community name length (0-64)
1317
+ * c1-cn: Community name bytes
1318
+ *
1319
+ * Valid only for ethernet or wi-fi interface
1320
+ */
1321
+ const setSNMP = (enabled, ip, community) => {
1322
+ const communityBytes = community.split('').map(c => c.charCodeAt(0)).slice(0, 64);
1323
+ return [exports.GS, 0xF9, 0x53, enabled ? 0x01 : 0x00, ...ip, communityBytes.length, ...communityBytes];
1324
+ };
1325
+ exports.setSNMP = setSNMP;
1326
+ // ============================================================================
1327
+ // NETWORK CONFIGURATION - WI-FI
1328
+ // ============================================================================
1329
+ /**
1330
+ * GS F9h W a s c m n e1...em p1...pn - Set Wi-Fi settings
1331
+ * a: Access mode (0=Access Point, 1=Ad-hoc)
1332
+ * s: Security mode (0=None, 1=WEP 64-bit, 2=WEP 128-bit, 3=WPA-TKIP, 4=WPA2-AES)
1333
+ * c: Channel (0-13, use 0 when a=0)
1334
+ * m: ESSID size (0-32)
1335
+ * n: Passphrase size (0-63)
1336
+ * e1-em: ESSID bytes
1337
+ * p1-pn: Passphrase bytes
1338
+ *
1339
+ * Valid only for wi-fi interface
1340
+ */
1341
+ const setWiFi = (accessMode, securityMode, channel, essid, passphrase) => {
1342
+ const essidBytes = essid.split('').map(c => c.charCodeAt(0)).slice(0, 32);
1343
+ const passphraseBytes = passphrase.split('').map(c => c.charCodeAt(0)).slice(0, 63);
1344
+ const c = Math.max(0, Math.min(13, channel));
1345
+ return [
1346
+ exports.GS, 0xF9, 0x57,
1347
+ accessMode,
1348
+ securityMode,
1349
+ c,
1350
+ essidBytes.length,
1351
+ passphraseBytes.length,
1352
+ ...essidBytes,
1353
+ ...passphraseBytes
1354
+ ];
1355
+ };
1356
+ exports.setWiFi = setWiFi;
1357
+ // ============================================================================
1358
+ // UTILITY FUNCTIONS
1359
+ // ============================================================================
1360
+ /**
1361
+ * Convert string to code page bytes
1362
+ * Uses CP860 encoding by default (Portuguese)
1363
+ */
1364
+ const encodeText = (text, codePage = CodePage.CP860) => {
1365
+ // Basic ASCII conversion - full implementation would require proper code page mapping
1366
+ return text.split('').map(c => {
1367
+ const code = c.charCodeAt(0);
1368
+ return code <= 127 ? code : 0x3F; // Replace non-ASCII with '?'
1369
+ });
1370
+ };
1371
+ exports.encodeText = encodeText;
1372
+ /**
1373
+ * Validate barcode data
1374
+ */
1375
+ const validateBarcodeData = (data, type) => {
1376
+ switch (type) {
1377
+ case 'numeric':
1378
+ return /^\d+$/.test(data);
1379
+ case 'alphanumeric':
1380
+ return /^[A-Z0-9\-. $%+/]+$/.test(data);
1381
+ case 'all':
1382
+ return data.split('').every(c => c.charCodeAt(0) <= 127);
1383
+ default:
1384
+ return false;
1385
+ }
1386
+ };
1387
+ exports.validateBarcodeData = validateBarcodeData;