diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/emu/emu.mak | 1 | ||||
-rw-r--r-- | src/emu/machine/bcreader.c | 323 | ||||
-rw-r--r-- | src/emu/machine/bcreader.h | 56 | ||||
-rw-r--r-- | src/emu/machine/machine.mak | 9 | ||||
-rw-r--r-- | src/emu/ui/barcode.c | 200 | ||||
-rw-r--r-- | src/emu/ui/barcode.h | 40 | ||||
-rw-r--r-- | src/emu/ui/mainmenu.c | 15 | ||||
-rw-r--r-- | src/emu/ui/mainmenu.h | 1 | ||||
-rw-r--r-- | src/mame/mame.mak | 1 | ||||
-rw-r--r-- | src/mess/mess.mak | 1 |
10 files changed, 646 insertions, 1 deletions
diff --git a/src/emu/emu.mak b/src/emu/emu.mak index a8ed64b5358..b89a52357de 100644 --- a/src/emu/emu.mak +++ b/src/emu/emu.mak @@ -152,6 +152,7 @@ EMUOBJS = \ $(EMUOBJ)/ui/filesel.o \ $(EMUOBJ)/ui/imginfo.o \ $(EMUOBJ)/ui/bbcontrl.o \ + $(EMUOBJ)/ui/barcode.o \ $(EMUOBJ)/ui/tapectrl.o \ $(EMUOBJ)/ui/viewgfx.o \ $(EMUOBJ)/validity.o \ diff --git a/src/emu/machine/bcreader.c b/src/emu/machine/bcreader.c new file mode 100644 index 00000000000..b02eb4b0854 --- /dev/null +++ b/src/emu/machine/bcreader.c @@ -0,0 +1,323 @@ +/*************************************************************************** + + bcreader.c + + Generic barcode reader emulation. + + This device only provides the storage of the actual barcode, entered + by the user via Internal UI, both as a raw strip of pixels (up to 95, + for an EAN-13 barcode) and as an array of 0-9 digits. + + It is up to the driver to handle the serial transfer of the data to + the emulated machine, depending on the used protocol + + E.g. Bandai Datach games directly read the raw pixel sequence of + black/white bars; + OTOH Barcode Battle (used by Barcode World for NES and a few SNES + titles) sends the digits as sequences of 20 bytes (13 for the code, + suitably padded for shorted codes, followed by a signature) and the + actual serial transmission to the console is up to the slot device + connected to the NES/SNES controller port (yet to be emulated, in this + case) + + Note: we currently support the following barcode formats + * UPC-A: 12 digits + * EAN-13: 13 digits (extension of the former) + * EAN-8: 8 digits (same encoding as UPC-A, but 4-digits blocks instead + of 6-digits blocks) + Notice that since EAN-13 is an extension of UPC-A, we just treat UPC-A + as an EAN-13 code with leading '0'. If any barcode reader shall be found + which supports the older format only, this shall be changed + + + TODO: add support for UPC-E barcodes? these are 8 digits barcodes with 17 + black stripes (they are compressed UPC-A codes). Datach reader does not + support these, so it is low priority + + + TODO 2: verify barcode checksum in is_valid() and not only length, so + that we can then use the actual last digit in the decode function below, + rather than replacing it with the checksum value + + + TODO 3: possibly the white spaces before the actual barcode (see the + 61 white pixels sent by read_pixel() before and after the code), shall + be moved to the specific implementations to emulate different "sensitivity" + of the readers? Bandai Datach seems to need at least 32 pixels... + +***************************************************************************/ + +#include "emu.h" +#include "bcreader.h" + +// device type definition +const device_type BARCODE_READER = &device_creator<barcode_reader_device>; + +//------------------------------------------------- +// barcode_reader_device - constructor +//------------------------------------------------- + +barcode_reader_device::barcode_reader_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, BARCODE_READER, "Barcode Reader", tag, owner, clock, "bcreader", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void barcode_reader_device::device_start() +{ + state_save_register_item(machine(), "DATACH", this->tag(), 0, m_byte_data); + state_save_register_item(machine(), "DATACH", this->tag(), 0, m_pixel_data); + state_save_register_item(machine(), "DATACH", this->tag(), 0, m_byte_length); + state_save_register_item(machine(), "DATACH", this->tag(), 0, m_pixel_length); + state_save_register_item(machine(), "DATACH", this->tag(), 0, m_byte_count); + state_save_register_item(machine(), "DATACH", this->tag(), 0, m_pixel_count); + state_save_register_item(machine(), "DATACH", this->tag(), 0, m_new_code); +} + + +//------------------------------------------------- +// Barcode Decoding - convert the entered sequence +// of digits into a sequence of B/W pixels (the +// actual bars) - each digit corresponds to 7 pixels +// 0 is black, 1 is white +//------------------------------------------------- + +// Left Odd +static const UINT8 bcread_data_LO[10][7] = +{ + {1, 1, 1, 0, 0, 1, 0}, {1, 1, 0, 0, 1, 1, 0}, + {1, 1, 0, 1, 1, 0, 0}, {1, 0, 0, 0, 0, 1, 0}, + {1, 0, 1, 1, 1, 0, 0}, {1, 0, 0, 1, 1, 1, 0}, + {1, 0, 1, 0, 0, 0, 0}, {1, 0, 0, 0, 1, 0, 0}, + {1, 0, 0, 1, 0, 0, 0}, {1, 1, 1, 0, 1, 0, 0} +}; + +// Left Even +static const UINT8 bcread_data_LE[10][7] = +{ + {1, 0, 1, 1, 0, 0, 0}, {1, 0, 0, 1, 1, 0, 0}, + {1, 1, 0, 0, 1, 0, 0}, {1, 0, 1, 1, 1, 1, 0}, + {1, 1, 0, 0, 0, 1, 0}, {1, 0, 0, 0, 1, 1, 0}, + {1, 1, 1, 1, 0, 1, 0}, {1, 1, 0, 1, 1, 1, 0}, + {1, 1, 1, 0, 1, 1, 0}, {1, 1, 0, 1, 0, 0, 0} +}; + +// Right Even +static const UINT8 bcread_data_RE[10][7] = +{ + {0, 0, 0, 1, 1, 0, 1}, {0, 0, 1, 1, 0, 0, 1}, + {0, 0, 1, 0, 0, 1, 1}, {0, 1, 1, 1, 1, 0, 1}, + {0, 1, 0, 0, 0, 1, 1}, {0, 1, 1, 0, 0, 0, 1}, + {0, 1, 0, 1, 1, 1, 1}, {0, 1, 1, 1, 0, 1, 1}, + {0, 1, 1, 0, 1, 1, 1}, {0, 0, 0, 1, 0, 1, 1} +}; + +// EAN-13 added an extra digit to determine +// the parity type of the first digits block +static const UINT8 bcread_parity_type[10][6] = +{ + {1, 1, 1, 1, 1, 1}, {1, 1, 0, 1, 0, 0}, + {1, 1, 0, 0, 1, 0}, {1, 1, 0, 0, 0, 1}, + {1, 0, 1, 1, 0, 0}, {1, 0, 0, 1, 1, 0}, + {1, 0, 0, 0, 1, 1}, {1, 0, 1, 0, 1, 0}, + {1, 0, 1, 0, 0, 1}, {1, 0, 0, 1, 0, 1} +}; + + +void barcode_reader_device::decode(int len) +{ + int output = 0; + int sum = 0; + + if (len == 13) + { + // UPC-A and EAN-13 + + m_pixel_data[output++] = 0; + m_pixel_data[output++] = 1; + m_pixel_data[output++] = 0; + + for (int i = 1; i < 7; i++) + { + if (bcread_parity_type[m_byte_data[0]][i - 1]) + { + for (int j = 0; j < 7; j++) + m_pixel_data[output++] = bcread_data_LO[m_byte_data[i]][j]; + } + else + { + for (int j = 0; j < 7; j++) + m_pixel_data[output++] = bcread_data_LE[m_byte_data[i]][j]; + } + } + + m_pixel_data[output++] = 1; + m_pixel_data[output++] = 0; + m_pixel_data[output++] = 1; + m_pixel_data[output++] = 0; + m_pixel_data[output++] = 1; + + for (int i = 7; i < 12; i++) + { + for (int j = 0; j < 7; j++) + m_pixel_data[output++] = bcread_data_RE[m_byte_data[i]][j]; + } + + // ignore the last digit and compute it as checksum of the first 12 + for (int i = 0; i < 12; i++) + sum += (i & 1) ? (m_byte_data[i] * 3) : (m_byte_data[i] * 1); + } + else if (len == 8) + { + // EAN-8 (same encoding as UPC-A, but only 4+4 digits, instead of 6+6) + + m_pixel_data[output++] = 0; + m_pixel_data[output++] = 1; + m_pixel_data[output++] = 0; + + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 7; j++) + m_pixel_data[output++] = bcread_data_LO[m_byte_data[i]][j]; + } + + m_pixel_data[output++] = 1; + m_pixel_data[output++] = 0; + m_pixel_data[output++] = 1; + m_pixel_data[output++] = 0; + m_pixel_data[output++] = 1; + + for (int i = 4; i < 7; i++) + { + for (int j = 0; j < 7; j++) + m_pixel_data[output++] = bcread_data_RE[m_byte_data[i]][j]; + } + + // ignore the last digit and compute it as checksum of the first 12 + for (int i = 0; i < 7; i++) + sum += (i & 1) ? (m_byte_data[i] * 1) : (m_byte_data[i] * 3); + } + + if (m_pixel_data) + { + sum = (10 - (sum % 10)) % 10; + if (sum != m_byte_data[len - 1]) + logerror("WARNING: wrong checksum detected in the barcode! chksum %d last digit %d\n", + sum, m_byte_data[len - 1]); + + for (int i = 0; i < 7; i++) + m_pixel_data[output++] = bcread_data_RE[sum][i]; + + m_pixel_data[output++] = 0; + m_pixel_data[output++] = 1; + m_pixel_data[output++] = 0; + } + + m_byte_length = len; + m_pixel_length = output; + +// printf("byte len %d - pixel len\n", m_byte_length, m_pixel_length); +} + + +//------------------------------------------------- +// write_code - invoked by UI, stores the barcode +// both as an array of digits and as a sequence +// of B/W pixels (the actual bars) +//------------------------------------------------- + +void barcode_reader_device::write_code(const char *barcode, int len) +{ + int shift = 0; + int deconde_len = len; + + // len has already been checked to be one of the following: 8, 12 or 13 + + if (deconde_len == 12) + { + // convert UPC-A to EAN-13 + shift = 1; + deconde_len = 13; + m_byte_data[0] = 0; + } + + for (int i = 0; i < len; i++) + m_byte_data[i+shift] = barcode[i] - '0'; + + decode(deconde_len); + + m_new_code = 1; +} + + +//------------------------------------------------- +// read_code - accessor for drivers which read +// the codes by bytes +//------------------------------------------------- + +UINT8 barcode_reader_device::read_code() +{ + if (m_new_code) + { + if (m_byte_count < m_byte_length) + { + UINT8 val = m_pixel_data[m_byte_count]; + m_byte_count++; + return val; + } + else + { + m_byte_count = 0; + m_new_code = 0; + return 0; + } + } + + // no pending transfer + return 0; +} + +//------------------------------------------------- +// read_pixel - accessor for drivers which read +// the codes by pixels +//------------------------------------------------- + +int barcode_reader_device::read_pixel() +{ + if (m_new_code) + { + // start of card: 61 white pixels + if (m_pixel_count < 61) + { + m_pixel_count++; + return 1; + } + // barcode: approx 95 pixels for B/W bars + else if (m_pixel_count < 61 + m_pixel_length) + { + // actual barcode starts here + int val = m_pixel_data[m_pixel_count - 61]; + m_pixel_count++; + return val; + } + // end of card: 61 white pixels + else if (m_pixel_count < 61 + m_pixel_length + 61) + { + m_pixel_count++; + return 1; + } + // finished scan, erase code + else + { + m_pixel_count = 0; + m_new_code = 0; + return 0; + } + } + + // no pending transfer = black pixel = 0 + return 0; +} diff --git a/src/emu/machine/bcreader.h b/src/emu/machine/bcreader.h new file mode 100644 index 00000000000..26e55a3d05c --- /dev/null +++ b/src/emu/machine/bcreader.h @@ -0,0 +1,56 @@ +/********************************************************************* + + bcreader.h + + Generic barcode reader emulation. + +*********************************************************************/ + +#ifndef __BCREADER_H_ +#define __BCREADER_H_ + +#define MCFG_BARCODE_READER_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, BARCODE_READER, 0 ) + +#define MCFG_BARCODE_READER_REMOVE( _tag ) \ + MCFG_DEVICE_REMOVE( _tag ) + + +// ======================> barcode_reader_device + +class barcode_reader_device : public device_t +{ +public: + // construction/destruction + barcode_reader_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void write_code(const char *barcode, int len); + UINT8 read_code(); + int read_pixel(); + + // TODO: add checksum validation! + bool is_valid(int len) { return (len != 12 && len != 13 && len != 8) ? FALSE : TRUE; } + void decode(int len); + +protected: + // device-level overrides + virtual void device_start(); + + UINT8 m_byte_data[13]; + UINT8 m_pixel_data[100]; + int m_byte_length; + int m_pixel_length; + int m_byte_count; + int m_pixel_count; + int m_new_code; +}; + + +// device type definition +extern const device_type BARCODE_READER; + +// device type iterator +typedef device_type_iterator<&device_creator<barcode_reader_device>, barcode_reader_device> barcode_reader_device_iterator; + + +#endif diff --git a/src/emu/machine/machine.mak b/src/emu/machine/machine.mak index 3a4458ee36b..a6d8a0e4107 100644 --- a/src/emu/machine/machine.mak +++ b/src/emu/machine/machine.mak @@ -338,6 +338,15 @@ endif #------------------------------------------------- # +#@src/emu/machine/bankdev.h,MACHINES += BANKDEV +#------------------------------------------------- + +ifneq ($(filter BARCODE_READER,$(MACHINES)),) +MACHINEOBJS += $(MACHINEOBJ)/bcreader.o +endif + +#------------------------------------------------- +# #@src/emu/machine/cdp1852.h,MACHINES += CDP1852 #------------------------------------------------- diff --git a/src/emu/ui/barcode.c b/src/emu/ui/barcode.c new file mode 100644 index 00000000000..a5c7db0c9dd --- /dev/null +++ b/src/emu/ui/barcode.c @@ -0,0 +1,200 @@ +/*************************************************************************** + + ui/barcode.c + + MESS's "barcode reader" control + + Copyright Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#include "emu.h" +#include "ui/ui.h" +#include "ui/menu.h" +#include "ui/barcode.h" + + +// itemrefs for key menu items +#define ITEMREF_NEW_BARCODE ((void *) 0x0001) +#define ITEMREF_ENTER ((void *) 0x0002) + + +/************************************************** + + BARCODE INPUT MENU + + **************************************************/ + + +//------------------------------------------------- +// ctor +//------------------------------------------------- + +ui_menu_barcode_code::ui_menu_barcode_code(running_machine &machine, render_container *container, barcode_reader_device *reader) + : ui_menu(machine, container) +{ + m_reader = reader; +} + + +//------------------------------------------------- +// dtor +//------------------------------------------------- + +ui_menu_barcode_code::~ui_menu_barcode_code() +{ +} + +//------------------------------------------------- +// populate - populates the barcode input menu +//------------------------------------------------- + +void ui_menu_barcode_code::populate() +{ + astring buffer; + const char *new_barcode; + + // append the "New Barcode" item + if (get_selection() == ITEMREF_NEW_BARCODE) + { + buffer.cat(m_barcode_buffer); + new_barcode = buffer; + } + else + { + new_barcode = m_barcode_buffer; + } + + item_append("New Barcode:", new_barcode, 0, ITEMREF_NEW_BARCODE); + + // finish up the menu + item_append(MENU_SEPARATOR_ITEM, NULL, 0, NULL); + item_append("Enter Code", NULL, 0, ITEMREF_ENTER); + + customtop = machine().ui().get_line_height() + 3.0f * UI_BOX_TB_BORDER; +} + + +//------------------------------------------------- +// handle - manages inputs in the barcode input menu +//------------------------------------------------- + +void ui_menu_barcode_code::handle() +{ + // process the menu + const ui_menu_event *event = process(0); + + // process the event + if (event != NULL) + { + // handle selections + switch (event->iptkey) + { + case IPT_UI_SELECT: + if (event->itemref == ITEMREF_ENTER) + { + astring tmp_file(m_barcode_buffer); + //printf("code %s\n", m_barcode_buffer); + if (!m_reader->is_valid(tmp_file.len())) + machine().ui().popup_time(5, "Barcode length invalid!"); + else + { + m_reader->write_code(tmp_file.cstr(), tmp_file.len()); + // if sending was successful, reset char buffer + if (m_barcode_buffer[0] != '\0') + memset(m_barcode_buffer, '\0', ARRAY_LENGTH(m_barcode_buffer)); + reset(UI_MENU_RESET_REMEMBER_POSITION); + } + } + break; + + case IPT_SPECIAL: + if (get_selection() == ITEMREF_NEW_BARCODE) + { + int buflen = strlen(m_barcode_buffer); + + // if it's a backspace and we can handle it, do so + if ((event->unichar == 8 || event->unichar == 0x7f) && buflen > 0) + *(char *)utf8_previous_char(&m_barcode_buffer[buflen]) = 0; + else if (event->unichar >= '0' && event->unichar <= '9') + { + buflen += utf8_from_uchar(&m_barcode_buffer[buflen], ARRAY_LENGTH(m_barcode_buffer) - buflen, event->unichar); + m_barcode_buffer[buflen] = 0; + } + reset(UI_MENU_RESET_REMEMBER_POSITION); + } + break; + + case IPT_UI_CANCEL: + // reset the char buffer also in this case + if (m_barcode_buffer[0] != '\0') + memset(m_barcode_buffer, '\0', ARRAY_LENGTH(m_barcode_buffer)); + break; + } + } +} + + + +/************************************************** + + READER MENU + +**************************************************/ + +//------------------------------------------------- +// ctor +//------------------------------------------------- + +ui_menu_barcode_reader::ui_menu_barcode_reader(running_machine &machine, render_container *container) + : ui_menu(machine, container) +{ +} + +//------------------------------------------------- +// dtor +//------------------------------------------------- + +ui_menu_barcode_reader::~ui_menu_barcode_reader() +{ +} + + +//------------------------------------------------- +// populate - populates the barcode reader menu +//------------------------------------------------- + +void ui_menu_barcode_reader::populate() +{ + astring buffer; + + barcode_reader_device_iterator iter(machine().config().root_device()); + for (const barcode_reader_device *bcreader = iter.first(); bcreader != NULL; bcreader = iter.next()) + { + char label[0x400]; + sprintf(label,"[%s (%s)]",bcreader->name(),bcreader->basetag()); + item_append(label, NULL, 0, (void *)bcreader); + } +} + + +//------------------------------------------------- +// handle - manages inputs in the barcode reader menu +//------------------------------------------------- + +void ui_menu_barcode_reader::handle() +{ + // process the menu + const ui_menu_event *event = process(0); + + // process the event + if (event != NULL && event->iptkey == IPT_UI_SELECT) + { + if (event->itemref != NULL) + { + ui_menu::stack_push(auto_alloc_clear(machine(), ui_menu_barcode_code(machine(), container, (barcode_reader_device *)event->itemref))); + } + + } +} diff --git a/src/emu/ui/barcode.h b/src/emu/ui/barcode.h new file mode 100644 index 00000000000..c467fff8f38 --- /dev/null +++ b/src/emu/ui/barcode.h @@ -0,0 +1,40 @@ +/*************************************************************************** + + ui/barcode.h + + MESS's "barcode reader" control + + Copyright Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#pragma once + +#ifndef __UI_BARCODE_H__ +#define __UI_BARCODE_H__ + +#include "machine/bcreader.h" + +class ui_menu_barcode_code : public ui_menu { +public: + ui_menu_barcode_code(running_machine &machine, render_container *container, barcode_reader_device *reader); + virtual ~ui_menu_barcode_code(); + virtual void populate(); + virtual void handle(); + +private: + barcode_reader_device *m_reader; + char m_barcode_buffer[20]; +}; + + +class ui_menu_barcode_reader : public ui_menu { +public: + ui_menu_barcode_reader(running_machine &machine, render_container *container); + virtual ~ui_menu_barcode_reader(); + virtual void populate(); + virtual void handle(); +}; + +#endif // __UI_BARCODE_H__ diff --git a/src/emu/ui/mainmenu.c b/src/emu/ui/mainmenu.c index 6e6c41f6fd9..5b48a80c153 100644 --- a/src/emu/ui/mainmenu.c +++ b/src/emu/ui/mainmenu.c @@ -18,6 +18,7 @@ #include "uiinput.h" #include "ui/filemngr.h" #include "ui/filesel.h" +#include "ui/barcode.h" #include "ui/bbcontrl.h" #include "ui/tapectrl.h" #include "ui/mainmenu.h" @@ -29,6 +30,7 @@ #include <ctype.h> #include "imagedev/cassette.h" #include "imagedev/bitbngr.h" +#include "machine/bcreader.h" @@ -102,6 +104,13 @@ void ui_menu_main::populate() item_append("Slot Devices", NULL, 0, (void *)SLOT_DEVICES); } + barcode_reader_device_iterator bcriter(machine().root_device()); + if (bcriter.first() != NULL) + { + /* add slot info menu */ + item_append("Barcode Reader", NULL, 0, (void *)BARCODE_READ); + } + network_interface_iterator netiter(machine().root_device()); if (netiter.first() != NULL) { @@ -237,7 +246,11 @@ void ui_menu_main::handle() case BIOS_SELECTION: ui_menu::stack_push(auto_alloc_clear(machine(), ui_menu_bios_selection(machine(), container))); break; - + + case BARCODE_READ: + ui_menu::stack_push(auto_alloc_clear(machine(), ui_menu_barcode_reader(machine(), container))); + break; + default: fatalerror("ui_menu_main::handle - unknown reference\n"); } diff --git a/src/emu/ui/mainmenu.h b/src/emu/ui/mainmenu.h index f92a0ccfe02..26b8a9765cb 100644 --- a/src/emu/ui/mainmenu.h +++ b/src/emu/ui/mainmenu.h @@ -48,6 +48,7 @@ private: MEMORY_CARD, SELECT_GAME, BIOS_SELECTION, + BARCODE_READ, }; }; diff --git a/src/mame/mame.mak b/src/mame/mame.mak index 888b533fb51..d3d3e409eb6 100644 --- a/src/mame/mame.mak +++ b/src/mame/mame.mak @@ -363,6 +363,7 @@ MACHINES += AT45DBXX MACHINES += ATAFLASH MACHINES += AY31015 MACHINES += BANKDEV +MACHINES += BARCODE_READER MACHINES += CDP1852 MACHINES += CDP1871 MACHINES += CDU76S diff --git a/src/mess/mess.mak b/src/mess/mess.mak index 2c11ca006e2..85cf32ebbbc 100644 --- a/src/mess/mess.mak +++ b/src/mess/mess.mak @@ -334,6 +334,7 @@ MACHINES += AT45DBXX MACHINES += ATAFLASH MACHINES += AY31015 MACHINES += BANKDEV +MACHINES += BARCODE_READER MACHINES += CDP1852 MACHINES += CDP1871 MACHINES += CMOS40105 |