My Marlin configs for Fabrikator Mini and CTC i3 Pro B
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.

SdFat.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /* Arduino SdFat Library
  2. * Copyright (C) 2009 by William Greiman
  3. *
  4. * This file is part of the Arduino SdFat Library
  5. *
  6. * This Library is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This Library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with the Arduino SdFat Library. If not, see
  18. * <http://www.gnu.org/licenses/>.
  19. */
  20. #include "SdFat.h"
  21. #include "SdFatUtil.h"
  22. //------------------------------------------------------------------------------
  23. /** Change a volume's working directory to root
  24. *
  25. * Changes the volume's working directory to the SD's root directory.
  26. * Optionally set the current working directory to the volume's
  27. * working directory.
  28. *
  29. * \param[in] set_cwd Set the current working directory to this volume's
  30. * working directory if true.
  31. *
  32. * \return The value one, true, is returned for success and
  33. * the value zero, false, is returned for failure.
  34. */
  35. bool SdFat::chdir(bool set_cwd) {
  36. if (set_cwd) SdBaseFile::cwd_ = &vwd_;
  37. vwd_.close();
  38. return vwd_.openRoot(&vol_);
  39. }
  40. //------------------------------------------------------------------------------
  41. /** Change a volume's working directory
  42. *
  43. * Changes the volume working directory to the \a path subdirectory.
  44. * Optionally set the current working directory to the volume's
  45. * working directory.
  46. *
  47. * Example: If the volume's working directory is "/DIR", chdir("SUB")
  48. * will change the volume's working directory from "/DIR" to "/DIR/SUB".
  49. *
  50. * If path is "/", the volume's working directory will be changed to the
  51. * root directory
  52. *
  53. * \param[in] path The name of the subdirectory.
  54. *
  55. * \param[in] set_cwd Set the current working directory to this volume's
  56. * working directory if true.
  57. *
  58. * \return The value one, true, is returned for success and
  59. * the value zero, false, is returned for failure.
  60. */
  61. bool SdFat::chdir(const char *path, bool set_cwd) {
  62. SdBaseFile dir;
  63. if (path[0] == '/' && path[1] == '\0') return chdir(set_cwd);
  64. if (!dir.open(&vwd_, path, O_READ)) goto fail;
  65. if (!dir.isDir()) goto fail;
  66. vwd_ = dir;
  67. if (set_cwd) SdBaseFile::cwd_ = &vwd_;
  68. return true;
  69. fail:
  70. return false;
  71. }
  72. //------------------------------------------------------------------------------
  73. /** Set the current working directory to a volume's working directory.
  74. *
  75. * This is useful with multiple SD cards.
  76. *
  77. * The current working directory is changed to this volume's working directory.
  78. *
  79. * This is like the Windows/DOS \<drive letter>: command.
  80. */
  81. void SdFat::chvol() {
  82. SdBaseFile::cwd_ = &vwd_;
  83. }
  84. //------------------------------------------------------------------------------
  85. /** %Print any SD error code and halt. */
  86. void SdFat::errorHalt() {
  87. errorPrint();
  88. while (1);
  89. }
  90. //------------------------------------------------------------------------------
  91. /** %Print msg, any SD error code, and halt.
  92. *
  93. * \param[in] msg Message to print.
  94. */
  95. void SdFat::errorHalt(char const* msg) {
  96. errorPrint(msg);
  97. while (1);
  98. }
  99. //------------------------------------------------------------------------------
  100. /** %Print msg, any SD error code, and halt.
  101. *
  102. * \param[in] msg Message in program space (flash memory) to print.
  103. */
  104. void SdFat::errorHalt_P(PGM_P msg) {
  105. errorPrint_P(msg);
  106. while (1);
  107. }
  108. //------------------------------------------------------------------------------
  109. /** %Print any SD error code. */
  110. void SdFat::errorPrint() {
  111. if (!card_.errorCode()) return;
  112. PgmPrint("SD errorCode: 0X");
  113. Serial.println(card_.errorCode(), HEX);
  114. }
  115. //------------------------------------------------------------------------------
  116. /** %Print msg, any SD error code.
  117. *
  118. * \param[in] msg Message to print.
  119. */
  120. void SdFat::errorPrint(char const* msg) {
  121. PgmPrint("error: ");
  122. Serial.println(msg);
  123. errorPrint();
  124. }
  125. //------------------------------------------------------------------------------
  126. /** %Print msg, any SD error code.
  127. *
  128. * \param[in] msg Message in program space (flash memory) to print.
  129. */
  130. void SdFat::errorPrint_P(PGM_P msg) {
  131. PgmPrint("error: ");
  132. SerialPrintln_P(msg);
  133. errorPrint();
  134. }
  135. //------------------------------------------------------------------------------
  136. /**
  137. * Test for the existence of a file.
  138. *
  139. * \param[in] name Name of the file to be tested for.
  140. *
  141. * \return true if the file exists else false.
  142. */
  143. bool SdFat::exists(const char* name) {
  144. return vwd_.exists(name);
  145. }
  146. //------------------------------------------------------------------------------
  147. /**
  148. * Initialize an SdFat object.
  149. *
  150. * Initializes the SD card, SD volume, and root directory.
  151. *
  152. * \param[in] sckRateID value for SPI SCK rate. See Sd2Card::init().
  153. * \param[in] chipSelectPin SD chip select pin. See Sd2Card::init().
  154. *
  155. * \return The value one, true, is returned for success and
  156. * the value zero, false, is returned for failure.
  157. */
  158. bool SdFat::init(uint8_t sckRateID, uint8_t chipSelectPin) {
  159. return card_.init(sckRateID, chipSelectPin) && vol_.init(&card_) && chdir(1);
  160. }
  161. //------------------------------------------------------------------------------
  162. /** %Print error details and halt after SdFat::init() fails. */
  163. void SdFat::initErrorHalt() {
  164. initErrorPrint();
  165. while (1);
  166. }
  167. //------------------------------------------------------------------------------
  168. /**Print message, error details, and halt after SdFat::init() fails.
  169. *
  170. * \param[in] msg Message to print.
  171. */
  172. void SdFat::initErrorHalt(char const *msg) {
  173. Serial.println(msg);
  174. initErrorHalt();
  175. }
  176. //------------------------------------------------------------------------------
  177. /**Print message, error details, and halt after SdFat::init() fails.
  178. *
  179. * \param[in] msg Message in program space (flash memory) to print.
  180. */
  181. void SdFat::initErrorHalt_P(PGM_P msg) {
  182. SerialPrintln_P(msg);
  183. initErrorHalt();
  184. }
  185. //------------------------------------------------------------------------------
  186. /** Print error details after SdFat::init() fails. */
  187. void SdFat::initErrorPrint() {
  188. if (card_.errorCode()) {
  189. PgmPrintln("Can't access SD card. Do not reformat.");
  190. if (card_.errorCode() == SD_CARD_ERROR_CMD0) {
  191. PgmPrintln("No card, wrong chip select pin, or SPI problem?");
  192. }
  193. errorPrint();
  194. } else if (vol_.fatType() == 0) {
  195. PgmPrintln("Invalid format, reformat SD.");
  196. } else if (!vwd_.isOpen()) {
  197. PgmPrintln("Can't open root directory.");
  198. } else {
  199. PgmPrintln("No error found.");
  200. }
  201. }
  202. //------------------------------------------------------------------------------
  203. /**Print message and error details and halt after SdFat::init() fails.
  204. *
  205. * \param[in] msg Message to print.
  206. */
  207. void SdFat::initErrorPrint(char const *msg) {
  208. Serial.println(msg);
  209. initErrorPrint();
  210. }
  211. //------------------------------------------------------------------------------
  212. /**Print message and error details after SdFat::init() fails.
  213. *
  214. * \param[in] msg Message in program space (flash memory) to print.
  215. */
  216. void SdFat::initErrorPrint_P(PGM_P msg) {
  217. SerialPrintln_P(msg);
  218. initErrorHalt();
  219. }
  220. //------------------------------------------------------------------------------
  221. /** List the directory contents of the volume working directory to Serial.
  222. *
  223. * \param[in] flags The inclusive OR of
  224. *
  225. * LS_DATE - %Print file modification date
  226. *
  227. * LS_SIZE - %Print file size.
  228. *
  229. * LS_R - Recursive list of subdirectories.
  230. */
  231. void SdFat::ls(uint8_t flags) {
  232. vwd_.ls(&Serial, flags);
  233. }
  234. //------------------------------------------------------------------------------
  235. /** List the directory contents of the volume working directory to Serial.
  236. *
  237. * \param[in] pr Print stream for list.
  238. *
  239. * \param[in] flags The inclusive OR of
  240. *
  241. * LS_DATE - %Print file modification date
  242. *
  243. * LS_SIZE - %Print file size.
  244. *
  245. * LS_R - Recursive list of subdirectories.
  246. */
  247. void SdFat::ls(Print* pr, uint8_t flags) {
  248. vwd_.ls(pr, flags);
  249. }
  250. //------------------------------------------------------------------------------
  251. /** Make a subdirectory in the volume working directory.
  252. *
  253. * \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
  254. *
  255. * \param[in] pFlag Create missing parent directories if true.
  256. *
  257. * \return The value one, true, is returned for success and
  258. * the value zero, false, is returned for failure.
  259. */
  260. bool SdFat::mkdir(const char* path, bool pFlag) {
  261. SdBaseFile sub;
  262. return sub.mkdir(&vwd_, path, pFlag);
  263. }
  264. //------------------------------------------------------------------------------
  265. /** Remove a file from the volume working directory.
  266. *
  267. * \param[in] path A path with a valid 8.3 DOS name for the file.
  268. *
  269. * \return The value one, true, is returned for success and
  270. * the value zero, false, is returned for failure.
  271. */
  272. bool SdFat::remove(const char* path) {
  273. return SdBaseFile::remove(&vwd_, path);
  274. }
  275. //------------------------------------------------------------------------------
  276. /** Rename a file or subdirectory.
  277. *
  278. * \param[in] oldPath Path name to the file or subdirectory to be renamed.
  279. *
  280. * \param[in] newPath New path name of the file or subdirectory.
  281. *
  282. * The \a newPath object must not exist before the rename call.
  283. *
  284. * The file to be renamed must not be open. The directory entry may be
  285. * moved and file system corruption could occur if the file is accessed by
  286. * a file object that was opened before the rename() call.
  287. *
  288. * \return The value one, true, is returned for success and
  289. * the value zero, false, is returned for failure.
  290. */
  291. bool SdFat::rename(const char *oldPath, const char *newPath) {
  292. SdBaseFile file;
  293. if (!file.open(oldPath, O_READ)) return false;
  294. return file.rename(&vwd_, newPath);
  295. }
  296. //------------------------------------------------------------------------------
  297. /** Remove a subdirectory from the volume's working directory.
  298. *
  299. * \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
  300. *
  301. * The subdirectory file will be removed only if it is empty.
  302. *
  303. * \return The value one, true, is returned for success and
  304. * the value zero, false, is returned for failure.
  305. */
  306. bool SdFat::rmdir(const char* path) {
  307. SdBaseFile sub;
  308. if (!sub.open(path, O_READ)) return false;
  309. return sub.rmdir();
  310. }
  311. //------------------------------------------------------------------------------
  312. /** Truncate a file to a specified length. The current file position
  313. * will be maintained if it is less than or equal to \a length otherwise
  314. * it will be set to end of file.
  315. *
  316. * \param[in] path A path with a valid 8.3 DOS name for the file.
  317. * \param[in] length The desired length for the file.
  318. *
  319. * \return The value one, true, is returned for success and
  320. * the value zero, false, is returned for failure.
  321. * Reasons for failure include file is read only, file is a directory,
  322. * \a length is greater than the current file size or an I/O error occurs.
  323. */
  324. bool SdFat::truncate(const char* path, uint32_t length) {
  325. SdBaseFile file;
  326. if (!file.open(path, O_WRITE)) return false;
  327. return file.truncate(length);
  328. }