Library(Beta) for Gameduino 2
Utils.h@0:9c211972beb2, 2014-04-11 (annotated)
- Committer:
- aluqard
- Date:
- Fri Apr 11 07:24:23 2014 +0000
- Revision:
- 0:9c211972beb2
Initial release for Gameduino 2
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
aluqard | 0:9c211972beb2 | 1 | #ifndef _UTILS_H_ |
aluqard | 0:9c211972beb2 | 2 | #define _UTILS_H_ |
aluqard | 0:9c211972beb2 | 3 | |
aluqard | 0:9c211972beb2 | 4 | #include "arduino.h" |
aluqard | 0:9c211972beb2 | 5 | |
aluqard | 0:9c211972beb2 | 6 | void loop(); |
aluqard | 0:9c211972beb2 | 7 | |
aluqard | 0:9c211972beb2 | 8 | #define LOOP while(1) loop() |
aluqard | 0:9c211972beb2 | 9 | |
aluqard | 0:9c211972beb2 | 10 | typedef struct { |
aluqard | 0:9c211972beb2 | 11 | byte handle; |
aluqard | 0:9c211972beb2 | 12 | uint16_t w, h; |
aluqard | 0:9c211972beb2 | 13 | uint16_t size; |
aluqard | 0:9c211972beb2 | 14 | } shape_t; |
aluqard | 0:9c211972beb2 | 15 | |
aluqard | 0:9c211972beb2 | 16 | struct direntry |
aluqard | 0:9c211972beb2 | 17 | { |
aluqard | 0:9c211972beb2 | 18 | char name[8]; |
aluqard | 0:9c211972beb2 | 19 | char ext[3]; |
aluqard | 0:9c211972beb2 | 20 | uint8_t attribute; |
aluqard | 0:9c211972beb2 | 21 | uint8_t reserved[8]; |
aluqard | 0:9c211972beb2 | 22 | uint16_t cluster_hi; // FAT32 only |
aluqard | 0:9c211972beb2 | 23 | uint16_t time; |
aluqard | 0:9c211972beb2 | 24 | uint16_t date; |
aluqard | 0:9c211972beb2 | 25 | uint16_t cluster; |
aluqard | 0:9c211972beb2 | 26 | uint32_t size; |
aluqard | 0:9c211972beb2 | 27 | }; |
aluqard | 0:9c211972beb2 | 28 | |
aluqard | 0:9c211972beb2 | 29 | // https://www.sdcard.org/downloads/pls/simplified_specs/Part_1_Physical_Layer_Simplified_Specification_Ver_3.01_Final_100518.pdf |
aluqard | 0:9c211972beb2 | 30 | // page 22 |
aluqard | 0:9c211972beb2 | 31 | // http://mac6.ma.psu.edu/space2008/RockSat/microController/sdcard_appnote_foust.pdf |
aluqard | 0:9c211972beb2 | 32 | // http://elm-chan.org/docs/mmc/mmc_e.html |
aluqard | 0:9c211972beb2 | 33 | // http://www.pjrc.com/tech/8051/ide/fat32.html |
aluqard | 0:9c211972beb2 | 34 | |
aluqard | 0:9c211972beb2 | 35 | #define FAT16 0 |
aluqard | 0:9c211972beb2 | 36 | #define FAT32 1 |
aluqard | 0:9c211972beb2 | 37 | |
aluqard | 0:9c211972beb2 | 38 | class sdcard |
aluqard | 0:9c211972beb2 | 39 | { |
aluqard | 0:9c211972beb2 | 40 | public: |
aluqard | 0:9c211972beb2 | 41 | SPI* _spi; |
aluqard | 0:9c211972beb2 | 42 | DigitalOut _cs; |
aluqard | 0:9c211972beb2 | 43 | uint8_t ccs; |
aluqard | 0:9c211972beb2 | 44 | |
aluqard | 0:9c211972beb2 | 45 | uint8_t type; |
aluqard | 0:9c211972beb2 | 46 | uint16_t sectors_per_cluster; |
aluqard | 0:9c211972beb2 | 47 | uint16_t reserved_sectors; |
aluqard | 0:9c211972beb2 | 48 | uint16_t max_root_dir_entries; |
aluqard | 0:9c211972beb2 | 49 | uint16_t sectors_per_fat; |
aluqard | 0:9c211972beb2 | 50 | uint16_t cluster_size; |
aluqard | 0:9c211972beb2 | 51 | uint32_t root_dir_first_cluster; |
aluqard | 0:9c211972beb2 | 52 | |
aluqard | 0:9c211972beb2 | 53 | // These are all linear addresses, hence the o_ prefix |
aluqard | 0:9c211972beb2 | 54 | uint32_t o_partition; |
aluqard | 0:9c211972beb2 | 55 | uint32_t o_fat; |
aluqard | 0:9c211972beb2 | 56 | uint32_t o_root; |
aluqard | 0:9c211972beb2 | 57 | uint32_t o_data; |
aluqard | 0:9c211972beb2 | 58 | public: |
aluqard | 0:9c211972beb2 | 59 | sdcard(SPI* spi, PinName cs) : _cs(cs) |
aluqard | 0:9c211972beb2 | 60 | { |
aluqard | 0:9c211972beb2 | 61 | _spi = spi; |
aluqard | 0:9c211972beb2 | 62 | } |
aluqard | 0:9c211972beb2 | 63 | |
aluqard | 0:9c211972beb2 | 64 | void sel() |
aluqard | 0:9c211972beb2 | 65 | { |
aluqard | 0:9c211972beb2 | 66 | _cs = 0; |
aluqard | 0:9c211972beb2 | 67 | delay(1); |
aluqard | 0:9c211972beb2 | 68 | } |
aluqard | 0:9c211972beb2 | 69 | void desel() |
aluqard | 0:9c211972beb2 | 70 | { |
aluqard | 0:9c211972beb2 | 71 | _cs = 1; |
aluqard | 0:9c211972beb2 | 72 | _spi->write(0xff); // force DO release |
aluqard | 0:9c211972beb2 | 73 | } |
aluqard | 0:9c211972beb2 | 74 | void sd_delay(uint8_t n) |
aluqard | 0:9c211972beb2 | 75 | { |
aluqard | 0:9c211972beb2 | 76 | while (n--) |
aluqard | 0:9c211972beb2 | 77 | _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 78 | } |
aluqard | 0:9c211972beb2 | 79 | |
aluqard | 0:9c211972beb2 | 80 | void cmd(uint8_t cmd, uint32_t lba = 0, uint8_t crc = 0x95) |
aluqard | 0:9c211972beb2 | 81 | { |
aluqard | 0:9c211972beb2 | 82 | sel(); |
aluqard | 0:9c211972beb2 | 83 | _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 84 | _spi->write(0x40 | cmd); |
aluqard | 0:9c211972beb2 | 85 | _spi->write(0xff & (lba >> 24)); |
aluqard | 0:9c211972beb2 | 86 | _spi->write(0xff & (lba >> 16)); |
aluqard | 0:9c211972beb2 | 87 | _spi->write(0xff & (lba >> 8)); |
aluqard | 0:9c211972beb2 | 88 | _spi->write(0xff & (lba)); |
aluqard | 0:9c211972beb2 | 89 | _spi->write(crc); |
aluqard | 0:9c211972beb2 | 90 | _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 91 | } |
aluqard | 0:9c211972beb2 | 92 | |
aluqard | 0:9c211972beb2 | 93 | uint8_t R1() |
aluqard | 0:9c211972beb2 | 94 | { // read response R1 |
aluqard | 0:9c211972beb2 | 95 | uint8_t r; |
aluqard | 0:9c211972beb2 | 96 | while ((r = _spi->write(0xff)) & 0x80) |
aluqard | 0:9c211972beb2 | 97 | ; |
aluqard | 0:9c211972beb2 | 98 | desel(); |
aluqard | 0:9c211972beb2 | 99 | _spi->write(0xff); // trailing uint8_t |
aluqard | 0:9c211972beb2 | 100 | return r; |
aluqard | 0:9c211972beb2 | 101 | } |
aluqard | 0:9c211972beb2 | 102 | |
aluqard | 0:9c211972beb2 | 103 | uint8_t sdR3(uint32_t &ocr) |
aluqard | 0:9c211972beb2 | 104 | { // read response R3 |
aluqard | 0:9c211972beb2 | 105 | uint32_t r; |
aluqard | 0:9c211972beb2 | 106 | while ((r = _spi->write(0xff)) & 0x80) |
aluqard | 0:9c211972beb2 | 107 | ; |
aluqard | 0:9c211972beb2 | 108 | for (uint8_t i = 4; i; i--) |
aluqard | 0:9c211972beb2 | 109 | ocr = (ocr << 8) | _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 110 | _spi->write(0xff); // trailing uint8_t |
aluqard | 0:9c211972beb2 | 111 | |
aluqard | 0:9c211972beb2 | 112 | desel(); |
aluqard | 0:9c211972beb2 | 113 | return r; |
aluqard | 0:9c211972beb2 | 114 | } |
aluqard | 0:9c211972beb2 | 115 | |
aluqard | 0:9c211972beb2 | 116 | uint8_t sdR7() |
aluqard | 0:9c211972beb2 | 117 | { // read response R3 |
aluqard | 0:9c211972beb2 | 118 | uint32_t r; |
aluqard | 0:9c211972beb2 | 119 | while ((r = _spi->write(0xff)) & 0x80) |
aluqard | 0:9c211972beb2 | 120 | ; |
aluqard | 0:9c211972beb2 | 121 | for (uint8_t i = 4; i; i--) |
aluqard | 0:9c211972beb2 | 122 | // Serial.println(____spi->write(0xff), HEX); |
aluqard | 0:9c211972beb2 | 123 | _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 124 | desel(); |
aluqard | 0:9c211972beb2 | 125 | |
aluqard | 0:9c211972beb2 | 126 | return r; |
aluqard | 0:9c211972beb2 | 127 | } |
aluqard | 0:9c211972beb2 | 128 | |
aluqard | 0:9c211972beb2 | 129 | void appcmd(uint8_t cc, uint32_t lba = 0) |
aluqard | 0:9c211972beb2 | 130 | { |
aluqard | 0:9c211972beb2 | 131 | cmd(55); R1(); |
aluqard | 0:9c211972beb2 | 132 | cmd(cc, lba); |
aluqard | 0:9c211972beb2 | 133 | } |
aluqard | 0:9c211972beb2 | 134 | |
aluqard | 0:9c211972beb2 | 135 | void begin() |
aluqard | 0:9c211972beb2 | 136 | { |
aluqard | 0:9c211972beb2 | 137 | uint8_t type_code; |
aluqard | 0:9c211972beb2 | 138 | uint8_t sdhc; |
aluqard | 0:9c211972beb2 | 139 | |
aluqard | 0:9c211972beb2 | 140 | desel(); |
aluqard | 0:9c211972beb2 | 141 | |
aluqard | 0:9c211972beb2 | 142 | delay(10); // wait for boot |
aluqard | 0:9c211972beb2 | 143 | sd_delay(10); // deselected, 80 pulses |
aluqard | 0:9c211972beb2 | 144 | |
aluqard | 0:9c211972beb2 | 145 | // Tty.printf("Attempting card reset... "); |
aluqard | 0:9c211972beb2 | 146 | // attempt reset |
aluqard | 0:9c211972beb2 | 147 | uint8_t r1; |
aluqard | 0:9c211972beb2 | 148 | int attempts = 0; |
aluqard | 0:9c211972beb2 | 149 | do |
aluqard | 0:9c211972beb2 | 150 | { // reset, enter idle |
aluqard | 0:9c211972beb2 | 151 | cmd(0); |
aluqard | 0:9c211972beb2 | 152 | while ((r1 = _spi->write(0xff)) & 0x80) |
aluqard | 0:9c211972beb2 | 153 | if (++attempts == 1000) |
aluqard | 0:9c211972beb2 | 154 | return; |
aluqard | 0:9c211972beb2 | 155 | desel(); |
aluqard | 0:9c211972beb2 | 156 | _spi->write(0xff); // trailing uint8_t |
aluqard | 0:9c211972beb2 | 157 | } while (r1 != 1); |
aluqard | 0:9c211972beb2 | 158 | // Tty.printf("reset ok\n"); |
aluqard | 0:9c211972beb2 | 159 | |
aluqard | 0:9c211972beb2 | 160 | sdhc = 0; |
aluqard | 0:9c211972beb2 | 161 | cmd(8, 0x1aa, 0x87); |
aluqard | 0:9c211972beb2 | 162 | r1 = sdR7(); |
aluqard | 0:9c211972beb2 | 163 | sdhc = (r1 == 1); |
aluqard | 0:9c211972beb2 | 164 | |
aluqard | 0:9c211972beb2 | 165 | // Tty.printf("card %s SDHC\n", sdhc ? "is" : "is not"); |
aluqard | 0:9c211972beb2 | 166 | |
aluqard | 0:9c211972beb2 | 167 | // Tty.printf("Sending card init command... "); |
aluqard | 0:9c211972beb2 | 168 | while (1) |
aluqard | 0:9c211972beb2 | 169 | { |
aluqard | 0:9c211972beb2 | 170 | appcmd(41, sdhc ? (1UL << 30) : 0); // card init |
aluqard | 0:9c211972beb2 | 171 | r1 = R1(); |
aluqard | 0:9c211972beb2 | 172 | if ((r1 & 1) == 0) |
aluqard | 0:9c211972beb2 | 173 | break; |
aluqard | 0:9c211972beb2 | 174 | delay(100); |
aluqard | 0:9c211972beb2 | 175 | } |
aluqard | 0:9c211972beb2 | 176 | // Tty.printf("OK\n"); |
aluqard | 0:9c211972beb2 | 177 | |
aluqard | 0:9c211972beb2 | 178 | if (sdhc) |
aluqard | 0:9c211972beb2 | 179 | { |
aluqard | 0:9c211972beb2 | 180 | cmd(58); |
aluqard | 0:9c211972beb2 | 181 | uint32_t OCR = 0; |
aluqard | 0:9c211972beb2 | 182 | sdR3(OCR); |
aluqard | 0:9c211972beb2 | 183 | ccs = 1UL & (OCR >> 30); |
aluqard | 0:9c211972beb2 | 184 | // Tty.printf("OCR register is %#010lx\n", long(OCR)); |
aluqard | 0:9c211972beb2 | 185 | } |
aluqard | 0:9c211972beb2 | 186 | |
aluqard | 0:9c211972beb2 | 187 | else |
aluqard | 0:9c211972beb2 | 188 | { |
aluqard | 0:9c211972beb2 | 189 | ccs = 0; |
aluqard | 0:9c211972beb2 | 190 | } |
aluqard | 0:9c211972beb2 | 191 | // Tty.printf("ccs = %d\n", ccs); |
aluqard | 0:9c211972beb2 | 192 | // REPORT(ccs); |
aluqard | 0:9c211972beb2 | 193 | |
aluqard | 0:9c211972beb2 | 194 | type_code = rd(0x1be + 0x4); |
aluqard | 0:9c211972beb2 | 195 | |
aluqard | 0:9c211972beb2 | 196 | switch (type_code) |
aluqard | 0:9c211972beb2 | 197 | { |
aluqard | 0:9c211972beb2 | 198 | default: |
aluqard | 0:9c211972beb2 | 199 | type = FAT16; |
aluqard | 0:9c211972beb2 | 200 | break; |
aluqard | 0:9c211972beb2 | 201 | case 0x0b: |
aluqard | 0:9c211972beb2 | 202 | case 0x0c: |
aluqard | 0:9c211972beb2 | 203 | type = FAT32; |
aluqard | 0:9c211972beb2 | 204 | break; |
aluqard | 0:9c211972beb2 | 205 | } |
aluqard | 0:9c211972beb2 | 206 | // REPORT(type_code); |
aluqard | 0:9c211972beb2 | 207 | // Tty.printf("Type code %#02x means FAT%d\n", type_code, (type == FAT16) ? 16 : 32); |
aluqard | 0:9c211972beb2 | 208 | #if VERBOSE |
aluqard | 0:9c211972beb2 | 209 | DEBUGOUT("Type "); |
aluqard | 0:9c211972beb2 | 210 | DEBUGOUT("%x", type_code); |
aluqard | 0:9c211972beb2 | 211 | DEBUGOUT(" so FAT"); |
aluqard | 0:9c211972beb2 | 212 | DEBUGOUT("%d\r\n", (type == FAT16) ? 16 : 32); |
aluqard | 0:9c211972beb2 | 213 | #endif |
aluqard | 0:9c211972beb2 | 214 | |
aluqard | 0:9c211972beb2 | 215 | o_partition = 512L * rd4(0x1be + 0x8); |
aluqard | 0:9c211972beb2 | 216 | sectors_per_cluster = rd(o_partition + 0xd); |
aluqard | 0:9c211972beb2 | 217 | reserved_sectors = rd2(o_partition + 0xe); |
aluqard | 0:9c211972beb2 | 218 | cluster_size = 512L * sectors_per_cluster; |
aluqard | 0:9c211972beb2 | 219 | // REPORT(sectors_per_cluster); |
aluqard | 0:9c211972beb2 | 220 | |
aluqard | 0:9c211972beb2 | 221 | // Tty.printf("Bytes per sector: %d\n", rd2(o_partition + 0xb)); |
aluqard | 0:9c211972beb2 | 222 | // Tty.printf("Sectors per cluster: %d\n", sectors_per_cluster); |
aluqard | 0:9c211972beb2 | 223 | |
aluqard | 0:9c211972beb2 | 224 | if (type == FAT16) |
aluqard | 0:9c211972beb2 | 225 | { |
aluqard | 0:9c211972beb2 | 226 | max_root_dir_entries = rd2(o_partition + 0x11); |
aluqard | 0:9c211972beb2 | 227 | sectors_per_fat = rd2(o_partition + 0x16); |
aluqard | 0:9c211972beb2 | 228 | o_fat = o_partition + 512L * reserved_sectors; |
aluqard | 0:9c211972beb2 | 229 | o_root = o_fat + (2 * 512L * sectors_per_fat); |
aluqard | 0:9c211972beb2 | 230 | // data area starts with cluster 2, so offset it here |
aluqard | 0:9c211972beb2 | 231 | o_data = o_root + (max_root_dir_entries * 32L) - (2L * cluster_size); |
aluqard | 0:9c211972beb2 | 232 | } |
aluqard | 0:9c211972beb2 | 233 | |
aluqard | 0:9c211972beb2 | 234 | else |
aluqard | 0:9c211972beb2 | 235 | { |
aluqard | 0:9c211972beb2 | 236 | uint32_t sectors_per_fat = rd4(o_partition + 0x24); |
aluqard | 0:9c211972beb2 | 237 | root_dir_first_cluster = rd4(o_partition + 0x2c); |
aluqard | 0:9c211972beb2 | 238 | uint32_t fat_begin_lba = (o_partition >> 9) + reserved_sectors; |
aluqard | 0:9c211972beb2 | 239 | uint32_t cluster_begin_lba = (o_partition >> 9) + reserved_sectors + (2 * sectors_per_fat); |
aluqard | 0:9c211972beb2 | 240 | |
aluqard | 0:9c211972beb2 | 241 | o_fat = 512L * fat_begin_lba; |
aluqard | 0:9c211972beb2 | 242 | o_root = (512L * (cluster_begin_lba + (root_dir_first_cluster - 2) * sectors_per_cluster)); |
aluqard | 0:9c211972beb2 | 243 | o_data = (512L * (cluster_begin_lba - 2 * sectors_per_cluster)); |
aluqard | 0:9c211972beb2 | 244 | } |
aluqard | 0:9c211972beb2 | 245 | } |
aluqard | 0:9c211972beb2 | 246 | |
aluqard | 0:9c211972beb2 | 247 | static char toupper(char sv) |
aluqard | 0:9c211972beb2 | 248 | { |
aluqard | 0:9c211972beb2 | 249 | char c = sv; |
aluqard | 0:9c211972beb2 | 250 | if( sv >= 'a' && sv <= 'z') |
aluqard | 0:9c211972beb2 | 251 | c = sv - ('a' - 'A'); |
aluqard | 0:9c211972beb2 | 252 | |
aluqard | 0:9c211972beb2 | 253 | return c; |
aluqard | 0:9c211972beb2 | 254 | } |
aluqard | 0:9c211972beb2 | 255 | |
aluqard | 0:9c211972beb2 | 256 | void cmd17(uint32_t off) |
aluqard | 0:9c211972beb2 | 257 | { |
aluqard | 0:9c211972beb2 | 258 | if (ccs) |
aluqard | 0:9c211972beb2 | 259 | cmd(17, off >> 9); |
aluqard | 0:9c211972beb2 | 260 | else |
aluqard | 0:9c211972beb2 | 261 | cmd(17, off & ~511L); |
aluqard | 0:9c211972beb2 | 262 | R1(); |
aluqard | 0:9c211972beb2 | 263 | sel(); |
aluqard | 0:9c211972beb2 | 264 | while (_spi->write(0xff) != 0xfe) |
aluqard | 0:9c211972beb2 | 265 | ; |
aluqard | 0:9c211972beb2 | 266 | } |
aluqard | 0:9c211972beb2 | 267 | |
aluqard | 0:9c211972beb2 | 268 | void rdn(uint8_t *d, uint32_t off, uint16_t n) |
aluqard | 0:9c211972beb2 | 269 | { |
aluqard | 0:9c211972beb2 | 270 | cmd17(off); |
aluqard | 0:9c211972beb2 | 271 | uint16_t i; |
aluqard | 0:9c211972beb2 | 272 | uint16_t bo = (off & 511); |
aluqard | 0:9c211972beb2 | 273 | for (i = 0; i < bo; i++) |
aluqard | 0:9c211972beb2 | 274 | _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 275 | for (i = 0; i < n; i++) |
aluqard | 0:9c211972beb2 | 276 | *d++ = _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 277 | for (i = 0; i < (514 - bo - n); i++) |
aluqard | 0:9c211972beb2 | 278 | _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 279 | desel(); |
aluqard | 0:9c211972beb2 | 280 | } |
aluqard | 0:9c211972beb2 | 281 | |
aluqard | 0:9c211972beb2 | 282 | uint32_t rd4(uint32_t off) |
aluqard | 0:9c211972beb2 | 283 | { |
aluqard | 0:9c211972beb2 | 284 | uint32_t r; |
aluqard | 0:9c211972beb2 | 285 | rdn((uint8_t*)&r, off, sizeof(r)); |
aluqard | 0:9c211972beb2 | 286 | return r; |
aluqard | 0:9c211972beb2 | 287 | } |
aluqard | 0:9c211972beb2 | 288 | |
aluqard | 0:9c211972beb2 | 289 | uint16_t rd2(uint32_t off) |
aluqard | 0:9c211972beb2 | 290 | { |
aluqard | 0:9c211972beb2 | 291 | uint16_t r; |
aluqard | 0:9c211972beb2 | 292 | rdn((uint8_t*)&r, off, sizeof(r)); |
aluqard | 0:9c211972beb2 | 293 | return r; |
aluqard | 0:9c211972beb2 | 294 | } |
aluqard | 0:9c211972beb2 | 295 | |
aluqard | 0:9c211972beb2 | 296 | uint8_t rd(uint32_t off) |
aluqard | 0:9c211972beb2 | 297 | { |
aluqard | 0:9c211972beb2 | 298 | uint8_t r; |
aluqard | 0:9c211972beb2 | 299 | rdn((uint8_t*)&r, off, sizeof(r)); |
aluqard | 0:9c211972beb2 | 300 | return r; |
aluqard | 0:9c211972beb2 | 301 | } |
aluqard | 0:9c211972beb2 | 302 | }; |
aluqard | 0:9c211972beb2 | 303 | |
aluqard | 0:9c211972beb2 | 304 | static void dos83(uint8_t dst[11], const char *ps) |
aluqard | 0:9c211972beb2 | 305 | { |
aluqard | 0:9c211972beb2 | 306 | uint8_t i = 0; |
aluqard | 0:9c211972beb2 | 307 | while (*ps) |
aluqard | 0:9c211972beb2 | 308 | { |
aluqard | 0:9c211972beb2 | 309 | if (*ps != '.') |
aluqard | 0:9c211972beb2 | 310 | dst[i++] = sdcard::toupper(*ps); |
aluqard | 0:9c211972beb2 | 311 | else |
aluqard | 0:9c211972beb2 | 312 | { |
aluqard | 0:9c211972beb2 | 313 | while (i < 8) |
aluqard | 0:9c211972beb2 | 314 | dst[i++] = ' '; |
aluqard | 0:9c211972beb2 | 315 | } |
aluqard | 0:9c211972beb2 | 316 | ps++; |
aluqard | 0:9c211972beb2 | 317 | } |
aluqard | 0:9c211972beb2 | 318 | while (i < 11) |
aluqard | 0:9c211972beb2 | 319 | dst[i++] = ' '; |
aluqard | 0:9c211972beb2 | 320 | } |
aluqard | 0:9c211972beb2 | 321 | |
aluqard | 0:9c211972beb2 | 322 | class Reader |
aluqard | 0:9c211972beb2 | 323 | { |
aluqard | 0:9c211972beb2 | 324 | SPI* _spi; |
aluqard | 0:9c211972beb2 | 325 | sdcard* _sd; |
aluqard | 0:9c211972beb2 | 326 | public: |
aluqard | 0:9c211972beb2 | 327 | Reader(SPI* spi, sdcard* sd) |
aluqard | 0:9c211972beb2 | 328 | { |
aluqard | 0:9c211972beb2 | 329 | _spi = spi; |
aluqard | 0:9c211972beb2 | 330 | _sd = sd; |
aluqard | 0:9c211972beb2 | 331 | } |
aluqard | 0:9c211972beb2 | 332 | |
aluqard | 0:9c211972beb2 | 333 | public: |
aluqard | 0:9c211972beb2 | 334 | int openfile(const char *filename) |
aluqard | 0:9c211972beb2 | 335 | { |
aluqard | 0:9c211972beb2 | 336 | int i = 0; |
aluqard | 0:9c211972beb2 | 337 | uint8_t dosname[11] = {0, }; |
aluqard | 0:9c211972beb2 | 338 | direntry de = {0, }; |
aluqard | 0:9c211972beb2 | 339 | |
aluqard | 0:9c211972beb2 | 340 | dos83(dosname, filename); |
aluqard | 0:9c211972beb2 | 341 | |
aluqard | 0:9c211972beb2 | 342 | do { |
aluqard | 0:9c211972beb2 | 343 | _sd->rdn((uint8_t*)&de, _sd->o_root + i * 32, sizeof(de)); |
aluqard | 0:9c211972beb2 | 344 | if (0 == memcmp(de.name, dosname, 11)) |
aluqard | 0:9c211972beb2 | 345 | { |
aluqard | 0:9c211972beb2 | 346 | DEBUGOUT("begin(de)\r\n"); |
aluqard | 0:9c211972beb2 | 347 | begin(de); |
aluqard | 0:9c211972beb2 | 348 | return 1; |
aluqard | 0:9c211972beb2 | 349 | } |
aluqard | 0:9c211972beb2 | 350 | i++; |
aluqard | 0:9c211972beb2 | 351 | } while (de.name[0]); |
aluqard | 0:9c211972beb2 | 352 | return 0; |
aluqard | 0:9c211972beb2 | 353 | } |
aluqard | 0:9c211972beb2 | 354 | |
aluqard | 0:9c211972beb2 | 355 | void begin(direntry &de) |
aluqard | 0:9c211972beb2 | 356 | { |
aluqard | 0:9c211972beb2 | 357 | size = de.size; |
aluqard | 0:9c211972beb2 | 358 | cluster = de.cluster; |
aluqard | 0:9c211972beb2 | 359 | if (_sd->type == FAT32) |
aluqard | 0:9c211972beb2 | 360 | cluster |= ((long)de.cluster_hi << 16); |
aluqard | 0:9c211972beb2 | 361 | sector = 0; |
aluqard | 0:9c211972beb2 | 362 | offset = 0; |
aluqard | 0:9c211972beb2 | 363 | } |
aluqard | 0:9c211972beb2 | 364 | |
aluqard | 0:9c211972beb2 | 365 | void nextcluster() |
aluqard | 0:9c211972beb2 | 366 | { |
aluqard | 0:9c211972beb2 | 367 | if (_sd->type == FAT16) |
aluqard | 0:9c211972beb2 | 368 | cluster = _sd->rd2(_sd->o_fat + 2 * cluster); |
aluqard | 0:9c211972beb2 | 369 | else |
aluqard | 0:9c211972beb2 | 370 | cluster = _sd->rd4(_sd->o_fat + 4 * cluster); |
aluqard | 0:9c211972beb2 | 371 | #if VERBOSE |
aluqard | 0:9c211972beb2 | 372 | DEBUGOUT("nextcluster="); |
aluqard | 0:9c211972beb2 | 373 | DEBUGOUT("%d\r\n", cluster); |
aluqard | 0:9c211972beb2 | 374 | #endif |
aluqard | 0:9c211972beb2 | 375 | } |
aluqard | 0:9c211972beb2 | 376 | |
aluqard | 0:9c211972beb2 | 377 | void skipcluster() |
aluqard | 0:9c211972beb2 | 378 | { |
aluqard | 0:9c211972beb2 | 379 | nextcluster(); |
aluqard | 0:9c211972beb2 | 380 | offset += _sd->cluster_size; |
aluqard | 0:9c211972beb2 | 381 | } |
aluqard | 0:9c211972beb2 | 382 | void skipsector() |
aluqard | 0:9c211972beb2 | 383 | { |
aluqard | 0:9c211972beb2 | 384 | if (sector == _sd->sectors_per_cluster) { |
aluqard | 0:9c211972beb2 | 385 | sector = 0; |
aluqard | 0:9c211972beb2 | 386 | nextcluster(); |
aluqard | 0:9c211972beb2 | 387 | } |
aluqard | 0:9c211972beb2 | 388 | sector++; |
aluqard | 0:9c211972beb2 | 389 | offset += 512; |
aluqard | 0:9c211972beb2 | 390 | } |
aluqard | 0:9c211972beb2 | 391 | |
aluqard | 0:9c211972beb2 | 392 | void seek(uint32_t o) |
aluqard | 0:9c211972beb2 | 393 | { |
aluqard | 0:9c211972beb2 | 394 | while (offset < o) |
aluqard | 0:9c211972beb2 | 395 | { |
aluqard | 0:9c211972beb2 | 396 | if ((sector == _sd->sectors_per_cluster) && ((o - offset) > (long)_sd->cluster_size)) |
aluqard | 0:9c211972beb2 | 397 | skipcluster(); |
aluqard | 0:9c211972beb2 | 398 | else |
aluqard | 0:9c211972beb2 | 399 | skipsector(); |
aluqard | 0:9c211972beb2 | 400 | } |
aluqard | 0:9c211972beb2 | 401 | } |
aluqard | 0:9c211972beb2 | 402 | void readsector() |
aluqard | 0:9c211972beb2 | 403 | { |
aluqard | 0:9c211972beb2 | 404 | if (sector == _sd->sectors_per_cluster) |
aluqard | 0:9c211972beb2 | 405 | { |
aluqard | 0:9c211972beb2 | 406 | sector = 0; |
aluqard | 0:9c211972beb2 | 407 | nextcluster(); |
aluqard | 0:9c211972beb2 | 408 | } |
aluqard | 0:9c211972beb2 | 409 | uint32_t off = _sd->o_data + ((long)_sd->cluster_size * cluster) + (512L * sector); |
aluqard | 0:9c211972beb2 | 410 | #if VERBOSE |
aluqard | 0:9c211972beb2 | 411 | DEBUGOUT("off=0x"); |
aluqard | 0:9c211972beb2 | 412 | DEBUGOUT("%x", off); |
aluqard | 0:9c211972beb2 | 413 | #endif |
aluqard | 0:9c211972beb2 | 414 | _sd->cmd17(off & ~511L); |
aluqard | 0:9c211972beb2 | 415 | // Serial.println(2 * (micros() - t0), DEC); |
aluqard | 0:9c211972beb2 | 416 | sector++; |
aluqard | 0:9c211972beb2 | 417 | offset += 512; |
aluqard | 0:9c211972beb2 | 418 | } |
aluqard | 0:9c211972beb2 | 419 | void readsector(uint8_t *dst) |
aluqard | 0:9c211972beb2 | 420 | { |
aluqard | 0:9c211972beb2 | 421 | readsector(); |
aluqard | 0:9c211972beb2 | 422 | for (int i = 0; i < 64; i++) { |
aluqard | 0:9c211972beb2 | 423 | *dst++ = _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 424 | *dst++ = _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 425 | *dst++ = _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 426 | *dst++ = _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 427 | *dst++ = _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 428 | *dst++ = _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 429 | *dst++ = _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 430 | *dst++ = _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 431 | } |
aluqard | 0:9c211972beb2 | 432 | _spi->write(0xff); // consume CRC |
aluqard | 0:9c211972beb2 | 433 | _spi->write(0xff); |
aluqard | 0:9c211972beb2 | 434 | _sd->desel(); |
aluqard | 0:9c211972beb2 | 435 | } |
aluqard | 0:9c211972beb2 | 436 | uint32_t cluster; |
aluqard | 0:9c211972beb2 | 437 | uint32_t offset; |
aluqard | 0:9c211972beb2 | 438 | uint32_t size; |
aluqard | 0:9c211972beb2 | 439 | uint8_t sector; |
aluqard | 0:9c211972beb2 | 440 | }; |
aluqard | 0:9c211972beb2 | 441 | |
aluqard | 0:9c211972beb2 | 442 | class Poly |
aluqard | 0:9c211972beb2 | 443 | { |
aluqard | 0:9c211972beb2 | 444 | public: |
aluqard | 0:9c211972beb2 | 445 | GDClass* _gd; |
aluqard | 0:9c211972beb2 | 446 | Poly(GDClass* gd) |
aluqard | 0:9c211972beb2 | 447 | { |
aluqard | 0:9c211972beb2 | 448 | _gd = gd; |
aluqard | 0:9c211972beb2 | 449 | } |
aluqard | 0:9c211972beb2 | 450 | |
aluqard | 0:9c211972beb2 | 451 | int x0, y0, x1, y1; |
aluqard | 0:9c211972beb2 | 452 | int x[8], y[8]; |
aluqard | 0:9c211972beb2 | 453 | uint8_t n; |
aluqard | 0:9c211972beb2 | 454 | |
aluqard | 0:9c211972beb2 | 455 | void restart() |
aluqard | 0:9c211972beb2 | 456 | { |
aluqard | 0:9c211972beb2 | 457 | n = 0; |
aluqard | 0:9c211972beb2 | 458 | x0 = 16 * 480; |
aluqard | 0:9c211972beb2 | 459 | x1 = 0; |
aluqard | 0:9c211972beb2 | 460 | y0 = 16 * 272; |
aluqard | 0:9c211972beb2 | 461 | y1 = 0; |
aluqard | 0:9c211972beb2 | 462 | } |
aluqard | 0:9c211972beb2 | 463 | |
aluqard | 0:9c211972beb2 | 464 | void perim() |
aluqard | 0:9c211972beb2 | 465 | { |
aluqard | 0:9c211972beb2 | 466 | for (uint8_t i = 0; i < n; i++) |
aluqard | 0:9c211972beb2 | 467 | _gd->Vertex2f(x[i], y[i]); |
aluqard | 0:9c211972beb2 | 468 | _gd->Vertex2f(x[0], y[0]); |
aluqard | 0:9c211972beb2 | 469 | } |
aluqard | 0:9c211972beb2 | 470 | public: |
aluqard | 0:9c211972beb2 | 471 | void begin() |
aluqard | 0:9c211972beb2 | 472 | { |
aluqard | 0:9c211972beb2 | 473 | restart(); |
aluqard | 0:9c211972beb2 | 474 | |
aluqard | 0:9c211972beb2 | 475 | _gd->ColorMask(0,0,0,0); |
aluqard | 0:9c211972beb2 | 476 | _gd->StencilOp(KEEP, INVERT); |
aluqard | 0:9c211972beb2 | 477 | _gd->StencilFunc(ALWAYS, 255, 255); |
aluqard | 0:9c211972beb2 | 478 | } |
aluqard | 0:9c211972beb2 | 479 | |
aluqard | 0:9c211972beb2 | 480 | void v(int _x, int _y) |
aluqard | 0:9c211972beb2 | 481 | { |
aluqard | 0:9c211972beb2 | 482 | x0 = min(x0, _x >> 4); |
aluqard | 0:9c211972beb2 | 483 | x1 = max(x1, _x >> 4); |
aluqard | 0:9c211972beb2 | 484 | y0 = min(y0, _y >> 4); |
aluqard | 0:9c211972beb2 | 485 | y1 = max(y1, _y >> 4); |
aluqard | 0:9c211972beb2 | 486 | x[n] = _x; |
aluqard | 0:9c211972beb2 | 487 | y[n] = _y; |
aluqard | 0:9c211972beb2 | 488 | n++; |
aluqard | 0:9c211972beb2 | 489 | } |
aluqard | 0:9c211972beb2 | 490 | |
aluqard | 0:9c211972beb2 | 491 | void paint() |
aluqard | 0:9c211972beb2 | 492 | { |
aluqard | 0:9c211972beb2 | 493 | x0 = max(0, x0); |
aluqard | 0:9c211972beb2 | 494 | y0 = max(0, y0); |
aluqard | 0:9c211972beb2 | 495 | x1 = min(16 * 480, x1); |
aluqard | 0:9c211972beb2 | 496 | y1 = min(16 * 272, y1); |
aluqard | 0:9c211972beb2 | 497 | _gd->ScissorXY(x0, y0); |
aluqard | 0:9c211972beb2 | 498 | _gd->ScissorSize(x1 - x0 + 1, y1 - y0 + 1); |
aluqard | 0:9c211972beb2 | 499 | _gd->Begin(EDGE_STRIP_B); |
aluqard | 0:9c211972beb2 | 500 | perim(); |
aluqard | 0:9c211972beb2 | 501 | } |
aluqard | 0:9c211972beb2 | 502 | |
aluqard | 0:9c211972beb2 | 503 | void finish() |
aluqard | 0:9c211972beb2 | 504 | { |
aluqard | 0:9c211972beb2 | 505 | _gd->ColorMask(1,1,1,1); |
aluqard | 0:9c211972beb2 | 506 | _gd->StencilFunc(EQUAL, 255, 255); |
aluqard | 0:9c211972beb2 | 507 | |
aluqard | 0:9c211972beb2 | 508 | _gd->Begin(EDGE_STRIP_B); |
aluqard | 0:9c211972beb2 | 509 | _gd->Vertex2ii(0, 0); |
aluqard | 0:9c211972beb2 | 510 | _gd->Vertex2ii(511, 0); |
aluqard | 0:9c211972beb2 | 511 | } |
aluqard | 0:9c211972beb2 | 512 | |
aluqard | 0:9c211972beb2 | 513 | void draw() |
aluqard | 0:9c211972beb2 | 514 | { |
aluqard | 0:9c211972beb2 | 515 | paint(); |
aluqard | 0:9c211972beb2 | 516 | finish(); |
aluqard | 0:9c211972beb2 | 517 | } |
aluqard | 0:9c211972beb2 | 518 | |
aluqard | 0:9c211972beb2 | 519 | void outline() |
aluqard | 0:9c211972beb2 | 520 | { |
aluqard | 0:9c211972beb2 | 521 | _gd->Begin(LINE_STRIP); |
aluqard | 0:9c211972beb2 | 522 | perim(); |
aluqard | 0:9c211972beb2 | 523 | } |
aluqard | 0:9c211972beb2 | 524 | }; |
aluqard | 0:9c211972beb2 | 525 | |
aluqard | 0:9c211972beb2 | 526 | class Streamer |
aluqard | 0:9c211972beb2 | 527 | { |
aluqard | 0:9c211972beb2 | 528 | public: |
aluqard | 0:9c211972beb2 | 529 | GDClass* _gd; |
aluqard | 0:9c211972beb2 | 530 | |
aluqard | 0:9c211972beb2 | 531 | Streamer(GDClass* gd, sdcard* sd) |
aluqard | 0:9c211972beb2 | 532 | { |
aluqard | 0:9c211972beb2 | 533 | r = new Reader(gd->GDTR.SPI(), sd); |
aluqard | 0:9c211972beb2 | 534 | _gd = gd; |
aluqard | 0:9c211972beb2 | 535 | } |
aluqard | 0:9c211972beb2 | 536 | void begin(const char *rawsamples, |
aluqard | 0:9c211972beb2 | 537 | uint16_t freq = 44100, |
aluqard | 0:9c211972beb2 | 538 | uint8_t format = ADPCM_SAMPLES, |
aluqard | 0:9c211972beb2 | 539 | uint32_t _base = (0x40000UL - 8192), uint16_t size = 8192) |
aluqard | 0:9c211972beb2 | 540 | { |
aluqard | 0:9c211972beb2 | 541 | r->openfile(rawsamples); |
aluqard | 0:9c211972beb2 | 542 | |
aluqard | 0:9c211972beb2 | 543 | base = _base; |
aluqard | 0:9c211972beb2 | 544 | mask = size - 1; |
aluqard | 0:9c211972beb2 | 545 | wp = 0; |
aluqard | 0:9c211972beb2 | 546 | |
aluqard | 0:9c211972beb2 | 547 | for (uint8_t i = 10; i; i--) |
aluqard | 0:9c211972beb2 | 548 | feed(); |
aluqard | 0:9c211972beb2 | 549 | |
aluqard | 0:9c211972beb2 | 550 | _gd->sample(base, size, freq, format, 1); |
aluqard | 0:9c211972beb2 | 551 | } |
aluqard | 0:9c211972beb2 | 552 | |
aluqard | 0:9c211972beb2 | 553 | int feed() |
aluqard | 0:9c211972beb2 | 554 | { |
aluqard | 0:9c211972beb2 | 555 | uint16_t rp = _gd->rd32(REG_PLAYBACK_READPTR) - base; |
aluqard | 0:9c211972beb2 | 556 | uint16_t freespace = mask & ((rp - 1) - wp); |
aluqard | 0:9c211972beb2 | 557 | if (freespace >= 512) { |
aluqard | 0:9c211972beb2 | 558 | // REPORT(base); |
aluqard | 0:9c211972beb2 | 559 | // REPORT(rp); |
aluqard | 0:9c211972beb2 | 560 | // REPORT(wp); |
aluqard | 0:9c211972beb2 | 561 | // REPORT(freespace); |
aluqard | 0:9c211972beb2 | 562 | // DEBUGOUT("\r\n"); |
aluqard | 0:9c211972beb2 | 563 | uint8_t buf[512]; |
aluqard | 0:9c211972beb2 | 564 | // uint16_t n = min(512, r->size - r->offset); |
aluqard | 0:9c211972beb2 | 565 | // n = (n + 3) & ~3; // force 32-bit alignment |
aluqard | 0:9c211972beb2 | 566 | _gd->__end(); |
aluqard | 0:9c211972beb2 | 567 | r->readsector(buf); |
aluqard | 0:9c211972beb2 | 568 | _gd->resume(); |
aluqard | 0:9c211972beb2 | 569 | _gd->cmd_memwrite(base + wp, 512); |
aluqard | 0:9c211972beb2 | 570 | _gd->copyram(buf, 512); |
aluqard | 0:9c211972beb2 | 571 | wp = (wp + 512) & mask; |
aluqard | 0:9c211972beb2 | 572 | } |
aluqard | 0:9c211972beb2 | 573 | return r->offset < r->size; |
aluqard | 0:9c211972beb2 | 574 | } |
aluqard | 0:9c211972beb2 | 575 | |
aluqard | 0:9c211972beb2 | 576 | void progress(uint16_t &val, uint16_t &range) |
aluqard | 0:9c211972beb2 | 577 | { |
aluqard | 0:9c211972beb2 | 578 | uint32_t m = r->size; |
aluqard | 0:9c211972beb2 | 579 | uint32_t p = min(r->offset, m); |
aluqard | 0:9c211972beb2 | 580 | while (m > 0x10000) { |
aluqard | 0:9c211972beb2 | 581 | m >>= 1; |
aluqard | 0:9c211972beb2 | 582 | p >>= 1; |
aluqard | 0:9c211972beb2 | 583 | } |
aluqard | 0:9c211972beb2 | 584 | val = p; |
aluqard | 0:9c211972beb2 | 585 | range = m; |
aluqard | 0:9c211972beb2 | 586 | } |
aluqard | 0:9c211972beb2 | 587 | private: |
aluqard | 0:9c211972beb2 | 588 | Reader* r; |
aluqard | 0:9c211972beb2 | 589 | uint32_t base; |
aluqard | 0:9c211972beb2 | 590 | uint16_t mask; |
aluqard | 0:9c211972beb2 | 591 | uint16_t wp; |
aluqard | 0:9c211972beb2 | 592 | }; |
aluqard | 0:9c211972beb2 | 593 | |
aluqard | 0:9c211972beb2 | 594 | |
aluqard | 0:9c211972beb2 | 595 | static uint8_t sinus(GDClass* gd, uint8_t x) |
aluqard | 0:9c211972beb2 | 596 | { |
aluqard | 0:9c211972beb2 | 597 | return 128 + gd->rsin(128, -16384 + (x << 7)); |
aluqard | 0:9c211972beb2 | 598 | } |
aluqard | 0:9c211972beb2 | 599 | |
aluqard | 0:9c211972beb2 | 600 | #endif |