diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index f48a41921..2de41a07a 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -1810,5 +1810,3 @@ void setPwmFrequency(uint8_t pin, int val) } } #endif - - diff --git a/Marlin/Sd2Card.cpp b/Marlin/Sd2Card.cpp index 884fa4553..eb38df6b7 100644 --- a/Marlin/Sd2Card.cpp +++ b/Marlin/Sd2Card.cpp @@ -369,7 +369,6 @@ bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { * * \param[in] blockNumber Logical block to be read. * \param[out] dst Pointer to the location that will receive the data. - * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ @@ -639,5 +638,4 @@ bool Sd2Card::writeStop() { return false; } - -#endif \ No newline at end of file +#endif diff --git a/Marlin/SdBaseFile.cpp b/Marlin/SdBaseFile.cpp index b84efc8ea..c4d538073 100644 --- a/Marlin/SdBaseFile.cpp +++ b/Marlin/SdBaseFile.cpp @@ -867,7 +867,7 @@ bool SdBaseFile::openParent(SdBaseFile* dir) { } // search for parent in '../..' do { - if (file.readDir(&entry) != 32) goto fail; + if (file.readDir(&entry, NULL) != 32) goto fail; c = entry.firstClusterLow; c |= (uint32_t)entry.firstClusterHigh << 16; } while (c != cluster); @@ -1108,10 +1108,16 @@ int16_t SdBaseFile::read(void* buf, uint16_t nbyte) { * readDir() called before a directory has been opened, this is not * a directory file or an I/O error occurred. */ -int8_t SdBaseFile::readDir(dir_t* dir) { +int8_t SdBaseFile::readDir(dir_t* dir, char* longFilename) { int16_t n; // if not a directory file or miss-positioned return an error if (!isDir() || (0X1F & curPosition_)) return -1; + + //If we have a longFilename buffer, mark it as invalid. If we find a long filename it will be filled automaticly. + if (longFilename != NULL) + { + longFilename[0] = '\0'; + } while (1) { n = read(dir, sizeof(dir_t)); @@ -1120,6 +1126,34 @@ int8_t SdBaseFile::readDir(dir_t* dir) { if (dir->name[0] == DIR_NAME_FREE) return 0; // skip empty entries and entry for . and .. if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue; + //Fill the long filename if we have a long filename entry, + // long filename entries are stored before the actual filename. + if (DIR_IS_LONG_NAME(dir) && longFilename != NULL) + { + vfat_t *VFAT = (vfat_t*)dir; + //Sanity check the VFAT entry. The first cluster is always set to zero. And th esequence number should be higher then 0 + if (VFAT->firstClusterLow == 0 && (VFAT->sequenceNumber & 0x1F) > 0 && (VFAT->sequenceNumber & 0x1F) <= MAX_VFAT_ENTRIES) + { + //TODO: Store the filename checksum to verify if a none-long filename aware system modified the file table. + n = ((VFAT->sequenceNumber & 0x1F) - 1) * 13; + longFilename[n+0] = VFAT->name1[0]; + longFilename[n+1] = VFAT->name1[1]; + longFilename[n+2] = VFAT->name1[2]; + longFilename[n+3] = VFAT->name1[3]; + longFilename[n+4] = VFAT->name1[4]; + longFilename[n+5] = VFAT->name2[0]; + longFilename[n+6] = VFAT->name2[1]; + longFilename[n+7] = VFAT->name2[2]; + longFilename[n+8] = VFAT->name2[3]; + longFilename[n+9] = VFAT->name2[4]; + longFilename[n+10] = VFAT->name2[5]; + longFilename[n+11] = VFAT->name3[0]; + longFilename[n+12] = VFAT->name3[1]; + //If this VFAT entry is the last one, add a NUL terminator at the end of the string + if (VFAT->sequenceNumber & 0x40) + longFilename[n+13] = '\0'; + } + } // return if normal file or subdirectory if (DIR_IS_FILE_OR_SUBDIR(dir)) return n; } @@ -1788,4 +1822,4 @@ void (*SdBaseFile::oldDateTime_)(uint16_t& date, uint16_t& time) = 0; // NOLINT #endif // ALLOW_DEPRECATED_FUNCTIONS -#endif +#endif diff --git a/Marlin/SdBaseFile.h b/Marlin/SdBaseFile.h index 1bf75f6f2..dea299a64 100644 --- a/Marlin/SdBaseFile.h +++ b/Marlin/SdBaseFile.h @@ -283,7 +283,7 @@ class SdBaseFile { bool printName(); int16_t read(); int16_t read(void* buf, uint16_t nbyte); - int8_t readDir(dir_t* dir); + int8_t readDir(dir_t* dir, char* longFilename); static bool remove(SdBaseFile* dirFile, const char* path); bool remove(); /** Set the file's current position to zero. */ @@ -455,7 +455,7 @@ class SdBaseFile { * \param[out] dir The dir_t struct that will receive the data. * \return bytes read for success zero for eof or -1 for failure. */ - int8_t readDir(dir_t& dir) {return readDir(&dir);} // NOLINT + int8_t readDir(dir_t& dir, char* longFilename) {return readDir(&dir, longFilename);} // NOLINT /** \deprecated Use: * static uint8_t remove(SdBaseFile* dirFile, const char* path); * \param[in] dirFile The directory that contains the file. @@ -480,4 +480,4 @@ class SdBaseFile { }; #endif // SdBaseFile_h -#endif \ No newline at end of file +#endif diff --git a/Marlin/SdFatConfig.h b/Marlin/SdFatConfig.h index 2a78c2a85..710b1f792 100644 --- a/Marlin/SdFatConfig.h +++ b/Marlin/SdFatConfig.h @@ -108,7 +108,14 @@ uint8_t const SOFT_SPI_SCK_PIN = 13; * a pure virtual function is called. */ #define USE_CXA_PURE_VIRTUAL 1 +/** + * Defines for long (vfat) filenames + */ +/** Number of VFAT entries used. Every entry has 13 UTF-16 characters */ +#define MAX_VFAT_ENTRIES (2) +/** Total size of the buffer used to store the long filenames */ +#define LONG_FILENAME_LENGTH (13*MAX_VFAT_ENTRIES+1) #endif // SdFatConfig_h -#endif \ No newline at end of file +#endif diff --git a/Marlin/SdFatStructs.h b/Marlin/SdFatStructs.h index 7ad88d67f..386721616 100644 --- a/Marlin/SdFatStructs.h +++ b/Marlin/SdFatStructs.h @@ -22,6 +22,8 @@ #ifndef SdFatStructs_h #define SdFatStructs_h + +#define PACKED __attribute__((__packed__)) /** * \file * \brief FAT file structures @@ -95,7 +97,7 @@ struct partitionTable { uint32_t firstSector; /** Length of the partition, in blocks. */ uint32_t totalSectors; -}; +} PACKED; /** Type name for partitionTable */ typedef struct partitionTable part_t; //------------------------------------------------------------------------------ @@ -119,7 +121,7 @@ struct masterBootRecord { uint8_t mbrSig0; /** Second MBR signature byte. Must be 0XAA */ uint8_t mbrSig1; -}; +} PACKED; /** Type name for masterBootRecord */ typedef struct masterBootRecord mbr_t; //------------------------------------------------------------------------------ @@ -247,7 +249,7 @@ struct fat_boot { uint8_t bootSectorSig0; /** must be 0XAA */ uint8_t bootSectorSig1; -}; +} PACKED; /** Type name for FAT Boot Sector */ typedef struct fat_boot fat_boot_t; //------------------------------------------------------------------------------ @@ -401,7 +403,7 @@ struct fat32_boot { uint8_t bootSectorSig0; /** must be 0XAA */ uint8_t bootSectorSig1; -}; +} PACKED; /** Type name for FAT32 Boot Sector */ typedef struct fat32_boot fat32_boot_t; //------------------------------------------------------------------------------ @@ -441,7 +443,7 @@ struct fat32_fsinfo { uint8_t reserved2[12]; /** must be 0X00, 0X00, 0X55, 0XAA */ uint8_t tailSignature[4]; -}; +} PACKED; /** Type name for FAT32 FSINFO Sector */ typedef struct fat32_fsinfo fat32_fsinfo_t; //------------------------------------------------------------------------------ @@ -539,12 +541,46 @@ struct directoryEntry { uint16_t firstClusterLow; /** 32-bit unsigned holding this file's size in bytes. */ uint32_t fileSize; -}; +} PACKED; +/** + * \struct directoryVFATEntry + * \brief VFAT long filename directory entry + * + * directoryVFATEntries are found in the same list as normal directoryEntry. + * But have the attribute field set to DIR_ATT_LONG_NAME. + * + * Long filenames are saved in multiple directoryVFATEntries. + * Each entry containing 13 UTF-16 characters. + */ +struct directoryVFATEntry { + /** + * Sequence number. Consists of 2 parts: + * bit 6: indicates first long filename block for the next file + * bit 0-4: the position of this long filename block (first block is 1) + */ + uint8_t sequenceNumber; + /** First set of UTF-16 characters */ + uint16_t name1[5];//UTF-16 + /** attributes (at the same location as in directoryEntry), always 0x0F */ + uint8_t attributes; + /** Reserved for use by Windows NT. Always 0. */ + uint8_t reservedNT; + /** Checksum of the short 8.3 filename, can be used to checked if the file system as modified by a not-long-filename aware implementation. */ + uint8_t checksum; + /** Second set of UTF-16 characters */ + uint16_t name2[6];//UTF-16 + /** firstClusterLow is always zero for longFilenames */ + uint16_t firstClusterLow; + /** Third set of UTF-16 characters */ + uint16_t name3[2];//UTF-16 +} PACKED; //------------------------------------------------------------------------------ // Definitions for directory entries // /** Type name for directoryEntry */ typedef struct directoryEntry dir_t; +/** Type name for directoryVFATEntry */ +typedef struct directoryVFATEntry vfat_t; /** escape for name[0] = 0XE5 */ uint8_t const DIR_NAME_0XE5 = 0X05; /** name[0] value for entry that is free after being "deleted" */ @@ -607,4 +643,4 @@ static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) { #endif // SdFatStructs_h -#endif \ No newline at end of file +#endif diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index 222632f55..47a3fd050 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -51,7 +51,7 @@ void CardReader::lsDive(const char *prepend,SdFile parent) dir_t p; uint8_t cnt=0; - while (parent.readDir(p) > 0) + while (parent.readDir(p, longFilename) > 0) { if( DIR_IS_SUBDIR(&p) && lsAction!=LS_Count && lsAction!=LS_GetFilename) // hence LS_SerialPrint { @@ -429,16 +429,16 @@ void CardReader::checkautostart(bool force) char autoname[30]; sprintf(autoname,"auto%i.g",lastnr); - for(int8_t i=0;i<(int)strlen(autoname);i++) + for(int8_t i=0;i<(int8_t)strlen(autoname);i++) autoname[i]=tolower(autoname[i]); dir_t p; root.rewind(); bool found=false; - while (root.readDir(p) > 0) + while (root.readDir(p, NULL) > 0) { - for(int8_t i=0;i<(int)strlen((char*)p.name);i++) + for(int8_t i=0;i<(int8_t)strlen((char*)p.name);i++) p.name[i]=tolower(p.name[i]); //Serial.print((char*)p.name); //Serial.print(" "); diff --git a/Marlin/cardreader.h b/Marlin/cardreader.h index 964bbe766..e5c8443f5 100644 --- a/Marlin/cardreader.h +++ b/Marlin/cardreader.h @@ -45,7 +45,8 @@ public: bool saving; bool sdprinting ; bool cardOK ; - char filename[12]; + char filename[13]; + char longFilename[LONG_FILENAME_LENGTH]; bool filenameIsDir; int lastnr; //last number of the autostart; private: @@ -72,4 +73,4 @@ private: #define IS_SD_PRINTING (false) #endif //SDSUPPORT -#endif +#endif diff --git a/Marlin/ultralcd.pde b/Marlin/ultralcd.pde index eee89237d..5bea7f39e 100644 --- a/Marlin/ultralcd.pde +++ b/Marlin/ultralcd.pde @@ -2304,7 +2304,15 @@ void MainMenu::showSD() //Serial.print("Filenr:");Serial.println(i-2); lcd.setCursor(0,line);lcdprintPGM(" "); if(card.filenameIsDir) lcd.print("\005"); - lcd.print(card.filename); + if (card.longFilename[0]) + { + card.longFilename[LCD_WIDTH-1] = '\0'; + lcd.print(card.longFilename); + } + else + { + lcd.print(card.filename); + } } if((activeline==line) && CLICKED) { @@ -2329,7 +2337,15 @@ void MainMenu::showSD() enquecommand("M24"); beep(); status=Main_Status; - lcd_status(card.filename); + if (card.longFilename[0]) + { + card.longFilename[LCD_WIDTH-1] = '\0'; + lcd_status(card.longFilename); + } + else + { + lcd_status(card.filename); + } } } }