Mesen/Core/DatachBarcodeReader.h

195 lines
4.3 KiB
C++

#pragma once
#include "stdafx.h"
#include "BaseControlDevice.h"
#include "IBarcodeReader.h"
#include "CPU.h"
#include "Console.h"
class DatachBarcodeReader : public BaseControlDevice, public IBarcodeReader
{
private:
vector<uint8_t> _data;
uint64_t _insertCycle = 0;
uint64_t _newBarcode = 0;
uint32_t _newBarcodeDigitCount = 0;
protected:
void StreamState(bool saving) override
{
BaseControlDevice::StreamState(saving);
VectorInfo<uint8_t> data{ &_data };
Stream(_insertCycle, _newBarcode, _newBarcodeDigitCount, data);
}
bool IsRawString() override
{
return true;
}
public:
DatachBarcodeReader(shared_ptr<Console> console) : BaseControlDevice(console, BaseControlDevice::MapperInputPort)
{
}
void InternalSetStateFromInput() override
{
if(_newBarcodeDigitCount > 0) {
string barcodeText = std::to_string(_newBarcode);
//Pad 8 or 13 character barcode with 0s at start
barcodeText.insert(0, _newBarcodeDigitCount - barcodeText.size(), '0');
SetTextState(barcodeText);
_newBarcode = 0;
_newBarcodeDigitCount = 0;
}
}
void OnAfterSetState() override
{
if(GetRawState().State.size() > 0) {
InitBarcodeData();
}
}
uint8_t GetOutput()
{
uint64_t elapsedCycles = _console->GetCpu()->GetCycleCount() - _insertCycle;
uint32_t bitNumber = (uint32_t)(elapsedCycles / 1000);
if(bitNumber < (uint32_t)_data.size()) {
return _data[bitNumber];
} else {
return 0;
}
}
void InputBarcode(uint64_t barcode, uint32_t digitCount) override
{
_newBarcode = barcode;
_newBarcodeDigitCount = digitCount;
}
void InitBarcodeData()
{
_insertCycle = _console->GetCpu()->GetCycleCount();
static constexpr uint8_t prefixParityType[10][6] = {
{ 8,8,8,8,8,8 },{ 8,8,0,8,0,0 },
{ 8,8,0,0,8,0 },{ 8,8,0,0,0,8 },
{ 8,0,8,8,0,0 },{ 8,0,0,8,8,0 },
{ 8,0,0,0,8,8 },{ 8,0,8,0,8,0 },
{ 8,0,8,0,0,8 },{ 8,0,0,8,0,8 }
};
static constexpr uint8_t dataLeftOdd[10][7] = {
{ 8,8,8,0,0,8,0 },{ 8,8,0,0,8,8,0 },
{ 8,8,0,8,8,0,0 },{ 8,0,0,0,0,8,0 },
{ 8,0,8,8,8,0,0 },{ 8,0,0,8,8,8,0 },
{ 8,0,8,0,0,0,0 },{ 8,0,0,0,8,0,0 },
{ 8,0,0,8,0,0,0 },{ 8,8,8,0,8,0,0 }
};
static constexpr uint8_t dataLeftEven[10][7] = {
{ 8,0,8,8,0,0,0 },{ 8,0,0,8,8,0,0 },
{ 8,8,0,0,8,0,0 },{ 8,0,8,8,8,8,0 },
{ 8,8,0,0,0,8,0 },{ 8,0,0,0,8,8,0 },
{ 8,8,8,8,0,8,0 },{ 8,8,0,8,8,8,0 },
{ 8,8,8,0,8,8,0 },{ 8,8,0,8,0,0,0 }
};
static constexpr uint8_t dataRight[10][7] = {
{ 0,0,0,8,8,0,8 },{ 0,0,8,8,0,0,8 },
{ 0,0,8,0,0,8,8 },{ 0,8,8,8,8,0,8 },
{ 0,8,0,0,0,8,8 },{ 0,8,8,0,0,0,8 },
{ 0,8,0,8,8,8,8 },{ 0,8,8,8,0,8,8 },
{ 0,8,8,0,8,8,8 },{ 0,0,0,8,0,8,8 }
};
string barcode = GetTextState();
vector<uint8_t> code;
for(uint8_t i = 0; i < barcode.size(); i++) {
code.push_back(barcode[i] - '0');
}
_data.clear();
for(uint32_t i = 0; i < 33; i++) {
_data.push_back(8);
}
_data.push_back(0);
_data.push_back(8);
_data.push_back(0);
uint32_t sum = 0;
if(barcode.size() == 13) {
for(uint32_t i = 0; i < 6; i++) {
bool odd = prefixParityType[code[0]][i] != 0;
for(uint32_t j = 0; j < 7; j++) {
_data.push_back(odd ? dataLeftOdd[code[i + 1]][j] : dataLeftEven[code[i + 1]][j]);
}
}
_data.push_back(8);
_data.push_back(0);
_data.push_back(8);
_data.push_back(0);
_data.push_back(8);
for(uint32_t i = 7; i < 12; i++) {
for(uint32_t j = 0; j < 7; j++) {
_data.push_back(dataRight[code[i]][j]);
}
}
for(uint32_t i = 0; i < 12; i++) {
sum += (i & 1) ? (code[i] * 3) : (code[i] * 1);
}
} else {
for(uint32_t i = 0; i < 4; i++) {
for(uint32_t j = 0; j < 7; j++) {
_data.push_back(dataLeftOdd[code[i]][j]);
}
}
_data.push_back(8);
_data.push_back(0);
_data.push_back(8);
_data.push_back(0);
_data.push_back(8);
for(uint32_t i = 4; i < 7; i++) {
for(uint32_t j = 0; j < 7; j++) {
_data.push_back(dataRight[code[i]][j]);
}
}
for(uint32_t i = 0; i < 7; i++) {
sum += (i & 1) ? (code[i] * 1) : (code[i] * 3);
}
}
sum = (10 - (sum % 10)) % 10;
for(uint32_t i = 0; i < 7; i++) {
_data.push_back(dataRight[sum][i]);
}
_data.push_back(0);
_data.push_back(8);
_data.push_back(0);
for(uint32_t i = 0; i < 32; i++) {
_data.push_back(8);
}
}
uint8_t ReadRAM(uint16_t addr) override
{
return 0;
}
void WriteRAM(uint16_t addr, uint8_t value) override
{
}
};