/** * Copyright (c) 2011-2022 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "FatLib.h" #ifndef DOXYGEN_SHOULD_SKIP_THIS //------------------------------------------------------------------------------ static uint16_t getLfnChar(DirLfn_t* ldir, uint8_t i) { if (i < 5) { return getLe16(ldir->unicode1 + 2 * i); } else if (i < 11) { return getLe16(ldir->unicode2 + 2 * (i - 5)); } else if (i < 13) { return getLe16(ldir->unicode3 + 2 * (i - 11)); } return 0; } //------------------------------------------------------------------------------ static void printHex(print_t* pr, uint8_t h) { if (h < 16) { pr->write('0'); } pr->print(h, HEX); } //------------------------------------------------------------------------------ static void printHex(print_t* pr, uint8_t w, uint16_t h) { char buf[5]; char* ptr = buf + sizeof(buf); *--ptr = 0; for (uint8_t i = 0; i < w; i++) { char c = h & 0XF; *--ptr = c < 10 ? c + '0' : c + 'A' - 10; h >>= 4; } pr->write(ptr); } //------------------------------------------------------------------------------ static void printHex(print_t* pr, uint16_t val) { bool space = true; for (uint8_t i = 0; i < 4; i++) { uint8_t h = (val >> (12 - 4 * i)) & 15; if (h || i == 3) { space = false; } if (space) { pr->write(' '); } else { pr->print(h, HEX); } } } //------------------------------------------------------------------------------ static void printHex(print_t* pr, uint32_t val) { bool space = true; for (uint8_t i = 0; i < 8; i++) { uint8_t h = (val >> (28 - 4 * i)) & 15; if (h || i == 7) { space = false; } if (space) { pr->write(' '); } else { pr->print(h, HEX); } } } //------------------------------------------------------------------------------ template static void printHexLn(print_t* pr, Uint val) { printHex(pr, val); pr->println(); } //------------------------------------------------------------------------------ static bool printFatDir(print_t* pr, DirFat_t* dir) { DirLfn_t* ldir = reinterpret_cast(dir); if (!dir->name[0]) { pr->println(F("Unused")); return false; } else if (dir->name[0] == FAT_NAME_DELETED) { pr->println(F("Deleted")); } else if (isFatFileOrSubdir(dir)) { pr->print(F("SFN: ")); for (uint8_t i = 0; i < 11; i++) { printHex(pr, dir->name[i]); pr->write(' '); } pr->write(' '); pr->write(dir->name, 11); pr->println(); pr->print(F("attributes: 0X")); printHexLn(pr, dir->attributes); pr->print(F("caseFlags: 0X")); printHexLn(pr, dir->caseFlags); uint32_t fc = ((uint32_t)getLe16(dir->firstClusterHigh) << 16) | getLe16(dir->firstClusterLow); pr->print(F("firstCluster: ")); pr->println(fc, HEX); pr->print(F("fileSize: ")); pr->println(getLe32(dir->fileSize)); } else if (isFatLongName(dir)) { pr->print(F("LFN: ")); for (uint8_t i = 0; i < 13; i++) { uint16_t c = getLfnChar(ldir, i); if (15 < c && c < 128) { pr->print(static_cast(c)); } else { pr->print("0X"); pr->print(c, HEX); } pr->print(' '); } pr->println(); pr->print(F("order: 0X")); pr->println(ldir->order, HEX); pr->print(F("attributes: 0X")); pr->println(ldir->attributes, HEX); pr->print(F("checksum: 0X")); pr->println(ldir->checksum, HEX); } else { pr->println(F("Other")); } pr->println(); return true; } //------------------------------------------------------------------------------ void FatFile::dmpFile(print_t* pr, uint32_t pos, size_t n) { char text[17]; text[16] = 0; if (n >= 0XFFF0) { n = 0XFFF0; } if (!seekSet(pos)) { return; } for (size_t i = 0; i <= n; i++) { if ((i & 15) == 0) { if (i) { pr->write(' '); pr->write(text); if (i == n) { break; } } pr->write('\r'); pr->write('\n'); if (i >= n) { break; } printHex(pr, 4, i); pr->write(' '); } int16_t h = read(); if (h < 0) { break; } pr->write(' '); printHex(pr, 2, h); text[i & 15] = ' ' <= h && h < 0X7F ? h : '.'; } pr->write('\r'); pr->write('\n'); } //------------------------------------------------------------------------------ bool FatPartition::dmpDirSector(print_t* pr, uint32_t sector) { DirFat_t dir[16]; if (!cacheSafeRead(sector, reinterpret_cast(dir))) { pr->println(F("dmpDir failed")); return false; } for (uint8_t i = 0; i < 16; i++) { if (!printFatDir(pr, dir + i)) { return false; } } return true; } //------------------------------------------------------------------------------ bool FatPartition::dmpRootDir(print_t* pr, uint32_t n) { uint32_t sector; if (fatType() == 16) { sector = rootDirStart(); } else if (fatType() == 32) { sector = clusterStartSector(rootDirStart()); } else { pr->println(F("dmpRootDir failed")); return false; } return dmpDirSector(pr, sector + n); } //------------------------------------------------------------------------------ void FatPartition::dmpSector(print_t* pr, uint32_t sector, uint8_t bits) { uint8_t data[FatPartition::m_bytesPerSector]; if (!cacheSafeRead(sector, data)) { pr->println(F("dmpSector failed")); return; } for (uint16_t i = 0; i < m_bytesPerSector;) { if (i % 32 == 0) { if (i) { pr->println(); } printHex(pr, i); } pr->write(' '); if (bits == 32) { printHex(pr, *reinterpret_cast(data + i)); i += 4; } else if (bits == 16) { printHex(pr, *reinterpret_cast(data + i)); i += 2; } else { printHex(pr, data[i++]); } } pr->println(); } //------------------------------------------------------------------------------ void FatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) { uint16_t nf = fatType() == 16 ? 256 : fatType() == 32 ? 128 : 0; if (nf == 0) { pr->println(F("Invalid fatType")); return; } pr->println(F("FAT:")); uint32_t sector = m_fatStartSector + start; uint32_t cluster = nf * start; for (uint32_t i = 0; i < count; i++) { uint8_t* pc = fatCachePrepare(sector + i, FsCache::CACHE_FOR_READ); if (!pc) { pr->println(F("cache read failed")); return; } for (size_t k = 0; k < nf; k++) { if (0 == cluster % 8) { if (k) { pr->println(); } printHex(pr, cluster); } cluster++; pr->write(' '); uint32_t v = fatType() == 32 ? getLe32(pc + 4 * k) : getLe16(pc + 2 * k); printHex(pr, v); } pr->println(); } } #endif // DOXYGEN_SHOULD_SKIP_THIS