From e7fee34332c61b9209468a4e8335d05cc02f32f6 Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Sat, 31 Jan 2026 14:41:04 +0100 Subject: [PATCH] ESC/P 2: 4 versions, filtering by version, selectable paper. The four versions are: - EX-1000 and 7 other early printers (including FX-80, the only Epson available OOTB for Windows 1.03), have ESC i and ESC j. - 9-pin ESC/P, a superset of EX-1000 besides ESC i and ESC j. - 24-pin ESC/P in 360 DPI instead of 240. - ESC/P 2 with raster graphics. As for paper, four sizes: Letter, A4, Legal, B4. The former ones are mainly for EX-800, the latter two are sideways and meant for EX-1000. I did some other minor changes, like converting a bunch of defines to enum. --- src/include/86box/prt_papersizes.h | 4 + src/printer/prt_escp.c | 580 ++++++++++++++++++----------- 2 files changed, 373 insertions(+), 211 deletions(-) diff --git a/src/include/86box/prt_papersizes.h b/src/include/86box/prt_papersizes.h index c45c74568..e468abb35 100644 --- a/src/include/86box/prt_papersizes.h +++ b/src/include/86box/prt_papersizes.h @@ -47,4 +47,8 @@ #define A4_PAGE_WIDTH 8.25 #define A4_PAGE_HEIGHT 11.75 +/* Standard B4 */ +#define B4_PAGE_WIDTH 9.875 +#define B4_PAGE_HEIGHT 13.875 + #endif /*EMU_PLAT_FALLTHROUGH_H*/ diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index 2a50ae54f..e87fa88db 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -72,31 +72,38 @@ #include <86box/prt_devs.h> #include <86box/prt_papersizes.h> +enum { + LANG_EX1000 = 0, // last printer with ESC i and j + LANG_9PIN, + LANG_ESCP, // also known as 24/48-pin + LANG_ESCP2 +}; + +enum { + PAPER_LETTER = 0, + PAPER_A4, + PAPER_LEGAL_SIDE, + PAPER_B4_SIDE +}; + /* Default page values (for now.) */ #define COLOR_BLACK 7 << 5 -#define PAGE_WIDTH LETTER_PAGE_WIDTH -#define PAGE_HEIGHT LETTER_PAGE_HEIGHT -#if 0 -#define PAGE_LMARGIN 0.0 -#define PAGE_RMARGIN PAGE_WIDTH -#define PAGE_TMARGIN 0.0 -#define PAGE_BMARGIN PAGE_HEIGHT -#endif -#define PAGE_DPI 360 -#define PAGE_CPI 10.0 /* standard 10 cpi */ +#define PAGE_CPI 10.0 /* standard310 cpi */ #define PAGE_LPI 6.0 /* standard 6 lpi */ /* FreeType library handles - global so they can be shared. */ FT_Library ft_lib = NULL; /* The fonts. */ -#define FONT_DEFAULT 0 -#define FONT_ROMAN 1 -#define FONT_SANSSERIF 2 -#define FONT_COURIER 3 -#define FONT_SCRIPT 4 -#define FONT_OCRA 5 -#define FONT_OCRB 6 +enum { + FONT_DEFAULT = 0, + FONT_ROMAN, + FONT_SANSSERIF, + FONT_COURIER, + FONT_SCRIPT, + FONT_OCRA, + FONT_OCRB +}; /* Font styles. */ #define STYLE_PROP 0x0001 @@ -125,20 +132,22 @@ FT_Library ft_lib = NULL; #define QUALITY_LQ 0x02 /* Typefaces. */ -#define TYPEFACE_ROMAN 0 -#define TYPEFACE_SANSSERIF 1 -#define TYPEFACE_COURIER 2 -#define TYPEFACE_PRESTIGE 3 -#define TYPEFACE_SCRIPT 4 -#define TYPEFACE_OCRB 5 -#define TYPEFACE_OCRA 6 -#define TYPEFACE_ORATOR 7 -#define TYPEFACE_ORATORS 8 -#define TYPEFACE_SCRIPTC 9 -#define TYPEFACE_ROMANT 10 -#define TYPEFACE_SANSSERIFH 11 -#define TYPEFACE_SVBUSABA 30 -#define TYPEFACE_SVJITTRA 31 +enum { + TYPEFACE_ROMAN = 0, + TYPEFACE_SANSSERIF, + TYPEFACE_COURIER, + TYPEFACE_PRESTIGE, + TYPEFACE_SCRIPT, + TYPEFACE_OCRB, + TYPEFACE_OCRA, + TYPEFACE_ORATOR, + TYPEFACE_ORATORS, + TYPEFACE_SCRIPTC, + TYPEFACE_ROMANT, + TYPEFACE_SANSSERIFH, + TYPEFACE_SVBUSABA = 30, + TYPEFACE_SVJITTRA +}; /* Some helper macros. */ #define PARAM16(x) (dev->esc_parms[x + 1] * 256 + dev->esc_parms[x]) @@ -164,6 +173,9 @@ typedef struct escp_t { pc_timer_t pulse_timer; pc_timer_t timeout_timer; + int lang; + int paper_size; + char page_fn[260]; uint8_t color; @@ -423,6 +435,23 @@ fill_palette(uint8_t redmax, uint8_t greenmax, uint8_t bluemax, uint8_t colorID, static void reset_printer(escp_t *dev) { + dev->top_margin = dev->left_margin = 0.0; + dev->right_margin = dev->page_width; + switch (dev->paper_size) { + case PAPER_A4: + dev->page_height = A4_PAGE_HEIGHT; + break; + case PAPER_LEGAL_SIDE: + dev->page_height = LEGAL_PAGE_WIDTH; + break; + case PAPER_B4_SIDE: + dev->page_height = B4_PAGE_WIDTH; + break; + case PAPER_LETTER: + default: + dev->page_height = LETTER_PAGE_HEIGHT; + } + dev->bottom_margin = dev->page_height; /* TODO: these should be configurable. */ dev->color = COLOR_BLACK; dev->curr_x = dev->curr_y = 0.0; @@ -430,23 +459,20 @@ reset_printer(escp_t *dev) dev->fss_seen = 0; dev->esc_pending = 0; dev->esc_parms_req = dev->esc_parms_curr = 0; - dev->top_margin = dev->left_margin = 0.0; - dev->right_margin = dev->page_width = PAGE_WIDTH; - dev->bottom_margin = dev->page_height = PAGE_HEIGHT; - dev->lpi = PAGE_LPI; - dev->linespacing = 1.0 / dev->lpi; - dev->cpi = PAGE_CPI; - dev->curr_char_table = 1; - dev->font_style = 0; - dev->print_quality = QUALITY_DRAFT; - dev->extra_intra_space = 0.0; - dev->print_upper_control = 1; - dev->bg_remaining_bytes = 0; - dev->density_k = 0; - dev->density_l = 1; - dev->density_y = 2; - dev->density_z = 3; - dev->char_tables[0] = 0; /* italics */ + dev->lpi = PAGE_LPI; + dev->linespacing = 1.0 / dev->lpi; + dev->cpi = PAGE_CPI; + dev->curr_char_table = 1; + dev->font_style = 0; + dev->print_quality = QUALITY_DRAFT; + dev->extra_intra_space = 0.0; + dev->print_upper_control = 1; + dev->bg_remaining_bytes = 0; + dev->density_k = 0; + dev->density_l = 1; + dev->density_y = 2; + dev->density_z = 3; + dev->char_tables[0] = 0; /* italics */ dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ dev->defined_unit = -1.0; dev->multipoint_mode = 0; @@ -633,73 +659,55 @@ process_char(escp_t *dev, uint8_t ch) escp_log("Command pending=%02x, font path=%s\n", dev->esc_pending, dev->fontpath); switch (dev->esc_pending) { case 0x02: // Undocumented - case 0x0a: // Reverse line feed - case 0x0c: // Return to top of current page case 0x0e: // Select double-width printing (one line) (ESC SO) case 0x0f: // Select condensed printing (ESC SI) - case 0x23: // Cancel MSB control (ESC #) - case 0x30: // Select 1/8-inch line spacing (ESC 0) - case 0x31: // Select 7/60-inch line spacing - case 0x32: // Select 1/6-inch line spacing (ESC 2) - case 0x34: // Select italic font (ESC 4) - case 0x35: // Cancel italic font (ESC 5) - case 0x36: // Enable printing of upper control codes (ESC 6) - case 0x37: // Enable upper control codes (ESC 7) - case 0x38: // Disable paper-out detector - case 0x39: // Enable paper-out detector - case 0x3c: // Unidirectional mode (one line) (ESC <) - case 0x3d: // Set MSB to 0 (ESC =) - case 0x3e: // Set MSB to 1 (ESC >) - case 0x40: // Initialize printer (ESC @) - case 0x45: // Select bold font (ESC E) - case 0x46: // Cancel bold font (ESC F) - case 0x47: // Select double-strike printing (ESC G) - case 0x48: // Cancel double-strike printing (ESC H) - case 0x4d: // Select 10.5-point, 12-cpi (ESC M) - case 0x4f: // Cancel bottom margin - case 0x50: // Select 10.5-point, 10-cpi (ESC P) - case 0x54: // Cancel superscript/subscript printing (ESC T) - case 0x5e: // Enable printing of all character codes on next character - case 0x67: // Select 10.5-point, 15-cpi (ESC g) - + case '#': // Cancel MSB control + case '0': // Select 1/8-inch line spacing + case '1': // Select 7/60-inch line spacing + case '2': // Select 1/6-inch line spacing + case '4': // Select italic font + case '5': // Cancel italic font + case '6': // Enable printing of upper control codes + case '7': // Enable upper control codes + case '8': // Disable paper-out detector + case '9': // Enable paper-out detector + case '<': // Unidirectional mode (one line) + case '=': // Set MSB to 0 + case '>': // Set MSB to 1 + case '@': // Initialize printer + case 'E': // Select bold font + case 'F': // Cancel bold font + case 'G': // Select double-strike printing + case 'H': // Cancel double-strike printing + case 'M': // Select 10.5-point, 12-cpi + case 'O': // Cancel bottom margin + case 'P': // Select 10.5-point, 10-cpi + case 'T': // Cancel superscript/subscript printing + case '^': // Enable printing of all character codes on next character + dev->esc_parms_req = 0; + break; + case 'g': // Select 10.5-point, 15-cpi + dev->esc_parms_req = 0; + if (dev->lang == LANG_EX1000) { + dev->esc_pending = 0; + return 1; + } + break; + case 0x0a: // Reverse line feed (IBM's ESC LF) + case 0x0c: // Return to top of current page (IBM's ESC FF) case 0x834: // Select italic font (FS 4) (= ESC 4) case 0x835: // Cancel italic font (FS 5) (= ESC 5) case 0x846: // Select forward feed mode (FS F) case 0x852: // Select reverse feed mode (FS R) dev->esc_parms_req = 0; + if (dev->lang < LANG_ESCP2) { + dev->esc_pending = 0; + return 1; + } break; - case 0x19: // Control paper loading/ejecting (ESC EM) - case 0x20: // Set intercharacter space (ESC SP) - case 0x21: // Master select (ESC !) - case 0x2b: // Set n/360-inch line spacing (ESC +) - case 0x2d: // Turn underline on/off (ESC -) - case 0x2f: // Select vertical tab channel (ESC /) - case 0x33: // Set n/180-inch line spacing (ESC 3) - case 0x41: // Set n/60-inch line spacing - case 0x43: // Set page length in lines (ESC C) - case 0x49: // Select character type and print pitch - case 0x4a: // Advance print position vertically (ESC J n) - case 0x4e: // Set bottom margin (ESC N) - case 0x51: // Set right margin (ESC Q) - case 0x52: // Select an international character set (ESC R) - case 0x53: // Select superscript/subscript printing (ESC S) - case 0x55: // Turn unidirectional mode on/off (ESC U) - case 0x57: // Turn double-width printing on/off (ESC W) - case 0x61: // Select justification (ESC a) - case 0x66: // Absolute horizontal tab in columns [conflict] - case 0x68: // Select double or quadruple size - case 0x69: // Immediate print - case 0x6a: // Reverse paper feed - case 0x6b: // Select typeface (ESC k) - case 0x6c: // Set left margin (ESC 1) - case 0x70: // Turn proportional mode on/off (ESC p) - case 0x72: // Select printing color (ESC r) - case 0x73: // Select low-speed mode (ESC s) - case 0x74: // Select character table (ESC t) - case 0x77: // Turn double-height printing on/off (ESC w) - case 0x78: // Select LQ or draft (ESC x) - case 0x7e: // Select/Deselect slash zero (ESC ~) + case 'h': // Select double or quadruple size (IBM's) + case '~': // Select/Deselect slash zero (IBM's?) case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2) case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +) case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A) @@ -708,53 +716,142 @@ process_char(escp_t *dev, uint8_t ch) case 0x849: // Select character table (FS I) (= ESC t) case 0x853: // Select High Speed/High Density elite pitch (FS S) case 0x856: // Turn double-height printing on/off (FS V) (= ESC w) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case '+': // Set n/360-inch line spacing + if (dev->lang < LANG_ESCP) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case 'w': // Turn double-height printing on/off + if (dev->lang == LANG_EX1000) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case 0x19: // Control paper loading/ejecting (ESC EM) + case ' ': // Set intercharacter space + case '!': // Master select + case '-': // Turn underline on/off + case '/': // Select vertical tab channel + case '3': // Set n/180-inch line spacing + case 'A': // Set n/60-inch line spacing + case 'C': // Set page length in lines + case 'I': // Select character type and print pitch + case 'J': // Advance print position vertically + case 'N': // Set bottom margin + case 'Q': // Set right margin + case 'R': // Select an international character set + case 'S': // Select superscript/subscript printing + case 'U': // Turn unidirectional mode on/off + case 'W': // Turn double-width printing on/off + case 'a': // Select justification + case 'k': // Select typeface + case 'l': // Set left margin + case 'p': // Turn proportional mode on/off + case 'r': // Select printing color + case 's': // Select low-speed mode + case 't': // Select character table + case 'x': // Select LQ or draft + dev->esc_parms_req = 1; + break; + case 'f': // Absolute horizontal tab in columns + if (dev->lang != LANG_9PIN) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + dev->esc_parms_req = 1; + break; + case 'i': // Immediate print + case 'j': // Reverse paper feed + if (dev->lang != LANG_EX1000) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } dev->esc_parms_req = 1; break; - case 0x24: // Set absolute horizontal print position (ESC $) - case 0x3f: // Reassign bit-image mode (ESC ?) - case 0x4b: // Select 60-dpi graphics (ESC K) - case 0x4c: // Select 120-dpi graphics (ESC L) - case 0x59: // Select 120-dpi, double-speed graphics (ESC Y) - case 0x5a: // Select 240-dpi graphics (ESC Z) - case 0x5c: // Set relative horizontal print position (ESC \) - case 0x63: // Set horizontal motion index (HMI) (ESC c) - case 0x65: // Set vertical tab stops every n lines (ESC e) + case 'c': // Set horizontal motion index (HMI) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case '$': // Set absolute horizontal print position + case '?': // Reassign bit-image mode + case 'K': // Select 60-dpi graphics + case 'L': // Select 120-dpi graphics + case 'Y': // Select 120-dpi, double-speed graphics + case 'Z': // Select 240-dpi graphics + case '\\': // Set relative horizontal print position case 0x85a: // Print 24-bit hex-density graphics (FS Z) dev->esc_parms_req = 2; break; + case 'e': // Set vertical tab stops every n lines + if (dev->lang != LANG_9PIN) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + dev->esc_parms_req = 2; + break; - case 0x2a: // Select bit image (ESC *) - case 0x58: // Select font by pitch and point (ESC X) + case 'X': // Select font by pitch and point + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case '*': // Select bit image dev->esc_parms_req = 3; break; - case 0x5b: // Select character height, width, line spacing + case '[': // Select character height, width, line spacing (IBM's) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } dev->esc_parms_req = 7; break; - case 0x62: // Set vertical tabs in VFU channels (ESC b) - case 0x42: // Set vertical tabs (ESC B) + case 'b': // Set vertical tabs in VFU channels + case 'B': // Set vertical tabs dev->num_vertical_tabs = 0; return 1; - case 0x44: // Set horizontal tabs (ESC D) + case 'D': // Set horizontal tabs dev->num_horizontal_tabs = 0; return 1; - case 0x25: // Select user-defined set (ESC %) - case 0x26: // Define user-defined characters (ESC &) - case 0x3a: // Copy ROM to RAM (ESC :) + case '%': // Select user-defined set + case '&': // Define user-defined characters + case ':': // Copy ROM to RAM escp_log("ESC/P: User-defined characters not supported (0x%02x).\n", dev->esc_pending); return 1; - case 0x28: // Two bytes sequence + case '(': // Two bytes sequence + if (dev->lang == LANG_EX1000) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + } /* return and wait for second ESC byte */ return 1; - case 0x2e: - fatal("ESC/P: Print Raster Graphics (2E) command is not implemented.\nTerminating the emulator to avoid endless PNG generation.\n"); - exit(-1); + case '.': + if (dev->lang >= LANG_ESCP2) { + fatal("ESC/P: Print Raster Graphics (2E) command is not implemented.\nTerminating the emulator to avoid endless PNG generation.\n"); + exit(-1); + } + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; default: escp_log("ESC/P: Unknown command ESC %c (0x%02x). Unable to skip parameters.\n", @@ -776,50 +873,67 @@ process_char(escp_t *dev, uint8_t ch) escp_log("Two-byte command pending=%03x, font path=%s\n", dev->esc_pending, dev->fontpath); switch (dev->esc_pending) { - case 0x0242: // Bar code setup and print (ESC (B) case 0x025e: // Print data as characters (ESC (^) + if (dev->lang < LANG_ESCP2) + default: + /* ESC ( commands are always followed by a "number of parameters" word parameter */ + dev->esc_pending = 0x101; /* dummy value to be checked later */ + case 0x0242: // Bar code setup and print (ESC (B) dev->esc_parms_req = 2; break; case 0x0255: // Set unit (ESC (U) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } dev->esc_parms_req = 3; break; case 0x0243: // Set page length in defined unit (ESC (C) case 0x0256: // Set absolute vertical print position (ESC (V) case 0x0276: // Set relative vertical print position (ESC (v) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } dev->esc_parms_req = 4; break; - case 0x0228: // Assign character table (ESC (t) case 0x022d: // Select line/score (ESC (-) + if (dev->lang == LANG_9PIN) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } + case 0x0228: // Assign character table (ESC (t) dev->esc_parms_req = 5; break; case 0x0263: // Set page format (ESC (c) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } dev->esc_parms_req = 6; break; - - default: - /* ESC ( commands are always followed by a "number of parameters" word parameter */ - dev->esc_parms_req = 2; - dev->esc_pending = 0x101; /* dummy value to be checked later */ - return 1; } - /* If we need parameters, return and wait for them to appear. */ - if (dev->esc_parms_req > 0) - return 1; + // Wait for more parameters. + return 1; } /* Ignore VFU channel setting. */ - if (dev->esc_pending == 0x62) { - dev->esc_pending = 0x42; + if (dev->esc_pending == 'b') { + dev->esc_pending = 'B'; return 1; } /* Collect vertical tabs. */ - if (dev->esc_pending == 0x42) { + if (dev->esc_pending == 'B') { /* check if we're done */ if ((ch == 0) || (dev->num_vertical_tabs > 0 && dev->vertical_tabs[dev->num_vertical_tabs - 1] > (double) ch * dev->linespacing)) { dev->esc_pending = 0; @@ -830,7 +944,7 @@ process_char(escp_t *dev, uint8_t ch) } /* Collect horizontal tabs. */ - if (dev->esc_pending == 0x44) { + if (dev->esc_pending == 'D') { /* check if we're done... */ if ((ch == 0) || (dev->num_horizontal_tabs > 0 && dev->horizontal_tabs[dev->num_horizontal_tabs - 1] > (double) ch * (1.0 / dev->cpi))) { dev->esc_pending = 0; @@ -887,7 +1001,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x21: /* master select (ESC !) */ + case '!': /* master select */ dev->cpi = (dev->esc_parms[0]) & 0x01 ? 12.0 : 10.0; /* Reset first seven bits. */ @@ -914,11 +1028,11 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x23: /* cancel MSB control (ESC #) */ + case '#': /* cancel MSB control */ dev->msb = 255; break; - case 0x24: /* set abs horizontal print position (ESC $) */ + case '$': /* set abs horizontal print position */ unit_size = dev->defined_unit; if (unit_size < 0) unit_size = 60.0; @@ -932,12 +1046,12 @@ process_char(escp_t *dev, uint8_t ch) setup_bit_image(dev, 40, PARAM16(0)); break; - case 0x2a: /* select bit image (ESC *) */ + case '*': /* select bit image */ setup_bit_image(dev, dev->esc_parms[0], PARAM16(1)); break; - case 0x2b: /* set n/360-inch line spacing (ESC +) */ case 0x833: /* Set n/360-inch line spacing (FS 3) */ + case '+': /* set n/360-inch line spacing */ dev->linespacing = (double) dev->esc_parms[0] / 360.0; break; @@ -951,58 +1065,58 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x2f: /* select vertical tab channel (ESC /) */ + case '/': /* select vertical tab channel */ /* Ignore */ break; - case 0x30: /* select 1/8-inch line spacing (ESC 0) */ + case '0': /* select 1/8-inch line spacing */ dev->linespacing = 1.0 / 8.0; break; - case 0x31: /* select 7/60-inch line spacing */ + case '1': /* select 7/60-inch line spacing */ dev->linespacing = 7.0 / 60.0; break; - case 0x32: /* select 1/6-inch line spacing (ESC 2) */ + case '2': /* select 1/6-inch line spacing */ dev->linespacing = 1.0 / 6.0; break; - case 0x33: /* set n/180-inch line spacing (ESC 3) */ + case '3': /* set n/180-inch line spacing */ dev->linespacing = (double) dev->esc_parms[0] / 180.0; break; - case 0x34: /* select italic font (ESC 4) */ + case '4': /* select italic font */ dev->font_style |= STYLE_ITALICS; update_font(dev); break; - case 0x35: /* cancel italic font (ESC 5) */ + case '5': /* cancel italic font */ dev->font_style &= ~STYLE_ITALICS; update_font(dev); break; - case 0x36: /* enable printing of upper control codes (ESC 6) */ + case '6': /* enable printing of upper control codes */ dev->print_upper_control = 1; break; - case 0x37: /* enable upper control codes (ESC 7) */ + case '7': /* enable upper control codes */ dev->print_upper_control = 0; break; - case 0x3c: /* unidirectional mode (one line) (ESC <) */ + case '<': /* unidirectional mode (one line) */ /* We don't have a print head, so just * ignore this. */ break; - case 0x3d: /* set MSB to 0 (ESC =) */ + case '=': /* set MSB to 0 */ dev->msb = 0; break; - case 0x3e: /* set MSB to 1 (ESC >) */ + case '>': /* set MSB to 1 */ dev->msb = 1; break; - case 0x3f: /* reassign bit-image mode (ESC ?) */ + case '?': /* reassign bit-image mode */ if (dev->esc_parms[0] == 'K') dev->density_k = dev->esc_parms[1]; if (dev->esc_parms[0] == 'L') @@ -1013,16 +1127,16 @@ process_char(escp_t *dev, uint8_t ch) dev->density_z = dev->esc_parms[1]; break; - case 0x40: /* initialize printer (ESC @) */ + case '@': /* initialize printer */ reset_printer(dev); break; - case 0x41: /* set n/60-inch line spacing */ - case 0x841: + case 'A': /* set n/60-inch line spacing */ + case 0x841: // FS A dev->linespacing = (double) dev->esc_parms[0] / 60.0; break; - case 0x43: /* set page length in lines (ESC C) */ + case 'C': /* set page length in lines */ if (dev->esc_parms[0] != 0) { dev->page_height = dev->bottom_margin = (double) dev->esc_parms[0] * dev->linespacing; } else { /* == 0 => Set page length in inches */ @@ -1033,69 +1147,69 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x45: /* select bold font (ESC E) */ + case 'E': /* select bold font */ dev->font_style |= STYLE_BOLD; update_font(dev); break; - case 0x46: /* cancel bold font (ESC F) */ + case 'F': /* cancel bold font */ dev->font_style &= ~STYLE_BOLD; update_font(dev); break; - case 0x47: /* select double-strike printing (ESC G) */ + case 'G': /* select double-strike printing */ dev->font_style |= STYLE_DOUBLESTRIKE; break; - case 0x48: /* cancel double-strike printing (ESC H) */ + case 'H': /* cancel double-strike printing */ dev->font_style &= ~STYLE_DOUBLESTRIKE; break; - case 0x4a: /* advance print pos vertically (ESC J n) */ + case 'J': /* advance print pos vertically */ dev->curr_y += (double) ((double) dev->esc_parms[0] / 180.0); if (dev->curr_y > dev->bottom_margin) new_page(dev, 1, 0); break; - case 0x4b: /* select 60-dpi graphics (ESC K) */ + case 'K': /* select 60-dpi graphics */ /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_k, PARAM16(0)); break; - case 0x4c: /* select 120-dpi graphics (ESC L) */ + case 'L': /* select 120-dpi graphics */ /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_l, PARAM16(0)); break; - case 0x4d: /* select 10.5-point, 12-cpi (ESC M) */ + case 'M': /* select 10.5-point, 12-cpi */ dev->cpi = 12.0; dev->hmi = -1; dev->multipoint_mode = 0; update_font(dev); break; - case 0x4e: /* set bottom margin (ESC N) */ + case 'N': /* set bottom margin */ dev->top_margin = 0.0; dev->bottom_margin = (double) dev->esc_parms[0] * dev->linespacing; break; - case 0x4f: /* cancel bottom (and top) margin */ + case 'O': /* cancel bottom (and top) margin */ dev->top_margin = 0.0; dev->bottom_margin = dev->page_height; break; - case 0x50: /* select 10.5-point, 10-cpi (ESC P) */ + case 'P': /* select 10.5-point, 10-cpi */ dev->cpi = 10.0; dev->hmi = -1; dev->multipoint_mode = 0; update_font(dev); break; - case 0x51: /* set right margin */ + case 'Q': /* set right margin */ dev->right_margin = ((double) dev->esc_parms[0] - 1.0) / dev->cpi; break; - case 0x52: /* select an intl character set (ESC R) */ + case 'R': /* select an intl character set */ if ((dev->esc_parms[0] <= 13) || (dev->esc_parms[0] == 64)) { if (dev->esc_parms[0] == 64) dev->esc_parms[0] = 14; @@ -1115,7 +1229,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x53: /* select superscript/subscript printing (ESC S) */ + case 'S': /* select superscript/subscript printing */ if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) dev->font_style |= STYLE_SUBSCRIPT; if ((dev->esc_parms[0] == 1) || (dev->esc_parms[1] == '1')) @@ -1123,16 +1237,16 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x54: /* cancel superscript/subscript printing (ESC T) */ + case 'T': /* cancel superscript/subscript printing */ dev->font_style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; update_font(dev); break; - case 0x55: /* turn unidirectional mode on/off (ESC U) */ + case 'U': /* turn unidirectional mode on/off */ /* We don't have a print head, so just ignore this. */ break; - case 0x57: /* turn double-width printing on/off (ESC W) */ + case 'W': /* turn double-width printing on/off */ if (!dev->multipoint_mode) { dev->hmi = -1; if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) @@ -1143,7 +1257,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x58: /* select font by pitch and point (ESC X) */ + case 'X': /* select font by pitch and point */ dev->multipoint_mode = 1; /* Copy currently non-multipoint CPI if no value was set so far. */ if (dev->multipoint_cpi == 0.0) { @@ -1165,17 +1279,17 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x59: /* select 120-dpi, double-speed graphics (ESC Y) */ + case 'Y': /* select 120-dpi, double-speed graphics */ /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_y, PARAM16(0)); break; - case 0x5a: /* select 240-dpi graphics (ESC Z) */ + case 'Z': /* select 240-dpi graphics */ /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_z, PARAM16(0)); break; - case 0x5c: /* set relative horizontal print pos (ESC \) */ + case '\\': /* set relative horizontal print pos */ rel_move = PARAM16(0); unit_size = dev->defined_unit; if (unit_size < 0) @@ -1183,16 +1297,16 @@ process_char(escp_t *dev, uint8_t ch) dev->curr_x += ((double) rel_move / unit_size); break; - case 0x61: /* select justification (ESC a) */ + case 'a': /* select justification */ /* Ignore. */ break; - case 0x63: /* set horizontal motion index (HMI) (ESC c) */ + case 'c': /* set horizontal motion index (HMI) */ dev->hmi = (double) PARAM16(0) / 360.0; dev->extra_intra_space = 0.0; break; - case 0x67: /* select 10.5-point, 15-cpi (ESC g) */ + case 'g': /* select 10.5-point, 15-cpi */ dev->cpi = 15; dev->hmi = -1; dev->multipoint_mode = 0; @@ -1204,7 +1318,7 @@ process_char(escp_t *dev, uint8_t ch) dev->linespacing *= -1; break; - case 0x6a: // Reverse paper feed (ESC j) + case 'j': // Reverse paper feed (ESC j) reverse = (double) PARAM16(0) / (double) 216.0; reverse = dev->curr_y - reverse; if (reverse < dev->left_margin) @@ -1213,20 +1327,20 @@ process_char(escp_t *dev, uint8_t ch) dev->curr_y = reverse; break; - case 0x6b: /* select typeface (ESC k) */ + case 'k': /* select typeface */ if ((dev->esc_parms[0] <= 11) || (dev->esc_parms[0] == 30) || (dev->esc_parms[0] == 31)) dev->lq_typeface = dev->esc_parms[0]; update_font(dev); break; - case 0x6c: /* set left margin (ESC 1) */ + case 'l': /* set left margin */ dev->left_margin = ((double) dev->esc_parms[0] - 1.0) / dev->cpi; if (dev->curr_x < dev->left_margin) dev->curr_x = dev->left_margin; break; - case 0x70: /* Turn proportional mode on/off (ESC p) */ + case 'p': /* Turn proportional mode on/off */ if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) dev->font_style &= ~STYLE_PROP; if ((dev->esc_parms[0] == 1) || (dev->esc_parms[0] == '1')) { @@ -1238,18 +1352,18 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x72: /* select printing color (ESC r) */ + case 'r': /* select printing color */ if (dev->esc_parms[0] == 0 || dev->esc_parms[0] > 6) dev->color = COLOR_BLACK; else dev->color = dev->esc_parms[0] << 5; break; - case 0x73: /* select low-speed mode (ESC s) */ + case 's': /* select low-speed mode */ /* Ignore. */ break; - case 0x74: /* select character table (ESC t) */ + case 't': /* select character table */ case 0x849: /* Select character table (FS I) */ if (dev->esc_parms[0] < 4) { dev->curr_char_table = dev->esc_parms[0]; @@ -1260,7 +1374,7 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x77: /* turn double-height printing on/off (ESC w) */ + case 'w': /* turn double-height printing on/off */ if (!dev->multipoint_mode) { if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) dev->font_style &= ~STYLE_DOUBLEHEIGHT; @@ -1270,7 +1384,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x78: /* select LQ or draft (ESC x) */ + case 'x': /* select LQ or draft */ if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) { dev->print_quality = QUALITY_DRAFT; dev->font_style |= STYLE_CONDENSED; @@ -1523,9 +1637,12 @@ process_char(escp_t *dev, uint8_t ch) dev->esc_seen = 1; return 1; - case 0x1c: /* FS (IBM commands) */ - dev->fss_seen = 1; - return 1; + case 0x1c: /* FS (IBM Proprinter II) + TODO: Make an IBM printer. */ + if (dev->lang == LANG_ESCP2) { + dev->fss_seen = 1; + return 1; + } default: /* This is a printable character -> print it. */ @@ -1998,6 +2115,8 @@ escp_init(const device_t *info) dev->lpt = lpt_attach(write_data, write_ctrl, strobe, read_status, read_ctrl, NULL, NULL, dev); + dev->lang = device_get_config_int("language"); + rom_get_full_path(dev->fontpath, "roms/printer/fonts/"); /* Create a full pathname for the font files. */ @@ -2014,9 +2133,28 @@ escp_init(const device_t *info) plat_dir_create(dev->pagepath); path_slash(dev->pagepath); - dev->page_width = PAGE_WIDTH; - dev->page_height = PAGE_HEIGHT; - dev->dpi = PAGE_DPI; + dev->paper_size = device_get_config_int("paper_size"); + + switch (dev->paper_size) { + case PAPER_A4: + dev->page_width = A4_PAGE_WIDTH; + dev->page_height = A4_PAGE_HEIGHT; + break; + case PAPER_LEGAL_SIDE: + dev->page_height = LEGAL_PAGE_WIDTH; + dev->page_width = LEGAL_PAGE_HEIGHT; + break; + case PAPER_B4_SIDE: + dev->page_height = B4_PAGE_WIDTH; + dev->page_width = B4_PAGE_HEIGHT; + break; + case PAPER_LETTER: + default: + dev->page_width = LETTER_PAGE_WIDTH; + dev->page_height = LETTER_PAGE_HEIGHT; + } + + dev->dpi = dev->lang >= LANG_ESCP ? 360 : 240; /* Create 8-bit grayscale buffer for the page. */ dev->page = (psurface_t *) malloc(sizeof(psurface_t)); @@ -2090,6 +2228,29 @@ escp_close(void *priv) // clang-format off #if 0 static const device_config_t lpt_prt_escp_config[] = { + { .name = "", .description = "", .type = CONFIG_END } +}; +#endif +static const device_config_t lpt_prt_escp_config[] = { + { + .name = "language", + .description = "Language", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = LANG_ESCP2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "EX-1000", .value = LANG_EX1000 }, +#if 0 + { .description = "9-pin", .value = LANG_9PIN }, + { .description = "ESC/P", .value = LANG_ESCP }, +#endif + { .description = "ESC/P 2", .value = LANG_ESCP2 }, + { .description = "" } + }, + .bios = { { 0 } } + }, { .name = "paper_size", .description = "Paper Size", @@ -2099,15 +2260,16 @@ static const device_config_t lpt_prt_escp_config[] = { .file_filter = NULL, .spinner = { 0 }, .selection = { - { .description = "Letter", .value = 0 }, - { .description = "A4", .value = 1 }, + { .description = "Letter", .value = PAPER_LETTER }, + { .description = "A4", .value = PAPER_A4 }, + { .description = "Legal (sideways)", .value = PAPER_LEGAL_SIDE }, + { .description = "B4 (sideways)", .value = PAPER_B4_SIDE }, { .description = "" } }, .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; -#endif // clang-format on const device_t lpt_prt_escp_device = { @@ -2121,9 +2283,5 @@ const device_t lpt_prt_escp_device = { .available = NULL, .speed_changed = NULL, .force_redraw = NULL, -#if 0 .config = lpt_prt_escp_config -#else - .config = NULL -#endif };