Adding bitmap_printer_device and convert epson_lx810 to use it. (#8863)

This commit is contained in:
goldnchild 2022-01-07 12:07:58 -08:00 committed by GitHub
parent fd73621285
commit c21bea828d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 671 additions and 97 deletions

View File

@ -4911,3 +4911,14 @@ if (MACHINES["GLUKRS"]~=null) then
MAME_DIR .. "src/devices/machine/glukrs.h", MAME_DIR .. "src/devices/machine/glukrs.h",
} }
end 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

View File

@ -829,6 +829,7 @@ MACHINES["BL_HANDHELDS_MENUCONTROL"] = true
MACHINES["NS32081"] = true MACHINES["NS32081"] = true
MACHINES["NS32202"] = true MACHINES["NS32202"] = true
MACHINES["NS32082"] = true MACHINES["NS32082"] = true
MACHINES["BITMAP_PRINTER"] = true
-------------------------------------------------- --------------------------------------------------
-- specify available bus cores -- specify available bus cores

View File

@ -42,8 +42,10 @@
* an offset must be used to centralize the pixels. * an offset must be used to centralize the pixels.
*/ */
#define CR_OFFSET (-14) #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); // 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 */ /* audio hardware */
SPEAKER(config, "speaker").front_center(); SPEAKER(config, "speaker").front_center();
DAC_1BIT(config, "dac", 0).add_route(ALL_OUTPUTS, "speaker", 0.25); 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_fault().set(FUNC(epson_lx810l_device::e05a30_centronics_fault));
e05a30.centronics_select().set(FUNC(epson_lx810l_device::e05a30_centronics_select)); e05a30.centronics_select().set(FUNC(epson_lx810l_device::e05a30_centronics_select));
e05a30.cpu_reset().set(FUNC(epson_lx810l_device::e05a30_cpu_reset)); 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 */ /* 256-bit eeprom */
EEPROM_93C06_16BIT(config, "eeprom"); EEPROM_93C06_16BIT(config, "eeprom");
STEPPER(config, m_pf_stepper, (uint8_t)4); BITMAP_PRINTER(config, m_bitmap_printer, PAPER_WIDTH, PAPER_HEIGHT, 120, 72); // do 72 dpi
STEPPER(config, m_cr_stepper, (uint8_t)2); 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 INPUT PORTS
***************************************************************************/ ***************************************************************************/
static INPUT_PORTS_START( epson_lx810 ) static INPUT_PORTS_START( epson_lx810 )
/* Buttons on printer */ /* Buttons on printer */
PORT_START("ONLINE") 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_t(mconfig, type, tag, owner, clock),
device_centronics_peripheral_interface(mconfig, *this), device_centronics_peripheral_interface(mconfig, *this),
m_maincpu(*this, "maincpu"), m_maincpu(*this, "maincpu"),
m_pf_stepper(*this, "pf_stepper"), m_bitmap_printer(*this, "bitmap_printer"),
m_cr_stepper(*this, "cr_stepper"),
m_eeprom(*this, "eeprom"), m_eeprom(*this, "eeprom"),
m_e05a30(*this, "e05a30"), m_e05a30(*this, "e05a30"),
m_screen(*this, "screen"),
m_online_led(*this, "online_led"), 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_clk(0),
m_93c06_cs(0), m_93c06_cs(0),
m_printhead(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_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() void epson_lx810l_device::device_start()
{ {
m_online_led.resolve(); m_online_led.resolve();
m_ready_led.resolve();
m_cr_timer = timer_alloc(TIMER_CR); 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() 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 * the same period as each half-step (417 microseconds), but with
* a 356 microseconds delay relative to the motor steps. * a 356 microseconds delay relative to the motor steps.
*/ */
m_real_cr_pos += param; m_in_between_offset += param;
m_real_cr_steps--; m_real_cr_steps--;
if (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; 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 epson_lx810l_device::porta_r(offs_t offset)
{ {
uint8_t result = 0; 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; //uint8_t pe_sensor = m_pf_pos_abs <= 0 ? 1 : 0;
result |= hp_sensor; /* home position */ result |= hp_sensor; /* home position */
//result |= pe_sensor << 1; /* paper end */ //result |= pe_sensor << 1; /* paper end */
result |= ioport("PAPEREND")->read() << 1; // simulate a paper out error result |= m_paperend_ioport->read() << 1; // simulate a paper out error
result |= ioport("LINEFEED")->read() << 6; result |= m_linefeed_ioport->read() << 6;
result |= ioport("FORMFEED")->read() << 7; result |= m_formfeed_ioport->read() << 7;
LOG("%s: lx810l_PA_r(%02x): result %02x\n", machine().describe_context(), offset, result); 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; 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 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 93C06 is selected */
if (m_93c06_cs) { if (m_93c06_cs) {
@ -469,7 +473,7 @@ uint8_t epson_lx810l_device::portc_r(offs_t offset)
uint8_t result = 0; uint8_t result = 0;
/* result |= ioport("serial")->read() << 1; */ /* result |= ioport("serial")->read() << 1; */
result |= !ioport("ONLINE")->read() << 3; result |= !m_online_ioport->read() << 3;
result |= m_93c06_clk << 4; result |= m_93c06_clk << 4;
result |= m_93c06_cs << 5; 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_eeprom->cs_write (m_93c06_cs ? ASSERT_LINE : CLEAR_LINE);
m_online_led = !BIT(data, 2); 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) void epson_lx810l_device::pf_stepper(uint8_t data)
{ {
int changed = m_pf_stepper->update(data); m_bitmap_printer->update_pf_stepper(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);
} }
void epson_lx810l_device::cr_stepper(uint8_t data) void epson_lx810l_device::cr_stepper(uint8_t data)
{ {
int m_cr_pos_abs_prev = m_cr_pos_abs; m_bitmap_printer->update_cr_stepper(bitswap<4>(data, 0, 1, 2, 3)); // reverse bits
m_cr_stepper->update(data); m_in_between_offset = 0;
m_cr_pos_abs = -m_cr_stepper->get_absolute_position();
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;
}
if (!m_real_cr_steps) if (!m_real_cr_steps)
m_cr_timer->adjust(attotime::from_usec(400), m_real_cr_dir); {
m_real_cr_steps++; m_cr_timer->adjust(attotime::from_usec(400), m_bitmap_printer->m_cr_direction);
m_real_cr_steps++;
LOG("%s: %s(%02x); abs %d\n", machine().describe_context(), __func__, data, m_cr_pos_abs); }
} }
WRITE_LINE_MEMBER( epson_lx810l_device::e05a30_ready ) 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 Extended Timer Output
***************************************************************************/ ***************************************************************************/
@ -583,11 +552,13 @@ WRITE_LINE_MEMBER( epson_lx810l_device::co0_w )
* lines which are being printed in different directions is * lines which are being printed in different directions is
* noticeably off in the 20+ years old printer used for testing =). * noticeably off in the 20+ years old printer used for testing =).
*/ */
if (m_real_cr_pos < m_bitmap.width()) { if (m_bitmap_printer->m_xpos < m_bitmap_printer->m_page_bitmap.width()) {
for (int i = 0; i < 9; i++) { for (int i = 0; i < 9; i++)
unsigned int const y = bitmap_line(i); {
if ((m_printhead & (1<<(8-i))) != 0) 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 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 */ return res - 1; /* DIPSW2.1 */
} }
uint8_t epson_lx810l_device::an1_r() 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 */ return res - 1; /* DIPSW2.2 */
} }
uint8_t epson_lx810l_device::an2_r() 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 */ return res - 1; /* DIPSW2.3 */
} }
uint8_t epson_lx810l_device::an3_r() 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 */ 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 epson_lx810l_device::an6_r()
{ {
uint8_t res = !ioport("LOADEJECT")->read(); uint8_t res = !m_loadeject_ioport->read();
return res - 1; return res - 1;
} }

View File

@ -13,6 +13,7 @@
#include "cpu/upd7810/upd7810.h" #include "cpu/upd7810/upd7810.h"
#include "machine/e05a30.h" #include "machine/e05a30.h"
#include "machine/eepromser.h" #include "machine/eepromser.h"
#include "machine/bitmap_printer.h"
#include "machine/steppers.h" #include "machine/steppers.h"
#include "sound/dac.h" #include "sound/dac.h"
#include "screen.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 DECLARE_WRITE_LINE_MEMBER(e05a30_cpu_reset) { if (!state) m_maincpu->pulse_input_line(INPUT_LINE_RESET, attotime::zero); } // reset cpu
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);
}
void lx810l_mem(address_map &map); void lx810l_mem(address_map &map);
/* Video hardware (simulates paper) */
uint32_t screen_update_lx810l(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
unsigned int bitmap_line(int i) { return ((std::abs(m_pf_pos_abs) / 6) + i) % m_bitmap.height(); }
required_device<cpu_device> m_maincpu; required_device<cpu_device> m_maincpu;
required_device<stepper_device> m_pf_stepper; required_device<bitmap_printer_device> m_bitmap_printer;
required_device<stepper_device> m_cr_stepper;
required_device<eeprom_serial_93cxx_device> m_eeprom; required_device<eeprom_serial_93cxx_device> m_eeprom;
required_device<e05a30_device> m_e05a30; required_device<e05a30_device> m_e05a30;
required_device<screen_device> m_screen;
output_finder<> m_online_led; 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_clk;
int m_93c06_cs; int m_93c06_cs;
uint16_t m_printhead; 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_steps;
int m_real_cr_dir; /* 1 is going right, -1 is going left */
uint8_t m_fakemem; 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 { enum {
TIMER_CR TIMER_CR

View File

@ -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();
}

View File

@ -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<screen_device> m_screen;
public:
required_device<stepper_device> m_pf_stepper;
required_device<stepper_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

View File

@ -30,6 +30,7 @@ e05a30_device::e05a30_device(const machine_config &mconfig, const char *tag, dev
m_write_centronics_fault(*this), m_write_centronics_fault(*this),
m_write_centronics_select(*this), m_write_centronics_select(*this),
m_write_cpu_reset(*this), m_write_cpu_reset(*this),
m_write_ready_led(*this),
m_printhead(0), m_printhead(0),
m_pf_stepper(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) 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_fault.resolve_safe();
m_write_centronics_select.resolve_safe(); m_write_centronics_select.resolve_safe();
m_write_cpu_reset.resolve_safe(); m_write_cpu_reset.resolve_safe();
m_write_ready_led.resolve_safe();
/* register for state saving */ /* register for state saving */
save_item(NAME(m_printhead)); save_item(NAME(m_printhead));
@ -74,6 +76,7 @@ void e05a30_device::device_reset()
/* centronics init */ /* centronics init */
m_centronics_nack = false; m_centronics_nack = false;
m_centronics_busy = false; m_centronics_busy = false;
m_write_ready_led(get_ready_led());
m_write_centronics_ack (!m_centronics_nack); m_write_centronics_ack (!m_centronics_nack);
m_write_centronics_busy ( m_centronics_busy); m_write_centronics_busy ( m_centronics_busy);
m_write_centronics_perror(false); m_write_centronics_perror(false);
@ -154,6 +157,7 @@ WRITE_LINE_MEMBER( e05a30_device::centronics_input_strobe )
m_centronics_data_latched = true; m_centronics_data_latched = true;
m_centronics_busy = true; m_centronics_busy = true;
m_write_ready_led(get_ready_led());
m_write_centronics_busy(m_centronics_busy); m_write_centronics_busy(m_centronics_busy);
} }
@ -201,13 +205,17 @@ void e05a30_device::write(offs_t offset, uint8_t data)
case 0x04: case 0x04:
m_centronics_nack = BIT(data,5); m_centronics_nack = BIT(data,5);
m_centronics_busy = BIT(data,0); m_centronics_busy = BIT(data,0);
m_write_ready_led(get_ready_led());
/* The ActionPrinter 2000 firmware might overwrite the busy signal at /* The ActionPrinter 2000 firmware might overwrite the busy signal at
* address 20AB if the host depends only on the busy signal and * 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 * 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 * assume the busy signal cannot be reset while the data hasn't been
* read. */ * read. */
if (m_centronics_data_latched) if (m_centronics_data_latched)
{
m_centronics_busy = true; m_centronics_busy = true;
m_write_ready_led(get_ready_led());
}
m_write_centronics_ack (!m_centronics_nack); m_write_centronics_ack (!m_centronics_nack);
m_write_centronics_busy( m_centronics_busy); m_write_centronics_busy( m_centronics_busy);
break; break;

View File

@ -25,6 +25,7 @@ public:
auto centronics_fault() { return m_write_centronics_fault.bind(); } auto centronics_fault() { return m_write_centronics_fault.bind(); }
auto centronics_select() { return m_write_centronics_select.bind(); } auto centronics_select() { return m_write_centronics_select.bind(); }
auto cpu_reset() { return m_write_cpu_reset.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); void write(offs_t offset, uint8_t data);
uint8_t read(offs_t offset); 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_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; } 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: protected:
// device-level overrides // device-level overrides
@ -60,6 +61,7 @@ private:
devcb_write_line m_write_centronics_fault; devcb_write_line m_write_centronics_fault;
devcb_write_line m_write_centronics_select; devcb_write_line m_write_centronics_select;
devcb_write_line m_write_cpu_reset; devcb_write_line m_write_cpu_reset;
devcb_write_line m_write_ready_led;
void update_printhead(int pos, uint8_t data); void update_printhead(int pos, uint8_t data);
void update_pf_stepper(uint8_t data); void update_pf_stepper(uint8_t data);

View File

@ -69,6 +69,8 @@ public:
int get_position() { return m_step_pos; } int get_position() { return m_step_pos; }
/* get current absolute position in half steps */ /* get current absolute position in half steps */
int get_absolute_position() { return m_abs_step_pos; } 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 */ /* get maximum position in half steps */
int get_max() { return m_max_steps; } int get_max() { return m_max_steps; }