From 933b8cacd072ee4d4e7a39df877b81f88f9728b8 Mon Sep 17 00:00:00 2001 From: waltje Date: Sat, 1 Sep 2018 06:35:50 -0400 Subject: [PATCH] Committed the basic printer module, cleaned up a bit. --- src/devices/ports/parallel_dev.c | 36 ++- src/devices/printer/printer.h | 60 +++++ src/devices/printer/prt_text.c | 437 +++++++++++++++++++++++++++++++ src/win/mingw/Makefile.MinGW | 8 +- src/win/msvc/Makefile.VC | 8 +- 5 files changed, 524 insertions(+), 25 deletions(-) create mode 100644 src/devices/printer/printer.h create mode 100644 src/devices/printer/prt_text.c diff --git a/src/devices/ports/parallel_dev.c b/src/devices/ports/parallel_dev.c index c13ae9d..dad0e45 100644 --- a/src/devices/ports/parallel_dev.c +++ b/src/devices/ports/parallel_dev.c @@ -8,7 +8,7 @@ * * Implementation of the parallel-port-attached devices. * - * Version: @(#)parallel_dev.c 1.0.6 2018/08/31 + * Version: @(#)parallel_dev.c 1.0.7 2018/08/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -47,9 +47,7 @@ #include "../../devices/sound/snd_lpt_dac.h" #include "../../devices/sound/snd_lpt_dss.h" -#if USE_PRINTERS -# include "../../devices/printer/printer.h" -#endif +#include "../../devices/printer/printer.h" static const struct { @@ -57,26 +55,26 @@ static const struct { const char *internal_name; const lpt_device_t *device; } devices[] = { - {"None", - "none", NULL }, + { "None", + "none", NULL }, - {"Disney Sound Source", - "dss", &dss_device }, - {"LPT DAC / Covox Speech Thing", - "lpt_dac", &lpt_dac_device }, - {"Stereo LPT DAC", - "lpt_dac_stereo", &lpt_dac_stereo_device }, + { "Disney Sound Source", + "dss", &dss_device }, + { "LPT DAC / Covox Speech Thing", + "lpt_dac", &lpt_dac_device }, + { "Stereo LPT DAC", + "lpt_dac_stereo", &lpt_dac_stereo_device }, + + { "Generic TEXT printer", + "lpt_prt_text", &lpt_prt_text_device }, #if USE_PRINTERS - {"Generic TEXT printer", - "lpt_printer_text", &lpt_printer_text_device }, - - {"Generic ESC/P Dot-Matrix printer", - "lpt_printer_escp", &lpt_printer_escp_device }, + { "Generic ESC/P Dot-Matrix printer", + "lpt_prt_escp", &lpt_prt_escp_device }, #endif - {NULL, NULL, - NULL } + { NULL, NULL, + NULL } }; diff --git a/src/devices/printer/printer.h b/src/devices/printer/printer.h new file mode 100644 index 0000000..e05a653 --- /dev/null +++ b/src/devices/printer/printer.h @@ -0,0 +1,60 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the printers module. + * + * Version: @(#)printer.h 1.0.1 2018/08/31 + * + * Authors: Michael Drüing, + * Fred N. van Kempen, + * + * Based on code by Frederic Weymann (originally for DosBox) + * + * Copyright 2018 Michael Drüing. + * Copyright 2018 Fred N. van Kempen. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef PRINTER_H +# define PRINTER_H + + +#define FONT_FILE_ROMAN L"roman.ttf" +#define FONT_FILE_SANSSERIF L"sansserif.ttf" +#define FONT_FILE_COURIER L"courier.ttf" +#define FONT_FILE_SCRIPT L"script.ttf" +#define FONT_FILE_OCRA L"ocra.ttf" +#define FONT_FILE_OCRB L"ocra.ttf" + + +#ifdef EMU_PARALLEL_DEV_H +extern const lpt_device_t lpt_prt_text_device; +extern const lpt_device_t lpt_prt_escp_device; +#endif + + +extern const uint16_t *select_codepage(uint16_t num); + + +#endif /*PRINTER_H*/ diff --git a/src/devices/printer/prt_text.c b/src/devices/printer/prt_text.c new file mode 100644 index 0000000..91cac1d --- /dev/null +++ b/src/devices/printer/prt_text.c @@ -0,0 +1,437 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of a generic text printer. + * + * Simple old text printers were unable to do any formatting + * of the text. They were just sheets of paper with a fixed + * size (in the U.S., this would be Letter, 8.5"x11") with a + * set of fixed margings to allow for proper operation of the + * printer mechanics. This would lead to a page being 66 lines + * of 80 characters each. + * + * Version: @(#)prt_text.c 1.0.1 2018/08/31 + * + * Author: Fred N. van Kempen, + * + * Copyright 2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include "../../emu.h" +#include "../../timer.h" +#include "../../plat.h" +#include "../ports/parallel_dev.h" +#include "printer.h" + + +typedef struct { + int8_t dirty; /* has the page been printed on? */ + char pad; + + uint8_t w; /* size info */ + uint8_t h; + + char *chars; /* character data */ +} psurface_t; + + +typedef struct { + const char *name; + + /* Output file name. */ + wchar_t filename[1024]; + + /* page data (TODO: make configurable) */ + double page_width, /* all in inches */ + page_height, + left_margin, + top_margin, + right_margin, + bot_margin; + + /* internal page data */ + psurface_t *page; + uint8_t max_chars, + max_lines; + uint8_t curr_x, /* print head position (chars) */ + curr_y; + + /* font data */ + double cpi, /* defined chars per inch */ + lpi; /* defined lines per inch */ + + /* handshake data */ + uint8_t data; + int8_t ack; + int8_t select; + int8_t busy; + int8_t int_pending; + int8_t error; + int8_t autofeed; +} prnt_t; + + +/* Dump the current page into a formatted file. */ +static void +dump_page(prnt_t *dev) +{ + wchar_t path[1024]; + uint16_t x, y; + uint8_t ch; + FILE *fp; + + /* Create the full path for this file. */ + memset(path, 0x00, sizeof(path)); + plat_append_filename(path, usr_path, PRINTER_PATH); + if (! plat_dir_check(path)) + plat_dir_create(path); + plat_append_slash(path); + wcscat(path, dev->filename); + + /* Create the file. */ + fp = plat_fopen(path, L"a"); + if (fp == NULL) { + pclog("PRNT: unable to create print page '%ls'\n", path); + return; + } + + /* If this is not a new file, add a formfeed first. */ + if (ftell(fp) != 0) + fputc('\014', fp); + + for (y = 0; y < dev->curr_y; y++) { + for (x = 0; x < dev->page->w; x++) { + ch = dev->page->chars[(y * dev->page->w) + x]; + if (ch == 0x00) { + /* End of line marker. */ + fputc('\n', fp); + break; + } else { + fputc(ch, fp); + } + } + } + + /* All done, close the file. */ + fclose(fp); +} + + +static void +new_page(prnt_t *dev) +{ + /* Dump the current page if needed. */ + if (dev->page->dirty) + dump_page(dev); + + /* Clear page. */ + memset(dev->page->chars, 0x00, dev->page->h * dev->page->w); + dev->curr_y = 0; + dev->page->dirty = 0; +} + + +static void +reset_printer(prnt_t *dev) +{ + /* TODO: these three should be configurable */ + dev->page_width = 8.5; + dev->page_height = 11; + dev->left_margin = 0.25; + dev->right_margin = 0.25; + dev->top_margin = 0.25; + dev->bot_margin = 0.25; + dev->cpi = 10.0; + dev->lpi = 6.0; + + /* Default page layout. */ + dev->max_chars = (int) ((dev->page_width - dev->left_margin - dev->right_margin) * dev->cpi); + dev->max_lines = (int) ((dev->page_height -dev->top_margin - dev->bot_margin) * dev->lpi); + + pclog("PRNT: width=%.1fin,height=%.1fin cpi=%i lpi=%i cols=%i lines=%i\n", + dev->page_width, dev->page_height, (int)dev->cpi, + (int)dev->lpi, dev->max_chars, dev->max_lines); + + dev->curr_x = dev->curr_y = 0; + + if (dev->page != NULL) + dev->page->dirty = 0; + + /* Create a file for this page. */ + plat_tempfile(dev->filename, PRINTER_FILE, L".txt"); +} + + +static int +process_char(prnt_t *dev, uint8_t ch) +{ + uint8_t i; + + switch (ch) { + case 0x07: /* Beeper (BEL) */ + /* TODO: beep? */ + return 1; + + case 0x08: /* Backspace (BS) */ + if (dev->curr_x > 0) + dev->curr_x--; + return 1; + + case 0x09: /* Tab horizontally (HT) */ + /* Find tab right to current pos. */ + i = dev->curr_x; + dev->page->chars[(dev->curr_y * dev->page->w) + i++] = ' '; + while ((i < dev->max_chars) && ((i % 8) != 0)) { + dev->page->chars[(dev->curr_y * dev->page->w) + i] = ' '; + i++; + } + dev->curr_x = i; + return 1; + + case 0x0b: /* Tab vertically (VT) */ + dev->curr_x = 0; + return 1; + + case 0x0c: /* Form feed (FF) */ + new_page(dev); + return 1; + + case 0x0d: /* Carriage Return (CR) */ + dev->curr_x = 0; + if (! dev->autofeed) + return 1; + /*FALLTHROUGH*/ + + case 0x0a: /* Line feed */ + dev->curr_x = 0; + if (++dev->curr_y >= dev->max_lines) + new_page(dev); + return 1; + + case 0x0e: /* select wide printing (SO) */ + /* Ignore. */ + return 1; + + case 0x0f: /* select condensed printing (SI) */ + /* Ignore. */ + return 1; + + case 0x11: /* select printer (DC1) */ + /* Ignore. */ + return 1; + + case 0x12: /* cancel condensed printing (DC2) */ + /* Ignore. */ + return 1; + + case 0x13: /* deselect printer (DC3) */ + /* Ignore. */ + return 1; + + case 0x14: /* cancel double-width printing (one line) (DC4) */ + /* Ignore. */ + return 1; + + case 0x18: /* cancel line (CAN) */ + /* Ignore. */ + return 1; + + case 0x1b: /* ESC */ + /* Ignore. */ + return 1; + + default: + break; + } + + /* Just a printable character. */ + return(0); +} + + +static void +handle_char(prnt_t *dev) +{ + uint8_t ch = dev->data; + + if (dev->page == NULL) return; + + if (process_char(dev, ch) == 1) { + /* Command was processed. */ + return; + } + + /* Store character in the page buffer. */ + dev->page->chars[(dev->curr_y * dev->page->w) + dev->curr_x] = ch; + dev->page->dirty = 1; + + /* Update print head position. */ + if (++dev->curr_x >= dev->max_chars) { + dev->curr_x = 0; + if (++dev->curr_y >= dev->max_lines) + new_page(dev); + } +} + + +static void +write_data(uint8_t val, void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + + dev->data = val; +} + + +static void +write_ctrl(uint8_t val, void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + + /* set autofeed value */ + dev->autofeed = val & 0x02 ? 1 : 0; + + if (val & 0x08) { /* SELECT */ + /* select printer */ + dev->select = 1; + } + + if ((val & 0x04) == 0) { + /* reset printer */ + dev->select = 0; + + pclog("PRNT: Printer reset\n"); + + reset_printer(dev); + } + + if (val & 0x01) { /* STROBE */ + /* Process incoming character. */ + handle_char(dev); + + /* ACK it, will be read on next READ STATUS. */ + dev->ack = 1; + } +} + + +static uint8_t +read_status(void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + + uint8_t status = (dev->ack ? 0x00 : 0x40) | + (dev->select ? 0x10 : 0x00) | + (dev->busy ? 0x00 : 0x80) | + (dev->int_pending ? 0x00 : 0x04) | + (dev->error ? 0x00 : 0x08); + + /* Clear ACK after reading status. */ + dev->ack = 0; + + return(status); +} + + +static void * +prnt_init(const lpt_device_t *info) +{ + prnt_t *dev; + + /* Initialize a device instance. */ + dev = malloc(sizeof(prnt_t)); + memset(dev, 0x00, sizeof(prnt_t)); + dev->name = info->name; + + pclog("PRNT: LPT printer '%s' initializing\n", dev->name); + + /* Initialize parameters. */ + reset_printer(dev); + + /* Create a page buffer. */ + dev->page = (psurface_t *)malloc(sizeof(psurface_t)); + dev->page->w = dev->max_chars; + dev->page->h = dev->max_lines; + dev->page->chars = (char *)malloc(dev->page->w * dev->page->h); + memset(dev->page->chars, 0x00, dev->page->w * dev->page->h); + + pclog("PRNT: created a virtual %ix%i page.\n", + dev->page->w, dev->page->h); + + return(dev); +} + + +static void +prnt_close(void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + + if (dev == NULL) return; + + pclog("PRNT: Closing LPT printer '%s'\n", dev->name); + + /* print last page if it contains data */ + if (dev->page->dirty) + dump_page(dev); + + if (dev->page != NULL) { + if (dev->page->chars != NULL) + free(dev->page->chars); + free(dev->page); + } + + pclog("PRNT: LPT printer '%s' closed.\n", dev->name); + + free(dev); +} + + +const lpt_device_t lpt_prt_text_device = { + "Generic TEXT printer", + 0, + prnt_init, + prnt_close, + write_data, + write_ctrl, + read_status +}; diff --git a/src/win/mingw/Makefile.MinGW b/src/win/mingw/Makefile.MinGW index ae31fed..42e2100 100644 --- a/src/win/mingw/Makefile.MinGW +++ b/src/win/mingw/Makefile.MinGW @@ -8,7 +8,7 @@ # # Makefile for Windows systems using the MinGW32 environment. # -# Version: @(#)Makefile.mingw 1.0.55 2018/08/31 +# Version: @(#)Makefile.mingw 1.0.56 2018/08/31 # # Author: Fred N. van Kempen, # @@ -548,7 +548,7 @@ ifeq ($(DEV_BRANCH), y) ifeq ($(PRINTERS), y) OPTS += -DUSE_PRINTERS=1 - DEVBROBJ += prt_text.o prt_cpmap.o prt_escp.o + DEVBROBJ += prt_cpmap.o prt_escp.o endif endif @@ -610,7 +610,9 @@ INTELOBJ := intel.o \ DEVOBJ := bugger.o \ isamem.o isartc.o \ game.o game_dev.o \ - parallel.o parallel_dev.o serial.o \ + parallel.o parallel_dev.o \ + prt_text.o \ + serial.o \ sio_fdc37c66x.o sio_fdc37c669.o sio_fdc37c93x.o \ sio_pc87306.o sio_w83877f.o sio_um8669f.o \ keyboard.o \ diff --git a/src/win/msvc/Makefile.VC b/src/win/msvc/Makefile.VC index 74c9c45..ed68087 100644 --- a/src/win/msvc/Makefile.VC +++ b/src/win/msvc/Makefile.VC @@ -8,7 +8,7 @@ # # Makefile for Windows using Visual Studio 2015. # -# Version: @(#)Makefile.VC 1.0.41 2018/08/31 +# Version: @(#)Makefile.VC 1.0.42 2018/08/31 # # Author: Fred N. van Kempen, # @@ -522,7 +522,7 @@ ifeq ($(DEV_BRANCH), y) ifeq ($(PRINTERS), y) OPTS += -DUSE_PRINTERS=1 - DEVBROBJ += prt_text.obj prt_cpmap.obj prt_escp.obj + DEVBROBJ += prt_cpmap.obj prt_escp.obj endif endif @@ -580,7 +580,9 @@ INTELOBJ := intel.obj \ DEVOBJ := bugger.obj \ isamem.obj isartc.obj \ game.obj game_dev.obj \ - parallel.obj parallel_dev.obj serial.obj \ + parallel.obj parallel_dev.obj \ + prt_text.obj \ + serial.obj \ sio_fdc37c66x.obj sio_fdc37c669.obj sio_fdc37c93x.obj \ sio_pc87306.obj sio_w83877f.obj sio_um8669f.obj \ keyboard.obj \