From c21bea828d7253fc2b0bf671937a09f123737b9a Mon Sep 17 00:00:00 2001 From: goldnchild <48141308+goldnchild@users.noreply.github.com> Date: Fri, 7 Jan 2022 12:07:58 -0800 Subject: Adding bitmap_printer_device and convert epson_lx810 to use it. (#8863) --- scripts/src/machine.lua | 11 + scripts/target/mame/mess.lua | 1 + src/devices/bus/centronics/epson_lx810l.cpp | 137 ++++----- src/devices/bus/centronics/epson_lx810l.h | 32 +- src/devices/machine/bitmap_printer.cpp | 443 ++++++++++++++++++++++++++++ src/devices/machine/bitmap_printer.h | 130 ++++++++ src/devices/machine/e05a30.cpp | 8 + src/devices/machine/e05a30.h | 4 +- src/devices/machine/steppers.h | 2 + 9 files changed, 671 insertions(+), 97 deletions(-) create mode 100644 src/devices/machine/bitmap_printer.cpp create mode 100644 src/devices/machine/bitmap_printer.h diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index 4bb5410edc9..1a4c85a7cc8 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -4911,3 +4911,14 @@ if (MACHINES["GLUKRS"]~=null) then MAME_DIR .. "src/devices/machine/glukrs.h", } end + +--------------------------------------------------- +-- +--@src/devices/machine/bitmap_printer.h,MACHINES["BITMAP_PRINTER"] = true +--------------------------------------------------- +if (MACHINES["BITMAP_PRINTER"]~=null) then + files { + MAME_DIR .. "src/devices/machine/bitmap_printer.cpp", + MAME_DIR .. "src/devices/machine/bitmap_printer.h", + } +end \ No newline at end of file diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 07f55663b4a..108774417ea 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -829,6 +829,7 @@ MACHINES["BL_HANDHELDS_MENUCONTROL"] = true MACHINES["NS32081"] = true MACHINES["NS32202"] = true MACHINES["NS32082"] = true +MACHINES["BITMAP_PRINTER"] = true -------------------------------------------------- -- specify available bus cores diff --git a/src/devices/bus/centronics/epson_lx810l.cpp b/src/devices/bus/centronics/epson_lx810l.cpp index ad901edb5b5..3c954f3d28e 100644 --- a/src/devices/bus/centronics/epson_lx810l.cpp +++ b/src/devices/bus/centronics/epson_lx810l.cpp @@ -42,8 +42,10 @@ * an offset must be used to centralize the pixels. */ #define CR_OFFSET (-14) -#define PAPER_WIDTH 1024 -#define PAPER_HEIGHT 576 + +#define PAPER_WIDTH 1024 // 120 dpi * 8.5333 inches +#define PAPER_HEIGHT (11*72) // 72 dpi * 11 inches + //************************************************************************** @@ -140,14 +142,6 @@ void epson_lx810l_device::device_add_mconfig(machine_config &config) // config.set_default_layout(layout_lx800); - /* video hardware (simulates paper) */ - screen_device &screen(SCREEN(config, m_screen, SCREEN_TYPE_RASTER)); - screen.set_refresh_hz(60); - screen.set_vblank_time(ATTOSECONDS_IN_USEC(0)); - screen.set_size(PAPER_WIDTH, PAPER_HEIGHT); - screen.set_visarea(0, PAPER_WIDTH-1, 0, PAPER_HEIGHT-1); - screen.set_screen_update(FUNC(epson_lx810l_device::screen_update_lx810l)); - /* audio hardware */ SPEAKER(config, "speaker").front_center(); DAC_1BIT(config, "dac", 0).add_route(ALL_OUTPUTS, "speaker", 0.25); @@ -164,19 +158,21 @@ void epson_lx810l_device::device_add_mconfig(machine_config &config) e05a30.centronics_fault().set(FUNC(epson_lx810l_device::e05a30_centronics_fault)); e05a30.centronics_select().set(FUNC(epson_lx810l_device::e05a30_centronics_select)); e05a30.cpu_reset().set(FUNC(epson_lx810l_device::e05a30_cpu_reset)); + e05a30.ready_led().set(FUNC(epson_lx810l_device::e05a30_ready_led)); /* 256-bit eeprom */ EEPROM_93C06_16BIT(config, "eeprom"); - STEPPER(config, m_pf_stepper, (uint8_t)4); - STEPPER(config, m_cr_stepper, (uint8_t)2); + BITMAP_PRINTER(config, m_bitmap_printer, PAPER_WIDTH, PAPER_HEIGHT, 120, 72); // do 72 dpi + m_bitmap_printer->set_pf_stepper_ratio(1,6); // pf stepper moves at 216 dpi so at 72dpi half steps + m_bitmap_printer->set_cr_stepper_ratio(1,1); } - /*************************************************************************** INPUT PORTS ***************************************************************************/ + static INPUT_PORTS_START( epson_lx810 ) /* Buttons on printer */ PORT_START("ONLINE") @@ -297,20 +293,25 @@ epson_lx810l_device::epson_lx810l_device(const machine_config &mconfig, device_t device_t(mconfig, type, tag, owner, clock), device_centronics_peripheral_interface(mconfig, *this), m_maincpu(*this, "maincpu"), - m_pf_stepper(*this, "pf_stepper"), - m_cr_stepper(*this, "cr_stepper"), + m_bitmap_printer(*this, "bitmap_printer"), m_eeprom(*this, "eeprom"), m_e05a30(*this, "e05a30"), - m_screen(*this, "screen"), m_online_led(*this, "online_led"), + m_ready_led(*this, "ready_led"), + m_online_ioport(*this, "ONLINE"), + m_formfeed_ioport(*this, "FORMFEED"), + m_linefeed_ioport(*this, "LINEFEED"), + m_loadeject_ioport(*this, "LOADEJECT"), + m_paperend_ioport(*this, "PAPEREND"), + m_dipsw1_ioport(*this, "DIPSW1"), + m_dipsw2_ioport(*this, "DIPSW2"), m_93c06_clk(0), m_93c06_cs(0), m_printhead(0), - m_pf_pos_abs(1), - m_cr_pos_abs(1), - m_real_cr_pos(1), m_real_cr_steps(0), - m_real_cr_dir(0), m_fakemem(0) + m_fakemem(0), + m_in_between_offset(0), + m_rightward_offset(-3) { } @@ -326,11 +327,9 @@ epson_ap2000_device::epson_ap2000_device(const machine_config &mconfig, const ch void epson_lx810l_device::device_start() { m_online_led.resolve(); + m_ready_led.resolve(); m_cr_timer = timer_alloc(TIMER_CR); - - m_screen->register_screen_bitmap(m_bitmap); - m_bitmap.fill(0xffffff); /* Start with a clean white piece of paper */ } @@ -340,6 +339,7 @@ void epson_lx810l_device::device_start() void epson_lx810l_device::device_reset() { + m_in_between_offset = 0; } @@ -357,10 +357,11 @@ void epson_lx810l_device::device_timer(emu_timer &timer, device_timer_id id, int * the same period as each half-step (417 microseconds), but with * a 356 microseconds delay relative to the motor steps. */ - m_real_cr_pos += param; + m_in_between_offset += param; + m_real_cr_steps--; if (m_real_cr_steps) - m_cr_timer->adjust(attotime::from_usec(400), m_real_cr_dir); + m_cr_timer->adjust(attotime::from_usec(400), m_bitmap_printer->m_cr_direction); break; } } @@ -398,17 +399,20 @@ void epson_lx810l_device::fakemem_w(uint8_t data) uint8_t epson_lx810l_device::porta_r(offs_t offset) { uint8_t result = 0; - uint8_t hp_sensor = m_real_cr_pos <= 0 ? 0 : 1; // use m_real_cr_pos instead of m_cr_pos_abs (fixes walking carriage on mame soft reset) + uint8_t hp_sensor = (m_bitmap_printer->m_xpos <= 0) ? 0 : 1; + //uint8_t pe_sensor = m_pf_pos_abs <= 0 ? 1 : 0; result |= hp_sensor; /* home position */ //result |= pe_sensor << 1; /* paper end */ - result |= ioport("PAPEREND")->read() << 1; // simulate a paper out error - result |= ioport("LINEFEED")->read() << 6; - result |= ioport("FORMFEED")->read() << 7; + result |= m_paperend_ioport->read() << 1; // simulate a paper out error + result |= m_linefeed_ioport->read() << 6; + result |= m_formfeed_ioport->read() << 7; LOG("%s: lx810l_PA_r(%02x): result %02x\n", machine().describe_context(), offset, result); + m_bitmap_printer->set_led_state(bitmap_printer_device::LED_ERROR, !m_paperend_ioport->read()); + return result; } @@ -429,7 +433,7 @@ void epson_lx810l_device::porta_w(offs_t offset, uint8_t data) */ uint8_t epson_lx810l_device::portb_r(offs_t offset) { - uint8_t result = ~ioport("DIPSW1")->read(); + uint8_t result = ~m_dipsw1_ioport->read(); /* if 93C06 is selected */ if (m_93c06_cs) { @@ -469,7 +473,7 @@ uint8_t epson_lx810l_device::portc_r(offs_t offset) uint8_t result = 0; /* result |= ioport("serial")->read() << 1; */ - result |= !ioport("ONLINE")->read() << 3; + result |= !m_online_ioport->read() << 3; result |= m_93c06_clk << 4; result |= m_93c06_cs << 5; @@ -491,6 +495,7 @@ void epson_lx810l_device::portc_w(offs_t offset, uint8_t data) m_eeprom->cs_write (m_93c06_cs ? ASSERT_LINE : CLEAR_LINE); m_online_led = !BIT(data, 2); + m_bitmap_printer->set_led_state(bitmap_printer_device::LED_ONLINE, m_online_led); } @@ -505,38 +510,20 @@ void epson_lx810l_device::printhead(uint16_t data) void epson_lx810l_device::pf_stepper(uint8_t data) { - int changed = m_pf_stepper->update(data); - m_pf_pos_abs = -m_pf_stepper->get_absolute_position(); - - /* clear last line of paper */ - if (changed > 0) { - void *line = m_bitmap.raw_pixptr(bitmap_line(9), 0); - memset(line, 0xff, m_bitmap.width() * 4); - } - - LOG("%s: %s(%02x); abs %d\n", machine().describe_context(), __func__, data, m_pf_pos_abs); + m_bitmap_printer->update_pf_stepper(data); } void epson_lx810l_device::cr_stepper(uint8_t data) { - int m_cr_pos_abs_prev = m_cr_pos_abs; - - m_cr_stepper->update(data); - m_cr_pos_abs = -m_cr_stepper->get_absolute_position(); + m_bitmap_printer->update_cr_stepper(bitswap<4>(data, 0, 1, 2, 3)); // reverse bits - if (m_cr_pos_abs > m_cr_pos_abs_prev) { - /* going right */ - m_real_cr_dir = 1; - } else { - /* going left */ - m_real_cr_dir = -1; - } + m_in_between_offset = 0; if (!m_real_cr_steps) - m_cr_timer->adjust(attotime::from_usec(400), m_real_cr_dir); - m_real_cr_steps++; - - LOG("%s: %s(%02x); abs %d\n", machine().describe_context(), __func__, data, m_cr_pos_abs); + { + m_cr_timer->adjust(attotime::from_usec(400), m_bitmap_printer->m_cr_direction); + m_real_cr_steps++; + } } WRITE_LINE_MEMBER( epson_lx810l_device::e05a30_ready ) @@ -546,24 +533,6 @@ WRITE_LINE_MEMBER( epson_lx810l_device::e05a30_ready ) } -/*************************************************************************** - Video hardware (simulates paper) -***************************************************************************/ - -uint32_t epson_lx810l_device::screen_update_lx810l(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) -{ - int scrolly = -bitmap_line(9); - copyscrollbitmap(bitmap, m_bitmap, 0, nullptr, 1, &scrolly, cliprect); - - /* draw "printhead" */ - int bordersize = 1; - bitmap.plot_box(m_real_cr_pos + CR_OFFSET - 10 - bordersize, PAPER_HEIGHT - 36 - bordersize, 20 + bordersize * 2, 36 + bordersize * 2, 0x000000 ); - bitmap.plot_box(m_real_cr_pos + CR_OFFSET - 10, PAPER_HEIGHT - 36, 20, 36, m_e05a30->ready_led() ? 0x55ff55 : 0x337733 ); - - return 0; -} - - /*************************************************************************** Extended Timer Output ***************************************************************************/ @@ -583,11 +552,13 @@ WRITE_LINE_MEMBER( epson_lx810l_device::co0_w ) * lines which are being printed in different directions is * noticeably off in the 20+ years old printer used for testing =). */ - if (m_real_cr_pos < m_bitmap.width()) { - for (int i = 0; i < 9; i++) { - unsigned int const y = bitmap_line(i); + if (m_bitmap_printer->m_xpos < m_bitmap_printer->m_page_bitmap.width()) { + for (int i = 0; i < 9; i++) + { if ((m_printhead & (1<<(8-i))) != 0) - m_bitmap.pix(y, m_real_cr_pos + CR_OFFSET) = 0x000000; + m_bitmap_printer->pix(m_bitmap_printer->m_ypos + i * 1, // * 1 for no interleave at 72 vdpi + m_bitmap_printer->m_xpos + CR_OFFSET + m_in_between_offset + + (m_bitmap_printer->m_cr_direction > 0 ? m_rightward_offset : 0)) = 0x000000; } } } @@ -600,25 +571,25 @@ WRITE_LINE_MEMBER( epson_lx810l_device::co0_w ) uint8_t epson_lx810l_device::an0_r() { - uint8_t res = !!(ioport("DIPSW2")->read() & 0x01); + uint8_t res = !!(m_dipsw2_ioport->read() & 0x01); return res - 1; /* DIPSW2.1 */ } uint8_t epson_lx810l_device::an1_r() { - uint8_t res = !!(ioport("DIPSW2")->read() & 0x02); + uint8_t res = !!(m_dipsw2_ioport->read() & 0x02); return res - 1; /* DIPSW2.2 */ } uint8_t epson_lx810l_device::an2_r() { - uint8_t res = !!(ioport("DIPSW2")->read() & 0x04); + uint8_t res = !!(m_dipsw2_ioport->read() & 0x04); return res - 1; /* DIPSW2.3 */ } uint8_t epson_lx810l_device::an3_r() { - uint8_t res = !!(ioport("DIPSW2")->read() & 0x08); + uint8_t res = !!(m_dipsw2_ioport->read() & 0x08); return res - 1; /* DIPSW2.4 */ } @@ -634,7 +605,7 @@ uint8_t epson_lx810l_device::an5_r() uint8_t epson_lx810l_device::an6_r() { - uint8_t res = !ioport("LOADEJECT")->read(); + uint8_t res = !m_loadeject_ioport->read(); return res - 1; } diff --git a/src/devices/bus/centronics/epson_lx810l.h b/src/devices/bus/centronics/epson_lx810l.h index 0e1c67df624..1ad845f0128 100644 --- a/src/devices/bus/centronics/epson_lx810l.h +++ b/src/devices/bus/centronics/epson_lx810l.h @@ -13,6 +13,7 @@ #include "cpu/upd7810/upd7810.h" #include "machine/e05a30.h" #include "machine/eepromser.h" +#include "machine/bitmap_printer.h" #include "machine/steppers.h" #include "sound/dac.h" #include "screen.h" @@ -105,32 +106,37 @@ private: DECLARE_WRITE_LINE_MEMBER(e05a30_cpu_reset) { if (!state) m_maincpu->pulse_input_line(INPUT_LINE_RESET, attotime::zero); } // reset cpu - void lx810l_mem(address_map &map); - - /* Video hardware (simulates paper) */ - uint32_t screen_update_lx810l(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + DECLARE_WRITE_LINE_MEMBER(e05a30_ready_led) + { + m_ready_led = state; + m_bitmap_printer->set_led_state(bitmap_printer_device::LED_READY, m_ready_led); + } - unsigned int bitmap_line(int i) { return ((std::abs(m_pf_pos_abs) / 6) + i) % m_bitmap.height(); } + void lx810l_mem(address_map &map); required_device m_maincpu; - required_device m_pf_stepper; - required_device m_cr_stepper; + required_device m_bitmap_printer; required_device m_eeprom; required_device m_e05a30; - required_device m_screen; output_finder<> m_online_led; + output_finder<> m_ready_led; + + required_ioport m_online_ioport; + required_ioport m_formfeed_ioport; + required_ioport m_linefeed_ioport; + required_ioport m_loadeject_ioport; + required_ioport m_paperend_ioport; + required_ioport m_dipsw1_ioport; + required_ioport m_dipsw2_ioport; int m_93c06_clk; int m_93c06_cs; uint16_t m_printhead; - int m_pf_pos_abs; - int m_cr_pos_abs; - int m_real_cr_pos; int m_real_cr_steps; - int m_real_cr_dir; /* 1 is going right, -1 is going left */ uint8_t m_fakemem; - bitmap_rgb32 m_bitmap; + int m_in_between_offset; // in between cr_stepper phases + int m_rightward_offset; // offset pixels when stepper moving rightward enum { TIMER_CR diff --git a/src/devices/machine/bitmap_printer.cpp b/src/devices/machine/bitmap_printer.cpp new file mode 100644 index 00000000000..c0b5e4780de --- /dev/null +++ b/src/devices/machine/bitmap_printer.cpp @@ -0,0 +1,443 @@ +// license:BSD-3-Clause +// copyright-holders: Golden Child +/********************************************************************* + + bitmap_printer.cpp + + Implementation of Bitmap Printer + +**********************************************************************/ + +#include "emu.h" +#include "video.h" +#include "screen.h" +#include "emuopts.h" +#include "fileio.h" +#include "png.h" +#include "bitmap_printer.h" +#include "corestr.h" + +/*************************************************************************** + DEVICE DECLARATION +***************************************************************************/ + +DEFINE_DEVICE_TYPE(BITMAP_PRINTER, bitmap_printer_device, "bitmap_printer", "Bitmap Printer Device") + +//************************************************************************** +// INPUT PORTS +//************************************************************************** + +#define PORT_ADJUSTER_16MASK(_default, _name) \ + configurer.field_alloc(IPT_ADJUSTER, (_default), 0xffff, (_name)); \ + configurer.field_set_min_max(0, 100); + +INPUT_PORTS_START(bitmap_printer) + PORT_START("DRAWMARKS") + PORT_CONFNAME(0x3, 0x02, "Draw Inch Marks") + PORT_CONFSETTING(0x0, "Off") + PORT_CONFSETTING(0x1, "with marks") + PORT_CONFSETTING(0x2, "with numbers") + + PORT_START("TOPMARGIN") + PORT_ADJUSTER_16MASK(18, "Printer Top Margin") + PORT_MINMAX(0,500) + + PORT_START("BOTTOMMARGIN") + PORT_ADJUSTER_16MASK(18, "Printer Bottom Margin") + PORT_MINMAX(0,500) + +INPUT_PORTS_END + + +ioport_constructor bitmap_printer_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(bitmap_printer); +} + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void bitmap_printer_device::device_add_mconfig(machine_config &config) +{ + // video hardware (simulates paper) + screen_device &screen(SCREEN(config, m_screen, SCREEN_TYPE_RASTER)); + screen.set_refresh_hz(60); + screen.set_vblank_time(ATTOSECONDS_IN_USEC(0)); + screen.set_size(m_paper_width, PAPER_SCREEN_HEIGHT); + screen.set_visarea(0, m_paper_width - 1, 0, PAPER_SCREEN_HEIGHT - 1); + screen.set_screen_update(FUNC(bitmap_printer_device::screen_update_bitmap)); + + STEPPER(config, m_pf_stepper, (uint8_t) 0xa); + STEPPER(config, m_cr_stepper, (uint8_t) 0xa); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +bitmap_printer_device::bitmap_printer_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, type, tag, owner, clock), + m_screen(*this, "screen"), + m_pf_stepper(*this, "pf_stepper"), + m_cr_stepper(*this, "cr_stepper"), + m_top_margin_ioport(*this, "TOPMARGIN"), + m_bottom_margin_ioport(*this, "BOTTOMMARGIN"), + m_draw_marks_ioport(*this, "DRAWMARKS"), + m_cr_direction(1), + m_pf_stepper_ratio0(1), + m_pf_stepper_ratio1(1), + m_cr_stepper_ratio0(1), + m_cr_stepper_ratio1(1), + m_xpos(0), + m_ypos(0), + m_printhead_color(0x00EE00), + m_printhead_bordercolor(0xEE0000), + m_printhead_bordersize(2), + m_printhead_xsize(10), + m_printhead_ysize(20), + m_page_dirty(0), + m_paper_width(0), + m_paper_height(0), + m_hdpi(0), + m_vdpi(0), + m_clear_pos(0), + m_newpage_flag(0), + m_led_state{0,1,1,1,1}, + m_num_leds(1) +{ +} + +bitmap_printer_device::bitmap_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + bitmap_printer_device(mconfig, BITMAP_PRINTER, tag, owner, clock) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void bitmap_printer_device::device_start() +{ + m_page_bitmap.allocate(m_paper_width, m_paper_height); + m_page_bitmap.fill(0xffffff); // Start with a white piece of paper + + save_item(NAME(m_page_bitmap)); + save_item(NAME(m_xpos)); + save_item(NAME(m_ypos)); + save_item(NAME(m_cr_direction)); + save_item(NAME(m_pf_stepper_ratio0)); + save_item(NAME(m_pf_stepper_ratio1)); + save_item(NAME(m_cr_stepper_ratio0)); + save_item(NAME(m_cr_stepper_ratio1)); + save_item(NAME(m_printhead_color)); + save_item(NAME(m_printhead_bordercolor)); + save_item(NAME(m_printhead_bordersize)); + save_item(NAME(m_printhead_xsize)); + save_item(NAME(m_printhead_ysize)); + save_item(NAME(m_page_dirty)); + save_item(NAME(m_paper_width)); + save_item(NAME(m_paper_height)); + save_item(NAME(m_hdpi)); + save_item(NAME(m_vdpi)); + save_item(NAME(m_clear_pos)); + save_item(NAME(m_newpage_flag)); +} + +void bitmap_printer_device::device_reset_after_children() +{ + m_ypos = get_top_margin(); +} + +void bitmap_printer_device::device_reset() +{ +} + +//------------------------------------------------- +// SCREEN UPDATE FUNCTIONS +//------------------------------------------------- + +int bitmap_printer_device::calc_scroll_y(bitmap_rgb32& bitmap) +{ + return bitmap.height() - m_distfrombottom - m_ypos; +} + +uint32_t bitmap_printer_device::screen_update_bitmap(screen_device &screen, + bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + static constexpr u32 top_edge_color = 0xEEE8AA; + static constexpr u32 bottom_edge_color = 0xEE8844; + static constexpr u32 coverup_color = 0xDDDDDD; + + int scrolly = calc_scroll_y(bitmap); + + copyscrollbitmap(bitmap, m_page_bitmap, 0, nullptr, 1, &scrolly, cliprect); + + // draw a line on the very top of the top edge of page + bitmap.plot_box(0, bitmap.height() - m_distfrombottom - m_ypos, m_paper_width, 2, top_edge_color); + // draw a line on the bottom edge of page + bitmap.plot_box(0, bitmap.height() - m_distfrombottom - m_ypos + m_paper_height, m_paper_width, 2, bottom_edge_color); + // cover up visible parts of current page at the bottom + bitmap.plot_box(0, bitmap.height() - m_distfrombottom - m_ypos + m_paper_height + 2, m_paper_width, m_distfrombottom, coverup_color); + + draw_printhead(bitmap, std::max(m_xpos, 0) , bitmap.height() - m_distfrombottom); + + draw_inch_marks(bitmap); + + return 0; +} + +//------------------------------------------------- +// BITMAP CLEARING FUNCTIONS +//------------------------------------------------- + +void bitmap_printer_device::clear_to_pos(int to_line, u32 color) +{ + int from_line = m_clear_pos; + to_line = std::min(m_page_bitmap.height(), to_line); + if (to_line >= from_line) + { + bitmap_clear_band(m_page_bitmap, from_line, to_line, color); + } + m_clear_pos = std::max(m_clear_pos, to_line + 1); +} + +void bitmap_printer_device::bitmap_clear_band(int from_line, int to_line, u32 color) +{ + bitmap_clear_band(m_page_bitmap, from_line, to_line, color); +} + +void bitmap_printer_device::bitmap_clear_band(bitmap_rgb32 &bitmap, int from_line, int to_line, u32 color) +{ + bitmap.plot_box(0, from_line, m_paper_width, to_line - from_line + 1, color); +} + +//------------------------------------------------- +// PRINTHEAD FUNCTIONS +//------------------------------------------------- + +void bitmap_printer_device::set_printhead_color(int headcolor, int bordcolor) +{ + m_printhead_color = headcolor; + m_printhead_bordercolor = bordcolor; +} + +void bitmap_printer_device::set_printhead_size(int xsize, int ysize, int bordersize) +{ + m_printhead_xsize = xsize; + m_printhead_ysize = ysize; + m_printhead_bordersize = bordersize; +} + +u32 bitmap_printer_device::dimcolor(u32 incolor, int factor) +{ + return (((incolor & 0xff0000) >> 16) / factor << 16) | + (((incolor & 0xff00) >> 8) / factor << 8) | + (((incolor & 0xff) >> 0) / factor); +} + +void bitmap_printer_device::draw_printhead(bitmap_rgb32 &bitmap, int x, int y) +{ + int bordx = m_printhead_bordersize; + int bordy = m_printhead_bordersize; + int offy = 9 + bordy; + int sizex = m_printhead_xsize; + int sizey = m_printhead_ysize; + bitmap.plot_box(x - sizex / 2- bordx, y + offy - bordy, sizex + 2 * bordx, sizey + bordy * 2, + m_led_state[0] ? m_printhead_bordercolor : dimcolor(m_printhead_bordercolor, 4)); + + for (int i = 1; i <= m_num_leds; i++) + bitmap.plot_box(x - sizex / 2, y + offy + ((i -1) * sizey / m_num_leds), sizex, + ((i+1) * sizey / m_num_leds) - (i * sizey / m_num_leds), + m_led_state[i] ? m_printhead_color : dimcolor(m_printhead_color, 4)); +} + +//------------------------------------------------- +// DRAW INCH MARKS AND NUMBERS +//------------------------------------------------- + +void bitmap_printer_device::draw7seg(u8 data, bool is_digit, int x0, int y0, int width, int height, int thick, bitmap_rgb32 &bitmap, u32 color, u32 erasecolor) +{ + // pass nonzero erasecolor to erase blank segments + const u8 pat[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71 }; + u8 seg = is_digit ? pat[data & 0xf] : data; + + if (BIT(seg,0) || erasecolor) bitmap.plot_box(x0, y0, width, thick, BIT(seg,0) ? color : erasecolor); + if (BIT(seg,1) || erasecolor) bitmap.plot_box(x0+width, y0+thick, thick, height, BIT(seg,1) ? color : erasecolor); + if (BIT(seg,2) || erasecolor) bitmap.plot_box(x0+width, y0+2*thick+height, thick, height, BIT(seg,2) ? color : erasecolor); + if (BIT(seg,3) || erasecolor) bitmap.plot_box(x0, y0+2*thick+2*height, width, thick, BIT(seg,3) ? color : erasecolor); + if (BIT(seg,4) || erasecolor) bitmap.plot_box(x0-thick, y0+2*thick+height, thick, height, BIT(seg,4) ? color : erasecolor); + if (BIT(seg,5) || erasecolor) bitmap.plot_box(x0-thick, y0+thick, thick, height, BIT(seg,5) ? color : erasecolor); + if (BIT(seg,6) || erasecolor) bitmap.plot_box(x0, y0+thick+height, width, thick, BIT(seg,6) ? color : erasecolor); + if (BIT(seg,7) || erasecolor) bitmap.plot_box(x0+width+thick, y0+2*thick+2*height, thick, thick, BIT(seg,7) ? color : erasecolor); // draw dot +} + +void bitmap_printer_device::draw_number(int number, int x, int y, bitmap_rgb32& bitmap) +{ + std::string s(std::to_string(number)); + + int width = std::max(m_hdpi / 15, 1); // 1/10 of inch + int height = std::max(m_vdpi / 30, 1); + int thick = std::max(m_vdpi / 72, 1); + + for (int i = s.length() - 1; i >= 0; i--) + draw7seg( s.at(i) - 0x30, true, + x + ( i - s.length()) * (3 * width) - (width), y + height * 3 / 2, + width, height, thick, bitmap, 0x000000, 0); +} + +void bitmap_printer_device::draw_inch_marks(bitmap_rgb32& bitmap) +{ + static constexpr u32 dark_grey_color = 0x202020; + static constexpr u32 light_grey_color = 0xc0c0c0; + + int drawmarks = m_draw_marks_ioport->read(); + if (!drawmarks) return; + + for (int i = 0; i < m_vdpi * 11; i += m_vdpi / 4) + { + int adj_i = i + calc_scroll_y(bitmap) % m_paper_height; + int barbase = m_vdpi / 6; + int barwidth = ((i % m_vdpi) == 0) ? barbase * 2 : barbase; + int barcolor = ((i % m_vdpi) == 0) ? dark_grey_color : light_grey_color; + if (adj_i < bitmap.height()) + { + bitmap.plot_box(bitmap.width() - 1 - barwidth, adj_i, barwidth, 1, barcolor); + if ((i % m_vdpi) == 0) + { + if (drawmarks & 2) + draw_number(i / m_vdpi, bitmap.width(), adj_i, bitmap); + } + } + } +} + +//------------------------------------------------- +// DRAW PIXEL FUNCTIONS +//------------------------------------------------- + +void bitmap_printer_device::draw_pixel(int x, int y, int pixelval) +{ + if (y >= m_page_bitmap.height()) y = m_page_bitmap.height() - 1; + if (x >= m_page_bitmap.width()) x = m_page_bitmap.width() - 1; + + m_page_bitmap.pix(y, x) = pixelval; + + m_page_dirty = 1; +}; + +int bitmap_printer_device::get_pixel(int x, int y) +{ + if (y >= m_page_bitmap.height()) y = m_page_bitmap.height() - 1; + if (x >= m_page_bitmap.width()) x = m_page_bitmap.width() - 1; + + return m_page_bitmap.pix(y, x); +}; + +unsigned int& bitmap_printer_device::pix(int y, int x) // reversed y x +{ + if (y >= m_page_bitmap.height()) y = m_page_bitmap.height() - 1; + if (x >= m_page_bitmap.width()) x = m_page_bitmap.width() - 1; + + return m_page_bitmap.pix(y,x); +}; + +//------------------------------------------------- +// WRITE SNAPSHOT TO FILE +//------------------------------------------------- + +void bitmap_printer_device::write_snapshot_to_file() +{ + machine().popmessage("writing printer snapshot"); + + emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + std::error_condition const filerr = machine().video().open_next(file, "png"); + + if (!filerr) + { + static const rgb_t png_palette[] = { rgb_t::white(), rgb_t::black() }; + + // save the paper into a png + util::png_write_bitmap(file, nullptr, m_page_bitmap, 2, png_palette); + } +} + +//------------------------------------------------- +// STEPPER AND MARGIN FUNCTIONS +//------------------------------------------------- + +int bitmap_printer_device::get_top_margin() { return m_top_margin_ioport->read(); } +int bitmap_printer_device::get_bottom_margin() { return m_bottom_margin_ioport->read(); } + +bool bitmap_printer_device::check_new_page() +{ + bool retval = false; + + // idea here is that you update the position, then check the page, this will do the saving of the page + // if this routine returns true, means there's a new page and you should clear the yposition + if (m_newpage_flag == 1) + { + // if you change m_ypos you have to change the stepper abs position too + m_ypos = get_top_margin(); // lock to the top of page until we seek horizontally + m_pf_stepper->set_absolute_position(get_top_margin() / m_pf_stepper_ratio0 * m_pf_stepper_ratio1); + } + if (m_ypos > m_page_bitmap.height() - 1 - get_bottom_margin()) + // If we are at the bottom of the page we will + // write the page to a file, then erase the top part of the page + // so we can still see the last page printed. + { + // clear paper to bottom from current position + clear_to_pos(m_paper_height - 1, rgb_t::white()); + + // save a snapshot + write_snapshot_to_file(); + + m_newpage_flag = 1; + + // clear page down to visible area, starting from the top of page + m_clear_pos = 0; + clear_to_pos(m_paper_height - 1 - PAPER_SCREEN_HEIGHT), + + m_ypos = get_top_margin(); // lock to the top of page until we seek horizontally + m_pf_stepper->set_absolute_position(get_top_margin() / m_pf_stepper_ratio0 * m_pf_stepper_ratio1); + retval = true; + } + else { clear_to_pos ( m_ypos + m_distfrombottom); } + return retval; +} + +int bitmap_printer_device::update_stepper_delta(stepper_device * stepper, uint8_t pattern) +{ + int lastpos = stepper->get_absolute_position(); + stepper->update(pattern); + int delta = stepper->get_absolute_position() - lastpos; + return delta; +} + +// When sending patterns to the update_cr_stepper and update_pf_stepper +// functions, the stepper device uses a "standard drive table" +// so you have to match that drive table by using a bitswap function. +// If the stepper drive is in the opposite direction, just reverse the +// bits in the bitswap. + +void bitmap_printer_device::update_cr_stepper(int pattern) +{ + int delta = update_stepper_delta(m_cr_stepper, pattern); + + if (delta != 0) + { + m_newpage_flag = 0; + + if (delta > 0) {m_cr_direction = 1;} + else if (delta < 0) {m_cr_direction = -1;} + } + m_xpos = m_cr_stepper->get_absolute_position() * m_cr_stepper_ratio0 / m_cr_stepper_ratio1; +} + +void bitmap_printer_device::update_pf_stepper(int pattern) +{ + update_stepper_delta(m_pf_stepper, pattern); + m_ypos = m_pf_stepper->get_absolute_position() * m_pf_stepper_ratio0 / m_pf_stepper_ratio1; + check_new_page(); +} + diff --git a/src/devices/machine/bitmap_printer.h b/src/devices/machine/bitmap_printer.h new file mode 100644 index 00000000000..637a6b3a26f --- /dev/null +++ b/src/devices/machine/bitmap_printer.h @@ -0,0 +1,130 @@ +// license:BSD-3-Clause +// copyright-holders: Golden Child +/* + bitmap printer (dot printer) + + * provides a page bitmap to draw on + * reads and writes pixels (representing printer dots) + * function to save the bitmap + * updates the bitmap to screen and draws the printhead + * printhead position given in m_xpos and m_ypos + * also provides a cr_stepper and a pf_stepper + * moving the cr_stepper/pf_stepper will update m_xpos/m_ypos according to ratio specified + + */ + +#include "screen.h" +#include "machine/steppers.h" + +#ifndef MAME_MACHINE_BITMAP_PRINTER_H +#define MAME_MACHINE_BITMAP_PRINTER_H + +#pragma once + +class bitmap_printer_device : public device_t +{ +public: + bitmap_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + bitmap_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, int paper_width, int paper_height, int hdpi, int vdpi) : + bitmap_printer_device(mconfig, tag, owner, u32(0)) + { + m_paper_width = paper_width; + m_paper_height = paper_height; + m_hdpi = hdpi; + m_vdpi = vdpi; + } + +protected: + bitmap_printer_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_reset_after_children() override; + virtual ioport_constructor device_input_ports() const override; + virtual void device_add_mconfig(machine_config &config) override; + +private: + required_device m_screen; +public: + required_device m_pf_stepper; + required_device m_cr_stepper; + + required_ioport m_top_margin_ioport; + required_ioport m_bottom_margin_ioport; + required_ioport m_draw_marks_ioport; + int m_cr_direction; // direction of carriage + int m_pf_stepper_ratio0; + int m_pf_stepper_ratio1; + int m_cr_stepper_ratio0; + int m_cr_stepper_ratio1; + int m_xpos; + int m_ypos; + + bitmap_rgb32 m_page_bitmap; // page bitmap +private: + static constexpr int PAPER_SCREEN_HEIGHT = 384; // match the height of the apple II driver + static constexpr int m_distfrombottom = 50; // print position from bottom of screen + + int m_printhead_color; + int m_printhead_bordercolor; + int m_printhead_bordersize; + int m_printhead_xsize; + int m_printhead_ysize; + int m_page_dirty; + int m_paper_width; + int m_paper_height; + int m_hdpi; + int m_vdpi; + int m_clear_pos; + int m_newpage_flag; // used to keep printhead at the top of page until actual printing + static constexpr int MAX_LEDS = 5; + int m_led_state[MAX_LEDS]; + int m_num_leds; + +public: + + enum { LED_ERROR, LED_READY, LED_ONLINE }; + + void set_led_state(int led, int value) { m_led_state[led] = value; m_num_leds = std::max(m_num_leds, led); } + void set_printhead_color(int headcolor, int bordcolor); + void set_printhead_size(int xsize, int ysize, int bordersize); + void setheadpos(int x, int y){ if (m_xpos != x) m_newpage_flag = 0; m_xpos = x; m_ypos = y;} + + void write_snapshot_to_file(); + + void draw_pixel(int x, int y, int pixelval); + int get_pixel(int x, int y); + unsigned int& pix(int y, int x); + + void bitmap_clear_band(bitmap_rgb32 &bitmap, int from_line, int to_line, u32 color); + void bitmap_clear_band(int from_line, int to_line, u32 color); + void clear_to_pos(int to_line, u32 color = 0xffffff); + + int get_top_margin(); + int get_bottom_margin(); + bool check_new_page(); + + int update_stepper_delta(stepper_device * stepper, uint8_t pattern); + void update_cr_stepper(int pattern); + void update_pf_stepper(int pattern); + + void set_pf_stepper_ratio(int ratio0, int ratio1) { m_pf_stepper_ratio0 = ratio0; m_pf_stepper_ratio1 = ratio1;} + void set_cr_stepper_ratio(int ratio0, int ratio1) { m_cr_stepper_ratio0 = ratio0; m_cr_stepper_ratio1 = ratio1;} + +private: + void draw_printhead(bitmap_rgb32 &bitmap, int x, int y); + u32 dimcolor(u32 incolor, int factor); + + int calc_scroll_y(bitmap_rgb32& bitmap); + uint32_t screen_update_bitmap(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + void draw7seg(u8 data, bool is_digit, int x0, int y0, int width, int height, int thick, bitmap_rgb32 &bitmap, u32 color, u32 erasecolor); + void draw_number(int number, int x, int y, bitmap_rgb32& bitmap); + void draw_inch_marks(bitmap_rgb32& bitmap); +}; + +DECLARE_DEVICE_TYPE(BITMAP_PRINTER, bitmap_printer_device) + +#endif // MAME_MACHINE_BITMAP_PRINTER_H diff --git a/src/devices/machine/e05a30.cpp b/src/devices/machine/e05a30.cpp index 650f6a28c97..44d90904644 100644 --- a/src/devices/machine/e05a30.cpp +++ b/src/devices/machine/e05a30.cpp @@ -30,6 +30,7 @@ e05a30_device::e05a30_device(const machine_config &mconfig, const char *tag, dev m_write_centronics_fault(*this), m_write_centronics_select(*this), m_write_cpu_reset(*this), + m_write_ready_led(*this), m_printhead(0), m_pf_stepper(0), m_cr_stepper(0), m_centronics_data(0), m_centronics_busy(0), m_centronics_nack(0), m_centronics_init(1), m_centronics_strobe(0), m_centronics_data_latch(0), m_centronics_data_latched(0) @@ -53,6 +54,7 @@ void e05a30_device::device_start() m_write_centronics_fault.resolve_safe(); m_write_centronics_select.resolve_safe(); m_write_cpu_reset.resolve_safe(); + m_write_ready_led.resolve_safe(); /* register for state saving */ save_item(NAME(m_printhead)); @@ -74,6 +76,7 @@ void e05a30_device::device_reset() /* centronics init */ m_centronics_nack = false; m_centronics_busy = false; + m_write_ready_led(get_ready_led()); m_write_centronics_ack (!m_centronics_nack); m_write_centronics_busy ( m_centronics_busy); m_write_centronics_perror(false); @@ -154,6 +157,7 @@ WRITE_LINE_MEMBER( e05a30_device::centronics_input_strobe ) m_centronics_data_latched = true; m_centronics_busy = true; + m_write_ready_led(get_ready_led()); m_write_centronics_busy(m_centronics_busy); } @@ -201,13 +205,17 @@ void e05a30_device::write(offs_t offset, uint8_t data) case 0x04: m_centronics_nack = BIT(data,5); m_centronics_busy = BIT(data,0); + m_write_ready_led(get_ready_led()); /* The ActionPrinter 2000 firmware might overwrite the busy signal at * address 20AB if the host depends only on the busy signal and * doesn't wait for the ack pulse. To avoid skipping input data, we * assume the busy signal cannot be reset while the data hasn't been * read. */ if (m_centronics_data_latched) + { m_centronics_busy = true; + m_write_ready_led(get_ready_led()); + } m_write_centronics_ack (!m_centronics_nack); m_write_centronics_busy( m_centronics_busy); break; diff --git a/src/devices/machine/e05a30.h b/src/devices/machine/e05a30.h index 6b5b5e7cf96..41bd94d999d 100644 --- a/src/devices/machine/e05a30.h +++ b/src/devices/machine/e05a30.h @@ -25,6 +25,7 @@ public: auto centronics_fault() { return m_write_centronics_fault.bind(); } auto centronics_select() { return m_write_centronics_select.bind(); } auto cpu_reset() { return m_write_cpu_reset.bind(); } + auto ready_led() { return m_write_ready_led.bind(); } void write(offs_t offset, uint8_t data); uint8_t read(offs_t offset); @@ -41,7 +42,7 @@ public: DECLARE_WRITE_LINE_MEMBER( centronics_input_data6 ) { if (state) m_centronics_data |= 0x40; else m_centronics_data &= ~0x40; } DECLARE_WRITE_LINE_MEMBER( centronics_input_data7 ) { if (state) m_centronics_data |= 0x80; else m_centronics_data &= ~0x80; } - int ready_led() { return !m_centronics_busy; } + int get_ready_led() { return !m_centronics_busy; } protected: // device-level overrides @@ -60,6 +61,7 @@ private: devcb_write_line m_write_centronics_fault; devcb_write_line m_write_centronics_select; devcb_write_line m_write_cpu_reset; + devcb_write_line m_write_ready_led; void update_printhead(int pos, uint8_t data); void update_pf_stepper(uint8_t data); diff --git a/src/devices/machine/steppers.h b/src/devices/machine/steppers.h index fac2a8e129c..53317c37e71 100644 --- a/src/devices/machine/steppers.h +++ b/src/devices/machine/steppers.h @@ -69,6 +69,8 @@ public: int get_position() { return m_step_pos; } /* get current absolute position in half steps */ int get_absolute_position() { return m_abs_step_pos; } + /* set absolute position in half steps */ + void set_absolute_position(int pos) { m_abs_step_pos = pos; } /* get maximum position in half steps */ int get_max() { return m_max_steps; } -- cgit v1.2.3