Library(Beta) for Gameduino 2

Dependencies:   arduino

Dependents:   aa_gd_jw

Revision:
0:9c211972beb2
diff -r 000000000000 -r 9c211972beb2 Utils.h
--- /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