Browse Source

Add SD library (not optimised).

flabbergast 4 years ago
parent
commit
2c954a58e4

+ 150
- 0
xmega/libraries/SD/File.cpp View File

@@ -0,0 +1,150 @@
1
+/*
2
+
3
+ SD - a slightly more friendly wrapper for sdfatlib
4
+
5
+ This library aims to expose a subset of SD card functionality
6
+ in the form of a higher level "wrapper" object.
7
+
8
+ License: GNU General Public License V3
9
+          (Because sdfatlib is licensed with this.)
10
+
11
+ (C) Copyright 2010 SparkFun Electronics
12
+
13
+ */
14
+
15
+#include <SD.h>
16
+
17
+/* for debugging file open/close leaks
18
+   uint8_t nfilecount=0;
19
+*/
20
+
21
+File::File(SdFile f, const char *n) {
22
+  // oh man you are kidding me, new() doesnt exist? Ok we do it by hand!
23
+  _file = (SdFile *)malloc(sizeof(SdFile)); 
24
+  if (_file) {
25
+    memcpy(_file, &f, sizeof(SdFile));
26
+    
27
+    strncpy(_name, n, 12);
28
+    _name[12] = 0;
29
+    
30
+    /* for debugging file open/close leaks
31
+       nfilecount++;
32
+       Serial.print("Created \"");
33
+       Serial.print(n);
34
+       Serial.print("\": ");
35
+       Serial.println(nfilecount, DEC);
36
+    */
37
+  }
38
+}
39
+
40
+File::File(void) {
41
+  _file = 0;
42
+  _name[0] = 0;
43
+  //Serial.print("Created empty file object");
44
+}
45
+
46
+File::~File(void) {
47
+  //  Serial.print("Deleted file object");
48
+}
49
+
50
+// returns a pointer to the file name
51
+char *File::name(void) {
52
+  return _name;
53
+}
54
+
55
+// a directory is a special type of file
56
+boolean File::isDirectory(void) {
57
+  return (_file && _file->isDir());
58
+}
59
+
60
+
61
+size_t File::write(uint8_t val) {
62
+  return write(&val, 1);
63
+}
64
+
65
+size_t File::write(const uint8_t *buf, size_t size) {
66
+  size_t t;
67
+  if (!_file) {
68
+    setWriteError();
69
+    return 0;
70
+  }
71
+  _file->clearWriteError();
72
+  t = _file->write(buf, size);
73
+  if (_file->getWriteError()) {
74
+    setWriteError();
75
+    return 0;
76
+  }
77
+  return t;
78
+}
79
+
80
+int File::peek() {
81
+  if (! _file) 
82
+    return 0;
83
+
84
+  int c = _file->read();
85
+  if (c != -1) _file->seekCur(-1);
86
+  return c;
87
+}
88
+
89
+int File::read() {
90
+  if (_file) 
91
+    return _file->read();
92
+  return -1;
93
+}
94
+
95
+// buffered read for more efficient, high speed reading
96
+int File::read(void *buf, uint16_t nbyte) {
97
+  if (_file) 
98
+    return _file->read(buf, nbyte);
99
+  return 0;
100
+}
101
+
102
+int File::available() {
103
+  if (! _file) return 0;
104
+
105
+  uint32_t n = size() - position();
106
+
107
+  return n > 0X7FFF ? 0X7FFF : n;
108
+}
109
+
110
+void File::flush() {
111
+  if (_file)
112
+    _file->sync();
113
+}
114
+
115
+boolean File::seek(uint32_t pos) {
116
+  if (! _file) return false;
117
+
118
+  return _file->seekSet(pos);
119
+}
120
+
121
+uint32_t File::position() {
122
+  if (! _file) return -1;
123
+  return _file->curPosition();
124
+}
125
+
126
+uint32_t File::size() {
127
+  if (! _file) return 0;
128
+  return _file->fileSize();
129
+}
130
+
131
+void File::close() {
132
+  if (_file) {
133
+    _file->close();
134
+    free(_file); 
135
+    _file = 0;
136
+
137
+    /* for debugging file open/close leaks
138
+    nfilecount--;
139
+    Serial.print("Deleted ");
140
+    Serial.println(nfilecount, DEC);
141
+    */
142
+  }
143
+}
144
+
145
+File::operator bool() {
146
+  if (_file) 
147
+    return  _file->isOpen();
148
+  return false;
149
+}
150
+

+ 15
- 0
xmega/libraries/SD/README.txt View File

@@ -0,0 +1,15 @@
1
+** SD - a slightly more friendly wrapper for sdfatlib **
2
+
3
+This library aims to expose a subset of SD card functionality in the
4
+form of a higher level "wrapper" object.
5
+
6
+License: GNU General Public License V3
7
+         (Because sdfatlib is licensed with this.)
8
+
9
+(C) Copyright 2010 SparkFun Electronics
10
+
11
+Now better than ever with optimization, multiple file support, directory handling, etc - ladyada!
12
+
13
+Modifications for XMEGA (c) 2015 flabbergast - taken from Teensyduino 1.22.
14
+Not optimised in any way on XMEGAs.
15
+

+ 616
- 0
xmega/libraries/SD/SD.cpp View File

@@ -0,0 +1,616 @@
1
+/*
2
+
3
+ SD - a slightly more friendly wrapper for sdfatlib
4
+
5
+ This library aims to expose a subset of SD card functionality
6
+ in the form of a higher level "wrapper" object.
7
+
8
+ License: GNU General Public License V3
9
+          (Because sdfatlib is licensed with this.)
10
+
11
+ (C) Copyright 2010 SparkFun Electronics
12
+
13
+
14
+ This library provides four key benefits:
15
+
16
+   * Including `XSD.h` automatically creates a global
17
+     `SD` object which can be interacted with in a similar
18
+     manner to other standard global objects like `Serial` and `Ethernet`.
19
+
20
+   * Boilerplate initialisation code is contained in one method named
21
+     `begin` and no further objects need to be created in order to access
22
+     the SD card.
23
+
24
+   * Calls to `open` can supply a full path name including parent
25
+     directories which simplifies interacting with files in subdirectories.
26
+
27
+   * Utility methods are provided to determine whether a file exists
28
+     and to create a directory heirarchy.
29
+
30
+
31
+  Note however that not all functionality provided by the underlying
32
+  sdfatlib library is exposed.
33
+
34
+ */
35
+
36
+/*
37
+
38
+  Implementation Notes
39
+
40
+  In order to handle multi-directory path traversal, functionality that
41
+  requires this ability is implemented as callback functions.
42
+
43
+  Individual methods call the `walkPath` function which performs the actual
44
+  directory traversal (swapping between two different directory/file handles
45
+  along the way) and at each level calls the supplied callback function.
46
+
47
+  Some types of functionality will take an action at each level (e.g. exists
48
+  or make directory) which others will only take an action at the bottom
49
+  level (e.g. open).
50
+
51
+ */
52
+
53
+#include "SD.h"
54
+
55
+// Used by `getNextPathComponent`
56
+#define MAX_COMPONENT_LEN 12 // What is max length?
57
+#define PATH_COMPONENT_BUFFER_LEN MAX_COMPONENT_LEN+1
58
+
59
+bool getNextPathComponent(char *path, unsigned int *p_offset,
60
+			  char *buffer) {
61
+  /*
62
+
63
+    Parse individual path components from a path.
64
+
65
+      e.g. after repeated calls '/foo/bar/baz' will be split
66
+           into 'foo', 'bar', 'baz'.
67
+
68
+    This is similar to `strtok()` but copies the component into the
69
+    supplied buffer rather than modifying the original string.
70
+
71
+
72
+    `buffer` needs to be PATH_COMPONENT_BUFFER_LEN in size.
73
+
74
+    `p_offset` needs to point to an integer of the offset at
75
+    which the previous path component finished.
76
+
77
+    Returns `true` if more components remain.
78
+
79
+    Returns `false` if this is the last component.
80
+      (This means path ended with 'foo' or 'foo/'.)
81
+
82
+   */
83
+
84
+  // TODO: Have buffer local to this function, so we know it's the
85
+  //       correct length?
86
+
87
+  int bufferOffset = 0;
88
+
89
+  int offset = *p_offset;
90
+
91
+  // Skip root or other separator
92
+  if (path[offset] == '/') {
93
+    offset++;
94
+  }
95
+
96
+  // Copy the next next path segment
97
+  while (bufferOffset < MAX_COMPONENT_LEN
98
+	 && (path[offset] != '/')
99
+	 && (path[offset] != '\0')) {
100
+    buffer[bufferOffset++] = path[offset++];
101
+  }
102
+
103
+  buffer[bufferOffset] = '\0';
104
+
105
+  // Skip trailing separator so we can determine if this
106
+  // is the last component in the path or not.
107
+  if (path[offset] == '/') {
108
+    offset++;
109
+  }
110
+
111
+  *p_offset = offset;
112
+
113
+  return (path[offset] != '\0');
114
+}
115
+
116
+
117
+
118
+boolean walkPath(char *filepath, SdFile& parentDir,
119
+		 boolean (*callback)(SdFile& parentDir,
120
+				     char *filePathComponent,
121
+				     boolean isLastComponent,
122
+				     void *object),
123
+		 void *object = NULL) {
124
+  /*
125
+
126
+     When given a file path (and parent directory--normally root),
127
+     this function traverses the directories in the path and at each
128
+     level calls the supplied callback function while also providing
129
+     the supplied object for context if required.
130
+
131
+       e.g. given the path '/foo/bar/baz'
132
+            the callback would be called at the equivalent of
133
+	    '/foo', '/foo/bar' and '/foo/bar/baz'.
134
+
135
+     The implementation swaps between two different directory/file
136
+     handles as it traverses the directories and does not use recursion
137
+     in an attempt to use memory efficiently.
138
+
139
+     If a callback wishes to stop the directory traversal it should
140
+     return false--in this case the function will stop the traversal,
141
+     tidy up and return false.
142
+
143
+     If a directory path doesn't exist at some point this function will
144
+     also return false and not subsequently call the callback.
145
+
146
+     If a directory path specified is complete, valid and the callback
147
+     did not indicate the traversal should be interrupted then this
148
+     function will return true.
149
+
150
+   */
151
+
152
+
153
+  SdFile subfile1;
154
+  SdFile subfile2;
155
+
156
+  char buffer[PATH_COMPONENT_BUFFER_LEN];
157
+
158
+  unsigned int offset = 0;
159
+
160
+  SdFile *p_parent;
161
+  SdFile *p_child;
162
+
163
+  SdFile *p_tmp_sdfile;
164
+
165
+  p_child = &subfile1;
166
+
167
+  p_parent = &parentDir;
168
+
169
+  while (true) {
170
+
171
+    boolean moreComponents = getNextPathComponent(filepath, &offset, buffer);
172
+
173
+    boolean shouldContinue = callback((*p_parent), buffer, !moreComponents, object);
174
+
175
+    if (!shouldContinue) {
176
+      // TODO: Don't repeat this code?
177
+      // If it's one we've created then we
178
+      // don't need the parent handle anymore.
179
+      if (p_parent != &parentDir) {
180
+        (*p_parent).close();
181
+      }
182
+      return false;
183
+    }
184
+
185
+    if (!moreComponents) {
186
+      break;
187
+    }
188
+
189
+    boolean exists = (*p_child).open(*p_parent, buffer, O_RDONLY);
190
+
191
+    // If it's one we've created then we
192
+    // don't need the parent handle anymore.
193
+    if (p_parent != &parentDir) {
194
+      (*p_parent).close();
195
+    }
196
+
197
+    // Handle case when it doesn't exist and we can't continue...
198
+    if (exists) {
199
+      // We alternate between two file handles as we go down
200
+      // the path.
201
+      if (p_parent == &parentDir) {
202
+        p_parent = &subfile2;
203
+      }
204
+
205
+      p_tmp_sdfile = p_parent;
206
+      p_parent = p_child;
207
+      p_child = p_tmp_sdfile;
208
+    } else {
209
+      return false;
210
+    }
211
+  }
212
+
213
+  if (p_parent != &parentDir) {
214
+    (*p_parent).close(); // TODO: Return/ handle different?
215
+  }
216
+
217
+  return true;
218
+}
219
+
220
+
221
+
222
+/*
223
+
224
+   The callbacks used to implement various functionality follow.
225
+
226
+   Each callback is supplied with a parent directory handle,
227
+   character string with the name of the current file path component,
228
+   a flag indicating if this component is the last in the path and
229
+   a pointer to an arbitrary object used for context.
230
+
231
+ */
232
+
233
+boolean callback_pathExists(SdFile& parentDir, char *filePathComponent,
234
+			    boolean isLastComponent, void *object) {
235
+  /*
236
+
237
+    Callback used to determine if a file/directory exists in parent
238
+    directory.
239
+
240
+    Returns true if file path exists.
241
+
242
+  */
243
+  SdFile child;
244
+
245
+  boolean exists = child.open(parentDir, filePathComponent, O_RDONLY);
246
+
247
+  if (exists) {
248
+     child.close();
249
+  }
250
+
251
+  return exists;
252
+}
253
+
254
+
255
+
256
+boolean callback_makeDirPath(SdFile& parentDir, char *filePathComponent,
257
+			     boolean isLastComponent, void *object) {
258
+  /*
259
+
260
+    Callback used to create a directory in the parent directory if
261
+    it does not already exist.
262
+
263
+    Returns true if a directory was created or it already existed.
264
+
265
+  */
266
+  boolean result = false;
267
+  SdFile child;
268
+
269
+  result = callback_pathExists(parentDir, filePathComponent, isLastComponent, object);
270
+  if (!result) {
271
+    result = child.makeDir(parentDir, filePathComponent);
272
+  }
273
+
274
+  return result;
275
+}
276
+
277
+
278
+  /*
279
+
280
+boolean callback_openPath(SdFile& parentDir, char *filePathComponent,
281
+			  boolean isLastComponent, void *object) {
282
+
283
+    Callback used to open a file specified by a filepath that may
284
+    specify one or more directories above it.
285
+
286
+    Expects the context object to be an instance of `SDClass` and
287
+    will use the `file` property of the instance to open the requested
288
+    file/directory with the associated file open mode property.
289
+
290
+    Always returns true if the directory traversal hasn't reached the
291
+    bottom of the directory heirarchy.
292
+
293
+    Returns false once the file has been opened--to prevent the traversal
294
+    from descending further. (This may be unnecessary.)
295
+
296
+  if (isLastComponent) {
297
+    SDClass *p_SD = static_cast<SDClass*>(object);
298
+    p_SD->file.open(parentDir, filePathComponent, p_SD->fileOpenMode);
299
+    if (p_SD->fileOpenMode == FILE_WRITE) {
300
+      p_SD->file.seekSet(p_SD->file.fileSize());
301
+    }
302
+    // TODO: Return file open result?
303
+    return false;
304
+  }
305
+  return true;
306
+}
307
+  */
308
+
309
+
310
+
311
+boolean callback_remove(SdFile& parentDir, char *filePathComponent,
312
+			boolean isLastComponent, void *object) {
313
+  if (isLastComponent) {
314
+    return SdFile::remove(parentDir, filePathComponent);
315
+  }
316
+  return true;
317
+}
318
+
319
+boolean callback_rmdir(SdFile& parentDir, char *filePathComponent,
320
+			boolean isLastComponent, void *object) {
321
+  if (isLastComponent) {
322
+    SdFile f;
323
+    if (!f.open(parentDir, filePathComponent, O_READ)) return false;
324
+    return f.rmDir();
325
+  }
326
+  return true;
327
+}
328
+
329
+
330
+
331
+/* Implementation of class used to create `SDCard` object. */
332
+
333
+
334
+
335
+boolean SDClass::begin(uint8_t csPin) {
336
+  /*
337
+
338
+    Performs the initialisation required by the sdfatlib library.
339
+
340
+    Return true if initialization succeeds, false otherwise.
341
+
342
+   */
343
+  return card.init(SPI_HALF_SPEED, csPin) &&
344
+         volume.init(card) &&
345
+         root.openRoot(volume);
346
+}
347
+
348
+
349
+
350
+// this little helper is used to traverse paths
351
+SdFile SDClass::getParentDir(const char *filepath, int *index) {
352
+  // get parent directory
353
+  SdFile d1 = root; // start with the mostparent, root!
354
+  SdFile d2;
355
+
356
+  // we'll use the pointers to swap between the two objects
357
+  SdFile *parent = &d1;
358
+  SdFile *subdir = &d2;
359
+
360
+  const char *origpath = filepath;
361
+
362
+  while (strchr(filepath, '/')) {
363
+
364
+    // get rid of leading /'s
365
+    if (filepath[0] == '/') {
366
+      filepath++;
367
+      continue;
368
+    }
369
+
370
+    if (! strchr(filepath, '/')) {
371
+      // it was in the root directory, so leave now
372
+      break;
373
+    }
374
+
375
+    // extract just the name of the next subdirectory
376
+    uint8_t idx = strchr(filepath, '/') - filepath;
377
+    if (idx > 12)
378
+      idx = 12;    // dont let them specify long names
379
+    char subdirname[13];
380
+    strncpy(subdirname, filepath, idx);
381
+    subdirname[idx] = 0;
382
+
383
+    // close the subdir (we reuse them) if open
384
+    subdir->close();
385
+    if (! subdir->open(parent, subdirname, O_READ)) {
386
+      // failed to open one of the subdirectories
387
+      return SdFile();
388
+    }
389
+    // move forward to the next subdirectory
390
+    filepath += idx;
391
+
392
+    // we reuse the objects, close it.
393
+    parent->close();
394
+
395
+    // swap the pointers
396
+    SdFile *t = parent;
397
+    parent = subdir;
398
+    subdir = t;
399
+  }
400
+
401
+  *index = (int)(filepath - origpath);
402
+  // parent is now the parent diretory of the file!
403
+  return *parent;
404
+}
405
+
406
+
407
+File SDClass::open(const char *filepath, uint8_t mode) {
408
+  /*
409
+
410
+     Open the supplied file path for reading or writing.
411
+
412
+     The file content can be accessed via the `file` property of
413
+     the `SDClass` object--this property is currently
414
+     a standard `SdFile` object from `sdfatlib`.
415
+
416
+     Defaults to read only.
417
+
418
+     If `write` is true, default action (when `append` is true) is to
419
+     append data to the end of the file.
420
+
421
+     If `append` is false then the file will be truncated first.
422
+
423
+     If the file does not exist and it is opened for writing the file
424
+     will be created.
425
+
426
+     An attempt to open a file for reading that does not exist is an
427
+     error.
428
+
429
+   */
430
+
431
+  int pathidx;
432
+
433
+  // do the interative search
434
+  SdFile parentdir = getParentDir(filepath, &pathidx);
435
+  // no more subdirs!
436
+
437
+  filepath += pathidx;
438
+
439
+  if (! filepath[0]) {
440
+    // it was the directory itself!
441
+    return File(parentdir, "/");
442
+  }
443
+
444
+  // Open the file itself
445
+  SdFile file;
446
+
447
+  // failed to open a subdir!
448
+  if (!parentdir.isOpen())
449
+    return File();
450
+
451
+  // there is a special case for the Root directory since its a static dir
452
+  if (parentdir.isRoot()) {
453
+    if ( ! file.open(SD.root, filepath, mode)) {
454
+      // failed to open the file :(
455
+      return File();
456
+    }
457
+    // dont close the root!
458
+  } else {
459
+    if ( ! file.open(parentdir, filepath, mode)) {
460
+      return File();
461
+    }
462
+    // close the parent
463
+    parentdir.close();
464
+  }
465
+
466
+  if (mode & (O_APPEND | O_WRITE))
467
+    file.seekSet(file.fileSize());
468
+  return File(file, filepath);
469
+}
470
+
471
+
472
+/*
473
+File SDClass::open(char *filepath, uint8_t mode) {
474
+  //
475
+
476
+     Open the supplied file path for reading or writing.
477
+
478
+     The file content can be accessed via the `file` property of
479
+     the `SDClass` object--this property is currently
480
+     a standard `SdFile` object from `sdfatlib`.
481
+
482
+     Defaults to read only.
483
+
484
+     If `write` is true, default action (when `append` is true) is to
485
+     append data to the end of the file.
486
+
487
+     If `append` is false then the file will be truncated first.
488
+
489
+     If the file does not exist and it is opened for writing the file
490
+     will be created.
491
+
492
+     An attempt to open a file for reading that does not exist is an
493
+     error.
494
+
495
+   //
496
+
497
+  // TODO: Allow for read&write? (Possibly not, as it requires seek.)
498
+
499
+  fileOpenMode = mode;
500
+  walkPath(filepath, root, callback_openPath, this);
501
+
502
+  return File();
503
+
504
+}
505
+*/
506
+
507
+
508
+//boolean SDClass::close() {
509
+//  /*
510
+//
511
+//    Closes the file opened by the `open` method.
512
+//
513
+//   */
514
+//  file.close();
515
+//}
516
+
517
+
518
+boolean SDClass::exists(char *filepath) {
519
+  /*
520
+
521
+     Returns true if the supplied file path exists.
522
+
523
+   */
524
+  return walkPath(filepath, root, callback_pathExists);
525
+}
526
+
527
+
528
+//boolean SDClass::exists(char *filepath, SdFile& parentDir) {
529
+//  /*
530
+//
531
+//     Returns true if the supplied file path rooted at `parentDir`
532
+//     exists.
533
+//
534
+//   */
535
+//  return walkPath(filepath, parentDir, callback_pathExists);
536
+//}
537
+
538
+
539
+boolean SDClass::mkdir(char *filepath) {
540
+  /*
541
+
542
+    Makes a single directory or a heirarchy of directories.
543
+
544
+    A rough equivalent to `mkdir -p`.
545
+
546
+   */
547
+  return walkPath(filepath, root, callback_makeDirPath);
548
+}
549
+
550
+boolean SDClass::rmdir(char *filepath) {
551
+  /*
552
+
553
+    Makes a single directory or a heirarchy of directories.
554
+
555
+    A rough equivalent to `mkdir -p`.
556
+
557
+   */
558
+  return walkPath(filepath, root, callback_rmdir);
559
+}
560
+
561
+boolean SDClass::remove(char *filepath) {
562
+  return walkPath(filepath, root, callback_remove);
563
+}
564
+
565
+
566
+// allows you to recurse into a directory
567
+File File::openNextFile(uint8_t mode) {
568
+  dir_t p;
569
+
570
+  //Serial.print("\t\treading dir...");
571
+  while (_file->readDir(&p) > 0) {
572
+
573
+    // done if past last used entry
574
+    if (p.name[0] == DIR_NAME_FREE) {
575
+      //Serial.println("end");
576
+      return File();
577
+    }
578
+
579
+    // skip deleted entry and entries for . and  ..
580
+    if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') {
581
+      //Serial.println("dots");
582
+      continue;
583
+    }
584
+
585
+    // only list subdirectories and files
586
+    if (!DIR_IS_FILE_OR_SUBDIR(&p)) {
587
+      //Serial.println("notafile");
588
+      continue;
589
+    }
590
+
591
+    // print file name with possible blank fill
592
+    SdFile f;
593
+    char name[13];
594
+    _file->dirName(p, name);
595
+    //Serial.print("try to open file ");
596
+    //Serial.println(name);
597
+
598
+    if (f.open(_file, name, mode)) {
599
+      //Serial.println("OK!");
600
+      return File(f, name);
601
+    } else {
602
+      //Serial.println("ugh");
603
+      return File();
604
+    }
605
+  }
606
+
607
+  //Serial.println("nothing");
608
+  return File();
609
+}
610
+
611
+void File::rewindDirectory(void) {
612
+  if (isDirectory())
613
+    _file->rewind();
614
+}
615
+
616
+SDClass SD;

+ 103
- 0
xmega/libraries/SD/SD.h View File

@@ -0,0 +1,103 @@
1
+/*
2
+
3
+ SD - a slightly more friendly wrapper for sdfatlib
4
+
5
+ This library aims to expose a subset of SD card functionality
6
+ in the form of a higher level "wrapper" object.
7
+
8
+ License: GNU General Public License V3
9
+          (Because sdfatlib is licensed with this.)
10
+
11
+ (C) Copyright 2010 SparkFun Electronics
12
+
13
+ */
14
+
15
+#ifndef __SD_H__
16
+#define __SD_H__
17
+
18
+#include <Arduino.h>
19
+
20
+#include <utility/SdFat.h>
21
+#include <utility/SdFatUtil.h>
22
+
23
+#define FILE_READ O_READ
24
+#define FILE_WRITE (O_READ | O_WRITE | O_CREAT)
25
+
26
+class File : public Stream {
27
+ private:
28
+  char _name[13]; // our name
29
+  SdFile *_file;  // underlying file pointer
30
+
31
+public:
32
+  File(SdFile f, const char *name);     // wraps an underlying SdFile
33
+  File(void);      // 'empty' constructor
34
+  ~File(void);     // destructor
35
+  virtual size_t write(uint8_t);
36
+  virtual size_t write(const uint8_t *buf, size_t size);
37
+  virtual int read();
38
+  virtual int peek();
39
+  virtual int available();
40
+  virtual void flush();
41
+  int read(void *buf, uint16_t nbyte);
42
+  boolean seek(uint32_t pos);
43
+  uint32_t position();
44
+  uint32_t size();
45
+  void close();
46
+  operator bool();
47
+  char * name();
48
+
49
+  boolean isDirectory(void);
50
+  File openNextFile(uint8_t mode = O_RDONLY);
51
+  void rewindDirectory(void);
52
+
53
+  using Print::write;
54
+};
55
+
56
+class SDClass {
57
+
58
+private:
59
+  // These are required for initialisation and use of sdfatlib
60
+  Sd2Card card;
61
+  SdVolume volume;
62
+  SdFile root;
63
+
64
+  // my quick&dirty iterator, should be replaced
65
+  SdFile getParentDir(const char *filepath, int *indx);
66
+public:
67
+  // This needs to be called to set up the connection to the SD card
68
+  // before other methods are used.
69
+  boolean begin(uint8_t csPin = SD_CHIP_SELECT_PIN);
70
+
71
+  // Open the specified file/directory with the supplied mode (e.g. read or
72
+  // write, etc). Returns a File object for interacting with the file.
73
+  // Note that currently only one file can be open at a time.
74
+  File open(const char *filename, uint8_t mode = FILE_READ);
75
+
76
+  // Methods to determine if the requested file path exists.
77
+  boolean exists(char *filepath);
78
+
79
+  // Create the requested directory heirarchy--if intermediate directories
80
+  // do not exist they will be created.
81
+  boolean mkdir(char *filepath);
82
+
83
+  // Delete the file.
84
+  boolean remove(char *filepath);
85
+
86
+  boolean rmdir(char *filepath);
87
+
88
+private:
89
+
90
+  // This is used to determine the mode used to open a file
91
+  // it's here because it's the easiest place to pass the 
92
+  // information through the directory walking function. But
93
+  // it's probably not the best place for it.
94
+  // It shouldn't be set directly--it is set via the parameters to `open`.
95
+  int fileOpenMode;
96
+
97
+  friend class File;
98
+  friend boolean callback_openPath(SdFile&, char *, boolean, void *); 
99
+};
100
+
101
+extern SDClass SD;
102
+
103
+#endif

+ 124
- 0
xmega/libraries/SD/examples/CardInfo/CardInfo.ino View File

@@ -0,0 +1,124 @@
1
+/*
2
+  SD card test 
3
+   
4
+ This example shows how use the utility libraries on which the'
5
+ SD library is based in order to get info about your SD card.
6
+ Very useful for testing a card when you're not sure whether its working or not.
7
+ 	
8
+ The circuit:
9
+  * SD card attached to SPI bus as follows:
10
+ ** MOSI - pin 11 on Arduino Uno/Duemilanove/Diecimila
11
+ ** MISO - pin 12 on Arduino Uno/Duemilanove/Diecimila
12
+ ** CLK - pin 13 on Arduino Uno/Duemilanove/Diecimila
13
+ ** CS - depends on your SD card shield or module. 
14
+ 		Pin 4 used here for consistency with other Arduino examples
15
+
16
+ 
17
+ created  28 Mar 2011
18
+ by Limor Fried 
19
+ modified 9 Apr 2012
20
+ by Tom Igoe
21
+ */
22
+ // include the SD library:
23
+#include <SD.h>
24
+#include <SPI.h>
25
+
26
+// set up variables using the SD utility library functions:
27
+Sd2Card card;
28
+SdVolume volume;
29
+SdFile root;
30
+
31
+// change this to match your SD shield or module;
32
+// Arduino Ethernet shield: pin 4
33
+// Adafruit SD shields and modules: pin 10
34
+// Sparkfun SD shield: pin 8
35
+// Teensy 2.0: pin 0
36
+// Teensy++ 2.0: pin 20
37
+#if defined(XMEGA_XA4U)
38
+const int chipSelect = 22;
39
+#else
40
+const int chipSelect = 4;
41
+#endif
42
+
43
+void setup()
44
+{
45
+ // Open serial communications and wait for port to open:
46
+  Serial.begin(9600);
47
+   while (!Serial) {
48
+    ; // wait for serial port to connect. Needed for Leonardo only
49
+  }
50
+
51
+
52
+  Serial.print("\nInitializing SD card...");
53
+  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
54
+  // Note that even if it's not used as the CS pin, the hardware SS pin 
55
+  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
56
+  // or the SD library functions will not work. 
57
+  pinMode(10, OUTPUT);     // change this to 53 on a mega
58
+
59
+
60
+  // we'll use the initialization code from the utility libraries
61
+  // since we're just testing if the card is working!
62
+  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
63
+    Serial.println("initialization failed. Things to check:");
64
+    Serial.println("* is a card is inserted?");
65
+    Serial.println("* Is your wiring correct?");
66
+    Serial.println("* did you change the chipSelect pin to match your shield or module?");
67
+    return;
68
+  } else {
69
+   Serial.println("Wiring is correct and a card is present."); 
70
+  }
71
+
72
+  // print the type of card
73
+  Serial.print("\nCard type: ");
74
+  switch(card.type()) {
75
+    case SD_CARD_TYPE_SD1:
76
+      Serial.println("SD1");
77
+      break;
78
+    case SD_CARD_TYPE_SD2:
79
+      Serial.println("SD2");
80
+      break;
81
+    case SD_CARD_TYPE_SDHC:
82
+      Serial.println("SDHC");
83
+      break;
84
+    default:
85
+      Serial.println("Unknown");
86
+  }
87
+
88
+  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
89
+  if (!volume.init(card)) {
90
+    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
91
+    return;
92
+  }
93
+
94
+
95
+  // print the type and size of the first FAT-type volume
96
+  uint32_t volumesize;
97
+  Serial.print("\nVolume type is FAT");
98
+  Serial.println(volume.fatType(), DEC);
99
+  Serial.println();
100
+  
101
+  volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
102
+  volumesize *= volume.clusterCount();       // we'll have a lot of clusters
103
+  volumesize *= 512;                            // SD card blocks are always 512 bytes
104
+  Serial.print("Volume size (bytes): ");
105
+  Serial.println(volumesize);
106
+  Serial.print("Volume size (Kbytes): ");
107
+  volumesize /= 1024;
108
+  Serial.println(volumesize);
109
+  Serial.print("Volume size (Mbytes): ");
110
+  volumesize /= 1024;
111
+  Serial.println(volumesize);
112
+
113
+  
114
+  Serial.println("\nFiles found on the card (name, date and size in bytes): ");
115
+  root.openRoot(volume);
116
+  
117
+  // list all files in the card with date and size
118
+  root.ls(LS_R | LS_DATE | LS_SIZE);
119
+}
120
+
121
+
122
+void loop(void) {
123
+  
124
+}

+ 104
- 0
xmega/libraries/SD/examples/Datalogger/Datalogger.ino View File

@@ -0,0 +1,104 @@
1
+/*
2
+  SD card datalogger
3
+ 
4
+ This example shows how to log data from three analog sensors 
5
+ to an SD card using the SD library.
6
+ 	
7
+ The circuit:
8
+ * analog sensors on analog ins 0, 1, and 2
9
+ * SD card attached to SPI bus as follows:
10
+ ** MOSI - pin 11
11
+ ** MISO - pin 12
12
+ ** CLK - pin 13
13
+ ** CS - pin 4
14
+ 
15
+ created  24 Nov 2010
16
+ modified 9 Apr 2012
17
+ by Tom Igoe
18
+ 
19
+ This example code is in the public domain.
20
+ 	 
21
+ */
22
+
23
+#include <SD.h>
24
+#include <SPI.h>
25
+
26
+// On the Ethernet Shield, CS is pin 4. Note that even if it's not
27
+// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
28
+// 53 on the Mega) must be left as an output or the SD library
29
+// functions will not work.
30
+
31
+// change this to match your SD shield or module;
32
+// Arduino Ethernet shield: pin 4
33
+// Adafruit SD shields and modules: pin 10
34
+// Sparkfun SD shield: pin 8
35
+// Teensy 2.0: pin 0
36
+// Teensy++ 2.0: pin 20
37
+#if defined(XMEGA_XA4U)
38
+const int chipSelect = 22;
39
+#else
40
+const int chipSelect = 4;    
41
+#endif
42
+
43
+void setup()
44
+{
45
+ // Open serial communications and wait for port to open:
46
+  Serial.begin(9600);
47
+   while (!Serial) {
48
+    ; // wait for serial port to connect. Needed for Leonardo only
49
+  }
50
+
51
+
52
+  Serial.print("Initializing SD card...");
53
+  // make sure that the default chip select pin is set to
54
+  // output, even if you don't use it:
55
+  pinMode(10, OUTPUT);
56
+  
57
+  // see if the card is present and can be initialized:
58
+  if (!SD.begin(chipSelect)) {
59
+    Serial.println("Card failed, or not present");
60
+    // don't do anything more:
61
+    return;
62
+  }
63
+  Serial.println("card initialized.");
64
+}
65
+
66
+void loop()
67
+{
68
+  // make a string for assembling the data to log:
69
+  String dataString = "";
70
+
71
+  // read three sensors and append to the string:
72
+  for (int analogPin = 0; analogPin < 3; analogPin++) {
73
+    int sensor = analogRead(analogPin);
74
+    dataString += String(sensor);
75
+    if (analogPin < 2) {
76
+      dataString += ","; 
77
+    }
78
+  }
79
+
80
+  // open the file. note that only one file can be open at a time,
81
+  // so you have to close this one before opening another.
82
+  File dataFile = SD.open("datalog.txt", FILE_WRITE);
83
+
84
+  // if the file is available, write to it:
85
+  if (dataFile) {
86
+    dataFile.println(dataString);
87
+    dataFile.close();
88
+    // print to the serial port too:
89
+    Serial.println(dataString);
90
+  }  
91
+  // if the file isn't open, pop up an error:
92
+  else {
93
+    Serial.println("error opening datalog.txt");
94
+  } 
95
+}
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+

+ 85
- 0
xmega/libraries/SD/examples/DumpFile/DumpFile.ino View File

@@ -0,0 +1,85 @@
1
+/*
2
+  SD card file dump
3
+ 
4
+ This example shows how to read a file from the SD card using the
5
+ SD library and send it over the serial port.
6
+ 	
7
+ The circuit:
8
+ * SD card attached to SPI bus as follows:
9
+ ** MOSI - pin 11
10
+ ** MISO - pin 12
11
+ ** CLK - pin 13
12
+ ** CS - pin 4
13
+ 
14
+ created  22 December 2010
15
+ by Limor Fried
16
+ modified 9 Apr 2012
17
+ by Tom Igoe
18
+ 
19
+ This example code is in the public domain.
20
+ 	 
21
+ */
22
+
23
+#include <SD.h>
24
+#include <SPI.h>
25
+
26
+// On the Ethernet Shield, CS is pin 4. Note that even if it's not
27
+// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
28
+// 53 on the Mega) must be left as an output or the SD library
29
+// functions will not work.
30
+
31
+// change this to match your SD shield or module;
32
+// Arduino Ethernet shield: pin 4
33
+// Adafruit SD shields and modules: pin 10
34
+// Sparkfun SD shield: pin 8
35
+// Teensy 2.0: pin 0
36
+// Teensy++ 2.0: pin 20
37
+#if defined(XMEGA_XA4U)
38
+const int chipSelect = 22;
39
+#else
40
+const int chipSelect = 4;
41
+#endif
42
+
43
+void setup()
44
+{
45
+ // Open serial communications and wait for port to open:
46
+  Serial.begin(9600);
47
+   while (!Serial) {
48
+    ; // wait for serial port to connect. Needed for Leonardo only
49
+  }
50
+
51
+
52
+  Serial.print("Initializing SD card...");
53
+  // make sure that the default chip select pin is set to
54
+  // output, even if you don't use it:
55
+  pinMode(10, OUTPUT);
56
+  
57
+  // see if the card is present and can be initialized:
58
+  if (!SD.begin(chipSelect)) {
59
+    Serial.println("Card failed, or not present");
60
+    // don't do anything more:
61
+    return;
62
+  }
63
+  Serial.println("card initialized.");
64
+  
65
+  // open the file. note that only one file can be open at a time,
66
+  // so you have to close this one before opening another.
67
+  File dataFile = SD.open("datalog.txt");
68
+
69
+  // if the file is available, write to it:
70
+  if (dataFile) {
71
+    while (dataFile.available()) {
72
+      Serial.write(dataFile.read());
73
+    }
74
+    dataFile.close();
75
+  }  
76
+  // if the file isn't open, pop up an error:
77
+  else {
78
+    Serial.println("error opening datalog.txt");
79
+  } 
80
+}
81
+
82
+void loop()
83
+{
84
+}
85
+

+ 97
- 0
xmega/libraries/SD/examples/Files/Files.ino View File

@@ -0,0 +1,97 @@
1
+/*
2
+  SD card basic file example
3
+ 
4
+ This example shows how to create and destroy an SD card file 	
5
+ The circuit:
6
+ * SD card attached to SPI bus as follows:
7
+ ** MOSI - pin 11
8
+ ** MISO - pin 12
9
+ ** CLK - pin 13
10
+ ** CS - pin 4
11
+ 
12
+ created   Nov 2010
13
+ by David A. Mellis
14
+ modified 9 Apr 2012
15
+ by Tom Igoe
16
+ 
17
+ This example code is in the public domain.
18
+ 	 
19
+ */
20
+#include <SD.h>
21
+#include <SPI.h>
22
+
23
+File myFile;
24
+
25
+// change this to match your SD shield or module;
26
+// Arduino Ethernet shield: pin 4
27
+// Adafruit SD shields and modules: pin 10
28
+// Sparkfun SD shield: pin 8
29
+// Teensy 2.0: pin 0
30
+// Teensy++ 2.0: pin 20
31
+#if defined(XMEGA_XA4U)
32
+const int chipSelect = 22;
33
+#else
34
+const int chipSelect = 4;
35
+#endif
36
+
37
+void setup()
38
+{
39
+ // Open serial communications and wait for port to open:
40
+  Serial.begin(9600);
41
+   while (!Serial) {
42
+    ; // wait for serial port to connect. Needed for Leonardo only
43
+  }
44
+
45
+
46
+  Serial.print("Initializing SD card...");
47
+  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
48
+  // Note that even if it's not used as the CS pin, the hardware SS pin 
49
+  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
50
+  // or the SD library functions will not work. 
51
+  pinMode(10, OUTPUT);
52
+
53
+  if (!SD.begin(chipSelect)) {
54
+    Serial.println("initialization failed!");
55
+    return;
56
+  }
57
+  Serial.println("initialization done.");
58
+
59
+  if (SD.exists("example.txt")) {
60
+    Serial.println("example.txt exists.");
61
+  }
62
+  else {
63
+    Serial.println("example.txt doesn't exist.");
64
+  }
65
+
66
+  // open a new file and immediately close it:
67
+  Serial.println("Creating example.txt...");
68
+  myFile = SD.open("example.txt", FILE_WRITE);
69
+  myFile.close();
70
+
71
+  // Check to see if the file exists: 
72
+  if (SD.exists("example.txt")) {
73
+    Serial.println("example.txt exists.");
74
+  }
75
+  else {
76
+    Serial.println("example.txt doesn't exist.");  
77
+  }
78
+
79
+  // delete the file:
80
+  Serial.println("Removing example.txt...");
81
+  SD.remove("example.txt");
82
+
83
+  if (SD.exists("example.txt")){ 
84
+    Serial.println("example.txt exists.");
85
+  }
86
+  else {
87
+    Serial.println("example.txt doesn't exist.");  
88
+  }
89
+}
90
+
91
+void loop()
92
+{
93
+  // nothing happens after setup finishes.
94
+}
95
+
96
+
97
+

+ 98
- 0
xmega/libraries/SD/examples/ReadWrite/ReadWrite.ino View File

@@ -0,0 +1,98 @@
1
+/*
2
+  SD card read/write
3
+ 
4
+ This example shows how to read and write data to and from an SD card file 	
5
+ The circuit:
6
+ * SD card attached to SPI bus as follows:
7
+ ** MOSI - pin 11
8
+ ** MISO - pin 12
9
+ ** CLK - pin 13
10
+ ** CS - pin 4
11
+ 
12
+ created   Nov 2010
13
+ by David A. Mellis
14
+ modified 9 Apr 2012
15
+ by Tom Igoe
16
+ 
17
+ This example code is in the public domain.
18
+ 	 
19
+ */
20
+ 
21
+#include <SD.h>
22
+#include <SPI.h>
23
+
24
+File myFile;
25
+
26
+// change this to match your SD shield or module;
27
+// Arduino Ethernet shield: pin 4
28
+// Adafruit SD shields and modules: pin 10
29
+// Sparkfun SD shield: pin 8
30
+// Teensy 2.0: pin 0
31
+// Teensy++ 2.0: pin 20
32
+#if defined(XMEGA_XA4U)
33
+const int chipSelect = 22;
34
+#else
35
+const int chipSelect = 4;
36
+#endif
37
+
38
+void setup()
39
+{
40
+ // Open serial communications and wait for port to open:
41
+  Serial.begin(9600);
42
+   while (!Serial) {
43
+    ; // wait for serial port to connect. Needed for Leonardo only
44
+  }
45
+
46
+
47
+  Serial.print("Initializing SD card...");
48
+  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
49
+  // Note that even if it's not used as the CS pin, the hardware SS pin 
50
+  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
51
+  // or the SD library functions will not work. 
52
+   pinMode(10, OUTPUT);
53
+   
54
+  if (!SD.begin(chipSelect)) {
55
+    Serial.println("initialization failed!");
56
+    return;
57
+  }
58
+  Serial.println("initialization done.");
59
+  
60
+  // open the file. note that only one file can be open at a time,
61
+  // so you have to close this one before opening another.
62
+  myFile = SD.open("test.txt", FILE_WRITE);
63
+  
64
+  // if the file opened okay, write to it:
65
+  if (myFile) {
66
+    Serial.print("Writing to test.txt...");
67
+    myFile.println("testing 1, 2, 3.");
68
+	// close the file:
69
+    myFile.close();
70
+    Serial.println("done.");
71
+  } else {
72
+    // if the file didn't open, print an error:
73
+    Serial.println("error opening test.txt");
74
+  }
75
+  
76
+  // re-open the file for reading:
77
+  myFile = SD.open("test.txt");
78
+  if (myFile) {
79
+    Serial.println("test.txt:");
80
+    
81
+    // read from the file until there's nothing else in it:
82
+    while (myFile.available()) {
83
+    	Serial.write(myFile.read());
84
+    }
85
+    // close the file:
86
+    myFile.close();
87
+  } else {
88
+  	// if the file didn't open, print an error:
89
+    Serial.println("error opening test.txt");
90
+  }
91
+}
92
+
93
+void loop()
94
+{
95
+	// nothing happens after setup
96
+}
97
+
98
+

+ 97
- 0
xmega/libraries/SD/examples/listfiles/listfiles.ino View File

@@ -0,0 +1,97 @@
1
+/*
2
+  SD card basic file example
3
+ 
4
+ This example shows how to create and destroy an SD card file 	
5
+ The circuit:
6
+ * SD card attached to SPI bus as follows:
7
+ ** MOSI - pin 11
8
+ ** MISO - pin 12
9
+ ** CLK - pin 13
10
+ ** CS - pin 4
11
+ 
12
+ created   Nov 2010
13
+ by David A. Mellis
14
+ modified 9 Apr 2012
15
+ by Tom Igoe
16
+ 
17
+ This example code is in the public domain.
18
+ 	 
19
+ */
20
+#include <SD.h>
21
+#include <SPI.h>
22
+
23
+File root;
24
+
25
+// change this to match your SD shield or module;
26
+// Arduino Ethernet shield: pin 4
27
+// Adafruit SD shields and modules: pin 10
28
+// Sparkfun SD shield: pin 8
29
+// Teensy 2.0: pin 0
30
+// Teensy++ 2.0: pin 20
31
+#if defined(XMEGA_XA4U)
32
+const int chipSelect = 22;
33
+#else
34
+const int chipSelect = 4;
35
+#endif
36
+
37
+void setup()
38
+{
39
+  // Open serial communications and wait for port to open:
40
+  Serial.begin(9600);
41
+   while (!Serial) {
42
+    ; // wait for serial port to connect. Needed for Leonardo only
43
+  }
44
+
45
+
46
+  Serial.print("Initializing SD card...");
47
+  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
48
+  // Note that even if it's not used as the CS pin, the hardware SS pin 
49
+  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
50
+  // or the SD library functions will not work. 
51
+  pinMode(10, OUTPUT);
52
+
53
+  if (!SD.begin(chipSelect)) {
54
+    Serial.println("initialization failed!");
55
+    return;
56
+  }
57
+  Serial.println("initialization done.");
58
+
59
+  root = SD.open("/");
60
+  
61
+  printDirectory(root, 0);
62
+  
63
+  Serial.println("done!");
64
+}
65
+
66
+void loop()
67
+{
68
+  // nothing happens after setup finishes.
69
+}
70
+
71
+void printDirectory(File dir, int numTabs) {
72
+   while(true) {
73
+     
74
+     File entry =  dir.openNextFile();
75
+     if (! entry) {
76
+       // no more files
77
+       //Serial.println("**nomorefiles**");
78
+       break;
79
+     }
80
+     for (uint8_t i=0; i<numTabs; i++) {
81
+       Serial.print('\t');
82
+     }
83
+     Serial.print(entry.name());
84
+     if (entry.isDirectory()) {
85
+       Serial.println("/");
86
+       printDirectory(entry, numTabs+1);
87
+     } else {
88
+       // files have sizes, directories do not
89
+       Serial.print("\t\t");
90
+       Serial.println(entry.size(), DEC);
91
+     }
92
+     entry.close();
93
+   }
94
+}
95
+
96
+
97
+

+ 30
- 0
xmega/libraries/SD/keywords.txt View File

@@ -0,0 +1,30 @@
1
+#######################################
2
+# Syntax Coloring Map SD
3
+#######################################
4
+
5
+#######################################
6
+# Datatypes (KEYWORD1)
7
+#######################################
8
+
9
+SD	KEYWORD1
10
+File	KEYWORD1
11
+
12
+#######################################
13
+# Methods and Functions (KEYWORD2)
14
+#######################################
15
+begin	KEYWORD2
16
+exists	KEYWORD2
17
+mkdir	KEYWORD2
18
+remove	KEYWORD2
19
+rmdir	KEYWORD2
20
+open	KEYWORD2
21
+close	KEYWORD2
22
+seek	KEYWORD2
23
+position	KEYWORD2
24
+size	KEYWORD2	
25
+
26
+#######################################
27
+# Constants (LITERAL1)
28
+#######################################
29
+FILE_READ	LITERAL1
30
+FILE_WRITE	LITERAL1

+ 418
- 0
xmega/libraries/SD/utility/FatStructs.h View File

@@ -0,0 +1,418 @@
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
+#ifndef FatStructs_h
21
+#define FatStructs_h
22
+/**
23
+ * \file
24
+ * FAT file structures
25
+ */
26
+/*
27
+ * mostly from Microsoft document fatgen103.doc
28
+ * http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
29
+ */
30
+//------------------------------------------------------------------------------
31
+/** Value for byte 510 of boot block or MBR */
32
+uint8_t const BOOTSIG0 = 0X55;
33
+/** Value for byte 511 of boot block or MBR */
34
+uint8_t const BOOTSIG1 = 0XAA;
35
+//------------------------------------------------------------------------------
36
+/**
37
+ * \struct partitionTable
38
+ * \brief MBR partition table entry
39
+ *
40
+ * A partition table entry for a MBR formatted storage device.
41
+ * The MBR partition table has four entries.
42
+ */
43
+struct partitionTable {
44
+          /**
45
+           * Boot Indicator . Indicates whether the volume is the active
46
+           * partition.  Legal values include: 0X00. Do not use for booting.
47
+           * 0X80 Active partition.
48
+           */
49
+  uint8_t  boot;
50
+          /**
51
+            * Head part of Cylinder-head-sector address of the first block in
52
+            * the partition. Legal values are 0-255. Only used in old PC BIOS.
53
+            */
54
+  uint8_t  beginHead;
55
+          /**
56
+           * Sector part of Cylinder-head-sector address of the first block in
57
+           * the partition. Legal values are 1-63. Only used in old PC BIOS.
58
+           */
59
+  unsigned beginSector : 6;
60
+           /** High bits cylinder for first block in partition. */
61
+  unsigned beginCylinderHigh : 2;
62
+          /**
63
+           * Combine beginCylinderLow with beginCylinderHigh. Legal values
64
+           * are 0-1023.  Only used in old PC BIOS.
65
+           */
66
+  uint8_t  beginCylinderLow;
67
+          /**
68
+           * Partition type. See defines that begin with PART_TYPE_ for
69
+           * some Microsoft partition types.
70
+           */
71
+  uint8_t  type;
72
+          /**
73
+           * head part of cylinder-head-sector address of the last sector in the
74
+           * partition.  Legal values are 0-255. Only used in old PC BIOS.
75
+           */
76
+  uint8_t  endHead;
77
+          /**
78
+           * Sector part of cylinder-head-sector address of the last sector in
79
+           * the partition.  Legal values are 1-63. Only used in old PC BIOS.
80
+           */
81
+  unsigned endSector : 6;
82
+           /** High bits of end cylinder */
83
+  unsigned endCylinderHigh : 2;
84
+          /**
85
+           * Combine endCylinderLow with endCylinderHigh. Legal values
86
+           * are 0-1023.  Only used in old PC BIOS.
87
+           */
88
+  uint8_t  endCylinderLow;
89
+           /** Logical block address of the first block in the partition. */
90
+  uint32_t firstSector;
91
+           /** Length of the partition, in blocks. */
92
+  uint32_t totalSectors;
93
+} __attribute__((packed));
94
+/** Type name for partitionTable */
95
+typedef struct partitionTable part_t;
96
+//------------------------------------------------------------------------------
97
+/**
98
+ * \struct masterBootRecord
99
+ *
100
+ * \brief Master Boot Record
101
+ *
102
+ * The first block of a storage device that is formatted with a MBR.
103
+ */
104
+struct masterBootRecord {
105
+           /** Code Area for master boot program. */
106
+  uint8_t  codeArea[440];
107
+           /** Optional WindowsNT disk signature. May contain more boot code. */
108
+  uint32_t diskSignature;
109
+           /** Usually zero but may be more boot code. */
110
+  uint16_t usuallyZero;
111
+           /** Partition tables. */
112
+  part_t   part[4];
113
+           /** First MBR signature byte. Must be 0X55 */
114
+  uint8_t  mbrSig0;
115
+           /** Second MBR signature byte. Must be 0XAA */
116
+  uint8_t  mbrSig1;
117
+} __attribute__((packed));
118
+/** Type name for masterBootRecord */
119
+typedef struct masterBootRecord mbr_t;
120
+//------------------------------------------------------------------------------
121
+/** 
122
+ * \struct biosParmBlock
123
+ *
124
+ * \brief BIOS parameter block
125
+ * 
126
+ *  The BIOS parameter block describes the physical layout of a FAT volume.
127
+ */
128
+struct biosParmBlock {
129
+          /**
130
+           * Count of bytes per sector. This value may take on only the
131
+           * following values: 512, 1024, 2048 or 4096
132
+           */
133
+  uint16_t bytesPerSector;
134
+          /**
135
+           * Number of sectors per allocation unit. This value must be a
136
+           * power of 2 that is greater than 0. The legal values are
137
+           * 1, 2, 4, 8, 16, 32, 64, and 128.
138
+           */
139
+  uint8_t  sectorsPerCluster;
140
+          /**
141
+           * Number of sectors before the first FAT.
142
+           * This value must not be zero.
143
+           */
144
+  uint16_t reservedSectorCount;
145
+          /** The count of FAT data structures on the volume. This field should
146
+           *  always contain the value 2 for any FAT volume of any type.
147
+           */
148
+  uint8_t  fatCount;
149
+          /**
150
+          * For FAT12 and FAT16 volumes, this field contains the count of
151
+          * 32-byte directory entries in the root directory. For FAT32 volumes,
152
+          * this field must be set to 0. For FAT12 and FAT16 volumes, this
153
+          * value should always specify a count that when multiplied by 32
154
+          * results in a multiple of bytesPerSector.  FAT16 volumes should
155
+          * use the value 512.
156
+          */
157
+  uint16_t rootDirEntryCount;
158
+          /**
159
+           * This field is the old 16-bit total count of sectors on the volume.
160
+           * This count includes the count of all sectors in all four regions
161
+           * of the volume. This field can be 0; if it is 0, then totalSectors32
162
+           * must be non-zero.  For FAT32 volumes, this field must be 0. For
163
+           * FAT12 and FAT16 volumes, this field contains the sector count, and
164
+           * totalSectors32 is 0 if the total sector count fits
165
+           * (is less than 0x10000).
166
+           */
167
+  uint16_t totalSectors16;
168
+          /**
169
+           * This dates back to the old MS-DOS 1.x media determination and is
170
+           * no longer usually used for anything.  0xF8 is the standard value
171
+           * for fixed (non-removable) media. For removable media, 0xF0 is
172
+           * frequently used. Legal values are 0xF0 or 0xF8-0xFF.
173
+           */
174
+  uint8_t  mediaType;
175
+          /**
176
+           * Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
177
+           * On FAT32 volumes this field must be 0, and sectorsPerFat32
178
+           * contains the FAT size count.
179
+           */
180
+  uint16_t sectorsPerFat16;
181
+           /** Sectors per track for interrupt 0x13. Not used otherwise. */
182
+  uint16_t sectorsPerTrtack;
183
+           /** Number of heads for interrupt 0x13.  Not used otherwise. */
184
+  uint16_t headCount;
185
+          /**
186
+           * Count of hidden sectors preceding the partition that contains this
187
+           * FAT volume. This field is generally only relevant for media
188
+           *  visible on interrupt 0x13.
189
+           */
190
+  uint32_t hidddenSectors;
191
+          /**
192
+           * This field is the new 32-bit total count of sectors on the volume.
193
+           * This count includes the count of all sectors in all four regions
194
+           * of the volume.  This field can be 0; if it is 0, then
195
+           * totalSectors16 must be non-zero.
196
+           */
197
+  uint32_t totalSectors32;
198
+          /**
199
+           * Count of sectors occupied by one FAT on FAT32 volumes.
200
+           */
201
+  uint32_t sectorsPerFat32;
202
+          /**
203
+           * This field is only defined for FAT32 media and does not exist on
204
+           * FAT12 and FAT16 media.
205
+           * Bits 0-3 -- Zero-based number of active FAT.
206
+           *             Only valid if mirroring is disabled.
207
+           * Bits 4-6 -- Reserved.
208
+           * Bit 7	-- 0 means the FAT is mirrored at runtime into all FATs.
209
+	         *        -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
210
+           * Bits 8-15 	-- Reserved.
211
+           */
212
+  uint16_t fat32Flags;
213
+          /**
214
+           * FAT32 version. High byte is major revision number.
215
+           * Low byte is minor revision number. Only 0.0 define.
216
+           */
217
+  uint16_t fat32Version;
218
+          /**
219
+           * Cluster number of the first cluster of the root directory for FAT32.
220
+           * This usually 2 but not required to be 2.
221
+           */
222
+  uint32_t fat32RootCluster;
223
+          /**
224
+           * Sector number of FSINFO structure in the reserved area of the
225
+           * FAT32 volume. Usually 1.
226
+           */
227
+  uint16_t fat32FSInfo;
228
+          /**
229
+           * If non-zero, indicates the sector number in the reserved area
230
+           * of the volume of a copy of the boot record. Usually 6.
231
+           * No value other than 6 is recommended.
232
+           */
233
+  uint16_t fat32BackBootBlock;
234
+          /**
235
+           * Reserved for future expansion. Code that formats FAT32 volumes
236
+           * should always set all of the bytes of this field to 0.
237
+           */
238
+  uint8_t  fat32Reserved[12];
239
+} __attribute__((packed));
240
+/** Type name for biosParmBlock */
241
+typedef struct biosParmBlock bpb_t;
242
+//------------------------------------------------------------------------------
243
+/**
244
+ * \struct fat32BootSector
245
+ *
246
+ * \brief Boot sector for a FAT16 or FAT32 volume.
247
+ * 
248
+ */  
249
+struct fat32BootSector {
250
+           /** X86 jmp to boot program */
251
+  uint8_t  jmpToBootCode[3];
252
+           /** informational only - don't depend on it */
253
+  char     oemName[8];
254
+           /** BIOS Parameter Block */
255
+  bpb_t    bpb;
256
+           /** for int0x13 use value 0X80 for hard drive */
257
+  uint8_t  driveNumber;
258
+           /** used by Windows NT - should be zero for FAT */
259
+  uint8_t  reserved1;
260
+           /** 0X29 if next three fields are valid */
261
+  uint8_t  bootSignature;
262
+           /** usually generated by combining date and time */
263
+  uint32_t volumeSerialNumber;
264
+           /** should match volume label in root dir */
265
+  char     volumeLabel[11];
266
+           /** informational only - don't depend on it */
267
+  char     fileSystemType[8];
268
+           /** X86 boot code */
269
+  uint8_t  bootCode[420];
270
+           /** must be 0X55 */
271
+  uint8_t  bootSectorSig0;
272
+           /** must be 0XAA */
273
+  uint8_t  bootSectorSig1;
274
+} __attribute__((packed));
275
+//------------------------------------------------------------------------------
276
+// End Of Chain values for FAT entries
277
+/** FAT16 end of chain value used by Microsoft. */
278
+uint16_t const FAT16EOC = 0XFFFF;
279
+/** Minimum value for FAT16 EOC.  Use to test for EOC. */
280
+uint16_t const FAT16EOC_MIN = 0XFFF8;
281
+/** FAT32 end of chain value used by Microsoft. */
282
+uint32_t const FAT32EOC = 0X0FFFFFFF;
283
+/** Minimum value for FAT32 EOC.  Use to test for EOC. */
284
+uint32_t const FAT32EOC_MIN = 0X0FFFFFF8;
285
+/** Mask a for FAT32 entry. Entries are 28 bits. */
286
+uint32_t const FAT32MASK = 0X0FFFFFFF;
287
+
288
+/** Type name for fat32BootSector */
289
+typedef struct fat32BootSector fbs_t;
290
+//------------------------------------------------------------------------------
291
+/**
292
+ * \struct directoryEntry
293
+ * \brief FAT short directory entry
294
+ *
295
+ * Short means short 8.3 name, not the entry size.
296
+ *  
297
+ * Date Format. A FAT directory entry date stamp is a 16-bit field that is 
298
+ * basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
299
+ * format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the 
300
+ * 16-bit word):
301
+ *   
302
+ * Bits 9-15: Count of years from 1980, valid value range 0-127 
303
+ * inclusive (1980-2107).
304
+ *   
305
+ * Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
306
+ *
307
+ * Bits 0-4: Day of month, valid value range 1-31 inclusive.
308
+ *
309
+ * Time Format. A FAT directory entry time stamp is a 16-bit field that has
310
+ * a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the 
311
+ * 16-bit word, bit 15 is the MSB of the 16-bit word).
312
+ *   
313
+ * Bits 11-15: Hours, valid value range 0-23 inclusive.
314
+ * 
315
+ * Bits 5-10: Minutes, valid value range 0-59 inclusive.
316
+ *      
317
+ * Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
318
+ *   
319
+ * The valid time range is from Midnight 00:00:00 to 23:59:58.
320
+ */
321
+struct directoryEntry {
322
+           /**
323
+            * Short 8.3 name.
324
+            * The first eight bytes contain the file name with blank fill.
325
+            * The last three bytes contain the file extension with blank fill.
326
+            */
327
+  uint8_t  name[11];
328
+          /** Entry attributes.
329
+           *
330
+           * The upper two bits of the attribute byte are reserved and should
331
+           * always be set to 0 when a file is created and never modified or
332
+           * looked at after that.  See defines that begin with DIR_ATT_.
333
+           */
334
+  uint8_t  attributes;
335
+          /**
336
+           * Reserved for use by Windows NT. Set value to 0 when a file is
337
+           * created and never modify or look at it after that.
338
+           */
339
+  uint8_t  reservedNT;
340
+          /**
341
+           * The granularity of the seconds part of creationTime is 2 seconds
342
+           * so this field is a count of tenths of a second and its valid
343
+           * value range is 0-199 inclusive. (WHG note - seems to be hundredths)
344
+           */
345
+  uint8_t  creationTimeTenths;
346
+           /** Time file was created. */
347
+  uint16_t creationTime;
348
+           /** Date file was created. */
349
+  uint16_t creationDate;
350
+          /**
351
+           * Last access date. Note that there is no last access time, only
352
+           * a date.  This is the date of last read or write. In the case of
353
+           * a write, this should be set to the same date as lastWriteDate.
354
+           */
355
+  uint16_t lastAccessDate;
356
+          /**
357
+           * High word of this entry's first cluster number (always 0 for a
358
+           * FAT12 or FAT16 volume).
359
+           */
360
+  uint16_t firstClusterHigh;
361
+           /** Time of last write. File creation is considered a write. */
362
+  uint16_t lastWriteTime;
363
+           /** Date of last write. File creation is considered a write. */
364
+  uint16_t lastWriteDate;
365
+           /** Low word of this entry's first cluster number. */
366
+  uint16_t firstClusterLow;
367
+           /** 32-bit unsigned holding this file's size in bytes. */
368
+  uint32_t fileSize;
369
+} __attribute__((packed));
370
+//------------------------------------------------------------------------------
371
+// Definitions for directory entries
372
+//
373
+/** Type name for directoryEntry */
374
+typedef struct directoryEntry dir_t;
375
+/** escape for name[0] = 0XE5 */
376
+uint8_t const DIR_NAME_0XE5 = 0X05;
377
+/** name[0] value for entry that is free after being "deleted" */
378
+uint8_t const DIR_NAME_DELETED = 0XE5;
379
+/** name[0] value for entry that is free and no allocated entries follow */
380
+uint8_t const DIR_NAME_FREE = 0X00;
381
+/** file is read-only */
382
+uint8_t const DIR_ATT_READ_ONLY = 0X01;
383
+/** File should hidden in directory listings */
384
+uint8_t const DIR_ATT_HIDDEN = 0X02;
385
+/** Entry is for a system file */
386
+uint8_t const DIR_ATT_SYSTEM = 0X04;
387
+/** Directory entry contains the volume label */
388
+uint8_t const DIR_ATT_VOLUME_ID = 0X08;
389
+/** Entry is for a directory */
390
+uint8_t const DIR_ATT_DIRECTORY = 0X10;
391
+/** Old DOS archive bit for backup support */
392
+uint8_t const DIR_ATT_ARCHIVE = 0X20;
393
+/** Test value for long name entry.  Test is
394
+  (d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */
395
+uint8_t const DIR_ATT_LONG_NAME = 0X0F;
396
+/** Test mask for long name entry */
397
+uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F;
398
+/** defined attribute bits */
399
+uint8_t const DIR_ATT_DEFINED_BITS = 0X3F;
400
+/** Directory entry is part of a long name */
401
+static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
402
+  return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
403
+}
404
+/** Mask for file/subdirectory tests */
405
+uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
406
+/** Directory entry is for a file */
407
+static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
408
+  return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
409
+}
410
+/** Directory entry is for a subdirectory */
411
+static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) {
412
+  return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
413
+}
414
+/** Directory entry is for a file or subdirectory */
415
+static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
416
+  return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
417
+}
418
+#endif  // FatStructs_h

+ 849
- 0
xmega/libraries/SD/utility/Sd2Card.cpp View File

@@ -0,0 +1,849 @@
1
+/* Arduino Sd2Card Library
2
+ * Copyright (C) 2009 by William Greiman
3
+ *
4
+ * This file is part of the Arduino Sd2Card 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 Sd2Card Library.  If not, see
18
+ * <http://www.gnu.org/licenses/>.
19
+ */
20
+#include <Arduino.h>
21
+#include <SPI.h>
22
+#include "Sd2Card.h"
23
+
24
+#ifdef SPI_HAS_TRANSACTION
25
+static SPISettings settings;
26
+#endif
27
+
28
+
29
+
30
+#if defined(__MK20DX128__) || defined(__MK20DX256__)
31
+#define USE_TEENSY3_SPI
32
+
33
+// Teensy 3.0 functions  (copied from sdfatlib20130629)
34
+#include <mk20dx128.h>
35
+// Limit initial fifo to three entries to avoid fifo overrun
36
+#define SPI_INITIAL_FIFO_DEPTH 3
37
+// define some symbols that are not in mk20dx128.h
38
+#ifndef SPI_SR_RXCTR
39
+#define SPI_SR_RXCTR 0XF0
40
+#endif  // SPI_SR_RXCTR
41
+#ifndef SPI_PUSHR_CONT
42
+#define SPI_PUSHR_CONT 0X80000000
43
+#endif   // SPI_PUSHR_CONT
44
+#ifndef SPI_PUSHR_CTAS
45
+#define SPI_PUSHR_CTAS(n) (((n) & 7) << 28)
46
+#endif  // SPI_PUSHR_CTAS
47
+
48
+static void spiBegin() {
49
+  SIM_SCGC6 |= SIM_SCGC6_SPI0;
50
+}
51
+
52
+static void spiInit(uint8_t spiRate) {
53
+  switch (spiRate) {
54
+    // the top 2 speeds are set to 24 MHz, for the SD library defaults
55
+    case 0:  settings = SPISettings(24000000, MSBFIRST, SPI_MODE0); break;
56
+    case 1:  settings = SPISettings(24000000, MSBFIRST, SPI_MODE0); break;
57
+    case 2:  settings = SPISettings(8000000, MSBFIRST, SPI_MODE0); break;
58
+    case 3:  settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); break;
59
+    case 4:  settings = SPISettings(3000000, MSBFIRST, SPI_MODE0); break;
60
+    case 5:  settings = SPISettings(2000000, MSBFIRST, SPI_MODE0); break;
61
+    default: settings = SPISettings(400000, MSBFIRST, SPI_MODE0);
62
+  }
63
+  SPI.begin();
64
+}
65
+
66
+/** SPI receive a byte */
67
+static  uint8_t spiRec() {
68
+  SPI0_MCR |= SPI_MCR_CLR_RXF;
69
+  SPI0_SR = SPI_SR_TCF;
70
+  SPI0_PUSHR = 0xFF;
71
+  while (!(SPI0_SR & SPI_SR_TCF)) {}
72
+  return SPI0_POPR;
73
+}
74
+/** SPI receive multiple bytes */
75
+static uint8_t spiRec(uint8_t* buf, size_t len) {
76
+  // clear any data in RX FIFO
77
+  SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
78
+  // use 16 bit frame to avoid TD delay between frames
79
+  // get one byte if len is odd
80
+  if (len & 1) {
81
+    *buf++ = spiRec();
82
+    len--;
83
+  }
84
+  // initial number of words to push into TX FIFO
85
+  int nf = len/2 < SPI_INITIAL_FIFO_DEPTH ? len/2 : SPI_INITIAL_FIFO_DEPTH;
86
+  for (int i = 0; i < nf; i++) {
87
+    SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | 0XFFFF;
88
+  }
89
+  uint8_t* limit = buf + len - 2*nf;
90
+  while (buf < limit) {
91
+    while (!(SPI0_SR & SPI_SR_RXCTR)) {}
92
+    SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | 0XFFFF;
93
+    uint16_t w = SPI0_POPR;
94
+    *buf++ = w >> 8;
95
+    *buf++ = w & 0XFF;
96
+  }
97
+  // limit for rest of RX data
98
+  limit += 2*nf;
99
+  while (buf < limit) {
100
+    while (!(SPI0_SR & SPI_SR_RXCTR)) {}
101
+    uint16_t w = SPI0_POPR;
102
+    *buf++ = w >> 8;
103
+    *buf++ = w & 0XFF;
104
+  }
105
+  return 0;
106
+}
107
+static void spiRecIgnore(size_t len) {
108
+  // clear any data in RX FIFO
109
+  SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
110
+  // use 16 bit frame to avoid TD delay between frames
111
+  // get one byte if len is odd
112
+  if (len & 1) {
113
+    spiRec();
114
+    len--;
115
+  }
116
+  // initial number of words to push into TX FIFO
117
+  int nf = len/2 < SPI_INITIAL_FIFO_DEPTH ? len/2 : SPI_INITIAL_FIFO_DEPTH;
118
+  for (int i = 0; i < nf; i++) {
119
+    SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | 0XFFFF;
120
+    len -= 2;
121
+  }
122
+  //uint8_t* limit = buf + len - 2*nf;
123
+  //while (buf < limit) {
124
+  while (len > 0) {
125
+    while (!(SPI0_SR & SPI_SR_RXCTR)) {}
126
+    SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | 0XFFFF;
127
+    SPI0_POPR;
128
+    len -= 2;
129
+  }
130
+  // limit for rest of RX data
131
+  while (nf > 0) {
132
+    while (!(SPI0_SR & SPI_SR_RXCTR)) {}
133
+    SPI0_POPR;
134
+    nf--;
135
+  }
136
+}
137
+/** SPI send a byte */
138
+static void spiSend(uint8_t b) {
139
+  SPI0_MCR |= SPI_MCR_CLR_RXF;
140
+  SPI0_SR = SPI_SR_TCF;
141
+  SPI0_PUSHR = b;
142
+  while (!(SPI0_SR & SPI_SR_TCF)) {}
143
+}
144
+/** SPI send multiple bytes */
145
+static void spiSend(const uint8_t* output, size_t len) {
146
+  // clear any data in RX FIFO
147
+  SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
148
+  // use 16 bit frame to avoid TD delay between frames
149
+  // send one byte if len is odd
150
+  if (len & 1) {
151
+    spiSend(*output++);
152
+    len--;
153
+  }
154
+  // initial number of words to push into TX FIFO
155
+  int nf = len/2 < SPI_INITIAL_FIFO_DEPTH ? len/2 : SPI_INITIAL_FIFO_DEPTH;
156
+  // limit for pushing data into TX fifo
157
+  const uint8_t* limit = output + len;
158
+  for (int i = 0; i < nf; i++) {
159
+    uint16_t w = (*output++) << 8;
160
+    w |= *output++;
161
+    SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | w;
162
+  }
163
+  // write data to TX FIFO
164
+  while (output < limit) {
165
+    uint16_t w = *output++ << 8;
166
+    w |= *output++;
167
+    while (!(SPI0_SR & SPI_SR_RXCTR)) {}
168
+    SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | w;
169
+    SPI0_POPR;
170
+  }
171
+  // wait for data to be sent
172
+  while (nf) {
173
+    while (!(SPI0_SR & SPI_SR_RXCTR)) {}
174
+    SPI0_POPR;
175
+    nf--;
176
+  }
177
+}
178
+
179
+
180
+
181
+//------------------------------------------------------------------------------
182
+#elif defined(__AVR_XMEGA__)
183
+
184
+// functions for hardware SPI
185
+/** Send a byte to the card */
186
+static void spiSend(uint8_t b) {
187
+  SPI.transfer(b);
188
+}
189
+/** Receive a byte from the card */
190
+static  uint8_t spiRec(void) {
191
+  return SPI.transfer(0xFF);
192
+}
193
+
194
+//------------------------------------------------------------------------------
195
+#else
196
+// functions for hardware SPI
197
+/** Send a byte to the card */
198
+static void spiSend(uint8_t b) {
199
+  SPDR = b;
200
+  while (!(SPSR & (1 << SPIF)));
201
+}
202
+/** Receive a byte from the card */
203
+static  uint8_t spiRec(void) {
204
+  spiSend(0XFF);
205
+  return SPDR;
206
+}
207
+
208
+#endif
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+
217
+//------------------------------------------------------------------------------
218
+// send command and return error code.  Return zero for OK
219
+uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
220
+  // end read if in partialBlockRead mode
221
+  readEnd();
222
+
223
+  // select card
224
+  chipSelectLow();
225
+
226
+  // wait up to 300 ms if busy
227
+  waitNotBusy(300);
228
+
229
+  // send command
230
+  spiSend(cmd | 0x40);
231
+
232
+  // send argument
233
+  for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s);
234
+
235
+  // send CRC
236
+  uint8_t crc = 0XFF;
237
+  if (cmd == CMD0) crc = 0X95;  // correct crc for CMD0 with arg 0
238
+  if (cmd == CMD8) crc = 0X87;  // correct crc for CMD8 with arg 0X1AA
239
+  spiSend(crc);
240
+
241
+  // wait for response
242
+  for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++);
243
+  return status_;
244
+}
245
+//------------------------------------------------------------------------------
246
+/**
247
+ * Determine the size of an SD flash memory card.
248
+ *
249
+ * \return The number of 512 byte data blocks in the card
250
+ *         or zero if an error occurs.
251
+ */
252
+uint32_t Sd2Card::cardSize(void) {
253
+  csd_t csd;
254
+  if (!readCSD(&csd)) return 0;
255
+  if (csd.v1.csd_ver == 0) {
256
+    uint8_t read_bl_len = csd.v1.read_bl_len;
257
+    uint16_t c_size = (csd.v1.c_size_high << 10)
258
+                      | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
259
+    uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
260
+                          | csd.v1.c_size_mult_low;
261
+    return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
262
+  } else if (csd.v2.csd_ver == 1) {
263
+    uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
264
+                      | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
265
+    return (c_size + 1) << 10;
266
+  } else {
267
+    error(SD_CARD_ERROR_BAD_CSD);
268
+    return 0;
269
+  }
270
+}
271
+//------------------------------------------------------------------------------
272
+#ifdef SPI_HAS_TRANSACTION
273
+static uint8_t chip_select_asserted = 0;
274
+#endif
275
+void Sd2Card::chipSelectHigh(void) {
276
+  digitalWrite(chipSelectPin_, HIGH);
277
+#ifdef SPI_HAS_TRANSACTION
278
+  if (chip_select_asserted) {
279
+    chip_select_asserted = 0;
280
+    SPI.endTransaction();
281
+  }
282
+#endif
283
+}
284
+//------------------------------------------------------------------------------
285
+void Sd2Card::chipSelectLow(void) {
286
+#ifdef SPI_HAS_TRANSACTION
287
+  if (!chip_select_asserted) {
288
+    chip_select_asserted = 1;
289
+    SPI.beginTransaction(settings);
290
+  }
291
+#endif
292
+  digitalWrite(chipSelectPin_, LOW);
293
+}
294
+//------------------------------------------------------------------------------
295
+/** Erase a range of blocks.
296
+ *
297
+ * \param[in] firstBlock The address of the first block in the range.
298
+ * \param[in] lastBlock The address of the last block in the range.
299
+ *
300
+ * \note This function requests the SD card to do a flash erase for a
301
+ * range of blocks.  The data on the card after an erase operation is
302
+ * either 0 or 1, depends on the card vendor.  The card must support
303
+ * single block erase.
304
+ *
305
+ * \return The value one, true, is returned for success and
306
+ * the value zero, false, is returned for failure.
307
+ */
308
+uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
309
+  if (!eraseSingleBlockEnable()) {
310
+    error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
311
+    goto fail;
312
+  }
313
+  if (type_ != SD_CARD_TYPE_SDHC) {
314
+    firstBlock <<= 9;
315
+    lastBlock <<= 9;
316
+  }
317
+  if (cardCommand(CMD32, firstBlock)
318
+    || cardCommand(CMD33, lastBlock)
319
+    || cardCommand(CMD38, 0)) {
320
+      error(SD_CARD_ERROR_ERASE);
321
+      goto fail;
322
+  }
323
+  if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
324
+    error(SD_CARD_ERROR_ERASE_TIMEOUT);
325
+    goto fail;
326
+  }
327
+  chipSelectHigh();
328
+  return true;
329
+
330
+ fail:
331
+  chipSelectHigh();
332
+  return false;
333
+}
334
+//------------------------------------------------------------------------------
335
+/** Determine if card supports single block erase.
336
+ *
337
+ * \return The value one, true, is returned if single block erase is supported.
338
+ * The value zero, false, is returned if single block erase is not supported.
339
+ */
340
+uint8_t Sd2Card::eraseSingleBlockEnable(void) {
341
+  csd_t csd;
342
+  return readCSD(&csd) ? csd.v1.erase_blk_en : 0;
343
+}
344
+//------------------------------------------------------------------------------
345
+/**
346
+ * Initialize an SD flash memory card.
347
+ *
348
+ * \param[in] sckRateID SPI clock rate selector. See setSckRate().
349
+ * \param[in] chipSelectPin SD chip select pin number.
350
+ *
351
+ * \return The value one, true, is returned for success and
352
+ * the value zero, false, is returned for failure.  The reason for failure
353
+ * can be determined by calling errorCode() and errorData().
354
+ */
355
+uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
356
+  errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0;
357
+  chipSelectPin_ = chipSelectPin;
358
+  // 16-bit init start time allows over a minute
359
+  uint16_t t0 = (uint16_t)millis();
360
+  uint32_t arg;
361
+
362
+  digitalWrite(chipSelectPin_, HIGH);
363
+  pinMode(chipSelectPin_, OUTPUT);
364
+  digitalWrite(chipSelectPin_, HIGH);
365
+
366
+#ifdef USE_TEENSY3_SPI
367
+  spiBegin();
368
+  spiInit(6);
369
+#elif defined(__AVR_XMEGA__)
370
+  SPI.begin();
371
+  SPI.setBitOrder(MSBFIRST);
372
+  SPI.setDataMode(SPI_MODE0);
373
+  SPI.setClockDivider(SPI_CLOCK_DIV128);
374
+#else
375
+  // set pin modes
376
+  pinMode(SPI_MISO_PIN, INPUT);
377
+  pinMode(SPI_MOSI_PIN, OUTPUT);
378
+  pinMode(SPI_SCK_PIN, OUTPUT);
379
+  // SS must be in output mode even it is not chip select
380
+  pinMode(SS_PIN, OUTPUT);
381
+  digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin
382
+  // Enable SPI, Master, clock rate f_osc/128
383
+  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
384
+  // clear double speed
385
+  SPSR &= ~(1 << SPI2X);
386
+#ifdef SPI_HAS_TRANSACTION
387
+  settings = SPISettings(250000, MSBFIRST, SPI_MODE0);
388
+#endif
389
+#endif  // not USE_TEENSY3_SPI
390
+
391
+  // must supply min of 74 clock cycles with CS high.
392
+#ifdef SPI_HAS_TRANSACTION
393
+  SPI.beginTransaction(settings);
394
+#endif
395
+  for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
396
+#ifdef SPI_HAS_TRANSACTION
397
+  SPI.endTransaction();
398
+#endif
399
+
400
+  chipSelectLow();
401
+
402
+  // command to go idle in SPI mode
403
+  while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
404
+    if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
405
+      error(SD_CARD_ERROR_CMD0);
406
+      goto fail;
407
+    }
408
+  }
409
+  // check SD version
410
+  if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
411
+    type(SD_CARD_TYPE_SD1);
412
+  } else {
413
+    // only need last byte of r7 response
414
+    for (uint8_t i = 0; i < 4; i++) status_ = spiRec();
415
+    if (status_ != 0XAA) {
416
+      error(SD_CARD_ERROR_CMD8);
417
+      goto fail;
418
+    }
419
+    type(SD_CARD_TYPE_SD2);
420
+  }
421
+  // initialize card and send host supports SDHC if SD2
422
+  arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
423
+
424
+  while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
425
+    // check for timeout
426
+    if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
427
+      error(SD_CARD_ERROR_ACMD41);
428
+      goto fail;
429
+    }
430
+  }
431
+  // if SD2 read OCR register to check for SDHC card
432
+  if (type() == SD_CARD_TYPE_SD2) {
433
+    if (cardCommand(CMD58, 0)) {
434
+      error(SD_CARD_ERROR_CMD58);
435
+      goto fail;
436
+    }
437
+    if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC);
438
+    // discard rest of ocr - contains allowed voltage range
439
+    for (uint8_t i = 0; i < 3; i++) spiRec();
440
+  }
441
+  chipSelectHigh();
442
+
443
+  return setSckRate(sckRateID);
444
+
445
+ fail:
446
+  chipSelectHigh();
447
+  return false;
448
+}
449
+//------------------------------------------------------------------------------
450
+/**
451
+ * Enable or disable partial block reads.
452
+ *
453
+ * Enabling partial block reads improves performance by allowing a block
454
+ * to be read over the SPI bus as several sub-blocks.  Errors may occur
455
+ * if the time between reads is too long since the SD card may timeout.
456
+ * The SPI SS line will be held low until the entire block is read or
457
+ * readEnd() is called.
458
+ *
459
+ * Use this for applications like the Adafruit Wave Shield.
460
+ *
461
+ * \param[in] value The value TRUE (non-zero) or FALSE (zero).)
462
+ */
463
+void Sd2Card::partialBlockRead(uint8_t value) {
464
+  readEnd();
465
+  partialBlockRead_ = value;
466
+}
467
+//------------------------------------------------------------------------------
468
+/**
469
+ * Read a 512 byte block from an SD card device.
470
+ *
471
+ * \param[in] block Logical block to be read.
472
+ * \param[out] dst Pointer to the location that will receive the data.
473
+
474
+ * \return The value one, true, is returned for success and
475
+ * the value zero, false, is returned for failure.
476
+ */
477
+uint8_t Sd2Card::readBlock(uint32_t block, uint8_t* dst) {
478
+  return readData(block, 0, 512, dst);
479
+}
480
+//------------------------------------------------------------------------------
481
+/**
482
+ * Read part of a 512 byte block from an SD card.
483
+ *
484
+ * \param[in] block Logical block to be read.
485
+ * \param[in] offset Number of bytes to skip at start of block
486
+ * \param[out] dst Pointer to the location that will receive the data.
487
+ * \param[in] count Number of bytes to read
488
+ * \return The value one, true, is returned for success and
489
+ * the value zero, false, is returned for failure.
490
+ */
491
+uint8_t Sd2Card::readData(uint32_t block,
492
+        uint16_t offset, uint16_t count, uint8_t* dst) {
493
+  uint16_t n;
494
+  if (count == 0) return true;
495
+  if ((count + offset) > 512) {
496
+    goto fail;
497
+  }
498
+  if (!inBlock_ || block != block_ || offset < offset_) {
499
+    block_ = block;
500
+    // use address if not SDHC card
501
+    if (type()!= SD_CARD_TYPE_SDHC) block <<= 9;
502
+    if (cardCommand(CMD17, block)) {
503
+      error(SD_CARD_ERROR_CMD17);
504
+      goto fail;
505
+    }
506
+    if (!waitStartBlock()) {
507
+      goto fail;
508
+    }
509
+    offset_ = 0;
510
+    inBlock_ = 1;
511
+  }
512
+
513
+#if defined(USE_TEENSY3_SPI)
514
+
515
+  // skip data before offset
516
+  //for (;offset_ < offset; offset_++) {
517
+    //spiRec();
518
+  //}
519
+  spiRecIgnore(offset);
520
+  spiRec(dst, count);
521
+
522
+#elif defined(OPTIMIZE_HARDWARE_SPI)
523
+  // start first spi transfer
524
+  SPDR = 0XFF;
525
+
526
+  // skip data before offset
527
+  for (;offset_ < offset; offset_++) {
528
+    while (!(SPSR & (1 << SPIF)));
529
+    SPDR = 0XFF;
530
+  }
531
+  // transfer data
532
+  n = count - 1;
533
+  for (uint16_t i = 0; i < n; i++) {
534
+    while (!(SPSR & (1 << SPIF)));
535
+    dst[i] = SPDR;
536
+    SPDR = 0XFF;
537
+  }
538
+  // wait for last byte
539
+  while (!(SPSR & (1 << SPIF)));
540
+  dst[n] = SPDR;
541
+
542
+#else  // OPTIMIZE_HARDWARE_SPI
543
+
544
+  // skip data before offset
545
+  for (;offset_ < offset; offset_++) {
546
+    spiRec();
547
+  }
548
+  // transfer data
549
+  for (uint16_t i = 0; i < count; i++) {
550
+    dst[i] = spiRec();
551
+  }
552
+#endif  // OPTIMIZE_HARDWARE_SPI
553
+
554
+  offset_ += count;
555
+  if (!partialBlockRead_ || offset_ >= 512) {
556
+    // read rest of data, checksum and set chip select high
557
+    readEnd();
558
+  }
559
+  return true;
560
+
561
+ fail:
562
+  chipSelectHigh();
563
+  return false;
564
+}
565
+//------------------------------------------------------------------------------
566
+/** Skip remaining data in a block when in partial block read mode. */
567
+void Sd2Card::readEnd(void) {
568
+  if (inBlock_) {
569
+      // skip data and crc
570
+#if defined(USE_TEENSY3_SPI)
571
+    if (offset_ < 514) {
572
+      spiRecIgnore(514 - offset_);
573
+      offset_ = 514;
574
+    }
575
+#elif defined(OPTIMIZE_HARDWARE_SPI)
576
+    // optimize skip for hardware
577
+    SPDR = 0XFF;
578
+    while (offset_++ < 513) {
579
+      while (!(SPSR & (1 << SPIF)));
580
+      SPDR = 0XFF;
581
+    }
582
+    // wait for last crc byte
583
+    while (!(SPSR & (1 << SPIF)));
584
+#else  // OPTIMIZE_HARDWARE_SPI
585
+    while (offset_++ < 514) spiRec();
586
+#endif  // OPTIMIZE_HARDWARE_SPI
587
+    chipSelectHigh();
588
+    inBlock_ = 0;
589
+  }
590
+}
591
+//------------------------------------------------------------------------------
592
+/** read CID or CSR register */
593
+uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) {
594
+  uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
595
+  if (cardCommand(cmd, 0)) {
596
+    error(SD_CARD_ERROR_READ_REG);
597
+    goto fail;
598
+  }
599
+  if (!waitStartBlock()) goto fail;
600
+  // transfer data
601
+  for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec();
602
+  spiRec();  // get first crc byte
603
+  spiRec();  // get second crc byte
604
+  chipSelectHigh();
605
+  return true;
606
+
607
+ fail:
608
+  chipSelectHigh();
609
+  return false;
610
+}
611
+//------------------------------------------------------------------------------
612
+/**
613
+ * Set the SPI clock rate.
614
+ *
615
+ * \param[in] sckRateID A value in the range [0, 6].
616
+ *
617
+ * 0 = 8 MHz
618
+ * 1 = 4 MHz
619
+ * 2 = 2 MHz
620
+ * 3 = 1 MHz
621
+ * 4 = 500 kHz
622
+ * 5 = 125 kHz
623
+ * 6 = 63 kHz
624
+ *
625
+ * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum
626
+ * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128
627
+ * for \a scsRateID = 6.
628
+ *
629
+ * \return The value one, true, is returned for success and the value zero,
630
+ * false, is returned for an invalid value of \a sckRateID.
631
+ */
632
+uint8_t Sd2Card::setSckRate(uint8_t sckRateID) {
633
+#ifdef USE_TEENSY3_SPI
634
+  spiInit(sckRateID);
635
+  return true;
636
+#elif defined(__AVR_XMEGA__)
637
+  SPI.setBitOrder(MSBFIRST);
638
+  SPI.setDataMode(SPI_MODE0);
639
+  switch (sckRateID) {
640
+    case 0:  SPI.setClockDivider(SPI_CLOCK_DIV2); break;
641
+    case 1:  SPI.setClockDivider(SPI_CLOCK_DIV4); break;
642
+    case 2:  SPI.setClockDivider(SPI_CLOCK_DIV8); break;
643
+    case 3:  SPI.setClockDivider(SPI_CLOCK_DIV16); break;
644
+    case 4:  SPI.setClockDivider(SPI_CLOCK_DIV32); break;
645
+    case 5:  SPI.setClockDivider(SPI_CLOCK_DIV64); break;
646
+    default: SPI.setClockDivider(SPI_CLOCK_DIV128);
647
+  }
648
+  SPI.begin();
649
+  return true;
650
+#else
651
+  if (sckRateID > 6) sckRateID = 6;
652
+  // see avr processor datasheet for SPI register bit definitions
653
+  if ((sckRateID & 1) || sckRateID == 6) {
654
+    SPSR &= ~(1 << SPI2X);
655
+  } else {
656
+    SPSR |= (1 << SPI2X);
657
+  }
658
+  SPCR &= ~((1 <<SPR1) | (1 << SPR0));
659
+  SPCR |= (sckRateID & 4 ? (1 << SPR1) : 0)
660
+    | (sckRateID & 2 ? (1 << SPR0) : 0);
661
+#ifdef SPI_HAS_TRANSACTION
662
+  switch (sckRateID) {
663
+    case 0:  settings = SPISettings(8000000, MSBFIRST, SPI_MODE0); break;
664
+    case 1:  settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); break;
665
+    case 2:  settings = SPISettings(2000000, MSBFIRST, SPI_MODE0); break;
666
+    case 3:  settings = SPISettings(1000000, MSBFIRST, SPI_MODE0); break;
667
+    case 4:  settings = SPISettings(500000, MSBFIRST, SPI_MODE0); break;
668
+    case 5:  settings = SPISettings(250000, MSBFIRST, SPI_MODE0); break;
669
+    default: settings = SPISettings(125000, MSBFIRST, SPI_MODE0);
670
+  }
671
+#endif
672
+  return true;
673
+#endif
674
+}
675
+//------------------------------------------------------------------------------
676
+// wait for card to go not busy
677
+uint8_t Sd2Card::waitNotBusy(uint16_t timeoutMillis) {
678
+  uint16_t t0 = millis();
679
+  do {
680
+    if (spiRec() == 0XFF) return true;
681
+  }
682
+  while (((uint16_t)millis() - t0) < timeoutMillis);
683
+  return false;
684
+}
685
+//------------------------------------------------------------------------------
686
+/** Wait for start block token */
687
+uint8_t Sd2Card::waitStartBlock(void) {
688
+  uint16_t t0 = millis();
689
+  while ((status_ = spiRec()) == 0XFF) {
690
+    if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) {
691
+      error(SD_CARD_ERROR_READ_TIMEOUT);
692
+      goto fail;
693
+    }
694
+  }
695
+  if (status_ != DATA_START_BLOCK) {
696
+    error(SD_CARD_ERROR_READ);
697
+    goto fail;
698
+  }
699
+  return true;
700
+
701
+ fail:
702
+  chipSelectHigh();
703
+  return false;
704
+}
705
+//------------------------------------------------------------------------------