//------------------------------------------------------------------------------ // 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; }
//------------------------------------------------------------------------------ // 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; }
int8_t PLEN2::ExternalSD::writeSlot(uint32_t slot, const uint8_t data[], uint8_t write_size) { uint32_t block; uint16_t offset; #if DEBUG PROFILING("ExternalSD::writeSlot()"); #endif if ( (slot >= SLOT_END) || (write_size > SLOT_SIZE) ) { #if DEBUG System::debugSerial().print(F(">>> bad argument! : slot = ")); System::debugSerial().print(slot); System::debugSerial().print(F(", or write_size = ")); System::debugSerial().println(write_size); #endif return -1; } block = 32 + (slot * CHUNK_SIZE) / 512; offset = (slot * CHUNK_SIZE) % 512; #if DEBUG System::debugSerial().print(F("writeSlot slot = ")); System::debugSerial().print(slot); System::debugSerial().print(F(", block = ")); System::debugSerial().print(block); System::debugSerial().print(F(", offset = ")); System::debugSerial().println(offset); #endif if (cacheRawBlock(block, CACHE_FOR_WRITE)) { memcpy(&mCacheBuf[offset], data, write_size); cacheFlush(); return 0; } return -1; }
int8_t PLEN2::ExternalSD::readSlot(uint32_t slot, uint8_t data[], uint8_t read_size) { uint32_t block; uint16_t offset; #if DEBUG PROFILING("ExternalSD::readSlot()"); #endif if ( (slot >= SLOT_END) || (read_size > SLOT_SIZE) ) { #if DEBUG System::debugSerial().print(F(">>> bad argument! : slot = ")); System::debugSerial().print(slot); System::debugSerial().print(F(", or read_size = ")); System::debugSerial().println(read_size); #endif return -1; } block = 32 + (slot * CHUNK_SIZE) / 512; offset = (slot * CHUNK_SIZE) % 512; #if DEBUG System::debugSerial().print(F("readSlot slot = ")); System::debugSerial().print(slot); System::debugSerial().print(F(", block = ")); System::debugSerial().print(block); System::debugSerial().print(F(", offset = ")); System::debugSerial().println(offset); #endif if (cacheRawBlock(block, CACHE_FOR_READ)) { memcpy(data, &mCacheBuf[offset], read_size); return read_size; } return -1; }
/** * 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) { DEBUG_SDFAT_PRINTLN("Error: SdVolume::init() MBR"); return false; } if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) { DEBUG_SDFAT_PRINTLN("Error: SdVolume::init() 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 DEBUG_SDFAT_PRINTLN("Error: SdVolume::init() Invalid partition"); return false; } volumeStartBlock = p->firstSector; } if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) { DEBUG_SDFAT_PRINTLN("Error: SdVolume::init() Cache for read2"); 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 DEBUG_SDFAT_PRINTLN("Error: SdVolume::init() invalid 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; DEBUG_SDFAT_PRINTLN("Error: SdVolume::init() not power of 2"); } } 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; }