Browse Source

Optimize SD card reader, sorting (#15395)

Scott Lahteine 5 years ago
parent
commit
2277c6dffc
No account linked to committer's email address

+ 2
- 2
Marlin/src/lcd/extensible_ui/ui_api.cpp View File

1002
 
1002
 
1003
   void FileList::upDir() {
1003
   void FileList::upDir() {
1004
     #if ENABLED(SDSUPPORT)
1004
     #if ENABLED(SDSUPPORT)
1005
-      card.updir();
1005
+      card.cdup();
1006
       num_files = 0xFFFF;
1006
       num_files = 0xFFFF;
1007
     #endif
1007
     #endif
1008
   }
1008
   }
1009
 
1009
 
1010
   void FileList::changeDir(const char * const dirname) {
1010
   void FileList::changeDir(const char * const dirname) {
1011
     #if ENABLED(SDSUPPORT)
1011
     #if ENABLED(SDSUPPORT)
1012
-      card.chdir(dirname);
1012
+      card.cd(dirname);
1013
       num_files = 0xFFFF;
1013
       num_files = 0xFFFF;
1014
     #endif
1014
     #endif
1015
   }
1015
   }

+ 3
- 3
Marlin/src/lcd/extui_malyan_lcd.cpp View File

246
         // Find the name of the file to print.
246
         // Find the name of the file to print.
247
         // It's needed to echo the PRINTFILE option.
247
         // It's needed to echo the PRINTFILE option.
248
         // The {S:L} command should've ensured the SD card was mounted.
248
         // The {S:L} command should've ensured the SD card was mounted.
249
-        card.getfilename(atoi(command));
249
+        card.selectFileByIndex(atoi(command));
250
 
250
 
251
         // There may be a difference in how V1 and V2 LCDs handle subdirectory
251
         // There may be a difference in how V1 and V2 LCDs handle subdirectory
252
         // prints. Investigate more. This matches the V1 motion controller actions
252
         // prints. Investigate more. This matches the V1 motion controller actions
253
         // but the V2 LCD switches to "print" mode on {SYS:DIR} response.
253
         // but the V2 LCD switches to "print" mode on {SYS:DIR} response.
254
         if (card.flag.filenameIsDir) {
254
         if (card.flag.filenameIsDir) {
255
-          card.chdir(card.filename);
255
+          card.cd(card.filename);
256
           write_to_lcd_P(PSTR("{SYS:DIR}"));
256
           write_to_lcd_P(PSTR("{SYS:DIR}"));
257
         }
257
         }
258
         else {
258
         else {
309
         char message_buffer[MAX_CURLY_COMMAND];
309
         char message_buffer[MAX_CURLY_COMMAND];
310
         uint16_t file_count = card.get_num_Files();
310
         uint16_t file_count = card.get_num_Files();
311
         for (uint16_t i = 0; i < file_count; i++) {
311
         for (uint16_t i = 0; i < file_count; i++) {
312
-          card.getfilename(i);
312
+          card.selectFileByIndex(i);
313
           sprintf_P(message_buffer, card.flag.filenameIsDir ? PSTR("{DIR:%s}") : PSTR("{FILE:%s}"), card.longest_filename());
313
           sprintf_P(message_buffer, card.flag.filenameIsDir ? PSTR("{DIR:%s}") : PSTR("{FILE:%s}"), card.longest_filename());
314
           write_to_lcd(message_buffer);
314
           write_to_lcd(message_buffer);
315
         }
315
         }

+ 2
- 2
Marlin/src/lcd/menu/menu_media.cpp View File

39
 #endif
39
 #endif
40
 
40
 
41
 void lcd_sd_updir() {
41
 void lcd_sd_updir() {
42
-  ui.encoderPosition = card.updir() ? ENCODER_STEPS_PER_MENU_ITEM : 0;
42
+  ui.encoderPosition = card.cdup() ? ENCODER_STEPS_PER_MENU_ITEM : 0;
43
   encoderTopLine = 0;
43
   encoderTopLine = 0;
44
   screen_changed = true;
44
   screen_changed = true;
45
   ui.refresh();
45
   ui.refresh();
115
 class MenuItem_sdfolder {
115
 class MenuItem_sdfolder {
116
   public:
116
   public:
117
     static void action(CardReader &theCard) {
117
     static void action(CardReader &theCard) {
118
-      card.chdir(theCard.filename);
118
+      card.cd(theCard.filename);
119
       encoderTopLine = 0;
119
       encoderTopLine = 0;
120
       ui.encoderPosition = 2 * (ENCODER_STEPS_PER_MENU_ITEM);
120
       ui.encoderPosition = 2 * (ENCODER_STEPS_PER_MENU_ITEM);
121
       screen_changed = true;
121
       screen_changed = true;

+ 200
- 149
Marlin/src/sd/cardreader.cpp View File

62
 uint8_t CardReader::workDirDepth;
62
 uint8_t CardReader::workDirDepth;
63
 
63
 
64
 #if ENABLED(SDCARD_SORT_ALPHA)
64
 #if ENABLED(SDCARD_SORT_ALPHA)
65
+
65
   uint16_t CardReader::sort_count;
66
   uint16_t CardReader::sort_count;
66
   #if ENABLED(SDSORT_GCODE)
67
   #if ENABLED(SDSORT_GCODE)
67
     bool CardReader::sort_alpha;
68
     bool CardReader::sort_alpha;
78
   #if ENABLED(SDSORT_USES_RAM)
79
   #if ENABLED(SDSORT_USES_RAM)
79
 
80
 
80
     #if ENABLED(SDSORT_CACHE_NAMES)
81
     #if ENABLED(SDSORT_CACHE_NAMES)
82
+      uint16_t CardReader::nrFiles; // Cached total file count
81
       #if ENABLED(SDSORT_DYNAMIC_RAM)
83
       #if ENABLED(SDSORT_DYNAMIC_RAM)
82
         char **CardReader::sortshort, **CardReader::sortnames;
84
         char **CardReader::sortshort, **CardReader::sortnames;
83
       #else
85
       #else
94
       #elif ENABLED(SDSORT_CACHE_NAMES) || DISABLED(SDSORT_USES_STACK)
96
       #elif ENABLED(SDSORT_CACHE_NAMES) || DISABLED(SDSORT_USES_STACK)
95
         uint8_t CardReader::isDir[(SDSORT_LIMIT+7)>>3];
97
         uint8_t CardReader::isDir[(SDSORT_LIMIT+7)>>3];
96
       #endif
98
       #endif
99
+      #define IS_DIR(n) TEST(isDir[(n) >> 3], (n) & 0x07)
97
     #endif
100
     #endif
98
 
101
 
99
   #endif // SDSORT_USES_RAM
102
   #endif // SDSORT_USES_RAM
110
 
113
 
111
 uint32_t CardReader::filesize, CardReader::sdpos;
114
 uint32_t CardReader::filesize, CardReader::sdpos;
112
 
115
 
113
-LsAction CardReader::lsAction; //stored for recursion.
114
-uint16_t CardReader::nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory.
115
-char *CardReader::diveDirName;
116
-
117
 CardReader::CardReader() {
116
 CardReader::CardReader() {
118
   #if ENABLED(SDCARD_SORT_ALPHA)
117
   #if ENABLED(SDCARD_SORT_ALPHA)
119
     sort_count = 0;
118
     sort_count = 0;
138
   #endif
137
   #endif
139
 }
138
 }
140
 
139
 
141
-char *createFilename(char *buffer, const dir_t &p) {
140
+//
141
+// Get a DOS 8.3 filename in its useful form
142
+//
143
+char *createFilename(char * const buffer, const dir_t &p) {
142
   char *pos = buffer;
144
   char *pos = buffer;
143
   for (uint8_t i = 0; i < 11; i++) {
145
   for (uint8_t i = 0; i < 11; i++) {
144
     if (p.name[i] == ' ') continue;
146
     if (p.name[i] == ' ') continue;
149
   return buffer;
151
   return buffer;
150
 }
152
 }
151
 
153
 
152
-/**
153
- * Dive into a folder and recurse depth-first to perform a pre-set operation lsAction:
154
- *   LS_Count       - Add +1 to nrFiles for every file within the parent
155
- *   LS_GetFilename - Get the filename of the file indexed by nrFile_index
156
- *   LS_SerialPrint - Print the full path and size of each file to serial output
157
- */
154
+//
155
+// Return 'true' if the item is a folder or G-code file
156
+//
157
+bool CardReader::is_dir_or_gcode(const dir_t &p) {
158
+  uint8_t pn0 = p.name[0];
159
+
160
+  if ( pn0 == DIR_NAME_FREE || pn0 == DIR_NAME_DELETED  // Clear or Deleted entry
161
+    || pn0 == '.' || longFilename[0] == '.'             // Hidden file
162
+    || !DIR_IS_FILE_OR_SUBDIR(&p)                       // Not a File or Directory
163
+    || (p.attributes & DIR_ATT_HIDDEN)                  // Hidden by attribute
164
+  ) return false;
158
 
165
 
159
-uint16_t nrFile_index;
166
+  flag.filenameIsDir = DIR_IS_SUBDIR(&p);               // We know it's a File or Folder
160
 
167
 
161
-void CardReader::lsDive(const char *prepend, SdFile parent, const char * const match/*=nullptr*/) {
168
+  return (
169
+    flag.filenameIsDir                                  // All Directories are ok
170
+    || (p.name[8] == 'G' && p.name[9] != '~')           // Non-backup *.G* files are accepted
171
+  );
172
+}
173
+
174
+//
175
+// Get the number of (compliant) items in the folder
176
+//
177
+int CardReader::countItems(SdFile dir) {
162
   dir_t p;
178
   dir_t p;
163
-  uint8_t cnt = 0;
179
+  int c = 0;
180
+  while (dir.readDir(&p, longFilename) > 0)
181
+    c += is_dir_or_gcode(p);
164
 
182
 
165
-  // Read the next entry from a directory
166
-  while (parent.readDir(&p, longFilename) > 0) {
183
+  #if ENABLED(SDCARD_SORT_ALPHA) && SDSORT_USES_RAM && SDSORT_CACHE_NAMES
184
+    nrFiles = c;
185
+  #endif
167
 
186
 
168
-    // If the entry is a directory and the action is LS_SerialPrint
169
-    if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) {
187
+  return c;
188
+}
189
+
190
+//
191
+// Get file/folder info for an item by index
192
+//
193
+void CardReader::selectByIndex(SdFile dir, const uint8_t index) {
194
+  dir_t p;
195
+  for (uint8_t cnt = 0; dir.readDir(&p, longFilename) > 0;) {
196
+    if (is_dir_or_gcode(p)) {
197
+      if (cnt == index) {
198
+        createFilename(filename, p);
199
+        return;  // 0 based index
200
+      }
201
+      cnt++;
202
+    }
203
+  }
204
+}
205
+
206
+//
207
+// Get file/folder info for an item by name
208
+//
209
+void CardReader::selectByName(SdFile dir, const char * const match) {
210
+  dir_t p;
211
+  for (uint8_t cnt = 0; dir.readDir(&p, longFilename) > 0; cnt++) {
212
+    if (is_dir_or_gcode(p)) {
213
+      createFilename(filename, p);
214
+      if (strcasecmp(match, filename) == 0) return;
215
+    }
216
+  }
217
+}
218
+
219
+//
220
+// Recursive method to list all files within a folder
221
+//
222
+void CardReader::printListing(SdFile parent, const char * const prepend/*=nullptr*/) {
223
+  dir_t p;
224
+  while (parent.readDir(&p, longFilename) > 0) {
225
+    if (DIR_IS_SUBDIR(&p)) {
170
 
226
 
171
       // Get the short name for the item, which we know is a folder
227
       // Get the short name for the item, which we know is a folder
172
       char dosFilename[FILENAME_LENGTH];
228
       char dosFilename[FILENAME_LENGTH];
188
 
244
 
189
       // Get a new directory object using the full path
245
       // Get a new directory object using the full path
190
       // and dive recursively into it.
246
       // and dive recursively into it.
191
-      SdFile dir;
192
-      if (!dir.open(&parent, dosFilename, O_READ)) {
193
-        if (lsAction == LS_SerialPrint) {
194
-          SERIAL_ECHO_START();
195
-          SERIAL_ECHOLNPAIR(MSG_SD_CANT_OPEN_SUBDIR, dosFilename);
196
-        }
247
+      SdFile child;
248
+      if (!child.open(&parent, dosFilename, O_READ)) {
249
+        SERIAL_ECHO_START();
250
+        SERIAL_ECHOLNPAIR(MSG_SD_CANT_OPEN_SUBDIR, dosFilename);
197
       }
251
       }
198
-      lsDive(path, dir);
252
+      printListing(child, path);
199
       // close() is done automatically by destructor of SdFile
253
       // close() is done automatically by destructor of SdFile
200
     }
254
     }
201
-    else {
202
-      uint8_t pn0 = p.name[0];
203
-      if (pn0 == DIR_NAME_FREE) break;
204
-      if (pn0 == DIR_NAME_DELETED || pn0 == '.') continue;
205
-      if (longFilename[0] == '.') continue;
206
-
207
-      if (!DIR_IS_FILE_OR_SUBDIR(&p) || (p.attributes & DIR_ATT_HIDDEN)) continue;
208
-
209
-      flag.filenameIsDir = DIR_IS_SUBDIR(&p);
210
-
211
-      if (!flag.filenameIsDir && (p.name[8] != 'G' || p.name[9] == '~')) continue;
212
-
213
-      switch (lsAction) {  // 1 based file count
214
-        case LS_Count:
215
-          nrFiles++;
216
-          break;
217
-
218
-        case LS_SerialPrint:
219
-          createFilename(filename, p);
220
-          if (prepend) SERIAL_ECHO(prepend);
221
-          SERIAL_ECHO(filename);
222
-          SERIAL_CHAR(' ');
223
-          SERIAL_ECHOLN(p.fileSize);
224
-          break;
225
-
226
-        case LS_GetFilename:
227
-          createFilename(filename, p);
228
-          if (match != nullptr) {
229
-            if (strcasecmp(match, filename) == 0) return;
230
-          }
231
-          else if (cnt == nrFile_index) return;  // 0 based index
232
-          cnt++;
233
-          break;
234
-      }
235
-
255
+    else if (is_dir_or_gcode(p)) {
256
+      createFilename(filename, p);
257
+      if (prepend) SERIAL_ECHO(prepend);
258
+      SERIAL_ECHO(filename);
259
+      SERIAL_CHAR(' ');
260
+      SERIAL_ECHOLN(p.fileSize);
236
     }
261
     }
237
-  } // while readDir
262
+  }
238
 }
263
 }
239
 
264
 
265
+//
266
+// List all files on the SD card
267
+//
240
 void CardReader::ls() {
268
 void CardReader::ls() {
241
-  lsAction = LS_SerialPrint;
242
   root.rewind();
269
   root.rewind();
243
-  lsDive(nullptr, root);
270
+  printListing(root);
244
 }
271
 }
245
 
272
 
246
 #if ENABLED(LONG_FILENAME_HOST_SUPPORT)
273
 #if ENABLED(LONG_FILENAME_HOST_SUPPORT)
247
 
274
 
248
-  /**
249
-   * Get a long pretty path based on a DOS 8.3 path
250
-   */
251
-  void CardReader::printLongPath(char *path) {
252
-    lsAction = LS_GetFilename;
275
+  //
276
+  // Get a long pretty path based on a DOS 8.3 path
277
+  //
278
+  void CardReader::printLongPath(char * const path) {
253
 
279
 
254
     int i, pathLen = strlen(path);
280
     int i, pathLen = strlen(path);
255
 
281
 
275
 
301
 
276
       // Find the item, setting the long filename
302
       // Find the item, setting the long filename
277
       diveDir.rewind();
303
       diveDir.rewind();
278
-      lsDive(nullptr, diveDir, segment);
304
+      selectByName(diveDir, segment);
279
 
305
 
280
       // Print /LongNamePart to serial output
306
       // Print /LongNamePart to serial output
281
       SERIAL_CHAR('/');
307
       SERIAL_CHAR('/');
305
 
331
 
306
 #endif // LONG_FILENAME_HOST_SUPPORT
332
 #endif // LONG_FILENAME_HOST_SUPPORT
307
 
333
 
308
-/**
309
- * Echo the DOS 8.3 filename (and long filename, if any)
310
- */
334
+//
335
+// Echo the DOS 8.3 filename (and long filename, if any)
336
+//
311
 void CardReader::printFilename() {
337
 void CardReader::printFilename() {
312
   if (file.isOpen()) {
338
   if (file.isOpen()) {
313
     char dosFilename[FILENAME_LENGTH];
339
     char dosFilename[FILENAME_LENGTH];
314
     file.getDosName(dosFilename);
340
     file.getDosName(dosFilename);
315
     SERIAL_ECHO(dosFilename);
341
     SERIAL_ECHO(dosFilename);
316
     #if ENABLED(LONG_FILENAME_HOST_SUPPORT)
342
     #if ENABLED(LONG_FILENAME_HOST_SUPPORT)
317
-      getfilename(0, dosFilename);
343
+      selectFileByName(dosFilename);
318
       if (longFilename[0]) {
344
       if (longFilename[0]) {
319
         SERIAL_ECHO(' ');
345
         SERIAL_ECHO(' ');
320
         SERIAL_ECHO(longFilename);
346
         SERIAL_ECHO(longFilename);
339
     #if defined(LCD_SDSS) && (LCD_SDSS != SDSS)
365
     #if defined(LCD_SDSS) && (LCD_SDSS != SDSS)
340
       && !sd2card.init(SPI_SPEED, LCD_SDSS)
366
       && !sd2card.init(SPI_SPEED, LCD_SDSS)
341
     #endif
367
     #endif
342
-  ) {
343
-    //if (!sd2card.init(SPI_HALF_SPEED,SDSS))
344
-    SERIAL_ECHO_MSG(MSG_SD_INIT_FAIL);
345
-  }
368
+  ) SERIAL_ECHO_MSG(MSG_SD_INIT_FAIL);
346
   else if (!volume.init(&sd2card))
369
   else if (!volume.init(&sd2card))
347
     SERIAL_ERROR_MSG(MSG_SD_VOL_INIT_FAIL);
370
     SERIAL_ERROR_MSG(MSG_SD_VOL_INIT_FAIL);
348
   else if (!root.openRoot(&volume))
371
   else if (!root.openRoot(&volume))
354
       settings.first_load();
377
       settings.first_load();
355
     #endif
378
     #endif
356
   }
379
   }
357
-  setroot();
380
+  cdroot();
358
 
381
 
359
   ui.refresh();
382
   ui.refresh();
360
 }
383
 }
401
   openFile(path, false);
424
   openFile(path, false);
402
 }
425
 }
403
 
426
 
404
-void appendAtom(SdFile &file, char *& dst, uint8_t &cnt) {
405
-  file.getDosName(dst);
406
-  while (*dst && cnt < MAXPATHNAMELENGTH) { dst++; cnt++; }
407
-  if (cnt < MAXPATHNAMELENGTH) { *dst = '/'; dst++; cnt++; }
408
-}
409
-
410
-void CardReader::getAbsFilename(char *t) {
411
-  *t++ = '/';                                               // Root folder
427
+//
428
+// Get the root-relative DOS path of the selected file
429
+//
430
+void CardReader::getAbsFilename(char *dst) {
431
+  *dst++ = '/';
412
   uint8_t cnt = 1;
432
   uint8_t cnt = 1;
413
 
433
 
414
-  for (uint8_t i = 0; i < workDirDepth; i++)                // Loop to current work dir
415
-    appendAtom(workDirParents[i], t, cnt);
434
+  auto appendAtom = [&](SdFile &file) {
435
+    file.getDosName(dst);
436
+    while (*dst && cnt < MAXPATHNAMELENGTH) { dst++; cnt++; }
437
+    if (cnt < MAXPATHNAMELENGTH) { *dst = '/'; dst++; cnt++; }
438
+  };
439
+
440
+  for (uint8_t i = 0; i < workDirDepth; i++)                // Loop down to current work dir
441
+    appendAtom(workDirParents[i]);
416
 
442
 
417
   if (cnt < MAXPATHNAMELENGTH - (FILENAME_LENGTH) - 1) {    // Leave room for filename and nul
443
   if (cnt < MAXPATHNAMELENGTH - (FILENAME_LENGTH) - 1) {    // Leave room for filename and nul
418
-    appendAtom(file, t, cnt);
419
-    --t;
444
+    appendAtom(file);
445
+    --dst;
420
   }
446
   }
421
-  *t = '\0';
447
+  *dst = '\0';
422
 }
448
 }
423
 
449
 
450
+//
451
+// Open a file by DOS path - for read or write
452
+//
424
 void CardReader::openFile(char * const path, const bool read, const bool subcall/*=false*/) {
453
 void CardReader::openFile(char * const path, const bool read, const bool subcall/*=false*/) {
425
 
454
 
426
   if (!isMounted()) return;
455
   if (!isMounted()) return;
472
       SERIAL_ECHOLNPAIR(MSG_SD_FILE_OPENED, fname, MSG_SD_SIZE, filesize);
501
       SERIAL_ECHOLNPAIR(MSG_SD_FILE_OPENED, fname, MSG_SD_SIZE, filesize);
473
       SERIAL_ECHOLNPGM(MSG_SD_FILE_SELECTED);
502
       SERIAL_ECHOLNPGM(MSG_SD_FILE_SELECTED);
474
 
503
 
475
-      getfilename(0, fname);
504
+      selectFileByName(fname);
476
       ui.set_status(longFilename[0] ? longFilename : fname);
505
       ui.set_status(longFilename[0] ? longFilename : fname);
477
       //if (longFilename[0]) {
506
       //if (longFilename[0]) {
478
       //  SERIAL_ECHOPAIR(MSG_SD_FILE_LONG_NAME, longFilename);
507
       //  SERIAL_ECHOPAIR(MSG_SD_FILE_LONG_NAME, longFilename);
486
       SERIAL_ECHOLNPAIR(MSG_SD_OPEN_FILE_FAIL, fname, ".");
515
       SERIAL_ECHOLNPAIR(MSG_SD_OPEN_FILE_FAIL, fname, ".");
487
     else {
516
     else {
488
       flag.saving = true;
517
       flag.saving = true;
489
-      getfilename(0, fname);
518
+      selectFileByName(fname);
490
       #if ENABLED(EMERGENCY_PARSER)
519
       #if ENABLED(EMERGENCY_PARSER)
491
         emergency_parser.disable();
520
         emergency_parser.disable();
492
       #endif
521
       #endif
496
   }
525
   }
497
 }
526
 }
498
 
527
 
528
+//
529
+// Delete a file by name in the working directory
530
+//
499
 void CardReader::removeFile(const char * const name) {
531
 void CardReader::removeFile(const char * const name) {
500
   if (!isMounted()) return;
532
   if (!isMounted()) return;
501
 
533
 
527
     SERIAL_ECHOLNPGM(MSG_SD_NOT_PRINTING);
559
     SERIAL_ECHOLNPGM(MSG_SD_NOT_PRINTING);
528
 }
560
 }
529
 
561
 
530
-void CardReader::write_command(char *buf) {
562
+void CardReader::write_command(char * const buf) {
531
   char* begin = buf;
563
   char* begin = buf;
532
   char* npos = nullptr;
564
   char* npos = nullptr;
533
   char* end = buf + strlen(buf) - 1;
565
   char* end = buf + strlen(buf) - 1;
584
 
616
 
585
 void CardReader::beginautostart() {
617
 void CardReader::beginautostart() {
586
   autostart_index = 0;
618
   autostart_index = 0;
587
-  setroot();
619
+  cdroot();
588
 }
620
 }
589
 
621
 
590
 void CardReader::closefile(const bool store_location) {
622
 void CardReader::closefile(const bool store_location) {
602
   }
634
   }
603
 }
635
 }
604
 
636
 
605
-/**
606
- * Get the name of a file in the current directory by index
607
- * with optional name to match.
608
- */
609
-void CardReader::getfilename(uint16_t nr, const char * const match/*=nullptr*/) {
637
+//
638
+// Get info for a file in the working directory by index
639
+//
640
+void CardReader::selectFileByIndex(const uint16_t nr) {
610
   #if ENABLED(SDSORT_CACHE_NAMES)
641
   #if ENABLED(SDSORT_CACHE_NAMES)
611
-    if (match != nullptr) {
612
-      while (nr < sort_count) {
613
-        if (strcasecmp(match, sortshort[nr]) == 0) break;
614
-        nr++;
615
-      }
616
-    }
617
     if (nr < sort_count) {
642
     if (nr < sort_count) {
618
       strcpy(filename, sortshort[nr]);
643
       strcpy(filename, sortshort[nr]);
619
       strcpy(longFilename, sortnames[nr]);
644
       strcpy(longFilename, sortnames[nr]);
620
-      flag.filenameIsDir = TEST(isDir[nr>>3], nr & 0x07);
645
+      flag.filenameIsDir = IS_DIR(nr);
621
       return;
646
       return;
622
     }
647
     }
623
-  #endif // SDSORT_CACHE_NAMES
624
-  lsAction = LS_GetFilename;
625
-  nrFile_index = nr;
648
+  #endif
649
+  workDir.rewind();
650
+  selectByIndex(workDir, nr);
651
+}
652
+
653
+//
654
+// Get info for a file in the working directory by DOS name
655
+//
656
+void CardReader::selectFileByName(const char * const match) {
657
+  #if ENABLED(SDSORT_CACHE_NAMES)
658
+    for (int nr = 0; nr < sort_count; nr++)
659
+      if (strcasecmp(match, sortshort[nr]) == 0) {
660
+        strcpy(filename, sortshort[nr]);
661
+        strcpy(longFilename, sortnames[nr]);
662
+        flag.filenameIsDir = IS_DIR(nr);
663
+        return;
664
+      }
665
+  #endif
626
   workDir.rewind();
666
   workDir.rewind();
627
-  lsDive(nullptr, workDir, match);
667
+  selectByName(workDir, match);
628
 }
668
 }
629
 
669
 
630
 uint16_t CardReader::countFilesInWorkDir() {
670
 uint16_t CardReader::countFilesInWorkDir() {
631
-  lsAction = LS_Count;
632
-  nrFiles = 0;
633
   workDir.rewind();
671
   workDir.rewind();
634
-  lsDive(nullptr, workDir);
635
-  //SERIAL_ECHOLN(nrFiles);
636
-  return nrFiles;
672
+  return countItems(workDir);
637
 }
673
 }
638
 
674
 
639
 /**
675
 /**
650
   static SdFile newDir1, newDir2;
686
   static SdFile newDir1, newDir2;
651
   SdFile *sub = &newDir1, *startDir;
687
   SdFile *sub = &newDir1, *startDir;
652
 
688
 
653
-  const char *dirname_start = path;
689
+  const char *item_name_adr = path;
654
   if (path[0] == '/') {
690
   if (path[0] == '/') {
655
     curDir = &root;
691
     curDir = &root;
656
     workDirDepth = 0;
692
     workDirDepth = 0;
657
-    dirname_start++;
693
+    item_name_adr++;
658
   }
694
   }
659
   else
695
   else
660
     curDir = &workDir;
696
     curDir = &workDir;
662
   startDir = curDir;
698
   startDir = curDir;
663
 
699
 
664
   // Start dive
700
   // Start dive
665
-  while (dirname_start) {
701
+  while (item_name_adr) {
666
     // Find next sub
702
     // Find next sub
667
-    char * const dirname_end = strchr(dirname_start, '/');
668
-    if (dirname_end <= dirname_start) break;
703
+    char * const name_end = strchr(item_name_adr, '/');
704
+    if (name_end <= item_name_adr) break;
669
 
705
 
670
     // Set subDirName
706
     // Set subDirName
671
-    const uint8_t len = dirname_end - dirname_start;
707
+    const uint8_t len = name_end - item_name_adr;
672
     char dosSubdirname[len + 1];
708
     char dosSubdirname[len + 1];
673
-    strncpy(dosSubdirname, dirname_start, len);
709
+    strncpy(dosSubdirname, item_name_adr, len);
674
     dosSubdirname[len] = 0;
710
     dosSubdirname[len] = 0;
675
 
711
 
676
     if (echo) SERIAL_ECHOLN(dosSubdirname);
712
     if (echo) SERIAL_ECHOLN(dosSubdirname);
693
     // Point sub pointer to unused newDir
729
     // Point sub pointer to unused newDir
694
     sub = (curDir != &newDir1) ? &newDir1 : &newDir2;
730
     sub = (curDir != &newDir1) ? &newDir1 : &newDir2;
695
 
731
 
696
-    // dirname_start point to next sub
697
-    dirname_start = dirname_end + 1;
732
+    // item_name_adr point to next sub
733
+    item_name_adr = name_end + 1;
698
   }
734
   }
699
-  return dirname_start;
735
+  return item_name_adr;
700
 }
736
 }
701
 
737
 
702
-void CardReader::chdir(const char * relpath) {
738
+void CardReader::cd(const char * relpath) {
703
   SdFile newDir;
739
   SdFile newDir;
704
   SdFile *parent = workDir.isOpen() ? &workDir : &root;
740
   SdFile *parent = workDir.isOpen() ? &workDir : &root;
705
 
741
 
718
   }
754
   }
719
 }
755
 }
720
 
756
 
721
-int8_t CardReader::updir() {
757
+int8_t CardReader::cdup() {
722
   if (workDirDepth > 0) {                                               // At least 1 dir has been saved
758
   if (workDirDepth > 0) {                                               // At least 1 dir has been saved
723
     workDir = --workDirDepth ? workDirParents[workDirDepth - 1] : root; // Use parent, or root if none
759
     workDir = --workDirDepth ? workDirParents[workDirDepth - 1] : root; // Use parent, or root if none
724
     #if ENABLED(SDCARD_SORT_ALPHA)
760
     #if ENABLED(SDCARD_SORT_ALPHA)
729
   return workDirDepth;
765
   return workDirDepth;
730
 }
766
 }
731
 
767
 
732
-void CardReader::setroot() {
768
+void CardReader::cdroot() {
733
   workDir = root;
769
   workDir = root;
734
   flag.workDirIsRoot = true;
770
   flag.workDirIsRoot = true;
735
   #if ENABLED(SDCARD_SORT_ALPHA)
771
   #if ENABLED(SDCARD_SORT_ALPHA)
740
 #if ENABLED(SDCARD_SORT_ALPHA)
776
 #if ENABLED(SDCARD_SORT_ALPHA)
741
 
777
 
742
   /**
778
   /**
743
-   * Get the name of a file in the current directory by sort-index
779
+   * Get the name of a file in the working directory by sort-index
744
    */
780
    */
745
   void CardReader::getfilename_sorted(const uint16_t nr) {
781
   void CardReader::getfilename_sorted(const uint16_t nr) {
746
-    getfilename(
782
+    selectFileByIndex(
747
       #if ENABLED(SDSORT_GCODE)
783
       #if ENABLED(SDSORT_GCODE)
748
         sort_alpha &&
784
         sort_alpha &&
749
       #endif
785
       #endif
757
       #define SET_SORTNAME(I) (sortnames[I] = strdup(longest_filename()))
793
       #define SET_SORTNAME(I) (sortnames[I] = strdup(longest_filename()))
758
       #if ENABLED(SDSORT_CACHE_NAMES)
794
       #if ENABLED(SDSORT_CACHE_NAMES)
759
         // When caching also store the short name, since
795
         // When caching also store the short name, since
760
-        // we're replacing the getfilename() behavior.
796
+        // we're replacing the selectFileByIndex() behavior.
761
         #define SET_SORTSHORT(I) (sortshort[I] = strdup(filename))
797
         #define SET_SORTSHORT(I) (sortshort[I] = strdup(filename))
762
       #else
798
       #else
763
         #define SET_SORTSHORT(I) NOOP
799
         #define SET_SORTSHORT(I) NOOP
854
           i);
890
           i);
855
           // If using RAM then read all filenames now.
891
           // If using RAM then read all filenames now.
856
           #if ENABLED(SDSORT_USES_RAM)
892
           #if ENABLED(SDSORT_USES_RAM)
857
-            getfilename(i);
893
+            selectFileByIndex(i);
858
             SET_SORTNAME(i);
894
             SET_SORTNAME(i);
859
             SET_SORTSHORT(i);
895
             SET_SORTSHORT(i);
860
             // char out[30];
896
             // char out[30];
871
         // Bubble Sort
907
         // Bubble Sort
872
         for (uint16_t i = fileCnt; --i;) {
908
         for (uint16_t i = fileCnt; --i;) {
873
           bool didSwap = false;
909
           bool didSwap = false;
910
+          uint8_t o1 = sort_order[0];
911
+          #if DISABLED(SDSORT_USES_RAM)
912
+            selectFileByIndex(o1);                // Pre-fetch the first entry and save it
913
+            strcpy(name1, longest_filename());  // so the loop only needs one fetch
914
+            #if HAS_FOLDER_SORTING
915
+              bool dir1 = flag.filenameIsDir;
916
+            #endif
917
+          #endif
918
+
874
           for (uint16_t j = 0; j < i; ++j) {
919
           for (uint16_t j = 0; j < i; ++j) {
875
-            const uint16_t o1 = sort_order[j], o2 = sort_order[j + 1];
920
+            const uint16_t o2 = sort_order[j + 1];
876
 
921
 
877
             // Compare names from the array or just the two buffered names
922
             // Compare names from the array or just the two buffered names
878
             #if ENABLED(SDSORT_USES_RAM)
923
             #if ENABLED(SDSORT_USES_RAM)
884
             #if HAS_FOLDER_SORTING
929
             #if HAS_FOLDER_SORTING
885
               #if ENABLED(SDSORT_USES_RAM)
930
               #if ENABLED(SDSORT_USES_RAM)
886
                 // Folder sorting needs an index and bit to test for folder-ness.
931
                 // Folder sorting needs an index and bit to test for folder-ness.
887
-                const uint8_t ind1 = o1 >> 3, bit1 = o1 & 0x07,
888
-                              ind2 = o2 >> 3, bit2 = o2 & 0x07;
889
-                #define _SORT_CMP_DIR(fs) \
890
-                  (((isDir[ind1] & _BV(bit1)) != 0) == ((isDir[ind2] & _BV(bit2)) != 0) \
891
-                    ? _SORT_CMP_NODIR() \
892
-                    : (isDir[fs > 0 ? ind1 : ind2] & (fs > 0 ? _BV(bit1) : _BV(bit2))) != 0)
932
+                #define _SORT_CMP_DIR(fs) IS_DIR(o1) == IS_DIR(o2) ? _SORT_CMP_NODIR() : IS_DIR(fs > 0 ? o1 : o2)
893
               #else
933
               #else
894
                 #define _SORT_CMP_DIR(fs) ((dir1 == flag.filenameIsDir) ? _SORT_CMP_NODIR() : (fs > 0 ? dir1 : !dir1))
934
                 #define _SORT_CMP_DIR(fs) ((dir1 == flag.filenameIsDir) ? _SORT_CMP_NODIR() : (fs > 0 ? dir1 : !dir1))
895
               #endif
935
               #endif
898
             // The most economical method reads names as-needed
938
             // The most economical method reads names as-needed
899
             // throughout the loop. Slow if there are many.
939
             // throughout the loop. Slow if there are many.
900
             #if DISABLED(SDSORT_USES_RAM)
940
             #if DISABLED(SDSORT_USES_RAM)
901
-              getfilename(o1);
902
-              strcpy(name1, longest_filename()); // save (or getfilename below will trounce it)
903
-              #if HAS_FOLDER_SORTING
904
-                bool dir1 = flag.filenameIsDir;
905
-              #endif
906
-              getfilename(o2);
907
-              char *name2 = longest_filename(); // use the string in-place
941
+              selectFileByIndex(o2);
942
+              const bool dir2 = flag.filenameIsDir;
943
+              char * const name2 = longest_filename(); // use the string in-place
908
             #endif // !SDSORT_USES_RAM
944
             #endif // !SDSORT_USES_RAM
909
 
945
 
910
             // Sort the current pair according to settings.
946
             // Sort the current pair according to settings.
919
                 _SORT_CMP_NODIR()
955
                 _SORT_CMP_NODIR()
920
               #endif
956
               #endif
921
             ) {
957
             ) {
958
+              // Reorder the index, indicate that sorting happened
959
+              // Note that the next o1 will be the current o1. No new fetch needed.
922
               sort_order[j] = o2;
960
               sort_order[j] = o2;
923
               sort_order[j + 1] = o1;
961
               sort_order[j + 1] = o1;
924
               didSwap = true;
962
               didSwap = true;
925
             }
963
             }
964
+            else {
965
+              // The next o1 is the current o2. No new fetch needed.
966
+              o1 = o2;
967
+              #if DISABLED(SDSORT_USES_RAM)
968
+                #if HAS_FOLDER_SORTING
969
+                  dir1 = dir2;
970
+                #endif
971
+                strcpy(name1, name2);
972
+              #endif
973
+            }
926
           }
974
           }
927
           if (!didSwap) break;
975
           if (!didSwap) break;
928
         }
976
         }
944
             sortshort = new char*[1];
992
             sortshort = new char*[1];
945
             isDir = new uint8_t[1];
993
             isDir = new uint8_t[1];
946
           #endif
994
           #endif
947
-          getfilename(0);
995
+          selectFileByIndex(0);
948
           SET_SORTNAME(0);
996
           SET_SORTNAME(0);
949
           SET_SORTSHORT(0);
997
           SET_SORTSHORT(0);
950
-          isDir[0] = flag.filenameIsDir ? 0x01 : 0x00;
998
+          isDir[0] = flag.filenameIsDir;
951
         #endif
999
         #endif
952
       }
1000
       }
953
 
1001
 
984
   ;
1032
   ;
985
 }
1033
 }
986
 
1034
 
1035
+//
1036
+// Return from procedure or close out the Print Job
1037
+//
987
 void CardReader::printingHasFinished() {
1038
 void CardReader::printingHasFinished() {
988
   planner.synchronize();
1039
   planner.synchronize();
989
   file.close();
1040
   file.close();

+ 86
- 62
Marlin/src/sd/cardreader.h View File

33
 
33
 
34
 #include "SdFile.h"
34
 #include "SdFile.h"
35
 
35
 
36
-enum LsAction : uint8_t { LS_SerialPrint, LS_Count, LS_GetFilename };
37
-
38
 typedef struct {
36
 typedef struct {
39
   bool saving:1,
37
   bool saving:1,
40
        logging:1,
38
        logging:1,
51
 
49
 
52
 class CardReader {
50
 class CardReader {
53
 public:
51
 public:
52
+  static card_flags_t flag;                         // Flags (above)
53
+  static char filename[FILENAME_LENGTH],            // DOS 8.3 filename of the selected item
54
+              longFilename[LONG_FILENAME_LENGTH];   // Long name of the selected item
55
+
56
+  // Fast! binary file transfer
57
+  #if ENABLED(BINARY_FILE_TRANSFER)
58
+    #if NUM_SERIAL > 1
59
+      static int8_t transfer_port_index;
60
+    #else
61
+      static constexpr int8_t transfer_port_index = 0;
62
+    #endif
63
+  #endif
64
+
65
+  // // // Methods // // //
66
+
54
   CardReader();
67
   CardReader();
55
 
68
 
69
+  static SdFile getroot() { return root; }
70
+
56
   static void mount();
71
   static void mount();
57
-  static void write_command(char *buf);
72
+  static void release();
73
+  static inline bool isMounted() { return flag.mounted; }
74
+  static void ls();
58
 
75
 
76
+  // SD Card Logging
77
+  static void openLogFile(char * const path);
78
+  static void write_command(char * const buf);
79
+
80
+  // Auto-Start files
81
+  static int8_t autostart_index;                    // Index of autoX.g files
59
   static void beginautostart();
82
   static void beginautostart();
60
   static void checkautostart();
83
   static void checkautostart();
61
 
84
 
85
+  // Basic file ops
62
   static void openFile(char * const path, const bool read, const bool subcall=false);
86
   static void openFile(char * const path, const bool read, const bool subcall=false);
63
-  static void openLogFile(char * const path);
64
-  static void removeFile(const char * const name);
65
   static void closefile(const bool store_location=false);
87
   static void closefile(const bool store_location=false);
66
-  static void release();
67
-  static void openAndPrintFile(const char *name);
68
-  static void startFileprint();
69
-  static void stopSDPrint(
70
-    #if SD_RESORT
71
-      const bool re_sort=false
72
-    #endif
73
-  );
74
-  static void report_status();
75
-  static void printingHasFinished();
76
-  static void printFilename();
88
+  static void removeFile(const char * const name);
77
 
89
 
90
+  static inline char* longest_filename() { return longFilename[0] ? longFilename : filename; }
78
   #if ENABLED(LONG_FILENAME_HOST_SUPPORT)
91
   #if ENABLED(LONG_FILENAME_HOST_SUPPORT)
79
-    static void printLongPath(char *path);
92
+    static void printLongPath(char * const path);   // Used by M33
80
   #endif
93
   #endif
81
 
94
 
82
-  static void getfilename(uint16_t nr, const char* const match=nullptr);
95
+  // Working Directory for SD card menu
96
+  static void cdroot();
97
+  static void cd(const char *relpath);
98
+  static int8_t cdup();
83
   static uint16_t countFilesInWorkDir();
99
   static uint16_t countFilesInWorkDir();
100
+  static uint16_t get_num_Files();
84
 
101
 
85
-  static void getAbsFilename(char *t);
102
+  // Select a file
103
+  static void selectFileByIndex(const uint16_t nr);
104
+  static void selectFileByName(const char* const match);
86
 
105
 
87
-  static void ls();
88
-  static void chdir(const char *relpath);
89
-  static int8_t updir();
90
-  static void setroot();
106
+  // Print job
107
+  static void openAndPrintFile(const char *name);   // (working directory)
108
+  static void printingHasFinished();
109
+  static void getAbsFilename(char *dst);
110
+  static void startFileprint();
111
+  static void printFilename();
112
+  static void stopSDPrint(
113
+    #if SD_RESORT
114
+      const bool re_sort=false
115
+    #endif
116
+  );
117
+  static void report_status();
118
+  static inline void pauseSDPrint() { flag.sdprinting = false; }
119
+  static inline bool isPaused() { return isFileOpen() && !flag.sdprinting; }
120
+  static inline bool isPrinting() { return flag.sdprinting; }
121
+  static inline uint8_t percentDone() { return (isFileOpen() && filesize) ? sdpos / ((filesize + 99) / 100) : 0; }
91
 
122
 
123
+  // Helper for open and remove
92
   static const char* diveToFile(SdFile*& curDir, const char * const path, const bool echo=false);
124
   static const char* diveToFile(SdFile*& curDir, const char * const path, const bool echo=false);
93
 
125
 
94
-  static uint16_t get_num_Files();
95
-
96
   #if ENABLED(SDCARD_SORT_ALPHA)
126
   #if ENABLED(SDCARD_SORT_ALPHA)
97
     static void presort();
127
     static void presort();
98
     static void getfilename_sorted(const uint16_t nr);
128
     static void getfilename_sorted(const uint16_t nr);
102
       //FORCE_INLINE static void setSortReverse(bool b) { sort_reverse = b; }
132
       //FORCE_INLINE static void setSortReverse(bool b) { sort_reverse = b; }
103
     #endif
133
     #endif
104
   #else
134
   #else
105
-    FORCE_INLINE static void getfilename_sorted(const uint16_t nr) { getfilename(nr); }
135
+    FORCE_INLINE static void getfilename_sorted(const uint16_t nr) { selectFileByIndex(nr); }
106
   #endif
136
   #endif
107
 
137
 
108
   #if ENABLED(POWER_LOSS_RECOVERY)
138
   #if ENABLED(POWER_LOSS_RECOVERY)
111
     static void removeJobRecoveryFile();
141
     static void removeJobRecoveryFile();
112
   #endif
142
   #endif
113
 
143
 
114
-  static inline void pauseSDPrint() { flag.sdprinting = false; }
115
-  static inline bool isMounted() { return flag.mounted; }
116
   static inline bool isFileOpen() { return isMounted() && file.isOpen(); }
144
   static inline bool isFileOpen() { return isMounted() && file.isOpen(); }
117
-  static inline bool isPaused() { return isFileOpen() && !flag.sdprinting; }
118
-  static inline bool isPrinting() { return flag.sdprinting; }
145
+  static inline uint32_t getIndex() { return sdpos; }
119
   static inline bool eof() { return sdpos >= filesize; }
146
   static inline bool eof() { return sdpos >= filesize; }
120
-  static inline int16_t get() { sdpos = file.curPosition(); return (int16_t)file.read(); }
121
   static inline void setIndex(const uint32_t index) { sdpos = index; file.seekSet(index); }
147
   static inline void setIndex(const uint32_t index) { sdpos = index; file.seekSet(index); }
122
-  static inline uint32_t getIndex() { return sdpos; }
123
-  static inline uint8_t percentDone() { return (isFileOpen() && filesize) ? sdpos / ((filesize + 99) / 100) : 0; }
124
   static inline char* getWorkDirName() { workDir.getDosName(filename); return filename; }
148
   static inline char* getWorkDirName() { workDir.getDosName(filename); return filename; }
149
+  static inline int16_t get() { sdpos = file.curPosition(); return (int16_t)file.read(); }
125
   static inline int16_t read(void* buf, uint16_t nbyte) { return file.isOpen() ? file.read(buf, nbyte) : -1; }
150
   static inline int16_t read(void* buf, uint16_t nbyte) { return file.isOpen() ? file.read(buf, nbyte) : -1; }
126
   static inline int16_t write(void* buf, uint16_t nbyte) { return file.isOpen() ? file.write(buf, nbyte) : -1; }
151
   static inline int16_t write(void* buf, uint16_t nbyte) { return file.isOpen() ? file.write(buf, nbyte) : -1; }
127
 
152
 
139
     }
164
     }
140
   #endif
165
   #endif
141
 
166
 
142
-  static inline char* longest_filename() { return longFilename[0] ? longFilename : filename; }
143
-
144
-public:
145
-  static card_flags_t flag;
146
-  static char filename[FILENAME_LENGTH], longFilename[LONG_FILENAME_LENGTH];
147
-  static int8_t autostart_index;
148
-  static SdFile getroot() { return root; }
149
-
150
-  #if ENABLED(BINARY_FILE_TRANSFER)
151
-    #if NUM_SERIAL > 1
152
-      static int8_t transfer_port_index;
153
-    #else
154
-      static constexpr int8_t transfer_port_index = 0;
155
-    #endif
156
-  #endif
157
-
158
 private:
167
 private:
168
+  //
169
+  // Working directory and parents
170
+  //
159
   static SdFile root, workDir, workDirParents[MAX_DIR_DEPTH];
171
   static SdFile root, workDir, workDirParents[MAX_DIR_DEPTH];
160
   static uint8_t workDirDepth;
172
   static uint8_t workDirDepth;
161
 
173
 
162
-  // Sort files and folders alphabetically.
174
+  //
175
+  // Alphabetical file and folder sorting
176
+  //
163
   #if ENABLED(SDCARD_SORT_ALPHA)
177
   #if ENABLED(SDCARD_SORT_ALPHA)
164
     static uint16_t sort_count;   // Count of sorted items in the current directory
178
     static uint16_t sort_count;   // Count of sorted items in the current directory
165
     #if ENABLED(SDSORT_GCODE)
179
     #if ENABLED(SDSORT_GCODE)
188
 
202
 
189
       // If using dynamic ram for names, allocate on the heap.
203
       // If using dynamic ram for names, allocate on the heap.
190
       #if ENABLED(SDSORT_CACHE_NAMES)
204
       #if ENABLED(SDSORT_CACHE_NAMES)
205
+        static uint16_t nrFiles; // Cache the total count
191
         #if ENABLED(SDSORT_DYNAMIC_RAM)
206
         #if ENABLED(SDSORT_DYNAMIC_RAM)
192
           static char **sortshort, **sortnames;
207
           static char **sortshort, **sortnames;
193
         #else
208
         #else
216
   static SdVolume volume;
231
   static SdVolume volume;
217
   static SdFile file;
232
   static SdFile file;
218
 
233
 
234
+  static uint32_t filesize, sdpos;
235
+
236
+  //
237
+  // Procedure calls to other files
238
+  //
219
   #ifndef SD_PROCEDURE_DEPTH
239
   #ifndef SD_PROCEDURE_DEPTH
220
     #define SD_PROCEDURE_DEPTH 1
240
     #define SD_PROCEDURE_DEPTH 1
221
   #endif
241
   #endif
222
-
223
   static uint8_t file_subcall_ctr;
242
   static uint8_t file_subcall_ctr;
224
   static uint32_t filespos[SD_PROCEDURE_DEPTH];
243
   static uint32_t filespos[SD_PROCEDURE_DEPTH];
225
   static char proc_filenames[SD_PROCEDURE_DEPTH][MAXPATHNAMELENGTH];
244
   static char proc_filenames[SD_PROCEDURE_DEPTH][MAXPATHNAMELENGTH];
226
 
245
 
227
-  static uint32_t filesize, sdpos;
228
-
229
-  static LsAction lsAction; //stored for recursion.
230
-  static uint16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory.
231
-  static char *diveDirName;
232
-  static void lsDive(const char *prepend, SdFile parent, const char * const match=nullptr);
233
-
234
-  #if ENABLED(SDCARD_SORT_ALPHA)
235
-    static void flush_presort();
236
-  #endif
237
-
246
+  //
247
+  // SD Auto Reporting
248
+  //
238
   #if ENABLED(AUTO_REPORT_SD_STATUS)
249
   #if ENABLED(AUTO_REPORT_SD_STATUS)
239
     static uint8_t auto_report_sd_interval;
250
     static uint8_t auto_report_sd_interval;
240
     static millis_t next_sd_report_ms;
251
     static millis_t next_sd_report_ms;
242
       static int8_t auto_report_port;
253
       static int8_t auto_report_port;
243
     #endif
254
     #endif
244
   #endif
255
   #endif
256
+
257
+  //
258
+  // Directory items
259
+  //
260
+  static bool is_dir_or_gcode(const dir_t &p);
261
+  static int countItems(SdFile dir);
262
+  static void selectByIndex(SdFile dir, const uint8_t index);
263
+  static void selectByName(SdFile dir, const char * const match);
264
+  static void printListing(SdFile parent, const char * const prepend=nullptr);
265
+
266
+  #if ENABLED(SDCARD_SORT_ALPHA)
267
+    static void flush_presort();
268
+  #endif
245
 };
269
 };
246
 
270
 
247
 #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
271
 #if ENABLED(USB_FLASH_DRIVE_SUPPORT)

Loading…
Cancel
Save