?

Log in

No account? Create an account
Gameboy Printer Simulator part 2: the software - 'Twas brillig, and the slithy toves did gyre and gimble in the wabe [entries|archive|friends|userinfo]
Thomas

[ website | Beware the Jabberwock... ]
[ deviantArt | the-boggyb ]
[ FanFiction | Torkell ]
[ Tumblr | torkellr ]

Links
[Random links| BBC news | Vulture Central | Slashdot | Dangerous Prototypes | LWN | Raspberry Pi]
[Fellow blogs| a Half Empty Glass | the Broken Cube | The Music Jungle | Please remove your feet | A letter from home]
[Other haunts| Un4seen Developments | Jazz 2 Online | EmuTalk.net | Feng's shui]

Gameboy Printer Simulator part 2: the software [Friday 5th April 2013 at 8:32 pm]
Thomas

boggyb
[Tags|, , ]
[Where |We are now approaching Barnham]
[Feeling |accomplishedaccomplished]
[Playing |Digitally Imported: Epic Trance]

Before I completely forget about it, here's the rest of that Gameboy Printer emulator post. This time, it's about the software.

There's two pieces of software that needed to be written for this: the Bus Pirate needed enough brains to pretend to be a Gameboy Printer, and a PC program needed to be written to actually turn the "printout" into an image. While the interface is slow enough that it could probably all be done on the computer, having the Bus Pirate do some of the work means that there's no timing issues.

The traditional way to do this sort of protocol emulation is to bit-bang it, by directly controlling a GPIO pin. But that's a rather brute-force way of doing things, and modern microcontrollers have a shedload of hardware units for speaking all sorts of different protocols. In the case of the PIC used on the Bus Pirate, it has a pair of SPI modules. These are perfectly capable of running as a SPI slave, which means all my code needs to do is take each byte as it arrives and display it. It also needs to track enough state to be able to send the necessary responses.

I started with the existing SPI sniffer code, and hacked it around until it could send as well as receive. I then added a pair of state machines: one to handle decoding the packets sent by the Gameboy and send the status/acknowledgement replies, and a second to ensure that the right status was sent. If I was writing this from scratch I'd need to come up with some way of getting the data to the computer, but the SPI sniffer mode in the Bus Pirate already has a set of functions for buffering data and feeding it to the serial UART as hex characters. This made it a lot easier to write, as the only really new bits were the state machines.

Once these were written and debugged (with thanks to Tros of #jj2 for spotting that I'd forgotten to actually turn on the output pin), I then just "printed" all the photos to the Bus Pirate and captured the output with a terminal client. This spat out a bunch of hex looking rather like the output from one of the earlier teaser posts. Except this time, I'll tell you how to understand it:

{0x01|0x00}
0x01|0x00
0x00|0x00
0x00|0x81
0x00|0x00


This is the basic packet format from my code. The code uses a mix of square [] and curly {} braces to mark certain things, and a vertical bar | to separate each byte. The curly braces contain the command and flags bytes - a command code of 0x01 is a status request.

The next four lines show the last few bytes of the packet. In each of those lines, the first byte shows what the Gameboy sent and the second shows what the Bus Pirate transmitted (which was actually sampled using the second SPI unit so I could check the bytes were being transmitted at the right time). The first two pairs show the checksum bytes from the Gameboy (which we ignore). For the final two pairs, the Gameboy sends a dummy 0x00 byte and reads in an acknowledgement byte (0x81) followed by a status byte. Simples!

Oh, the actual packet also includes a pair of synchronisation bytes (0x88, 0x33) at the start and two bytes of length immediately after the flags, but my code doesn't bother printing that.

{0x0F|0x00}
0x0F|0x00
0x00|0x00
0x00|0x81
0x00|0x00


Here the command code is 0x0F, which is a signal to prepare for printing. I've no idea what significance this actually has, if any.

{0x04|0x00}
[0xFF|0xFF|0xFF|0xFF| ... |0xFF|0xFF|0xFF|0xFF]
0xC6|0x00
0x0C|0x00
0x00|0x81
0x00|0x00


This one is slightly different, as this packet has actual data (which is much longer that what I've put there). The 0x04 command tells the printer that the Gameboy is sending it a chunk of image data, and my code displays this inside the square brackets. More about this image data later.

{0x02|0x00}
[0x01|0x13|0xE4|0x41]
0x3F|0x00
0x01|0x00
0x00|081
0x00|0x08


Finally we get a print command (0x02), which includes in the payload the margins and a value controlling how dark the resulting print is. At this point a real printer would go away and actually print stuff, and the Gameboy would send status commands every so often until the flags byte shows that the printer has finished. My emulation code just waits for about a second - I had some issues with reporting immediate success.

And now you know what the gibberish means.

The next stage is to turn said gibberish into actual pictures. The way the Gameboy encodes the images requires a bit of thought to decode. Rather than sending the data a line at a time, it splits the image into 8 pixel by 8 pixel tiles and sends these a row at a time. Within a tile, each successive pair of bytes encodes a row of pixels, starting with the topmost row in the tile. The first byte has the least significant bit of each pixel and the second byte the most significant bit. I'm sure this format makes perfect sense for the graphics hardware in the Gameboy, but it's rather unfriendly to decode on a PC.

I wrote a decoder in Java that runs through that log and extracts the images from it. It basically extract the image data from the log and does scary bit-mangling to decode the pixel values and draw them on screen, at which point it can be saved as a GIF or whatever. I need to modify it to split out multiple images in the same log - once I've done that, I'll post it online along with my Bus Pirate modifications (or if you can't wait for that - it'll be later rather than sooner - then feel free to ask me for the code). Then I can get started on Mystery Project number 2...
Link | Previous Entry | Share | Next Entry[ One penny | Penny for your thoughts? ]

Comments:
[User Picture]From: allegramente
Saturday 6th April 2013 at 8:07 am (UTC)
So what language have you used to write this post? 'Cos it sure ain't written in English English or American English or Singaporean English or Australian English.... or any English thst I've ever encountered!
(Reply) (Thread)