summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/bcreader.cpp
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
committer Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
commit7c19aac60e12d6f5ea301bdb34d7826a01e0b06f (patch)
treef310d86aa2c6bfc19d115307dedde4eb0cd52dad /src/devices/machine/bcreader.cpp
parenta57b46ae933badd7441ce1644711dbb851e2b504 (diff)
Rename *.c -> *.cpp in our source (nw)
Diffstat (limited to 'src/devices/machine/bcreader.cpp')
-rw-r--r--src/devices/machine/bcreader.cpp330
1 files changed, 330 insertions, 0 deletions
diff --git a/src/devices/machine/bcreader.cpp b/src/devices/machine/bcreader.cpp
new file mode 100644
index 00000000000..5a5df7fb452
--- /dev/null
+++ b/src/devices/machine/bcreader.cpp
@@ -0,0 +1,330 @@
+// license:BSD-3-Clause
+// copyright-holders:Fabio Priuli
+/***************************************************************************
+
+ 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__)
+ , m_byte_length(0)
+ , m_pixel_length(0)
+ , m_byte_count(0)
+ , m_pixel_count(0)
+ , m_new_code(0)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void barcode_reader_device::device_start()
+{
+ save_item(m_byte_data, "DATACH/m_byte_data");
+ save_item(m_pixel_data, "DATACH/m_pixel_data");
+ save_item(m_byte_length, "DATACH/m_byte_length");
+ save_item(m_pixel_length, "DATACH/m_pixel_length");
+ save_item(m_byte_count, "DATACH/m_byte_count");
+ save_item(m_pixel_count, "DATACH/m_pixel_count");
+ save_item(m_new_code, "DATACH/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_byte_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;
+}