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; } } } /// /// d3 /// /// public bool GetOutput() { return output == 8; } } }