. . . . . . . . . . .
Nintendo, a name synonymous with innovation in gaming, consistently pushed the boundaries of its consoles. Each system release was often accompanied by a suite of accessories, adding unique and unexpected functionalities for gamers. The Game Boy, Nintendo’s groundbreaking handheld console, was no exception, boasting a wide array of add-ons. Among these, the Game Boy Printer stands out as a particularly inventive example.
The Game Boy Printer was a truly forward-thinking device for its time. The concept of a portable gaming system connecting to its own printer was practically unheard of. Moreover, the printer itself was remarkably compact, especially considering the technology available then. While undeniably brick-like by today’s standards, the Game Boy Printer was genuinely one of the smallest printers on the market during its heyday. Its primary appeal was undoubtedly its compatibility with the Game Boy Camera, allowing users to instantly print out their lo-fi digital snapshots. However, numerous other Game Boy games also leveraged the printer’s capabilities to output in-game content such as images, high scores, and even fun extras like badges or certificates.
My personal ambition with the GBE+ emulator project has always been to achieve the most comprehensive and accurate emulation possible. This naturally includes supporting peripherals like the Game Boy Printer. Truthfully, Game Boy Printer support has been on my radar for quite some time. However, it was only after significant advancements in the DMG/GBC core emulation that tackling printer functionality became feasible. Years ago, I attempted to get the Game Boy Printer working within VBA-M (version 1.8.0). Unfortunately, the Linux version seemed unresponsive – while it appeared to emulate the printer connection, I couldn’t locate any saved output images. The Windows version, in contrast, worked perfectly, displaying the printed image as expected. This experience, possibly due to user error on my part with the Linux setup, motivated me to one day create an emulator that would properly emulate the Game Boy Printer on Linux, my preferred operating system. But let’s set aside emulator development for a moment and delve into the inner workings of the Game Boy Printer and its communication with a Game Boy system.
How the Game Boy Printer Works: Beyond Ctrl+P
You might assume printing from a Game Boy would be as simple as hitting “Ctrl+P” on a computer. However, the process is quite different. The Game Boy Printer connects to a Game Boy via the Link Cable, the same interface used for multiplayer gaming. Communication between the two devices occurs through Serial Input/Output (Serial I/O). Essentially, the Game Boy transmits data to the Game Boy Printer in a manner analogous to how it communicates with another Game Boy during link cable gameplay. It sends data bytes sequentially over the Link Cable.
There are subtle yet crucial differences in this communication protocol. The Game Boy always assumes the role of the “master,” while the Game Boy Printer acts as the “slave.” The printer constantly listens for incoming commands from the Game Boy. It doesn’t initiate communication, making the “slave” designation appropriate. For the most part, the Game Boy Printer responds with a status byte, often 0x0, during data transmission, primarily sending back information about its operational status. This master-slave relationship means that Game Boy Printer serial communication doesn’t fully utilize the duplex capabilities of the Link Cable. However, for emulation purposes, this nuance is largely insignificant.
Communicating with the Game Boy Printer follows a defined protocol based on packets. A substantial block of data, referred to as a packet, is sent to the printer via Serial I/O, byte by byte. This data adheres to a specific structure that the Game Boy Printer interprets to understand how to process the incoming bytes. The structure of these Game Boy Printer packets is detailed below:
- Magic Bytes:
- Length: 2 Bytes
- Values: 0x88, 0x33
- Printer Command:
- Length: 1 Byte
- Values: 0x1 or 0x2 or 0x4 or 0xF
- Compression Flag:
- Length: 1 Byte
- Values: 0x0 or 0x1
- Packet Data Length:
- Length: 2 Bytes
- Values: 16-bit number, Least Significant Byte (LSB) first
- Actual Packet Data:
- Length: Varies
- Values: Data sent by the Game Boy
- Packet Checksum:
- Length: 2 Bytes
- Values: 16-bit checksum, LSB first
- Keepalive:
- Length: 1 Byte
- Values: 0x0
- Current Printer Status:
- Length: 1 Byte
- Values: 0x0
The “magic bytes” are essentially identifiers, a two-byte sequence (0x88, 0x33) that the Game Boy Printer checks to confirm that it’s receiving a valid printer packet rather than random noise. The printer command byte specifies the action the printer should perform. There are only four known commands, which we will explore shortly. The compression flag indicates whether the image data (dot-data) being sent is compressed or uncompressed. Dot-data, in this context, represents the Game Boy’s pixel data after palette application, essentially the image intended for printing. Since some commands include data (typically for image transmission or print settings), the packet includes a field to specify the length of the data section.
The Game Boy Printer also expects a 16-bit checksum for each packet. It calculates its own checksum based on the received bytes and compares it to the checksum sent in the packet. If they don’t match, it signals a communication error, ensuring data integrity during transmission. The checksum is calculated by summing all bytes from the Printer Command byte through the Packet Data.
Finally, at the packet’s end, the Game Boy sends two bytes, both invariably 0x0. The first acts as a “keepalive” message. The Game Boy Printer is supposed to respond with a specific byte (0x80 or 0x81) to acknowledge its continued operation after receiving the preceding packet bytes. While the printer usually sends back 0x0 while receiving data, these last two bytes trigger a non-zero response. The very last byte in the packet prompts the Game Boy Printer to send back its status code, which can be a non-zero value indicating various printer states.
Once the Game Boy Printer has received a complete packet, and assuming the checksums are valid, it proceeds to execute the command specified in the packet. There are four primary commands: INIT, PRINT, DATA (Process Data), and STATUS (0x01, 0x02, 0x04, and 0x0F, respectively). Let’s examine each of these commands in detail:
The Four Commands: Directing the Game Boy Printer
INIT – 0x1: Clearing the Buffer
The INIT command is the simplest of the four. Its sole function is to clear the Game Boy Printer’s internal RAM buffer. The printer has a buffer just large enough to hold a 160×144 pixel image (at 2 bits per pixel). When the INIT command is received, the printer erases this buffer, discarding any image data previously stored.
PRINT – 0x2: Bringing Pixels to Paper
The PRINT command is what triggers the actual printing process. It instructs the Game Boy Printer to print the image currently stored in its buffer. Unlike the other commands, PRINT takes a noticeable amount of time to execute in real-world operation because the printer physically engages its mechanisms, moving gears and paper. However, in the realm of emulation, the printing process becomes virtually instantaneous. A real Game Boy should ideally wait for the Game Boy Printer to update its status (signaling print completion) after issuing a PRINT command.
The PRINT command packet always includes 4 data bytes in its data section. These bytes are used to configure print settings:
- Byte 1: Always 0x1. Its purpose remains unknown.
- Byte 2: Printing margins. The high nibble (upper 4 bits) controls the margin before the image, and the low nibble (lower 4 bits) sets the margin after the image.
- Byte 3: Palette. This byte functions identically to the Game Boy’s BGP (Background Palette) register, determining the color palette used for printing. It’s frequently set to 0xE4.
- Byte 4: A 7-bit value that adjusts the exposure time of the thermal print head, affecting print darkness.
DATA – 0x4: Sending Image Data Segments
The DATA command is used to transmit image data (dot-data) to the Game Boy Printer, allowing it to build up an image in its buffer. For each DATA command sent, the printer can receive enough dot-data to represent a 160×16 pixel segment of the overall image. By sending multiple DATA commands, the Game Boy gradually constructs a complete 160×144 pixel image within the printer’s memory. In essence, sending nine DATA command packets is sufficient to transmit a full page ready for printing. Games can, of course, send fewer than nine segments to print smaller images. If the compression flag in the packet is set, the Game Boy Printer will decompress the incoming dot-data during processing of the DATA command.
STATUS – 0xF: Checking Printer Health
The STATUS command is straightforward. It requests the Game Boy Printer to return a single byte indicating its current status to the Game Boy. While the printer already sends a status byte after each packet reception, the STATUS command is still valuable. Packets using the STATUS command are minimal in size (only 9 bytes), providing a quick way to “ping” the printer without needing to send a dummy DATA command (for example, a DATA command with no actual data). The Game Boy Printer has a comprehensive set of status codes, covering various conditions from communication timeouts and battery issues to temperature problems and paper jams. More detailed information about these status codes can be found here.
Sending and processing these packets inevitably takes time. Many games cleverly masked this data transfer period by displaying animations like the one shown above while the commands were being executed in the background.
The typical workflow for printing involves a game first sending an INIT command to clear the buffer, followed by a series of DATA commands to transmit the image data segments. Once sufficient dot-data has been sent, the game issues a PRINT command to start printing. Subsequently, it may send STATUS commands to monitor the printer’s state and confirm print completion. After printing is done, the game can optionally send another INIT command to prepare for the next print job, repeating the process. The Game Boy Printer is even capable of printing elongated images by repeating this sequence multiple times with print margins set to zero, creating a continuous print output. For example, the Pokédex entries in Pokémon Gold, Silver, and Crystal are implemented as two separate images printed consecutively. Now that we have a solid understanding of how the Game Boy Printer operates, let’s delve into the process of emulating it within GBE+.
Emulating the Game Boy Printer: Bridging the Digital and (Virtual) Physical
Emulation Setup: Serial I/O Foundation
The fundamental prerequisite for any Game Boy Printer emulation is functional Serial I/O emulation, essentially Link Cable emulation. When I began working on Game Boy Printer support for GBE+, I had recently completed the implementation of netplay functionality. This meant the emulator already had the necessary infrastructure to handle Serial I/O, making the printer emulation significantly easier. Unlike netplay between two emulated Game Boys, communicating with an emulated Game Boy Printer is considerably simpler and doesn’t require any network connection. Instead of sending data bytes to another instance of GBE+ over a network, the emulator simply directs the data to internal code modules designed to mimic the behavior of a Game Boy Printer. So, instead of utilizing SDL_net and network protocols, the data is directly fed to internal C++ functions.
Packet Handling: State Machine Approach
The next crucial step was to accurately receive and interpret the packets being sent by the emulated game over the Link Cable. I decided the most effective approach was to have the emulated Game Boy Printer listen for the “magic bytes” (0x88, 0x33) that signal the start of a valid packet and then process each section of the packet sequentially according to the protocol. To manage this, I implemented a C++ enumeration to represent the different states of the printer emulation – from waiting for the initial magic bytes to handling each part of the packet, executing commands, and simulating the printing process. Essentially, the emulated Game Boy Printer functions as a simplified state machine, ensuring that packet processing occurs in the correct order. Handling the packet data itself was relatively straightforward and didn’t present significant challenges.
Data Processing and “Printing” (Bitmap Saving)
With packet reception and command interpretation in place, the emulated Game Boy Printer could correctly receive and process commands. The next step was to handle the image data sent via DATA commands and simulate the printing process. GBE+ accumulates the dot-data received from all DATA commands and stores it in an internal buffer. The emulator needs to track the number of DATA commands received to manage the buffer correctly, particularly in cases where more than the expected number of DATA commands are sent (although, in my testing, no commercial games exhibited this behavior). Initially, I focused on supporting uncompressed data only. The majority of Game Boy Printer-compatible games use uncompressed data, providing ample test cases. In fact, Pokémon Trading Card Game was the only game I encountered that utilized compressed dot-data. The process of “printing” the dot-data in emulation is conceptually similar to rendering graphics from the Game Boy’s Video RAM (VRAM). The dot-data format is essentially identical to the Game Boy’s tile data format. From this in-memory representation, I implemented functions to convert the buffer into a bitmap file, effectively simulating the printed output. And just like that, basic Game Boy Printer emulation was achieved!
Of course, achieving accurate emulation often requires some degree of trial and error to fine-tune the implementation and resolve unexpected issues.
The Case of the Empty DATA Commands
While emulating the Game Boy Printer proved to be relatively uncomplicated overall, I did encounter one particularly perplexing issue. For reasons that remain unclear, many games would send “empty” DATA commands. That is, they would transmit a DATA command packet, but the Packet Data Length field would be set to zero, and the packet would contain no actual dot-data bytes. This initially threw me off. My emulation logic assumed that every DATA command would contribute to building the image buffer. For example, even when encountering a dummy DATA command, my emulator would still advance the buffer pointer by 160×16 pixels, assuming data was received. This resulted in the top portion of the emulated printouts consistently being blank. This issue was initially confusing and led me to suspect problems with printing margins, which turned out to be a red herring. In emulation, printing margins can be effectively disregarded. If the emulated printer outputs an image larger than 160×144 pixels, GBE+ simply splits it into multiple bitmap files. Printing margins would only become relevant if you were attempting to stitch these split bitmaps back together into a single continuous image. Ultimately, these dummy DATA commands were the main source of frustration during the emulation process.
Decoding Compression: Run-Length Encoding Unveiled
One of the final aspects of Game Boy Printer emulation I tackled was support for data compression. As mentioned earlier, most games opted for uncompressed data, likely due to its simplicity (often directly transferring existing tile data from VRAM). However, a few games do utilize compression to reduce data transfer size. The compression algorithm employed by the Game Boy Printer is based on Run-Length Encoding (RLE). The stream of bytes sent to the printer is divided into “compressed” and “uncompressed” segments, referred to as “runs.” When the printer encounters an uncompressed run, it simply copies the data as is. When it encounters a compressed run, it replicates a preceding byte a specified number of times.
Let’s illustrate this with a fictional example data stream. Imagine we have the following raw, uncompressed data:
0xFF 0xFF 0xFF 0xFF 0xFE 0x02 0x55 0x33 0x90
Notice the sequence of repeating bytes: 0xFF 0xFF 0xFF 0xFF. This is the same byte (0xFF) repeated four times, making it suitable for run-length encoding. The remaining portion of the data stream (0xFE 0x02 0x55 0x33 0x90) lacks any repeating patterns and will remain uncompressed. The Game Boy Printer’s RLE implementation requires inserting control bytes into the data stream to indicate whether subsequent data is compressed or uncompressed. These control bytes are simple and follow a consistent structure. The Most Significant Bit (MSB) of the control byte determines the run type (compressed or uncompressed), and bits 0-6 specify the length of the run in bytes:
Compressed Run:
Bit 7 (MSB) is set (1). Bits 0-6 represent the run length minus 2.
Uncompressed Run:
Bit 7 (MSB) is unset (0). Bits 0-6 represent the run length minus 1.
Applying this RLE scheme to our example data, the compressed stream becomes:
0x82 0xFF 0x04 0xFE 0x02 0x55 0x33 0x90
Here’s how it works: The byte 0x82 (binary 10000010) signals a compressed run because the MSB is set. Bits 0-6 (0000010) represent the value 2. Adding 2 to this value gives us 4, indicating that the following byte (0xFF) should be repeated four times. Thus, the printer expands this to 0xFF 0xFF 0xFF 0xFF. Next, the byte 0x04 (binary 00000100) signals an uncompressed run (MSB is unset). Bits 0-6 (0000100) represent the value 4. Adding 1 to this value gives us 5, indicating that the next 5 bytes should be copied directly as uncompressed data. These 5 bytes are 0xFE 0x02 0x55 0x33 0x90. And that’s the essence of the Game Boy Printer’s run-length encoding.
Going Paperless
That concludes my exploration of the Game Boy Printer. It’s a testament to Nintendo’s ingenuity – a functional printer small enough to hold in your hand, powered by a handheld gaming device. Despite its innovative nature, game developer adoption was somewhat limited. According to Wikipedia, only 38 games are known to officially support the Game Boy Printer. Considering the vast Game Boy game library, this is a relatively small fraction. This trend of limited adoption for cool Game Boy peripherals was common with Nintendo; even first-party titles often overlooked accessories like the Game Boy Printer. Nevertheless, the Game Boy Printer enjoyed broader support compared to other peripherals like the Transfer Pak or the Game Boy Color’s IR port.
With GBE+ now supporting the Game Boy Printer, a personal emulation goal has been achieved. Now, I can “print” to my heart’s content, limited only by disk space. No more worries about running out of 6 AA batteries! I’ll never need to buy printer paper again! And the emulated printer is guaranteed never to jam!