From 801f99edadbf37966f231a8ae4b06fd93ff58cb1 Mon Sep 17 00:00:00 2001 From: "Leandro A. F. Pereira" Date: Sat, 30 May 2020 21:59:29 -0700 Subject: [PATCH] SDCARD_READONLY (#17884) --- Marlin/Configuration_adv.h | 2 ++ Marlin/src/inc/SanityCheck.h | 14 ++++++++++ Marlin/src/sd/Sd2Card.cpp | 21 +++++++++------ Marlin/src/sd/SdBaseFile.cpp | 40 ++++++++++++++++++++++++--- Marlin/src/sd/SdVolume.cpp | 26 +++++++++++------- Marlin/src/sd/cardreader.cpp | 42 +++++++++++++++++------------ buildroot/share/tests/LPC1768-tests | 3 +-- 7 files changed, 108 insertions(+), 40 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 22755f8122..ec6cb27ec4 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1084,6 +1084,8 @@ // Enable this option and set to HIGH if your SD cards are incorrectly detected. //#define SD_DETECT_STATE HIGH + //#define SDCARD_READONLY // Read-only SD card (to save over 2K of flash) + #define SD_PROCEDURE_DEPTH 1 // Increase if you need more nested M32 calls #define SD_FINISHED_STEPPERRELEASE true // Disable steppers when SD Print is finished diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index da29c0ecf0..ab3b6b8a11 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -2062,6 +2062,20 @@ static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal #endif #endif +/** + * Make sure features that need to write to the SD card are + * disabled unless write support is enabled. + */ +#if ENABLED(SDCARD_READONLY) + #if ENABLED(POWER_LOSS_RECOVERY) + #error "POWER_LOSS_RECOVERY is incompatible with SDCARD_READONLY." + #elif ENABLED(BINARY_FILE_TRANSFER) + #error "BINARY_FILE_TRANSFER is incompatible with SDCARD_READONLY." + #elif ENABLED(SDCARD_EEPROM_EMULATION) + #error "SDCARD_EEPROM_EMULATION is incompatible with SDCARD_READONLY." + #endif +#endif + /** * Make sure only one display is enabled */ diff --git a/Marlin/src/sd/Sd2Card.cpp b/Marlin/src/sd/Sd2Card.cpp index e21662afc1..b5a3960890 100644 --- a/Marlin/src/sd/Sd2Card.cpp +++ b/Marlin/src/sd/Sd2Card.cpp @@ -179,8 +179,11 @@ void Sd2Card::chipSelect() { * \return true for success, false for failure. */ bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { + if (ENABLED(SDCARD_READONLY)) return false; + csd_t csd; if (!readCSD(&csd)) goto FAIL; + // check for single block erase if (!csd.v1.erase_blk_en) { // erase size mask @@ -535,9 +538,10 @@ bool Sd2Card::waitNotBusy(const millis_t timeout_ms) { * \return true for success, false for failure. */ bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { - if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; // Use address if not SDHC card + if (ENABLED(SDCARD_READONLY)) return false; bool success = false; + if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; // Use address if not SDHC card if (!cardCommand(CMD24, blockNumber)) { if (writeData(DATA_START_BLOCK, src)) { if (waitNotBusy(SD_WRITE_TIMEOUT)) { // Wait for flashing to complete @@ -561,6 +565,8 @@ bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { * \return true for success, false for failure. */ bool Sd2Card::writeData(const uint8_t* src) { + if (ENABLED(SDCARD_READONLY)) return false; + bool success = true; chipSelect(); // Wait for previous write to finish @@ -574,14 +580,9 @@ bool Sd2Card::writeData(const uint8_t* src) { // Send one block of data for write block or write multiple blocks bool Sd2Card::writeData(const uint8_t token, const uint8_t* src) { + if (ENABLED(SDCARD_READONLY)) return false; - const uint16_t crc = - #if ENABLED(SD_CHECK_AND_RETRY) - CRC_CCITT(src, 512) - #else - 0xFFFF - #endif - ; + const uint16_t crc = TERN(SD_CHECK_AND_RETRY, CRC_CCITT(src, 512), 0xFFFF); spiSendBlock(token, src); spiSend(crc >> 8); spiSend(crc & 0xFF); @@ -607,6 +608,8 @@ bool Sd2Card::writeData(const uint8_t token, const uint8_t* src) { * \return true for success, false for failure. */ bool Sd2Card::writeStart(uint32_t blockNumber, const uint32_t eraseCount) { + if (ENABLED(SDCARD_READONLY)) return false; + bool success = false; if (!cardAcmd(ACMD23, eraseCount)) { // Send pre-erase count if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; // Use address if not SDHC card @@ -626,6 +629,8 @@ bool Sd2Card::writeStart(uint32_t blockNumber, const uint32_t eraseCount) { * \return true for success, false for failure. */ bool Sd2Card::writeStop() { + if (ENABLED(SDCARD_READONLY)) return false; + bool success = false; chipSelect(); if (waitNotBusy(SD_WRITE_TIMEOUT)) { diff --git a/Marlin/src/sd/SdBaseFile.cpp b/Marlin/src/sd/SdBaseFile.cpp index 27c191a6a6..6e43c9f7c6 100644 --- a/Marlin/src/sd/SdBaseFile.cpp +++ b/Marlin/src/sd/SdBaseFile.cpp @@ -47,6 +47,8 @@ void (*SdBaseFile::dateTime_)(uint16_t* date, uint16_t* time) = 0; // add a cluster to a file bool SdBaseFile::addCluster() { + if (ENABLED(SDCARD_READONLY)) return false; + if (!vol_->allocContiguous(1, &curCluster_)) return false; // if first cluster of file link to directory entry @@ -60,6 +62,8 @@ bool SdBaseFile::addCluster() { // Add a cluster to a directory file and zero the cluster. // return with first block of cluster in the cache bool SdBaseFile::addDirCluster() { + if (ENABLED(SDCARD_READONLY)) return false; + uint32_t block; // max folder size if (fileSize_ / sizeof(dir_t) >= 0xFFFF) return false; @@ -153,6 +157,8 @@ bool SdBaseFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) { * */ bool SdBaseFile::createContiguous(SdBaseFile* dirFile, const char* path, uint32_t size) { + if (ENABLED(SDCARD_READONLY)) return false; + uint32_t count; // don't allow zero length file if (size == 0) return false; @@ -419,6 +425,8 @@ bool SdBaseFile::make83Name(const char* str, uint8_t* name, const char** ptr) { * directory, \a path is invalid or already exists in \a parent. */ bool SdBaseFile::mkdir(SdBaseFile* parent, const char* path, bool pFlag) { + if (ENABLED(SDCARD_READONLY)) return false; + uint8_t dname[11]; SdBaseFile dir1, dir2; SdBaseFile* sub = &dir1; @@ -449,6 +457,8 @@ bool SdBaseFile::mkdir(SdBaseFile* parent, const char* path, bool pFlag) { } bool SdBaseFile::mkdir(SdBaseFile* parent, const uint8_t dname[11]) { + if (ENABLED(SDCARD_READONLY)) return false; + uint32_t block; dir_t d; dir_t* p; @@ -632,7 +642,7 @@ bool SdBaseFile::open(SdBaseFile* dirFile, const uint8_t dname[11], uint8_t ofla } else { // don't create unless O_CREAT and O_WRITE - if (!(oflag & O_CREAT) || !(oflag & O_WRITE)) return false; + if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) return false; if (emptyFound) { index = dirIndex_; p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); @@ -716,8 +726,14 @@ bool SdBaseFile::open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag) { // open a cached directory entry. Assumes vol_ is initialized bool SdBaseFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) { + dir_t* p; + + #if ENABLED(SDCARD_READONLY) + if (oflag & (O_WRITE | O_CREAT | O_TRUNC)) goto FAIL; + #endif + // location of entry in cache - dir_t* p = &vol_->cache()->dir[dirIndex]; + p = &vol_->cache()->dir[dirIndex]; // write or truncate is an error for a directory or read-only file if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) { @@ -1135,6 +1151,8 @@ dir_t* SdBaseFile::readDirCache() { * or an I/O error occurred. */ bool SdBaseFile::remove() { + if (ENABLED(SDCARD_READONLY)) return false; + dir_t* d; // free any clusters - will fail if read-only or directory if (!truncate(0)) return false; @@ -1172,6 +1190,8 @@ bool SdBaseFile::remove() { * or an I/O error occurred. */ bool SdBaseFile::remove(SdBaseFile* dirFile, const char* path) { + if (ENABLED(SDCARD_READONLY)) return false; + SdBaseFile file; return file.open(dirFile, path, O_WRITE) ? file.remove() : false; } @@ -1187,6 +1207,8 @@ bool SdBaseFile::remove(SdBaseFile* dirFile, const char* path) { * file, newPath is invalid or already exists, or an I/O error occurs. */ bool SdBaseFile::rename(SdBaseFile* dirFile, const char* newPath) { + if (ENABLED(SDCARD_READONLY)) return false; + dir_t entry; uint32_t dirCluster = 0; SdBaseFile file; @@ -1279,6 +1301,8 @@ restore: * directory, is not empty, or an I/O error occurred. */ bool SdBaseFile::rmdir() { + if (ENABLED(SDCARD_READONLY)) return false; + // must be open subdirectory if (!isSubDir()) return false; @@ -1317,6 +1341,8 @@ bool SdBaseFile::rmdir() { * \return true for success, false for failure. */ bool SdBaseFile::rmRfStar() { + if (ENABLED(SDCARD_READONLY)) return false; + uint32_t index; SdBaseFile f; rewind(); @@ -1424,7 +1450,7 @@ void SdBaseFile::setpos(filepos_t* pos) { */ bool SdBaseFile::sync() { // only allow open files and directories - if (!isOpen()) goto FAIL; + if (ENABLED(SDCARD_READONLY) || !isOpen()) goto FAIL; if (flags_ & F_FILE_DIR_DIRTY) { dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); @@ -1524,6 +1550,8 @@ bool SdBaseFile::timestamp(SdBaseFile* file) { */ bool SdBaseFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { + if (ENABLED(SDCARD_READONLY)) return false; + uint16_t dirDate, dirTime; dir_t* d; @@ -1575,6 +1603,8 @@ bool SdBaseFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, * \a length is greater than the current file size or an I/O error occurs. */ bool SdBaseFile::truncate(uint32_t length) { + if (ENABLED(SDCARD_READONLY)) return false; + uint32_t newPos; // error if not a normal file or read-only if (!isFile() || !(flags_ & O_WRITE)) return false; @@ -1636,6 +1666,10 @@ bool SdBaseFile::truncate(uint32_t length) { * */ int16_t SdBaseFile::write(const void* buf, uint16_t nbyte) { + #if ENABLED(SDCARD_READONLY) + writeError = true; return -1; + #endif + // convert void* to uint8_t* - must be before goto statements const uint8_t* src = reinterpret_cast(buf); diff --git a/Marlin/src/sd/SdVolume.cpp b/Marlin/src/sd/SdVolume.cpp index 1d4c56a344..0effc31aa5 100644 --- a/Marlin/src/sd/SdVolume.cpp +++ b/Marlin/src/sd/SdVolume.cpp @@ -46,6 +46,8 @@ // find a contiguous group of clusters bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { + if (ENABLED(SDCARD_READONLY)) return false; + // start of group uint32_t bgnCluster; // end of group @@ -117,18 +119,20 @@ bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { } bool SdVolume::cacheFlush() { - if (cacheDirty_) { - if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) - return false; - - // mirror FAT tables - if (cacheMirrorBlock_) { - if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) + #if DISABLED(SDCARD_READONLY) + if (cacheDirty_) { + if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) return false; - cacheMirrorBlock_ = 0; + + // mirror FAT tables + if (cacheMirrorBlock_) { + if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) + return false; + cacheMirrorBlock_ = 0; + } + cacheDirty_ = 0; } - cacheDirty_ = 0; - } + #endif return true; } @@ -190,6 +194,8 @@ bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) { // Store a FAT entry bool SdVolume::fatPut(uint32_t cluster, uint32_t value) { + if (ENABLED(SDCARD_READONLY)) return false; + uint32_t lba; // error if reserved cluster if (cluster < 2) return false; diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index 7be69beb91..9ce2c5304c 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -446,8 +446,8 @@ void CardReader::endFilePrint(TERN_(SD_RESORT, const bool re_sort/*=false*/)) { } void CardReader::openLogFile(char * const path) { - flag.logging = true; - openFileWrite(path); + flag.logging = DISABLED(SDCARD_READONLY); + TERN(SDCARD_READONLY,,openFileWrite(path)); } // @@ -573,15 +573,19 @@ void CardReader::openFileWrite(char * const path) { const char * const fname = diveToFile(false, curDir, path); if (!fname) return; - if (file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) { - flag.saving = true; - selectFileByName(fname); - TERN_(EMERGENCY_PARSER, emergency_parser.disable()); - echo_write_to_file(fname); - ui.set_status(fname); - } - else + #if ENABLED(SDCARD_READONLY) openFailed(fname); + #else + if (file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) { + flag.saving = true; + selectFileByName(fname); + TERN_(EMERGENCY_PARSER, emergency_parser.disable()); + echo_write_to_file(fname); + ui.set_status(fname); + } + else + openFailed(fname); + #endif } // @@ -596,13 +600,17 @@ void CardReader::removeFile(const char * const name) { const char * const fname = diveToFile(false, curDir, name); if (!fname) return; - if (file.remove(curDir, fname)) { - SERIAL_ECHOLNPAIR("File deleted:", fname); - sdpos = 0; - TERN_(SDCARD_SORT_ALPHA, presort()); - } - else - SERIAL_ECHOLNPAIR("Deletion failed, File: ", fname, "."); + #if ENABLED(SDCARD_READONLY) + SERIAL_ECHOLNPAIR("Deletion failed (read-only), File: ", fname, "."); + #else + if (file.remove(curDir, fname)) { + SERIAL_ECHOLNPAIR("File deleted:", fname); + sdpos = 0; + TERN_(SDCARD_SORT_ALPHA, presort()); + } + else + SERIAL_ECHOLNPAIR("Deletion failed, File: ", fname, "."); + #endif } void CardReader::report_status() { diff --git a/buildroot/share/tests/LPC1768-tests b/buildroot/share/tests/LPC1768-tests index 332d22396e..2f206f02f2 100755 --- a/buildroot/share/tests/LPC1768-tests +++ b/buildroot/share/tests/LPC1768-tests @@ -15,8 +15,7 @@ set -e restore_configs opt_set MOTHERBOARD BOARD_RAMPS_14_RE_ARM_EFB -opt_enable VIKI2 SDSUPPORT SERIAL_PORT_2 NEOPIXEL_LED - +opt_enable VIKI2 SDSUPPORT SDCARD_READONLY SERIAL_PORT_2 NEOPIXEL_LED opt_set NEOPIXEL_PIN P1_16 exec_test $1 $2 "ReARM EFB VIKI2, SDSUPPORT, 2 Serial ports (USB CDC + UART0), NeoPixel"