BizHawk/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/DatachBarcode.cs

238 lines
5.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BizHawk.Common.NumberExtensions;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.NES
{
// mostly jacked from nestopia's NstBoardBandaiDatach.cpp
// very dirty, needs cleanup and such
public class DatachBarcode : IEmulatorService
{
static readonly byte[,] prefixParityType = new byte[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 readonly byte[,] dataLeftOdd = new byte[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 readonly byte[,] dataLeftEven = new byte[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 readonly byte[,] dataRight = new byte[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}
};
const int MIN_DIGITS = 8;
const int MAX_DIGITS = 13;
const int CC_INTERVAL = 1000;
int cycles;
byte output;
int stream_idx;
byte[] data = new byte[0];
byte streamoutput { get { return data[stream_idx]; } }
public void SyncState(Serializer ser)
{
ser.BeginSection("DatachBarcode");
ser.Sync("cycles", ref cycles);
ser.Sync("output", ref output);
ser.Sync("stream_idx", ref stream_idx);
ser.Sync("data", ref data, false);
ser.EndSection();
}
public void Reset()
{
cycles = 0;
stream_idx = 0;
data = new byte[0];
}
public bool IsTransferring()
{
return stream_idx < data.Length;
}
private static bool IsDigtsSupported(int count)
{
return count.In(MIN_DIGITS, MAX_DIGITS);
}
public static bool ValidString(string s, out string why)
{
if (s == null)
throw new ArgumentNullException(nameof(s));
if (!s.Length.In(MIN_DIGITS, MAX_DIGITS))
{
why = string.Format("String must be {0} or {1} digits long!", MIN_DIGITS, MAX_DIGITS);
return false;
}
foreach (char c in s)
{
if (c < '0' || c > '9')
{
why = "String must be numeric only!";
return false;
}
}
why = "String is OK.";
return true;
}
public void Transfer(string s)
{
string why;
if (!ValidString(s, out why))
throw new InvalidOperationException(why);
Reset();
byte[] code = new byte[16];
for (int i = 0; i < s.Length; i++)
{
if (s[i] >= '0' && s[i] <= '9')
code[i] = (byte)(s[i] - '0');
else
throw new InvalidOperationException("s must be numeric only");
}
var result = new System.IO.MemoryStream();
for (int i = 0; i < 33; i++)
result.WriteByte(8);
result.WriteByte(0);
result.WriteByte(8);
result.WriteByte(0);
int sum = 0;
if (s.Length == MAX_DIGITS)
{
for (int i = 0; i < 6; i++)
{
if (prefixParityType[code[0], i] != 0)
{
for (int j = 0; j < 7; j++)
result.WriteByte(dataLeftOdd[code[i + 1], j]);
}
else
{
for (int j = 0; j < 7; j++)
result.WriteByte(dataLeftEven[code[i + 1], j]);
}
}
result.WriteByte(8);
result.WriteByte(0);
result.WriteByte(8);
result.WriteByte(0);
result.WriteByte(8);
for (int i = 7; i < 12; i++)
for (int j = 0; j < 7; j++)
result.WriteByte(dataRight[code[i], j]);
for (int i = 0; i < 12; i++)
sum += code[i] * ((i & 1) != 0 ? 3 : 1);
}
else // s.Length == MIN_DIGITS
{
for (int i = 0; i < 4; i++)
for (int j = 0; j < 7; j++)
result.WriteByte(dataLeftOdd[code[i], j]);
result.WriteByte(8);
result.WriteByte(0);
result.WriteByte(8);
result.WriteByte(0);
result.WriteByte(8);
for (int i = 4; i < 7; i++)
for (int j = 0; j < 7; j++)
result.WriteByte(dataRight[code[i], j]);
for (int i = 0; i < 7; i++)
sum += code[i] * ((i & 1) != 0 ? 3 : 1);
}
sum = (10 - (sum % 10)) % 10;
for (int j = 0; j < 7; j++)
result.WriteByte(dataRight[sum, j]);
result.WriteByte(0);
result.WriteByte(8);
result.WriteByte(0);
for (int i = 0; i < 32; i++)
result.WriteByte(8);
data = result.ToArray();
cycles = CC_INTERVAL;
output = streamoutput;
}
public void Clock()
{
if (cycles <= 0 || !IsTransferring())
return;
cycles--;
if (cycles <= 0)
{
stream_idx++;
if (IsTransferring())
{
output = streamoutput;
cycles = CC_INTERVAL;
}
else
{
output = 0;
}
}
}
/// <summary>
/// d3
/// </summary>
/// <returns></returns>
public bool GetOutput()
{
return output == 8;
}
}
}