Retro Invaders a space invaders clone by Chris Favreau. Written for the RetroMbuino development board from outrageouscircuits.com for the game programming contest.

Dependencies:   mbed

This is a space invaders clone written for the Retro Mbuino from outrageous circuits.

Development board: http://www.outrageouscircuits.com/shop/product/15 ).

The game itself is basic space invaders. Shoot them before they get to the bottom of the screen. It has a UFO saucer which you can shoot for extra points. You get 4 shields and each shield can be hit up to 4 times before it is gone. Hmm... as each level increases the speed of the invaders shots goes up. The invaders only speed up when there is less of them. You complete the level when you shoot all the invaders. The game ends when a) you run out of lives (you start with 3) or the invaders get to the bottom.

The LEDs turned out to be a pretty cool addition to the game. I wrote a class that blinks them and turns them on for a specified amount of time. They add a nice extra to the game. I use them on the intro screen and when the UFO is present.

The sound turned out to be really difficult for a few reasons. The biggest was that I had never written a sound engine before. The interrupt service routine working off the timer was the easier part. I also had a lot of trouble because there is no filter to filter out the PWM frequency to the speaker... so I had to run the PWM frequency way up there 30 kHz.

The graphics turned out to be a bit of a bear too. Thanks to Chris Taylor for his really great LCD API. I picked up a couple of frames per second from that. I had modified the DisplayN18 class for blitting a single line buffer to the LCD panel however his is a little faster for some reason? I used a different approach to doing the graphics (as I have very little experience with anything other than double buffered displays). I have a tile map and a list of sprites. Each tile/sprite is 1 bit 8x8. They could be bigger. I ran out of time. That much is not special. What is different from what I can tell is that I use a 1 line buffer that is 160 shorts long. The render function first adds the tile map data into the line buffer first. Then the sprites are added over the existing data. You can have a great deal of different sprites and maps going to the screen and just have to rewrite the LCD memory once per frame. After each line is composited, the line is then drawn to the LCD. Kind of like an Atari 2600. Each sprite/tile has a foreground and background color and can be different from the other tiles/sprites. There is one color reserved for Transparency.

There are 16 colors to choose from. I chose a palette based on the Macintosh OS 4.1 palette I found on WikiPedia. It is a very nice mix of colors.

I found a sprite editor called SpriteX ( https://code.google.com/p/spritesx-ed/ )... it works nicely except that the 16x16 sprites are in a weird format. Time limited me to 8x8 sprites. Oh well.

I used nokring to make the music. It makes RTTTL formatted ring tones which my sound api can play. Here is a useful site that has lots of arcade/video game ring tones with a link to nokring in the utilities page. http://arcadetones.emuunlim.com/files.htm

Other than all that stuff I used state machines to do most of the game logic. Please excuse the horrible coding as I tried to comment a lot of it however it is not very nice to look at. Lots of long functions...

Files at this revision

API Documentation at this revision

Comitter:
cfavreau
Date:
Tue Mar 03 04:26:01 2015 +0000
Commit message:
Retro Invaders by Chris Favreau for the RetroMbuino Platform - outrageouscircuits.com game programming contest.

Changed in this revision

Display/BurstSPI.cpp Show annotated file Show diff for this revision Revisions of this file
Display/BurstSPI.h Show annotated file Show diff for this revision Revisions of this file
Display/DisplayN18.cpp Show annotated file Show diff for this revision Revisions of this file
Display/DisplayN18.h Show annotated file Show diff for this revision Revisions of this file
Display/LCD_ST7735.cpp Show annotated file Show diff for this revision Revisions of this file
Display/LCD_ST7735.h Show annotated file Show diff for this revision Revisions of this file
Display/colors.h Show annotated file Show diff for this revision Revisions of this file
Display/display.cpp Show annotated file Show diff for this revision Revisions of this file
Display/display.h Show annotated file Show diff for this revision Revisions of this file
Display/font8x8.cpp Show annotated file Show diff for this revision Revisions of this file
Display/font8x8.h Show annotated file Show diff for this revision Revisions of this file
Game.cpp Show annotated file Show diff for this revision Revisions of this file
Game.h Show annotated file Show diff for this revision Revisions of this file
Input/input.cpp Show annotated file Show diff for this revision Revisions of this file
Input/input.h Show annotated file Show diff for this revision Revisions of this file
Main.cpp Show annotated file Show diff for this revision Revisions of this file
Sound/lpc111x.h Show annotated file Show diff for this revision Revisions of this file
Sound/sound.cpp Show annotated file Show diff for this revision Revisions of this file
Sound/sound.h Show annotated file Show diff for this revision Revisions of this file
led/led.cpp Show annotated file Show diff for this revision Revisions of this file
led/led.h Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r c79e1f29f029 Display/BurstSPI.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Display/BurstSPI.cpp	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,20 @@
+#if defined(TARGET_LPC1768) || defined(TARGET_LPC1114) || defined(TARGET_LPC11U24) || defined(TARGET_LPC13XX)
+#include "BurstSPI.h"
+ 
+void BurstSPI::fastWrite(int data) {
+    //Wait until FIFO has space
+    while(((_spi.spi->SR) & 0x02) == 0);
+    
+    //transmit data
+    _spi.spi->DR = data;
+    }
+ 
+void BurstSPI::clearRX( void ) {
+    //Do it while either data in RX buffer, or while it is busy
+    while(((_spi.spi->SR) & ((1<<4) + (1<<2))) != 0) {
+        //Wait until data in RX buffer
+        while(((_spi.spi->SR) & (1<<2)) == 0);
+        int dummy = _spi.spi->DR;
+        }
+}
+#endif
diff -r 000000000000 -r c79e1f29f029 Display/BurstSPI.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Display/BurstSPI.h	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,114 @@
+#ifndef BURSTSPI_H
+#define BURSTSPI_H
+ 
+#include "mbed.h"
+ 
+ 
+/** An SPI Master, used for communicating with SPI slave devices at very high speeds
+ *
+ * The default mbed SPI class allows for communication via the SPI bus at high clock frequencies,
+ * however at these frequencies there is alot of overhead from the mbed code.
+ * While this code makes sure your code is alot more robust, it is also relative slow.
+ * This library adds to your default SPI commands some extra commands to transmit data rapidly with
+ * very little overhead. Downsides are that currently it is TX only (all RX packets are discarded),
+ * and it requires some extra commands.
+ *
+ * Example:
+ * @code
+ *  //Send 1000 SPI packets as fast as possible
+ *  spi.setFormat();
+ *  for (int i = 0; i<1000; i++)
+ *    spi.fastWrite(data[i]);
+ *  spi.clearRX();
+ * @endcode
+ *
+ * As an example, writing 76,800 16-bit data packets to an LCD screen at 48MHz requires 111ms with
+ * the normal mbed library. With this library it takes 25ms, which is also the theoretical
+ * amount of time it should take. If you are running at 1MHz this will do alot less.
+ */
+class BurstSPI : public SPI
+{
+public:
+    /** Create a SPI master connected to the specified pins
+    *
+    * Pin Options:
+    *  (5, 6, 7) or (11, 12, 13)
+    *
+    *  mosi or miso can be specfied as NC if not used
+    *
+    *  @param mosi SPI Master Out, Slave In pin
+    *  @param miso SPI Master In, Slave Out pin
+    *  @param sclk SPI Clock pin
+    */
+    BurstSPI(PinName mosi, PinName miso, PinName sclk) : SPI(mosi, miso, sclk) {};
+ 
+    /** Put data packet in the SPI TX FIFO buffer
+    *
+    *  If there is no space in the FIFO buffer it will block until there is space.
+    * The FIFO buffer will automatically send the packets. There is no receiving here, only transmitting.
+    *
+    *  @param data Data to be sent to the SPI slave
+    */
+    void fastWrite(int data);
+ 
+    /** Use this function before fastWrite to set the correct settings
+    *
+    * It is not needed to use this if the last SPI commands were either normal SPI transmissions,
+    * or setting different format/frequency for this object. It is required to call this
+    * function when several SPI objects use the same peripheral, and your last transmission was
+    * from a different object with different settings. Not sure if you should use it?
+    * Use it, it takes very little time to execute, so can't hurt.
+    */
+    void setFormat( void ) {
+        format(_bits, _mode);
+        frequency(_hz);
+    }
+ 
+    /** After you are done with fastWrite, call this function
+    *
+    * FastWrite simply fills the SPI's (SSP's actually) TX FIFO buffer as fast as it can,
+    * and that is the only thing it does. It doesn't do anything with received packages (currently, may change),
+    * so the the RX buffer is full with unneeded packets. This function waits until transmission is finished,
+    * and clears the RX buffer. You always have to call this before you want to receive
+    * SPI data after using fastWrite.
+    */
+    void clearRX( void );
+ 
+ 
+    //Just for documentation:
+#if 0
+    /** Configure the data transmission format
+     *
+     *  @param bits Number of bits per SPI frame (4 - 16)
+     *  @param mode Clock polarity and phase mode (0 - 3)
+     *
+     * @code
+     * mode | POL PHA
+     * -----+--------
+     *   0  |  0   0
+     *   1  |  0   1
+     *   2  |  1   0
+     *   3  |  1   1
+     * @endcode
+     */
+    void format(int bits, int mode = 0);
+ 
+    /** Set the spi bus clock frequency
+     *
+     *  @param hz SCLK frequency in hz (default = 1MHz)
+     */
+    void frequency(int hz = 1000000);
+ 
+    /** Write to the SPI Slave and return the response
+     *
+     *  @param value Data to be sent to the SPI slave
+     *
+     *  @returns
+     *    Response from the SPI slave
+    */
+    virtual int write(int value);
+#endif
+ 
+};
+ 
+#endif
diff -r 000000000000 -r c79e1f29f029 Display/DisplayN18.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Display/DisplayN18.cpp	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,475 @@
+#include "DisplayN18.h"
+
+DisplayN18::DisplayN18() : resetPin(P0_20), backlightPin(P0_19), rsPin(P0_7), csPin(P0_2), spi(P0_21, P0_22, P1_15) {
+    
+    //buffer = new unsigned char[512];
+    //memset(buffer, 0, 512);
+    buffer = new unsigned char[320];
+    memset(buffer, 0, 320);
+    
+    this->resetPin.write(false);
+    this->backlightPin.write(true);
+    this->rsPin.write(false);
+    
+    this->spi.format(8, 3);
+    this->spi.frequency(15000000);
+    
+    this->initialize();
+}
+
+void DisplayN18::writeCommand(unsigned char command) {
+    this->rsPin.write(false);
+    
+    this->csPin.write(false);
+    
+    this->spi.write(command);
+    
+    this->csPin.write(true);
+}
+
+void DisplayN18::writeData(unsigned char data) {
+    this->writeData(&data, 1);
+}
+
+void DisplayN18::writeData(const unsigned char* data, unsigned int length) {
+    this->rsPin.write(true);
+    
+    this->csPin.write(false);
+    
+    for (unsigned int i = 0; i < length; i++)
+        // Turbo Time! Use the Burst SPI FastWrite! (from Erik Olieman -> http://developer.mbed.org/users/Sissors/code/BurstSPI/)
+        this->spi.fastWrite(data[i]);
+    //   this->spi.write(data[i]);
+    
+    spi.clearRX();
+    
+    this->csPin.write(true);
+}
+
+void DisplayN18::reset() {
+    this->resetPin.write(false);
+    wait_ms(300);
+    
+    this->resetPin.write(true);
+    wait_ms(500);
+}
+
+void DisplayN18::initialize() {
+    this->reset();
+
+    // Sleep Out - Turn sleep mode off
+    this->writeCommand(0x11);
+    
+    wait_ms(120);
+
+    // SETPOWER
+    this->writeCommand(0xB1);
+    this->writeData(0x01); this->writeData(0x2C); this->writeData(0x2D);
+    // SETDISP
+    this->writeCommand(0xB2);
+    this->writeData(0x01); this->writeData(0x2C); this->writeData(0x2D);
+    // SETLUT
+    this->writeCommand(0xB3);
+    this->writeData(0x01); this->writeData(0x2C); this->writeData(0x2D);
+    this->writeData(0x01); this->writeData(0x2C); this->writeData(0x2D);
+
+    // SETCYC
+    this->writeCommand(0xB4);
+    this->writeData(0x07);
+
+    // SETSTBA
+    this->writeCommand(0xC0);
+    this->writeData(0xA2); this->writeData(0x02); this->writeData(0x84);
+    // SETPFUSE
+    this->writeCommand(0xC1); this->writeData(0xC5);
+    // What does this do?
+    this->writeCommand(0xC2);
+    this->writeData(0x0A); this->writeData(0x00);
+    // What does this do?
+    this->writeCommand(0xC3);
+    this->writeData(0x8A); this->writeData(0x2A);
+    // SetID
+    this->writeCommand(0xC4);
+    this->writeData(0x8A); this->writeData(0xEE);
+    // What does this do?
+    this->writeCommand(0xC5);
+    this->writeData(0x0E);
+
+    // Set Memory Access Control
+    this->writeCommand(0x36);
+    this->writeData(0xA8);
+
+    // Read Internal Oscillator
+    this->writeCommand(0xe0);
+    this->writeData(0x0f); this->writeData(0x1a);
+    this->writeData(0x0f); this->writeData(0x18);
+    this->writeData(0x2f); this->writeData(0x28);
+    this->writeData(0x20); this->writeData(0x22);
+    this->writeData(0x1f); this->writeData(0x1b);
+    this->writeData(0x23); this->writeData(0x37); this->writeData(0x00);
+    this->writeData(0x07);
+    this->writeData(0x02); this->writeData(0x10);
+
+    // Read Power
+    this->writeCommand(0xe1);
+    this->writeData(0x0f); this->writeData(0x1b);
+    this->writeData(0x0f); this->writeData(0x17);
+    this->writeData(0x33); this->writeData(0x2c);
+    this->writeData(0x29); this->writeData(0x2e);
+    this->writeData(0x30); this->writeData(0x30);
+    this->writeData(0x39); this->writeData(0x3f);
+    this->writeData(0x00); this->writeData(0x07);
+    this->writeData(0x03); this->writeData(0x10);
+
+    // Set the initial column and page address sets (clipping area)
+    this->writeCommand(0x2a);
+    this->writeData(0x00); this->writeData(0x00);
+    this->writeData(0x00); this->writeData(0x7f);
+    this->writeCommand(0x2b);
+    this->writeData(0x00); this->writeData(0x00);
+    this->writeData(0x00); this->writeData(0x9f);
+
+    // Read Source Option
+    this->writeCommand(0xF0);
+    this->writeData(0x01);
+    this->writeCommand(0xF6);
+    this->writeData(0x00);
+
+    // Set the pixel format (16 bits per pixel)
+    this->writeCommand(0x3A);
+    this->writeData(0x05);
+
+    // Turn on the display
+    this->writeCommand(0x29);
+
+    this->clear();
+}
+
+unsigned short *DisplayN18::getLineBuffer()
+{
+    // *** Tried buffering up all the commands however I think we need to toggle the CS pin or something
+    // in order to execute the command... so we cannot just buffer and send everything at once...
+    // Anyhoo.. ran out of time so we have to try this some other time...
+    // Have to return a pointer on a 4 byte boundary I think!
+    //return (unsigned short *)&buffer[12];
+    // Just return the base buffer for now
+    return (unsigned short *)buffer;
+}
+    
+void DisplayN18::blitLine(unsigned char line)
+{
+    this->setClippingArea(0, line, 159, 0);
+    this->writeCommand(0x2C);
+    this->writeData(buffer, 160 * 1 * 2);
+    
+    // *** Tried buffering up all the commands however I think we need to toggle the CS pin or something
+    // in order to execute the command... so we cannot just buffer and send everything at once...
+    // Anyhoo.. ran out of time so we have to try this some other time...
+    /*
+    // Setup column address set
+    buffer[0] = 0;
+    buffer[1] = 0x2A;
+    buffer[2] = 0;
+    buffer[3] = 0;      // x
+    buffer[4] = 0;
+    buffer[5] = 159;    // x + (width - 1)
+    buffer[6] = 0x2B;
+    buffer[7] = 0;
+    buffer[8] = line;   // y
+    buffer[9] = 0;
+    buffer[10] = line;   // y + (height - 1)
+    // Write Command
+    buffer[11] = 0x2C;
+    
+    //buffer[0] = 0;
+    //buffer[1] = 0x2C;
+    // Everything else is a buffer of 160 unsigned shorts
+    // Already should be filled out....
+    
+    // Write the buffer to the display
+    writeData(&buffer[1], 11 + (160 * 2));
+    */
+}
+
+void DisplayN18::setClippingArea(unsigned char x, unsigned char y, unsigned char width, unsigned char height) {
+    unsigned char data[4] = { 0x00, 0x00, 0x00, 0x00 };
+
+    // Set the Column Address Set
+    data[1] = x;
+    data[3] = x + width;
+    this->writeCommand(0x2A);
+    this->writeData(data, 4);
+
+    // Set the Page Address Set
+    data[1] = y;
+    data[3] = y + height;
+    this->writeCommand(0x2B);
+    this->writeData(data, 4);
+}
+
+unsigned short DisplayN18::rgbToShort(unsigned char r, unsigned char g, unsigned char b) {   
+unsigned short red = r;
+    unsigned short green = g;
+    unsigned short blue = b;
+
+    red /= 8;
+    green /= 4;
+    blue /= 8;
+
+    red &= 0x1F;
+    green &= 0x3F;
+    blue &= 0x1F;
+
+    red <<= 8;//3;
+    blue <<= 3;//8;
+    green = ((green & 0x7) << 13) + ((green & 0x38) >> 3);
+
+    return red | green | blue;
+}
+
+void DisplayN18::clear(unsigned short backColor) {
+    for (unsigned int i = 0; i < LCD_WIDTH; i += 10)
+        for (unsigned int j = 0; j < LCD_HEIGHT; j += 8)
+            this->fillRect(i, j, 10, 8, backColor);
+}
+
+void DisplayN18::draw(const unsigned short* data, int x, int y, int width, int height) {
+    this->setClippingArea(x, y, width - 1, height - 1);
+    this->writeCommand(0x2C);
+    this->writeData(reinterpret_cast<const unsigned char*>(data), width * height * 2);
+}
+
+void DisplayN18::setPixel(int x, int y, unsigned short foreColor) {
+    this->draw(&foreColor, x, y, 1, 1);
+}
+
+void DisplayN18::fillRect(int x, int y, int width, int height, unsigned short foreColor) {
+    this->setClippingArea(static_cast<unsigned char>(x), static_cast<unsigned char>(y), static_cast<unsigned char>(width - 1), static_cast<unsigned char>(height));
+    
+    this->writeCommand(0x2C);
+    
+    unsigned short buffer[50];
+    for (int j = 0; j < sizeof(buffer) / 2; j++)
+        buffer[j] = foreColor;
+
+    this->rsPin.write(true);
+
+    int i;
+    for (i = sizeof(buffer); i < height * width * 2; i += sizeof(buffer))
+        this->writeData(reinterpret_cast<unsigned char*>(buffer), sizeof(buffer));
+    
+    i -= sizeof(buffer);
+    if (i != height * width * 2)
+        this->writeData(reinterpret_cast<unsigned char*>(buffer), height * width * 2 - i);
+}
+
+void DisplayN18::drawRect(int x, int y, int width, int height, unsigned short foreColor) {
+    this->drawLine(x, y, x + width, y, foreColor);
+    this->drawLine(x, y + height, x + width, y + height, foreColor);
+    this->drawLine(x, y, x, y + height, foreColor);
+    this->drawLine(x + width, y, x + width, y + height, foreColor);
+}
+
+void DisplayN18::fillCircle(int x, int y, int radius, unsigned short foreColor) {
+    int f = 1 - radius;
+    int dd_f_x = 1;
+    int dd_f_y = -2 * radius;
+    int x1 = 0;
+    int y1 = radius;
+
+    for (int i = y - radius; i <= y + radius; i++)
+        this->setPixel(x, i, foreColor);
+
+    while (x1 < y1) {
+        if (f >= 0) {
+            y1--;
+            dd_f_y += 2;
+            f += dd_f_y;
+        }
+
+        x1++;
+        dd_f_x += 2;
+        f += dd_f_x;
+
+        for (int i = y - y1; i <= y + y1; i++) {
+            this->setPixel(x + x1, i, foreColor);
+            this->setPixel(x - x1, i, foreColor);
+        }
+
+        for (int i = y - x1; i <= y + x1; i++) {
+            this->setPixel(x + y1, i, foreColor);
+            this->setPixel(x - y1, i, foreColor);
+        }
+    }
+}
+
+void DisplayN18::drawCircle(int x, int y, int radius, unsigned short foreColor) {
+    int f = 1 - radius;
+    int dd_f_x = 1;
+    int dd_f_y = -2 * radius;
+    int x1 = 0;
+    int y1 = radius;
+
+    this->setPixel(x, y + radius, foreColor);
+    this->setPixel(x, y - radius, foreColor);
+    this->setPixel(x + radius, y, foreColor);
+    this->setPixel(x - radius, y, foreColor);
+
+    while (x1 < y1) {
+        if (f >= 0) {
+            y1--;
+            dd_f_y += 2;
+            f += dd_f_y;
+        }
+
+        x1++;
+        dd_f_x += 2;
+        f += dd_f_x;
+
+        this->setPixel(x + x1, y + y1, foreColor);
+        this->setPixel(x - x1, y + y1, foreColor);
+        this->setPixel(x + x1, y - y1, foreColor);
+        this->setPixel(x - x1, y - y1, foreColor);
+
+        this->setPixel(x + y1, y + x1, foreColor);
+        this->setPixel(x - y1, y + x1, foreColor);
+        this->setPixel(x + y1, y - x1, foreColor);
+        this->setPixel(x - y1, y - x1, foreColor);
+    }
+}
+
+void DisplayN18::drawLine(int x0, int y0, int x1, int y1, unsigned short foreColor) {
+    if (x0 == x1) {
+        if (y1 < y0) {
+            int temp = y0;
+            y0 = y1;
+            y1 = temp;
+        }
+
+        this->setClippingArea(static_cast<unsigned char>(x0), static_cast<unsigned char>(y0), 0, static_cast<unsigned char>(y1 - y0 - 1));
+        this->writeCommand(0x2C);
+
+        unsigned short data[DisplayN18::STEP];
+        for (int i = 0; i < DisplayN18::STEP; i++)
+            data[i] = foreColor;
+
+        for (unsigned char thisY = y0; thisY < y1; thisY += DisplayN18::STEP)
+            this->writeData(reinterpret_cast<unsigned char*>(data), (thisY + DisplayN18::STEP <= y1 ? DisplayN18::STEP : y1 - thisY) * 2);
+
+        return;
+    }
+
+    if (y0 == y1) {
+        if (x1 < x0) {
+            int temp = x0;
+            x0 = x1;
+            x1 = temp;
+        }
+
+        this->setClippingArea(static_cast<unsigned char>(x0), static_cast<unsigned char>(y0), static_cast<unsigned char>(x1 - x0 - 1), 0);
+        this->writeCommand(0x2C);
+
+        unsigned short data[DisplayN18::STEP];
+        for (int i = 0; i < DisplayN18::STEP; i++)
+            data[i] = foreColor;
+
+        for (unsigned char thisX = x0; thisX < x1; thisX += DisplayN18::STEP)
+            this->writeData(reinterpret_cast<unsigned char*>(data), (thisX + DisplayN18::STEP <= x1 ? DisplayN18::STEP : x1 - thisX) * 2);
+
+        return;
+    }
+
+    int t;
+    bool steep = ((y1 - y0) < 0 ? -(y1 - y0) : (y1 - y0)) > ((x1 - x0) < 0 ? -(x1 - x0) : (x1 - x0));
+
+    if (steep) {
+        t = x0;
+        x0 = y0;
+        y0 = t;
+        t = x1;
+        x1 = y1;
+        y1 = t;
+    }
+
+    if (x0 > x1) {
+        t = x0;
+        x0 = x1;
+        x1 = t;
+
+        t = y0;
+        y0 = y1;
+        y1 = t;
+    }
+
+    int dx, dy;
+    dx = x1 - x0;
+    dy = (y1 - y0) < 0 ? -(y1 - y0) : (y1 - y0);
+
+    int err = (dx / 2);
+    int ystep;
+
+    ystep = y0 < y1 ? 1 : -1;
+
+    for (; x0 < x1; x0++) {
+        if (steep)
+            this->setPixel(y0, x0, foreColor);
+        else
+            this->setPixel(x0, y0, foreColor);
+
+        err -= dy;
+
+        if (err < 0) {
+            y0 += (char)ystep;
+            err += dx;
+        }
+    }
+}
+  
+void DisplayN18::drawBitmap(int x, int y, int w, int h, unsigned char *bitmap, unsigned short foreColor, unsigned short backColor)
+{
+    this->setClippingArea(x, y, w - 1, h);
+    this->writeCommand(0x2C);
+    
+    this->rsPin.write(true);
+    this->csPin.write(false);
+    
+    int length = ((h * w) / 8);
+    
+    for (unsigned int i = 0; i < length; i++)
+    {
+        unsigned short color = 0;
+        unsigned char data = bitmap[i];
+        for (unsigned int bit = 0; bit < 8; bit++)
+        {
+            color = (data & (1 << bit)) ? foreColor : backColor;
+            this->spi.write((unsigned char)(color >> 8));
+            this->spi.write((unsigned char)(color & 0x00FF));
+        }
+    }
+    
+    this->csPin.write(true);
+}
+/*
+void DisplayN18::drawCharacter(int x, int y, const char character, unsigned short foreColor, unsigned short backColor, unsigned char fontSize)
+{
+    if (character > 126 || character < 32) return;
+    drawBitmap(x, y, CHAR_WIDTH, CHAR_HEIGHT, &font8x8_basic[(character - 32) * 8], foreColor, backColor);
+}
+
+void DisplayN18::drawString(int x, int y, const char* str, unsigned short foreColor, unsigned short backColor, unsigned char fontSize) {
+    if (*str == '\0')
+        return;
+
+    do {
+        this->drawCharacter(x, y, *str, foreColor, backColor, fontSize);
+        
+        x += (CHAR_WIDTH + CHAR_SPACING) * fontSize;
+    } while (*(++str) != '\0');
+}
+
+unsigned char *DisplayN18::getCharBuffer()
+{
+    return font8x8_basic;
+}
+
+*/
diff -r 000000000000 -r c79e1f29f029 Display/DisplayN18.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Display/DisplayN18.h	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,76 @@
+#include "mbed.h"
+#include "BurstSPI.h"   // Fast SPI class
+#include "font8x8.h"    // Default 8x8 Font
+
+// Colors
+#define RGB2SHORT(r, g, b) (((r & 0xF8) << 8) | ((b & 0xFC) << 3) | (g >> 3))
+#define     BLUE    RGB2SHORT(0, 0, 255)
+#define     GREEN   RGB2SHORT(0, 255, 0)
+#define     RED     RGB2SHORT(255, 0, 0)
+#define     WHITE   RGB2SHORT(255, 255, 255)
+#define     BLACK   RGB2SHORT(0, 0, 0)
+#define     MAGENTA RGB2SHORT(255, 0, 255)      
+#define     CYAN    RGB2SHORT(0, 255, 255)
+#define     YELLOW  RGB2SHORT(255, 255, 0)
+
+#define LCD_WIDTH        160
+#define LCD_HEIGHT       128
+
+#pragma once
+
+class DisplayN18 {
+protected:
+    static const unsigned char STEP = 4;
+    
+    DigitalOut resetPin;
+    DigitalOut backlightPin;
+    DigitalOut rsPin;
+    DigitalOut csPin;
+    //SPI spi;
+    BurstSPI spi;
+    
+    unsigned char *buffer;
+
+    void writeCommand(unsigned char command);
+    void writeData(unsigned char data);
+    void writeData(const unsigned char* data, unsigned int length);
+
+    void reset();
+    void initialize();
+    void setClippingArea(unsigned char x, unsigned char y, unsigned char width, unsigned char height);
+    
+    public:
+        DisplayN18();
+        
+        // Either rgbToShort is backwards OR these were backwards.. so I reorganized the byte order.
+        /*
+        static const unsigned short BLUE = 0xF800;
+        static const unsigned short GREEN = 0x07E0;
+        static const unsigned short RED = 0x001F;
+        static const unsigned short WHITE = 0xFFFF;
+        static const unsigned short BLACK = 0x0000;
+        */
+
+        unsigned short *getLineBuffer();
+        void blitLine(unsigned char line);
+        
+        static unsigned short rgbToShort(unsigned char r, unsigned char g, unsigned char b);
+
+        void clear(unsigned short backColor = BLACK);
+        void draw(const unsigned short* data, int x, int y, int width, int height);
+        void setPixel(int x, int y, unsigned short foreColor);
+        
+        void drawBitmap(int x, int y, int w, int h, unsigned char *bitmap, unsigned short foreColor, unsigned short backColor);
+
+        void fillRect(int x, int y, int width, int height, unsigned short foreColor);
+        void drawRect(int x, int y, int width, int height, unsigned short foreColor);
+
+        void fillCircle(int x, int y, int radius, unsigned short foreColor);
+        void drawCircle(int x, int y, int radius, unsigned short foreColor);
+
+        void drawLine(int x0, int y0, int x1, int y1, unsigned short foreColor);
+
+        //unsigned char *getCharBuffer();
+        //void drawCharacter(int x, int y, const char character, unsigned short foreColor, unsigned short backColor, unsigned char fontSize = 1);
+        //void drawString(int x, int y, const char* str, unsigned short foreColor, unsigned short backColor, unsigned char fontSize = 1);
+};
\ No newline at end of file
diff -r 000000000000 -r c79e1f29f029 Display/LCD_ST7735.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Display/LCD_ST7735.cpp	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,692 @@
+#include "mbed.h"
+#include "LCD_ST7735.h"
+ 
+LCD_ST7735::LCD_ST7735(
+    PinName backlightPin,
+    PinName resetPin,
+    PinName dsPin,
+    PinName mosiPin,
+    PinName misoPin,
+    PinName clkPin,
+    PinName csPin,
+    PanelColorFilter colorFilter
+    ) :
+        _colorFilter(colorFilter),
+        _backlight(backlightPin, 0),
+        _reset(resetPin, 1),
+        _ds(dsPin, 0),
+        _cs(csPin, 1),
+        _spi(mosiPin, misoPin, clkPin)        
+{        
+    _spi.format(8, 3);
+    _spi.frequency(15000000);
+    
+    initDisplay();
+    setOrientation(Rotate270, false);
+    clearScreen();
+    setForegroundColor(0xffff);
+    setBackgroundColor(0x0000);
+}
+ 
+void LCD_ST7735::setOrientation(Orientation orientation, bool flip)
+{
+    const static uint8_t my = 0x80; 
+    const static uint8_t mx = 0x40;
+    const static uint8_t mv = 0x20;
+    
+    uint8_t madctlData = _colorFilter;
+    switch(orientation)
+    {
+        case Rotate0:
+            _width = 128;
+            _height = 160;
+            madctlData |= flip ? mx : 0;
+            break;
+            
+        case Rotate90:
+            _width = 160;
+            _height = 128;
+            madctlData |= flip ? my | mv | mx : mv | mx;
+            break;
+            
+        case Rotate180:
+            _width = 128;
+            _height = 160;
+            madctlData |= flip ? my : mx | my;
+            break;
+            
+        case Rotate270:
+            _width = 160;
+            _height = 128;
+            madctlData |= flip ? mv : mv | my;
+            break;
+    }
+    write(CMD_MADCTL, (uint8_t[]){madctlData}, 1);
+}
+ 
+int LCD_ST7735::getWidth()
+{
+    return _width;
+}
+        
+int LCD_ST7735::getHeight()
+{
+    return _height;
+}
+ 
+void LCD_ST7735::setBacklight(bool state)
+{
+    _backlight = state ? 1 : 0;
+}
+ 
+void LCD_ST7735::clearScreen(uint16_t color)
+{
+    clipRect(0, 0, _width - 1, _height - 1);
+    beginBatchCommand(CMD_RAMWR);
+    uint8_t colorHigh = color >> 8;
+    uint8_t colorLow = color;
+    for(int i = 0; i < 128 * 160 * 2; ++i)
+    {
+        writeBatchData(colorHigh, colorLow);
+    }
+    endBatchCommand();
+}
+ 
+void LCD_ST7735::setPixel(int x, int y, uint16_t color)
+{
+    write(CMD_CASET, (uint8_t[]){0, x, 0, x}, 4);    
+    write(CMD_RASET, (uint8_t[]){0, y, 0, y}, 4);    
+    write(CMD_RAMWR, color);
+}
+ 
+void LCD_ST7735::drawLine(int x1, int y1, int x2, int y2, uint16_t color)
+{
+    int dx = abs(x2 - x1);
+    int dy = abs(y2 - y1);
+    
+    if (dx == 0) 
+    {
+        drawVertLine(x1, y1, y2, color);
+        return;
+    }
+    else if(dy == 0)
+    {
+        drawHorizLine(x1, y1, x2, color);
+        return;
+    }
+   
+    int sx = (x1 < x2) ? 1 : -1;
+    int sy = (y1 < y2) ? 1 : -1;
+    int err = dx - dy;
+    while(x1 != x2 || y1 != y2)
+    {
+        setPixel(x1, y1, color);
+        int e2 = err << 1;
+        if (e2 > -dy)
+        {
+            err -= dy;
+            x1 += sx;            
+        }
+        if (e2 < dx)
+        {
+            err += dx;
+            y1 += sy;
+        }
+    }
+    setPixel(x2, y2, color);
+}
+ 
+void LCD_ST7735::swap(int &a, int &b)
+{
+    int t = a;
+    a = b;
+    b = t;
+}
+ 
+void LCD_ST7735::drawRect(int x1, int y1, int x2, int y2, uint16_t color)
+{
+    if (x1 > x2) swap(x1, x2);
+    if (y1 > y2) swap(y1, y2);
+    
+    drawHorizLine(x1, y1, x2, color);
+    drawHorizLine(x1, y2, x2, color);
+    drawVertLine(x1, y1, y2, color);
+    drawVertLine(x2, y1, y2, color);
+}
+ 
+void LCD_ST7735::drawCircle(int x, int y, int r, uint16_t color)
+{
+    int ix = r;
+    int iy = 0;
+    int err = 1 - r;
+    
+    while(ix >= iy)
+    {
+        setPixel(x + ix, y + iy, color);
+        setPixel(x + iy, y + ix, color);
+        setPixel(x - ix, y + iy, color);
+        setPixel(x - iy, y + ix, color);
+        setPixel(x - ix, y - iy, color);
+        setPixel(x - iy, y - ix, color);
+        setPixel(x + ix, y - iy, color);
+        setPixel(x + iy, y - ix, color);
+        iy++;
+        if (err < 0)
+        {
+            err += 2 * iy + 1;
+        }
+        else
+        {
+            ix--;
+            err += 2 * (iy - ix + 1);
+        }
+    }
+}
+ 
+void LCD_ST7735::drawEllipse(int x, int y, int rx, int ry, uint16_t color)
+{
+    int a2 = rx * rx;
+    int b2 = ry * ry;
+    int fa2 = 4 * a2;
+    int fb2 = 4 * b2;
+    
+    int ix, iy, sigma;    
+    for (ix = 0, iy = ry, sigma = 2 * b2 + a2 * (1 - 2 * ry); b2 * ix <= a2 * iy; ix++)
+    {
+        setPixel(x + ix, y + iy, color);
+        setPixel(x - ix, y + iy, color);
+        setPixel(x + ix, y - iy, color);
+        setPixel(x - ix, y - iy, color);
+        if (sigma >= 0)
+        {
+            sigma+= fa2 * (1 - iy);
+            iy--;
+        }
+        sigma += b2 * ((4 * ix) + 6);
+    }
+    
+    for (ix = rx, iy = 0, sigma = 2 * a2 + b2 * (1 - 2 * rx); a2 * iy <= b2 * ix; iy++)
+    {
+        setPixel(x + ix, y + iy, color);
+        setPixel(x - ix, y + iy, color);
+        setPixel(x + ix, y - iy, color);
+        setPixel(x - ix, y - iy, color);
+        if (sigma >= 0)
+        {
+            sigma+= fb2 * (1 - ix);
+            ix--;
+        }
+        sigma += a2 * ((4 * iy) + 6);
+    }
+}
+void LCD_ST7735::fillRect(int x1, int y1, int x2, int y2, uint16_t fillColor)
+{
+    if (x1 > x2) swap(x1, x2);
+    if (y1 > y2) swap(y1, y2);
+    
+    clipRect(x1, y1, x2, y2);
+    int c = ((x2-x1) * (y2-y1)) << 1;
+    uint8_t colorHigh = fillColor >> 8;
+    uint8_t colorLow = fillColor;
+    beginBatchCommand(CMD_RAMWR);
+    while(c--)
+    {
+        writeBatchData(colorHigh, colorLow);
+    }
+    endBatchCommand();
+}
+ 
+void LCD_ST7735::fillRect(int x1, int y1, int x2, int y2, uint16_t borderColor, uint16_t fillColor)
+{
+    if (x1 > x2) swap(x1, x2);
+    if (y1 > y2) swap(y1, y2);
+    
+    drawRect(x1, y1, x2, y2, borderColor);
+    ++x1; ++y1; --x2; --y2;
+    if (x2 >= x1 && y2 >= y1)
+    {           
+        int c = ((x2 + 1 - x1) * (y2 + 1 - y1)) << 1;
+            
+        clipRect(x1, y1, x2, y2);        
+        uint8_t colorHigh = fillColor >> 8;
+        uint8_t colorLow = fillColor;
+        beginBatchCommand(CMD_RAMWR);
+        while(c--)
+        {
+            writeBatchData(colorHigh, colorLow);
+        }
+        endBatchCommand();
+    }
+}
+ 
+void LCD_ST7735::fillCircle(int x, int y, int r, uint16_t borderColor, uint16_t fillColor)
+{
+    int ix = r;
+    int iy = 0;
+    int err = 1 - r;
+    
+    while(ix >= iy)
+    {
+        setPixel(x - ix, y + iy, borderColor);
+        setPixel(x + ix, y + iy, borderColor);        
+        drawHorizLine(x - ix + 1, y + iy, x + ix - 1, fillColor);
+        
+        setPixel(x - iy, y + ix, borderColor);
+        setPixel(x + iy, y + ix, borderColor);                
+        drawHorizLine(x - iy + 1, y + ix, x + iy - 1, fillColor);
+                
+        setPixel(x - ix, y - iy, borderColor);
+        setPixel(x + ix, y - iy, borderColor);
+        drawHorizLine(x - ix + 1, y - iy, x + ix - 1, fillColor);
+        
+        setPixel(x - iy, y - ix, borderColor);        
+        setPixel(x + iy, y - ix, borderColor);
+        drawHorizLine(x - iy + 1, y - ix, x + iy - 1, fillColor);
+        iy++;
+        if (err < 0)
+        {
+            err += 2 * iy + 1;
+        }
+        else
+        {
+            ix--;
+            err += 2 * (iy - ix + 1);
+        }
+    }
+}
+ 
+void LCD_ST7735::fillEllipse(int x, int y, int rx, int ry, uint16_t borderColor, uint16_t fillColor)
+{
+    int a2 = rx * rx;
+    int b2 = ry * ry;
+    int fa2 = 4 * a2;
+    int fb2 = 4 * b2;
+    
+    int ix, iy, sigma;    
+    for (ix = 0, iy = ry, sigma = 2 * b2 + a2 * (1 - 2 * ry); b2 * ix <= a2 * iy; ix++)
+    {
+        setPixel(x + ix, y + iy, borderColor);
+        setPixel(x - ix, y + iy, borderColor);
+        drawHorizLine(x - ix + 1, y + iy, x + ix - 1, fillColor);
+        
+        setPixel(x + ix, y - iy, borderColor);
+        setPixel(x - ix, y - iy, borderColor);
+        drawHorizLine(x - ix + 1, y - iy, x + ix - 1, fillColor);
+        
+        if (sigma >= 0)
+        {
+            sigma+= fa2 * (1 - iy);
+            iy--;
+        }
+        sigma += b2 * ((4 * ix) + 6);
+    }
+    
+    for (ix = rx, iy = 0, sigma = 2 * a2 + b2 * (1 - 2 * rx); a2 * iy <= b2 * ix; iy++)
+    {
+        setPixel(x + ix, y + iy, borderColor);
+        setPixel(x - ix, y + iy, borderColor);
+        drawHorizLine(x - ix + 1, y + iy, x + ix - 1, fillColor);
+        
+        setPixel(x + ix, y - iy, borderColor);
+        setPixel(x - ix, y - iy, borderColor);
+        drawHorizLine(x - ix + 1, y - iy, x + ix - 1, fillColor);
+        if (sigma >= 0)
+        {
+            sigma+= fb2 * (1 - ix);
+            ix--;
+        }
+        sigma += a2 * ((4 * iy) + 6);
+    }
+}
+ 
+void LCD_ST7735::drawBitmap(int x, int y, const uint16_t *pbmp)
+{
+    int w = *pbmp++;
+    int h = *pbmp++;
+    
+    clip(x, y, w, h);
+    int c = w * h;
+    beginBatchCommand(CMD_RAMWR);
+    while(c--)
+    {
+        writeBatchData(*pbmp++);
+    }
+    endBatchCommand();
+}
+ 
+void LCD_ST7735::drawBitmap(int x, int y, const uint16_t *pbmp, int srcX, int srcY, int srcWidth, int srcHeight)
+{
+    int w = *pbmp++;
+    int h = *pbmp++;
+    
+    clip(x, y, srcWidth, srcHeight);
+    beginBatchCommand(CMD_RAMWR);    
+    const uint16_t *p = pbmp + srcX + (srcY * w);
+    for(int iy = 0; iy < srcHeight; ++iy)
+    {
+        for(int ix = 0; ix < srcWidth; ++ix)
+        {
+            writeBatchData(*(p + ix));
+        }
+        p += w;
+    } 
+    endBatchCommand();
+}
+ 
+void LCD_ST7735::setForegroundColor(uint16_t color)
+{
+    _foregroundColorHigh = color >> 8;
+    _foregroundColorLow = color;
+}
+ 
+void LCD_ST7735::setBackgroundColor(uint16_t color)
+{
+    _backgroundColorHigh = color >> 8;
+    _backgroundColorLow = color;
+}
+        
+void LCD_ST7735::drawString(const uint8_t *pFont, int x, int y, const char *pString)
+{
+    uint8_t w = *pFont;
+    uint8_t h = *(pFont + 1);
+    uint8_t offset = *(pFont + 2);
+    uint8_t leftPad = *(pFont + 3);
+    uint8_t rightPad = *(pFont + 4);
+    uint8_t topPad = *(pFont + 5);
+    uint8_t bottomPad = *(pFont + 6);
+    
+    if (y + topPad + h + bottomPad < 0) return;
+    if (y >= _height) return;
+    if (x + leftPad + w + rightPad < 0) return;    
+    
+    char *p = (char*)pString;
+    while(*p != 0)
+    {        
+        if (x >= _width) return;
+        drawChar(pFont, x, y, *p++, w, h, offset, leftPad, rightPad, topPad, bottomPad);
+        x += (w + leftPad + rightPad);
+    }
+}
+ 
+void LCD_ST7735::measureString(const uint8_t *pFont, const char *pString, uint8_t &width, uint8_t &height)
+{
+    uint8_t w = *pFont;
+    uint8_t h = *(pFont + 1);
+    uint8_t leftPad = *(pFont + 3);
+    uint8_t rightPad = *(pFont + 4);
+    uint8_t topPad = *(pFont + 5);
+    uint8_t bottomPad = *(pFont + 6);
+    
+    width = (w + leftPad + rightPad) * strlen(pString);
+    height = (h + topPad + bottomPad);
+}
+ 
+void LCD_ST7735::selectDevice()
+{
+    _spi.prepareFastSPI();
+}
+ 
+void LCD_ST7735::drawVertLine(int x1, int y1, int y2, uint16_t color)
+{
+    clipRect(x1, y1, x1, y2);
+    beginBatchCommand(CMD_RAMWR);
+    int c = (y2 - y1) << 1;
+    uint8_t colorHigh = color >> 8;
+    uint8_t colorLow = color;
+    for (int i = 0; i < c; ++i)
+    {
+        writeBatchData(colorHigh, colorLow);        
+    }
+    endBatchCommand();
+}
+ 
+void LCD_ST7735::drawHorizLine(int x1, int y1, int x2, uint16_t color)
+{
+    clipRect(x1, y1, x2, y1);
+    beginBatchCommand(CMD_RAMWR);
+    int c = (x2 - x1) << 1;
+    uint8_t colorHigh = color >> 8;
+    uint8_t colorLow = color;
+    for (int i = 0; i < c; ++i)
+    {
+        writeBatchData(colorHigh, colorLow);
+    }
+    endBatchCommand();
+}
+ 
+void LCD_ST7735::drawChar(const uint8_t *pFont, int x, int y, char c, uint8_t w, uint8_t h, uint8_t offset, uint8_t leftPad, uint8_t rightPad, uint8_t topPad, uint8_t bottomPad)
+{
+    const uint8_t *pChar = (pFont + 7) + ((c - offset) * h);
+    
+    clip(x, y, w + leftPad + rightPad, h + topPad + bottomPad);
+    
+    beginBatchCommand(CMD_RAMWR);
+    
+    // Render top spacing
+    for (int r = 0; r < topPad; ++r)
+    {
+        for (int c = 0; c < w + leftPad + rightPad; ++c)
+        {
+            writeBatchData(_backgroundColorHigh);
+            writeBatchData(_backgroundColorLow);
+        }
+    }
+    
+    // Render character
+    for(int r = 0; r < h; ++r)
+    {
+        uint8_t b = pChar[r];
+        
+        // Render left spacing
+        for (int c = 0; c < leftPad; ++c)
+        {
+            writeBatchData(_backgroundColorHigh);
+            writeBatchData(_backgroundColorLow);
+        }        
+        for(int c = 0; c < w; ++c)
+        {
+            if (b & 0x80)
+            {
+                writeBatchData(_foregroundColorHigh);
+                writeBatchData(_foregroundColorLow);
+            }
+            else
+            {
+                writeBatchData(_backgroundColorHigh);
+                writeBatchData(_backgroundColorLow);
+            }
+                
+            b <<= 1;
+        }
+        
+        for (int c = 0; c < rightPad; ++c)
+        {
+            writeBatchData(_backgroundColorHigh);
+            writeBatchData(_backgroundColorLow);
+        }        
+    }
+    
+    // Render bottom spacing
+    for (int r = 0; r < bottomPad; ++r)
+    {
+        for (int c = 0; c < w + leftPad + rightPad; ++c)
+        {
+            writeBatchData(_backgroundColorHigh);
+            writeBatchData(_backgroundColorLow);
+        }
+    }
+    endBatchCommand();
+}
+ 
+void LCD_ST7735::initDisplay()
+{
+    selectDevice();
+    reset();
+    
+    writeCommand(CMD_SLPOUT);
+    
+    write(CMD_FRMCTR1, (uint8_t[]){0x01, 0x2c, 0x2d}, 3);
+    write(CMD_FRMCTR2, (uint8_t[]){0x01, 0x2c, 0x2d}, 3);
+    write(CMD_FRMCTR3, (uint8_t[]){0x01, 0x2c, 0x2d, 0x01, 0x2c, 0x2d}, 6);
+    
+    write(CMD_INVCTR, (uint8_t[]){0x07}, 1);
+    
+    write(CMD_PWCTR1, (uint8_t[]){0xa2, 0x02, 0x84}, 3);
+    write(CMD_PWCTR2, (uint8_t[]){0xc5}, 1);
+    write(CMD_PWCTR3, (uint8_t[]){0x0a, 0x00}, 2);
+    write(CMD_PWCTR4, (uint8_t[]){0x8a, 0x2a}, 2);
+    write(CMD_PWCTR5, (uint8_t[]){0x8a, 0xee}, 2);
+    
+    write(CMD_VMCTR1, (uint8_t[]){0x0e}, 1);
+    
+    write(CMD_MADCTL, (uint8_t[]){0xc0 | _colorFilter}, 1);
+    
+    // Gama sequence
+    write(CMD_GAMCTRP1, (uint8_t[])
+        {
+            0x0f, 0x1a,
+            0x0f, 0x18,
+            0x2f, 0x28,
+            0x20, 0x22,
+            0x1f, 0x1b,
+            0x23, 0x37,
+            0x00, 0x07,
+            0x02, 0x10
+        }, 16);
+        
+    write(CMD_GAMCTRN1, (uint8_t[])
+        {
+            0x0f, 0x1b,
+            0x0f, 0x17,
+            0x33, 0x2c,
+            0x29, 0x2e,
+            0x30, 0x30,
+            0x39, 0x3f,
+            0x00, 0x07,
+            0x03, 0x10
+        }, 16);
+        
+    write(CMD_CASET, (uint8_t[]){0x00, 0x00, 0x00, 0x7f}, 4);
+    write(CMD_RASET, (uint8_t[]){0x00, 0x00, 0x00, 0x9f}, 4);
+    
+    write(CMD_EXTCTRL, (uint8_t[]){0x01}, 1);            
+    
+    // Disable RAM power save
+    write(0xf6, (uint8_t[]){0x00}, 1);                    
+    
+    // 65k color mode
+    write(CMD_COLMOD, (uint8_t[]){0x05}, 1);            
+    
+    // Enable display
+    writeCommand(CMD_DISPON);            
+    
+    setBacklight(true);
+}
+ 
+void LCD_ST7735::reset()
+{
+    _reset = 0;
+    wait_us(100);
+    _reset = 1;
+    wait_us(100);
+}
+ 
+void LCD_ST7735::clip(int x, int y, int w, int h)
+{
+    clipRect(x, y, (x + w) - 1, (y + h) - 1);
+}
+ 
+void LCD_ST7735::clipRect(int x1, int y1, int x2, int y2)
+{
+    uint8_t x1l = (uint8_t)x1;
+    uint8_t x1h = (uint8_t)(x1 >> 8);
+    uint8_t x2l = (uint8_t)x2;
+    uint8_t x2h = (uint8_t)(x2 >> 8);
+    write(CMD_CASET, (uint8_t[]){x1h, x1l, x2h, x2l}, 4);    
+    
+    uint8_t y1l = (uint8_t)y1;
+    uint8_t y1h = (uint8_t)(y1 >> 8);
+    uint8_t y2l = (uint8_t)y2;
+    uint8_t y2h = (uint8_t)(y2 >> 8);
+    write(CMD_RASET, (uint8_t[]){y1h, y1l, y2h, y2l}, 4);    
+}
+        
+void LCD_ST7735::writeCommand(uint8_t cmd)
+{
+    _cs = 0;
+    _ds = 0;    
+    _spi.fastWrite(cmd);
+    _spi.waitWhileBusy();
+    _spi.clearRx();
+    _cs = 1;
+}
+ 
+void LCD_ST7735::write(uint8_t cmd, uint8_t data[], int dataLen)
+{
+    _cs = 0;
+    _ds = 0;    
+    _spi.fastWrite(cmd);
+    _spi.waitWhileBusy();
+    if (data != NULL & dataLen > 0)
+    {
+        _ds = 1;        
+        for(int i = 0; i < dataLen; ++i)
+        {            
+            _spi.fastWrite(data[i]); 
+        }        
+        _spi.waitWhileBusy();
+        _ds = 0; 
+    }    
+    _spi.clearRx();
+    _cs = 1;
+}
+ 
+void LCD_ST7735::write(uint8_t cmd, uint16_t data)
+{
+    _cs = 0; 
+    _ds = 0;    
+    _spi.fastWrite(cmd);       
+    _spi.waitWhileBusy();
+    _ds = 1;            
+    _spi.fastWrite(data >> 8);
+    _spi.fastWrite(data);
+    _spi.waitWhileBusy();
+    _spi.clearRx();
+    _ds = 0;     
+    _cs = 1;
+}
+ 
+void LCD_ST7735::beginBatchCommand(uint8_t cmd)
+{
+    _cs = 0;
+    _ds = 0;        
+    _spi.fastWrite(cmd);   
+    _spi.waitWhileBusy();
+    _ds = 1;
+}
+ 
+void LCD_ST7735::writeBatchData(uint8_t data)
+{
+    _spi.fastWrite(data);
+}
+ 
+void LCD_ST7735::writeBatchData(uint8_t dataHigh, uint8_t dataLow)
+{
+    _spi.fastWrite(dataHigh);
+    _spi.fastWrite(dataLow);
+}
+ 
+ 
+void LCD_ST7735::writeBatchData(uint16_t data)
+{
+    _spi.fastWrite(data >> 8);
+    _spi.fastWrite(data); 
+}
+ 
+void LCD_ST7735::endBatchCommand()
+{
+    _spi.waitWhileBusy();
+    _spi.clearRx();
+    _ds = 0; 
+    _cs = 1; 
+}
diff -r 000000000000 -r c79e1f29f029 Display/LCD_ST7735.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Display/LCD_ST7735.h	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,339 @@
+///////////////////////////////////////////////////////////////////////////////
+// LCD_ST7735 - Driver for ST7735 LCD display controller
+// Author: Chris Taylor (taylorza)
+#include "mbed.h"
+#include "BurstSPI.h"
+
+#ifndef __LCD_ST7735__
+#define __LCD_ST7735__
+
+#define LCD_WIDTH        160
+#define LCD_HEIGHT       128
+
+/** LCD_ST7735 is a simple driver for the ST7735 LCD controller. It provides basic drawing primitives sa well as text and font capabilities.
+ * The driver is currently hardcoded to support 65K colors using a 565 RGB pixel format.
+*/
+class LCD_ST7735
+{   
+    public:
+        /** Orientation of the display */
+        enum Orientation 
+        {
+            /** No rotation of the display image*/
+            Rotate0, 
+            /** Rotate the display image 90 degrees */
+            Rotate90, 
+            /** Rotate the display image 180 degrees */
+            Rotate180, 
+            /** Rotate the display image 270 degrees */
+            Rotate270
+        };
+        
+        /** Type of color filter of the panel */
+        enum PanelColorFilter
+        {
+            /** RGB color filter panel */
+            RGB = 0,
+            
+            /** BGR color filter panel */
+            BGR = 8,
+        };
+        
+    public:
+        /**Creates an instance of the LCD_ST7735 driver
+         * @param backlightPin pin used to control the backlight
+         * @param resetPin pin used to reset the display controller
+         * @param dsPin pin used to put the display controller into data mode
+         * @param mosiPin SPI channel MOSI pin
+         * @param misoPin SPI channel MISO pin
+         * @param clkPin SPI channel clock pin
+         * @param csPin SPI chip select pin 
+        */
+        LCD_ST7735(
+            PinName backlightPin,
+            PinName resetPin,
+            PinName dsPin,
+            PinName mosiPin,
+            PinName misoPin,
+            PinName clkPin,
+            PinName csPin,
+            PanelColorFilter colorFilter = BGR
+            );
+            
+        /** Set the orientation of the display
+         * @param orientation Orientation of the display.
+         * @param flip Flips the display direction
+         */
+        void setOrientation(Orientation orientation, bool flip);
+        
+        /** Get the width of the display given the current orientation */
+        int getWidth();
+        
+        /** Get the height of the display given the current orientation */
+        int getHeight();
+    
+        /** Control the display's backlight 
+         * @param state true to turn the backlight on, false to turn it off   
+        */
+        void setBacklight(bool state);
+        
+        /** Clear the screen 
+         * @param color The color used to clear the screen. Defaults to black if not passed.
+        */
+        void clearScreen(uint16_t color = 0x0000);
+        
+        /**  Set a pixel on the display to the specified color 
+         * @param x The X coordinate of the pixel (0..127)   
+         * @param y The Y coordinate of the pixel (0..159)   
+         * @param color Color to set the pixel to.
+        */
+        void setPixel(int x, int y, uint16_t color);
+        
+        /** Draw a line on the display
+         * @param x1 The X coordinate of the starting point on the line
+         * @param y1 The Y coordinate of the starting point on the line
+         * @param x2 The X coordinate of the end point on the line
+         * @param y2 The Y coordinate of the end point on the line
+         * @param color The color used to draw the pixel
+        */
+        void drawLine(int x1, int y1, int x2, int y2, uint16_t color);
+        
+        /** Draw a rectangle on the display 
+         * @param x1 The X coordinate of the upper left corner
+         * @param y1 The Y coordinate of the upper left corner
+         * @param x2 The X coordinate of the lower right corner
+         * @param y2 The Y coordinate of the lower right corner
+         * @param color The color used to draw the rectangle
+        */
+        void drawRect(int x1, int y1, int x2, int y2, uint16_t color);
+        
+        /** Draw a circle on the display
+         * @param x The X coordinate of the center of the circle
+         * @param y The Y coordinate of the center of the circle
+         * @param r The radius of the circle
+         * @param color The color used to draw the circle
+        */
+        void drawCircle(int x, int y, int r, uint16_t color);
+        
+        /** Draw an ellipse on the display
+         * @param x The X coordinate of the center of the ellipse
+         * @param y The Y coordinate of the center of the ellipse
+         * @param rx The X radius of the ellipse
+         * @param ry The X radius of the ellipse
+         * @param color The color used to draw the ellipse
+        */
+        void drawEllipse(int x, int y, int rx, int ry, uint16_t color);
+        
+        /** Draw a filled rectangle on the display 
+         * @param x1 The X coordinate of the upper left corner
+         * @param y1 The Y coordinate of the upper left corner
+         * @param x2 The X coordinate of the lower right corner
+         * @param y2 The Y coordinate of the lower right corner
+         * @param fillColor The color used to fill the rectangle
+        */
+        void fillRect(int x1, int y1, int x2, int y2, uint16_t fillColor);
+        
+        /** Draw a filled rectangle on the display 
+         * @param x1 The X coordinate of the upper left corner
+         * @param y1 The Y coordinate of the upper left corner
+         * @param x2 The X coordinate of the lower right corner
+         * @param y2 The Y coordinate of the lower right corner
+         * @param borderColor The color used to draw the rectangle frame
+         * @param fillColor The color used to fill the rectangle
+        */
+        void fillRect(int x1, int y1, int x2, int y2, uint16_t borderColor, uint16_t fillColor);
+        
+        /** Draw a filled circle on the display
+         * @param x The X coordinate of the center of the circle
+         * @param y The Y coordinate of the center of the circle
+         * @param borderColor The color used to draw the circumference of the circle
+         * @param fillColor The color used to fill the circle
+        */
+        void fillCircle(int x, int y, int r, uint16_t borderColor, uint16_t fillColor);
+        
+        /** Draw a filled ellipse on the display
+         * @param x The X coordinate of the center of the ellipse
+         * @param y The Y coordinate of the center of the ellipse
+         * @param rx The X radius of the ellipse
+         * @param ry The X radius of the ellipse
+         * @param borderColor The color used to draw the circumference of the circle
+         * @param fillColor The color used to fill the circle
+        */
+        void fillEllipse(int x, int y, int rx, int ry, uint16_t borderColor, uint16_t fillColor);
+        
+        /** Draw a bitmap on the screen 
+         * @param x The X coordinate location to draw the bitmap.
+         * @param y The Y coordinate location to draw the bitmap.
+         * @param pbmp Pointer to the bitmap.
+         * @note The bitmap is an single dimensional uint8_t (unsigned short) array. 
+         * The first to elements of the array indicate the width and height of the bitmap repectively.
+         * The rest of the entries int the array make up the pixel data for the array.
+        */
+        void drawBitmap(int x, int y, const uint16_t *pbmp);
+        
+        /** Extracts a portion of a bitmap and draws it on the screen 
+         * @param x The X coordinate location to draw the bitmap.
+         * @param y The Y coordinate location to draw the bitmap.
+         * @param pbmp Pointer to the bitmap.
+         * @param srcX X offset into the source bitmap of the portion to extract
+         * @param srcY Y offset into the source bitmap of the portion to extract
+         * @param srcWidth Width of the bitmap portion to draw
+         * @param srcHeight Height of the bitmap portion to draw
+         * @note The bitmap is an single dimensional uint8_t (unsigned short) array. 
+         * The first to elements of the array indicate the width and height of the bitmap repectively.
+         * The rest of the entries int the array make up the pixel data for the array.
+        */
+        void drawBitmap(int x, int y, const uint16_t *pbmp, int srcX, int srcY, int srcWidth, int srcHeight);
+        
+        /** Set the foreground color used to render text
+         * @param color Color used when drawing text to the display
+         * @note The color can be changed multiple times to render text in various colors on the display
+        */
+        void setForegroundColor(uint16_t color);
+        
+        /** Set the background color used to render text
+         * @param color Color used when drawing background portions of the text
+         * @note The color can be changed multiple times to render text with various background colors on the display
+        */
+        void setBackgroundColor(uint16_t color);        
+        
+        /** Draw a string to the screen using the currently active foreground and background colors
+         * @param pFont Pointer to the font used to render the string to the display
+         * @param x The X coordinate location to draw the string.
+         * @param y The Y coordinate location to draw the string.
+         * @param pString ASCIIZ string to draw to the display.         
+        */
+        void drawString(const uint8_t *pFont, int x, int y, const char *pString);
+        
+        /** Measure the width and height of the string when rendered with the specified font
+         * @param pFont Pointer to the font used to measure the string         
+         * @param pString ASCIIZ string to measure.
+         * @param width Reference to the variable that will contain the width
+         * @param height Reference to the variable that will contain the height         
+        */
+        void measureString(const uint8_t *pFont, const char *pString, uint8_t &width, uint8_t &height);
+        
+        /** Select the device on the SPI bus.
+        selectDevice needs to be called before accessing the screen if there are multiple devices on the SPI bus.
+        */
+        void selectDevice();   
+        
+    protected:
+        void writeCommand(uint8_t cmd);
+        void write(uint8_t cmd, uint8_t data[], int dataLen);
+        void write(uint8_t cmd, uint16_t data);        
+        
+        void beginBatchCommand(uint8_t cmd);
+        void writeBatchData(uint8_t data);
+        void writeBatchData(uint8_t dataHigh, uint8_t dataLow);
+        void writeBatchData(uint16_t data);
+        void endBatchCommand();
+        
+        void clip(int x, int y, int w, int h);
+        void clipRect(int x1, int y1, int x2, int y2);
+        
+    private:
+        void drawVertLine(int x1, int y1, int y2, uint16_t color);
+        void drawHorizLine(int x1, int y1, int x2, uint16_t color);
+        void drawChar(const uint8_t *pFont, int x, int y, char c, uint8_t w, uint8_t h, uint8_t offset, uint8_t leftPad, uint8_t rightPad, uint8_t topPad, uint8_t bottomPad);
+        
+    private:
+        void swap(int &a, int &b);
+        
+    private:
+        void initDisplay();
+        void reset();        
+        
+    private:
+        int         _width;
+        int         _height;
+        Orientation _orientation;
+        PanelColorFilter _colorFilter;
+        bool        _flip; 
+        uint8_t    _foregroundColorHigh;
+        uint8_t    _foregroundColorLow;
+        uint8_t    _backgroundColorHigh;
+        uint8_t    _backgroundColorLow;
+        
+    private:
+        class LCDSPI : public SPI
+        {
+            public:
+                LCDSPI(PinName mosi, PinName miso, PinName sclk) :
+                    SPI(mosi, miso, sclk)
+                {
+                }
+                
+                void prepareFastSPI()
+                {
+                    #ifdef TARGET_LPC11U24
+                    aquire();
+                    #endif
+                }
+                
+                void waitWhileBusy()
+                {
+                    #ifdef TARGET_LPC11U24
+                    while (((_spi.spi->SR) & 0x10) != 0);
+                    #endif
+                }
+                
+                void fastWrite(uint8_t data)
+                {       
+                    #ifdef TARGET_LPC11U24
+                        while (((_spi.spi->SR) & 0x01) == 0);
+                        //while(((_spi.spi->SR) & 0x02) == 0);
+                        _spi.spi->DR = data;
+                    #else
+                        SPI::write(data);
+                    #endif 
+                }       
+                
+                void clearRx()
+                { 
+                    #ifdef TARGET_LPC11U24
+                        while (((_spi.spi->SR) & 0x14) != 0)
+                        {
+                            while (((_spi.spi->SR) & 0x04) == 0);
+                            int data = _spi.spi->DR;
+                        }                                         
+                    #endif  
+                }            
+        };
+        
+    private:                
+        DigitalOut  _backlight;
+        DigitalOut  _reset;
+        DigitalOut  _ds;
+        DigitalOut  _cs;
+        LCDSPI      _spi;
+        
+    protected:
+        static const uint8_t CMD_SLPOUT     = 0x11;
+        static const uint8_t CMD_DISPON     = 0x29;
+        static const uint8_t CMD_CASET      = 0x2a;
+        static const uint8_t CMD_RASET      = 0x2b;
+        static const uint8_t CMD_RAMWR      = 0x2c;
+        
+        static const uint8_t CMD_MADCTL     = 0x36;
+        static const uint8_t CMD_COLMOD     = 0x3a;
+        
+        static const uint8_t CMD_FRMCTR1    = 0xb1;
+        static const uint8_t CMD_FRMCTR2    = 0xb2;
+        static const uint8_t CMD_FRMCTR3    = 0xb3;
+        static const uint8_t CMD_INVCTR     = 0xb4;
+        
+        static const uint8_t CMD_PWCTR1     = 0xc0;
+        static const uint8_t CMD_PWCTR2     = 0xc1;
+        static const uint8_t CMD_PWCTR3     = 0xc2;
+        static const uint8_t CMD_PWCTR4     = 0xc3;
+        static const uint8_t CMD_PWCTR5     = 0xc4;
+        static const uint8_t CMD_VMCTR1     = 0xc5;
+        
+        static const uint8_t CMD_GAMCTRP1   = 0xe0;
+        static const uint8_t CMD_GAMCTRN1   = 0xe1;
+        
+        static const uint8_t CMD_EXTCTRL    = 0xf0;                
+};
+ 
+#endif // __LCD_ST7735__
diff -r 000000000000 -r c79e1f29f029 Display/colors.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Display/colors.h	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,16 @@
+#ifndef __COLORS_H__
+#define __COLORS_H__
+
+// Colors
+//#define RGB2SHORT(r, g, b) ((((uint8_t)r & 0xF8) << 8) | (((uint8_t)g & 0xFC) << 3) | ((uint8_t)b >> 3))
+#define RGB2SHORT(r, g, b) (uint16_t)( ((g & 0x1C) << 13) | ((b & 0xF8) << 5) | (r & 0xF8) | (g >> 5))
+#define     BLUE    RGB2SHORT(0, 0, 255)
+#define     GREEN   RGB2SHORT(0, 255, 0)
+#define     RED     RGB2SHORT(255, 0, 0)
+#define     WHITE   RGB2SHORT(255, 255, 255)
+#define     BLACK   RGB2SHORT(0, 0, 0)
+#define     MAGENTA RGB2SHORT(255, 0, 255)      
+#define     CYAN    RGB2SHORT(0, 255, 255)
+#define     YELLOW  RGB2SHORT(255, 255, 0)
+
+#endif // __COLORS_H__
diff -r 000000000000 -r c79e1f29f029 Display/display.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Display/display.cpp	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,723 @@
+#include <stdarg.h>     // va_list
+#include "display.h"
+#include "font8x8.h"    // default 8x8 bitmap font
+#include "colors.h"     // predefined colors
+
+#define COLOR(fore, back) ((fore << 4) | (back & 0x0F))
+
+display::display() : LCD_ST7735(P0_19, P0_20, P0_7, P0_21, P0_22, P1_15, P0_2, LCD_ST7735::RGB)
+{
+    // Fill out the default color palette - use the MSX/Coleco default 16 color palette
+    // Found them here:  http://theadamresource.com/articles/misc/wk970202.html
+    memset(m_color_pal, 0, COLOR_PAL_LEN * sizeof(uint16_t));
+    /*
+    m_color_pal[0] =    RGB2SHORT(0,    0,      0);         // BLACK - Transparent (support in display code)
+    m_color_pal[1] =    RGB2SHORT(0,    0,      0);         // BLACK - Opaque
+    m_color_pal[2] =    RGB2SHORT(71,   183,    59);        // Medium Green
+    m_color_pal[3] =    RGB2SHORT(124,  207,    111);       // Light Green
+    m_color_pal[4] =    RGB2SHORT(93,   18,     255);       // Dark Blue
+    m_color_pal[5] =    RGB2SHORT(128,  114,    255);       // Light Blue
+    m_color_pal[6] =    RGB2SHORT(182,  91,     71);        // Dark Red (maybe brown)
+    m_color_pal[7] =    RGB2SHORT(93,   200,    237);       // Cyan
+    m_color_pal[8] =    RGB2SHORT(215,  107,    72);        // Medium Red
+    m_color_pal[9] =    RGB2SHORT(251,  143,    108);       // Light Red
+    m_color_pal[10] =   RGB2SHORT(195,  205,    65);        // Dark Yellow
+    m_color_pal[11] =   RGB2SHORT(211,  218,    118);       // Light Yellow
+    m_color_pal[12] =   RGB2SHORT(62,   159,    47);        // Dark Green
+    m_color_pal[13] =   RGB2SHORT(182,  100,    199);       // Magenta
+    m_color_pal[14] =   RGB2SHORT(204,  204,    204);       // Grey
+    m_color_pal[15] =   RGB2SHORT(255,  255,    255);       // White
+    */
+    /*
+    m_color_pal[0] =    RGB2SHORT(0,    0,      0);         // BLACK - Transparent (support in display code)
+    m_color_pal[1] =    RGB2SHORT(0,    0,      0);         // BLACK - Opaque
+    m_color_pal[2] =    RGB2SHORT(32,   192,    32);        // Medium Green
+    m_color_pal[3] =    RGB2SHORT(96,   224,    96);        // Light Green
+    m_color_pal[4] =    RGB2SHORT(32,   32,     224);       // Dark Blue
+    m_color_pal[5] =    RGB2SHORT(64,   96,     224);       // Light Blue
+    m_color_pal[6] =    RGB2SHORT(160,  32,     32);        // Dark Red (maybe brown)
+    m_color_pal[7] =    RGB2SHORT(64,   192,    224);       // Cyan
+    m_color_pal[8] =    RGB2SHORT(224,  32,     32);        // Medium Red
+    m_color_pal[9] =    RGB2SHORT(224,  96,     96);        // Light Red
+    m_color_pal[10] =   RGB2SHORT(192,  192,    32);        // Dark Yellow
+    m_color_pal[11] =   RGB2SHORT(192,  192,    128);       // Light Yellow
+    m_color_pal[12] =   RGB2SHORT(32,   128,    32);        // Dark Green
+    m_color_pal[13] =   RGB2SHORT(192,  64,     160);       // Magenta
+    m_color_pal[14] =   RGB2SHORT(160,  160,    160);       // Grey
+    m_color_pal[15] =   RGB2SHORT(255,  255,    255);       // White
+    */
+    
+    // Mac OS4.1 16 Color Palette (modified for transparent)
+    // Found here: http://upload.wikimedia.org/wikipedia/commons/5/57/Mac_16colors_palette.png
+    m_color_pal[0] =    RGB2SHORT(255,  255,    255);       // White
+    m_color_pal[1] =    RGB2SHORT(255,  255,    0);         // Yellow
+    m_color_pal[2] =    RGB2SHORT(255,  102,    0);         // Orange
+    m_color_pal[3] =    RGB2SHORT(255,  0,      0);         // Red
+    m_color_pal[4] =    RGB2SHORT(255,  0,      103);       // Magenta
+    m_color_pal[5] =    RGB2SHORT(51,   0,      153);       // Dark Blue
+    m_color_pal[6] =    RGB2SHORT(0,    0,      204);       // Blue
+    m_color_pal[7] =    RGB2SHORT(0,    153,    255);       // Light Blue
+    m_color_pal[8] =    RGB2SHORT(0,    255,    0);         // Green
+    m_color_pal[9] =    RGB2SHORT(0,    102,    0);         // Dark Green
+    m_color_pal[10] =   RGB2SHORT(102,  51,     0);         // Brown
+    m_color_pal[11] =   RGB2SHORT(153,  102,    51);        // Light Brown
+    m_color_pal[12] =   RGB2SHORT(187,  187,    187);       // Light Grey
+    m_color_pal[13] =   RGB2SHORT(136,  136,    136);       // Grey
+    m_color_pal[14] =   RGB2SHORT(0,    0,      0);       // White
+    m_color_pal[15] =   RGB2SHORT(0,    0,      0);         // Transparent (black)
+    
+    // Allocate our line buffer
+    m_line_buffer = new uint8_t[LINE_BUFFER_LEN];
+    
+    // Set our default colors
+    m_fore_color = PAL_WHITE;
+    m_back_color = PAL_TRANSPARENT;
+    
+    clear();
+    
+    // Initialize our sprite list
+    for (int i = 0; i < MAX_SPRITES; i++)
+        memset(&sprite_list[i], 0, sizeof(SPRITE));
+        
+    // Clear our user character buffer
+    memset(user_char, 0, MAX_USER_CHAR_BUF_LEN);
+}
+
+display::~display()
+{
+}
+
+void display::clear()
+{
+    // Clear our character map buffer
+    memset(m_char_map, 0, CHAR_MAP_LEN);
+    // Clear our color map buffer
+    memset(m_color_map, COLOR(m_fore_color, m_back_color), CHAR_MAP_LEN);
+    
+    // Set the cursor position back to 0
+    m_cursor_x = 0;
+    m_cursor_y = 0;
+}
+
+void display::bounds_check_and_scroll()
+{
+    // Check to see if our Y cursor location is beyond our map height
+    if (m_cursor_y >= CHAR_MAP_HEIGHT)
+    {
+        // Check to see if we are 
+        // Scroll everything up 1 line
+        memcpy(m_char_map, &m_char_map[CHAR_MAP_WIDTH], CHAR_MAP_LAST_LINE);
+        memcpy(m_color_map, &m_color_map[CHAR_MAP_WIDTH], CHAR_MAP_LAST_LINE);
+        // Clear the bottom line
+        memset(&m_char_map[CHAR_MAP_LAST_LINE], 0, CHAR_MAP_WIDTH);
+        memset(&m_color_map[CHAR_MAP_LAST_LINE], COLOR(m_fore_color, m_back_color), CHAR_MAP_WIDTH);
+        // Put the position of the cursor on the last line
+        m_cursor_y = CHAR_MAP_HEIGHT - 1;
+        m_cursor_x = 0;
+    }
+}
+
+void display::crlf()
+{
+    // Advance our cursor to the next line
+    m_cursor_x = 0;
+    m_cursor_y++;
+}
+
+void display::print(char *pString)
+{   
+    // Bounds check the cursor position (and do scrolling if we need to)
+    // before we put any characters in the map
+    bounds_check_and_scroll();
+    
+    // Calculate the current linear cursor position
+    int pos = get_linear_cursor_pos();
+    
+    // Loop through the string and put it into the character map
+    while (*pString)
+    {
+        char character = *pString;
+        
+        /*
+        // Handle a carriage return
+        if (character == 10)
+        {
+            m_cursor_x = 0;
+            pos = get_linear_cursor_pos();
+        }
+        else
+        // Handle a line feed
+        if (character == 13)
+        {
+            m_cursor_y++;
+            bounds_check_and_scroll();
+            pos = get_linear_cursor_pos();
+        }
+        else
+        */
+        {
+            if ((character < 32) || (character > 126))
+            {
+                // Some other special character
+                character = 95; // substitue a solid block if there is a special character
+            }
+            else
+            {
+                // Just subtract out the special character offset
+                character -= 32;
+            }
+            
+            // Place the character into the map
+            m_char_map[pos] = character;
+            // Copy the forecolor into the map
+            m_color_map[pos] = COLOR(m_fore_color, m_back_color); 
+            // Next linear position
+            pos++;
+            // Advance the cursor position
+            m_cursor_x++;
+            if (m_cursor_x >= CHAR_MAP_WIDTH)
+            {
+                if (m_word_wrap)
+                {
+                    // Next line
+                    crlf();
+                    pos = get_linear_cursor_pos();
+                }
+                else
+                {
+                    // Stop putting the characters in the map
+                    // we have hit the end of the line
+                    break;
+                }
+                    
+            }
+        }
+        // Next character
+        pString++;
+    }
+}
+
+void display::print(int iNumber)
+{
+    char sTemp[CHAR_MAP_WIDTH];
+    snprintf(sTemp, CHAR_MAP_WIDTH, "%d", iNumber);
+    print(sTemp);
+}
+
+void display::print(float fNumber)
+{
+    char sTemp[CHAR_MAP_WIDTH];
+    snprintf(sTemp, CHAR_MAP_WIDTH, "%0.2f", fNumber);
+    print(sTemp);
+}
+
+void display::print(const char *format, ...)
+{
+    char sTemp[CHAR_MAP_WIDTH];
+    
+    va_list list;
+    va_start(list, format);
+
+    // Print something in the file
+    vsnprintf(sTemp, CHAR_MAP_WIDTH, format, list);
+    
+    print(sTemp);
+}
+
+void display::println(char *pString)
+{
+    print(pString);
+    crlf();
+    
+}
+
+void display::println(int iNumber)
+{
+    print(iNumber);
+    crlf();
+}
+
+void display::println(float fNumber)
+{
+    print(fNumber);
+    crlf();
+}
+
+void display::println(const char *format, ...)
+{
+    char sTemp[CHAR_MAP_WIDTH];
+    
+    va_list list;
+    va_start(list, format);
+
+    // Print something in the file
+    vsnprintf(sTemp, CHAR_MAP_WIDTH, format, list);
+    
+    println(sTemp);
+}
+
+void display::printat(uint8_t x, uint8_t y, char *pString)
+{
+    // Bounds check the coordinates
+    if (x >= CHAR_MAP_WIDTH) return;
+    if (y >= CHAR_MAP_HEIGHT) return;
+    
+    // Get the starting linear position
+    int pos = get_linear_pos(x, y);
+    
+    // Loop through the string and put it into the character map
+    while (*pString)
+    {
+        char character = *pString;
+        
+        // Ignore CR and LF
+        if ((character == 10) || (character == 13))
+        {
+            pString++;
+            continue;
+        }
+        
+        if ((character < 32) || (character > 126))
+        {
+            // Some other special character
+            character = 95; // substitue a solid block if there is a special character
+        }
+        else
+        {
+            // Just subtract out the special character offset
+            character -= 32;
+        }
+        
+        // Place the character into the map
+        m_char_map[pos] = character;
+        // Copy the forecolor into the map
+        m_color_map[pos] = COLOR(m_fore_color, m_back_color);
+        // Next linear position
+        pos++;
+        // Advance the cursor position
+        x++;
+        // Check for out of bounds in which case we just exit
+        if (x >= CHAR_MAP_WIDTH) return;
+        if (pos >= CHAR_MAP_LEN) return;
+        // Next character
+        pString++;
+    }
+}
+
+void display::printat(uint8_t x, uint8_t y, int iNumber)
+{
+    char sTemp[CHAR_MAP_WIDTH];
+    snprintf(sTemp, CHAR_MAP_WIDTH, "%d", iNumber);
+    printat(x, y, sTemp);
+}
+
+void display::printat(uint8_t x, uint8_t y, float fNumber)
+{
+    char sTemp[CHAR_MAP_WIDTH];
+    snprintf(sTemp, CHAR_MAP_WIDTH, "%0.2f", fNumber);
+    printat(x, y, sTemp);
+}
+
+void display::printat(uint8_t x, uint8_t y, const char *format, ...)
+{
+    char sTemp[CHAR_MAP_WIDTH];
+    
+    va_list list;
+    va_start(list, format);
+
+    // Print something in the file
+    vsnprintf(sTemp, CHAR_MAP_WIDTH, format, list);
+    
+    printat(x, y, sTemp);
+}
+
+void display::setcharat(uint8_t x, uint8_t y, uint8_t character, uint8_t fore_color, uint8_t back_color)
+{
+    // Bounds check the coordinates
+    if (x >= CHAR_MAP_WIDTH) return;
+    if (y >= CHAR_MAP_HEIGHT) return;
+    
+    // Get the starting linear position
+    int pos = get_linear_pos(x, y);
+    
+    // Place the character into the map
+    m_char_map[pos] = character;
+    
+    // Check the colors
+    if (fore_color >= 16) fore_color = m_fore_color;
+    if (back_color >= 16) back_color = m_back_color;
+    
+    // Copy the forecolor into the map
+    m_color_map[pos] = COLOR(fore_color, back_color);
+    
+}
+
+void display::blit_line(uint8_t line)
+{
+    if (line >= LCD_HEIGHT) return;
+    
+    // LCD_ST7735
+    clip(0, line, 159, 0);
+    write(0x2C, m_line_buffer, LINE_BUFFER_LEN);
+    
+    // DisplayN18
+    //setClippingArea(0, line, 159, 0);
+    //writeCommand(0x2C);
+    //writeData(m_line_buffer, LINE_BUFFER_LEN);
+}
+
+void display::render()
+{
+    uint16_t *line_buf = (uint16_t *)m_line_buffer;
+    uint8_t *char_buf = font8x8_basic;
+    register uint8_t data = 0;
+    
+    int cindex = 0;
+    int char_line = 0;
+    int line_x = 0;
+    
+    for (int line = 0; line < LCD_HEIGHT; line++)
+    {
+        line_x = 0;
+        cindex = (line >> 3) * CHAR_MAP_WIDTH;
+        for (int map_x = 0; map_x < CHAR_MAP_WIDTH; map_x++)
+        {
+            register uint8_t data_index = m_char_map[cindex];
+            if (data_index < 128)
+                data = char_buf[(data_index << 3) + char_line];
+            else
+                data = user_char[((data_index - 128) << 3) + char_line];
+            register uint16_t fore_color = m_color_pal[m_color_map[cindex] >> 4];
+            register uint16_t back_color = m_color_pal[(m_color_map[cindex] & 0x0F)];
+            line_buf[line_x++] = (data & 0x01) ? fore_color : back_color;
+            line_buf[line_x++] = (data & 0x02) ? fore_color : back_color;
+            line_buf[line_x++] = (data & 0x04) ? fore_color : back_color;
+            line_buf[line_x++] = (data & 0x08) ? fore_color : back_color;
+            line_buf[line_x++] = (data & 0x10) ? fore_color : back_color;
+            line_buf[line_x++] = (data & 0x20) ? fore_color : back_color;
+            line_buf[line_x++] = (data & 0x40) ? fore_color : back_color;
+            line_buf[line_x++] = (data & 0x80) ? fore_color : back_color;
+            // Next character in our map
+            cindex++;
+        }
+        
+        char_line++;
+        if (char_line >= CHAR_HEIGHT) char_line = 0;
+        
+        // Add in the sprites ... they are the TOP layer
+        for (int iSprite = 0; iSprite < MAX_SPRITES; iSprite++)
+        {
+            // Check to see if the sprite is enabled
+            if (!sprite_list[iSprite].enabled) continue;
+            
+            // Check to see if the sprite is within our current line
+            if (line < sprite_list[iSprite].y) continue;
+            if (line >= (sprite_list[iSprite].y + 8)) continue;
+            
+            // Get the row of the sprite we are blitting
+            register uint8_t row = line - sprite_list[iSprite].y;
+            // Get the x position
+            register uint8_t x = sprite_list[iSprite].x;
+            // Get the foreground color
+            register uint16_t fc = m_color_pal[sprite_list[iSprite].fore_color];
+            register uint16_t bc = m_color_pal[sprite_list[iSprite].back_color];
+            // Get the starting index for the sprite into the user character buffer
+            register uint8_t data = user_char[(sprite_list[iSprite].char_index << 3) + row];
+            
+            if (sprite_list[iSprite].back_color != PAL_TRANSPARENT)
+            {
+                line_buf[x] = (data & 0x01) ? fc : bc; x++;
+                line_buf[x] = (data & 0x02) ? fc : bc; x++;
+                line_buf[x] = (data & 0x04) ? fc : bc; x++;
+                line_buf[x] = (data & 0x08) ? fc : bc; x++;
+                line_buf[x] = (data & 0x10) ? fc : bc; x++;
+                line_buf[x] = (data & 0x20) ? fc : bc; x++;
+                line_buf[x] = (data & 0x40) ? fc : bc; x++;
+                line_buf[x] = (data & 0x80) ? fc : bc; x++;
+            }
+            else
+            {
+                if (data & 0x01) line_buf[x] = fc; x++;
+                if (data & 0x02) line_buf[x] = fc; x++;
+                if (data & 0x04) line_buf[x] = fc; x++;
+                if (data & 0x08) line_buf[x] = fc; x++;
+                if (data & 0x10) line_buf[x] = fc; x++;
+                if (data & 0x20) line_buf[x] = fc; x++;
+                if (data & 0x40) line_buf[x] = fc; x++;
+                if (data & 0x80) line_buf[x] = fc; x++;
+            }
+        }
+                
+        // Draw the line
+        blit_line(line);
+    }
+}
+
+void display::AddSprite(int iSpriteNum, int iChar, int x, int y, int fore_color, int back_color, bool midhandle)
+{
+    if (iSpriteNum < 0) return;
+    if (iSpriteNum >= MAX_SPRITES) return;
+    if (iChar >= MAX_USER_CHAR) return;
+    
+    sprite_list[iSpriteNum].char_index = iChar;
+    sprite_list[iSpriteNum].x = x;
+    sprite_list[iSpriteNum].y = y;
+    sprite_list[iSpriteNum].fore_color = fore_color;
+    sprite_list[iSpriteNum].back_color = back_color;
+    sprite_list[iSpriteNum].midhandle = midhandle;
+    
+    // CHeck to see if we treat the X and Y coordinates as the middle of the sprite...
+    if (midhandle)
+    {
+        // Redo the XY coordinates
+        SetSpritePos(iSpriteNum, x, y);
+    }
+    
+    // Set the enabled flag last just in case we get called from an interrupt or we are interrupted
+    sprite_list[iSpriteNum].enabled = true;
+}
+
+void display::EnableSprite(int iSpriteNum, bool bEnable)
+{
+    if (iSpriteNum < 0) return;
+    if (iSpriteNum >= MAX_SPRITES) return;
+    
+    sprite_list[iSpriteNum].enabled = bEnable;
+}
+
+void display::RemoveSprite(int iSpriteNum)
+{
+    EnableSprite(iSpriteNum, false);
+}
+
+void display::SetSpriteChar(int iSpriteNum, int iChar)
+{
+    if (iSpriteNum < 0) return;
+    if (iSpriteNum >= MAX_SPRITES) return;
+    if (iChar >= MAX_USER_CHAR) return;
+    
+    sprite_list[iSpriteNum].char_index = iChar;
+}
+
+void display::SetSpritePos(int iSpriteNum, int x, int y)
+{
+    if (iSpriteNum < 0) return;
+    if (iSpriteNum >= MAX_SPRITES) return;
+    
+    if (sprite_list[iSpriteNum].midhandle)
+    {
+        x -= 4;
+        y -= 4;
+    }
+    
+    sprite_list[iSpriteNum].x = x;
+    sprite_list[iSpriteNum].y = y;
+}
+
+void display::SetSpriteColor(int iSpriteNum, int fore_color, int back_color)
+{
+    if (iSpriteNum < 0) return;
+    if (iSpriteNum >= MAX_SPRITES) return;
+    
+    sprite_list[iSpriteNum].fore_color = fore_color;
+    sprite_list[iSpriteNum].back_color = back_color;
+}
+
+void display::SetMidHandle(int iSpriteNum, bool bEnable)
+{
+    if (iSpriteNum < 0) return;
+    if (iSpriteNum >= MAX_SPRITES) return;
+    
+    sprite_list[iSpriteNum].midhandle = bEnable;
+}
+
+void display::SetCustomChar(int iCharNum, uint8_t *pBuf, int iNum, bool isMSX)
+{
+    if (iCharNum >= MAX_USER_CHAR) return;
+    if ((iNum + iCharNum) > MAX_USER_CHAR) return;
+    
+    for (int i = 0; i < iNum; i++)
+    {
+        if (isMSX)
+            SetCustomChar8x8MSX(iCharNum + i, pBuf);
+        else
+            SetCustomChar8x8Norm(iCharNum + i, pBuf);
+        pBuf += 8;
+    }
+}
+
+void display::SetCustomChar8x8Norm(int iCharNum, uint8_t *pBuf)
+{
+    if (iCharNum >= MAX_USER_CHAR) return;
+    
+    memcpy(&user_char[iCharNum * 8], pBuf, 8);
+}
+
+void display::SetCustomChar8x8MSX(int iCharNum, uint8_t *pBuf)
+{
+    if (iCharNum >= MAX_USER_CHAR) return;
+    
+    // 8x8 MSX tiles have the bit order reversed
+    for (int i = 0; i < 8; i++)
+    {
+        uint8_t temp2 = 0;
+        uint8_t temp1 = pBuf[i];
+        for (int bit = 0; bit < 8; bit++)
+        {
+            temp2 = temp2 << 1;
+            temp2 |= (temp1 & 0x01);
+            temp1 = temp1 >> 1;
+        }
+        user_char[iCharNum * 8 + i] = temp2;
+    }
+}
+
+void display::set_map(uint8_t char_index, uint8_t x, uint8_t y, uint8_t fore_color, uint8_t back_color)
+{
+    if (x >= CHAR_MAP_WIDTH) return;
+    if (y >= CHAR_MAP_HEIGHT) return;
+    
+    int pos = get_linear_pos(x, y);
+    
+    m_char_map[pos] = char_index;
+    m_color_map[pos] = COLOR(fore_color, back_color);
+    
+}
+
+void display::set_map_info(uint16_t tile_info, uint8_t x, uint8_t y)
+{
+    if (x >= CHAR_MAP_WIDTH) return;
+    if (y >= CHAR_MAP_HEIGHT) return;
+    
+    int pos = get_linear_pos(x, y);
+    
+    m_char_map[pos] = (tile_info >> 8);
+    m_color_map[pos] = (tile_info & 0x00FF);
+}
+
+uint8_t display::get_map(uint8_t x, uint8_t y)
+{
+    return (get_map_info(x, y) >> 8);
+}
+
+uint8_t display::get_map_color(uint8_t x, uint8_t y)
+{
+    return (get_map_info(x, y) & 0x00FF);
+}
+
+uint16_t display::get_map_info(uint8_t x, uint8_t y)
+{
+    if (x >= CHAR_MAP_WIDTH) return 0;
+    if (y >= CHAR_MAP_HEIGHT) return 0;
+    
+    int pos = get_linear_pos(x, y);
+    
+    return ((m_char_map[pos] << 8) | m_color_map[pos]);
+}
+
+void display::shift_map(SHIFT_DIRECTION direction, int inc, bool clear_after_shift)
+{
+    switch (direction)
+    {
+    case (eShiftUp):
+        for (int i = 1; i < CHAR_MAP_HEIGHT; i++)
+        {
+            memcpy(&m_char_map[(i - 1) * CHAR_MAP_WIDTH], &m_char_map[i * CHAR_MAP_WIDTH], CHAR_MAP_WIDTH);
+            memcpy(&m_color_map[(i - 1) * CHAR_MAP_WIDTH], &m_color_map[i * CHAR_MAP_WIDTH], CHAR_MAP_WIDTH);
+        }
+        if (clear_after_shift)
+        {
+            // Clear the bottom row
+            memset(&m_char_map[CHAR_MAP_HEIGHT - 1], 0, CHAR_MAP_WIDTH); 
+             memset(&m_color_map[CHAR_MAP_HEIGHT - 1], COLOR(m_fore_color, m_back_color), CHAR_MAP_WIDTH);
+        }
+        break;
+    case (eShiftDown):
+        for (int i = (CHAR_MAP_HEIGHT - 1); i > 0; i--)
+        {
+            memcpy(&m_char_map[i * CHAR_MAP_WIDTH], &m_char_map[(i - 1) * CHAR_MAP_WIDTH], CHAR_MAP_WIDTH);
+            memcpy(&m_color_map[i * CHAR_MAP_WIDTH], &m_color_map[(i - 1) * CHAR_MAP_WIDTH], CHAR_MAP_WIDTH);
+        }
+        if (clear_after_shift)
+        {
+            // Clear the top row
+            memset(&m_char_map[0], 0, CHAR_MAP_WIDTH); 
+            memset(&m_color_map[0], COLOR(m_fore_color, m_back_color), CHAR_MAP_WIDTH);
+        }
+        break;
+    case (eShiftLeft):
+        for (int y = 0; y < CHAR_MAP_HEIGHT; y++)
+        {
+            for (int x = 1; x < CHAR_MAP_WIDTH; x++)
+            {
+                int pos = get_linear_pos(x, y);
+                m_char_map[pos - 1] = m_char_map[pos];
+                m_color_map[pos -1] = m_color_map[pos];
+            }
+        }
+        if (clear_after_shift)
+        {
+            // Clear the right column
+            for (int y = 0; y < CHAR_MAP_HEIGHT; y++)
+            {
+                m_char_map[get_linear_pos((CHAR_MAP_WIDTH - 1), y)] = 0;
+                m_color_map[get_linear_pos((CHAR_MAP_WIDTH - 1), y)] = COLOR(m_fore_color, m_back_color);
+            }
+        }
+        break;
+    case (eShiftRight):
+        for (int y = 0; y < CHAR_MAP_HEIGHT; y++)
+        {
+            for (int x = (CHAR_MAP_WIDTH - 1); x > 0; x--)
+            {
+                int pos = get_linear_pos(x, y);
+                m_char_map[pos] = m_char_map[pos - 1];
+                m_color_map[pos] = m_color_map[pos - 1];
+            }
+        }
+        if (clear_after_shift)
+        {
+            // Clear the left column
+            for (int y = 0; y < CHAR_MAP_HEIGHT; y++)
+            {
+                m_char_map[get_linear_pos(0, y)] = 0;
+                m_color_map[get_linear_pos(0, y)] = COLOR(m_fore_color, m_back_color);
+            }
+        }
+        break;
+    }
+}
+
+bool display::SpriteCollision(int iSpriteNum1, int iSpriteNum2)
+{
+    if (iSpriteNum1 < 0) return false;
+    if (iSpriteNum1 >= MAX_SPRITES) return false;
+    if (iSpriteNum2 < 0) return false;
+    if (iSpriteNum2 >= MAX_SPRITES) return false;
+    
+    SPRITE *pSprite1 = &sprite_list[iSpriteNum1];
+    SPRITE *pSprite2 = &sprite_list[iSpriteNum2];
+    
+    if (!pSprite1->enabled) return false;
+    if (!pSprite2->enabled) return false;
+    
+    // Bounding box collision - might be broken
+    /*
+    int dx = pSprite1->x - pSprite2->x;
+    if (dx < 0) dx *= -1;
+    int dy = pSprite1->y - pSprite2->y;
+    if (dy < 0) dy *= -1;
+
+    return ((dx < 16) && (dy < 16));
+    */
+    
+    // Circle based collision detection
+    int dx = pSprite1->x - pSprite2->x;
+    int dy = pSprite1->y - pSprite2->y;
+    int dist = (dx * dx) + (dy * dy);
+    int r = 3 + 3;  // make the radius 4 - 1
+    return (dist < (r * r));
+    
+    // TODO - perhaps after the circle detection maybe we can do pixel perfect detection...
+    // OR - do detection when we are rendering???
+}
diff -r 000000000000 -r c79e1f29f029 Display/display.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Display/display.h	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,150 @@
+#include <stdio.h>
+#include <string.h>
+//#include "DisplayN18.h"
+#include "LCD_ST7735.h"     // Retro LCD Library by Chris Taylor
+#include "font8x8.h"        // 8x8 Font
+
+#define CHAR_WIDTH      FONT8X8_WIDTH
+#define CHAR_HEIGHT     FONT8X8_HEIGHT
+#define CHAR_MAP_WIDTH  (LCD_WIDTH / CHAR_WIDTH)
+#define CHAR_MAP_HEIGHT (LCD_HEIGHT / CHAR_HEIGHT)
+#define CHAR_MAP_LEN    (CHAR_MAP_WIDTH * CHAR_MAP_HEIGHT)
+#define CHAR_MAP_LAST_LINE (CHAR_MAP_LEN - CHAR_MAP_WIDTH)
+#define COLOR_PAL_LEN   16
+#define LINE_BUFFER_LEN (LCD_WIDTH * sizeof(uint16_t))
+
+enum SHIFT_DIRECTION
+{
+    eShiftUp,
+    eShiftDown,
+    eShiftLeft,
+    eShiftRight,
+};
+
+/*
+#define PAL_TRANSPARENT         0
+#define PAL_BLACK               1
+#define PAL_MEDGREEN            2
+#define PAL_LIGHTGREEN          3
+#define PAL_DARKBLUE            4
+#define PAL_LIGHTBLUE           5
+#define PAL_DARKRED             6
+#define PAL_CYAN                7
+#define PAL_MEDRED              8
+#define PAL_LIGHTRED            9
+#define PAL_DARKYELLOW          10
+#define PAL_LIGHTYELLOW         11
+#define PAL_DARKGREEN           12
+#define PAL_MAGENTA             13
+#define PAL_GREY                14
+#define PAL_WHITE               15
+*/
+
+#define PAL_WHITE               0
+#define PAL_YELLOW              1
+#define PAL_ORANGE              2
+#define PAL_RED                 3
+#define PAL_MAGENTA             4
+#define PAL_DARKBLUE            5
+#define PAL_BLUE                6
+#define PAL_LIGHTBLUE           7
+#define PAL_GREEN               8
+#define PAL_DARKGREEN           9
+#define PAL_BROWN               10
+#define PAL_LIGHTBROWN          11
+#define PAL_LIGHTGREY           12
+#define PAL_GREY                13
+#define PAL_BLACK               14
+#define PAL_TRANSPARENT         15
+#define PAL_DEFAULT             255
+
+struct SPRITE
+{
+    bool enabled;
+    uint8_t char_index;
+    uint8_t x;
+    uint8_t y;
+    uint8_t fore_color;
+    uint8_t back_color;
+    bool midhandle;
+};
+
+#define MAX_SPRITES             64
+#define MAX_USER_CHAR           64
+#define MAX_USER_CHAR_BUF_LEN   (MAX_USER_CHAR * 8)
+
+//class display : public DisplayN18
+class display : public LCD_ST7735
+{
+public:
+
+    display();
+    ~display();
+
+    void render();
+    
+    // Character Map Functions
+    void shift_map(SHIFT_DIRECTION direction, int inc = 1, bool clear_after_shift = false);
+    uint16_t get_map_info(uint8_t x, uint8_t y);
+    uint8_t get_map_color(uint8_t x, uint8_t y);
+    uint8_t get_map(uint8_t x, uint8_t y);
+    void set_map(uint8_t char_index, uint8_t x, uint8_t y, uint8_t fore_color, uint8_t back_color);
+    void set_map_info(uint16_t tile_info, uint8_t x, uint8_t y);
+    void setcharat(uint8_t x, uint8_t y, uint8_t character, uint8_t fore_color = PAL_DEFAULT, uint8_t back_color = PAL_DEFAULT);
+    
+    // Character based printing
+    void clear();
+    void crlf();
+    void setforecolor(uint8_t color) { m_fore_color = color; };
+    void setbackcolor(uint8_t color) { m_back_color = color; };
+    void setwordwrap(bool enable) { m_word_wrap = enable; };
+    
+    void print(char *pString);
+    void print(int iNumber);
+    void print(float fNumber);
+    void print(const char *format, ...);
+    
+    void println(char *pString);
+    void println(int iNumber);
+    void println(float fNumber);
+    void println(const char *format, ...);
+    
+    void printat(uint8_t x, uint8_t y, char *pString);
+    void printat(uint8_t x, uint8_t y, int iNumber);
+    void printat(uint8_t x, uint8_t y, float fNumber);
+    void printat(uint8_t x, uint8_t y, const char *format, ...);
+    
+    // Sprite functions
+    void AddSprite(int iSpriteNum, int iChar, int x, int y, int fore_color, int back_color, bool midhandle = false);  // width/height is a multiple of 8
+    void EnableSprite(int iSpriteNum, bool bEnable);
+    void RemoveSprite(int iSpriteNum);
+    void SetSpriteChar(int iSpriteNum, int iChar);
+    void SetSpritePos(int iSpriteNum, int x, int y);
+    void SetSpriteColor(int iSpriteNum, int fore_color, int back_color);
+    void SetMidHandle(int iSpriteNum, bool bEnable);
+    bool SpriteCollision(int iSpriteNum1, int iSpriteNum2);
+    
+    void SetCustomChar(int iCharNum, uint8_t *pBuf, int iNum = 1, bool isMSX = false);         // Custom Characters can be used for Sprites and Tiles
+    
+protected:
+
+    bool m_word_wrap;
+    uint8_t m_fore_color, m_back_color;     // Indecies into the color palette
+    uint8_t m_cursor_x, m_cursor_y;
+    uint8_t m_char_map[CHAR_MAP_LEN];
+    uint8_t m_color_map[CHAR_MAP_LEN];
+    uint16_t m_color_pal[COLOR_PAL_LEN];
+    uint8_t *m_line_buffer;
+    
+    void blit_line(uint8_t line);
+    void bounds_check_and_scroll();
+    int get_linear_cursor_pos() { return (m_cursor_x + (m_cursor_y * CHAR_MAP_WIDTH)); };
+    int get_linear_pos(int x, int y) { return (x + (y * CHAR_MAP_WIDTH)); };
+    
+    SPRITE sprite_list[MAX_SPRITES];
+    
+    uint8_t user_char[MAX_USER_CHAR_BUF_LEN];
+    void SetCustomChar8x8Norm(int iCharNum, uint8_t *pBuf);
+    void SetCustomChar8x8MSX(int iCharNum, uint8_t *pBuf);
+};
+
diff -r 000000000000 -r c79e1f29f029 Display/font8x8.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Display/font8x8.cpp	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,102 @@
+#include "font8x8.h"
+
+// Constant: font8x8_basic
+// Contains an 8x8 font map for unicode points U+0000 - U+007F (basic latin)
+unsigned char font8x8_basic[FONT8X8_CHARACTERS * FONT8X8_WIDTH] = {
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   // U+0020 (space)
+     0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00,   // U+0021 (!)
+     0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   // U+0022 (")
+     0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00,   // U+0023 (#)
+     0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00,   // U+0024 ($)
+     0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00,   // U+0025 (%)
+     0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00,   // U+0026 (&)
+     0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,   // U+0027 (')
+     0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00,   // U+0028 (()
+     0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00,   // U+0029 ())
+     0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,   // U+002A (*)
+     0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00,   // U+002B (+)
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06,   // U+002C (,)
+     0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00,   // U+002D (-)
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00,   // U+002E (.)
+     0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00,   // U+002F (/)
+     0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00,   // U+0030 (0)
+     0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00,   // U+0031 (1)
+     0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00,   // U+0032 (2)
+     0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00,   // U+0033 (3)
+     0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00,   // U+0034 (4)
+     0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00,   // U+0035 (5)
+     0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00,   // U+0036 (6)
+     0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00,   // U+0037 (7)
+     0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00,   // U+0038 (8)
+     0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00,   // U+0039 (9)
+     0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00,   // U+003A (:)
+     0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06,   // U+003B (//)
+     0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00,   // U+003C (<)
+     0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00,   // U+003D (=)
+     0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00,   // U+003E (>)
+     0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00,   // U+003F (?)
+     0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00,   // U+0040 (@)
+     0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00,   // U+0041 (A)
+     0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00,   // U+0042 (B)
+     0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00,   // U+0043 (C)
+     0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00,   // U+0044 (D)
+     0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00,   // U+0045 (E)
+     0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00,   // U+0046 (F)
+     0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00,   // U+0047 (G)
+     0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00,   // U+0048 (H)
+     0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00,   // U+0049 (I)
+     0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00,   // U+004A (J)
+     0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00,   // U+004B (K)
+     0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00,   // U+004C (L)
+     0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00,   // U+004D (M)
+     0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00,   // U+004E (N)
+     0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00,   // U+004F (O)
+     0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00,   // U+0050 (P)
+     0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00,   // U+0051 (Q)
+     0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00,   // U+0052 (R)
+     0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00,   // U+0053 (S)
+     0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00,   // U+0054 (T)
+     0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00,   // U+0055 (U)
+     0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00,   // U+0056 (V)
+     0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00,   // U+0057 (W)
+     0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00,   // U+0058 (X)
+     0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00,   // U+0059 (Y)
+     0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00,   // U+005A (Z)
+     0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00,   // U+005B ([)
+     0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00,   // U+005C (\)
+     0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00,   // U+005D (])
+     0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00,   // U+005E (^)
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,   // U+005F (_)
+     0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,   // U+0060 (`)
+     0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00,   // U+0061 (a)
+     0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00,   // U+0062 (b)
+     0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00,   // U+0063 (c)
+     0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00,   // U+0064 (d)
+     0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00,   // U+0065 (e)
+     0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00,   // U+0066 (f)
+     0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F,   // U+0067 (g)
+     0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00,   // U+0068 (h)
+     0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00,   // U+0069 (i)
+     0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E,   // U+006A (j)
+     0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00,   // U+006B (k)
+     0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00,   // U+006C (l)
+     0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00,   // U+006D (m)
+     0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00,   // U+006E (n)
+     0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00,   // U+006F (o)
+     0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F,   // U+0070 (p)
+     0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78,   // U+0071 (q)
+     0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00,   // U+0072 (r)
+     0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00,   // U+0073 (s)
+     0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00,   // U+0074 (t)
+     0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00,   // U+0075 (u)
+     0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00,   // U+0076 (v)
+     0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00,   // U+0077 (w)
+     0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00,   // U+0078 (x)
+     0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F,   // U+0079 (y)
+     0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00,   // U+007A (z)
+     0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00,   // U+007B ({)
+     0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,   // U+007C (|)
+     0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00,   // U+007D (})
+     0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   // U+007E (~)
+     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF    // U+007F (SOLID BLOCK)
+};
diff -r 000000000000 -r c79e1f29f029 Display/font8x8.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Display/font8x8.h	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,12 @@
+#ifndef __FONT8X8_H__
+#define __FONT8X8_H__
+
+#define FONT8X8_CHARACTERS      96
+#define FONT8X8_WIDTH           8
+#define FONT8X8_HEIGHT          8
+
+// Constant: font8x8_basic
+// Contains an 8x8 font map for unicode points U+0000 - U+007F (basic latin)
+extern unsigned char font8x8_basic[FONT8X8_CHARACTERS * FONT8X8_WIDTH];
+
+#endif // __FONT8X8_H__
diff -r 000000000000 -r c79e1f29f029 Game.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Game.cpp	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,1131 @@
+// RETRO Invaders!
+// Written by Chris Favreau
+// cfavreau@fab-favreau.com
+// for the RetroMbuino development board from outrageouscircuits.com
+//
+
+#include "Game.h"
+
+enum TILE_INDEX
+{
+    eTileBlank,
+    eTilePlayer,
+    eTilePlayerShot,
+    eTileInvaderBolt,
+    eTileShield1,
+    eTileShield2,
+    eTileShield3,
+    eTileShield4,
+    eTileSaucer,
+    eTileInvader1,
+    eTileInvader2,
+    eTileInvader3,
+    eTileInvader4,
+    eTileStarfield1,
+    eTileStarfield2,
+    eTileStarfield3,
+    eTileStarfield4,
+    eTileStarfield5,
+    eTileCount,
+};
+
+enum SPRITE_INDEX       // Up to 64 sprites
+{
+    eSpritePlayer = 0,
+    eSpritePlayerShot,
+    eSpriteShield1,
+    eSpriteShield2,
+    eSpriteShield3,
+    eSpriteShield4,
+    eSpriteSaucer,
+    eSpriteInvaderShot1,
+    eSpriteInvaderShot2,
+    eSpriteInvaderShot3,
+    eSpriteInvaderShot4,
+    eSpriteInvaderStart,
+    
+};
+    
+unsigned char TILE_DATA[]={
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    // Blank
+0x18,0x3C,0x7E,0x7E,0x7E,0x3C,0x66,0x42,    // Player
+0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,    // Player Shot
+0x00,0x00,0x10,0x18,0x18,0x08,0x00,0x00,    // Invader Bolt
+0x3C,0x7E,0x7E,0xFF,0xFF,0xFF,0xFF,0x81,    // Shield 1
+0x34,0x76,0x76,0xFF,0xFF,0xFF,0xFF,0x81,    // Shield 2
+0x00,0x52,0x56,0xDF,0xFF,0xFF,0xFF,0x81,    // Shield 3
+0x00,0x00,0x14,0x5D,0x7D,0xFF,0xFF,0x81,    // Shield 4
+0x00,0x3C,0x7E,0xFF,0x7E,0x00,0x00,0x00,    // Saucer 
+0x00,0x3C,0x52,0x3C,0x42,0x24,0x00,0x00,    // Invader 1
+0x00,0x3C,0x4A,0x3C,0x42,0x42,0x00,0x00,    // Invader 2
+0x00,0x3C,0x46,0x3C,0x42,0x81,0x00,0x00,    // Invader 3
+0x00,0x3C,0x62,0x3C,0x42,0x42,0x00,0x00,    // Invader 4
+0x00,0x40,0x00,0x00,0x00,0x04,0x20,0x00,    // Star Field 1
+0x00,0x08,0x00,0x00,0x44,0x00,0x00,0x00,    // Star Field 2
+0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,    // Star Field 3
+0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x80,    // Star Field 4
+0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00};   // Star Field 5
+
+char intro_song[] = "8g5,8f#5,8f5,8e.5,8d#5,8d.5,8c#5,4b4,1p";
+char saucer_song[] = "8f#4,8g4,8f#4,8g4,8f#4,8g4,8f#4,8g4,1p";      // Add a pause at the end... there is a bug in the PlaySong code that skips the last note
+uint16_t invader_march[4] = {NOTE_G3, NOTE_F3, NOTE_E3, NOTE_D3};
+
+Game::Game() : ain(P0_15)
+{
+    initialize();
+}
+
+void Game::initialize()
+{    
+    // Seed the random number generator
+    srand(this->ain.read_u16());
+    
+    // Start the timer
+    timer.start();
+    frame_timeout = timer.read_ms() + MS_PER_FRAME;
+    frame_count = 0;
+    
+    // Setup the customer character buffer with our sprites
+    disp.SetCustomChar(0, TILE_DATA, eTileCount, true);
+    
+    // Start the sound driver
+    sound.Init();
+    sound.SetInstrument(0, SOUND_SQUARE, 255, 10, 0, 0, 0, 0, 0, 0);   // Music?
+    sound.SetInstrument(1, SOUND_NOISE, 255, 8, 0, 0, 0, 0, 0, 0);      // Explosion?
+    sound.SetInstrument(2, SOUND_SQUARE, 255, 0, -50, 0, 0, 0, 0, 0);   // Pew Pew
+    
+    
+    // Set the game mode
+    mode = eGameTitle;
+    // Set the step state machine to 0
+    game_step = 0;
+    // Not paused
+    paused = false;
+    
+    // Initialize the scores
+    score = 0;
+    hiscore = 32;    // TODO - store this value in the onboard EEPROM ... no mbed class to do that at the present... outta time
+    
+    // Initialize the level
+    level = 1;
+    
+    // Initialize our star map
+    star_field_timer = 0;
+}
+
+bool Game::dotick()
+{
+    now = timer.read_ms();
+    if (now < frame_timeout) return false;
+    frame_timeout = now + MS_PER_FRAME;
+    frame_count++;
+    return true;
+}
+
+void Game::tick()
+{
+    if (!dotick()) return;
+    
+    lights.tick();
+    inputs.tick();
+    
+    if (!paused)
+    {
+        switch(mode)
+        {
+        case (eGameTitle): DoGameTitle(); break;
+        case (eGamePlay): DoGamePlay(); break;
+        case (eGameOver): DoGameOver(); break;
+        }
+    }
+    else
+    {
+        disp.printat((CHAR_MAP_WIDTH >> 1) - 6, 8, ".oOPausedOo.");
+        if (inputs.hit(eCircle) || (inputs.hit(eSquare)))
+        {
+            paused = false;
+        }
+    }
+    
+    disp.render();
+}
+
+int ax, ay, avx, avy, af;
+int mx, my;
+bool missle;
+int await;
+int selection = 0;
+
+void Game::DoGameTitle()
+{
+    switch(game_step)
+    {
+    default:
+    case (0):
+        // Setup the title animation sprite
+        disp.AddSprite(0, eTileInvader1, 0, 0, PAL_GREEN, PAL_TRANSPARENT, true);   // Invader
+        disp.AddSprite(1, eTileInvaderBolt, 0, 0, PAL_YELLOW, PAL_TRANSPARENT, true);  // Invader Bolt
+        // Setup some sounds
+        sound.SetInstrument(1, SOUND_NOISE, 255, 8, 0, 0, 0, 0, 0, 0);      // Explosion?
+        sound.SetInstrument(2, SOUND_SQUARE, 255, 0, -50, 0, 0, 0, 0, 0);   // Pew Pew
+        // Setup the sound for the invader
+        sound.SetInstrument(0, SOUND_SQUARE, 200, 0, -1, 0, 0, 0, 255, 100);    // Vibrato + SLide down
+        // Next step
+        game_step++;
+        break;
+    case (1):
+        // Setup the invader's position and frame
+        ax = 16; ay = 8;
+        avx = 1;
+        af = 0;
+        disp.SetSpritePos(0, ax, ay);
+        disp.EnableSprite(0, true);
+        game_step++;
+        break;
+    case (2):
+        // Draw the score (current and hi score)
+        UpdateScore();
+        // Display the title and the invader coming down...
+        disp.clear();
+        disp.printat(10 - 8, 6, "RETRO Invaders!");
+        if (selection == 0) disp.setforecolor(PAL_YELLOW);
+        disp.printat(10 - 3, 8, "%cPlay%c", (selection == 0) ? '>' : ' ', (selection == 0) ? '<' : ' ');
+        disp.setforecolor(PAL_WHITE);
+        if (selection == 1) disp.setforecolor(PAL_YELLOW);
+        disp.printat(10 - 5, 9, "%cSound %s%c", (selection == 1) ? '>' : ' ', sound.IsMuted() ? "Off" : "On ", (selection == 1) ? '<' : ' ');
+        disp.setforecolor(PAL_WHITE);
+        disp.SetSpritePos(0, ax, ay);
+        disp.SetSpriteChar(0, eTileInvader1 + af);
+        af++;
+        if (af > 3) af = 0;
+        ax += avx;
+        if ((ax > 128) || (ax < 16))
+        {
+            missle = true;
+            mx = ax + 4; my = ay;
+            disp.EnableSprite(1, true);
+            avx *= -1;
+            ay += 8;
+            sound.PlaySound(0, NOTE_C4, 40);
+            lights.set(1, true, 5);
+            lights.set(2, true, 5);
+        }
+        if (ay >= 48)
+        {
+            // Hide the missle sprite
+            disp.EnableSprite(1, false);
+            missle = false;
+            // Hide the invader
+            disp.EnableSprite(0, false);
+            // Setup a wait timer count 3 seconds
+            await = 3 * FRAMES_PER_SECOND;
+            // Play an explosion sound
+            sound.PlaySound(1, NOTE_C7, 20);
+            // Setup the leds to blink
+            lights.blink(1, 5, 1, -1);
+            lights.blink(2, 5, 0, -1);
+            // go to the next animated sequence step
+            game_step++;
+        }
+        if (missle)
+        {
+            my +=2;
+            disp.SetSpritePos(1, mx, my);
+            if (my > LCD_HEIGHT)
+            {
+                missle = false;
+                disp.EnableSprite(1, false);
+            }
+        }
+        if (inputs.hit(eCircle) || inputs.hit(eSquare))
+        {
+            sound.PlaySound(0, NOTE_C6, 10);
+            
+            // Do the selection
+            if (selection == 1)
+            {
+                // Toggle the sound on/off
+                sound.Mute(!sound.IsMuted());
+            }
+            if (selection == 0)
+            {
+                sound.SetInstrument(0, SOUND_SQUARE, 255, 0, 0, 0, 0, 0, 0, 0);   // Music?
+                // Play the intro song
+                sound.PlaySong(intro_song, 0, 130, false);
+                // Let's play the game! goto step 4
+                game_step = 4;
+            }
+        }
+        if (inputs.hit(eUp))
+        {
+            selection++;
+            if (selection > 1) selection = 0;
+        }
+        if (inputs.hit(eDown))
+        {
+            selection--;
+            if (selection < 0) selection = 1;
+        }
+        break;
+    case (3):
+        // Flash the game logo red
+        if ((frame_count % FRAMES_PER_SECOND) >= 15)
+            disp.setforecolor(PAL_RED);
+        else
+            disp.setforecolor(PAL_WHITE);
+        disp.clear();
+        disp.printat((CHAR_MAP_WIDTH >> 1) - 8, 6, "RETRO Invaders!");
+        // subtract one from the wait counter
+        await--;
+        if (await < 1)
+        {
+            // Stop the leds from blinking
+            lights.set(1, false, 1);
+            lights.set(2, false, 1);
+            // Set the text color back to white
+            disp.setforecolor(PAL_WHITE);
+            // do the previous animation sequence
+            game_step = 1;
+        }
+        break;
+    case (4):
+        disp.EnableSprite(0, false);    // Hide the invader sprite
+        mode = eGamePlay;
+        game_step = 0;
+        break;
+    }    
+}
+
+void Game::SetupStarfield()
+{
+    uint8_t color = 0;
+    
+    for (int y = 0; y < CHAR_MAP_HEIGHT; y++)
+    for (int x = 0; x < CHAR_MAP_WIDTH; x++)
+    {
+        // Pick random number between 0 and 4
+        uint8_t num = rand() % 5;
+        // Pick a color based on the random number
+        switch(num)
+        {
+        case (0):
+        case (1):
+        case (2):
+            color = PAL_BLUE;
+            break;
+        case (3):
+        case (4):
+            color = PAL_LIGHTBLUE;
+            break;
+        }
+        // Set the startfield tile based on the random number and random color
+        disp.set_map(128 + (eTileStarfield1 + num), x, y, color, PAL_BLACK);
+    }
+}
+
+void Game::UpdateStarfield()
+{
+    // Check to see if it is time to update the starfield
+    star_field_timer++;
+    if (star_field_timer < 5) return;
+    star_field_timer = 0;
+ 
+    uint8_t y = 0;
+    uint8_t color = 0;
+       
+    // Replace the Score and Lives with Star tiles before we scroll
+    // otherwise they will scroll with us...
+    for (int x = 0; x < CHAR_MAP_WIDTH; x++)
+    {
+        // Pick random number between 0 and 4
+        uint8_t num = rand() % 5;
+        // Pick a color based on the random number
+        switch(num)
+        {
+        case (0):
+        case (1):
+        case (2):
+            color = PAL_BLUE;
+            break;
+        case (3):
+        case (4):
+            color = PAL_LIGHTBLUE;
+            break;
+        }
+        // Set the startfield tile based on the random number and random color
+        disp.set_map(128 + (eTileStarfield1 + num), x, 0, color, PAL_BLACK);                    // Top line of the screen
+    }
+    
+    // Scroll the whole field down 1 tile
+    disp.shift_map(eShiftDown);
+    
+    for (int x = 0; x < CHAR_MAP_WIDTH; x++)
+    {
+        // Pick random number between 0 and 4
+        uint8_t num = rand() % 5;
+        // Pick a color based on the random number
+        switch(num)
+        {
+        case (0):
+        case (1):
+        case (2):
+            color = PAL_BLUE;
+            break;
+        case (3):
+        case (4):
+            color = PAL_LIGHTBLUE;
+            break;
+        }
+        // Set the startfield tile based on the random number and random color
+        disp.set_map(128 + (eTileStarfield1 + num), x, y, color, PAL_BLACK);
+    }
+}
+
+void Game::SetupInvaders()
+{
+    invaders_x = 10;
+    invaders_y = 10;
+    invaders_inc = 4;
+    invaders_frame = 0;
+    invaders_timer = 0;
+    active_invaders = 40;
+    invaders_wait_time = 5;
+    uint8_t color = 0;
+    for (int i = 0; i < 40; i++)
+    {
+        switch(i / 8)
+        {
+        case (0): color = PAL_WHITE; break;
+        case (1): color = PAL_YELLOW; break;
+        case (2): color = PAL_ORANGE; break;
+        case (3): color = PAL_RED; break;
+        case (4): color = PAL_GREEN; break;
+        case (5): color = PAL_LIGHTBLUE; break;
+        case (6): color = PAL_BLUE; break;
+        case (7): color = PAL_MAGENTA; break;
+        }
+        
+        uint8_t x = invaders_x + ((i % 8) * 10);
+        uint8_t y = invaders_y + ((i / 8) * 10);
+        disp.AddSprite(eSpriteInvaderStart + i, eTileInvader1, x, y, color, PAL_TRANSPARENT);
+        invaders[i] = true;
+    }
+    
+    for (int i = 0; i < 4; i++)
+    {
+        invader_active_shot[i] = false;
+        invader_shot_x[i] = 0;
+        invader_shot_y[i] = 0;
+        disp.AddSprite(eSpriteInvaderShot1 + i, eTileInvaderBolt, invader_shot_x[i], invader_shot_y[i], PAL_WHITE, PAL_TRANSPARENT);
+    }
+    invader_shot_interval = FRAMES_PER_SECOND;
+    invader_shot_timer = invader_shot_interval;
+    invader_march_note = 0;
+}
+
+void Game::UpdateInvaders()
+{
+    // Check to see if it is time to advance the frame
+    invaders_timer++;
+    if (invaders_timer > invaders_wait_time)
+    {
+        invaders_timer = 0;
+        invaders_frame++;
+        if (invaders_frame > 3) invaders_frame = 0; 
+        // Play the invader march sound
+        if ((invaders_frame == 0) || (invaders_frame == 2))
+        {
+            sound.PlaySound(0, invader_march[invader_march_note++], 10);
+            if (invader_march_note >= 4) invader_march_note = 0;
+        }
+        // Move the invaders
+        invaders_x += invaders_inc;
+    }
+    // Update all of the invaders
+    bool move_down = false;
+    for (int i = 0; i < 40; i++)
+    {
+        // Check to see if this invader is active and not blown up
+        if (invaders[i])
+        {
+            // Calculate the position of this invader
+            uint8_t x = invaders_x + ((i % 8) * 10);
+            uint8_t y = invaders_y + ((i / 8) * 10);
+            
+            // Check to see if the invader has reach the edge of the play area
+            if (x >= 150) move_down = true;
+            if (x < 10) move_down = true;
+        
+            disp.SetSpriteChar(eSpriteInvaderStart + i, eTileInvader1 + invaders_frame);
+            disp.SetSpritePos(eSpriteInvaderStart + i, x, y);
+        }
+        disp.EnableSprite(eSpriteInvaderStart + i, invaders[i]);
+    }
+    // Check to see if we should move the invaders down one notch
+    if (move_down)
+    {
+        invaders_y += 5;    // Half the height of the invader space (10 x 10?)
+        invaders_inc *= -1;
+        invaders_x += invaders_inc;
+        // Increase the invader speed if we need to
+        if (active_invaders <= 30) invaders_wait_time = 4;
+        if (active_invaders <= 20) invaders_wait_time = 3;
+        if (active_invaders <= 10) invaders_wait_time = 2;
+        if (active_invaders <= 5) invaders_wait_time = 1;
+        if (active_invaders <= 2) invaders_wait_time = 0;
+    }
+        
+    // Service any active shots
+    for (int shot = 0; shot < 4; shot++)
+    {
+        if (invader_active_shot[shot])
+        {
+            // Advance downwards
+            invader_shot_y[shot] += (2 * level);    // Speed the shots up the higher up we get in the levels ... that is the difficulty setting
+            disp.SetSpritePos(eSpriteInvaderShot1 + shot, invader_shot_x[shot], invader_shot_y[shot]);
+            // Check to see if we are off the screen
+            if (invader_shot_y[shot] > (LCD_HEIGHT - 4))
+            {
+                invader_active_shot[shot] = false;
+                disp.EnableSprite(eSpriteInvaderShot1 + shot, false);
+            }
+        }
+    }
+    // Do the invader shooting
+    invader_shot_timer--;
+    if (invader_shot_timer < 0)
+    {
+        // Reset the shot timer
+        invader_shot_timer = invader_shot_interval;
+        // Find an inactive shot to use (up to 4 active at a time)
+        int shot;
+        for (shot = 0; shot < 4; shot++)
+        {
+            if (!invader_active_shot[shot])
+            {
+                // Pick a random invader for it to come from (there are 40 of them)
+                int invader = rand() % active_invaders;
+                // Figure out the active invader's coordinates
+                for (int i = 0; i < 40; i++)
+                {
+                    int index = (i + invader) % 40;
+                    if (invaders[index])
+                    {
+                        uint8_t color = 0;
+                        switch(index / 8)
+                        {
+                        case (0): color = PAL_WHITE; break;
+                        case (1): color = PAL_YELLOW; break;
+                        case (2): color = PAL_ORANGE; break;
+                        case (3): color = PAL_RED; break;
+                        case (4): color = PAL_GREEN; break;
+                        case (5): color = PAL_LIGHTBLUE; break;
+                        case (6): color = PAL_BLUE; break;
+                        case (7): color = PAL_MAGENTA; break;
+                        }
+                        // Initialize the shot
+                        invader_active_shot[shot] = true;
+                        invader_shot_x[shot] = invaders_x + ((index % 8) * 10) + 4;
+                        invader_shot_y[shot] = invaders_y + ((index / 8) * 10) + 4;
+                        disp.EnableSprite(eSpriteInvaderShot1 + shot, true);
+                        disp.SetSpriteColor(eSpriteInvaderShot1 + shot, color, PAL_TRANSPARENT);
+                        disp.SetSpritePos(eSpriteInvaderShot1 + shot, invader_shot_x[shot], invader_shot_y[shot]);
+                        sound.PlaySound(2, NOTE_C7, 20);
+                        break;
+                    }
+                }
+                break;
+            }
+        }
+    }
+}
+
+void Game::SetupPlayer()
+{
+    player_x = LCD_WIDTH >> 1;
+    player_y = LCD_HEIGHT - 10;
+    disp.AddSprite(eSpritePlayer, eTilePlayer, player_x, player_y, PAL_LIGHTGREY, PAL_TRANSPARENT, true);   // auto midhandle
+    player_shot_active = false;
+    player_shot_x = 0;
+    player_shot_y = 0;
+    disp.AddSprite(eSpritePlayerShot, eTilePlayerShot, player_shot_x, player_shot_y, PAL_WHITE, PAL_TRANSPARENT, true); // auto midhandle
+}
+
+void Game::UpdatePlayer()
+{
+    // Check to see if the left and right buttons have been hit
+    if (inputs.pressed(eLeft))
+    {
+        player_x -= 2;
+        if (player_x < 5) player_x = 5;
+    }
+    if (inputs.pressed(eRight))
+    {
+        player_x += 2;
+        if (player_x > (LCD_WIDTH - 5)) player_x = (LCD_WIDTH - 5); 
+    }
+    disp.SetSpritePos(eSpritePlayer, player_x, player_y);
+    if ((inputs.hit(eSquare) || inputs.hit(eCircle)) && !player_shot_active)
+    {
+        player_shot_x = player_x;
+        player_shot_y = player_y;
+        player_shot_active = true;
+        disp.EnableSprite(eSpritePlayerShot, true);
+        sound.PlaySound(2, NOTE_C7, 20);
+    }
+    if (inputs.pressed(eSquare) && inputs.pressed(eCircle))
+    {
+        // Pause the game
+        paused = true;
+    }
+    if (player_shot_active)
+    {
+        player_shot_y -= 5;
+        if (player_shot_y < 5)
+        {
+            player_shot_active = false;
+            disp.EnableSprite(eSpritePlayerShot, false);
+        }
+        disp.SetSpritePos(eSpritePlayerShot, player_shot_x, player_shot_y);
+    }
+}
+
+void Game::SetupSaucer()
+{
+    saucer_x = 0;
+    saucer_y = 10;
+    disp.AddSprite(eSpriteSaucer, eTileSaucer, saucer_x, saucer_y, PAL_YELLOW, PAL_TRANSPARENT, true);
+    disp.EnableSprite(eSpriteSaucer, false);
+    saucer_timer = (rand() % 10) * FRAMES_PER_SECOND;  // Random time every 10 seconds
+    saucer_active = false;
+}
+
+void Game::UpdateSaucer()
+{
+    if (!saucer_active)
+    {
+        saucer_timer--;
+        if (saucer_timer > 1) return;
+        // Calculate a new time for the saucer to be active (after it completes its sequence)
+        saucer_timer = (rand() % 10) * FRAMES_PER_SECOND;  // Random time every 10 seconds
+        // Time to go.. setup the saucer to go
+        // Set the saucer active flag
+        saucer_active = true;
+        // Set the saucer movement increment (same speed and opposite direction as the invaders are currently moving)
+        saucer_inc = invaders_inc * -1;
+        // Set the saucers starting coordiantes
+        if (saucer_inc > 0)
+            saucer_x = 0;               // left to right movement
+        else
+            saucer_x = LCD_WIDTH - 4;   // right to left movement
+        // Set the sprite position and enable the sprite
+        disp.SetSpritePos(eSpriteSaucer, saucer_x, saucer_y);
+        disp.EnableSprite(eSpriteSaucer, true);
+        // Play the saucer song (looped)
+        sound.PlaySong(saucer_song, 0, 130, true);
+        // Setup the leds to blink
+        lights.blink(1, 5, 1, -1);
+        lights.blink(2, 5, 0, -1);
+        // Set the saucer timer .. we will use it to divide the frame counter
+        saucer_timer = 0;
+        return;
+    }
+    
+    // Divide the frame counter to slow things down (same speed as invaders)
+    saucer_timer++;
+    if (saucer_timer < 5) return;
+    saucer_timer = 0;
+    
+    // Move the saucer
+    saucer_x += saucer_inc;
+    if ((saucer_x < 1) || (saucer_x > (LCD_WIDTH - 1)))
+    {
+        lights.set(1, false, 1);
+        lights.set(2, false, 1);
+        saucer_active = false;
+        disp.EnableSprite(eSpriteSaucer, false);
+        sound.StopSong();
+        saucer_timer = (rand() % 10) * FRAMES_PER_SECOND;  // Random time every 10 seconds
+    }
+    disp.SetSpritePos(eSpriteSaucer, saucer_x, saucer_y);
+}
+
+void Game::SetupShields()
+{
+    shield_x = LCD_WIDTH >> 1;
+    shield_y = LCD_HEIGHT - 20;
+    disp.AddSprite(eSpriteShield1, eTileShield1, shield_x - 45, shield_y, PAL_GREEN, PAL_TRANSPARENT, true);
+    disp.AddSprite(eSpriteShield2, eTileShield1, shield_x - 15, shield_y, PAL_GREEN, PAL_TRANSPARENT, true);
+    disp.AddSprite(eSpriteShield3, eTileShield1, shield_x + 15, shield_y, PAL_GREEN, PAL_TRANSPARENT, true);
+    disp.AddSprite(eSpriteShield4, eTileShield1, shield_x + 45, shield_y, PAL_GREEN, PAL_TRANSPARENT, true);
+    for (int i = 0; i < 4; i++)
+        shield_points[i] = 4;
+}
+
+void Game::UpdateShields()
+{
+    // Todo - they don't move but they have hit points...
+    for (int i = 0; i < 4; i++)
+    {
+        disp.SetSpriteChar(eSpriteShield1 + i, eTileShield1 + (4 - shield_points[i]));
+    }
+}
+
+void Game::CheckCollisions()
+{
+    // Check the player's shot to see if it hits any:
+    // Invader
+    for (int i = 0; i < 40; i++)
+    {
+        // Check to see if this invader is active
+        if (invaders[i])
+        {
+            if (disp.SpriteCollision(eSpritePlayerShot, eSpriteInvaderStart + i))
+            {
+                // Destroy the invader
+                disp.EnableSprite(eSpriteInvaderStart + i, false);
+                invaders[i] = false;
+                active_invaders--;
+                // Destroy the player's shot
+                sound.PlaySound(1, NOTE_C6, 30);
+                disp.EnableSprite(eSpritePlayerShot, false);
+                player_shot_active = false;
+                // Increment the score (more points for the ones at the top)
+                // 5 points for the top row, 4 points for the next, etc...
+                IncScore(5 - (i / 8));
+                // Check to see if all of the invaders were destroyed
+                if (active_invaders < 1)
+                {
+                    // Level Up and go to the next step (for going to the next level)
+                    level++;
+                    game_step = 2;
+                }
+            }
+        }
+    }
+    // Shield
+    for (int i = 0; i < 4; i++)
+    {
+        if (disp.SpriteCollision(eSpritePlayerShot, eSpriteShield1 + i))
+        {
+            // Subtract 1 from the shield's points
+            shield_points[i]--;
+            if (shield_points[i] < 1)
+            {
+                // Disable this shield
+                disp.EnableSprite(eSpriteShield1 + i, false);
+                // TODO - Maybe make a noise...
+            }
+            // Destroy the player's shot
+            sound.PlaySound(1, NOTE_C6, 30);
+            disp.EnableSprite(eSpritePlayerShot, false);
+            player_shot_active = false;
+        }
+    }
+    // Invader Shot
+    for (int i = 0; i < 4; i++)
+    {
+        if (disp.SpriteCollision(eSpritePlayerShot, eSpriteInvaderShot1 + i))
+        {
+            // Disable this invader shot
+            invader_active_shot[i] = false;
+            disp.EnableSprite(eSpriteInvaderShot1 + i, false);
+            // Destroy the player's shot
+            sound.PlaySound(1, NOTE_C6, 30);
+            disp.EnableSprite(eSpritePlayerShot, false);
+            player_shot_active = false;
+            // 1 point for shooting an invader bullet
+            IncScore(1);
+        }
+    }
+    // Saucer
+    if (disp.SpriteCollision(eSpritePlayerShot, eSpriteSaucer))
+    {
+        // Destroy the saucer
+        lights.set(1, false, 1);
+        lights.set(2, false, 1);
+        saucer_active = false;
+        disp.EnableSprite(eSpriteSaucer, false);
+        sound.StopSong();
+        saucer_timer = (rand() % 10) * FRAMES_PER_SECOND;  // Random time every 10 seconds
+        // Destroy the player's shot
+        sound.PlaySound(1, NOTE_C6, 30);
+        disp.EnableSprite(eSpritePlayerShot, false);
+        player_shot_active = false;
+        // 10 points for a saucer
+        IncScore(10);
+    }
+    
+    // Check to see if the invader's shots hit any:
+    // Shields
+    // Player Ships
+    for (int shot = 0; shot < 4; shot++)
+    {
+        if (!invader_active_shot[shot]) continue;
+        
+        // Check the player
+        if (disp.SpriteCollision(eSpritePlayer, eSpriteInvaderShot1 + shot))
+        {
+            // Play the Explosion sound
+            sound.PlaySound(1, NOTE_C6, 30);
+            // Destroy the shot
+            invader_active_shot[shot] = false;
+            disp.EnableSprite(eSpriteInvaderShot1 + shot, false);
+            // Decrement the player lives
+            lives--;
+            // Go to the player blow up sequence
+            game_step = 4; // we will check to see if the lives are 0 there!
+        }
+        
+        // Check the shields
+        for (int shield = 0; shield < 4; shield++)
+        {
+            if (disp.SpriteCollision(eSpriteInvaderShot1 + shot, eSpriteShield1 + shield))
+            {
+                // Subtract 1 from the shield's points
+                shield_points[shield]--;
+                if (shield_points[shield] < 1)
+                {
+                    // Disable this shield
+                    disp.EnableSprite(eSpriteShield1 + shield, false);
+                    // TODO - Maybe make a noise...
+                }
+                sound.PlaySound(1, NOTE_C6, 30);
+                // Destroy the shot
+                invader_active_shot[shot] = false;
+                disp.EnableSprite(eSpriteInvaderShot1 + shot, false);
+            }
+        } 
+    }
+    // Check to see if the invaders have reached the shields
+    // Or if the invaders have reached the ship!
+    for (int i = 0 ; i < 40; i++)
+    {
+        // Check only active invaders
+        if (!invaders[i]) continue;
+        
+        for (int shield = 0; shield < 4; shield++)
+        {
+            // Check only active shields
+            if (shield_points[shield] < 1) continue;
+            if (disp.SpriteCollision(eSpriteInvaderStart + i, eSpriteShield1 + shield))
+            {
+                // Destroy the shield
+                shield_points[shield] = 0;
+                disp.EnableSprite(eSpriteShield1 + shield, false);
+                sound.PlaySound(1, NOTE_C6, 10);
+            }
+        }
+        
+        if (disp.SpriteCollision(eSpriteInvaderStart + i, eSpritePlayer))
+        {
+            // Game Over!!!!
+            lives = 0;
+           // Go to the player blow up sequence
+            game_step = 4; // we will check to see if the lives are 0 there!
+        }
+    }
+}
+
+void Game::IncScore(int points)
+{
+    // Increment the score
+    score += points;
+    // Update the hi score if necessary
+    if (score > hiscore) hiscore = score;
+}
+
+void Game::UpdateScore()
+{
+    // Hi Score in the middle
+    disp.printat(7, 0, "HI%04d", hiscore);
+    // Current Score on the left
+    disp.printat(0, 0, "%04d", score);
+}
+
+void Game::UpdateLives()
+{
+    // Men left in the upper right
+    if (lives >= 1) disp.setcharat(CHAR_MAP_WIDTH - 1, 0, 128 + eTilePlayer, PAL_LIGHTBLUE, PAL_BLACK);
+    if (lives >= 2) disp.setcharat(CHAR_MAP_WIDTH - 2, 0, 128 + eTilePlayer, PAL_LIGHTBLUE, PAL_BLACK);
+    if (lives >= 3) disp.setcharat(CHAR_MAP_WIDTH - 3, 0, 128 + eTilePlayer, PAL_LIGHTBLUE, PAL_BLACK);
+}
+
+void Game::DoGamePlay()
+{
+    switch(game_step)
+    {
+    case (0):
+        disp.clear();
+        // Setup the score and lives
+        score = 0;
+        lives = 3;
+        // DEBUG
+        //mode = eGameOver; break;
+        // Sprites
+        // Invaders ( 8 x 5 = 40 total - starts at sprite #10)
+        SetupInvaders();
+        // Shields  ( 3 shields)
+        SetupShields();
+        // Player     ( 1 player)
+        SetupPlayer();
+        // Saucer   ( 1 saucer)
+        SetupSaucer();
+        // Setup the playfield
+        SetupStarfield();
+        // Draw the taunt
+        disp.printat((CHAR_MAP_WIDTH >> 1) - 8, 8, "We Are Coming...");
+        // DEBUG - kill most of the invaders
+        /*(
+        for (int i = 0; i < 35; i++)
+        {
+            invaders[i] = false;
+            active_invaders--;
+        }
+        */
+        // Next step
+        game_step = 1;
+        break;
+    case (1):
+        // This is the main game loop here
+        // Check for Input
+        // Update the star field
+        UpdateStarfield();
+        // Move Invaders
+        UpdateInvaders();
+        // Move Player
+        UpdatePlayer();
+        // Update the shields
+        UpdateShields();
+        // Update the saucer
+        UpdateSaucer();
+        // Update the rest of the screen
+        UpdateScore();
+        UpdateLives();
+        // Make things shoot each other
+        // Check for collisions
+        CheckCollisions();
+        // Check for Game Over
+        
+        // dEBUG
+        //disp.printat(0, 15, "%d", active_invaders);
+        break;
+    case (2):
+        // Next Level
+        UpdateStarfield();
+        UpdateScore();
+        UpdateLives();
+        // Play the intro song
+        sound.PlaySong(intro_song, 0, 130, false);
+        // Print out a taunt
+        disp.printat((CHAR_MAP_WIDTH >> 1) - 3, 8, "Ready?");
+        // Set the wait timer
+        wait_timer = 20;
+        // Next step to do the waiting
+        game_step = 3;
+        break;
+    case (3):
+        // Wait a few ticks before putting the invaders up
+        UpdateStarfield();
+        UpdateScore();
+        UpdateLives();
+        wait_timer--;
+        if (wait_timer == 0)
+        {
+            // Initialize the board again
+            // Sprites
+            // Invaders ( 8 x 5 = 40 total - starts at sprite #10)
+            SetupInvaders();
+            // Shields  ( 3 shields)
+            SetupShields();
+            // Player     ( 1 player)
+            SetupPlayer();
+            // Saucer   ( 1 saucer)
+            SetupSaucer();
+            // Setup the playfield
+            SetupStarfield();
+            // Draw the taunt
+            disp.printat((CHAR_MAP_WIDTH >> 1) - 8, 8, "We Are Coming...");
+            // Next step
+            game_step = 1;
+        }
+        break;
+    case (4):
+        // Set the wait timer
+        wait_timer = 20;
+        // Play a LOOONG blow up sound
+        sound.PlaySound(1, NOTE_C6, 60);
+        // Taunt the player!
+        disp.setforecolor(PAL_RED);
+        disp.printat((CHAR_MAP_WIDTH >> 1) - 4, 8, "Winning!");
+        disp.setforecolor(PAL_WHITE);
+        // Next step to wait and do the player explosion sequence
+        game_step = 5;
+        break;
+    case (5):
+        // Do the player blow up sequence
+        disp.SetSpriteChar(eSpritePlayer, eTileStarfield1 + (wait_timer % 3));
+        disp.SetSpriteColor(eSpritePlayer, PAL_RED, PAL_TRANSPARENT);
+        wait_timer--;
+        // When we are done go back to the play the game step
+        if (wait_timer < 1)
+        {
+            game_step = 1;
+            // Set the player sprite back to normal
+            disp.SetSpriteChar(eSpritePlayer, eTilePlayer);
+            disp.SetSpriteColor(eSpritePlayer, PAL_GREY, PAL_TRANSPARENT);
+            // check to see if the lives have reached 0
+            if (lives < 1)
+            {
+                // Disable the player sprite
+                disp.EnableSprite(eSpritePlayer, false);
+                // Switch the mode to Game Over
+                game_step = 0;
+                mode = eGameOver;
+                // The Invaders have Arrived!
+            }
+        }
+        break;
+    }
+}
+
+void Game::UpdateGameOverInvaders()
+{
+    uint8_t color = 0;
+    
+    // Scroll the whole field up 1 tile
+    disp.shift_map(eShiftUp);
+    
+    // Pick a color    
+    switch(invaders_frame % 8)
+    {
+    case (0): color = PAL_WHITE; break;
+    case (1): color = PAL_YELLOW; break;
+    case (2): color = PAL_ORANGE; break;
+    case (3): color = PAL_RED; break;
+    case (4): color = PAL_GREEN; break;
+    case (5): color = PAL_LIGHTBLUE; break;
+    case (6): color = PAL_BLUE; break;
+    case (7): color = PAL_MAGENTA; break;
+    }
+
+    // Fill the top with invaders of a color
+    for (int i = 0; i < CHAR_MAP_WIDTH; i++)
+    {
+        disp.setcharat(i, CHAR_MAP_HEIGHT - 1, 128 + eTileInvader1 + (invaders_frame % 4), color, PAL_BLACK);
+    }
+    
+    // Next frame
+    invaders_frame++;
+}
+
+void Game::DoGameOver()
+{
+    switch (game_step)
+    {
+    case (0):
+        // Disable all the sprites
+        for (int i = 0; i < MAX_SPRITES; i++)
+            disp.EnableSprite(i, false);
+        // Turn off the leds
+        lights.set(1, false, 1);
+        lights.set(2, false, 1);
+        // Stop the song
+        sound.StopSong();
+        // initialize the game over screen stuff...
+        // play the game over tune
+        wait_timer = 0;
+        star_field_timer = 0;
+        invader_march_note = 0;
+        invaders_frame = 0;
+        game_over_msg = 0;
+        // Setup the coin sound
+        sound.SetInstrument(2, SOUND_SQUARE, 128, 10, 0, 120, 6, 0, 0, 0);    // Coin Sound (Change + Decay)
+        // Next step
+        game_step = 1;
+        break;
+    case (1):
+        // Scroll the screen down and fill with invaders
+        // While playing the march
+        
+        // Use the starfield timer to slow down the scroll
+        star_field_timer++;
+        if (star_field_timer < 10) return;
+        star_field_timer = 0;
+    
+        UpdateGameOverInvaders();
+        
+        // Play the march sound
+        sound.PlaySound(0, invader_march[invader_march_note++], 10);
+        if (invader_march_note >= 4) invader_march_note = 0;
+        
+        // Subtract one from the wait timer
+        wait_timer++;
+        if (wait_timer >= CHAR_MAP_HEIGHT)
+        {
+            game_step = 2;
+            wait_timer = 0;
+        }
+        break;
+    case (2):
+        // Empty step
+        // Clear the wait timer
+        wait_timer = 0;
+        // Next step
+        game_step = 3;
+        break;
+    case (3):
+    
+        // Use the starfield timer to slow down the scroll
+        star_field_timer++;
+        if (star_field_timer < 10) return;
+        star_field_timer = 0;
+        
+        UpdateGameOverInvaders();
+        
+        wait_timer++;
+        if (wait_timer > 3)
+        {
+            wait_timer = 0;
+            game_step = 4;
+        }
+        // Wait a few frames... then print a thanks to outrageous circuits / GHI
+        break;
+    case (4):
+    {
+        char msg[16] = "";
+        
+        switch (game_over_msg)
+        {
+        case (0): sprintf(msg, "The Invaders..."); break;
+        case (1): sprintf(msg, "Have Arrived!"); break;
+        case (2): sprintf(msg, "Game Over!"); break;
+        case (3): sprintf(msg, "Thanks To:"); break;
+        case (4): sprintf(msg, "outrageous"); break;
+        case (5): sprintf(msg, "circuits.com"); break;
+        case (6): sprintf(msg, "GHI"); break;
+        case (7): sprintf(msg, ""); break;
+        case (8): sprintf(msg, "written by"); break;
+        case (9): sprintf(msg, "cfavreau"); break;
+        case (10): game_step = 5; return;
+        }
+        uint8_t len = strlen(msg);
+        disp.printat((CHAR_MAP_WIDTH >> 1) - (len >> 1), CHAR_MAP_HEIGHT - 1, msg);
+        // Play the coin sound
+        sound.PlaySound(2, NOTE_Fs6, 20);
+        // Next message
+        game_over_msg++;
+        game_step = 3;
+    }
+        break;
+    default:
+    case (5):
+        // Reset the game to the title sequence
+        mode = eGameTitle;
+        game_step = 0;
+        // Clear the button hits
+        inputs.clear();
+        break;
+    }
+}
+
diff -r 000000000000 -r c79e1f29f029 Game.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Game.h	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,102 @@
+#include "mbed.h"
+#include "./Display/display.h"      // LCD Display Driver
+#include "./led/led.h"              // LED Driver
+#include "./Input/input.h"          // INPUT Driver
+#include "./Sound/sound.h"          // SOUND Driver
+
+#pragma once
+
+enum GAME_MODE
+{
+    eGameTitle,
+    eGamePlay,
+    eGameOver,
+};
+
+#define FRAMES_PER_SECOND   20      // unfortunately this is what we get...
+#define MS_PER_FRAME        50
+
+class Game
+{   
+    int frame_timeout;
+    int frame_count;
+    int now;
+
+    Timer timer;
+    display disp;
+    AnalogIn ain;
+    led lights;
+    input inputs;
+    Sound sound;
+    
+    GAME_MODE mode;
+    int game_step;
+    bool paused;
+    
+    void initialize();
+    bool dotick();
+    
+    void DoGameTitle();
+    void DoGamePlay();
+    void DoGameOver();
+    
+    uint8_t star_field_timer;
+    void SetupStarfield();
+    void UpdateStarfield();
+    
+    void SetupInvaders();
+    void UpdateInvaders();
+    bool invaders[40];
+    int8_t active_invaders;
+    int8_t invaders_inc;
+    uint8_t invaders_timer;
+    uint8_t invaders_wait_time;
+    uint8_t invaders_frame;
+    uint8_t invaders_x, invaders_y;
+    bool invader_active_shot[4];
+    uint8_t invader_shot_interval;
+    uint8_t invader_shot_x[4];
+    uint8_t invader_shot_y[4];
+    int8_t invader_shot_timer;
+    uint8_t invader_march_note;
+    
+    
+    void SetupPlayer();
+    void UpdatePlayer();
+    uint8_t player_x, player_y;
+    bool player_shot_active;
+    uint8_t player_shot_x, player_shot_y;
+    
+    void SetupSaucer();
+    void UpdateSaucer();
+    bool saucer_active;
+    int saucer_timer;
+    int8_t saucer_inc;
+    uint8_t saucer_x, saucer_y;
+    
+    void SetupShields();
+    void UpdateShields();
+    uint8_t shield_x, shield_y;
+    uint8_t shield_points[4];
+    
+    void CheckCollisions();
+    
+    void IncScore(int points);
+    void UpdateScore();
+    void UpdateLives();
+    int hiscore;
+    int score;
+    uint8_t lives;
+    uint8_t level;
+    
+    uint8_t wait_timer;
+    
+    void UpdateGameOverInvaders();
+    uint8_t game_over_msg;
+    
+public:
+
+    Game();
+    
+    void tick();
+};
\ No newline at end of file
diff -r 000000000000 -r c79e1f29f029 Input/input.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Input/input.cpp	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,134 @@
+#include <math.h>
+#include "input.h"
+
+input::input() : left(P0_14, PullUp), right(P0_11, PullUp), down(P0_12, PullUp), up(P0_13, PullUp), square(P0_16, PullUp), circle(P0_1, PullUp), i2c(P0_5, P0_4)
+{
+    // Clear all the button states
+    for (int i = 0; i < eLastButton; i++)
+    {
+        m_iPressedTicks[i] = 0;
+        m_iHitCount[i] = 0;
+    }
+
+    m_fAccelX = 0.0;
+    m_fAccelY = 0.0;
+    m_fAccelZ = 0.0;
+    
+    i2c.frequency(400);
+    accelWriteRegister(0x2A, 0x01);
+}
+
+void input::dobutton(INPUT_BUTTON button, bool bPressed)
+{
+    // If this button is not being debounced then set the ticks we can debounce the switch
+    if (bPressed)
+    {
+        if (m_iPressedTicks[button] < 1)
+        {
+            // This is the first time this button was pressed since it was UP
+            // Increment the hit count
+            m_iHitCount[button]++;
+        }
+        // Reset the debounce counter
+        m_iPressedTicks[button] = BUTTON_DEBOUNCE_TICKS;
+    }
+    // If this button IS not pressed and we have ticks left... deduct 1 tick
+    if (!bPressed && (m_iPressedTicks[button] > 0))
+         m_iPressedTicks[button]--;
+}
+
+void input::tick()
+{
+    // Sample all of the buttons
+    dobutton(eUp, up.read() == 0);
+    dobutton(eDown, down.read() == 0);
+    dobutton(eLeft, left.read() == 0);
+    dobutton(eRight, right.read() == 0);
+    dobutton(eCircle, circle.read() == 0);
+    dobutton(eSquare, square.read() == 0);
+    
+    // UGHHHHHHH - accelReadRegisters() is BALLS SLOW!!! Disable for NOW!
+    /*
+    // Sample the accelerometers
+    char buffer[6];
+    accelReadRegisters(0x01, buffer, 6);
+    m_fAccelX = accelConvert(buffer);
+    m_fAccelY = accelConvert(buffer + 2);
+    m_fAccelZ = accelConvert(buffer + 4);
+    */
+}
+
+void input::clear()
+{
+    for (int i = 0; i < eLastButton; i++)
+    {
+        m_iHitCount[i] = 0;
+        m_iPressedTicks[i] = 0;
+    }
+}
+
+int input::hit(INPUT_BUTTON button)
+{
+    if (button >= eLastButton) return 0;
+    // Store the hit count for this button
+    int hit_count = m_iHitCount[button];
+    // Clear the hit count
+    m_iHitCount[button] = 0;
+    // Return the stored hit count
+    return hit_count;
+}
+ 
+bool input::pressed(INPUT_BUTTON button)
+{
+    if (button >= eLastButton) return false;
+    
+    return (m_iPressedTicks[button] > 0);
+}
+
+
+int input::accel_x()
+{
+    return (int)(m_fAccelX * 100.0);
+}
+
+int input::accel_y()
+{
+    return (int)(m_fAccelY * 100.0);
+}
+
+int input::accel_z()
+{
+    return (int)(m_fAccelZ * 100.0);
+}
+
+int input::accel_roll()
+{
+    // Roll and Pitch are swapped on the Retro... 
+    return (int)((atan(m_fAccelX / sqrt((m_fAccelY * m_fAccelY) + (m_fAccelZ * m_fAccelZ))) * 180.0) / 3.14159);
+}
+
+int input::accel_pitch()
+{
+    // Roll and Pitch are swapped on the Retro.. (Pitch is Roll, Roll is Pitch)
+    return (int)((atan(m_fAccelY / sqrt((m_fAccelX * m_fAccelX) + (m_fAccelZ * m_fAccelZ))) * 180.0) / 3.14159);
+}
+
+void input::accelReadRegisters(char address, char* buffer, int len)
+{
+    // BALLS SLOW!!!
+    i2c.write(I2C_ADDR, &address, 1, true);
+    i2c.read(I2C_ADDR | 1, buffer, len);
+}
+
+int input::accelWriteRegister(char address, char value)
+{    
+    char buffer[2] = { address, value };    
+    return i2c.write(I2C_ADDR, buffer, 2);
+}
+
+float input::accelConvert(char* buffer)
+{
+    float val = ((buffer[0] << 2) | (buffer[1] >> 6));           
+    if (val > 511.0) val -= 1024.0;
+    return val / 512.0;
+}
diff -r 000000000000 -r c79e1f29f029 Input/input.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Input/input.h	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,60 @@
+#include <mbed.h>
+
+enum INPUT_BUTTON
+{
+    eUp,
+    eDown,
+    eLeft,
+    eRight,
+    eCircle,
+    eSquare,
+    eLastButton,
+};
+
+#define BUTTON_DEBOUNCE_TICKS   3
+
+class input
+{
+public:
+
+    input();
+    virtual ~input() {};
+    
+    void tick();        // Call this function at regular intervals (preferably the frame rate)
+    
+    // Buttons
+    int hit(INPUT_BUTTON button);
+    bool pressed(INPUT_BUTTON button);
+    void clear();
+    
+    // Accelerometer
+    // X,Y,Z (0 to 100)
+    int accel_x();
+    int accel_y();
+    int accel_z();
+    // Roll,Pitch (0 to 359)
+    int accel_roll();
+    int accel_pitch();
+    
+protected:
+
+    DigitalIn left;
+    DigitalIn right;
+    DigitalIn down;
+    DigitalIn up;
+    DigitalIn square;
+    DigitalIn circle;
+    int m_iPressedTicks[eLastButton];
+    int m_iHitCount[eLastButton];
+    void dobutton(INPUT_BUTTON button, bool bPressed);
+
+    static const char I2C_ADDR = 0x1C << 1;
+    I2C i2c;
+    void accelReadRegisters(char address, char* buffer, int len);
+    int accelWriteRegister(char address, char value);
+    float accelConvert(char* buffer);
+    
+    float m_fAccelX;
+    float m_fAccelY;
+    float m_fAccelZ;
+};
diff -r 000000000000 -r c79e1f29f029 Main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Main.cpp	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,10 @@
+#include "mbed.h"
+#include "Game.h"
+
+int main()
+{
+    Game game;
+    
+    while (true)
+        game.tick();
+}
\ No newline at end of file
diff -r 000000000000 -r c79e1f29f029 Sound/lpc111x.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Sound/lpc111x.h	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,462 @@
+// lpc111x.h
+// LPC low level all-in-one header file for lpc111x devices
+// principally targeted at lpc1114fn28 (DIP28 package)
+// Written by Frank Duignan
+// Latest version available at http://eleceng.dit.ie/frank/arm/cortex/lpc111x.h
+// Derived from UM10398 user manual from NXP semiconductors
+// Naming convention: Register names are as described in UM10398
+// No claims are made for the suitability, accuracy or otherwise of this file
+// for any application
+// Define some bitmasks
+#define BIT0 (1 << 0)
+#define BIT1 (1 << 1)
+#define BIT2 (1 << 2)
+#define BIT3 (1 << 3)
+#define BIT4 (1 << 4)
+#define BIT5 (1 << 5)
+#define BIT6 (1 << 6)
+#define BIT7 (1 << 7)
+#define BIT8 (1 << 8)
+#define BIT9 (1 << 9)
+#define BIT10 (1 << 10)
+#define BIT11 (1 << 11)
+#define BIT12 (1 << 12)
+#define BIT13 (1 << 13)
+#define BIT14 (1 << 14)
+#define BIT15 (1 << 15)
+#define BIT16 (1 << 16)
+#define BIT17 (1 << 17)
+#define BIT18 (1 << 18)
+#define BIT19 (1 << 19)
+#define BIT20 (1 << 20)
+#define BIT21 (1 << 21)
+#define BIT22 (1 << 22)
+#define BIT23 (1 << 23)
+#define BIT24 (1 << 24)
+#define BIT25 (1 << 25)
+#define BIT26 (1 << 26)
+#define BIT27 (1 << 27)
+#define BIT28 (1 << 28)
+#define BIT29 (1 << 29)
+#define BIT30 (1 << 30)
+#define BIT31 (1 << 31)
+
+// Macros to reduce typing later on
+#define  REGISTER_32(ADDRESS) (*((volatile unsigned int *)(ADDRESS)))
+#define  REGISTER_16(ADDRESS) (*((volatile unsigned int *)(ADDRESS)))
+// Macros to enable/disable global interrupts
+#define enable_interrupts() asm(" cpsie i ")
+#define disable_interrupts() asm(" cpsid i ")
+
+// APB Peripherals
+#define I2C_BASE        0x40000000
+#define WDT_BASE        0x40004000
+#define UART_BASE       0x40008000
+#define TMR16B0_BASE    0x4000c000
+#define TMR16B1_BASE    0x40010000
+#define TMR32B0_BASE    0x40014000
+#define TMR32B1_BASE    0x40018000
+#define ADC_BASE        0x4001c000
+#define PMU_BASE        0x40038000
+#define FLASH_CTRL_BASE 0x4003c000
+#define SSP0_BASE       0x40040000
+#define IOCONFIG_BASE   0x40044000
+#define SYSCON_BASE     0x40048000
+#define C_CAN_BASE      0x40050000
+#define SSP1_BASE       0x40058000
+
+// I2C
+#define I2C0CONSET      REGISTER_32(I2C_BASE + 0x000)
+#define I2C0STAT        REGISTER_32(I2C_BASE + 0x004)
+#define I2C0DAT         REGISTER_32(I2C_BASE + 0x008)
+#define I2C0ADR0        REGISTER_32(I2C_BASE + 0x00c)
+#define I2C0SCLH        REGISTER_32(I2C_BASE + 0x010)
+#define I2C0SCLL        REGISTER_32(I2C_BASE + 0x014)
+#define I2C0CONCLR      REGISTER_32(I2C_BASE + 0x018)
+#define I2C0COMMCTRL    REGISTER_32(I2C_BASE + 0x01c)
+#define I2C0ADR1        REGISTER_32(I2C_BASE + 0x020)
+#define I2C0ADR2        REGISTER_32(I2C_BASE + 0x024)
+#define I2C0ADR3        REGISTER_32(I2C_BASE + 0x028)
+#define I2C0DATA_BUFFER REGISTER_32(I2C_BASE + 0x02c)
+#define I2C0MASK0       REGISTER_32(I2C_BASE + 0x030)
+#define I2C0MASK1       REGISTER_32(I2C_BASE + 0x034)
+#define I2C0MASK2       REGISTER_32(I2C_BASE + 0x038)
+#define I2C0MASK3       REGISTER_32(I2C_BASE + 0x03c)
+// WDT
+#define WDMOD           REGISTER_32(WDT_BASE + 0x000)
+#define WDTC            REGISTER_32(WDT_BASE + 0x004)
+#define WDFEED          REGISTER_32(WDT_BASE + 0x008)
+#define WDTV            REGISTER_32(WDT_BASE + 0x00c)
+#define WDWARNINT       REGISTER_32(WDT_BASE + 0x014)
+#define WDWINDOW        REGISTER_32(WDT_BASE + 0x018)
+
+// UART
+// registers appear to share addresses here.  Depending 
+// on the state of DLAB different registers are active.
+// Also some registers are read-only, some write-only
+#define U0RBR           REGISTER_32(UART_BASE + 0x000) 
+#define U0THR           REGISTER_32(UART_BASE + 0x000)
+#define U0DLL           REGISTER_32(UART_BASE + 0x000)
+#define U0DLM           REGISTER_32(UART_BASE + 0x004)
+#define U0IER           REGISTER_32(UART_BASE + 0x004)
+#define U0IIR           REGISTER_32(UART_BASE + 0x008)
+#define U0FCR           REGISTER_32(UART_BASE + 0x008)
+#define U0LCR           REGISTER_32(UART_BASE + 0x00c)
+#define U0MCR           REGISTER_32(UART_BASE + 0x010)
+#define U0LSR           REGISTER_32(UART_BASE + 0x014)
+#define U0MSR           REGISTER_32(UART_BASE + 0x018)
+#define U0SCR           REGISTER_32(UART_BASE + 0x01c)
+#define U0ACR           REGISTER_32(UART_BASE + 0x020)
+#define U0FDR           REGISTER_32(UART_BASE + 0x028)
+#define U0TER           REGISTER_32(UART_BASE + 0x030)
+#define U0RS485CTRL     REGISTER_32(UART_BASE + 0x04c)
+#define U0RS485ADRMATCH     REGISTER_32(UART_BASE + 0x050)
+#define U0RS485DLY      REGISTER_32(UART_BASE + 0x054)
+
+
+
+// TMR16B0
+#define TMR16B0IR       REGISTER_32(TMR16B0_BASE + 0x000)
+#define TMR16B0TCR      REGISTER_32(TMR16B0_BASE + 0x004)
+#define TMR16B0TC       REGISTER_32(TMR16B0_BASE + 0x008)
+#define TMR16B0PR       REGISTER_32(TMR16B0_BASE + 0x00c)
+#define TMR16B0PC       REGISTER_32(TMR16B0_BASE + 0x010)
+#define TMR16B0MCR      REGISTER_32(TMR16B0_BASE + 0x014)
+#define TMR16B0MR0      REGISTER_32(TMR16B0_BASE + 0x018)
+#define TMR16B0MR1      REGISTER_32(TMR16B0_BASE + 0x01c)
+#define TMR16B0MR2      REGISTER_32(TMR16B0_BASE + 0x020)
+#define TMR16B0MR3      REGISTER_32(TMR16B0_BASE + 0x024)
+#define TMR16B0CCR      REGISTER_32(TMR16B0_BASE + 0x028)
+#define TMR16B0CR0      REGISTER_32(TMR16B0_BASE + 0x02c)
+#define TMR16B0CR1      REGISTER_32(TMR16B0_BASE + 0x030)
+#define TMR16B0EMR      REGISTER_32(TMR16B0_BASE + 0x03c)
+#define TMR16B0CTCR     REGISTER_32(TMR16B0_BASE + 0x070)
+#define TMR16B0PWMC     REGISTER_32(TMR16B0_BASE + 0x074)
+// TMR16B1
+#define TMR16B1IR       REGISTER_32(TMR16B1_BASE + 0x000)
+#define TMR16B1TCR      REGISTER_32(TMR16B1_BASE + 0x004)
+#define TMR16B1TC       REGISTER_32(TMR16B1_BASE + 0x008)
+#define TMR16B1PR       REGISTER_32(TMR16B1_BASE + 0x00c)
+#define TMR16B1PC       REGISTER_32(TMR16B1_BASE + 0x010)
+#define TMR16B1MCR      REGISTER_32(TMR16B1_BASE + 0x014)
+#define TMR16B1MR0      REGISTER_32(TMR16B1_BASE + 0x018)
+#define TMR16B1MR1      REGISTER_32(TMR16B1_BASE + 0x01c)
+#define TMR16B1MR2      REGISTER_32(TMR16B1_BASE + 0x020)
+#define TMR16B1MR3      REGISTER_32(TMR16B1_BASE + 0x024)
+#define TMR16B1CCR      REGISTER_32(TMR16B1_BASE + 0x028)
+#define TMR16B1CR0      REGISTER_32(TMR16B1_BASE + 0x02c)
+#define TMR16B1CR1      REGISTER_32(TMR16B1_BASE + 0x030)
+#define TMR16B1EMR      REGISTER_32(TMR16B1_BASE + 0x03c)
+#define TMR16B1CTCR     REGISTER_32(TMR16B1_BASE + 0x070)
+#define TMR16B1PWMC     REGISTER_32(TMR16B1_BASE + 0x074)
+
+
+
+// TMR32B0
+#define TMR32B0IR       REGISTER_32(TMR32B0_BASE + 0x000)
+#define TMR32B0TCR      REGISTER_32(TMR32B0_BASE + 0x004)
+#define TMR32B0TC       REGISTER_32(TMR32B0_BASE + 0x008)
+#define TMR32B0PR       REGISTER_32(TMR32B0_BASE + 0x00c)
+#define TMR32B0PC       REGISTER_32(TMR32B0_BASE + 0x010)
+#define TMR32B0MCR      REGISTER_32(TMR32B0_BASE + 0x014)
+#define TMR32B0MR0      REGISTER_32(TMR32B0_BASE + 0x018)
+#define TMR32B0MR1      REGISTER_32(TMR32B0_BASE + 0x01c)
+#define TMR32B0MR2      REGISTER_32(TMR32B0_BASE + 0x020)
+#define TMR32B0MR3      REGISTER_32(TMR32B0_BASE + 0x024)
+#define TMR32B0CCR      REGISTER_32(TMR32B0_BASE + 0x028)
+#define TMR32B0CR0      REGISTER_32(TMR32B0_BASE + 0x02c)
+#define TMR32B0CR1      REGISTER_32(TMR32B0_BASE + 0x030)
+#define TMR32B0EMR      REGISTER_32(TMR32B0_BASE + 0x03c)
+#define TMR32B0CTCR     REGISTER_32(TMR32B0_BASE + 0x070)
+#define TMR32B0PWMC     REGISTER_32(TMR32B0_BASE + 0x074)
+// TMR32B1
+#define TMR32B1IR       REGISTER_32(TMR32B1_BASE + 0x000)
+#define TMR32B1TCR      REGISTER_32(TMR32B1_BASE + 0x004)
+#define TMR32B1TC       REGISTER_32(TMR32B1_BASE + 0x008)
+#define TMR32B1PR       REGISTER_32(TMR32B1_BASE + 0x00c)
+#define TMR32B1PC       REGISTER_32(TMR32B1_BASE + 0x010)
+#define TMR32B1MCR      REGISTER_32(TMR32B1_BASE + 0x014)
+#define TMR32B1MR0      REGISTER_32(TMR32B1_BASE + 0x018)
+#define TMR32B1MR1      REGISTER_32(TMR32B1_BASE + 0x01c)
+#define TMR32B1MR2      REGISTER_32(TMR32B1_BASE + 0x020)
+#define TMR32B1MR3      REGISTER_32(TMR32B1_BASE + 0x024)
+#define TMR32B1CCR      REGISTER_32(TMR32B1_BASE + 0x028)
+#define TMR32B1CR0      REGISTER_32(TMR32B1_BASE + 0x02c)
+#define TMR32B1CR1      REGISTER_32(TMR32B1_BASE + 0x030)
+#define TMR32B1EMR      REGISTER_32(TMR32B1_BASE + 0x03c)
+#define TMR32B1CTCR     REGISTER_32(TMR32B1_BASE + 0x070)
+#define TMR32B1PWMC     REGISTER_32(TMR32B1_BASE + 0x074)
+
+
+
+// ADC 
+#define AD0CR       REGISTER_32(ADC_BASE + 0x000)
+#define AD0GDR      REGISTER_32(ADC_BASE + 0x004)
+#define AD0INTEN    REGISTER_32(ADC_BASE + 0x00c)
+#define AD0DR0      REGISTER_32(ADC_BASE + 0x010)
+#define AD0DR1      REGISTER_32(ADC_BASE + 0x014)
+#define AD0DR2      REGISTER_32(ADC_BASE + 0x018)
+#define AD0DR3      REGISTER_32(ADC_BASE + 0x01c)
+#define AD0DR4      REGISTER_32(ADC_BASE + 0x020)
+#define AD0DR5      REGISTER_32(ADC_BASE + 0x024)
+#define AD0DR6      REGISTER_32(ADC_BASE + 0x028)
+#define AD0DR7      REGISTER_32(ADC_BASE + 0x02c)
+#define AD0STAT     REGISTER_32(ADC_BASE + 0x030)
+
+// PMU
+#define PCON        REGISTER_32(PMU_BASE + 0x000)
+#define GPREG0      REGISTER_32(PMU_BASE + 0x004)
+#define GPREG1      REGISTER_32(PMU_BASE + 0x008)
+#define GPREG2      REGISTER_32(PMU_BASE + 0x00c)
+#define GPREG3      REGISTER_32(PMU_BASE + 0x010)
+#define GPREG4      REGISTER_32(PMU_BASE + 0x014)
+
+// FLASH CONTROLLER
+#define FLASHCFG    REGISTER_32(FLASH_CTRL_BASE + 0x010)
+#define FMSSTART    REGISTER_32(FLASH_CTRL_BASE + 0x020)
+#define FMSSTOP     REGISTER_32(FLASH_CTRL_BASE + 0x024)
+#define FMSW0       REGISTER_32(FLASH_CTRL_BASE + 0x02c)
+#define FMSW1       REGISTER_32(FLASH_CTRL_BASE + 0x030)
+#define FMSW2       REGISTER_32(FLASH_CTRL_BASE + 0x034)
+#define FMSW3       REGISTER_32(FLASH_CTRL_BASE + 0x038)
+#define FMSTAT      REGISTER_32(FLASH_CTRL_BASE + 0xfe0)
+#define FMSTATCLR   REGISTER_32(FLASH_CTRL_BASE + 0xfe8)
+// IOCONFIG
+#define IOCON_PIO2_6        REGISTER_32(IOCONFIG_BASE + 0x000)
+#define IOCON_PIO2_0        REGISTER_32(IOCONFIG_BASE + 0x008)
+#define IOCON_RESET_PIO0_0  REGISTER_32(IOCONFIG_BASE + 0x00c)
+#define IOCON_PIO0_1        REGISTER_32(IOCONFIG_BASE + 0x010)
+#define IOCON_PIO1_8        REGISTER_32(IOCONFIG_BASE + 0x014)
+#define IOCON_SSEL1_LOC     REGISTER_32(IOCONFIG_BASE + 0x018)
+#define IOCON_PIO0_2        REGISTER_32(IOCONFIG_BASE + 0x01c)
+#define IOCON_PIO2_7        REGISTER_32(IOCONFIG_BASE + 0x020)
+#define IOCON_PIO2_8        REGISTER_32(IOCONFIG_BASE + 0x024)
+#define IOCON_PIO2_1        REGISTER_32(IOCONFIG_BASE + 0x028)
+#define IOCON_PIO0_3        REGISTER_32(IOCONFIG_BASE + 0x02c)
+#define IOCON_PIO0_4        REGISTER_32(IOCONFIG_BASE + 0x030)
+#define IOCON_PIO0_5        REGISTER_32(IOCONFIG_BASE + 0x034)
+#define IOCON_PIO1_9        REGISTER_32(IOCONFIG_BASE + 0x038)
+#define IOCON_PIO3_4        REGISTER_32(IOCONFIG_BASE + 0x03c)
+#define IOCON_PIO2_4        REGISTER_32(IOCONFIG_BASE + 0x040)
+#define IOCON_PIO2_5        REGISTER_32(IOCONFIG_BASE + 0x044)
+#define IOCON_PIO3_5        REGISTER_32(IOCONFIG_BASE + 0x048)
+#define IOCON_PIO0_6        REGISTER_32(IOCONFIG_BASE + 0x04c)
+#define IOCON_PIO0_7        REGISTER_32(IOCONFIG_BASE + 0x050)
+#define IOCON_PIO2_9        REGISTER_32(IOCONFIG_BASE + 0x054)
+#define IOCON_PIO2_10       REGISTER_32(IOCONFIG_BASE + 0x058)
+#define IOCON_PIO2_2        REGISTER_32(IOCONFIG_BASE + 0x05c)
+#define IOCON_PIO0_8        REGISTER_32(IOCONFIG_BASE + 0x060)
+#define IOCON_PIO0_9        REGISTER_32(IOCONFIG_BASE + 0x064)
+#define IOCON_PIO0_18       REGISTER_32(IOCONFIG_BASE + 0x048)
+#define IOCON_SWCLK_PIO0_10 REGISTER_32(IOCONFIG_BASE + 0x068)
+#define IOCON_PIO1_10       REGISTER_32(IOCONFIG_BASE + 0x06c)
+#define IOCON_PIO2_11       REGISTER_32(IOCONFIG_BASE + 0x070)
+#define IOCON_R_PIO0_11     REGISTER_32(IOCONFIG_BASE + 0x074)
+#define IOCON_R_PIO1_0      REGISTER_32(IOCONFIG_BASE + 0x078)
+#define IOCON_R_PIO1_1      REGISTER_32(IOCONFIG_BASE + 0x07c)
+#define IOCON_R_PIO1_2      REGISTER_32(IOCONFIG_BASE + 0x080)
+#define IOCON_PIO3_0        REGISTER_32(IOCONFIG_BASE + 0x084)
+#define IOCON_PIO3_1        REGISTER_32(IOCONFIG_BASE + 0x088)
+#define IOCON_PIO2_3        REGISTER_32(IOCONFIG_BASE + 0x08c)
+#define IOCON_SWDIO_PIO1_3  REGISTER_32(IOCONFIG_BASE + 0x090)
+#define IOCON_PIO1_4        REGISTER_32(IOCONFIG_BASE + 0x094)
+#define IOCON_PIO1_11       REGISTER_32(IOCONFIG_BASE + 0x098)
+#define IOCON_PIO3_2        REGISTER_32(IOCONFIG_BASE + 0x09c)
+#define IOCON_PIO1_5        REGISTER_32(IOCONFIG_BASE + 0x0a0)
+#define IOCON_PIO1_6        REGISTER_32(IOCONFIG_BASE + 0x0a4)
+#define IOCON_PIO1_7        REGISTER_32(IOCONFIG_BASE + 0x0a8)
+#define IOCON_PIO3_3        REGISTER_32(IOCONFIG_BASE + 0x0ac)
+#define IOCON_SCK0_LOC      REGISTER_32(IOCONFIG_BASE + 0x0b0)
+#define IOCON_DSR_LOC       REGISTER_32(IOCONFIG_BASE + 0x0b4)
+#define IOCON_DCD_LOC       REGISTER_32(IOCONFIG_BASE + 0x0b8)
+#define IOCON_RI_LOC        REGISTER_32(IOCONFIG_BASE + 0x0bc)
+#define IOCON_CT16B0_CAP0_LOC       REGISTER_32(IOCONFIG_BASE + 0x0c0)
+#define IOCON_SCK1_LOC      REGISTER_32(IOCONFIG_BASE + 0x0c4)
+#define IOCON_MISO1_LOC     REGISTER_32(IOCONFIG_BASE + 0x0c8)
+#define IOCON_MOSI1_LOC     REGISTER_32(IOCONFIG_BASE + 0x0cc)
+#define IOCON_CT32B0_CAP0_LOC       REGISTER_32(IOCONFIG_BASE + 0x0d0)
+#define IOCON_RXD_LOC       REGISTER_32(IOCONFIG_BASE + 0x0d4)
+
+
+
+
+
+// SYSCON
+#define SYSMEMREMAP     REGISTER_32(SYSCON_BASE + 0x000)
+#define PRESETCTRL      REGISTER_32(SYSCON_BASE + 0x004)
+#define SYSPLLCTRL      REGISTER_32(SYSCON_BASE + 0x008)
+#define SYSPLLSTAT      REGISTER_32(SYSCON_BASE + 0x00c)
+#define SYSOSCCTRL      REGISTER_32(SYSCON_BASE + 0x020)
+#define WDTOSCCTRL      REGISTER_32(SYSCON_BASE + 0x024)
+#define IRCCTL          REGISTER_32(SYSCON_BASE + 0x028)
+#define SYSRSTSTAT      REGISTER_32(SYSCON_BASE + 0x030)
+#define SYSPLLCLKSEL    REGISTER_32(SYSCON_BASE + 0x040)
+#define SYSPLLCLKUEN    REGISTER_32(SYSCON_BASE + 0x044)
+#define MAINCLKSEL      REGISTER_32(SYSCON_BASE + 0x070)
+#define MAINCLKUEN      REGISTER_32(SYSCON_BASE + 0x074)
+#define SYSAHBCLKDIV    REGISTER_32(SYSCON_BASE + 0x078)
+#define SYSAHBCLKCTRL   REGISTER_32(SYSCON_BASE + 0x080)
+#define SSP0CLKDIV      REGISTER_32(SYSCON_BASE + 0x094)
+#define UARTCLKDIV      REGISTER_32(SYSCON_BASE + 0x098)
+#define SSP1CLKDIV      REGISTER_32(SYSCON_BASE + 0x09c)
+#define WDTCLKSEL       REGISTER_32(SYSCON_BASE + 0x0d0)
+#define WDTCLKUEN       REGISTER_32(SYSCON_BASE + 0x0d4)
+#define WDTCLKDIV       REGISTER_32(SYSCON_BASE + 0x0d8)
+#define CLKOUTCLKSEL    REGISTER_32(SYSCON_BASE + 0x0e0)
+#define CLKOUTUEN       REGISTER_32(SYSCON_BASE + 0x0e4)
+#define CLKOUTCLKDIV    REGISTER_32(SYSCON_BASE + 0x0e8)
+#define PIOPORCAP0      REGISTER_32(SYSCON_BASE + 0x100)
+#define PIOPORCAP1      REGISTER_32(SYSCON_BASE + 0x104)
+#define BODCTRL         REGISTER_32(SYSCON_BASE + 0x150)
+#define SYSTCKCAL       REGISTER_32(SYSCON_BASE + 0x154)
+#define NMISRC          REGISTER_32(SYSCON_BASE + 0x174)
+#define STARTAPRP0      REGISTER_32(SYSCON_BASE + 0x200)
+#define STARTERP0       REGISTER_32(SYSCON_BASE + 0x204)
+#define STARTRSRP0CLR   REGISTER_32(SYSCON_BASE + 0x208)
+#define STARTSRP0       REGISTER_32(SYSCON_BASE + 0x20c)
+#define PDSLEEPCFG      REGISTER_32(SYSCON_BASE + 0x230)
+#define PDAWAKECFG      REGISTER_32(SYSCON_BASE + 0x234)
+#define PDRUNCFG        REGISTER_32(SYSCON_BASE + 0x238)
+#define DEVICE_ID       REGISTER_32(SYSCON_BASE + 0x3f4)
+
+
+// CAN
+#define CANCNTL     REGISTER_32(C_CAN_BASE + 0x000)
+#define CANSTAT     REGISTER_32(C_CAN_BASE + 0x004)
+#define CANEC       REGISTER_32(C_CAN_BASE + 0x008)
+#define CANBT       REGISTER_32(C_CAN_BASE + 0x00c)
+#define CANINT      REGISTER_32(C_CAN_BASE + 0x010)
+#define CANTEST     REGISTER_32(C_CAN_BASE + 0x014)
+#define CANBRPE     REGISTER_32(C_CAN_BASE + 0x018)
+#define CANIF1_CMDREQ   REGISTER_32(C_CAN_BASE + 0x020)
+#define CANIF1_CMDMSK_W REGISTER_32(C_CAN_BASE + 0x024)
+#define CANIF1_CMDMSK_R REGISTER_32(C_CAN_BASE + 0x024)
+#define CANIF1_MSK1     REGISTER_32(C_CAN_BASE + 0x028)
+#define CANIF1_MSK2     REGISTER_32(C_CAN_BASE + 0x02c)
+#define CANIF1_ARB1     REGISTER_32(C_CAN_BASE + 0x030)
+#define CANIF1_ARB2     REGISTER_32(C_CAN_BASE + 0x034)
+#define CANIF1_MCTRL    REGISTER_32(C_CAN_BASE + 0x038)
+#define CANIF1_DA1      REGISTER_32(C_CAN_BASE + 0x03c)
+#define CANIF1_DA2      REGISTER_32(C_CAN_BASE + 0x040)
+#define CANIF1_DB1      REGISTER_32(C_CAN_BASE + 0x044)
+#define CANIF1_DB2      REGISTER_32(C_CAN_BASE + 0x048)
+#define CANIF2_CMDREQ   REGISTER_32(C_CAN_BASE + 0x080)
+#define CANIF2_CMDMSK_W REGISTER_32(C_CAN_BASE + 0x084)
+#define CANIF2_CMDMSK_R REGISTER_32(C_CAN_BASE + 0x084)
+#define CANIF2_MSK1     REGISTER_32(C_CAN_BASE + 0x088)
+#define CANIF2_MSK2     REGISTER_32(C_CAN_BASE + 0x08c)
+#define CANIF2_ARB1     REGISTER_32(C_CAN_BASE + 0x090)
+#define CANIF2_ARB2     REGISTER_32(C_CAN_BASE + 0x094)
+#define CANIF2_MCTRL    REGISTER_32(C_CAN_BASE + 0x098)
+#define CANIF2_DA1      REGISTER_32(C_CAN_BASE + 0x09c)
+#define CANIF2_DA2      REGISTER_32(C_CAN_BASE + 0x0a0)
+#define CANIF2_DB1      REGISTER_32(C_CAN_BASE + 0x0a4)
+#define CANIF2_DB2      REGISTER_32(C_CAN_BASE + 0x0a8)
+#define CANTXREQ1       REGISTER_32(C_CAN_BASE + 0x100)
+#define CANTXREQ2       REGISTER_32(C_CAN_BASE + 0x104)
+#define CANND1          REGISTER_32(C_CAN_BASE + 0x120)
+#define CANND2          REGISTER_32(C_CAN_BASE + 0x124)
+#define CANIR1          REGISTER_32(C_CAN_BASE + 0x140)
+#define CANIR2          REGISTER_32(C_CAN_BASE + 0x144)
+#define CANMSGV1        REGISTER_32(C_CAN_BASE + 0x160)
+#define CANNSGV2        REGISTER_32(C_CAN_BASE + 0x164)
+#define CANCLKDIV       REGISTER_32(C_CAN_BASE + 0x180)
+
+
+// SSP0
+#define SSP0CR0     REGISTER_32(SSP0_BASE + 0x000)
+#define SSP0CR1     REGISTER_32(SSP0_BASE + 0x004)
+#define SSP0DR      REGISTER_32(SSP0_BASE + 0x008)
+#define SSP0SR      REGISTER_32(SSP0_BASE + 0x00c)
+#define SSP0CPSR    REGISTER_32(SSP0_BASE + 0x010)
+#define SSP0IMSC    REGISTER_32(SSP0_BASE + 0x014)
+#define SSP0RIS     REGISTER_32(SSP0_BASE + 0x018)
+#define SSP0MIS     REGISTER_32(SSP0_BASE + 0x01c)
+#define SSP0ICR     REGISTER_32(SSP0_BASE + 0x020)
+
+// SSP1
+#define SSP1CR0     REGISTER_32(SSP1_BASE + 0x000)
+#define SSP1CR1     REGISTER_32(SSP1_BASE + 0x004)
+#define SSP1DR      REGISTER_32(SSP1_BASE + 0x008)
+#define SSP1SR      REGISTER_32(SSP1_BASE + 0x00c)
+#define SSP1CPSR    REGISTER_32(SSP1_BASE + 0x010)
+#define SSP1IMSC    REGISTER_32(SSP1_BASE + 0x014)
+#define SSP1RIS     REGISTER_32(SSP1_BASE + 0x018)
+#define SSP1MIS     REGISTER_32(SSP1_BASE + 0x01c)
+#define SSP1ICR     REGISTER_32(SSP1_BASE + 0x020)
+
+// AHB Peripherals
+#define GPIO0_BASE      0x50000000
+#define GPIO1_BASE      0x50010000
+#define GPIO2_BASE      0x50020000
+#define GPIO3_BASE      0x50030000
+
+// not dealing with mask registers here
+#define GPIO0DATA       REGISTER_32(GPIO0_BASE + 0x3ffc)
+#define GPIO0DIR        REGISTER_32(GPIO0_BASE + 0x8000)
+#define GPIO0IS         REGISTER_32(GPIO0_BASE + 0x8004)
+#define GPIO0IBE        REGISTER_32(GPIO0_BASE + 0x8008)
+#define GPIO0IEV        REGISTER_32(GPIO0_BASE + 0x800c)
+#define GPIO0IE         REGISTER_32(GPIO0_BASE + 0x8010)
+#define GPIO0RIS        REGISTER_32(GPIO0_BASE + 0x8014)
+#define GPIO0MIS        REGISTER_32(GPIO0_BASE + 0x8018)
+#define GPIO0IC         REGISTER_32(GPIO0_BASE + 0x801c)
+
+// not dealing with mask registers here
+#define GPIO1DATA       REGISTER_32(GPIO1_BASE + 0x3ffc)
+#define GPIO1DIR        REGISTER_32(GPIO1_BASE + 0x8000)
+#define GPIO1IS         REGISTER_32(GPIO1_BASE + 0x8004)
+#define GPIO1IBE        REGISTER_32(GPIO1_BASE + 0x8008)
+#define GPIO1IEV        REGISTER_32(GPIO1_BASE + 0x800c)
+#define GPIO1IE         REGISTER_32(GPIO1_BASE + 0x8010)
+#define GPIO1RIS        REGISTER_32(GPIO1_BASE + 0x8014)
+#define GPIO1MIS        REGISTER_32(GPIO1_BASE + 0x8018)
+#define GPIO1IC         REGISTER_32(GPIO1_BASE + 0x801c)
+
+// not dealing with mask registers here
+#define GPIO2DATA       REGISTER_32(GPIO2_BASE + 0x3ffc)
+#define GPIO2DIR        REGISTER_32(GPIO2_BASE + 0x8000)
+#define GPIO2IS         REGISTER_32(GPIO2_BASE + 0x8004)
+#define GPIO2IBE        REGISTER_32(GPIO2_BASE + 0x8008)
+#define GPIO2IEV        REGISTER_32(GPIO2_BASE + 0x800c)
+#define GPIO2IE         REGISTER_32(GPIO2_BASE + 0x8010)
+#define GPIO2RIS        REGISTER_32(GPIO2_BASE + 0x8014)
+#define GPIO2MIS        REGISTER_32(GPIO2_BASE + 0x8018)
+#define GPIO2IC         REGISTER_32(GPIO2_BASE + 0x801c)
+
+// Core peripherals
+#define STK_BASE    0xe000e010
+#define SCB_BASE    0xe000ed00
+#define NVIC_BASE   0xe000e100
+// Seems base addresses are split for some core peripherals
+#define SCB_BASE2   0xe000e008
+#define NVIC_BASE2  0xe000ef00 
+
+// NVIC
+#define ISER        REGISTER_32(NVIC_BASE + 0)
+#define ICER        REGISTER_32(NVIC_BASE + 0x80)
+#define ISPR        REGISTER_32(NVIC_BASE + 0x100)
+#define ICPR        REGISTER_32(NVIC_BASE + 0x180)
+#define IPR0        REGISTER_32(NVIC_BASE + 0x300)
+#define IPR1        REGISTER_32(NVIC_BASE + 0x304)
+#define IPR2        REGISTER_32(NVIC_BASE + 0x308)
+#define IPR3        REGISTER_32(NVIC_BASE + 0x30c)
+#define IPR4        REGISTER_32(NVIC_BASE + 0x310)
+#define IPR5        REGISTER_32(NVIC_BASE + 0x314)
+#define IPR6        REGISTER_32(NVIC_BASE + 0x318)
+#define IPR7        REGISTER_32(NVIC_BASE + 0x31c)
+
+// STK
+#define SYST_CSR    REGISTER_32(STK_BASE + 0)
+#define SYST_RVR    REGISTER_32(STK_BASE + 4)
+#define SYST_CVR    REGISTER_32(STK_BASE + 8)
+#define SYST_CALIB  REGISTER_32(STK_BASE + 0x0c)
+
+// SCB_BASE
+#define CPUID       REGISTER_32(SCB_BASE + 0)
+#define ICSR        REGISTER_32(SCB_BASE + 4)
+#define AIRCR       REGISTER_32(SCB_BASE + 0x0c)
+#define SCR         REGISTER_32(SCB_BASE + 0x10)
+#define CCR         REGISTER_32(SCB_BASE + 0x14)
+#define SHPR2       REGISTER_32(SCB_BASE + 0x1c)
+#define SHPR3       REGISTER_32(SCB_BASE + 0x20)
diff -r 000000000000 -r c79e1f29f029 Sound/sound.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Sound/sound.cpp	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,727 @@
+#include <string.h>
+#include "sound.h"
+#include "lpc111x.h"
+
+// Useful Macros
+#define ISNUMBER(a) ((a >= '0') && (a <= '9'))
+#define ISALPHA(a) (((a >= 'a') && (a <= 'z')) || ((a >= 'A') && (a <= 'Z')))
+#define TOLOWER(a) if ((a >= 'A') && (a <= 'Z')) a = (a - 'A') + 'a';
+
+//  ======== Waveform Definitions ========
+// 64 elements
+const char sine[] = {
+    0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,
+    0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8,
+    0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5,
+    0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,
+    0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc,
+    0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3,
+    0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83,
+    0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51,
+    0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27,
+    0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a,
+    0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08,
+    0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23,
+    0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c,
+    0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c};
+    
+const char square[] =  {
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
+
+const char sawtooth[] = {
+    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+    0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+    0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+    0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+    0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+    0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+    0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+    0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+    0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+    0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff};
+
+const char triangle[] = {
+    0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,
+    0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,
+    0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,
+    0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,
+    0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e,
+    0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe,
+    0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce,0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde,
+    0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee,0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe,
+    0xff,0xfd,0xfb,0xf9,0xf7,0xf5,0xf3,0xf1,0xef,0xef,0xeb,0xe9,0xe7,0xe5,0xe3,0xe1,
+    0xdf,0xdd,0xdb,0xd9,0xd7,0xd5,0xd3,0xd1,0xcf,0xcf,0xcb,0xc9,0xc7,0xc5,0xc3,0xc1,
+    0xbf,0xbd,0xbb,0xb9,0xb7,0xb5,0xb3,0xb1,0xaf,0xaf,0xab,0xa9,0xa7,0xa5,0xa3,0xa1,
+    0x9f,0x9d,0x9b,0x99,0x97,0x95,0x93,0x91,0x8f,0x8f,0x8b,0x89,0x87,0x85,0x83,0x81,
+    0x7f,0x7d,0x7b,0x79,0x77,0x75,0x73,0x71,0x6f,0x6f,0x6b,0x69,0x67,0x65,0x63,0x61,
+    0x5f,0x5d,0x5b,0x59,0x57,0x55,0x53,0x51,0x4f,0x4f,0x4b,0x49,0x47,0x45,0x43,0x41,
+    0x3f,0x3d,0x3b,0x39,0x37,0x35,0x33,0x31,0x2f,0x2f,0x2b,0x29,0x27,0x25,0x23,0x21,
+    0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x11,0x0f,0x0f,0x0b,0x09,0x07,0x05,0x03,0x01};
+
+
+// For vibrato - 64 elements in length - thanks lft
+const int8_t sinetable[] = {
+    0, 12, 25, 37, 49, 60, 71, 81, 90, 98, 106, 112, 117, 122, 125, 126,
+    127, 126, 125, 122, 117, 112, 106, 98, 90, 81, 71, 60, 49, 37, 25, 12,
+    0, -12, -25, -37, -49, -60, -71, -81, -90, -98, -106, -112, -117, -122,
+    -125, -126, -127, -126, -125, -122, -117, -112, -106, -98, -90, -81,
+    -71, -60, -49, -37, -25, -12
+};
+
+// -=-=-=-=-=-=-= End Waveforms -=-=-=-=-=-=-=-=-=
+
+#define PWM_FREQUENCY       23448       // 23.448 kHz => Match value of ~2047 (Convenient for binary math)
+#define PWM_MATCH_VAL       (48000000 / PWM_FREQUENCY)
+#define EFFECT_CALL_FREQ    50          // Hz
+#define EFFECT_CALL_WAIT    PWM_FREQUENCY / EFFECT_CALL_FREQ
+#define MAX_FREQ            8000                                      // 8 kHz (something pratical.. and not ear splitting)
+#define MAX_FREQ_INC        ((65535 * MAX_FREQ) / PWM_FREQUENCY)
+#define SLIDE_SCALER        ((65535 * 10) / PWM_FREQUENCY)            // 10 Hz per tick...
+
+// Volatile Interrupt Variables
+volatile int timer32_0_counter;
+Sound *pSound = NULL;
+volatile unsigned short int effect_wait = EFFECT_CALL_WAIT;
+
+// Interrupt ---------------------------------------
+
+void TIMER32_0_IRQHandler(void)
+{    
+    // Check to see if the PWM interrupt is triggered (MR3)
+    if (TMR32B0IR & BIT3)
+    {
+        if (!pSound) return;
+        
+        effect_wait--;
+        if (effect_wait == 0)
+        {
+            // Do the effects at 50 Hz ... why because everyone does it that way
+            pSound->DoEffects();
+            effect_wait = EFFECT_CALL_WAIT;
+            // Do the song at 50 Hz
+            pSound->DoSong();
+        }
+        
+        static unsigned int noiseseed = 1;
+        unsigned char newbit;
+        
+        newbit = 0;
+        if(noiseseed & 0x80000000L) newbit ^= 1;
+        if(noiseseed & 0x01000000L) newbit ^= 1;
+        if(noiseseed & 0x00000040L) newbit ^= 1;
+        if(noiseseed & 0x00000200L) newbit ^= 1;
+        noiseseed = (noiseseed << 1) | newbit;
+        
+        // Reset the interrupt flag
+        TMR32B0IR = BIT3;
+        
+        // Increment the counter
+        timer32_0_counter++;
+        
+        register int master_acc = 0;
+        register int acc = 0;
+        register int channels = 0;
+        bool bMuted = pSound->bMuted;
+        
+        for (int i = 0; i < SOUND_MAX_CHANNELS; i++)
+        {
+            SOUND_CHANNEL *pChannel = &pSound->channel[i];
+            if ((pChannel->active) && (pChannel->volume > 0))
+            {
+                pChannel->phase_acc += pChannel->phase_inc;
+                acc = pChannel->pWaveform[pChannel->phase_acc >> 8];    // -128 to 127
+                if (pChannel->use_noise) acc = (noiseseed & 0xFF) - 127;// -128 to 127
+                acc *= pChannel->volume;                                // 0 to 65535
+                acc = acc >> 8;                                         // Rescale to -128 to 127
+                acc += 128;                                             // 0 to 255
+                master_acc += acc;
+                channels++;
+            }
+        }
+        
+        if (channels > 1) master_acc /= channels;
+        master_acc = master_acc << 3;                               // 0 to 2047 (PWM_MATCH_VAL)
+        //master_acc = acc << 3;
+        if (master_acc > PWM_MATCH_VAL) master_acc = PWM_MATCH_VAL;
+        
+        // Check to see if we are muted
+        if (bMuted) master_acc = 0;
+        
+        // Bounds check the master accumulator
+        TMR32B0MR0 = master_acc;  // ( xx >> 8 equivalent to x / 256)
+    }
+    
+    return;
+}
+
+// Implementation ----------------------------------
+
+Sound::Sound()
+{
+    timer32_0_counter = 0;
+    pSound = this;
+    for (int i = 0; i < SOUND_MAX_CHANNELS; i++)
+        channel[i].active = false;
+    // Initialize the song stuff
+    bPlaySong = false;
+    bLoopSong = false;
+    m_pSong = NULL;
+    m_pSongBuffer = NULL;
+    iSongChannel = 0;
+    iSongNoteOffset = 0;
+    iNoteCounter = 0;
+    iTicksPerBeat = 0;
+    bMuted = false;
+}
+    
+Sound::~Sound()
+{
+}
+
+void Sound::Init()
+{
+    SetupDefaults();
+    
+    // DISABLE the TImer
+    TMR32B0TCR = 0;
+    
+    // DEBUG - do not enable the output pin so we do not make so much noise!!!
+    // Initialize the PWM Match Output
+    // Configure IO control register IOCON_PIO0_18 offset 0x40044048 with CT32B0_MAT0 bit set (0x02)
+    REGISTER_32(0x40044048) = BIT1 | BIT4;
+    
+    // Configure the interrupt
+    NVIC_SetVector(TIMER_32_0_IRQn, (uint32_t)TIMER32_0_IRQHandler);
+    NVIC_SetPriority(TIMER_32_1_IRQn,0);
+    NVIC_EnableIRQ(TIMER_32_0_IRQn);
+    
+    // CT32B0 base address 0x40014000
+    // Turn ON CT32B0 => System Clock Control Register => SYSAHBCLKCTRL Bit 9
+    SYSAHBCLKCTRL |= BIT9;
+    // Set our frequency (counter value) in Match Register 0 (as it does not map directly to a pin) => Match Register 0 MR0
+    TMR32B0MR3 = PWM_MATCH_VAL;        // PWM Frequency
+    TMR32B0MR0 = 0;        // 0% Duty for now (OFF)
+    // Configure Reset TC on Match with MR0 MR0R (Bit 1) MR0I (Bit 0) => Match Control Register MCR
+    // Reset on Match Register 3 MR3 (as this is the register we use for the base frequency ... MR0 is used to set the duty cycle)
+    TMR32B0MCR = BIT10 | BIT9;
+    // PWM Control Register
+    TMR32B0PWMC = BIT0;
+    // Zero the counter 0 => Timer Counter Register TC
+    TMR32B0TC = 0;
+    // Set the PreScale Register
+    TMR32B0PR = 0;
+    // Clear the Prescale Counter
+    TMR32B0PC = 0;
+    // Enable the timer => Timer Control Register CR
+    TMR32B0TCR = BIT0;
+    
+    __enable_irq();     // Enable Interrupts
+}
+
+void Sound::PlaySound(int iChannel, int iFreqHz, int iLength)
+{
+    // Check the channel
+    if (iChannel < 0) return;
+    if (iChannel >= SOUND_MAX_CHANNELS) return;
+    
+    if (iFreqHz == 0)
+    {
+        StopSound(iChannel);
+        return;
+    }
+    
+    // Get a pointer to the sound channel structure
+    SOUND_CHANNEL *pChannel = &channel[iChannel];
+    
+    // Calculate a phase increment value
+    int inc = (65535 * iFreqHz) / PWM_FREQUENCY;
+    pChannel->phase_inc = (unsigned short)inc;
+    pChannel->orig_phase_inc = (unsigned short)inc;
+    // Clear the phase accumulator
+    pChannel->phase_acc = 0;
+    
+    // Set the play length (0 to 255, 0 = INFINITE, 1 to 255 delay in 50 Hz ticks)
+    pChannel->play_length = iLength;
+    
+    // Reset the volume level to its initial setting
+    pChannel->volume = pChannel->vol_level;
+    
+    // Reset the change wait to the change speed
+    pChannel->change_wait = pChannel->change_speed;
+    
+    // Set the active flag last
+    pChannel->active = true;
+}
+
+void Sound::StopSound(int iChannel)
+{
+    // Check the channel
+    if (iChannel < 0) return;
+    if (iChannel >= SOUND_MAX_CHANNELS) return;
+    
+    // Clear the active flag
+    channel[iChannel].active = false;
+}
+
+bool Sound::IsBusy(int iChannel)
+{
+    // Check the channel
+    if (iChannel < 0) return false;
+    if (iChannel >= SOUND_MAX_CHANNELS) return false;
+    
+    return (channel[iChannel].active && (channel[iChannel].volume > 0));
+}
+
+int Sound::GetCounter(void)
+{
+    return timer32_0_counter;
+}
+
+void Sound::SetInstrument(int iChannel, int iWaveform, int iVolume, int iDecayTime, int iSlide, int iChangeAmount, int iChangeSpeed, int iRepeatSpeed, int iVibratoDepth, int iVibratoSpeed)
+{
+    // Bounds check the channel
+    if (iChannel < 0) return;
+    if (iChannel >= SOUND_MAX_CHANNELS) return;
+    
+    // Set the waveform
+    channel[iChannel].use_noise = false;
+    switch (iWaveform)
+    {
+    default:
+    case (SOUND_SQUARE):
+        channel[iChannel].pWaveform = (unsigned char *)square;
+        break;
+    case (SOUND_SAW):
+        channel[iChannel].pWaveform = (unsigned char *)sawtooth;
+        break;
+    case (SOUND_TRIANGLE):
+        channel[iChannel].pWaveform = (unsigned char *)triangle;
+        break;
+    case (SOUND_SINE):
+        channel[iChannel].pWaveform = (unsigned char *)sine;
+        break;
+    case (SOUND_NOISE):
+        channel[iChannel].pWaveform = (unsigned char *)square;
+        channel[iChannel].use_noise = true;
+        break;
+    }
+    
+    // Set the volume level
+    channel[iChannel].vol_level = iVolume;
+    channel[iChannel].volume = iVolume;
+    
+    // Set the Decay time
+    channel[iChannel].decay_amount = iDecayTime;
+    
+    // Set the Slide value
+    channel[iChannel].slide = iSlide;
+    
+    // Set the Change Amount and Change Speed
+    int inc = (65535 * iChangeAmount / PWM_FREQUENCY);
+    channel[iChannel].change_inc = (signed short)inc; // frequency amount in phase increments
+    channel[iChannel].change_speed = iChangeSpeed;                                          // change delay in 50 hz ticks
+    channel[iChannel].change_wait = iChangeSpeed;
+    
+    // Set the repeat speed
+    channel[iChannel].repeat_speed = iRepeatSpeed;  // effect repeat speed in 50 hz ticks (really a delay)
+    channel[iChannel].repeat_wait = iRepeatSpeed;
+    
+    // Set the vibrato parameters
+    channel[iChannel].vibrato_depth = iVibratoDepth;                // Vibrato amplitude
+    channel[iChannel].vibrato_speed = iVibratoSpeed;                // Vibrato speed in 50 Hz ticks (delay)
+    channel[iChannel].vibrato_phase = 0;
+    channel[iChannel].vibrato_inc = 0;
+}
+    
+// Setup the default instruments and stuff
+void Sound::SetupDefaults(void)
+{
+    for (int i = 0; i < SOUND_MAX_CHANNELS; i++)
+    {
+        // Set the default instrument parameters
+        SetInstrument(i, SOUND_SQUARE, 255, 0, 0, 0, 0, 0, 0, 0);
+    }
+}
+
+void Sound::DoEffects(void)
+{
+    for (int i = 0; i < SOUND_MAX_CHANNELS; i++)
+    {
+    
+        if (!channel[i].active) continue;
+        
+        // Set the play length (0 to 255, 0 = INFINITE, 1 to 255 delay in 50 Hz ticks)
+        if (channel[i].play_length > 0)
+        {
+            // Subtract 1 tick
+            channel[i].play_length--;
+            // If we get to 0 set the channel to inactive
+            if (channel[i].play_length == 0) channel[i].active = false;
+        }
+    
+        // Volume Related Effects
+        if (channel[i].volume > 0)
+        {
+            short int vol = channel[i].volume;
+            // Decay
+            if (channel[i].decay_amount)
+            {
+                if (channel[i].decay_amount < vol)
+                    vol -= channel[i].decay_amount;
+                else
+                    vol = 0;
+            }
+            // Set the adjusted volume level
+            channel[i].volume = vol;
+        }
+        // If the volume is 0 then who cares?
+        // Do not turn the channel off as Repeat will not work?
+        /*
+        if (channel[i].volume == 0)
+        {
+            // Turn this channel off for now
+            channel[i].active = false;
+        }
+        */
+        
+        // Slide (Frequency Shifting) Effects
+        if (channel[i].slide != 0)
+        {
+            int inc = (int)channel[i].phase_inc + ((int)channel[i].slide * SLIDE_SCALER);
+            if ((inc > 0) && (inc < MAX_FREQ_INC))
+                channel[i].phase_inc = inc;
+            else
+                //channel[i].active = false;
+                channel[i].volume = 0;
+        }
+        
+        // Change (Frequency Change after Delay)
+        if (channel[i].change_wait > 0)
+        {
+            channel[i].change_wait--;
+            if (channel[i].change_wait == 0)
+                channel[i].phase_inc += channel[i].change_inc;
+        }
+        
+        // Vibrato
+        if (channel[i].vibrato_speed > 0)
+        {
+            // Calculate the vibrato waveform's phase
+            channel[i].vibrato_phase += (channel[i].vibrato_speed * SLIDE_SCALER);
+            // Calculate the sinewave values
+            int inc = sinetable[channel[i].vibrato_phase & 63] * channel[i].vibrato_depth;
+            // Rescale (from 65535 to 255)
+            inc = inc >> 8;
+            
+            inc = inc + (int)channel[i].phase_inc;
+            channel[i].phase_inc = inc;
+        }
+        
+        // Repeat (resets parameters after a certain mount of time ... pew pew pew)
+        if (channel[i].repeat_speed > 0)
+        {
+            channel[i].repeat_wait--;
+            if (channel[i].repeat_wait == 0)
+            {
+                // Reset the repeat wait (so we can do this again!
+                channel[i].repeat_wait = channel[i].repeat_speed;
+                // Reset the frequency and amplitude to the original
+                channel[i].phase_inc = channel[i].orig_phase_inc;
+                // Reset the volume (amplitude) to the original
+                channel[i].volume = channel[i].vol_level;
+            }
+        }
+    }
+}
+
+void Sound::PlaySong(char *pRTTTL, int iChannel, int iBPM, bool bLoop)
+{
+    // Check the RTTTL pointer
+    if (!pRTTTL) return;
+    
+    // Stop the song temporarily
+    bPlaySong = false;
+    
+    // Setup the song variables
+    iSongChannel = iChannel;
+    SetSongTempo(iBPM);
+    bLoopSong = bLoop;
+    iNoteCounter = 0;
+    
+    // Get the length of this song (in characters)
+    int iNewLen = strlen(pRTTTL);
+    
+    // Copy and allocate the song buffer
+    
+    // Deal with the song buffer if it has already allocated memory
+    if (m_pSongBuffer)
+    {
+        // Check to see if we need to allocate more memory
+        if (iSongBufferLen < iNewLen)
+        {
+            // Cleanup the old and allocate a new buffer
+            delete [] m_pSongBuffer;
+            m_pSongBuffer = NULL;
+        }
+    }
+    // Allocate a new song buffer if we need to
+    if (!m_pSongBuffer)
+    {
+        m_pSongBuffer = new char[iNewLen + 1];
+    }
+    // Copy the song into the song buffer
+    memcpy(m_pSongBuffer, pRTTTL, iNewLen);
+    // Add an extra NULL terminator just incase
+    m_pSongBuffer[iNewLen] = 0;
+    
+    // Set the song pointer to the beginning
+    m_pSong = m_pSongBuffer;
+    
+    // Start the song
+    bPlaySong = true;
+}
+
+#define TICKSPERMINUTE  (60 * 50)
+
+void Sound::SetSongTempo(int iBPM)
+{
+    // Setup the note wait time in 50Hz ticks
+    iTicksPerBeat = TICKSPERMINUTE / iBPM;
+    if (iTicksPerBeat < 1) iTicksPerBeat = 1;
+    if (iTicksPerBeat > TICKSPERMINUTE) iTicksPerBeat = TICKSPERMINUTE;
+}
+
+void Sound::TransposeSong(int iOffset)
+{
+    iSongNoteOffset = iOffset;
+}
+
+void Sound::StopSong(void)
+{
+    // clear the play sound
+    bPlaySong = false;
+    // Silence
+    StopSound(iSongChannel);
+    // All done with this function
+    return;
+}
+
+void Sound::DoSong(void)
+{
+    // Check to see if we are playing a song
+    if (!bPlaySong) return;
+    
+    // Check to see if there is a song to play
+    if (!m_pSong) return;
+    
+    // Check to see if we need to play the next note
+    iNoteCounter--;
+    if (iNoteCounter > 0) return;
+    
+    int duration = 4;
+    int octave = 5;
+    int freq = NOTE_C4;
+    char note = 'c';
+    bool bSharp = false;
+    bool bDotted = false;
+    int volume = channel[iSongChannel].volume;
+    while (*m_pSong != ',')
+    {
+        // Parse and play a note
+        // Check for duration
+        if (ISNUMBER(*m_pSong))
+        {
+            duration = *m_pSong - '0';
+            m_pSong++;
+            if (ISNUMBER(*m_pSong))
+            {
+                duration = (duration * 10) + (*m_pSong - '0');
+                m_pSong++;
+            }
+        }
+        // Check for the note
+        if (ISALPHA(*m_pSong))
+        {
+            TOLOWER(*m_pSong);
+            note = *m_pSong;
+            m_pSong++;
+        }
+        // Check for a sharp
+        if (*m_pSong == '#') { bSharp = true; m_pSong++; }
+        // Check for dotted
+        if (*m_pSong == '.') { bDotted = true; m_pSong++; }
+        // Check for the octave
+        if (ISNUMBER(*m_pSong))
+        {
+            octave = *m_pSong - '0';
+            m_pSong++;
+        }
+        // Check to see if we need to start over
+        if (*m_pSong == 0)
+        {  
+            if (bLoopSong)
+            {
+                // Set the song buffer to the beginning
+                m_pSong = m_pSongBuffer;
+                // and process the first note all over again
+                continue;
+            }
+            else
+            {
+                StopSong();
+                // All done with this function
+                return;
+            }
+        }
+        // Next character so we do not get stuck
+        if (*m_pSong != ',') m_pSong++;
+        // Check for silence
+        if (note != 'p')
+        {
+            // Convert the note to a frequency
+            freq = SongGetFreq(note, octave, bSharp);
+            // Play the note
+            PlaySound(iSongChannel, freq, volume + 1);
+        }
+        else
+        {
+            // Silence (Pause)
+            StopSound(iSongChannel);
+        }
+        
+        // Set the note counter so we play the note for so many frames
+        switch(duration)
+        {
+        case (1): iNoteCounter = 4 * iTicksPerBeat; break;
+        case (2): iNoteCounter = 2 * iTicksPerBeat; break;
+        default:
+        case (4): iNoteCounter = iTicksPerBeat; break;
+        case (8): iNoteCounter = iTicksPerBeat >> 1; break;
+        case (16): iNoteCounter = iTicksPerBeat >> 2; break;
+        case (32): iNoteCounter = iTicksPerBeat >> 3; break;
+        }
+        if (bDotted) iNoteCounter += iNoteCounter >> 1;
+        
+        //char cTemp[32];
+        //snprintf(cTemp, 32, "N(%c%c)D(%02d)O(%d)", note, bSharp ? '#' : ' ', duration, octave);
+        //disp.drawString(0, 16, cTemp, DisplayN18::RED, DisplayN18::BLACK);
+
+    }
+    m_pSong++;
+}
+
+int Sound::SongGetFreq(char note, int octave, bool bSharp)
+{
+    // Bounds check the octave
+    if (octave < 4) octave = 4;
+    if (octave > 6) octave = 6;
+    
+    switch(octave)
+    {
+    case (4):
+        switch(note)
+        {
+        case ('a'):
+            if (bSharp) return NOTE_As4;
+            return NOTE_A4;
+        case ('b'):
+            if (bSharp) return NOTE_C5;
+            return NOTE_B4;
+        case ('c'):
+            if (bSharp) return NOTE_Cs4;
+            return NOTE_C4;
+        case ('d'):
+            if (bSharp) return NOTE_Ds4;
+            return NOTE_D4;
+        case ('e'):
+            if (bSharp) return NOTE_F4;
+            return NOTE_E4;
+        case ('f'):
+            if (bSharp) return NOTE_Fs4;
+            return NOTE_F4;
+        case ('g'):
+            if (bSharp) return NOTE_Gs4;
+            return NOTE_G4;
+        }
+    case (5):
+        switch(note)
+        {
+        case ('a'):
+            if (bSharp) return NOTE_As5;
+            return NOTE_A5;
+        case ('b'):
+            if (bSharp) return NOTE_C6;
+            return NOTE_B5;
+        case ('c'):
+            if (bSharp) return NOTE_Cs5;
+            return NOTE_C5;
+        case ('d'):
+            if (bSharp) return NOTE_Ds5;
+            return NOTE_D5;
+        case ('e'):
+            if (bSharp) return NOTE_F5;
+            return NOTE_E5;
+        case ('f'):
+            if (bSharp) return NOTE_Fs5;
+            return NOTE_F5;
+        case ('g'):
+            if (bSharp) return NOTE_Gs5;
+            return NOTE_G5;
+        }
+    case (6):
+        switch(note)
+        {
+        case ('a'):
+            if (bSharp) return NOTE_As6;
+            return NOTE_A6;
+        case ('b'):
+            if (bSharp) return NOTE_C7;
+            return NOTE_B6;
+        case ('c'):
+            if (bSharp) return NOTE_Cs6;
+            return NOTE_C6;
+        case ('d'):
+            if (bSharp) return NOTE_Ds6;
+            return NOTE_D6;
+        case ('e'):
+            if (bSharp) return NOTE_F6;
+            return NOTE_E6;
+        case ('f'):
+            if (bSharp) return NOTE_Fs6;
+            return NOTE_F6;
+        case ('g'):
+            if (bSharp) return NOTE_Gs6;
+            return NOTE_G6;
+        }
+    }
+    
+    return NOTE_C7;
+}
+
+void Sound:: Mute(bool mute)
+{
+    bMuted = mute;   
+}
diff -r 000000000000 -r c79e1f29f029 Sound/sound.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Sound/sound.h	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,194 @@
+#include "mbed.h"
+
+#ifndef __SOUND_H__
+#define __SOUND_H__
+
+
+// Notes in Hertz
+enum NOTE
+{
+    NOTE_C3 = 130,
+    NOTE_Cs3 = 138,
+    NOTE_Db3 = NOTE_Cs3,
+    NOTE_D3 = 146,
+    NOTE_Ds3 = 155,
+    NOTE_Eb3 = NOTE_Ds3,
+    NOTE_E3 = 164,
+    NOTE_F3 = 174,
+    NOTE_Fs3 = 184,
+    NOTE_Gb3 = NOTE_Fs3,
+    NOTE_G3 = 195,
+    NOTE_Gs3 = 207,
+    NOTE_Ab3 = NOTE_Gs3,
+    NOTE_A3 = 220,
+    NOTE_As3 = 233,
+    NOTE_Bb3 = NOTE_As3,
+    NOTE_B3 = 246,
+    NOTE_C4 = 262,
+    NOTE_Cs4 = 277,
+    NOTE_Db4 = NOTE_Cs4,
+    NOTE_D4 = 294,
+    NOTE_Ds4 = 311,
+    NOTE_Eb4 = NOTE_Ds4,
+    NOTE_E4 = 330,
+    NOTE_F4 = 349,
+    NOTE_Fs4 = 370,
+    NOTE_Gb4 = NOTE_Fs4,
+    NOTE_G4 = 392,
+    NOTE_Gs4 = 415,
+    NOTE_Ab4 = NOTE_Gs4,
+    NOTE_A4 = 440,
+    NOTE_As4 = 466,
+    NOTE_B4 = 494,
+    NOTE_C5 = 523,
+    NOTE_Cs5 = 554,
+    NOTE_Db5 = NOTE_Cs5,
+    NOTE_D5 = 587,
+    NOTE_Ds5 = 622,
+    NOTE_Eb5 = NOTE_Ds5,
+    NOTE_E5 = 659,
+    NOTE_F5 = 698,
+    NOTE_Fs5 = 740,
+    NOTE_Gb5 = NOTE_Fs5,
+    NOTE_G5 = 784,
+    NOTE_Gs5 = 831,
+    NOTE_Ab5 = NOTE_Gs5,
+    NOTE_A5 = 880,
+    NOTE_As5 = 932,
+    NOTE_Bb5 = NOTE_As5,
+    NOTE_B5 = 988,
+    NOTE_C6 = 1047,
+    NOTE_Cs6 = 1109,
+    NOTE_Db6 = NOTE_Cs6,
+    NOTE_D6 = 1175,
+    NOTE_Ds6 = 1245,
+    NOTE_Eb6 = NOTE_Ds6,
+    NOTE_E6 = 1319,
+    NOTE_F6 = 1397,
+    NOTE_Fs6 = 1480,
+    NOTE_Gb6 = NOTE_Fs6,
+    NOTE_G6 = 1568,
+    NOTE_Gs6 = 1661,
+    NOTE_Ab6 = NOTE_Gs6,
+    NOTE_A6 = 1760,
+    NOTE_As6 = 1865,
+    NOTE_Bb6 = NOTE_As6,
+    NOTE_B6 = 1976,
+    NOTE_C7 = 2093,
+    NOTE_Cs7 = 2217,
+    NOTE_Db7 = NOTE_Cs7,
+    NOTE_D7 = 2349,
+    NOTE_Ds7 = 2489,
+    NOTE_F7 = 2793,
+    NOTE_Fs7 = 2959,
+    NOTE_Gb7 = NOTE_Fs7,
+    NOTE_G7 = 3135,
+    NOTE_Gs7 = 3322,
+    NOTE_Ab7 = NOTE_Gs7,
+    NOTE_A7 = 3520,
+    NOTE_As7 = 3729,
+    NOTE_Bb7 = NOTE_As7,
+    NOTE_B7 = 3951,
+    NOTE_C8 = 4186
+};
+
+#define SOUND_MAX_CHANNELS  4
+
+enum SOUND_INST_WAVEFORM
+{
+    SOUND_SQUARE,
+    SOUND_SAW,
+    SOUND_TRIANGLE,
+    SOUND_SINE,
+    SOUND_NOISE,
+};
+
+struct SOUND_CHANNEL
+{
+    bool active;
+    
+    unsigned short orig_phase_inc;
+    unsigned short phase_inc;
+    unsigned short phase_acc;
+    unsigned char volume;
+    
+    unsigned char play_length;             // 0 to 255 in 50Hz ticks
+    
+    // Instrument parameters
+    unsigned char  vol_level;              // Starting volume 0 to 64
+    char            waveform;              // 0 = square, 1 = saw, 2 = triangle, 3 = sine, 4 = noise
+    unsigned char   decay_amount;          // 0 to 255
+    signed char     slide;                 // +- 127
+    unsigned short  change_amount;         // +-127
+    char            change_speed;          // +-127
+    unsigned char   repeat_speed;          // 0 to 255
+    unsigned char   vibrato_depth;         // Amplitude of Vibrato => 0 to 255
+    unsigned char   vibrato_speed;         // Frequency of the Vibrato
+    
+    // Extra state stuff that makes the instrument do its thing
+    bool use_noise;
+    unsigned char *pWaveform;
+    
+    unsigned char vibrato_phase;
+    short int vibrato_inc;
+    unsigned short repeat_wait;
+    unsigned short change_wait;
+    unsigned short change_inc;
+};
+
+class Sound
+{
+public:
+
+    Sound();
+    ~Sound();
+    
+    void Init();
+    
+    void PlaySong(char *pRTTTL, int iChannel = 0, int iBPM = 120, bool bLoop = true);
+    void SetSongTempo(int iBPM);
+    void TransposeSong(int iOffset);
+    void StopSong(void);
+    bool SongIsPlaying(void) { return bPlaySong; };
+    
+    // TODO - create a set instrument that allows the parameters to be encoded
+    // TODO - what else??? we have sound effects, we have songs... drums?
+    void SetInstrument(int iChannel, int iWaveform, int iVolume, int iDecayTime, int iSlide, int iChangeAmount, int iChangeSpeed, int iRepeatSpeed, int iVibratoDepth, int iVibratoSpeed);
+    void PlaySound(int iChannel, int iFreqHz, int iLength = 0);
+    void StopSound(int iChannel);
+    bool IsBusy(int iChannel);
+    
+    void Mute(bool mute);
+    bool IsMuted(void) { return bMuted; };
+
+    int GetCounter(void);
+    
+    friend void TIMER32_0_IRQHandler(void);
+    
+protected:
+
+    void SetupDefaults(void);
+    void DoEffects(void);
+    
+    SOUND_CHANNEL channel[SOUND_MAX_CHANNELS];
+    
+    unsigned short effect_wait;
+    
+    // Sound Related variables
+    bool bMuted;
+    
+    // Song Related Variables and Functions
+    bool bPlaySong;
+    bool bLoopSong;
+    int iSongChannel;
+    char *m_pSong;
+    char *m_pSongBuffer;
+    int iSongBufferLen;
+    int iSongNoteOffset;
+    int iNoteCounter;
+    int iTicksPerBeat;
+    void DoSong(void);
+    int SongGetFreq(char note, int octave, bool bSharp);
+};
+
+#endif // __SOUND_H__
diff -r 000000000000 -r c79e1f29f029 led/led.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/led/led.cpp	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,125 @@
+#include "led.h"
+
+led_state::led_state()
+{
+    m_eMode = eLEDOff;
+    m_iValue = 0;
+    m_iTicks = 0;
+    m_iRate = 0;
+}
+
+bool led_state::tick()
+{
+    if (m_eMode == eLEDOff) return false;
+    
+    if (m_eMode == eLEDBlink)
+    {
+        // Decrement the counter until it gets to 0
+        m_iCounter--;
+        if (m_iCounter < 1)
+        {
+            // Toggle the LED
+            m_iValue = !m_iValue;
+            // Reset the counter
+            m_iCounter = m_iRate;
+        }
+    }
+    
+    // Decrement the ticks
+    if (m_iTicks > 0)
+    {
+        m_iTicks--;
+        if (m_iTicks < 1)
+        {
+            // Turn the LED Off
+            m_iValue = 0;
+            // Set the MODE to Off
+            m_eMode = eLEDOff;
+        }
+    }
+    
+    return true;
+}
+
+void led_state::set(bool on, int ticks)
+{
+    // Set the ticks
+    m_iTicks = ticks;
+    
+    if (on)
+    {
+        m_eMode = eLEDOn;
+        m_iValue = 1;   
+    }
+    else
+    {
+        m_eMode = eLEDOff;
+        m_iValue = 0;
+    }
+}
+
+void led_state::blink(int rate, int state, int ticks)
+{
+    // Bounds check the rate
+    if (rate < 1) return;
+    
+    // Set the rate
+    m_iRate = rate;
+    m_iCounter = rate;
+    
+    // Set the ticks
+    m_iTicks = ticks;
+    
+    // Set the mode
+    m_eMode = eLEDBlink;
+    
+    // Set the initial value
+    m_iValue = state;
+}
+
+led::led() : led1(P0_9), led2(P0_8)
+{
+    led1 = 0;
+    led2 = 0;
+}
+
+void led::tick()
+{
+    if (led_state1.tick()) led1 = led_state1.m_iValue;
+    if (led_state2.tick()) led2 = led_state2.m_iValue;
+}
+
+bool led::get(int led)
+{
+    if (led == 1) return (led_state1.m_eMode != led_state::eLEDOff);
+    if (led == 2) return (led_state2.m_eMode != led_state::eLEDOff);
+    return false;
+}
+    
+void led::set(int led, bool on, int ticks)
+{
+    if (led == 1)
+    {
+        led_state1.set(on, ticks);
+        led1 = led_state1.m_iValue;
+    }
+    if (led == 2)
+    {
+        led_state2.set(on, ticks);
+        led2 = led_state2.m_iValue;
+    }
+}
+
+void led::blink(int led, int rate, int state, int ticks)
+{
+    if (led == 1)
+    {
+        led_state1.blink(rate, state, ticks);
+        led1 = led_state1.m_iValue;
+    }
+    if (led == 2)
+    {
+        led_state2.blink(rate, state, ticks);
+        led2 = led_state2.m_iValue;
+    }
+}
diff -r 000000000000 -r c79e1f29f029 led/led.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/led/led.h	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,49 @@
+#include "mbed.h"
+
+class led_state
+{
+public:
+    
+    led_state();
+    virtual ~led_state() {};
+    
+    bool tick();
+    
+    void set(bool on, int ticks = -1);
+    void blink(int rate, int state = 1, int ticks = -1);
+
+    enum LED_MODE
+    {
+        eLEDOff,
+        eLEDOn,
+        eLEDBlink,
+    } m_eMode;
+    
+    int m_iValue;
+    int m_iTicks;
+    int m_iRate;
+    int m_iCounter;
+    
+};
+
+class led
+{
+public:
+    
+    led();
+    virtual ~led() {};
+    
+    void tick();        // call at about 50 Hz
+    
+    // Set, Get, Blink, etc...
+    bool get(int led);
+    void set(int led, bool on, int ticks = -1);      // ticks == -1 => infinite
+    void blink(int led, int rate, int state = 1, int ticks = -1);    // rate in ticks, ticks == -1 => infinite
+    
+protected:
+    
+    led_state led_state1, led_state2;
+    DigitalOut led1;
+    DigitalOut led2;
+    
+};
\ No newline at end of file
diff -r 000000000000 -r c79e1f29f029 mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Mar 03 04:26:01 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/4fc01daae5a5
\ No newline at end of file