diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index 689330934..f391159b2 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -3963,6 +3963,8 @@ static void extended_capabilities_report()
#endif //FANCHECK and TACH_0 or TACH_1
// AUTOREPORT_POSITION (M114)
cap_line(PSTR("AUTOREPORT_POSITION"), ENABLED(AUTO_REPORT));
+ // EXTENDED_M20 (support for L and T parameters)
+ cap_line(PSTR("EXTENDED_M20"), 1);
//@todo Update RepRap cap
}
#endif //EXTENDED_CAPABILITIES_REPORT
@@ -5739,16 +5741,17 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
### M20 - SD Card file list M20: List SD card
#### Usage
- M20 [ L ]
+ M20 [ L | T ]
#### Parameters
- - `L` - Reports ling filenames instead of just short filenames. Requires host software parsing.
+ - `T` - Report timestamps as well. The value is one uint32_t encoded as hex. Requires host software parsing (Cap:EXTENDED_M20).
+ - `L` - Reports long filenames instead of just short filenames. Requires host software parsing (Cap:EXTENDED_M20).
*/
case 20:
KEEPALIVE_STATE(NOT_BUSY); // do not send busy messages during listing. Inhibits the output of manage_heater()
SERIAL_PROTOCOLLNRPGM(_N("Begin file list"));////MSG_BEGIN_FILE_LIST
- card.ls(code_seen('L'));
+ card.ls(CardReader::ls_param(code_seen('L'), code_seen('T')));
SERIAL_PROTOCOLLNRPGM(_N("End file list"));////MSG_END_FILE_LIST
- break;
+ break;
/*!
### M21 - Init SD card M21: Initialize SD card
diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp
index 673e88c17..a86c49e16 100644
--- a/Firmware/cardreader.cpp
+++ b/Firmware/cardreader.cpp
@@ -61,10 +61,9 @@ char *createFilename(char *buffer,const dir_t &p) //buffer>12characters
+* LS_Count - Add +1 to nrFiles for every file within the parent
+* LS_GetFilename - Get the filename of the file indexed by nrFiles
+* LS_SerialPrint - Print the full path and size of each file to serial output
-+* LS_SerialPrint_LFN - Print the full path, long filename and size of each file to serial output
+*/
-void CardReader::lsDive(const char *prepend, SdFile parent, const char * const match/*=NULL*/) {
+void CardReader::lsDive(const char *prepend, SdFile parent, const char * const match/*=NULL*/, LsAction lsAction, ls_param lsParams) {
static uint8_t recursionCnt = 0;
// RAII incrementer for the recursionCnt
class _incrementer
@@ -80,8 +79,12 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
for (position = parent.curPosition(); parent.readDir(p, longFilename) > 0; position = parent.curPosition()) {
if (recursionCnt > MAX_DIR_DEPTH)
return;
- else if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) { // If the entry is a directory and the action is LS_SerialPrint
-
+ uint8_t pn0 = p.name[0];
+ if (pn0 == DIR_NAME_FREE) break;
+ if (pn0 == DIR_NAME_DELETED || pn0 == '.') continue;
+ if (longFilename[0] == '.') continue;
+ if (!DIR_IS_FILE_OR_SUBDIR(&p) || (p.attributes & DIR_ATT_HIDDEN)) continue;
+ if (DIR_IS_SUBDIR(&p) && lsAction == LS_SerialPrint) { // If the entry is a directory and the action is LS_SerialPrint
// Get the short name for the item, which we know is a folder
char lfilename[FILENAME_LENGTH];
createFilename(lfilename, p);
@@ -99,29 +102,22 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
// Get a new directory object using the full path
// and dive recursively into it.
- if (lsAction == LS_SerialPrint_LFN)
+ if (lsParams.LFN)
printf_P(PSTR("DIR_ENTER: %s \"%s\"\n"), path, longFilename[0] ? longFilename : lfilename);
SdFile dir;
if (!dir.open(parent, lfilename, O_READ)) {
- if (lsAction == LS_SerialPrint || lsAction == LS_SerialPrint_LFN) {
- //SERIAL_ECHO_START();
- //SERIAL_ECHOPGM(_i("Cannot open subdir"));////MSG_SD_CANT_OPEN_SUBDIR
- //SERIAL_ECHOLN(lfilename);
- }
+ //SERIAL_ECHO_START();
+ //SERIAL_ECHOPGM(_i("Cannot open subdir"));////MSG_SD_CANT_OPEN_SUBDIR
+ //SERIAL_ECHOLN(lfilename);
}
- lsDive(path, dir);
+ lsDive(path, dir, NULL, lsAction, lsParams);
// close() is done automatically by destructor of SdFile
- if (lsAction == LS_SerialPrint_LFN)
+ if (lsParams.LFN)
puts_P(PSTR("DIR_EXIT"));
}
else {
- uint8_t pn0 = p.name[0];
- if (pn0 == DIR_NAME_FREE) break;
- if (pn0 == DIR_NAME_DELETED || pn0 == '.') continue;
- if (longFilename[0] == '.') continue;
- if (!DIR_IS_FILE_OR_SUBDIR(&p) || (p.attributes & DIR_ATT_HIDDEN)) continue;
filenameIsDir = DIR_IS_SUBDIR(&p);
if (!filenameIsDir && (p.name[8] != 'G' || p.name[9] == '~')) continue;
switch (lsAction) {
@@ -129,17 +125,29 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
nrFiles++;
break;
- case LS_SerialPrint_LFN:
case LS_SerialPrint:
createFilename(filename, p);
SERIAL_PROTOCOL(prepend);
SERIAL_PROTOCOL(filename);
+
MYSERIAL.write(' ');
+ SERIAL_PROTOCOL(p.fileSize);
- if (lsAction == LS_SerialPrint_LFN)
- printf_P(PSTR("\"%s\" "), LONGEST_FILENAME);
+ if (lsParams.timestamp)
+ {
+ crmodDate = p.lastWriteDate;
+ crmodTime = p.lastWriteTime;
+ if( crmodDate < p.creationDate || ( crmodDate == p.creationDate && crmodTime < p.creationTime ) ){
+ crmodDate = p.creationDate;
+ crmodTime = p.creationTime;
+ }
+ printf_P(PSTR(" %#lx"), ((uint32_t)crmodDate << 16) | crmodTime);
+ }
- SERIAL_PROTOCOLLN(p.fileSize);
+ if (lsParams.LFN)
+ printf_P(PSTR(" \"%s\""), LONGEST_FILENAME);
+
+ SERIAL_PROTOCOLLN();
manage_heater();
break;
@@ -181,14 +189,10 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
} // while readDir
}
-void CardReader::ls(bool printLFN)
+void CardReader::ls(ls_param params)
{
- lsAction = printLFN ? LS_SerialPrint_LFN : LS_SerialPrint;
- //if(lsAction==LS_Count)
- //nrFiles=0;
-
root.rewind();
- lsDive("",root);
+ lsDive("",root, NULL, LS_SerialPrint, params);
}
@@ -695,38 +699,34 @@ void CardReader::closefile(bool store_location)
void CardReader::getfilename(uint16_t nr, const char * const match/*=NULL*/)
{
curDir=&workDir;
- lsAction=LS_GetFilename;
nrFiles=nr;
curDir->rewind();
- lsDive("",*curDir,match);
+ lsDive("",*curDir,match, LS_GetFilename);
}
void CardReader::getfilename_simple(uint32_t position, const char * const match/*=NULL*/)
{
curDir = &workDir;
- lsAction = LS_GetFilename;
nrFiles = 0;
curDir->seekSet(position);
- lsDive("", *curDir, match);
+ lsDive("", *curDir, match, LS_GetFilename);
}
void CardReader::getfilename_next(uint32_t position, const char * const match/*=NULL*/)
{
curDir = &workDir;
- lsAction = LS_GetFilename;
nrFiles = 1;
curDir->seekSet(position);
- lsDive("", *curDir, match);
+ lsDive("", *curDir, match, LS_GetFilename);
}
uint16_t CardReader::getnrfilenames()
{
curDir=&workDir;
- lsAction=LS_Count;
nrFiles=0;
curDir->rewind();
- lsDive("",*curDir);
+ lsDive("",*curDir, NULL, LS_Count);
//SERIAL_ECHOLN(nrFiles);
return nrFiles;
}
diff --git a/Firmware/cardreader.h b/Firmware/cardreader.h
index 47343e238..c6e55428d 100644
--- a/Firmware/cardreader.h
+++ b/Firmware/cardreader.h
@@ -8,12 +8,25 @@
#define MAX_DIR_DEPTH 6
#include "SdFile.h"
-enum LsAction {LS_SerialPrint,LS_SerialPrint_LFN,LS_Count,LS_GetFilename};
class CardReader
{
public:
CardReader();
+ enum LsAction : uint8_t
+ {
+ LS_SerialPrint,
+ LS_Count,
+ LS_GetFilename,
+ };
+ struct ls_param
+ {
+ bool LFN : 1;
+ bool timestamp : 1;
+ inline ls_param():LFN(0), timestamp(0) { }
+ inline ls_param(bool LFN, bool timestamp):LFN(LFN), timestamp(timestamp) { }
+ } __attribute__((packed));
+
void initsd();
void write_command(char *buf);
void write_command_no_newline(char *buf);
@@ -43,7 +56,7 @@ public:
uint16_t getWorkDirDepth();
- void ls(bool printLFN);
+ void ls(ls_param params);
bool chdir(const char * relpath, bool doPresort);
void updir();
void setroot(bool doPresort);
@@ -122,12 +135,11 @@ private:
bool autostart_stilltocheck; //the sd start is delayed, because otherwise the serial cannot answer fast enought to make contact with the hostsoftware.
- LsAction lsAction; //stored for recursion.
int16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory.
char* diveDirName;
bool diveSubfolder (const char *&fileName);
- void lsDive(const char *prepend, SdFile parent, const char * const match=NULL);
+ void lsDive(const char *prepend, SdFile parent, const char * const match=NULL, LsAction lsAction = LS_GetFilename, ls_param lsParams = ls_param());
#ifdef SDCARD_SORT_ALPHA
void flush_presort();
#endif