From 3bae4748bfed9efeb5ce09ccc1fdc71da84c7e57 Mon Sep 17 00:00:00 2001 From: Luc Date: Tue, 22 Oct 2019 13:12:27 +0200 Subject: [PATCH] Add [ESP715]FORMATSD to format SD card Add SD format feature on SDFat for esp8266 and esp32 --- docs/Commands.txt | 3 + esp3d/src/core/commands.cpp | 9 +- esp3d/src/core/commands.h | 1 + esp3d/src/core/esp3doutput.cpp | 8 +- esp3d/src/core/esp3doutput.h | 2 +- esp3d/src/core/espcmd/ESP715.cpp | 59 +++ esp3d/src/include/version.h | 2 +- esp3d/src/modules/filesystem/esp_sd.h | 3 +- .../modules/filesystem/sd/sd_native_esp32.cpp | 5 +- .../filesystem/sd/sd_native_esp8266.cpp | 437 +++++++++++++++++- .../modules/filesystem/sd/sd_sdfat_esp32.cpp | 437 +++++++++++++++++- .../src/modules/filesystem/sd/sdio_esp32.cpp | 5 +- 12 files changed, 957 insertions(+), 14 deletions(-) create mode 100644 esp3d/src/core/espcmd/ESP715.cpp diff --git a/docs/Commands.txt b/docs/Commands.txt index 44394c22..2780ac55 100644 --- a/docs/Commands.txt +++ b/docs/Commands.txt @@ -187,6 +187,9 @@ Get will give type and settings only, not the protected T1/T2 * Format ESP Filesystem [ESP710]FORMAT pwd= +* Format SD Filesystem +[ESP715]FORMATSD pwd= + * List ESP Filesystem [ESP720] pwd= diff --git a/esp3d/src/core/commands.cpp b/esp3d/src/core/commands.cpp index cb12ccd2..ab9b5c8a 100644 --- a/esp3d/src/core/commands.cpp +++ b/esp3d/src/core/commands.cpp @@ -513,9 +513,16 @@ bool Commands::execute_internal_command (int cmd, const char* cmd_params, level_ response = ESP710(cmd_params, auth_type, output); break; #endif //FILESYSTEM_FEATURE +#if defined(SD_DEVICE) + //Format ESP Filesystem + //[ESP715]FORMATSD pwd= + case 715: + response = ESP715(cmd_params, auth_type, output); + break; +#endif //SD_DEVICE #if defined(FILESYSTEM_FEATURE) && defined(ESP_GCODE_HOST_FEATURE) //Open local file - //[ESP700] + //[ESP700] case 700: response = ESP700(cmd_params, auth_type, output); break; diff --git a/esp3d/src/core/commands.h b/esp3d/src/core/commands.h index 1ea3f922..d88bda08 100644 --- a/esp3d/src/core/commands.h +++ b/esp3d/src/core/commands.h @@ -124,6 +124,7 @@ public: bool ESP730(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); #endif //FILESYSTEM_FEATURE #if defined (SD_DEVICE) + bool ESP715(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); bool ESP750(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); bool ESP740(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); #endif //SD_DEVICE diff --git a/esp3d/src/core/esp3doutput.cpp b/esp3d/src/core/esp3doutput.cpp index 389879bd..7b5e3a48 100644 --- a/esp3d/src/core/esp3doutput.cpp +++ b/esp3d/src/core/esp3doutput.cpp @@ -187,7 +187,7 @@ size_t ESP3DOutput::printLN(const char * s) return println(s); } -size_t ESP3DOutput::printMSG(const char * s) +size_t ESP3DOutput::printMSG(const char * s, bool withNL) { if (!isOutput(_client)) { return 0; @@ -237,7 +237,11 @@ size_t ESP3DOutput::printMSG(const char * s) display = ";"; display += s; } - return printLN(display.c_str()); + if(withNL) { + return printLN(display.c_str()); + } else { + return print(display.c_str()); + } } size_t ESP3DOutput::printERROR(const char * s, int code_error) diff --git a/esp3d/src/core/esp3doutput.h b/esp3d/src/core/esp3doutput.h index 94336d53..e71c51c0 100644 --- a/esp3d/src/core/esp3doutput.h +++ b/esp3d/src/core/esp3doutput.h @@ -81,7 +81,7 @@ public: return _client; } size_t dispatch (uint8_t * sbuf, size_t len); - size_t printMSG(const char * s); + size_t printMSG(const char * s, bool withNL = true); size_t printERROR(const char * s, int code_error = 200); size_t printLN(const char * s); void flush(); diff --git a/esp3d/src/core/espcmd/ESP715.cpp b/esp3d/src/core/espcmd/ESP715.cpp new file mode 100644 index 00000000..b87bdf94 --- /dev/null +++ b/esp3d/src/core/espcmd/ESP715.cpp @@ -0,0 +1,59 @@ +/* + ESP715.cpp - ESP3D command class + + Copyright (c) 2014 Luc Lebosse. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "../../include/esp3d_config.h" +#if defined (SD_DEVICE) +#include "../commands.h" +#include "../esp3doutput.h" +#include "../settings_esp3d.h" +#include "../../modules/authentication/authentication_service.h" +#include "../../modules/filesystem/esp_sd.h" +//Format SD Filesystem +//[ESP715]FORMAT pwd= +bool Commands::ESP715(const char* cmd_params, level_authenticate_type auth_type, ESP3DOutput * output) +{ + bool response = true; + String parameter; + parameter = get_param (cmd_params, ""); +#ifdef AUTHENTICATION_FEATURE + if (auth_type != LEVEL_ADMIN) { + output->printERROR("Wrong authentication!", 401); + response = false; + } else +#else + (void)auth_type; +#endif //AUTHENTICATION_FEATURE + { + if (parameter == "FORMATSD") { + output->printMSG("Start Formating"); + if (ESP_SD::format(output)) { + output->printMSG("Format Done"); + } else { + output->printERROR ("Format failed!"); + response = false; + } + } else { + output->printERROR ("Invalid parameter!"); + response = false; + } + } + return response; +} + +#endif //SD_DEVICE diff --git a/esp3d/src/include/version.h b/esp3d/src/include/version.h index 60c4d3de..ed8a81ab 100644 --- a/esp3d/src/include/version.h +++ b/esp3d/src/include/version.h @@ -22,7 +22,7 @@ #define _VERSION_ESP3D_H //version and sources location -#define FW_VERSION "3.0.0.a23" +#define FW_VERSION "3.0.0.a24" #define REPOSITORY "https://github.com/luc-github/ESP3D" #endif //_VERSION_ESP3D_H diff --git a/esp3d/src/modules/filesystem/esp_sd.h b/esp3d/src/modules/filesystem/esp_sd.h index ff8fc50d..05b5b9b6 100644 --- a/esp3d/src/modules/filesystem/esp_sd.h +++ b/esp3d/src/modules/filesystem/esp_sd.h @@ -21,6 +21,7 @@ #ifndef _ESP_SD_H #define _ESP_SD_H #include "../../include/esp3d_config.h" +#include "../../core/esp3doutput.h" #ifdef SD_TIMESTAMP_FEATURE #include #endif //SD_TIMESTAMP_FEATURE @@ -85,7 +86,7 @@ public: static uint64_t usedBytes(); static uint64_t freeBytes(); static const char * FilesystemName(); - static bool format(); + static bool format(ESP3DOutput * output = nullptr); static ESP_SDFile open(const char* path, uint8_t mode = ESP_SD_FILE_READ); static bool exists(const char* path); static bool remove(const char *path); diff --git a/esp3d/src/modules/filesystem/sd/sd_native_esp32.cpp b/esp3d/src/modules/filesystem/sd/sd_native_esp32.cpp index 404ed798..2e493e40 100644 --- a/esp3d/src/modules/filesystem/sd/sd_native_esp32.cpp +++ b/esp3d/src/modules/filesystem/sd/sd_native_esp32.cpp @@ -99,9 +99,12 @@ uint64_t ESP_SD::freeBytes() return (SD.totalBytes() - SD.usedBytes()); }; -bool ESP_SD::format() +bool ESP_SD::format(ESP3DOutput * output) { //not available yet + if (output) { + output->printERROR ("Not implemented!"); + } return false; } diff --git a/esp3d/src/modules/filesystem/sd/sd_native_esp8266.cpp b/esp3d/src/modules/filesystem/sd/sd_native_esp8266.cpp index 055535d2..3c7f8717 100644 --- a/esp3d/src/modules/filesystem/sd/sd_native_esp8266.cpp +++ b/esp3d/src/modules/filesystem/sd/sd_native_esp8266.cpp @@ -147,10 +147,441 @@ uint64_t ESP_SD::freeBytes() return volFree * blocks * 512; }; -bool ESP_SD::format() +// strings needed in file system structures +#define noName "NO NAME " +#define fat16str "FAT16 " +#define fat32str "FAT32 " +// constants for file system structure +#define BU16 128 +#define BU32 8192 +#define ERASE_SIZE 262144L; + +//------------------------------------------------------------------------------ +// write cached block to the card +uint8_t writeCache(uint32_t lbn, Sd2Card & card, cache_t & cache) { - //not available yet - //SDFat has a feature for this + return card.writeBlock(lbn, cache.data); +} + +//------------------------------------------------------------------------------ +// initialize appropriate sizes for SD capacity +bool initSizes(uint32_t cardCapacityMB, uint8_t & sectorsPerCluster, uint8_t & numberOfHeads, uint8_t & sectorsPerTrack) +{ + if (cardCapacityMB <= 6) { + return false; + } else if (cardCapacityMB <= 16) { + sectorsPerCluster = 2; + } else if (cardCapacityMB <= 32) { + sectorsPerCluster = 4; + } else if (cardCapacityMB <= 64) { + sectorsPerCluster = 8; + } else if (cardCapacityMB <= 128) { + sectorsPerCluster = 16; + } else if (cardCapacityMB <= 1024) { + sectorsPerCluster = 32; + } else if (cardCapacityMB <= 32768) { + sectorsPerCluster = 64; + } else { + // SDXC cards + sectorsPerCluster = 128; + } + + // set fake disk geometry + sectorsPerTrack = cardCapacityMB <= 256 ? 32 : 63; + + if (cardCapacityMB <= 16) { + numberOfHeads = 2; + } else if (cardCapacityMB <= 32) { + numberOfHeads = 4; + } else if (cardCapacityMB <= 128) { + numberOfHeads = 8; + } else if (cardCapacityMB <= 504) { + numberOfHeads = 16; + } else if (cardCapacityMB <= 1008) { + numberOfHeads = 32; + } else if (cardCapacityMB <= 2016) { + numberOfHeads = 64; + } else if (cardCapacityMB <= 4032) { + numberOfHeads = 128; + } else { + numberOfHeads = 255; + } + return true; +} + +//------------------------------------------------------------------------------ +// zero cache and optionally set the sector signature +void clearCache(uint8_t addSig, cache_t & cache) +{ + memset(&cache, 0, sizeof(cache)); + if (addSig) { + cache.mbr.mbrSig0 = BOOTSIG0; + cache.mbr.mbrSig1 = BOOTSIG1; + } +} +//------------------------------------------------------------------------------ +// zero FAT and root dir area on SD +bool clearFatDir(uint32_t bgn, uint32_t count, Sd2Card & card, cache_t & cache, ESP3DOutput * output) +{ + clearCache(false, cache); + if (!card.writeStart(bgn, count)) { + return false; + } + for (uint32_t i = 0; i < count; i++) { + if ((i & 0XFF) == 0) { + if (output) { + output->print("."); + } + } + if (!card.writeData(cache.data)) { + return false; + } + } + if (!card.writeStop()) { + return false; + } + return true; +} + +//------------------------------------------------------------------------------ +// return cylinder number for a logical block number +uint16_t lbnToCylinder(uint32_t lbn, uint8_t numberOfHeads, uint8_t sectorsPerTrack) +{ + return lbn / (numberOfHeads * sectorsPerTrack); +} +//------------------------------------------------------------------------------ +// return head number for a logical block number +uint8_t lbnToHead(uint32_t lbn, uint8_t numberOfHeads, uint8_t sectorsPerTrack) +{ + return (lbn % (numberOfHeads * sectorsPerTrack)) / sectorsPerTrack; +} +//------------------------------------------------------------------------------ +// return sector number for a logical block number +uint8_t lbnToSector(uint32_t lbn, uint8_t sectorsPerTrack) +{ + return (lbn % sectorsPerTrack) + 1; +} + +//------------------------------------------------------------------------------ +// format and write the Master Boot Record +bool writeMbr(Sd2Card & card, cache_t & cache, uint8_t partType, uint32_t relSector, uint32_t partSize, uint8_t numberOfHeads, uint8_t sectorsPerTrack) +{ + clearCache(true, cache); + part_t* p = cache.mbr.part; + p->boot = 0; + uint16_t c = lbnToCylinder(relSector, numberOfHeads, sectorsPerTrack); + if (c > 1023) { + return false; + } + p->beginCylinderHigh = c >> 8; + p->beginCylinderLow = c & 0XFF; + p->beginHead = lbnToHead(relSector, numberOfHeads, sectorsPerTrack); + p->beginSector = lbnToSector(relSector, sectorsPerTrack); + p->type = partType; + uint32_t endLbn = relSector + partSize - 1; + c = lbnToCylinder(endLbn,numberOfHeads, sectorsPerTrack); + if (c <= 1023) { + p->endCylinderHigh = c >> 8; + p->endCylinderLow = c & 0XFF; + p->endHead = lbnToHead(endLbn, numberOfHeads, sectorsPerTrack); + p->endSector = lbnToSector(endLbn, sectorsPerTrack); + } else { + // Too big flag, c = 1023, h = 254, s = 63 + p->endCylinderHigh = 3; + p->endCylinderLow = 255; + p->endHead = 254; + p->endSector = 63; + } + p->firstSector = relSector; + p->totalSectors = partSize; + if (!writeCache(0, card, cache)) { + return false; + } + return true; +} + +//------------------------------------------------------------------------------ +// generate serial number from card size and micros since boot +uint32_t volSerialNumber(uint32_t cardSizeBlocks) +{ + return (cardSizeBlocks << 8) + micros(); +} + +// format the SD as FAT16 +bool makeFat16(uint32_t & dataStart, Sd2Card & card, cache_t & cache, uint8_t numberOfHeads, uint8_t sectorsPerTrack, uint32_t cardSizeBlocks, uint8_t sectorsPerCluster, uint32_t &relSector, uint32_t partSize, uint8_t & partType, uint32_t &fatSize, uint32_t &fatStart, uint16_t reservedSectors, ESP3DOutput * output) +{ + uint32_t nc; + for (dataStart = 2 * BU16;; dataStart += BU16) { + nc = (cardSizeBlocks - dataStart)/sectorsPerCluster; + fatSize = (nc + 2 + 255)/256; + uint32_t r = BU16 + 1 + 2 * fatSize + 32; + if (dataStart < r) { + continue; + } + relSector = dataStart - r + BU16; + break; + } + // check valid cluster count for FAT16 volume + if (nc < 4085 || nc >= 65525) { + return false; + } + reservedSectors = 1; + fatStart = relSector + reservedSectors; + partSize = nc * sectorsPerCluster + 2 * fatSize + reservedSectors + 32; + if (partSize < 32680) { + partType = 0X01; + } else if (partSize < 65536) { + partType = 0X04; + } else { + partType = 0X06; + } + // write MBR + if (!writeMbr(card, cache, partType, relSector, partSize, numberOfHeads, sectorsPerTrack)) { + return false; + } + clearCache(true, cache); + fat_boot_t* pb = &cache.fbs; + pb->jump[0] = 0XEB; + pb->jump[1] = 0X00; + pb->jump[2] = 0X90; + for (uint8_t i = 0; i < sizeof(pb->oemId); i++) { + pb->oemId[i] = ' '; + } + pb->bytesPerSector = 512; + pb->sectorsPerCluster = sectorsPerCluster; + pb->reservedSectorCount = reservedSectors; + pb->fatCount = 2; + pb->rootDirEntryCount = 512; + pb->mediaType = 0XF8; + pb->sectorsPerFat16 = fatSize; + pb->sectorsPerTrack = sectorsPerTrack; + pb->headCount = numberOfHeads; + pb->hidddenSectors = relSector; + pb->totalSectors32 = partSize; + pb->driveNumber = 0X80; + pb->bootSignature = EXTENDED_BOOT_SIG; + pb->volumeSerialNumber = volSerialNumber(cardSizeBlocks); + memcpy(pb->volumeLabel, noName, sizeof(pb->volumeLabel)); + memcpy(pb->fileSystemType, fat16str, sizeof(pb->fileSystemType)); + // write partition boot sector + if (!writeCache(relSector, card, cache)) { + return false; + } + // clear FAT and root directory + clearFatDir(fatStart, dataStart - fatStart, card, cache, output); + clearCache(false, cache); + cache.fat16[0] = 0XFFF8; + cache.fat16[1] = 0XFFFF; + // write first block of FAT and backup for reserved clusters + if (!writeCache(fatStart, card, cache) + || !writeCache(fatStart + fatSize, card, cache)) { + return false; + } + return true; +} + +// format the SD as FAT32 +bool makeFat32(uint32_t & dataStart, Sd2Card & card, cache_t & cache, uint8_t numberOfHeads, uint8_t sectorsPerTrack, uint32_t cardSizeBlocks, uint8_t sectorsPerCluster, uint32_t &relSector, uint32_t partSize, uint8_t & partType, uint32_t &fatSize, uint32_t &fatStart, uint16_t reservedSectors, ESP3DOutput * output) +{ + uint32_t nc; + relSector = BU32; + for (dataStart = 2 * BU32;; dataStart += BU32) { + nc = (cardSizeBlocks - dataStart)/sectorsPerCluster; + fatSize = (nc + 2 + 127)/128; + uint32_t r = relSector + 9 + 2 * fatSize; + if (dataStart >= r) { + break; + } + } + // error if too few clusters in FAT32 volume + if (nc < 65525) { + return false; + } + reservedSectors = dataStart - relSector - 2 * fatSize; + fatStart = relSector + reservedSectors; + partSize = nc * sectorsPerCluster + dataStart - relSector; + // type depends on address of end sector + // max CHS has lbn = 16450560 = 1024*255*63 + if ((relSector + partSize) <= 16450560) { + // FAT32 + partType = 0X0B; + } else { + // FAT32 with INT 13 + partType = 0X0C; + } + if (!writeMbr(card, cache, partType, relSector, partSize, numberOfHeads, sectorsPerTrack)) { + return false; + } + clearCache(true, cache); + + fat32_boot_t* pb = &cache.fbs32; + pb->jump[0] = 0XEB; + pb->jump[1] = 0X00; + pb->jump[2] = 0X90; + for (uint8_t i = 0; i < sizeof(pb->oemId); i++) { + pb->oemId[i] = ' '; + } + pb->bytesPerSector = 512; + pb->sectorsPerCluster = sectorsPerCluster; + pb->reservedSectorCount = reservedSectors; + pb->fatCount = 2; + pb->mediaType = 0XF8; + pb->sectorsPerTrack = sectorsPerTrack; + pb->headCount = numberOfHeads; + pb->hidddenSectors = relSector; + pb->totalSectors32 = partSize; + pb->sectorsPerFat32 = fatSize; + pb->fat32RootCluster = 2; + pb->fat32FSInfo = 1; + pb->fat32BackBootBlock = 6; + pb->driveNumber = 0X80; + pb->bootSignature = EXTENDED_BOOT_SIG; + pb->volumeSerialNumber = volSerialNumber(cardSizeBlocks); + memcpy(pb->volumeLabel, noName, sizeof(pb->volumeLabel)); + memcpy(pb->fileSystemType, fat32str, sizeof(pb->fileSystemType)); + // write partition boot sector and backup + if (!writeCache(relSector, card, cache) + || !writeCache(relSector + 6, card, cache)) { + return false; + } + clearCache(true, cache); + // write extra boot area and backup + if (!writeCache(relSector + 2, card, cache) + || !writeCache(relSector + 8, card, cache)) { + return false; + } + fat32_fsinfo_t* pf = &cache.fsinfo; + pf->leadSignature = FSINFO_LEAD_SIG; + pf->structSignature = FSINFO_STRUCT_SIG; + pf->freeCount = 0XFFFFFFFF; + pf->nextFree = 0XFFFFFFFF; + // write FSINFO sector and backup + if (!writeCache(relSector + 1, card, cache) + || !writeCache(relSector + 7, card, cache)) { + return false; + } + clearFatDir(fatStart, 2 * fatSize + sectorsPerCluster, card, cache, output); + clearCache(false, cache); + cache.fat32[0] = 0x0FFFFFF8; + cache.fat32[1] = 0x0FFFFFFF; + cache.fat32[2] = 0x0FFFFFFF; + // write first block of FAT and backup for reserved clusters + if (!writeCache(fatStart, card, cache) + || !writeCache(fatStart + fatSize, card, cache)) { + return false; + } + return true; +} + +bool eraseCard(Sd2Card & card, cache_t & cache, uint32_t cardSizeBlocks, ESP3DOutput * output) +{ + uint32_t firstBlock = 0; + uint32_t lastBlock; + uint16_t n = 0; + if (output) { + output->printMSG("Erasing ", false); + } + do { + lastBlock = firstBlock + ERASE_SIZE - 1; + if (lastBlock >= cardSizeBlocks) { + lastBlock = cardSizeBlocks - 1; + } + if (!card.erase(firstBlock, lastBlock)) { + return false; + } + if (output) { + output->print("."); + } + firstBlock += ERASE_SIZE; + } while (firstBlock < cardSizeBlocks); + + if (!card.readBlock(0, cache.data)) { + return false; + } + if (output) { + output->printLN(""); + } + return true; +} + +bool formatCard(uint32_t & dataStart, Sd2Card & card, + cache_t & cache, uint8_t numberOfHeads, + uint8_t sectorsPerTrack, uint32_t cardSizeBlocks, + uint8_t sectorsPerCluster, uint32_t &relSector, + uint32_t partSize, uint8_t & partType, + uint32_t &fatSize, uint32_t &fatStart, + uint32_t cardCapacityMB, uint16_t reservedSectors, ESP3DOutput * output) +{ + initSizes(cardCapacityMB, sectorsPerCluster, numberOfHeads, sectorsPerTrack); + if (card.type() != SD_CARD_TYPE_SDHC) { + if (output) { + output->printMSG("Formating FAT16 "); + } + if(!makeFat16(dataStart, card, cache, numberOfHeads, sectorsPerTrack, cardSizeBlocks, sectorsPerCluster, relSector, partSize, partType, fatSize, fatStart, reservedSectors, output)) { + return false; + } + } else { + if (output) { + output->printMSG("Formating FAT32 ", false); + } + if(!makeFat32(dataStart, card, cache, numberOfHeads, sectorsPerTrack, cardSizeBlocks, sectorsPerCluster, relSector, partSize, partType, fatSize, fatStart, reservedSectors, output)) { + return false; + } + } + if (output) { + output->printLN(""); + } + return true; +} + +bool ESP_SD::format(ESP3DOutput * output) +{ + if (ESP_SD::getState(true) == ESP_SDCARD_IDLE) { + Sd2Card card; + uint32_t cardSizeBlocks; + uint32_t cardCapacityMB; + // cache for SD block + cache_t cache; + + // MBR information + uint8_t partType; + uint32_t relSector; + uint32_t partSize; + + // Fake disk geometry + uint8_t numberOfHeads; + uint8_t sectorsPerTrack; + + // FAT parameters + uint16_t reservedSectors; + uint8_t sectorsPerCluster; + uint32_t fatStart; + uint32_t fatSize; + uint32_t dataStart; + if (!card.begin((ESP_SD_CS_PIN == -1)?SS:ESP_SD_CS_PIN, SD_SCK_HZ(F_CPU/_spi_speed_divider))) { + return false; + } + cardSizeBlocks = card.cardSize(); + if (cardSizeBlocks == 0) { + return false; + } + cardCapacityMB = (cardSizeBlocks + 2047)/2048; + if (output) { + String s = "Capacity detected :" + String((1.048576*cardCapacityMB)/1024) + "GB"; + output->printMSG(s.c_str()); + } + if (!eraseCard(card, cache, cardSizeBlocks, output)) { + return false; + } + + if (!formatCard(dataStart, card, cache, numberOfHeads, + sectorsPerTrack, cardSizeBlocks, + sectorsPerCluster, relSector, partSize, partType, + fatSize, fatStart, cardCapacityMB, reservedSectors,output)) { + return false; + } + return true; + } return false; } diff --git a/esp3d/src/modules/filesystem/sd/sd_sdfat_esp32.cpp b/esp3d/src/modules/filesystem/sd/sd_sdfat_esp32.cpp index da3f9cd5..71aee69f 100644 --- a/esp3d/src/modules/filesystem/sd/sd_sdfat_esp32.cpp +++ b/esp3d/src/modules/filesystem/sd/sd_sdfat_esp32.cpp @@ -146,10 +146,441 @@ uint64_t ESP_SD::freeBytes() return volFree * blocks * 512; }; -bool ESP_SD::format() +// strings needed in file system structures +#define noName "NO NAME " +#define fat16str "FAT16 " +#define fat32str "FAT32 " +// constants for file system structure +#define BU16 128 +#define BU32 8192 +#define ERASE_SIZE 262144L; + +//------------------------------------------------------------------------------ +// write cached block to the card +uint8_t writeCache(uint32_t lbn, Sd2Card & card, cache_t & cache) { - //not available yet - //SDFat has a feature for this + return card.writeBlock(lbn, cache.data); +} + +//------------------------------------------------------------------------------ +// initialize appropriate sizes for SD capacity +bool initSizes(uint32_t cardCapacityMB, uint8_t & sectorsPerCluster, uint8_t & numberOfHeads, uint8_t & sectorsPerTrack) +{ + if (cardCapacityMB <= 6) { + return false; + } else if (cardCapacityMB <= 16) { + sectorsPerCluster = 2; + } else if (cardCapacityMB <= 32) { + sectorsPerCluster = 4; + } else if (cardCapacityMB <= 64) { + sectorsPerCluster = 8; + } else if (cardCapacityMB <= 128) { + sectorsPerCluster = 16; + } else if (cardCapacityMB <= 1024) { + sectorsPerCluster = 32; + } else if (cardCapacityMB <= 32768) { + sectorsPerCluster = 64; + } else { + // SDXC cards + sectorsPerCluster = 128; + } + + // set fake disk geometry + sectorsPerTrack = cardCapacityMB <= 256 ? 32 : 63; + + if (cardCapacityMB <= 16) { + numberOfHeads = 2; + } else if (cardCapacityMB <= 32) { + numberOfHeads = 4; + } else if (cardCapacityMB <= 128) { + numberOfHeads = 8; + } else if (cardCapacityMB <= 504) { + numberOfHeads = 16; + } else if (cardCapacityMB <= 1008) { + numberOfHeads = 32; + } else if (cardCapacityMB <= 2016) { + numberOfHeads = 64; + } else if (cardCapacityMB <= 4032) { + numberOfHeads = 128; + } else { + numberOfHeads = 255; + } + return true; +} + +//------------------------------------------------------------------------------ +// zero cache and optionally set the sector signature +void clearCache(uint8_t addSig, cache_t & cache) +{ + memset(&cache, 0, sizeof(cache)); + if (addSig) { + cache.mbr.mbrSig0 = BOOTSIG0; + cache.mbr.mbrSig1 = BOOTSIG1; + } +} +//------------------------------------------------------------------------------ +// zero FAT and root dir area on SD +bool clearFatDir(uint32_t bgn, uint32_t count, Sd2Card & card, cache_t & cache, ESP3DOutput * output) +{ + clearCache(false, cache); + if (!card.writeStart(bgn, count)) { + return false; + } + for (uint32_t i = 0; i < count; i++) { + if ((i & 0XFF) == 0) { + if (output) { + output->print("."); + } + } + if (!card.writeData(cache.data)) { + return false; + } + } + if (!card.writeStop()) { + return false; + } + return true; +} + +//------------------------------------------------------------------------------ +// return cylinder number for a logical block number +uint16_t lbnToCylinder(uint32_t lbn, uint8_t numberOfHeads, uint8_t sectorsPerTrack) +{ + return lbn / (numberOfHeads * sectorsPerTrack); +} +//------------------------------------------------------------------------------ +// return head number for a logical block number +uint8_t lbnToHead(uint32_t lbn, uint8_t numberOfHeads, uint8_t sectorsPerTrack) +{ + return (lbn % (numberOfHeads * sectorsPerTrack)) / sectorsPerTrack; +} +//------------------------------------------------------------------------------ +// return sector number for a logical block number +uint8_t lbnToSector(uint32_t lbn, uint8_t sectorsPerTrack) +{ + return (lbn % sectorsPerTrack) + 1; +} + +//------------------------------------------------------------------------------ +// format and write the Master Boot Record +bool writeMbr(Sd2Card & card, cache_t & cache, uint8_t partType, uint32_t relSector, uint32_t partSize, uint8_t numberOfHeads, uint8_t sectorsPerTrack) +{ + clearCache(true, cache); + part_t* p = cache.mbr.part; + p->boot = 0; + uint16_t c = lbnToCylinder(relSector, numberOfHeads, sectorsPerTrack); + if (c > 1023) { + return false; + } + p->beginCylinderHigh = c >> 8; + p->beginCylinderLow = c & 0XFF; + p->beginHead = lbnToHead(relSector, numberOfHeads, sectorsPerTrack); + p->beginSector = lbnToSector(relSector, sectorsPerTrack); + p->type = partType; + uint32_t endLbn = relSector + partSize - 1; + c = lbnToCylinder(endLbn,numberOfHeads, sectorsPerTrack); + if (c <= 1023) { + p->endCylinderHigh = c >> 8; + p->endCylinderLow = c & 0XFF; + p->endHead = lbnToHead(endLbn, numberOfHeads, sectorsPerTrack); + p->endSector = lbnToSector(endLbn, sectorsPerTrack); + } else { + // Too big flag, c = 1023, h = 254, s = 63 + p->endCylinderHigh = 3; + p->endCylinderLow = 255; + p->endHead = 254; + p->endSector = 63; + } + p->firstSector = relSector; + p->totalSectors = partSize; + if (!writeCache(0, card, cache)) { + return false; + } + return true; +} + +//------------------------------------------------------------------------------ +// generate serial number from card size and micros since boot +uint32_t volSerialNumber(uint32_t cardSizeBlocks) +{ + return (cardSizeBlocks << 8) + micros(); +} + +// format the SD as FAT16 +bool makeFat16(uint32_t & dataStart, Sd2Card & card, cache_t & cache, uint8_t numberOfHeads, uint8_t sectorsPerTrack, uint32_t cardSizeBlocks, uint8_t sectorsPerCluster, uint32_t &relSector, uint32_t partSize, uint8_t & partType, uint32_t &fatSize, uint32_t &fatStart, uint16_t reservedSectors, ESP3DOutput * output) +{ + uint32_t nc; + for (dataStart = 2 * BU16;; dataStart += BU16) { + nc = (cardSizeBlocks - dataStart)/sectorsPerCluster; + fatSize = (nc + 2 + 255)/256; + uint32_t r = BU16 + 1 + 2 * fatSize + 32; + if (dataStart < r) { + continue; + } + relSector = dataStart - r + BU16; + break; + } + // check valid cluster count for FAT16 volume + if (nc < 4085 || nc >= 65525) { + return false; + } + reservedSectors = 1; + fatStart = relSector + reservedSectors; + partSize = nc * sectorsPerCluster + 2 * fatSize + reservedSectors + 32; + if (partSize < 32680) { + partType = 0X01; + } else if (partSize < 65536) { + partType = 0X04; + } else { + partType = 0X06; + } + // write MBR + if (!writeMbr(card, cache, partType, relSector, partSize, numberOfHeads, sectorsPerTrack)) { + return false; + } + clearCache(true, cache); + fat_boot_t* pb = &cache.fbs; + pb->jump[0] = 0XEB; + pb->jump[1] = 0X00; + pb->jump[2] = 0X90; + for (uint8_t i = 0; i < sizeof(pb->oemId); i++) { + pb->oemId[i] = ' '; + } + pb->bytesPerSector = 512; + pb->sectorsPerCluster = sectorsPerCluster; + pb->reservedSectorCount = reservedSectors; + pb->fatCount = 2; + pb->rootDirEntryCount = 512; + pb->mediaType = 0XF8; + pb->sectorsPerFat16 = fatSize; + pb->sectorsPerTrack = sectorsPerTrack; + pb->headCount = numberOfHeads; + pb->hidddenSectors = relSector; + pb->totalSectors32 = partSize; + pb->driveNumber = 0X80; + pb->bootSignature = EXTENDED_BOOT_SIG; + pb->volumeSerialNumber = volSerialNumber(cardSizeBlocks); + memcpy(pb->volumeLabel, noName, sizeof(pb->volumeLabel)); + memcpy(pb->fileSystemType, fat16str, sizeof(pb->fileSystemType)); + // write partition boot sector + if (!writeCache(relSector, card, cache)) { + return false; + } + // clear FAT and root directory + clearFatDir(fatStart, dataStart - fatStart, card, cache, output); + clearCache(false, cache); + cache.fat16[0] = 0XFFF8; + cache.fat16[1] = 0XFFFF; + // write first block of FAT and backup for reserved clusters + if (!writeCache(fatStart, card, cache) + || !writeCache(fatStart + fatSize, card, cache)) { + return false; + } + return true; +} + +// format the SD as FAT32 +bool makeFat32(uint32_t & dataStart, Sd2Card & card, cache_t & cache, uint8_t numberOfHeads, uint8_t sectorsPerTrack, uint32_t cardSizeBlocks, uint8_t sectorsPerCluster, uint32_t &relSector, uint32_t partSize, uint8_t & partType, uint32_t &fatSize, uint32_t &fatStart, uint16_t reservedSectors, ESP3DOutput * output) +{ + uint32_t nc; + relSector = BU32; + for (dataStart = 2 * BU32;; dataStart += BU32) { + nc = (cardSizeBlocks - dataStart)/sectorsPerCluster; + fatSize = (nc + 2 + 127)/128; + uint32_t r = relSector + 9 + 2 * fatSize; + if (dataStart >= r) { + break; + } + } + // error if too few clusters in FAT32 volume + if (nc < 65525) { + return false; + } + reservedSectors = dataStart - relSector - 2 * fatSize; + fatStart = relSector + reservedSectors; + partSize = nc * sectorsPerCluster + dataStart - relSector; + // type depends on address of end sector + // max CHS has lbn = 16450560 = 1024*255*63 + if ((relSector + partSize) <= 16450560) { + // FAT32 + partType = 0X0B; + } else { + // FAT32 with INT 13 + partType = 0X0C; + } + if (!writeMbr(card, cache, partType, relSector, partSize, numberOfHeads, sectorsPerTrack)) { + return false; + } + clearCache(true, cache); + + fat32_boot_t* pb = &cache.fbs32; + pb->jump[0] = 0XEB; + pb->jump[1] = 0X00; + pb->jump[2] = 0X90; + for (uint8_t i = 0; i < sizeof(pb->oemId); i++) { + pb->oemId[i] = ' '; + } + pb->bytesPerSector = 512; + pb->sectorsPerCluster = sectorsPerCluster; + pb->reservedSectorCount = reservedSectors; + pb->fatCount = 2; + pb->mediaType = 0XF8; + pb->sectorsPerTrack = sectorsPerTrack; + pb->headCount = numberOfHeads; + pb->hidddenSectors = relSector; + pb->totalSectors32 = partSize; + pb->sectorsPerFat32 = fatSize; + pb->fat32RootCluster = 2; + pb->fat32FSInfo = 1; + pb->fat32BackBootBlock = 6; + pb->driveNumber = 0X80; + pb->bootSignature = EXTENDED_BOOT_SIG; + pb->volumeSerialNumber = volSerialNumber(cardSizeBlocks); + memcpy(pb->volumeLabel, noName, sizeof(pb->volumeLabel)); + memcpy(pb->fileSystemType, fat32str, sizeof(pb->fileSystemType)); + // write partition boot sector and backup + if (!writeCache(relSector, card, cache) + || !writeCache(relSector + 6, card, cache)) { + return false; + } + clearCache(true, cache); + // write extra boot area and backup + if (!writeCache(relSector + 2, card, cache) + || !writeCache(relSector + 8, card, cache)) { + return false; + } + fat32_fsinfo_t* pf = &cache.fsinfo; + pf->leadSignature = FSINFO_LEAD_SIG; + pf->structSignature = FSINFO_STRUCT_SIG; + pf->freeCount = 0XFFFFFFFF; + pf->nextFree = 0XFFFFFFFF; + // write FSINFO sector and backup + if (!writeCache(relSector + 1, card, cache) + || !writeCache(relSector + 7, card, cache)) { + return false; + } + clearFatDir(fatStart, 2 * fatSize + sectorsPerCluster, card, cache, output); + clearCache(false, cache); + cache.fat32[0] = 0x0FFFFFF8; + cache.fat32[1] = 0x0FFFFFFF; + cache.fat32[2] = 0x0FFFFFFF; + // write first block of FAT and backup for reserved clusters + if (!writeCache(fatStart, card, cache) + || !writeCache(fatStart + fatSize, card, cache)) { + return false; + } + return true; +} + +bool eraseCard(Sd2Card & card, cache_t & cache, uint32_t cardSizeBlocks, ESP3DOutput * output) +{ + uint32_t firstBlock = 0; + uint32_t lastBlock; + uint16_t n = 0; + if (output) { + output->printMSG("Erasing ", false); + } + do { + lastBlock = firstBlock + ERASE_SIZE - 1; + if (lastBlock >= cardSizeBlocks) { + lastBlock = cardSizeBlocks - 1; + } + if (!card.erase(firstBlock, lastBlock)) { + return false; + } + if (output) { + output->print("."); + } + firstBlock += ERASE_SIZE; + } while (firstBlock < cardSizeBlocks); + + if (!card.readBlock(0, cache.data)) { + return false; + } + if (output) { + output->printLN(""); + } + return true; +} + +bool formatCard(uint32_t & dataStart, Sd2Card & card, + cache_t & cache, uint8_t numberOfHeads, + uint8_t sectorsPerTrack, uint32_t cardSizeBlocks, + uint8_t sectorsPerCluster, uint32_t &relSector, + uint32_t partSize, uint8_t & partType, + uint32_t &fatSize, uint32_t &fatStart, + uint32_t cardCapacityMB, uint16_t reservedSectors, ESP3DOutput * output) +{ + initSizes(cardCapacityMB, sectorsPerCluster, numberOfHeads, sectorsPerTrack); + if (card.type() != SD_CARD_TYPE_SDHC) { + if (output) { + output->printMSG("Formating FAT16 "); + } + if(!makeFat16(dataStart, card, cache, numberOfHeads, sectorsPerTrack, cardSizeBlocks, sectorsPerCluster, relSector, partSize, partType, fatSize, fatStart, reservedSectors, output)) { + return false; + } + } else { + if (output) { + output->printMSG("Formating FAT32 ", false); + } + if(!makeFat32(dataStart, card, cache, numberOfHeads, sectorsPerTrack, cardSizeBlocks, sectorsPerCluster, relSector, partSize, partType, fatSize, fatStart, reservedSectors, output)) { + return false; + } + } + if (output) { + output->printLN(""); + } + return true; +} + +bool ESP_SD::format(ESP3DOutput * output) +{ + if (ESP_SD::getState(true) == ESP_SDCARD_IDLE) { + Sd2Card card; + uint32_t cardSizeBlocks; + uint32_t cardCapacityMB; + // cache for SD block + cache_t cache; + + // MBR information + uint8_t partType; + uint32_t relSector; + uint32_t partSize; + + // Fake disk geometry + uint8_t numberOfHeads; + uint8_t sectorsPerTrack; + + // FAT parameters + uint16_t reservedSectors; + uint8_t sectorsPerCluster; + uint32_t fatStart; + uint32_t fatSize; + uint32_t dataStart; + if (!card.begin((ESP_SD_CS_PIN == -1)?SS:ESP_SD_CS_PIN, SD_SCK_MHZ(FREQMZ/_spi_speed_divider))) { + return false; + } + cardSizeBlocks = card.cardSize(); + if (cardSizeBlocks == 0) { + return false; + } + cardCapacityMB = (cardSizeBlocks + 2047)/2048; + if (output) { + String s = "Capacity detected :" + String((1.048576*cardCapacityMB)/1024) + "GB"; + output->printMSG(s.c_str()); + } + if (!eraseCard(card, cache, cardSizeBlocks, output)) { + return false; + } + + if (!formatCard(dataStart, card, cache, numberOfHeads, + sectorsPerTrack, cardSizeBlocks, + sectorsPerCluster, relSector, partSize, partType, + fatSize, fatStart, cardCapacityMB, reservedSectors,output)) { + return false; + } + return true; + } return false; } diff --git a/esp3d/src/modules/filesystem/sd/sdio_esp32.cpp b/esp3d/src/modules/filesystem/sd/sdio_esp32.cpp index 70f572ea..7de3ccf4 100644 --- a/esp3d/src/modules/filesystem/sd/sdio_esp32.cpp +++ b/esp3d/src/modules/filesystem/sd/sdio_esp32.cpp @@ -88,9 +88,12 @@ uint64_t ESP_SD::freeBytes() return (SD_MMC.totalBytes() - SD_MMC.usedBytes()); }; -bool ESP_SD::format() +bool ESP_SD::format(ESP3DOutput * output) { //not available yet + if (output) { + output->printERROR ("Not implemented!"); + } return false; }