mirror of
https://github.com/esp8266/Arduino.git
synced 2025-07-23 08:45:22 +03:00
This includes empty stubs for most core Arduino functions. Need to actually implement all those digital reads writes whatever. Need to prebuild toolchains (xtensa-elf-lx106) for 3 platforms and put them on some download server. Need to do the same with esptool. Need to fix 0x40000 binary generation and add correct upload commands. Maybe even implement uploads over WiFi.
296 lines
9.6 KiB
C++
296 lines
9.6 KiB
C++
/* Arduino SdFat Library
|
|
* Copyright (C) 2009 by William Greiman
|
|
*
|
|
* This file is part of the Arduino SdFat Library
|
|
*
|
|
* This Library is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with the Arduino SdFat Library. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "SdFat.h"
|
|
//------------------------------------------------------------------------------
|
|
// raw block cache
|
|
// init cacheBlockNumber_to invalid SD block number
|
|
uint32_t SdVolume::cacheBlockNumber_ = 0XFFFFFFFF;
|
|
cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card
|
|
Sd2Card* SdVolume::sdCard_; // pointer to SD card object
|
|
uint8_t SdVolume::cacheDirty_ = 0; // cacheFlush() will write block if true
|
|
uint32_t SdVolume::cacheMirrorBlock_ = 0; // mirror block for second FAT
|
|
//------------------------------------------------------------------------------
|
|
// find a contiguous group of clusters
|
|
uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
|
|
// start of group
|
|
uint32_t bgnCluster;
|
|
|
|
// flag to save place to start next search
|
|
uint8_t setStart;
|
|
|
|
// set search start cluster
|
|
if (*curCluster) {
|
|
// try to make file contiguous
|
|
bgnCluster = *curCluster + 1;
|
|
|
|
// don't save new start location
|
|
setStart = false;
|
|
} else {
|
|
// start at likely place for free cluster
|
|
bgnCluster = allocSearchStart_;
|
|
|
|
// save next search start if one cluster
|
|
setStart = 1 == count;
|
|
}
|
|
// end of group
|
|
uint32_t endCluster = bgnCluster;
|
|
|
|
// last cluster of FAT
|
|
uint32_t fatEnd = clusterCount_ + 1;
|
|
|
|
// search the FAT for free clusters
|
|
for (uint32_t n = 0;; n++, endCluster++) {
|
|
// can't find space checked all clusters
|
|
if (n >= clusterCount_) return false;
|
|
|
|
// past end - start from beginning of FAT
|
|
if (endCluster > fatEnd) {
|
|
bgnCluster = endCluster = 2;
|
|
}
|
|
uint32_t f;
|
|
if (!fatGet(endCluster, &f)) return false;
|
|
|
|
if (f != 0) {
|
|
// cluster in use try next cluster as bgnCluster
|
|
bgnCluster = endCluster + 1;
|
|
} else if ((endCluster - bgnCluster + 1) == count) {
|
|
// done - found space
|
|
break;
|
|
}
|
|
}
|
|
// mark end of chain
|
|
if (!fatPutEOC(endCluster)) return false;
|
|
|
|
// link clusters
|
|
while (endCluster > bgnCluster) {
|
|
if (!fatPut(endCluster - 1, endCluster)) return false;
|
|
endCluster--;
|
|
}
|
|
if (*curCluster != 0) {
|
|
// connect chains
|
|
if (!fatPut(*curCluster, bgnCluster)) return false;
|
|
}
|
|
// return first cluster number to caller
|
|
*curCluster = bgnCluster;
|
|
|
|
// remember possible next free cluster
|
|
if (setStart) allocSearchStart_ = bgnCluster + 1;
|
|
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
uint8_t SdVolume::cacheFlush(void) {
|
|
if (cacheDirty_) {
|
|
if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) {
|
|
return false;
|
|
}
|
|
// mirror FAT tables
|
|
if (cacheMirrorBlock_) {
|
|
if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) {
|
|
return false;
|
|
}
|
|
cacheMirrorBlock_ = 0;
|
|
}
|
|
cacheDirty_ = 0;
|
|
}
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
uint8_t SdVolume::cacheRawBlock(uint32_t blockNumber, uint8_t action) {
|
|
if (cacheBlockNumber_ != blockNumber) {
|
|
if (!cacheFlush()) return false;
|
|
if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) return false;
|
|
cacheBlockNumber_ = blockNumber;
|
|
}
|
|
cacheDirty_ |= action;
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
// cache a zero block for blockNumber
|
|
uint8_t SdVolume::cacheZeroBlock(uint32_t blockNumber) {
|
|
if (!cacheFlush()) return false;
|
|
|
|
// loop take less flash than memset(cacheBuffer_.data, 0, 512);
|
|
for (uint16_t i = 0; i < 512; i++) {
|
|
cacheBuffer_.data[i] = 0;
|
|
}
|
|
cacheBlockNumber_ = blockNumber;
|
|
cacheSetDirty();
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
// return the size in bytes of a cluster chain
|
|
uint8_t SdVolume::chainSize(uint32_t cluster, uint32_t* size) const {
|
|
uint32_t s = 0;
|
|
do {
|
|
if (!fatGet(cluster, &cluster)) return false;
|
|
s += 512UL << clusterSizeShift_;
|
|
} while (!isEOC(cluster));
|
|
*size = s;
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
// Fetch a FAT entry
|
|
uint8_t SdVolume::fatGet(uint32_t cluster, uint32_t* value) const {
|
|
if (cluster > (clusterCount_ + 1)) return false;
|
|
uint32_t lba = fatStartBlock_;
|
|
lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7;
|
|
if (lba != cacheBlockNumber_) {
|
|
if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false;
|
|
}
|
|
if (fatType_ == 16) {
|
|
*value = cacheBuffer_.fat16[cluster & 0XFF];
|
|
} else {
|
|
*value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK;
|
|
}
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
// Store a FAT entry
|
|
uint8_t SdVolume::fatPut(uint32_t cluster, uint32_t value) {
|
|
// error if reserved cluster
|
|
if (cluster < 2) return false;
|
|
|
|
// error if not in FAT
|
|
if (cluster > (clusterCount_ + 1)) return false;
|
|
|
|
// calculate block address for entry
|
|
uint32_t lba = fatStartBlock_;
|
|
lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7;
|
|
|
|
if (lba != cacheBlockNumber_) {
|
|
if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false;
|
|
}
|
|
// store entry
|
|
if (fatType_ == 16) {
|
|
cacheBuffer_.fat16[cluster & 0XFF] = value;
|
|
} else {
|
|
cacheBuffer_.fat32[cluster & 0X7F] = value;
|
|
}
|
|
cacheSetDirty();
|
|
|
|
// mirror second FAT
|
|
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
// free a cluster chain
|
|
uint8_t SdVolume::freeChain(uint32_t cluster) {
|
|
// clear free cluster location
|
|
allocSearchStart_ = 2;
|
|
|
|
do {
|
|
uint32_t next;
|
|
if (!fatGet(cluster, &next)) return false;
|
|
|
|
// free cluster
|
|
if (!fatPut(cluster, 0)) return false;
|
|
|
|
cluster = next;
|
|
} while (!isEOC(cluster));
|
|
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Initialize a FAT volume.
|
|
*
|
|
* \param[in] dev The SD card where the volume is located.
|
|
*
|
|
* \param[in] part The partition to be used. Legal values for \a part are
|
|
* 1-4 to use the corresponding partition on a device formatted with
|
|
* a MBR, Master Boot Record, or zero if the device is formatted as
|
|
* a super floppy with the FAT boot sector in block zero.
|
|
*
|
|
* \return The value one, true, is returned for success and
|
|
* the value zero, false, is returned for failure. Reasons for
|
|
* failure include not finding a valid partition, not finding a valid
|
|
* FAT file system in the specified partition or an I/O error.
|
|
*/
|
|
uint8_t SdVolume::init(Sd2Card* dev, uint8_t part) {
|
|
uint32_t volumeStartBlock = 0;
|
|
sdCard_ = dev;
|
|
// if part == 0 assume super floppy with FAT boot sector in block zero
|
|
// if part > 0 assume mbr volume with partition table
|
|
if (part) {
|
|
if (part > 4)return false;
|
|
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false;
|
|
part_t* p = &cacheBuffer_.mbr.part[part-1];
|
|
if ((p->boot & 0X7F) !=0 ||
|
|
p->totalSectors < 100 ||
|
|
p->firstSector == 0) {
|
|
// not a valid partition
|
|
return false;
|
|
}
|
|
volumeStartBlock = p->firstSector;
|
|
}
|
|
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false;
|
|
bpb_t* bpb = &cacheBuffer_.fbs.bpb;
|
|
if (bpb->bytesPerSector != 512 ||
|
|
bpb->fatCount == 0 ||
|
|
bpb->reservedSectorCount == 0 ||
|
|
bpb->sectorsPerCluster == 0) {
|
|
// not valid FAT volume
|
|
return false;
|
|
}
|
|
fatCount_ = bpb->fatCount;
|
|
blocksPerCluster_ = bpb->sectorsPerCluster;
|
|
|
|
// determine shift that is same as multiply by blocksPerCluster_
|
|
clusterSizeShift_ = 0;
|
|
while (blocksPerCluster_ != (1 << clusterSizeShift_)) {
|
|
// error if not power of 2
|
|
if (clusterSizeShift_++ > 7) return false;
|
|
}
|
|
blocksPerFat_ = bpb->sectorsPerFat16 ?
|
|
bpb->sectorsPerFat16 : bpb->sectorsPerFat32;
|
|
|
|
fatStartBlock_ = volumeStartBlock + bpb->reservedSectorCount;
|
|
|
|
// count for FAT16 zero for FAT32
|
|
rootDirEntryCount_ = bpb->rootDirEntryCount;
|
|
|
|
// directory start for FAT16 dataStart for FAT32
|
|
rootDirStart_ = fatStartBlock_ + bpb->fatCount * blocksPerFat_;
|
|
|
|
// data start for FAT16 and FAT32
|
|
dataStartBlock_ = rootDirStart_ + ((32 * bpb->rootDirEntryCount + 511)/512);
|
|
|
|
// total blocks for FAT16 or FAT32
|
|
uint32_t totalBlocks = bpb->totalSectors16 ?
|
|
bpb->totalSectors16 : bpb->totalSectors32;
|
|
// total data blocks
|
|
clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
|
|
|
|
// divide by cluster size to get cluster count
|
|
clusterCount_ >>= clusterSizeShift_;
|
|
|
|
// FAT type is determined by cluster count
|
|
if (clusterCount_ < 4085) {
|
|
fatType_ = 12;
|
|
} else if (clusterCount_ < 65525) {
|
|
fatType_ = 16;
|
|
} else {
|
|
rootDirStart_ = bpb->fat32RootCluster;
|
|
fatType_ = 32;
|
|
}
|
|
return true;
|
|
}
|