diff --git a/Assets/dll/libgambatte.dll b/Assets/dll/libgambatte.dll
index 073a8bd5ee..d91f7c7995 100644
Binary files a/Assets/dll/libgambatte.dll and b/Assets/dll/libgambatte.dll differ
diff --git a/Assets/dll/libgambatte.so b/Assets/dll/libgambatte.so
index 616feee8d9..d1002107dd 100644
Binary files a/Assets/dll/libgambatte.so and b/Assets/dll/libgambatte.so differ
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ILinkable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ILinkable.cs
index e76ed0d7c6..f7e87993c1 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ILinkable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ILinkable.cs
@@ -4,6 +4,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
{
public partial class Gameboy : ILinkable
{
- public bool LinkConnected { get; set; }
+ private bool _linkConnected;
+
+ public bool LinkConnected
+ {
+ get => _linkConnected;
+ set { return; }
+ }
}
}
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IStatable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IStatable.cs
index db8c68387d..139f2dcc21 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IStatable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IStatable.cs
@@ -9,7 +9,7 @@ using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
{
- public partial class Gameboy : ITextStatable
+ public partial class Gameboy : IStatable, ITextStatable
{
public void SaveStateText(TextWriter writer)
{
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IVideoProvider.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IVideoProvider.cs
index 17f1ab92bb..d35a96eae1 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IVideoProvider.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IVideoProvider.cs
@@ -1,6 +1,8 @@
-namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
+using BizHawk.Emulation.Common;
+
+namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
{
- public partial class Gameboy
+ public partial class Gameboy : IVideoProvider
{
///
/// buffer of last frame produced
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
index 81ba126db8..dfbf7972dc 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
@@ -13,14 +13,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
///
[PortedCore(CoreNames.Gambatte, "", "Gambatte-Speedrun r717+", "https://github.com/pokemon-speedrunning/gambatte-speedrun")]
[ServiceNotApplicable(new[] { typeof(IDriveLight) })]
- public partial class Gameboy : IEmulator, IVideoProvider, ISoundProvider, ISaveRam, IStatable, IInputPollable, ICodeDataLogger,
- IBoardInfo, IRomInfo, IDebuggable, ISettable,
- IGameboyCommon, ICycleTiming, ILinkable
+ public partial class Gameboy : IInputPollable, IRomInfo, IGameboyCommon, ICycleTiming, ILinkable
{
[CoreConstructor(VSystemID.Raw.GB)]
[CoreConstructor(VSystemID.Raw.GBC)]
[CoreConstructor(VSystemID.Raw.SGB)]
- public Gameboy(CoreComm comm, GameInfo game, byte[] file, Gameboy.GambatteSettings settings, Gameboy.GambatteSyncSettings syncSettings, bool deterministic)
+ public Gameboy(CoreComm comm, GameInfo game, byte[] file, GambatteSettings settings, GambatteSyncSettings syncSettings, bool deterministic)
{
var ser = new BasicServiceProvider(this);
ser.Register(_disassembler);
@@ -707,11 +705,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
if (callback != null)
{
printer = new GambattePrinter(this, callback);
- LinkConnected = true;
+ _linkConnected = true;
}
else
{
- LinkConnected = false;
+ _linkConnected = false;
if (printer != null) // have no idea how this is ever null???
{
printer.Disconnect();
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs
index 9583d7d21a..36d7751441 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs
@@ -34,8 +34,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
bool linkDiscoSignalNew = controller.IsPressed("Toggle Link Connection");
if (linkDiscoSignalNew && !_linkDiscoSignal)
{
- _linkConnected ^= true;
- Console.WriteLine("Link connect status to {0}", _linkConnected);
+ LinkConnected ^= true;
+ Console.WriteLine("Link connect status to {0}", LinkConnected);
}
_linkDiscoSignal = linkDiscoSignalNew;
@@ -229,29 +229,29 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
if (CanIR(one, two))
{
- if (LibGambatte.gambatte_linkstatus(_linkedCores[one].GambatteState, 260) != 0) // InfraredTrigger
+ if (LibGambatte.gambatte_linkstatus(_linkedCores[one].GambatteState, 259) != 0) // InfraredTrigger
{
- LibGambatte.gambatte_linkstatus(_linkedCores[one].GambatteState, 261); // ack
- if (LibGambatte.gambatte_linkstatus(_linkedCores[one].GambatteState, 262) != 0) // GetOut
+ LibGambatte.gambatte_linkstatus(_linkedCores[one].GambatteState, 260); // ack
+ if (LibGambatte.gambatte_linkstatus(_linkedCores[one].GambatteState, 261) != 0) // GetOut
{
- LibGambatte.gambatte_linkstatus(_linkedCores[two].GambatteState, 263); // ShiftInOn
+ LibGambatte.gambatte_linkstatus(_linkedCores[two].GambatteState, 262); // ShiftInOn
}
else
{
- LibGambatte.gambatte_linkstatus(_linkedCores[two].GambatteState, 264); // ShiftInOff
+ LibGambatte.gambatte_linkstatus(_linkedCores[two].GambatteState, 263); // ShiftInOff
}
}
- if (LibGambatte.gambatte_linkstatus(_linkedCores[two].GambatteState, 260) != 0) // InfraredTrigger
+ if (LibGambatte.gambatte_linkstatus(_linkedCores[two].GambatteState, 259) != 0) // InfraredTrigger
{
- LibGambatte.gambatte_linkstatus(_linkedCores[two].GambatteState, 261); // ack
- if (LibGambatte.gambatte_linkstatus(_linkedCores[two].GambatteState, 262) != 0) // GetOut
+ LibGambatte.gambatte_linkstatus(_linkedCores[two].GambatteState, 260); // ack
+ if (LibGambatte.gambatte_linkstatus(_linkedCores[two].GambatteState, 261) != 0) // GetOut
{
- LibGambatte.gambatte_linkstatus(_linkedCores[one].GambatteState, 263); // ShiftInOn
+ LibGambatte.gambatte_linkstatus(_linkedCores[one].GambatteState, 262); // ShiftInOn
}
else
{
- LibGambatte.gambatte_linkstatus(_linkedCores[one].GambatteState, 264); // ShiftInOff
+ LibGambatte.gambatte_linkstatus(_linkedCores[one].GambatteState, 263); // ShiftInOff
}
}
}
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs
index d33b1a9961..5195003b4d 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs
@@ -33,7 +33,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
for (int i = 0; i < _numCores; i++)
{
_linkedCores[i] = new Gameboy(lp.Comm, lp.Roms[i].Game, lp.Roms[i].RomData, _settings._linkedSettings[i], _syncSettings._linkedSyncSettings[i], lp.DeterministicEmulationRequested);
- LibGambatte.gambatte_linkstatus(_linkedCores[i].GambatteState, 259); // connect link cable
_linkedCores[i].ConnectInputCallbackSystem(_inputCallbacks);
_linkedCores[i].ConnectMemoryCallbackSystem(_memoryCallbacks);
_linkedConts[i] = new SaveController(Gameboy.CreateControllerDefinition(false, false));
@@ -76,7 +75,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
public bool LinkConnected
{
get => _linkConnected;
- set => _linkConnected = value;
+ set
+ {
+ _linkConnected = value;
+ for (int i = 0; i < _numCores; i++)
+ {
+ LibGambatte.gambatte_linkstatus(_linkedCores[i].GambatteState, _linkConnected ? 264 : 265);
+ }
+ }
}
private int _numCores = 0;
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambattePrinter.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambattePrinter.cs
index fde77ce1db..fa44cb0533 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambattePrinter.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambattePrinter.cs
@@ -1,311 +1,314 @@
using System;
-
-using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
-
-namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
-{
- ///
- /// Emulate the gameboy printer in managed code
- ///
- public class GambattePrinter
- {
- // A loose c->c# port of SameBoy's printer code
-
- private enum CommandState : byte
- {
- GB_PRINTER_COMMAND_MAGIC1,
- GB_PRINTER_COMMAND_MAGIC2,
- GB_PRINTER_COMMAND_ID,
- GB_PRINTER_COMMAND_COMPRESSION,
- GB_PRINTER_COMMAND_LENGTH_LOW,
- GB_PRINTER_COMMAND_LENGTH_HIGH,
- GB_PRINTER_COMMAND_DATA,
- GB_PRINTER_COMMAND_CHECKSUM_LOW,
- GB_PRINTER_COMMAND_CHECKSUM_HIGH,
- GB_PRINTER_COMMAND_ACTIVE,
- GB_PRINTER_COMMAND_STATUS,
- }
-
- private enum CommandID : byte
- {
- GB_PRINTER_INIT_COMMAND = 1,
- GB_PRINTER_START_COMMAND = 2,
- GB_PRINTER_DATA_COMMAND = 4,
- GB_PRINTER_NOP_COMMAND = 0xF,
- }
-
- private const int GB_PRINTER_MAX_COMMAND_LENGTH = 0x280;
- private const int GB_PRINTER_DATA_SIZE = 0x280;
-
- private const ushort SerialIRQAddress = 0x58;
-
- private readonly Gameboy gb;
- private readonly PrinterCallback callback;
- private LibGambatte.LinkCallback linkCallback;
-
- private CommandState command_state;
- private CommandID command_id;
-
- private bool compression;
- private ushort length_left;
- private readonly byte[] command_data = new byte[GB_PRINTER_MAX_COMMAND_LENGTH];
- private ushort command_length;
- private ushort checksum;
- private byte status;
-
- private readonly byte[] image = new byte[160 * 200];
- private ushort image_offset;
-
- private byte compression_run_length;
- private bool compression_run_is_compressed;
-
- public GambattePrinter(Gameboy gb, PrinterCallback callback)
- {
- this.gb = gb;
- this.callback = callback;
-
- linkCallback = OnSerial;
- LibGambatte.gambatte_setlinkcallback(gb.GambatteState, linkCallback);
-
- // connect the cable
- LibGambatte.gambatte_linkstatus(gb.GambatteState, 259);
- }
-
- public void Disconnect()
- {
- if (gb.GambatteState != IntPtr.Zero)
- LibGambatte.gambatte_setlinkcallback(gb.GambatteState, null);
- }
-
- private void OnSerial()
- {
- if (LibGambatte.gambatte_linkstatus(gb.GambatteState, 256) != 0) // ClockTrigger
- {
- LibGambatte.gambatte_linkstatus(gb.GambatteState, 257); // ack
-
- byte output = HandleSerial((byte)LibGambatte.gambatte_linkstatus(gb.GambatteState, 258)); // GetOut
- LibGambatte.gambatte_linkstatus(gb.GambatteState, output); // ShiftIn
- }
- }
-
- private byte HandleSerial(byte byte_received)
- {
- byte byte_to_send = 0;
-
- switch (command_state)
- {
- case CommandState.GB_PRINTER_COMMAND_MAGIC1:
- if (byte_received != 0x88)
- {
- return byte_to_send;
- }
- status &= 254;
- command_length = 0;
- checksum = 0;
- break;
-
- case CommandState.GB_PRINTER_COMMAND_MAGIC2:
- if (byte_received != 0x33)
- {
- if (byte_received != 0x88)
- {
- command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1;
- }
- return byte_to_send;
- }
- break;
-
- case CommandState.GB_PRINTER_COMMAND_ID:
- command_id = (CommandID)(byte_received & 0xF);
- break;
-
- case CommandState.GB_PRINTER_COMMAND_COMPRESSION:
- compression = (byte_received & 1) != 0;
- break;
-
- case CommandState.GB_PRINTER_COMMAND_LENGTH_LOW:
- length_left = byte_received;
- break;
-
- case CommandState.GB_PRINTER_COMMAND_LENGTH_HIGH:
- length_left |= (ushort)((byte_received & 3) << 8);
- break;
-
- case CommandState.GB_PRINTER_COMMAND_DATA:
- if (command_length != GB_PRINTER_MAX_COMMAND_LENGTH)
- {
- if (compression)
- {
- if (compression_run_length == 0)
- {
- compression_run_is_compressed = (byte_received & 0x80) != 0;
- compression_run_length = (byte)((byte_received & 0x7F) + 1 + (compression_run_is_compressed ? 1 : 0));
- }
- else if (compression_run_is_compressed)
- {
- while (compression_run_length > 0)
- {
- command_data[command_length++] = byte_received;
- compression_run_length--;
- if (command_length == GB_PRINTER_MAX_COMMAND_LENGTH)
- {
- compression_run_length = 0;
- }
- }
- }
- else
- {
- command_data[command_length++] = byte_received;
- compression_run_length--;
- }
- }
- else
- {
- command_data[command_length++] = byte_received;
- }
- }
- length_left--;
- break;
-
- case CommandState.GB_PRINTER_COMMAND_CHECKSUM_LOW:
- checksum ^= byte_received;
- break;
-
- case CommandState.GB_PRINTER_COMMAND_CHECKSUM_HIGH:
- checksum ^= (ushort)(byte_received << 8);
- if (checksum != 0)
- {
- status |= 1; /* Checksum error*/
- command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1;
- return byte_to_send;
- }
- break;
-
- case CommandState.GB_PRINTER_COMMAND_ACTIVE:
- byte_to_send = 0x81;
- break;
-
- case CommandState.GB_PRINTER_COMMAND_STATUS:
-
- if (((int)command_id & 0xF) == (byte)CommandID.GB_PRINTER_INIT_COMMAND)
- {
- /* Games expect INIT commands to return 0? */
- byte_to_send = 0;
- }
- else
- {
- byte_to_send = status;
- }
-
- /* Printing is done instantly, but let the game recieve a 6 (Printing) status at least once, for compatibility */
- if (status == 6)
- {
- status = 4; /* Done */
- }
-
- command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1;
- HandleCommand();
- return byte_to_send;
- }
-
- if (command_state >= CommandState.GB_PRINTER_COMMAND_ID && command_state < CommandState.GB_PRINTER_COMMAND_CHECKSUM_LOW)
- {
- checksum += byte_received;
- }
-
- if (command_state != CommandState.GB_PRINTER_COMMAND_DATA)
- {
- command_state++;
- }
-
- if (command_state == CommandState.GB_PRINTER_COMMAND_DATA)
- {
- if (length_left == 0)
- {
- command_state++;
- }
- }
-
- return byte_to_send;
- }
-
- private void HandleCommand()
- {
- switch (command_id)
- {
- case CommandID.GB_PRINTER_INIT_COMMAND:
- status = 0;
- image_offset = 0;
- break;
-
- case CommandID.GB_PRINTER_START_COMMAND:
- if (command_length == 4)
- {
- status = 6; /* Printing */
- uint[] outputImage = new uint[image_offset];
-
- int palette = command_data[2];
- uint[] colors = {
- 0xFFFFFFFFU,
- 0xFFAAAAAAU,
- 0xFF555555U,
- 0xFF000000U
- };
- for (int i = 0; i < image_offset; i++)
- {
- outputImage[i] = colors[(palette >> (image[i] * 2)) & 3];
- }
-
- if (callback != null)
- {
- // The native-friendly callback almost seems silly now :P
- unsafe
- {
- fixed (uint* imagePtr = outputImage)
- {
- callback((IntPtr)imagePtr, (byte)(image_offset / 160),
- (byte)(command_data[1] >> 4), (byte)(command_data[1] & 7),
- (byte)(command_data[3] & 0x7F));
- }
- }
- }
-
- image_offset = 0;
- }
- break;
-
- case CommandID.GB_PRINTER_DATA_COMMAND:
- if (command_length == GB_PRINTER_DATA_SIZE)
- {
- image_offset %= (ushort)image.Length;
- status = 8; /* Received 0x280 bytes */
-
- int data_index = 0;
-
- for (int row = 2; row > 0; row--)
- {
- for (int tile_x = 0; tile_x < 160 / 8; tile_x++)
- {
- for (int y = 0; y < 8; y++, data_index += 2)
- {
- for (int x_pixel = 0; x_pixel < 8; x_pixel++)
- {
- image[image_offset + tile_x * 8 + x_pixel + y * 160] =
- (byte)((command_data[data_index] >> 7) | ((command_data[data_index + 1] >> 7) << 1));
- command_data[data_index] <<= 1;
- command_data[data_index + 1] <<= 1;
- }
- }
- }
-
- image_offset += 8 * 160;
- }
- }
- break;
-
- default:
- break;
- }
- }
- }
-}
+
+using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
+
+namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
+{
+ ///
+ /// Emulate the gameboy printer in managed code
+ ///
+ public class GambattePrinter
+ {
+ // A loose c->c# port of SameBoy's printer code
+
+ private enum CommandState : byte
+ {
+ GB_PRINTER_COMMAND_MAGIC1,
+ GB_PRINTER_COMMAND_MAGIC2,
+ GB_PRINTER_COMMAND_ID,
+ GB_PRINTER_COMMAND_COMPRESSION,
+ GB_PRINTER_COMMAND_LENGTH_LOW,
+ GB_PRINTER_COMMAND_LENGTH_HIGH,
+ GB_PRINTER_COMMAND_DATA,
+ GB_PRINTER_COMMAND_CHECKSUM_LOW,
+ GB_PRINTER_COMMAND_CHECKSUM_HIGH,
+ GB_PRINTER_COMMAND_ACTIVE,
+ GB_PRINTER_COMMAND_STATUS,
+ }
+
+ private enum CommandID : byte
+ {
+ GB_PRINTER_INIT_COMMAND = 1,
+ GB_PRINTER_START_COMMAND = 2,
+ GB_PRINTER_DATA_COMMAND = 4,
+ GB_PRINTER_NOP_COMMAND = 0xF,
+ }
+
+ private const int GB_PRINTER_MAX_COMMAND_LENGTH = 0x280;
+ private const int GB_PRINTER_DATA_SIZE = 0x280;
+
+ private const ushort SerialIRQAddress = 0x58;
+
+ private readonly Gameboy gb;
+ private readonly PrinterCallback callback;
+ private readonly LibGambatte.LinkCallback linkCallback;
+
+ private CommandState command_state;
+ private CommandID command_id;
+
+ private bool compression;
+ private ushort length_left;
+ private readonly byte[] command_data = new byte[GB_PRINTER_MAX_COMMAND_LENGTH];
+ private ushort command_length;
+ private ushort checksum;
+ private byte status;
+
+ private readonly byte[] image = new byte[160 * 200];
+ private ushort image_offset;
+
+ private byte compression_run_length;
+ private bool compression_run_is_compressed;
+
+ public GambattePrinter(Gameboy gb, PrinterCallback callback)
+ {
+ this.gb = gb;
+ this.callback = callback;
+
+ linkCallback = OnSerial;
+ LibGambatte.gambatte_setlinkcallback(gb.GambatteState, linkCallback);
+
+ // connect the cable
+ LibGambatte.gambatte_linkstatus(gb.GambatteState, 264);
+ }
+
+ public void Disconnect()
+ {
+ if (gb.GambatteState != IntPtr.Zero)
+ {
+ LibGambatte.gambatte_setlinkcallback(gb.GambatteState, null);
+ LibGambatte.gambatte_linkstatus(gb.GambatteState, 265);
+ }
+ }
+
+ private void OnSerial()
+ {
+ if (LibGambatte.gambatte_linkstatus(gb.GambatteState, 256) != 0) // ClockTrigger
+ {
+ LibGambatte.gambatte_linkstatus(gb.GambatteState, 257); // ack
+
+ byte output = HandleSerial((byte)LibGambatte.gambatte_linkstatus(gb.GambatteState, 258)); // GetOut
+ LibGambatte.gambatte_linkstatus(gb.GambatteState, output); // ShiftIn
+ }
+ }
+
+ private byte HandleSerial(byte byte_received)
+ {
+ byte byte_to_send = 0;
+
+ switch (command_state)
+ {
+ case CommandState.GB_PRINTER_COMMAND_MAGIC1:
+ if (byte_received != 0x88)
+ {
+ return byte_to_send;
+ }
+ status &= 254;
+ command_length = 0;
+ checksum = 0;
+ break;
+
+ case CommandState.GB_PRINTER_COMMAND_MAGIC2:
+ if (byte_received != 0x33)
+ {
+ if (byte_received != 0x88)
+ {
+ command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1;
+ }
+ return byte_to_send;
+ }
+ break;
+
+ case CommandState.GB_PRINTER_COMMAND_ID:
+ command_id = (CommandID)(byte_received & 0xF);
+ break;
+
+ case CommandState.GB_PRINTER_COMMAND_COMPRESSION:
+ compression = (byte_received & 1) != 0;
+ break;
+
+ case CommandState.GB_PRINTER_COMMAND_LENGTH_LOW:
+ length_left = byte_received;
+ break;
+
+ case CommandState.GB_PRINTER_COMMAND_LENGTH_HIGH:
+ length_left |= (ushort)((byte_received & 3) << 8);
+ break;
+
+ case CommandState.GB_PRINTER_COMMAND_DATA:
+ if (command_length != GB_PRINTER_MAX_COMMAND_LENGTH)
+ {
+ if (compression)
+ {
+ if (compression_run_length == 0)
+ {
+ compression_run_is_compressed = (byte_received & 0x80) != 0;
+ compression_run_length = (byte)((byte_received & 0x7F) + 1 + (compression_run_is_compressed ? 1 : 0));
+ }
+ else if (compression_run_is_compressed)
+ {
+ while (compression_run_length > 0)
+ {
+ command_data[command_length++] = byte_received;
+ compression_run_length--;
+ if (command_length == GB_PRINTER_MAX_COMMAND_LENGTH)
+ {
+ compression_run_length = 0;
+ }
+ }
+ }
+ else
+ {
+ command_data[command_length++] = byte_received;
+ compression_run_length--;
+ }
+ }
+ else
+ {
+ command_data[command_length++] = byte_received;
+ }
+ }
+ length_left--;
+ break;
+
+ case CommandState.GB_PRINTER_COMMAND_CHECKSUM_LOW:
+ checksum ^= byte_received;
+ break;
+
+ case CommandState.GB_PRINTER_COMMAND_CHECKSUM_HIGH:
+ checksum ^= (ushort)(byte_received << 8);
+ if (checksum != 0)
+ {
+ status |= 1; /* Checksum error*/
+ command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1;
+ return byte_to_send;
+ }
+ break;
+
+ case CommandState.GB_PRINTER_COMMAND_ACTIVE:
+ byte_to_send = 0x81;
+ break;
+
+ case CommandState.GB_PRINTER_COMMAND_STATUS:
+
+ if (((int)command_id & 0xF) == (byte)CommandID.GB_PRINTER_INIT_COMMAND)
+ {
+ /* Games expect INIT commands to return 0? */
+ byte_to_send = 0;
+ }
+ else
+ {
+ byte_to_send = status;
+ }
+
+ /* Printing is done instantly, but let the game recieve a 6 (Printing) status at least once, for compatibility */
+ if (status == 6)
+ {
+ status = 4; /* Done */
+ }
+
+ command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1;
+ HandleCommand();
+ return byte_to_send;
+ }
+
+ if (command_state >= CommandState.GB_PRINTER_COMMAND_ID && command_state < CommandState.GB_PRINTER_COMMAND_CHECKSUM_LOW)
+ {
+ checksum += byte_received;
+ }
+
+ if (command_state != CommandState.GB_PRINTER_COMMAND_DATA)
+ {
+ command_state++;
+ }
+
+ if (command_state == CommandState.GB_PRINTER_COMMAND_DATA)
+ {
+ if (length_left == 0)
+ {
+ command_state++;
+ }
+ }
+
+ return byte_to_send;
+ }
+
+ private void HandleCommand()
+ {
+ switch (command_id)
+ {
+ case CommandID.GB_PRINTER_INIT_COMMAND:
+ status = 0;
+ image_offset = 0;
+ break;
+
+ case CommandID.GB_PRINTER_START_COMMAND:
+ if (command_length == 4)
+ {
+ status = 6; /* Printing */
+ uint[] outputImage = new uint[image_offset];
+
+ int palette = command_data[2];
+ uint[] colors = {
+ 0xFFFFFFFFU,
+ 0xFFAAAAAAU,
+ 0xFF555555U,
+ 0xFF000000U
+ };
+ for (int i = 0; i < image_offset; i++)
+ {
+ outputImage[i] = colors[(palette >> (image[i] * 2)) & 3];
+ }
+
+ if (callback != null)
+ {
+ // The native-friendly callback almost seems silly now :P
+ unsafe
+ {
+ fixed (uint* imagePtr = outputImage)
+ {
+ callback((IntPtr)imagePtr, (byte)(image_offset / 160),
+ (byte)(command_data[1] >> 4), (byte)(command_data[1] & 7),
+ (byte)(command_data[3] & 0x7F));
+ }
+ }
+ }
+
+ image_offset = 0;
+ }
+ break;
+
+ case CommandID.GB_PRINTER_DATA_COMMAND:
+ if (command_length == GB_PRINTER_DATA_SIZE)
+ {
+ image_offset %= (ushort)image.Length;
+ status = 8; /* Received 0x280 bytes */
+
+ int data_index = 0;
+
+ for (int row = 2; row > 0; row--)
+ {
+ for (int tile_x = 0; tile_x < 160 / 8; tile_x++)
+ {
+ for (int y = 0; y < 8; y++, data_index += 2)
+ {
+ for (int x_pixel = 0; x_pixel < 8; x_pixel++)
+ {
+ image[image_offset + tile_x * 8 + x_pixel + y * 160] =
+ (byte)((command_data[data_index] >> 7) | ((command_data[data_index + 1] >> 7) << 1));
+ command_data[data_index] <<= 1;
+ command_data[data_index + 1] <<= 1;
+ }
+ }
+ }
+
+ image_offset += 8 * 160;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/submodules/gambatte b/submodules/gambatte
index 72630bfce7..dc50297053 160000
--- a/submodules/gambatte
+++ b/submodules/gambatte
@@ -1 +1 @@
-Subproject commit 72630bfce765fc8e9fd60e78de3c3fe4aae571a1
+Subproject commit dc50297053a3e8fff285629d735a9618b9406245