aboutsummaryrefslogtreecommitdiff
path: root/Marlin/src/sd/cardreader.h
blob: 0a89bbba789b844d9a9a26cdce0778d8c5a12108 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
/**
 * Marlin 3D Printer Firmware
 * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
 *
 * Based on Sprinter and grbl.
 * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */
#pragma once

#include "../inc/MarlinConfig.h"

#define IFSD(A,B) TERN(SDSUPPORT,A,B)

#if ENABLED(SDSUPPORT)

extern const char M23_STR[], M24_STR[];

#if BOTH(SDCARD_SORT_ALPHA, SDSORT_DYNAMIC_RAM)
  #define SD_RESORT 1
#endif

#if ENABLED(SDCARD_RATHERRECENTFIRST) && DISABLED(SDCARD_SORT_ALPHA)
  #define SD_ORDER(N,C) ((C) - 1 - (N))
#else
  #define SD_ORDER(N,C) N
#endif

#define MAX_DIR_DEPTH     10       // Maximum folder depth
#define MAXDIRNAMELENGTH   8       // DOS folder name size
#define MAXPATHNAMELENGTH  (1 + (MAXDIRNAMELENGTH + 1) * (MAX_DIR_DEPTH) + 1 + FILENAME_LENGTH) // "/" + N * ("ADIRNAME/") + "filename.ext"

#include "SdFile.h"

typedef struct {
  bool saving:1,
       logging:1,
       sdprinting:1,
       mounted:1,
       filenameIsDir:1,
       workDirIsRoot:1,
       abort_sd_printing:1
       #if ENABLED(BINARY_FILE_TRANSFER)
         , binary_mode:1
       #endif
    ;
} card_flags_t;

#if ENABLED(AUTO_REPORT_SD_STATUS)
  #include "../libs/autoreport.h"
#endif

class CardReader {
public:
  static card_flags_t flag;                         // Flags (above)
  static char filename[FILENAME_LENGTH],            // DOS 8.3 filename of the selected item
              longFilename[LONG_FILENAME_LENGTH];   // Long name of the selected item

  // Fast! binary file transfer
  #if ENABLED(BINARY_FILE_TRANSFER)
    #if HAS_MULTI_SERIAL
      static int8_t transfer_port_index;
    #else
      static constexpr int8_t transfer_port_index = 0;
    #endif
  #endif

  // // // Methods // // //

  CardReader();

  static SdFile getroot() { return root; }

  static void mount();
  static void release();
  static inline bool isMounted() { return flag.mounted; }
  static void ls();

  // Handle media insert/remove
  static void manage_media();

  // SD Card Logging
  static void openLogFile(char * const path);
  static void write_command(char * const buf);

  #if DISABLED(NO_SD_AUTOSTART)     // Auto-Start auto#.g file handling
    static uint8_t autofile_index;  // Next auto#.g index to run, plus one. Ignored by autofile_check when zero.
    static void autofile_begin();   // Begin check. Called automatically after boot-up.
    static bool autofile_check();   // Check for the next auto-start file and run it.
    static inline void autofile_cancel() { autofile_index = 0; }
  #endif

  // Basic file ops
  static void openFileRead(char * const path, const uint8_t subcall=0);
  static void openFileWrite(char * const path);
  static void closefile(const bool store_location=false);
  static bool fileExists(const char * const name);
  static void removeFile(const char * const name);

  static inline char* longest_filename() { return longFilename[0] ? longFilename : filename; }
  #if ENABLED(LONG_FILENAME_HOST_SUPPORT)
    static void printLongPath(char * const path);   // Used by M33
  #endif

  // Working Directory for SD card menu
  static void cdroot();
  static void cd(const char *relpath);
  static int8_t cdup();
  static uint16_t countFilesInWorkDir();
  static uint16_t get_num_Files();

  // Select a file
  static void selectFileByIndex(const uint16_t nr);
  static void selectFileByName(const char* const match);

  // Print job
  static void openAndPrintFile(const char *name);   // (working directory)
  static void fileHasFinished();
  static void getAbsFilename(char *dst);
  static void printFilename();
  static void startFileprint();
  static void endFilePrint(TERN_(SD_RESORT, const bool re_sort=false));
  static void report_status();
  static inline void pauseSDPrint() { flag.sdprinting = false; }
  static inline bool isPaused() { return isFileOpen() && !flag.sdprinting; }
  static inline bool isPrinting() { return flag.sdprinting; }
  #if HAS_PRINT_PROGRESS_PERMYRIAD
    static inline uint16_t permyriadDone() { return (isFileOpen() && filesize) ? sdpos / ((filesize + 9999) / 10000) : 0; }
  #endif
  static inline uint8_t percentDone() { return (isFileOpen() && filesize) ? sdpos / ((filesize + 99) / 100) : 0; }

  // Helper for open and remove
  static const char* diveToFile(const bool update_cwd, SdFile*& curDir, const char * const path, const bool echo=false);

  #if ENABLED(SDCARD_SORT_ALPHA)
    static void presort();
    static void getfilename_sorted(const uint16_t nr);
    #if ENABLED(SDSORT_GCODE)
      FORCE_INLINE static void setSortOn(bool b) { sort_alpha = b; presort(); }
      FORCE_INLINE static void setSortFolders(int i) { sort_folders = i; presort(); }
      //FORCE_INLINE static void setSortReverse(bool b) { sort_reverse = b; }
    #endif
  #else
    FORCE_INLINE static void getfilename_sorted(const uint16_t nr) { selectFileByIndex(nr); }
  #endif

  #if ENABLED(POWER_LOSS_RECOVERY)
    static bool jobRecoverFileExists();
    static void openJobRecoveryFile(const bool read);
    static void removeJobRecoveryFile();
  #endif

  static inline bool isFileOpen() { return isMounted() && file.isOpen(); }
  static inline uint32_t getIndex() { return sdpos; }
  static inline uint32_t getFileSize() { return filesize; }
  static inline bool eof() { return sdpos >= filesize; }
  static inline void setIndex(const uint32_t index) { file.seekSet((sdpos = index)); }
  static inline char* getWorkDirName() { workDir.getDosName(filename); return filename; }
  static inline int16_t get() { int16_t out = (int16_t)file.read(); sdpos = file.curPosition(); return out; }
  static inline int16_t read(void* buf, uint16_t nbyte) { return file.isOpen() ? file.read(buf, nbyte) : -1; }
  static inline int16_t write(void* buf, uint16_t nbyte) { return file.isOpen() ? file.write(buf, nbyte) : -1; }

  static Sd2Card& getSd2Card() { return sd2card; }

  #if ENABLED(AUTO_REPORT_SD_STATUS)
    //
    // SD Auto Reporting
    //
    struct AutoReportSD { static void report() { report_status(); } };
    static AutoReporter<AutoReportSD> auto_reporter;
  #endif

private:
  //
  // Working directory and parents
  //
  static SdFile root, workDir, workDirParents[MAX_DIR_DEPTH];
  static uint8_t workDirDepth;

  //
  // Alphabetical file and folder sorting
  //
  #if ENABLED(SDCARD_SORT_ALPHA)
    static uint16_t sort_count;   // Count of sorted items in the current directory
    #if ENABLED(SDSORT_GCODE)
      static bool sort_alpha;     // Flag to enable / disable the feature
      static int sort_folders;    // Folder sorting before/none/after
      //static bool sort_reverse; // Flag to enable / disable reverse sorting
    #endif

    // By default the sort index is static
    #if ENABLED(SDSORT_DYNAMIC_RAM)
      static uint8_t *sort_order;
    #else
      static uint8_t sort_order[SDSORT_LIMIT];
    #endif

    #if BOTH(SDSORT_USES_RAM, SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM)
      #define SORTED_LONGNAME_MAXLEN (SDSORT_CACHE_VFATS) * (FILENAME_LENGTH)
      #define SORTED_LONGNAME_STORAGE (SORTED_LONGNAME_MAXLEN + 1)
    #else
      #define SORTED_LONGNAME_MAXLEN LONG_FILENAME_LENGTH
      #define SORTED_LONGNAME_STORAGE SORTED_LONGNAME_MAXLEN
    #endif

    // Cache filenames to speed up SD menus.
    #if ENABLED(SDSORT_USES_RAM)

      // If using dynamic ram for names, allocate on the heap.
      #if ENABLED(SDSORT_CACHE_NAMES)
        static uint16_t nrFiles; // Cache the total count
        #if ENABLED(SDSORT_DYNAMIC_RAM)
          static char **sortshort, **sortnames;
        #else
          static char sortshort[SDSORT_LIMIT][FILENAME_LENGTH];
        #endif
      #endif

      #if (ENABLED(SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM)) || NONE(SDSORT_CACHE_NAMES, SDSORT_USES_STACK)
        static char sortnames[SDSORT_LIMIT][SORTED_LONGNAME_STORAGE];
      #endif

      // Folder sorting uses an isDir array when caching items.
      #if HAS_FOLDER_SORTING
        #if ENABLED(SDSORT_DYNAMIC_RAM)
          static uint8_t *isDir;
        #elif ENABLED(SDSORT_CACHE_NAMES) || DISABLED(SDSORT_USES_STACK)
          static uint8_t isDir[(SDSORT_LIMIT+7)>>3];
        #endif
      #endif

    #endif // SDSORT_USES_RAM

  #endif // SDCARD_SORT_ALPHA

  static Sd2Card sd2card;
  static SdVolume volume;
  static SdFile file;

  static uint32_t filesize, // Total size of the current file, in bytes
                  sdpos;    // Index most recently read (one behind file.getPos)

  //
  // Procedure calls to other files
  //
  #if HAS_MEDIA_SUBCALLS
    static uint8_t file_subcall_ctr;
    static uint32_t filespos[SD_PROCEDURE_DEPTH];
    static char proc_filenames[SD_PROCEDURE_DEPTH][MAXPATHNAMELENGTH];
  #endif

  //
  // Directory items
  //
  static bool is_dir_or_gcode(const dir_t &p);
  static int countItems(SdFile dir);
  static void selectByIndex(SdFile dir, const uint8_t index);
  static void selectByName(SdFile dir, const char * const match);
  static void printListing(SdFile parent, const char * const prepend=nullptr);

  #if ENABLED(SDCARD_SORT_ALPHA)
    static void flush_presort();
  #endif
};

#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
  #define IS_SD_INSERTED() Sd2Card::isInserted()
#elif PIN_EXISTS(SD_DETECT)
  #define IS_SD_INSERTED() (READ(SD_DETECT_PIN) == SD_DETECT_STATE)
#else
  // No card detect line? Assume the card is inserted.
  #define IS_SD_INSERTED() true
#endif

#define IS_SD_PRINTING()  card.flag.sdprinting
#define IS_SD_PAUSED()    card.isPaused()
#define IS_SD_FILE_OPEN() card.isFileOpen()

extern CardReader card;

#else // !SDSUPPORT

#define IS_SD_PRINTING()  false
#define IS_SD_PAUSED()    false
#define IS_SD_FILE_OPEN() false

#define LONG_FILENAME_LENGTH 0

#endif // !SDSUPPORT