Library(Beta) for Gameduino 2

Dependencies:   arduino

Dependents:   aa_gd_jw

Files at this revision

API Documentation at this revision

Comitter:
aluqard
Date:
Fri Apr 11 07:24:23 2014 +0000
Commit message:
Initial release for Gameduino 2

Changed in this revision

GD2.cpp Show annotated file Show diff for this revision Revisions of this file
GD2.h Show annotated file Show diff for this revision Revisions of this file
GDTransport.h Show annotated file Show diff for this revision Revisions of this file
Utils.h Show annotated file Show diff for this revision Revisions of this file
arduino.lib Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GD2.cpp	Fri Apr 11 07:24:23 2014 +0000
@@ -0,0 +1,825 @@
+#include "stdarg.h"
+#include "GD2.h"
+#include "Utils.h"
+
+//AnalogIn accel[3] = {P0_23, P0_24, P0_25};
+byte touch_transform0[] = { 0xEA, 0x81, 0x00, 0x00, 0xAE, 0xFE, 0xFF, 0xFF, 0x49, 0xCC, 0xEC, 0xFF, 0x28, 0x00, 0x00, 0x00, 0x09, 0xB3, 0xFF, 0xFF, 0x42, 0x5D, 0x18, 0x01 };
+byte touch_transform1[] = { 0xAB, 0x7E, 0xFF, 0xFF, 0x0F, 0x01, 0x00, 0x00, 0x97, 0x22, 0xEE, 0x01, 0xA3, 0x00, 0x00, 0x00, 0xB3, 0x4B, 0x00, 0x00, 0xE9, 0xC9, 0xF6, 0xFF };
+
+GDClass::GDClass(PinName mosi, PinName miso, PinName sclk, PinName graphic_cs, PinName sdcard_cs)
+    : GDTR(mosi, miso, sclk, graphic_cs)
+{
+    _sdcard_cs = sdcard_cs;
+    
+    accel[0] = new AnalogIn(P0_23);
+    accel[1] = new AnalogIn(P0_24);
+    accel[2] = new AnalogIn(P0_25);
+}
+
+void GDClass::begin(uint8_t options)
+{
+    GDTR.begin();
+
+    // Generate a blank screen
+    cmd_dlstart();
+    Clear();
+    swap();
+    finish();
+
+    GDTR.wr(REG_PCLK_POL, 1);
+    
+    GDTR.wr(REG_PCLK, 5);
+#if PROTO == 1
+    GDTR.wr(REG_ROTATE, 0);
+    GDTR.wr(REG_SWIZZLE, 3);
+#endif
+    GDTR.wr(REG_GPIO_DIR, 0x83);
+    GDTR.wr(REG_GPIO, 0x80);
+    
+    for (int i = 0; i < sizeof(touch_transform0); i++)
+    {
+        if(GDTR.rd(REG_ROTATE) == 0)
+            GDTR.wr(REG_TOUCH_TRANSFORM_A + i, touch_transform0[i]);
+        else
+            GDTR.wr(REG_TOUCH_TRANSFORM_A + i, touch_transform1[i]);
+    }
+    
+    if (options & GD_CALIBRATE)
+    {
+#if CALIBRATION
+    
+    self_calibrate();
+    for (int i = 0; i < 24; i++) 
+        std::printf("0x%02X, ", GDTR.rd(REG_TOUCH_TRANSFORM_A + i));
+/*
+        if (EEPROM.read(0) != 0x7c) {
+            self_calibrate();
+             for (int i = 0; i < 24; i++) 
+                DEBUGOUT(GDTR.rd(REG_TOUCH_TRANSFORM_A + i), HEX);
+            for (int i = 0; i < 24; i++)
+                EEPROM.write(1 + i, GDTR.rd(REG_TOUCH_TRANSFORM_A + i));
+            EEPROM.write(0, 0x7c);  // is written!
+        } else {
+            for (int i = 0; i < 24; i++)
+                GDTR.wr(REG_TOUCH_TRANSFORM_A + i, EEPROM.read(1 + i));
+        }
+*/
+#endif
+    }
+
+    GDTR.wr16(REG_TOUCH_RZTHRESH, 1200);
+
+    lfsr = 0x5555;
+    lcg = 0;
+
+    SD = new sdcard(GDTR.SPI(), _sdcard_cs);
+    
+#if STORAGE
+    if (options & GD_STORAGE) 
+    {
+        storage();
+    }
+#endif
+
+    if (options & GD_TRIM) 
+    {
+        tune();
+        DEBUGOUT("tune()\r\n");
+    }
+}
+
+void GDClass::flush(void)
+{
+    GDTR.flush();
+}
+
+void GDClass::swap(void) {
+    Display();
+    cmd_swap();
+    cmd_loadidentity();
+    cmd_dlstart();
+    GDTR.flush();
+}
+
+uint32_t GDClass::measure_freq(void)
+{
+    unsigned long t0 = GDTR.rd32(REG_CLOCK);
+    delayMicroseconds(15625);
+    unsigned long t1 = GDTR.rd32(REG_CLOCK);
+    return (t1 - t0) << 6;
+}
+
+void GDClass::tune(void)
+{
+    uint32_t f;
+    for (byte i = 0; (i < 31) && ((f = measure_freq()) < LOW_FREQ_BOUND); i++)
+        GDTR.wr(REG_TRIM, i);
+    GDTR.wr32(REG_FREQUENCY, f);
+}
+
+
+void GDClass::storage(void) {
+    GDTR.__end();
+    SD->begin();
+    GDTR.resume();
+}
+
+void GDClass::self_calibrate(void) {
+    cmd_dlstart();
+    Clear();
+    cmd_text(240, 100, 30, OPT_CENTERX, "please tap on the dot");
+    cmd_calibrate();
+    finish();
+    cmd_loadidentity();
+    cmd_dlstart();
+    GDTR.flush();
+}
+
+void GDClass::seed(uint16_t n) {
+    lfsr = n | 1;
+    lcg = n ^ 0x7921;
+}
+uint16_t GDClass::random() {
+    lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xB400u);
+    lcg = (lcg * 47) + 60497;
+    return (lcg ^ lfsr);
+}
+uint16_t GDClass::random(uint16_t n) {
+    return GDClass::random() % n;
+}
+
+
+// >>> [int(65535*math.sin(math.pi * 2 * i / 1024)) for i in range(257)]
+static PROGMEM int sintab[257] = {
+    0, 402, 804, 1206, 1608, 2010, 2412, 2813, 3215, 3617, 4018, 4419, 4821, 5221, 5622, 6023, 6423, 6823, 7223, 7622, 8022, 8421, 8819, 9218, 9615, 10013, 10410, 10807, 11203, 11599, 11995, 12390, 12785, 13179, 13573, 13966, 14358, 14750, 15142, 15533, 15923, 16313, 16702, 17091, 17479, 17866, 18252, 18638, 19023, 19408, 19791, 20174, 20557, 20938, 21319, 21699, 22078, 22456, 22833, 23210, 23585, 23960, 24334, 24707, 25079, 25450, 25820, 26189, 26557, 26924, 27290, 27655, 28019, 28382, 28744, 29105, 29465, 29823, 30181, 30537, 30892, 31247, 31599, 31951, 32302, 32651, 32999, 33346, 33691, 34035, 34378, 34720, 35061, 35400, 35737, 36074, 36409, 36742, 37075, 37406, 37735, 38063, 38390, 38715, 39039, 39361, 39682, 40001, 40319, 40635, 40950, 41263, 41574, 41885, 42193, 42500, 42805, 43109, 43411, 43711, 44010, 44307, 44603, 44896, 45189, 45479, 45768, 46055, 46340, 46623, 46905, 47185, 47463, 47739, 48014, 48287, 48558, 48827, 49094, 49360, 49623, 49885, 50145, 50403, 50659, 50913, 51165, 51415, 51664, 51910, 52155, 52397, 52638, 52876, 53113, 53347, 53580, 53810, 54039, 54265, 54490, 54712, 54933, 55151, 55367, 55581, 55793, 56003, 56211, 56416, 56620, 56821, 57021, 57218, 57413, 57606, 57796, 57985, 58171, 58355, 58537, 58717, 58894, 59069, 59242, 59413, 59582, 59748, 59912, 60074, 60234, 60391, 60546, 60699, 60849, 60997, 61143, 61287, 61428, 61567, 61704, 61838, 61970, 62100, 62227, 62352, 62474, 62595, 62713, 62828, 62941, 63052, 63161, 63267, 63370, 63472, 63570, 63667, 63761, 63853, 63942, 64029, 64114, 64196, 64275, 64353, 64427, 64500, 64570, 64637, 64702, 64765, 64825, 64883, 64938, 64991, 65042, 65090, 65135, 65178, 65219, 65257, 65293, 65326, 65357, 65385, 65411, 65435, 65456, 65474, 65490, 65504, 65515, 65523, 65530, 65533, 65535
+};
+
+int16_t GDClass::rsin(int16_t r, uint16_t th) {
+    th >>= 6; // angle 0-123
+    // return int(r * sin((2 * M_PI) * th / 1024.));
+    int th4 = th & 511;
+    if (th4 & 256)
+        th4 = 512 - th4; // 256->256 257->255, etc
+    uint16_t s = pgm_read_word_near(sintab + th4);
+    int16_t p = ((uint32_t)s * r) >> 16;
+    if (th & 512)
+        p = -p;
+    return p;
+}
+
+int16_t GDClass::rcos(int16_t r, uint16_t th) {
+    return rsin(r, th + 0x4000);
+}
+
+void GDClass::polar(int &x, int &y, int16_t r, uint16_t th) {
+    x = (int)(-rsin(r, th));
+    y = (int)( rcos(r, th));
+}
+
+// >>> [int(round(1024 * math.atan(i / 256.) / math.pi)) for i in range(256)]
+static PROGMEM unsigned char atan8[] = {
+    0,1,3,4,5,6,8,9,10,11,13,14,15,17,18,19,20,22,23,24,25,27,28,29,30,32,33,34,36,37,38,39,41,42,43,44,46,47,48,49,51,52,53,54,55,57,58,59,60,62,63,64,65,67,68,69,70,71,73,74,75,76,77,79,80,81,82,83,85,86,87,88,89,91,92,93,94,95,96,98,99,100,101,102,103,104,106,107,108,109,110,111,112,114,115,116,117,118,119,120,121,122,124,125,126,127,128,129,130,131,132,133,134,135,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,177,178,179,180,181,182,183,184,185,186,187,188,188,189,190,191,192,193,194,195,195,196,197,198,199,200,201,201,202,203,204,205,206,206,207,208,209,210,211,211,212,213,214,215,215,216,217,218,219,219,220,221,222,222,223,224,225,225,226,227,228,228,229,230,231,231,232,233,234,234,235,236,236,237,238,239,239,240,241,241,242,243,243,244,245,245,246,247,248,248,249,250,250,251,251,252,253,253,254,255,255
+};
+
+uint16_t GDClass::atan2(int16_t y, int16_t x)
+{
+    uint16_t a;
+    uint16_t xx = 0;
+
+    if ((x <= 0) ^ (y > 0)) {
+        int16_t t; t = x; x = y; y = t;
+        xx ^= 0x4000;
+    }
+    if (x <= 0) {
+        x = -x;
+    } else {
+        xx ^= 0x8000;
+    }
+    y = abs(y);
+    if (x > y) {
+        int16_t t; t = x; x = y; y = t;
+        xx ^= 0x3fff;
+    }
+    while ((x | y) & 0xff80) {
+        x >>= 1;
+        y >>= 1;
+    }
+    if (y == 0) {
+        a = 0;
+    } else if (x == y) {
+        a = 0x2000;
+    } else {
+        // assert(x <= y);
+        int r = ((x << 8) / y);
+        // assert(0 <= r);
+        // assert(r < 256);
+        a = pgm_read_byte(atan8 + r) << 5;
+    }
+    a ^= xx;
+    return a;
+}
+
+void GDClass::align(byte n) {
+    while ((n++) & 3)
+        GDTR.cmdbyte(0);
+}
+
+void GDClass::cH(uint16_t v) {
+    GDTR.cmdbyte(v & 0xff);
+    GDTR.cmdbyte((v >> 8) & 0xff);
+}
+
+void GDClass::ch(int16_t v) {
+    cH((uint16_t)v);
+}
+
+void GDClass::cI(uint32_t v) {
+    GDTR.cmd32(v);
+}
+
+void GDClass::cFFFFFF(byte v) {
+    union {
+        uint32_t c;
+        uint8_t b[4];
+    };
+    b[0] = v;
+    b[1] = 0xff;
+    b[2] = 0xff;
+    b[3] = 0xff;
+    GDTR.cmd32(c);
+}
+
+void GDClass::ci(int32_t v) {
+    cI((uint32_t) v);
+}
+
+void GDClass::cs(const char *s) {
+    while (*s) {
+        char c = *s++;
+        GDTR.cmdbyte(c);
+    }
+    GDTR.cmdbyte(0);
+}
+
+void GDClass::copy(const unsigned char *src, int count) {
+    byte a = count & 3;
+    while (count--) {
+        GDTR.cmdbyte(pgm_read_byte_near(src));
+        src++;
+    }
+    align(a);
+}
+
+void GDClass::copyram(byte *src, int count) {
+    byte a = count & 3;
+    GDTR.cmd_n(src, count);
+    align(a);
+}
+
+void GDClass::AlphaFunc(byte func, byte ref) {
+    cI((9UL << 24) | ((func & 7L) << 8) | ((ref & 255L) << 0));
+}
+void GDClass::Begin(byte prim) {
+    cI((31UL << 24) | prim);
+}
+void GDClass::BitmapHandle(byte handle) {
+    cI((5UL << 24) | handle);
+}
+void GDClass::BitmapLayout(byte format, uint16_t linestride, uint16_t height) {
+    // cI((7UL << 24) | ((format & 31L) << 19) | ((linestride & 1023L) << 9) | ((height & 511L) << 0));
+    union {
+        uint32_t c;
+        uint8_t b[4];
+    };
+    b[0] = height;
+    b[1] = (1 & (height >> 8)) | (linestride << 1);
+    b[2] = (7 & (linestride >> 7)) | (format << 3);
+    b[3] = 7;
+    cI(c);
+}
+void GDClass::BitmapSize(byte filter, byte wrapx, byte wrapy, uint16_t width, uint16_t height) {
+    byte fxy = (filter << 2) | (wrapx << 1) | (wrapy);
+    // cI((8UL << 24) | ((uint32_t)fxy << 18) | ((width & 511L) << 9) | ((height & 511L) << 0));
+    union {
+        uint32_t c;
+        uint8_t b[4];
+    };
+    b[0] = height;
+    b[1] = (1 & (height >> 8)) | (width << 1);
+    b[2] = (3 & (width >> 7)) | (fxy << 2);
+    b[3] = 8;
+    cI(c);
+}
+void GDClass::BitmapSource(uint32_t addr) {
+    cI((1UL << 24) | ((addr & 1048575L) << 0));
+}
+void GDClass::BitmapTransformA(int32_t a) {
+    cI((21UL << 24) | ((a & 131071L) << 0));
+}
+void GDClass::BitmapTransformB(int32_t b) {
+    cI((22UL << 24) | ((b & 131071L) << 0));
+}
+void GDClass::BitmapTransformC(int32_t c) {
+    cI((23UL << 24) | ((c & 16777215L) << 0));
+}
+void GDClass::BitmapTransformD(int32_t d) {
+    cI((24UL << 24) | ((d & 131071L) << 0));
+}
+void GDClass::BitmapTransformE(int32_t e) {
+    cI((25UL << 24) | ((e & 131071L) << 0));
+}
+void GDClass::BitmapTransformF(int32_t f) {
+    cI((26UL << 24) | ((f & 16777215L) << 0));
+}
+void GDClass::BlendFunc(byte src, byte dst) {
+    cI((11UL << 24) | ((src & 7L) << 3) | ((dst & 7L) << 0));
+}
+void GDClass::Call(uint16_t dest) {
+    cI((29UL << 24) | ((dest & 2047L) << 0));
+}
+void GDClass::Cell(byte cell) {
+    cI((6UL << 24) | ((cell & 127L) << 0));
+}
+void GDClass::ClearColorA(byte alpha) {
+    cI((15UL << 24) | ((alpha & 255L) << 0));
+}
+void GDClass::ClearColorRGB(byte red, byte green, byte blue) {
+    cI((2UL << 24) | ((red & 255L) << 16) | ((green & 255L) << 8) | ((blue & 255L) << 0));
+}
+void GDClass::ClearColorRGB(uint32_t rgb) {
+    cI((2UL << 24) | (rgb & 0xffffffL));
+}
+void GDClass::Clear(byte c, byte s, byte t) {
+    byte m = (c << 2) | (s << 1) | t;
+    cI((38UL << 24) | m);
+}
+void GDClass::Clear(void) {
+    cI((38UL << 24) | 7);
+}
+void GDClass::ClearStencil(byte s) {
+    cI((17UL << 24) | ((s & 255L) << 0));
+}
+void GDClass::ClearTag(byte s) {
+    cI((18UL << 24) | ((s & 255L) << 0));
+}
+void GDClass::ColorA(byte alpha) {
+    cI((16UL << 24) | ((alpha & 255L) << 0));
+}
+void GDClass::ColorMask(byte r, byte g, byte b, byte a) {
+    cI((32UL << 24) | ((r & 1L) << 3) | ((g & 1L) << 2) | ((b & 1L) << 1) | ((a & 1L) << 0));
+}
+void GDClass::ColorRGB(byte red, byte green, byte blue) {
+    // cI((4UL << 24) | ((red & 255L) << 16) | ((green & 255L) << 8) | ((blue & 255L) << 0));
+    union {
+        uint32_t c;
+        uint8_t b[4];
+    };
+    b[0] = blue;
+    b[1] = green;
+    b[2] = red;
+    b[3] = 4;
+    cI(c);
+}
+void GDClass::ColorRGB(uint32_t rgb) {
+    cI((4UL << 24) | (rgb & 0xffffffL));
+}
+void GDClass::Display(void) {
+    cI((0UL << 24));
+}
+void GDClass::End(void) {
+    cI((33UL << 24));
+}
+void GDClass::Jump(uint16_t dest) {
+    cI((30UL << 24) | ((dest & 2047L) << 0));
+}
+void GDClass::LineWidth(uint16_t width) {
+    cI((14UL << 24) | ((width & 4095L) << 0));
+}
+void GDClass::Macro(byte m) {
+    cI((37UL << 24) | ((m & 1L) << 0));
+}
+void GDClass::PointSize(uint16_t size) {
+    cI((13UL << 24) | ((size & 8191L) << 0));
+}
+void GDClass::RestoreContext(void) {
+    cI((35UL << 24));
+}
+void GDClass::Return(void) {
+    cI((36UL << 24));
+}
+void GDClass::SaveContext(void) {
+    cI((34UL << 24));
+}
+void GDClass::ScissorSize(uint16_t width, uint16_t height) {
+    cI((28UL << 24) | ((width & 1023L) << 10) | ((height & 1023L) << 0));
+}
+void GDClass::ScissorXY(uint16_t x, uint16_t y) {
+    cI((27UL << 24) | ((x & 511L) << 9) | ((y & 511L) << 0));
+}
+void GDClass::StencilFunc(byte func, byte ref, byte mask) {
+    cI((10UL << 24) | ((func & 7L) << 16) | ((ref & 255L) << 8) | ((mask & 255L) << 0));
+}
+void GDClass::StencilMask(byte mask) {
+    cI((19UL << 24) | ((mask & 255L) << 0));
+}
+void GDClass::StencilOp(byte sfail, byte spass) {
+    cI((12UL << 24) | ((sfail & 7L) << 3) | ((spass & 7L) << 0));
+}
+void GDClass::TagMask(byte mask) {
+    cI((20UL << 24) | ((mask & 1L) << 0));
+}
+void GDClass::Tag(byte s) {
+    cI((3UL << 24) | ((s & 255L) << 0));
+}
+void GDClass::Vertex2f(int16_t x, int16_t y) {
+    // x = int(16 * x);
+    // y = int(16 * y);
+    cI((1UL << 30) | ((x & 32767L) << 15) | ((y & 32767L) << 0));
+}
+void GDClass::Vertex2ii(uint16_t x, uint16_t y, byte handle, byte cell) {
+    // cI((2UL << 30) | ((x & 511L) << 21) | ((y & 511L) << 12) | ((handle & 31L) << 7) | ((cell & 127L) << 0));
+    union {
+        uint32_t c;
+        uint8_t b[4];
+    };
+    b[0] = cell | ((handle & 1) << 7);
+    b[1] = (handle >> 1) | (y << 4);
+    b[2] = (y >> 4) | (x << 5);
+    b[3] = (2 << 6) | (x >> 3);
+    cI(c);
+}
+
+void GDClass::fmtcmd(const char *fmt, ...) {
+    va_list ap;
+    va_start(ap, fmt);
+    byte sz = 0;  // Only the low 2 bits matter
+    const char *s;
+
+    while (*fmt)
+        switch (*fmt++) {
+        case 'i':
+        case 'I':
+            cI(va_arg(ap, uint32_t));
+            break;
+        case 'h':
+        case 'H':
+            cH(va_arg(ap, unsigned int));
+            sz += 2;
+            break;
+        case 's':
+            s = va_arg(ap, const char*);
+            cs(s);
+            sz += strlen(s) + 1;
+            break;
+    }
+    align(sz);
+}
+
+void GDClass::cmd_append(uint32_t ptr, uint32_t num) {
+    cFFFFFF(0x1e);
+    cI(ptr);
+    cI(num);
+}
+void GDClass::cmd_bgcolor(uint32_t c) {
+    fmtcmd("II", 0xffffff09UL, c);
+}
+void GDClass::cmd_button(int16_t x, int16_t y, uint16_t w, uint16_t h, byte font, uint16_t options, const char *s) {
+    fmtcmd("IhhhhhHs", 0xffffff0dUL, x, y, w, h, font, options, s);
+}
+void GDClass::cmd_calibrate(void) {
+    cFFFFFF(0x15);
+    cFFFFFF(0xff);
+}
+void GDClass::cmd_clock(int16_t x, int16_t y, int16_t r, uint16_t options, uint16_t h, uint16_t m, uint16_t s, uint16_t ms) {
+    fmtcmd("IhhhHHHHH", 0xffffff14UL, x, y, r, options, h, m, s, ms);
+}
+void GDClass::cmd_coldstart(void) {
+    cFFFFFF(0x32);
+}
+void GDClass::cmd_dial(int16_t x, int16_t y, int16_t r, uint16_t options, uint16_t val) {
+    fmtcmd("IhhhHH", 0xffffff2dUL, x, y, r, options, val);
+}
+void GDClass::cmd_dlstart(void) {
+    cFFFFFF(0x00);
+}
+void GDClass::cmd_fgcolor(uint32_t c) {
+    fmtcmd("II", 0xffffff0aUL, c);
+}
+void GDClass::cmd_gauge(int16_t x, int16_t y, int16_t r, uint16_t options, uint16_t major, uint16_t minor, uint16_t val, uint16_t range) {
+    fmtcmd("IhhhHHHHH", 0xffffff13UL, x, y, r, options, major, minor, val, range);
+}
+void GDClass::cmd_getmatrix(void) {
+    fmtcmd("Iiiiiii", 0xffffff33UL, 0, 0, 0, 0, 0, 0);
+}
+void GDClass::cmd_getprops(uint32_t &ptr, uint32_t &w, uint32_t &h) {
+    cFFFFFF(0x25);
+    ptr = GDTR.getwp();
+    cI(0);
+    w = GDTR.getwp();
+    cI(0);
+    h = GDTR.getwp();
+    cI(0);
+}
+void GDClass::cmd_getptr(void) {
+    fmtcmd("II", 0xffffff23UL, 0);
+}
+void GDClass::cmd_gradcolor(uint32_t c) {
+    fmtcmd("II", 0xffffff34UL, c);
+}
+void GDClass::cmd_gradient(int16_t x0, int16_t y0, uint32_t rgb0, int16_t x1, int16_t y1, uint32_t rgb1) {
+    fmtcmd("IhhIhhI", 0xffffff0bUL, x0, y0, rgb0, x1, y1, rgb1);
+}
+void GDClass::cmd_inflate(uint32_t ptr) {
+    cFFFFFF(0x22);
+    cI(ptr);
+}
+void GDClass::cmd_interrupt(uint32_t ms) {
+    fmtcmd("II", 0xffffff02UL, ms);
+}
+void GDClass::cmd_keys(int16_t x, int16_t y, int16_t w, int16_t h, byte font, uint16_t options, const char*s) {
+    fmtcmd("IhhhhhHs", 0xffffff0eUL, x, y, w, h, font, options, s);
+}
+void GDClass::cmd_loadidentity(void) {
+    cFFFFFF(0x26);
+}
+void GDClass::cmd_loadimage(uint32_t ptr, int32_t options) {
+    fmtcmd("III", 0xffffff24UL, ptr, options);
+}
+void GDClass::cmd_memcpy(uint32_t dest, uint32_t src, uint32_t num) {
+    fmtcmd("IIII", 0xffffff1dUL, dest, src, num);
+}
+void GDClass::cmd_memset(uint32_t ptr, byte value, uint32_t num) {
+    cFFFFFF(0x1b);
+    cI(ptr);
+    cI((uint32_t)value);
+    cI(num);
+}
+uint32_t GDClass::cmd_memcrc(uint32_t ptr, uint32_t num) {
+    cFFFFFF(0x18);
+    cI(ptr);
+    cI(num);
+    uint32_t r = GDTR.getwp();
+    cI(0xFFFFFFFF);
+    return r;
+}
+void GDClass::cmd_memwrite(uint32_t ptr, uint32_t num) {
+    fmtcmd("III", 0xffffff1aUL, ptr, num);
+}
+void GDClass::cmd_regwrite(uint32_t ptr, uint32_t val) {
+    cFFFFFF(0x1a);
+    cI(ptr);
+    cI(4UL);
+    cI(val);
+}
+void GDClass::cmd_number(int16_t x, int16_t y, byte font, uint16_t options, uint32_t n) {
+    // fmtcmd("IhhhHi", 0xffffff2eUL, x, y, font, options, n);
+    cFFFFFF(0x2e);
+    ch(x);
+    ch(y);
+    ch(font);
+    cH(options);
+    ci(n);
+}
+void GDClass::cmd_progress(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t options, uint16_t val, uint16_t range) {
+    fmtcmd("IhhhhHHH", 0xffffff0fUL, x, y, w, h, options, val, range);
+}
+void GDClass::cmd_regread(uint32_t ptr) {
+    fmtcmd("III", 0xffffff19UL, ptr, 0);
+}
+void GDClass::cmd_rotate(int32_t a) {
+    cFFFFFF(0x29);
+    ci(a);
+}
+void GDClass::cmd_scale(int32_t sx, int32_t sy) {
+    cFFFFFF(0x28);
+    ci(sx);
+    ci(sy);
+}
+void GDClass::cmd_screensaver(void) {
+    cFFFFFF(0x2f);
+}
+void GDClass::cmd_scrollbar(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t options, uint16_t val, uint16_t size, uint16_t range) {
+    fmtcmd("IhhhhHHHH", 0xffffff11UL, x, y, w, h, options, val, size, range);
+}
+void GDClass::cmd_setfont(byte font, uint32_t ptr) {
+    fmtcmd("III", 0xffffff2bUL, font, ptr);
+}
+void GDClass::cmd_setmatrix(void) {
+    cFFFFFF(0x2a);
+}
+void GDClass::cmd_sketch(int16_t x, int16_t y, uint16_t w, uint16_t h, uint32_t ptr, uint16_t format) {
+    cFFFFFF(0x30);
+    ch(x);
+    ch(y);
+    cH(w);
+    cH(h);
+    cI(ptr);
+    cI(format);
+}
+void GDClass::cmd_slider(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t options, uint16_t val, uint16_t range) {
+    fmtcmd("IhhhhHHH", 0xffffff10UL, x, y, w, h, options, val, range);
+}
+void GDClass::cmd_snapshot(uint32_t ptr) {
+    fmtcmd("II", 0xffffff1fUL, ptr);
+}
+void GDClass::cmd_spinner(int16_t x, int16_t y, byte style, byte scale) {
+    cFFFFFF(0x16);
+    ch(x);
+    ch(y);
+    cH(style);
+    cH(scale);
+}
+void GDClass::cmd_stop(void) {
+    cFFFFFF(0x17);
+}
+void GDClass::cmd_swap(void) {
+    cFFFFFF(0x01);
+}
+void GDClass::cmd_text(int16_t x, int16_t y, byte font, uint16_t options, const char *s) {
+    // fmtcmd("IhhhHs", 0xffffff0cUL, x, y, font, options, s);
+    cFFFFFF(0x0c);
+    ch(x);
+    ch(y);
+    ch(font);
+    cH(options);
+    cs(s);
+    align(strlen(s) + 1);
+}
+void GDClass::cmd_toggle(int16_t x, int16_t y, int16_t w, byte font, uint16_t options, uint16_t state, const char *s) {
+    fmtcmd("IhhhhHHs", 0xffffff12UL, x, y, w, font, options, state, s);
+}
+void GDClass::cmd_track(int16_t x, int16_t y, uint16_t w, uint16_t h, byte tag) {
+    fmtcmd("Ihhhhh", 0xffffff2cUL, x, y, w, h, tag);
+}
+void GDClass::cmd_translate(int32_t tx, int32_t ty) {
+    cFFFFFF(0x27);
+    ci(tx);
+    ci(ty);
+}
+
+byte GDClass::rd(uint32_t addr) 
+{
+    return GDTR.rd(addr);
+}
+void GDClass::wr(uint32_t addr, uint8_t v) 
+{
+    GDTR.wr(addr, v);
+}
+uint16_t GDClass::rd16(uint32_t addr) 
+{
+    return GDTR.rd16(addr);
+}
+void GDClass::wr16(uint32_t addr, uint16_t v) 
+{
+    GDTR.wr16(addr, v);
+}
+uint32_t GDClass::rd32(uint32_t addr) 
+{
+    return GDTR.rd32(addr);
+}
+void GDClass::wr32(uint32_t addr, uint32_t v) 
+{
+    GDTR.wr32(addr, v);
+}
+void GDClass::wr_n(uint32_t addr, byte *src, uint32_t n) 
+{
+    GDTR.wr_n(addr, src, n);
+}
+
+void GDClass::cmdbyte(uint8_t b) 
+{
+    GDTR.cmdbyte(b);
+}
+void GDClass::cmd32(uint32_t b) {
+    GDTR.cmd32(b);
+}
+void GDClass::finish(void) {
+    GDTR.finish();
+}
+void GDClass::get_accel(int &x, int &y, int &z) 
+{
+    static float f[3];
+    
+    for (byte i = 0; i < 3; i++) 
+    {
+        float a = accel[i]->read() * 1000;
+        // Serial.print(a, DEC); Serial.print(" ");
+        int s = (-160 * ((int)(a - 376)) >> 6);
+        f[i] = (((int)(3 * f[i])) >> 2) + (s >> 2);
+    }
+    // DEBUGOUT();
+    x = f[2];
+    y = f[1];
+    z = f[0];
+}
+void GDClass::get_inputs(void) {
+    GDTR.finish();
+    byte *bi = (byte*)&inputs;
+    GDTR.rd_n(bi, REG_TRACKER, 4);
+    GDTR.rd_n(bi + 4, REG_TOUCH_RZ, 13);
+    GDTR.rd_n(bi + 17, REG_TAG, 1);
+#if DUMP_INPUTS
+    for (size_t i = 0; i < sizeof(inputs); i++) {
+        DEBUGOUT("%x", bi[i]);
+        DEBUGOUT(" ");
+    }
+#endif
+}
+void GDClass::bulkrd(uint32_t a) {
+    GDTR.bulk(a);
+}
+void GDClass::resume(void) {
+    GDTR.resume();
+}
+void GDClass::__end(void) {
+    GDTR.__end();
+}
+void GDClass::play(uint8_t instrument, uint8_t note) {
+    wr16(REG_SOUND, (note << 8) | instrument);
+    wr(REG_PLAY, 1);
+}
+void GDClass::sample(uint32_t start, uint32_t len, uint16_t freq, uint16_t format, int loop) 
+{
+    wr32(REG_PLAYBACK_START, start);
+    wr32(REG_PLAYBACK_LENGTH, len);
+    wr16(REG_PLAYBACK_FREQ, freq);
+    wr(REG_PLAYBACK_FORMAT, format);
+    wr(REG_PLAYBACK_LOOP, loop);
+    wr(REG_PLAYBACK_PLAY, 1);
+}
+void GDClass::reset() {
+    GDTR.__end();
+    GDTR.wr(REG_CPURESET, 1);
+    GDTR.wr(REG_CPURESET, 0);
+    GDTR.resume();
+}
+
+
+// Load named file from storage
+// returns 0 on failure (e.g. file not found), 1 on success
+
+byte GDClass::load(const char *filename, void (*progress)(long, long))
+{
+#if defined(RASPBERRY_PI)
+    FILE *f = fopen(filename, "rb");
+    if (!f) {
+        perror(filename);
+        exit(1);
+    }
+    byte buf[512];
+    int n;
+    while ((n = fread(buf, 1, 512, f)) > 0) {
+        GDTR.cmd_n(buf, (n + 3) & ~3);
+    }
+    fclose(f);
+    return 1;
+#else
+    __end();
+    Reader* r = new Reader(GDTR.SPI(), SD);
+    if (r->openfile(filename)) 
+    {
+        byte buf[512];
+        while (r->offset < r->size) 
+        {
+            uint16_t n = min(512, r->size - r->offset);
+            n = (n + 3) & ~3;   // force 32-bit alignment
+            r->readsector(buf);
+
+            resume();
+            if (progress)
+                (*progress)(r->offset, r->size);
+            copyram(buf, n);
+            GDTR.stop();
+        }
+        resume();
+        delete r;
+        return 1;
+    }
+    resume();
+    delete r;
+    return 0;
+#endif
+}
+
+// Generated by mk_bsod.py. Blue screen with 'ERROR' text
+static const unsigned char __bsod[31] = {
+    0, 255, 255, 255, 255, 0, 0, 2, 7, 0, 0, 38, 12, 255, 255, 255, 240,
+    0, 120, 0, 28, 0, 0, 6, 69, 82, 82, 79, 82, 33, 0
+};
+// "Cannot open file" text
+static const unsigned char __bsod_badfile[31] = {
+    12, 255, 255, 255, 240, 0, 148, 0, 28, 0, 0, 6, 67, 97, 110, 110, 111,
+    116, 32, 111, 112, 101, 110, 32, 102, 105, 108, 101, 0, 0, 0
+};
+
+void GDClass::safeload(const char *filename)
+{
+    if (!load(filename)) {
+        copy(__bsod, sizeof(__bsod));
+        copy(__bsod_badfile, sizeof(__bsod_badfile));
+        cmd_text(240, 176, 28, OPT_CENTER, filename);
+        swap();
+        for (;;)
+            ;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GD2.h	Fri Apr 11 07:24:23 2014 +0000
@@ -0,0 +1,205 @@
+#ifndef     _GAMEDUINO2_H_
+#define     _GAMEDUINO2_H_
+
+#include "mbed.h"
+#include "arduino.h"
+#include "GDTransport.h"
+
+#define PROTO         1
+#define STORAGE       1
+#define CALIBRATION   0
+#define DUMP_INPUTS   0
+#define VERBOSE       0
+
+#define RGB(r, g, b)    ((uint32_t)((((r) & 0xffL) << 16) | (((g) & 0xffL) << 8) | ((b) & 0xffL)))
+#define F8(x)           (int((x) * 256L))
+#define F16(x)          ((int32_t)((x) * 65536L))
+
+#define GD_CALIBRATE    1
+#define GD_TRIM         2
+#define GD_STORAGE      4
+
+#define REG_TRIM        0x10256C
+#define LOW_FREQ_BOUND  47040000UL
+
+class sdcard;
+
+class GDClass
+{
+public:
+    GDClass(PinName mosi, PinName miso, PinName sclk, PinName graphic_cs, PinName sdcard_cs);
+
+    GDTransport GDTR;
+    sdcard *SD;
+    AnalogIn *accel[3];
+    PinName _sdcard_cs;
+
+    sdcard* getSD() { return SD; }
+    void begin(unsigned char options = (GD_CALIBRATE | GD_TRIM | GD_STORAGE));
+
+    unsigned short random();
+    unsigned short random(unsigned short n);
+    void seed(unsigned short n);
+    short rsin(short r, unsigned short th);
+    short rcos(short r, unsigned short th);
+    void polar(int &x, int &y, short r, unsigned short th);
+    unsigned short atan2(short y, short x);
+
+    void copy(const unsigned char *src, int count);
+    void copyram(unsigned char *src, int count);
+
+    void self_calibrate(void);
+
+    void swap(void);
+    void flush(void);
+    void finish(void);
+
+    void play(unsigned char instrument, unsigned char note = 0);
+    void sample(unsigned int start, unsigned int len, unsigned short freq, unsigned short format, int loop = 0);
+
+    void get_inputs(void);
+    void get_accel(int &x, int &y, int &z);
+    struct {
+        unsigned short track_tag;
+        unsigned short track_val;
+        unsigned short rz;
+        unsigned short __dummy_1;
+        short y;
+        short x;
+        short tag_y;
+        short tag_x;
+        unsigned char tag;
+        unsigned char ptag;
+    } inputs;
+
+    void AlphaFunc(unsigned char func, unsigned char ref);
+    void Begin(unsigned char prim);
+    void BitmapHandle(unsigned char handle);
+    void BitmapLayout(unsigned char format, unsigned short linestride, unsigned short height);
+    void BitmapSize(unsigned char filter, unsigned char wrapx, unsigned char wrapy, unsigned short width, unsigned short height);
+    void BitmapSource(unsigned int addr);
+    void BitmapTransformA(int a);
+    void BitmapTransformB(int b);
+    void BitmapTransformC(int c);
+    void BitmapTransformD(int d);
+    void BitmapTransformE(int e);
+    void BitmapTransformF(int f);
+    void BlendFunc(unsigned char src, unsigned char dst);
+    void Call(unsigned short dest);
+    void Cell(unsigned char cell);
+    void ClearColorA(unsigned char alpha);
+    void ClearColorRGB(unsigned char red, unsigned char green, unsigned char blue);
+    void ClearColorRGB(unsigned int rgb);
+    void Clear(unsigned char c, unsigned char s, unsigned char t);
+    void Clear(void);
+    void ClearStencil(unsigned char s);
+    void ClearTag(unsigned char s);
+    void ColorA(unsigned char alpha);
+    void ColorMask(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+    void ColorRGB(unsigned char red, unsigned char green, unsigned char blue);
+    void ColorRGB(unsigned int rgb);
+    void Display(void);
+    void End(void);
+    void Jump(unsigned short dest);
+    void LineWidth(unsigned short width);
+    void Macro(unsigned char m);
+    void PointSize(unsigned short size);
+    void RestoreContext(void);
+    void Return(void);
+    void SaveContext(void);
+    void ScissorSize(unsigned short width, unsigned short height);
+    void ScissorXY(unsigned short x, unsigned short y);
+    void StencilFunc(unsigned char func, unsigned char ref, unsigned char mask);
+    void StencilMask(unsigned char mask);
+    void StencilOp(unsigned char sfail, unsigned char spass);
+    void TagMask(unsigned char mask);
+    void Tag(unsigned char s);
+    void Vertex2f(short x, short y);
+    void Vertex2ii(unsigned short x, unsigned short y, unsigned char handle = 0, unsigned char cell = 0);
+
+    // Higher-level graphics commands
+
+    void cmd_append(unsigned int ptr, unsigned int num);
+    void cmd_bgcolor(unsigned int c);
+    void cmd_button(short x, short y, unsigned short w, unsigned short h, unsigned char font, unsigned short options, const char *s);
+    void cmd_calibrate(void);
+    void cmd_clock(short x, short y, short r, unsigned short options, unsigned short h, unsigned short m, unsigned short s, unsigned short ms);
+    void cmd_coldstart(void);
+    void cmd_dial(short x, short y, short r, unsigned short options, unsigned short val);
+    void cmd_dlstart(void);
+    void cmd_fgcolor(unsigned int c);
+    void cmd_gauge(short x, short y, short r, unsigned short options, unsigned short major, unsigned short minor, unsigned short val, unsigned short range);
+    void cmd_getmatrix(void);
+    void cmd_getprops(unsigned int &ptr, unsigned int &w, unsigned int &h);
+    void cmd_getptr(void);
+    void cmd_gradcolor(unsigned int c);
+    void cmd_gradient(short x0, short y0, unsigned int rgb0, short x1, short y1, unsigned int rgb1);
+    void cmd_inflate(unsigned int ptr);
+    void cmd_interrupt(unsigned int ms);
+    void cmd_keys(short x, short y, short w, short h, unsigned char font, unsigned short options, const char*s);
+    void cmd_loadidentity(void);
+    void cmd_loadimage(unsigned int ptr, int options);
+    void cmd_memcpy(unsigned int dest, unsigned int src, unsigned int num);
+    void cmd_memset(unsigned int ptr, unsigned char value, unsigned int num);
+    unsigned int cmd_memcrc(unsigned int ptr, unsigned int num);
+    void cmd_memwrite(unsigned int ptr, unsigned int num);
+    void cmd_regwrite(unsigned int ptr, unsigned int val);
+    void cmd_number(short x, short y, unsigned char font, unsigned short options, unsigned int n);
+    void cmd_progress(short x, short y, short w, short h, unsigned short options, unsigned short val, unsigned short range);
+    void cmd_regread(unsigned int ptr);
+    void cmd_rotate(int a);
+    void cmd_scale(int sx, int sy);
+    void cmd_screensaver(void);
+    void cmd_scrollbar(short x, short y, short w, short h, unsigned short options, unsigned short val, unsigned short size, unsigned short range);
+    void cmd_setfont(unsigned char font, unsigned int ptr);
+    void cmd_setmatrix(void);
+    void cmd_sketch(short x, short y, unsigned short w, unsigned short h, unsigned int ptr, unsigned short format);
+    void cmd_slider(short x, short y, unsigned short w, unsigned short h, unsigned short options, unsigned short val, unsigned short range);
+    void cmd_snapshot(unsigned int ptr);
+    void cmd_spinner(short x, short y, unsigned char style, unsigned char scale);
+    void cmd_stop(void);
+    void cmd_swap(void);
+    void cmd_text(short x, short y, unsigned char font, unsigned short options, const char *s);
+    void cmd_toggle(short x, short y, short w, unsigned char font, unsigned short options, unsigned short state, const char *s);
+    void cmd_track(short x, short y, unsigned short w, unsigned short h, unsigned char tag);
+    void cmd_translate(int tx, int ty);
+
+    unsigned char rd(unsigned int addr);
+    void wr(unsigned int addr, unsigned char v);
+    unsigned short rd16(unsigned int addr);
+    void wr16(unsigned int addr, unsigned short v);
+    unsigned int rd32(unsigned int addr);
+    void wr32(unsigned int addr, unsigned int v);
+    void wr_n(unsigned int addr, unsigned char *src, unsigned int n);
+
+    void cmd32(unsigned int b);
+
+    void bulkrd(unsigned int a);
+    void resume(void);
+    void __end(void);
+    void reset(void);
+
+    void dumpscreen(void);
+    unsigned char load(const char *filename, void (*progress)(long, long) = NULL);
+    void safeload(const char *filename);
+
+    void storage(void);
+    void tune(void);
+
+private:
+    void cFFFFFF(unsigned char v);
+    void cI(unsigned int);
+    void ci(int);
+    void cH(unsigned short);
+    void ch(short);
+    void cs(const char *);
+    void fmtcmd(const char *fmt, ...);
+
+    void align(unsigned char n);
+    void cmdbyte(unsigned char b);
+
+    unsigned int measure_freq(void);
+
+    unsigned short lfsr, lcg;
+};
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GDTransport.h	Fri Apr 11 07:24:23 2014 +0000
@@ -0,0 +1,524 @@
+#ifndef _GDTRANSPORT_H_
+#define _GDTRANSPORT_H_
+
+#include "mbed.h"
+#include "arduino.h"
+
+#ifndef DEBUGOUT
+//#define DEBUGOUT (x,...)   std::printf(x, ##y);
+#define DEBUGOUT(x, ...) std::printf(""x"\r\n", ##__VA_ARGS__);
+#endif
+
+// Convert degrees to Furmans
+#define DEGREES(n) ((65536UL * (n)) / 360)
+
+#define NEVER                0
+#define LESS                 1
+#define LEQUAL               2
+#define GREATER              3
+#define GEQUAL               4
+#define EQUAL                5
+#define NOTEQUAL             6
+#define ALWAYS               7
+
+#define ARGB1555             0
+#define L1                   1
+#define L4                   2
+#define L8                   3
+#define RGB332               4
+#define ARGB2                5
+#define ARGB4                6
+#define RGB565               7
+#define PALETTED             8
+#define TEXT8X8              9
+#define TEXTVGA              10
+#define BARGRAPH             11
+
+#define NEAREST              0
+#define BILINEAR             1
+
+#define BORDER               0
+#define REPEAT               1
+
+#define KEEP                 1
+#define REPLACE              2
+#define INCR                 3
+#define DECR                 4
+#define INVERT               5
+
+#define DLSWAP_DONE          0
+#define DLSWAP_LINE          1
+#define DLSWAP_FRAME         2
+
+#define INT_SWAP             1
+#define INT_TOUCH            2
+#define INT_TAG              4
+#define INT_SOUND            8
+#define INT_PLAYBACK         16
+#define INT_CMDEMPTY         32
+#define INT_CMDFLAG          64
+#define INT_CONVCOMPLETE     128
+
+#define TOUCHMODE_OFF        0
+#define TOUCHMODE_ONESHOT    1
+#define TOUCHMODE_FRAME      2
+#define TOUCHMODE_CONTINUOUS 3
+
+#define ZERO                 0
+#define ONE                  1
+#define SRC_ALPHA            2
+#define DST_ALPHA            3
+#define ONE_MINUS_SRC_ALPHA  4
+#define ONE_MINUS_DST_ALPHA  5
+
+#define BITMAPS              1
+#define POINTS               2
+#define LINES                3
+#define LINE_STRIP           4
+#define EDGE_STRIP_R         5
+#define EDGE_STRIP_L         6
+#define EDGE_STRIP_A         7
+#define EDGE_STRIP_B         8
+#define RECTS                9
+
+#define OPT_MONO             1
+#define OPT_NODL             2
+#define OPT_FLAT             256
+#define OPT_CENTERX          512
+#define OPT_CENTERY          1024
+#define OPT_CENTER           (OPT_CENTERX | OPT_CENTERY)
+#define OPT_NOBACK           4096
+#define OPT_NOTICKS          8192
+#define OPT_NOHM             16384
+#define OPT_NOPOINTER        16384
+#define OPT_NOSECS           32768
+#define OPT_NOHANDS          49152
+#define OPT_RIGHTX           2048
+#define OPT_SIGNED           256
+
+#define LINEAR_SAMPLES       0
+#define ULAW_SAMPLES         1
+#define ADPCM_SAMPLES        2
+
+// 'instrument' argument to GD.play()
+
+#define SILENCE              0x00
+
+#define SQUAREWAVE           0x01
+#define SINEWAVE             0x02
+#define SAWTOOTH             0x03
+#define TRIANGLE             0x04
+
+#define BEEPING              0x05
+#define ALARM                0x06
+#define WARBLE               0x07
+#define CAROUSEL             0x08
+
+#define PIPS(n)              (0x0f + (n))
+
+#define HARP                 0x40
+#define XYLOPHONE            0x41
+#define TUBA                 0x42
+#define GLOCKENSPIEL         0x43
+#define ORGAN                0x44
+#define TRUMPET              0x45
+#define PIANO                0x46
+#define CHIMES               0x47
+#define MUSICBOX             0x48
+#define BELL                 0x49
+
+#define CLICK                0x50
+#define SWITCH               0x51
+#define COWBELL              0x52
+#define NOTCH                0x53
+#define HIHAT                0x54
+#define KICKDRUM             0x55
+#define POP                  0x56
+#define CLACK                0x57
+#define CHACK                0x58
+
+#define MUTE                 0x60
+#define UNMUTE               0x61
+
+#define RAM_CMD              1081344UL
+#define RAM_DL               1048576UL
+#define RAM_PAL              1056768UL
+
+#define REG_CLOCK            1057800UL
+#define REG_CMD_DL           1058028UL
+#define REG_CMD_READ         1058020UL
+#define REG_CMD_WRITE        1058024UL
+#define REG_CPURESET         1057820UL
+#define REG_CSPREAD          1057892UL
+#define REG_DITHER           1057884UL
+#define REG_DLSWAP           1057872UL
+#define REG_FRAMES           1057796UL
+#define REG_FREQUENCY        1057804UL
+#define REG_GPIO             1057936UL
+#define REG_GPIO_DIR         1057932UL
+#define REG_HCYCLE           1057832UL
+#define REG_HOFFSET          1057836UL
+#define REG_HSIZE            1057840UL
+#define REG_HSYNC0           1057844UL
+#define REG_HSYNC1           1057848UL
+#define REG_ID               1057792UL
+#define REG_INT_EN           1057948UL
+#define REG_INT_FLAGS        1057944UL
+#define REG_INT_MASK         1057952UL
+#define REG_MACRO_0          1057992UL
+#define REG_MACRO_1          1057996UL
+#define REG_OUTBITS          1057880UL
+#define REG_PCLK             1057900UL
+#define REG_PCLK_POL         1057896UL
+#define REG_PLAY             1057928UL
+#define REG_PLAYBACK_FORMAT  1057972UL
+#define REG_PLAYBACK_FREQ    1057968UL
+#define REG_PLAYBACK_LENGTH  1057960UL
+#define REG_PLAYBACK_LOOP    1057976UL
+#define REG_PLAYBACK_PLAY    1057980UL
+#define REG_PLAYBACK_READPTR 1057964UL
+#define REG_PLAYBACK_START   1057956UL
+#define REG_PWM_DUTY         1057988UL
+#define REG_PWM_HZ           1057984UL
+#define REG_ROTATE           1057876UL
+#define REG_SOUND            1057924UL
+#define REG_SWIZZLE          1057888UL
+#define REG_TAG              1057912UL
+#define REG_TAG_X            1057904UL
+#define REG_TAG_Y            1057908UL
+#define REG_TOUCH_ADC_MODE   1058036UL
+#define REG_TOUCH_CHARGE     1058040UL
+#define REG_TOUCH_DIRECT_XY  1058164UL
+#define REG_TOUCH_DIRECT_Z1Z2 1058168UL
+#define REG_TOUCH_MODE       1058032UL
+#define REG_TOUCH_OVERSAMPLE 1058048UL
+#define REG_TOUCH_RAW_XY     1058056UL
+#define REG_TOUCH_RZ         1058060UL
+#define REG_TOUCH_RZTHRESH   1058052UL
+#define REG_TOUCH_SCREEN_XY  1058064UL
+#define REG_TOUCH_SETTLE     1058044UL
+#define REG_TOUCH_TAG        1058072UL
+#define REG_TOUCH_TAG_XY     1058068UL
+#define REG_TOUCH_TRANSFORM_A 1058076UL
+#define REG_TOUCH_TRANSFORM_B 1058080UL
+#define REG_TOUCH_TRANSFORM_C 1058084UL
+#define REG_TOUCH_TRANSFORM_D 1058088UL
+#define REG_TOUCH_TRANSFORM_E 1058092UL
+#define REG_TOUCH_TRANSFORM_F 1058096UL
+#define REG_TRACKER          1085440UL
+#define REG_VCYCLE           1057852UL
+#define REG_VOFFSET          1057856UL
+#define REG_VOL_PB           1057916UL
+#define REG_VOL_SOUND        1057920UL
+#define REG_VSIZE            1057860UL
+#define REG_VSYNC0           1057864UL
+#define REG_VSYNC1           1057868UL
+
+#define VERTEX2II(x, y, handle, cell) \
+    ((2UL << 30) | (((x) & 511UL) << 21) | (((y) & 511UL) << 12) | (((handle) & 31) << 7) | (((cell) & 127) << 0))
+
+#define ROM_PIXEL_FF        0xc0400UL
+
+class GDTransport {
+protected:
+    SPI _spi;
+    DigitalOut _cs;
+    
+    byte streaming;
+    uint16_t wp;
+    uint16_t freespace;
+
+public:
+    GDTransport(PinName mosi, PinName miso, PinName sclk, PinName cs)
+        : _spi(mosi, miso, sclk)
+        , _cs(cs)
+    {
+    }
+
+    void begin() 
+    {   
+        _spi.format(8, 0);
+        _spi.frequency(10000000);
+     
+        _cs = 1;   
+        
+        hostcmd(0x00); // FT_GPU_ACTIVE_M
+
+        hostcmd(0x62); // Switch PLL output to 48MHz
+            
+        hostcmd(0x68); // FT_GPU_CORE_RESET
+        
+        _spi.frequency(16000000);
+        
+        byte chipid = rd(REG_ID);
+    
+        DEBUGOUT("0x%x", chipid);
+        
+        wp = 0;
+        freespace = 4096 - 4;
+
+        stream();
+    }
+    
+    SPI* SPI()
+    {
+        return &_spi;
+    }
+
+    void cmd32(uint32_t x) 
+    {
+        if (freespace < 4) 
+        {
+            getfree(4);
+        }
+        wp += 4;
+        freespace -= 4;
+        union 
+        {
+            uint32_t c;
+            uint8_t b[4];
+        };
+        c = x;
+        _spi.write(b[0]);
+        _spi.write(b[1]);
+        _spi.write(b[2]);
+        _spi.write(b[3]);
+    }
+    void cmdbyte(byte x) 
+    {
+        if (freespace == 0) 
+        {
+            getfree(1);
+        }
+        wp++;
+        freespace--;
+        _spi.write(x);
+    }
+    void cmd_n(byte *s, uint16_t n) 
+    {
+        if (freespace < n) 
+        {
+            getfree(n);
+        }
+        wp += n;
+        freespace -= n;
+        while (n > 8) 
+        {
+            n -= 8;
+            _spi.write(*s++);
+            _spi.write(*s++);
+            _spi.write(*s++);
+            _spi.write(*s++);
+            _spi.write(*s++);
+            _spi.write(*s++);
+            _spi.write(*s++);
+            _spi.write(*s++);
+        }
+        while (n--)
+            _spi.write(*s++);
+    }
+
+    void flush() 
+    {
+        getfree(0);
+    }
+    uint16_t rp() 
+    {
+        uint16_t r = __rd16(REG_CMD_READ);
+        
+        if (r == 0xfff) 
+        {
+            for (;;) ;
+        }
+        return r;
+    }
+    void finish() 
+    {
+        wp &= 0xffc;
+        __end();
+        __wr16(REG_CMD_WRITE, wp);
+
+        while (rp() != wp);
+       
+        stream();
+    }
+
+    byte rd(uint32_t addr)
+    {
+        __end(); // stop streaming
+        __start(addr);
+        byte r = _spi.write(0);
+        stream();
+        
+        return r;
+    }
+
+    void wr(uint32_t addr, byte v)
+    {
+        __end(); // stop streaming
+        __wstart(addr);
+        _spi.write(v);
+        stream();
+    }
+
+    uint16_t rd16(uint32_t addr)
+    {
+        uint16_t r = 0;
+        __end(); // stop streaming
+        __start(addr);
+        r = _spi.write(0);
+        r |= (_spi.write(0) << 8);
+        stream();
+        return r;
+    }
+
+    void wr16(uint32_t addr, uint32_t v)
+    {
+        __end(); // stop streaming
+        __wstart(addr);
+        
+        _spi.write(v);
+        _spi.write(v >> 8);
+        stream();
+    }
+
+    uint32_t rd32(uint32_t addr)
+    {
+        __end(); // stop streaming
+        __start(addr);
+//        _spi.write(0);
+        union {
+            uint32_t c;
+            uint8_t b[4];
+        };
+        b[0] = _spi.write(0);
+        b[1] = _spi.write(0);
+        b[2] = _spi.write(0);
+        b[3] = _spi.write(0);
+        stream();
+        return c;
+    }
+    void rd_n(byte *dst, uint32_t addr, uint16_t n)
+    {
+        __end(); // stop streaming
+        __start(addr);
+//        _spi.write(0);
+        while (n--)
+            *dst++ = _spi.write(0);
+        stream();
+    }
+    void wr_n(uint32_t addr, byte *src, uint16_t n)
+    {
+        __end(); // stop streaming
+        __wstart(addr);
+        while (n--)
+            _spi.write(*src++);
+        stream();
+    }
+
+    void wr32(uint32_t addr, unsigned long v)
+    {
+        __end(); // stop streaming
+        __wstart(addr);
+        _spi.write(v);
+        _spi.write(v >> 8);
+        _spi.write(v >> 16);
+        _spi.write(v >> 24);
+        stream();
+    }
+
+    uint32_t getwp(void) 
+    {
+        return RAM_CMD + (wp & 0xffc);
+    }
+
+    void bulk(uint32_t addr) 
+    {
+        __end(); // stop streaming
+        __start(addr);
+    }
+    void resume(void) 
+    {
+        stream();
+    }
+
+    void __start(uint32_t addr) // start an SPI transaction to addr
+    {
+        _cs = 0;
+        _spi.write(addr >> 16);
+        _spi.write(addr >> 8);
+        _spi.write(addr & 0xff );
+        _spi.write(0);
+    }
+
+    void __wstart(uint32_t addr) // start an SPI write transaction to addr
+    {
+        _cs = 0;
+        _spi.write(0x80 | (addr >> 16));
+        _spi.write(addr >> 8);
+        _spi.write(addr & 0xff);
+    }
+
+    void __end() // end the SPI transaction
+    {
+        _cs = 1;
+    }
+
+    void stop() // end the SPI transaction
+    {
+        wp &= 0xffc;
+        __end();
+        __wr16(REG_CMD_WRITE, wp);
+    }
+
+    void stream(void) {
+        __end();
+        __wstart(RAM_CMD + (wp & 0xfff));
+    }
+
+    uint32_t __rd16(uint32_t addr)
+    {
+        uint32_t r;
+        
+        __start(addr);
+        r = _spi.write(0);
+        r |= (_spi.write(0) << 8);
+        __end();
+        return r;
+    }
+
+    void __wr16(uint32_t addr, uint32_t v)
+    {
+        __wstart(addr);
+        _spi.write(lowByte(v));
+        _spi.write(highByte(v));
+        __end();
+    }
+
+    void hostcmd(byte a)
+    {
+        _cs = 0;
+
+        _spi.write(a);
+        _spi.write(0x00);
+        _spi.write(0x00);
+        
+        _cs = 1;
+        
+        delay(60);
+    }
+
+    void getfree(uint16_t n)
+    {
+        wp &= 0xfff;
+        __end();
+        __wr16(REG_CMD_WRITE, wp & 0xffc);
+        do {
+            uint16_t fullness = (wp - rp()) & 4095;
+            freespace = (4096 - 4) - fullness;
+        } while (freespace < n);
+        stream();
+    }
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Utils.h	Fri Apr 11 07:24:23 2014 +0000
@@ -0,0 +1,600 @@
+#ifndef _UTILS_H_
+#define _UTILS_H_
+
+#include "arduino.h"
+
+void loop();
+
+#define LOOP    while(1) loop()
+
+typedef struct {
+    byte handle;
+    uint16_t w, h;
+    uint16_t size;
+} shape_t;
+
+struct direntry
+{
+    char name[8];
+    char ext[3];
+    uint8_t attribute;
+    uint8_t reserved[8];
+    uint16_t cluster_hi;  // FAT32 only
+    uint16_t time;
+    uint16_t date;
+    uint16_t cluster;
+    uint32_t size;
+};
+
+// https://www.sdcard.org/downloads/pls/simplified_specs/Part_1_Physical_Layer_Simplified_Specification_Ver_3.01_Final_100518.pdf
+// page 22
+// http://mac6.ma.psu.edu/space2008/RockSat/microController/sdcard_appnote_foust.pdf
+// http://elm-chan.org/docs/mmc/mmc_e.html
+// http://www.pjrc.com/tech/8051/ide/fat32.html
+
+#define FAT16 0
+#define FAT32 1
+
+class sdcard 
+{
+public:
+    SPI* _spi;
+    DigitalOut _cs;
+    uint8_t ccs;
+
+    uint8_t type;
+    uint16_t sectors_per_cluster;
+    uint16_t reserved_sectors;
+    uint16_t max_root_dir_entries;
+    uint16_t sectors_per_fat;
+    uint16_t cluster_size;
+    uint32_t root_dir_first_cluster;
+
+    // These are all linear addresses, hence the o_ prefix
+    uint32_t o_partition;
+    uint32_t o_fat;
+    uint32_t o_root;
+    uint32_t o_data;
+public:
+    sdcard(SPI* spi, PinName cs) : _cs(cs)
+    {
+        _spi = spi;
+    }
+    
+    void sel() 
+    {
+        _cs = 0;
+        delay(1);
+    }
+    void desel() 
+    {
+        _cs = 1;
+        _spi->write(0xff); // force DO release
+    }
+    void sd_delay(uint8_t n) 
+    {
+        while (n--)
+            _spi->write(0xff);
+    }
+
+    void cmd(uint8_t cmd, uint32_t lba = 0, uint8_t crc = 0x95) 
+    {
+        sel();
+        _spi->write(0xff);
+        _spi->write(0x40 | cmd);
+        _spi->write(0xff & (lba >> 24));
+        _spi->write(0xff & (lba >> 16));
+        _spi->write(0xff & (lba >> 8));
+        _spi->write(0xff & (lba));
+        _spi->write(crc);
+        _spi->write(0xff);
+    }
+
+    uint8_t R1() 
+    {   // read response R1
+        uint8_t r;
+        while ((r = _spi->write(0xff)) & 0x80)
+            ;
+        desel();
+        _spi->write(0xff);   // trailing uint8_t
+        return r;
+    }
+
+    uint8_t sdR3(uint32_t &ocr) 
+    {  // read response R3
+        uint32_t r;
+        while ((r = _spi->write(0xff)) & 0x80)
+            ;
+        for (uint8_t i = 4; i; i--)
+            ocr = (ocr << 8) | _spi->write(0xff);
+        _spi->write(0xff);   // trailing uint8_t
+
+        desel();
+        return r;
+    }
+
+    uint8_t sdR7() 
+    {  // read response R3
+        uint32_t r;
+        while ((r = _spi->write(0xff)) & 0x80)
+            ;
+        for (uint8_t i = 4; i; i--)
+            // Serial.println(____spi->write(0xff), HEX);
+            _spi->write(0xff);
+        desel();
+
+        return r;
+    }
+
+    void appcmd(uint8_t cc, uint32_t lba = 0) 
+    {
+        cmd(55); R1();
+        cmd(cc, lba);
+    }
+
+    void begin() 
+    {
+        uint8_t type_code;
+        uint8_t sdhc;
+
+        desel();
+
+        delay(10);      // wait for boot
+        sd_delay(10);   // deselected, 80 pulses
+
+        // Tty.printf("Attempting card reset... ");
+        // attempt reset
+        uint8_t r1;
+        int attempts = 0;
+        do 
+        {       // reset, enter idle
+            cmd(0);
+            while ((r1 = _spi->write(0xff)) & 0x80)
+                if (++attempts == 1000)
+                    return;
+            desel();
+            _spi->write(0xff);   // trailing uint8_t
+        } while (r1 != 1);
+        // Tty.printf("reset ok\n");
+
+        sdhc = 0;
+        cmd(8, 0x1aa, 0x87);
+        r1 = sdR7();
+        sdhc = (r1 == 1);
+
+        // Tty.printf("card %s SDHC\n", sdhc ? "is" : "is not");
+
+        // Tty.printf("Sending card init command... ");
+        while (1) 
+        {
+            appcmd(41, sdhc ? (1UL << 30) : 0); // card init
+            r1 = R1();
+            if ((r1 & 1) == 0)
+                break;
+            delay(100);
+        }
+        // Tty.printf("OK\n");
+
+        if (sdhc) 
+        {
+            cmd(58);
+            uint32_t OCR = 0;
+            sdR3(OCR);
+            ccs = 1UL & (OCR >> 30);
+            // Tty.printf("OCR register is %#010lx\n", long(OCR));
+        }
+
+        else 
+        {
+            ccs = 0;
+        }
+        // Tty.printf("ccs = %d\n", ccs);
+        // REPORT(ccs);
+
+        type_code = rd(0x1be + 0x4);
+        
+        switch (type_code) 
+        {
+            default:
+                type = FAT16;
+                break;
+            case 0x0b:
+            case 0x0c:
+                type = FAT32;
+                break;
+        }
+        // REPORT(type_code);
+        // Tty.printf("Type code %#02x means FAT%d\n", type_code, (type == FAT16) ? 16 : 32);
+#if VERBOSE
+        DEBUGOUT("Type ");
+        DEBUGOUT("%x", type_code);
+        DEBUGOUT(" so FAT");
+        DEBUGOUT("%d\r\n", (type == FAT16) ? 16 : 32);
+#endif
+
+        o_partition = 512L * rd4(0x1be + 0x8);
+        sectors_per_cluster = rd(o_partition + 0xd);
+        reserved_sectors = rd2(o_partition + 0xe);
+        cluster_size = 512L * sectors_per_cluster;
+        // REPORT(sectors_per_cluster);
+
+        // Tty.printf("Bytes per sector:    %d\n", rd2(o_partition + 0xb));
+        // Tty.printf("Sectors per cluster: %d\n", sectors_per_cluster);
+
+        if (type == FAT16) 
+        {
+            max_root_dir_entries = rd2(o_partition + 0x11);
+            sectors_per_fat = rd2(o_partition + 0x16);
+            o_fat = o_partition + 512L * reserved_sectors;
+            o_root = o_fat + (2 * 512L * sectors_per_fat);
+            // data area starts with cluster 2, so offset it here
+            o_data = o_root + (max_root_dir_entries * 32L) - (2L * cluster_size);
+        }
+
+        else 
+        {
+            uint32_t sectors_per_fat = rd4(o_partition + 0x24);
+            root_dir_first_cluster = rd4(o_partition + 0x2c);
+            uint32_t fat_begin_lba = (o_partition >> 9) + reserved_sectors;
+            uint32_t cluster_begin_lba = (o_partition >> 9) + reserved_sectors + (2 * sectors_per_fat);
+
+            o_fat = 512L * fat_begin_lba;
+            o_root = (512L * (cluster_begin_lba + (root_dir_first_cluster - 2) * sectors_per_cluster));
+            o_data = (512L * (cluster_begin_lba - 2 * sectors_per_cluster));
+        }
+    }
+    
+    static char toupper(char sv)
+    {
+        char c = sv;
+        if( sv >= 'a' && sv <= 'z')
+            c = sv - ('a' - 'A');
+        
+        return c;
+    }
+    
+    void cmd17(uint32_t off) 
+    {
+        if (ccs)
+            cmd(17, off >> 9);
+        else
+            cmd(17, off & ~511L);
+        R1();
+        sel();
+        while (_spi->write(0xff) != 0xfe)
+            ;
+    }
+
+    void rdn(uint8_t *d, uint32_t off, uint16_t n) 
+    {
+        cmd17(off);
+        uint16_t i;
+        uint16_t bo = (off & 511);
+        for (i = 0; i < bo; i++)
+            _spi->write(0xff);
+        for (i = 0; i < n; i++)
+            *d++ = _spi->write(0xff);
+        for (i = 0; i < (514 - bo - n); i++)
+            _spi->write(0xff);
+        desel();
+    }
+
+    uint32_t rd4(uint32_t off) 
+    {
+        uint32_t r;
+        rdn((uint8_t*)&r, off, sizeof(r));
+        return r;
+    }
+
+    uint16_t rd2(uint32_t off) 
+    {
+        uint16_t r;
+        rdn((uint8_t*)&r, off, sizeof(r));
+        return r;
+    }
+
+    uint8_t rd(uint32_t off) 
+    {
+        uint8_t r;
+        rdn((uint8_t*)&r, off, sizeof(r));
+        return r;
+    }
+};
+
+static void dos83(uint8_t dst[11], const char *ps)
+{
+    uint8_t i = 0;
+    while (*ps) 
+    {
+        if (*ps != '.')
+            dst[i++] = sdcard::toupper(*ps);
+        else 
+        {
+            while (i < 8)
+                dst[i++] = ' ';
+        }
+        ps++;
+    }
+    while (i < 11)
+        dst[i++] = ' ';
+}
+
+class Reader 
+{
+    SPI* _spi;
+    sdcard* _sd;
+public:
+    Reader(SPI* spi, sdcard* sd)
+    {
+        _spi = spi;
+        _sd = sd;
+    }
+
+public:
+    int openfile(const char *filename) 
+    {
+        int i = 0;
+        uint8_t dosname[11] = {0, };
+        direntry de = {0, };
+
+        dos83(dosname, filename);
+        
+        do {
+            _sd->rdn((uint8_t*)&de, _sd->o_root + i * 32, sizeof(de));
+            if (0 == memcmp(de.name, dosname, 11)) 
+            {
+                DEBUGOUT("begin(de)\r\n");
+                begin(de);
+                return 1;
+            }
+            i++;
+        } while (de.name[0]);
+        return 0;
+    }
+
+    void begin(direntry &de) 
+    {
+        size = de.size;
+        cluster = de.cluster;
+        if (_sd->type == FAT32)
+            cluster |= ((long)de.cluster_hi << 16);
+        sector = 0;
+        offset = 0;
+    }
+
+    void nextcluster() 
+    {
+        if (_sd->type == FAT16)
+            cluster = _sd->rd2(_sd->o_fat + 2 * cluster);
+        else
+            cluster = _sd->rd4(_sd->o_fat + 4 * cluster);
+#if VERBOSE
+        DEBUGOUT("nextcluster=");
+        DEBUGOUT("%d\r\n", cluster);
+#endif
+    }
+
+    void skipcluster() 
+    {
+        nextcluster();
+        offset += _sd->cluster_size;
+    }
+    void skipsector() 
+    {
+        if (sector == _sd->sectors_per_cluster) {
+            sector = 0;
+            nextcluster();
+        }
+        sector++;
+        offset += 512;
+    }
+
+    void seek(uint32_t o) 
+    {
+        while (offset < o) 
+        {
+            if ((sector == _sd->sectors_per_cluster) && ((o - offset) > (long)_sd->cluster_size))
+                skipcluster();
+            else
+                skipsector();
+        }
+    }
+    void readsector() 
+    {
+        if (sector == _sd->sectors_per_cluster) 
+        {
+            sector = 0;
+            nextcluster();
+        }
+        uint32_t off = _sd->o_data + ((long)_sd->cluster_size * cluster) + (512L * sector);
+#if VERBOSE
+        DEBUGOUT("off=0x");
+        DEBUGOUT("%x", off);
+#endif
+        _sd->cmd17(off & ~511L);
+        // Serial.println(2 * (micros() - t0), DEC);
+        sector++;
+        offset += 512;
+    }
+    void readsector(uint8_t *dst) 
+    {
+        readsector();
+        for (int i = 0; i < 64; i++) {
+            *dst++ = _spi->write(0xff);
+            *dst++ = _spi->write(0xff);
+            *dst++ = _spi->write(0xff);
+            *dst++ = _spi->write(0xff);
+            *dst++ = _spi->write(0xff);
+            *dst++ = _spi->write(0xff);
+            *dst++ = _spi->write(0xff);
+            *dst++ = _spi->write(0xff);
+        }
+        _spi->write(0xff);   // consume CRC
+        _spi->write(0xff);
+        _sd->desel();
+    }
+    uint32_t cluster;
+    uint32_t offset;
+    uint32_t size;
+    uint8_t sector;
+};
+
+class Poly 
+{
+public:
+    GDClass* _gd;
+    Poly(GDClass* gd)
+    {
+        _gd = gd;
+    }
+    
+    int x0, y0, x1, y1;
+    int x[8], y[8];
+    uint8_t n;
+
+    void restart() 
+    {
+        n = 0;
+        x0 = 16 * 480;
+        x1 = 0;
+        y0 = 16 * 272;
+        y1 = 0;
+    }
+
+    void perim() 
+    {
+        for (uint8_t i = 0; i < n; i++)
+            _gd->Vertex2f(x[i], y[i]);
+        _gd->Vertex2f(x[0], y[0]);
+    }
+public:
+    void begin() 
+    {
+        restart();
+
+        _gd->ColorMask(0,0,0,0);
+        _gd->StencilOp(KEEP, INVERT);
+        _gd->StencilFunc(ALWAYS, 255, 255);
+    }
+
+    void v(int _x, int _y) 
+    {
+        x0 = min(x0, _x >> 4);
+        x1 = max(x1, _x >> 4);
+        y0 = min(y0, _y >> 4);
+        y1 = max(y1, _y >> 4);
+        x[n] = _x;
+        y[n] = _y;
+        n++;
+    }
+
+    void paint() 
+    {
+        x0 = max(0, x0);
+        y0 = max(0, y0);
+        x1 = min(16 * 480, x1);
+        y1 = min(16 * 272, y1);
+        _gd->ScissorXY(x0, y0);
+        _gd->ScissorSize(x1 - x0 + 1, y1 - y0 + 1);
+        _gd->Begin(EDGE_STRIP_B);
+        perim();
+    }
+
+    void finish() 
+    {
+        _gd->ColorMask(1,1,1,1);
+        _gd->StencilFunc(EQUAL, 255, 255);
+
+        _gd->Begin(EDGE_STRIP_B);
+        _gd->Vertex2ii(0, 0);
+        _gd->Vertex2ii(511, 0);
+    }
+
+    void draw() 
+    {
+        paint();
+        finish();
+    }
+
+    void outline() 
+    {
+        _gd->Begin(LINE_STRIP);
+        perim();
+    }
+};
+
+class Streamer 
+{
+public:
+    GDClass* _gd;
+    
+    Streamer(GDClass* gd, sdcard* sd)
+    {
+        r = new Reader(gd->GDTR.SPI(), sd);
+        _gd = gd;
+    }
+    void begin(const char *rawsamples,
+        uint16_t freq = 44100,
+        uint8_t format = ADPCM_SAMPLES,
+        uint32_t _base = (0x40000UL - 8192), uint16_t size = 8192) 
+    {
+            r->openfile(rawsamples);
+
+            base = _base;
+            mask = size - 1;
+            wp = 0;
+
+            for (uint8_t i = 10; i; i--)
+                feed();
+
+            _gd->sample(base, size, freq, format, 1);
+    }
+
+    int feed() 
+    {
+        uint16_t rp = _gd->rd32(REG_PLAYBACK_READPTR) - base;
+        uint16_t freespace = mask & ((rp - 1) - wp);
+        if (freespace >= 512) {
+            // REPORT(base);
+            // REPORT(rp);
+            // REPORT(wp);
+            // REPORT(freespace);
+            // DEBUGOUT("\r\n");
+            uint8_t buf[512];
+            // uint16_t n = min(512, r->size - r->offset);
+            // n = (n + 3) & ~3;   // force 32-bit alignment
+            _gd->__end();
+            r->readsector(buf);
+            _gd->resume();
+            _gd->cmd_memwrite(base + wp, 512);
+            _gd->copyram(buf, 512);
+            wp = (wp + 512) & mask;
+        }
+        return r->offset < r->size;
+    }
+
+    void progress(uint16_t &val, uint16_t &range) 
+    {
+        uint32_t m = r->size;
+        uint32_t p = min(r->offset, m);
+        while (m > 0x10000) {
+            m >>= 1;
+            p >>= 1;
+        }
+        val = p;
+        range = m;
+    }
+private:
+    Reader* r;
+    uint32_t base;
+    uint16_t mask;
+    uint16_t wp;
+};
+
+
+static uint8_t sinus(GDClass* gd, uint8_t x)
+{
+    return 128 + gd->rsin(128, -16384 + (x << 7));
+}
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arduino.lib	Fri Apr 11 07:24:23 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/aluqard/code/arduino/#3b83fc30bbdf