You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
6.7KB

  1. /* Optimized SD Library for Teensy 3.X
  2. * Copyright (c) 2015, Paul Stoffregen, paul@pjrc.com
  3. *
  4. * Development of this SD library was funded by PJRC.COM, LLC by sales of
  5. * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
  6. * open source software by purchasing genuine Teensy or other PJRC products.
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice, development funding notice, and this permission
  16. * notice shall be included in all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. #if defined(__arm__)
  27. #include "SD_t3.h"
  28. #ifdef USE_TEENSY3_OPTIMIZED_CODE
  29. #define sector_t SDClass::sector_t
  30. #define fatdir_t SDClass::fatdir_t
  31. File SDClass::open(const char *path, uint8_t mode)
  32. {
  33. File ret, parent = rootDir;
  34. //Serial.print("SD.open: ");
  35. //Serial.println(path);
  36. while (1) {
  37. while (*path == '/') path++;
  38. if (*path == 0) {
  39. // end of pathname is "/", use last subdir
  40. ret = parent;
  41. break;
  42. }
  43. File next;
  44. bool found = parent.find(path, &next);
  45. const char *p = path;
  46. do p++; while (*p != '/' && *p != 0);
  47. if (found) {
  48. //Serial.println(" open: found");
  49. if (*p == 0) {
  50. // found the file
  51. ret = next;
  52. break;
  53. }
  54. // found next subdir
  55. parent = next;
  56. path = p;
  57. } else {
  58. //Serial.print(" open: not found ");
  59. //Serial.println(path);
  60. if (*p == '/') break; // subdir doesn't exist
  61. // file doesn't exist
  62. if (mode == FILE_READ) break;
  63. // TODO: for writing, create the file
  64. break;
  65. }
  66. }
  67. return ret;
  68. }
  69. bool SDClass::exists(const char *path)
  70. {
  71. File f = open(path);
  72. return (bool)f;
  73. }
  74. File File::openNextFile(uint8_t mode)
  75. {
  76. File f;
  77. uint32_t lba, sector_offset, sector_index, sector_count;
  78. //Serial.print("File::openNextFile, offset=");
  79. //Serial.println(offset);
  80. if (mode > FILE_READ) return f; // TODO: writing not yet supported
  81. if (type == FILE_DIR_ROOT16) {
  82. //Serial.print(" fat16 dir");
  83. sector_offset = offset >> 9;
  84. lba = start_cluster + sector_offset;
  85. sector_count = length >> 9;
  86. } else if (type == FILE_DIR) {
  87. //Serial.print(" subdir");
  88. sector_offset = cluster_offset(offset) >> 9;
  89. lba = custer_to_sector(current_cluster) + sector_offset;
  90. sector_count = (1 << SDClass::sector2cluster);
  91. } else {
  92. return f;
  93. }
  94. //Serial.print(" sector_offset=");
  95. //Serial.println(sector_offset);
  96. //Serial.print(" lba=");
  97. //Serial.println(lba);
  98. //Serial.print(" sector_count=");
  99. //Serial.println(sector_count);
  100. sector_index = (offset >> 5) & 15;
  101. //Serial.print(" sector_index=");
  102. //Serial.println(sector_index);
  103. while (1) {
  104. SDCache sector;
  105. sector_t *s = sector.read(lba);
  106. if (!s) return f;
  107. fatdir_t *dirent = s->dir + sector_index;
  108. while (sector_index < 16) {
  109. //Serial.print(" sector_index=");
  110. //Serial.println(sector_index);
  111. if (dirent->attrib != ATTR_LONG_NAME) {
  112. uint8_t b0 = dirent->name[0];
  113. //Serial.print(" b0=");
  114. //Serial.println(b0);
  115. if (b0 == 0) return f;
  116. if (b0 != 0xE5 && memcmp(dirent->name, ". ", 11) != 0
  117. && memcmp(dirent->name, ".. ", 11) != 0) {
  118. f.init(dirent);
  119. sector.release();
  120. offset += 32;
  121. if (cluster_offset(offset) == 0) {
  122. next_cluster(); // TODO: handle error
  123. }
  124. return f;
  125. }
  126. }
  127. offset += 32;
  128. dirent++;
  129. sector_index++;
  130. }
  131. sector.release();
  132. sector_index = 0;
  133. if (++sector_offset >= sector_count) {
  134. if (type == FILE_DIR_ROOT16) {
  135. break;
  136. } else {
  137. if (!next_cluster()) break;
  138. lba = custer_to_sector(current_cluster);
  139. sector_offset = 0;
  140. }
  141. }
  142. }
  143. return f;
  144. }
  145. bool File::find(const char *filename, File *found)
  146. {
  147. bool find_unused = true;
  148. char name83[11];
  149. uint32_t lba, sector_count;
  150. //Serial.println("File::open");
  151. const char *f = filename;
  152. if (*f == 0) return false;
  153. char *p = name83;
  154. while (p < name83 + 11) {
  155. char c = *f++;
  156. if (c == 0 || c == '/') {
  157. while (p < name83 + 11) *p++ = ' ';
  158. break;
  159. }
  160. if (c == '.') {
  161. while (p < name83 + 8) *p++ = ' ';
  162. continue;
  163. }
  164. if (c > 126) continue;
  165. if (c >= 'a' && c <= 'z') c -= 32;
  166. *p++ = c;
  167. }
  168. //Serial.print("name83 = ");
  169. //for (uint32_t i=0; i < 11; i++) {
  170. //Serial.printf(" %02X", name83[i]);
  171. //}
  172. //Serial.println();
  173. if (type == FILE_DIR_ROOT16) {
  174. lba = start_cluster;
  175. sector_count = length >> 9;
  176. } else if (type == FILE_DIR) {
  177. current_cluster = start_cluster;
  178. lba = custer_to_sector(start_cluster);
  179. sector_count = (1 << SDClass::sector2cluster);
  180. } else {
  181. return false; // not a directory
  182. }
  183. while (1) {
  184. for (uint32_t i=0; i < sector_count; i++) {
  185. SDCache sector;
  186. sector_t *s = sector.read(lba);
  187. if (!s) return false;
  188. fatdir_t *dirent = s->dir;
  189. for (uint32_t j=0; j < 16; j++) {
  190. if (dirent->attrib == ATTR_LONG_NAME) {
  191. // TODO: how to match long names?
  192. }
  193. if (memcmp(dirent->name, name83, 11) == 0) {
  194. //Serial.printf("found 8.3, j=%d\n", j);
  195. found->init(dirent);
  196. return true;
  197. }
  198. uint8_t b0 = dirent->name[0];
  199. if (find_unused && (b0 == 0 || b0 == 0xE5)) {
  200. found->dirent_lba = lba;
  201. found->dirent_index = j;
  202. find_unused = false;
  203. }
  204. if (b0 == 0) return false;
  205. offset += 32;
  206. dirent++;
  207. }
  208. lba++;
  209. }
  210. if (type == FILE_DIR_ROOT16) break;
  211. if (!next_cluster()) break;
  212. lba = custer_to_sector(current_cluster);
  213. //Serial.printf(" next lba = %d\n", lba);
  214. }
  215. return false;
  216. }
  217. void File::init(fatdir_t *dirent)
  218. {
  219. offset = 0;
  220. length = dirent->size;
  221. start_cluster = (dirent->cluster_high << 16) | dirent->cluster_low;
  222. current_cluster = start_cluster;
  223. type = (dirent->attrib & ATTR_DIRECTORY) ? FILE_DIR : FILE_READ;
  224. char *p = namestr;
  225. const char *s = dirent->name;
  226. for (int i=0; i < 8; i++) {
  227. if (*s == ' ') break;
  228. *p++ = *s++;
  229. }
  230. s = dirent->name + 8;
  231. if (*s != ' ') {
  232. *p++ = '.';
  233. *p++ = *s++;
  234. if (*s != ' ') *p++ = *s++;
  235. if (*s != ' ') *p++ = *s++;
  236. }
  237. *p = 0;
  238. //Serial.printf("File::init, cluster = %d, length = %d\n", start_cluster, length);
  239. }
  240. #endif
  241. #endif