Library(Beta) for Gameduino 2
Utils.h
- Committer:
- aluqard
- Date:
- 2014-04-11
- Revision:
- 0:9c211972beb2
File content as of revision 0:9c211972beb2:
#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