/** * This fills the file's currentFATData buffer with the next block of FAT data to write. * If the next block is not the previously predicted block, then the previousFATData * cache is modified to account for this, and the previousFATDirty byte is set to 1. * If the cluster pointer to the beginning of the next block does not reside at * the beginning block boundary, the entire block is read in and the relevant portions * are updated. * * @param file File to fill for. * @return Number of clusters allocated */ uint16_t FAT32_AllocateFATBlock(FAT32FileOpt *file) { uint16_t clusterPointer; uint32_t nextCluster = file->fs->mostRecentCluster + 1; uint16_t numAllocatedClusters = 0; // Check next cluster allocated against the last cluster link if (FATDataToInt32(file->previousFATBlockData + file->previousFATBlockOffset) != nextCluster) { Int32ToFATData(file->previousFATBlockData + file->previousFATBlockOffset, nextCluster); file->previousFATDirty = 1; } clusterPointer = GetClusterFATOffset(file->fs, nextCluster); file->currentFATLBA = GetClusterFATLBA(file->fs, nextCluster); // If the next cluster pointer isn't on a block boundary, read in the current entries in the block if (clusterPointer != 0) { DBG_DATA_printf("Reading in FAT data at LBA=0x%08lx (cluster=0x%08lx, offset=0x%04x)", file->currentFATLBA, nextCluster, clusterPointer); // TODO Make this DMA Friendly if (BLOCK_SIZE != SD_SPI_ReadSingleBlock(file->fs->card, file->currentFATLBA, file->currentFATBlockData)) { DBG_ERR_printf("Error creating file (SD Read error on LBA = 0x%08lx).", file->currentFATLBA); return -1; // Sanity check: Not reading the correct number of bytes } } // Fill in file table data file->nextClusterBegin = file->fs->mostRecentCluster + 1; for (;clusterPointer<BLOCK_SIZE;clusterPointer+=file->fs->clusterPointerSize) { nextCluster++; Int32ToFATData(file->currentFATBlockData+clusterPointer, nextCluster); } file->currentFATBlockOffset = clusterPointer - file->fs->clusterPointerSize; file->nextClusterEnd = nextCluster - 1; // Mark as allocated file->currentFATAllocated = 1; file->currentFATDirty = 1; // Compute new file size numAllocatedClusters = (file->nextClusterEnd - file->nextClusterBegin) + 1; file->size += (uint32_t)numAllocatedClusters * file->fs->bytesPerSector * file->fs->sectorsPerCluster; FAT32_UpdateDirectoryTableEntry(file); // Update FS Information sector file->fs->mostRecentCluster = file->nextClusterEnd; file->fs->numFreeClusters -= numAllocatedClusters; file->fs->fsInfoDirty = 1; DBG_DATA_printf("Allocated clusters 0x%08lx to 0x%08lx (FAT LBA=0x%08lx), file size=%lu)", file->nextClusterBegin, file->nextClusterEnd, file->currentFATLBA, file->size); DBG_DATA_printf("Most recent cluster=0x%08lx, num free clusters=%lu", file->fs->mostRecentCluster, file->fs->numFreeClusters); return numAllocatedClusters; }
/** * Fills the FS buffer with the updated FS Information Sector for FAT32. * @param file File. */ void FAT32_FillFSInformationSector(FAT32FileOpt *file) { uint16_t i = 0; file->fsBuffer[0x00] = 0x52; file->fsBuffer[0x01] = 0x52; file->fsBuffer[0x02] = 0x61; file->fsBuffer[0x03] = 0x41; for (i=0x04;i<0x1e4;i++) { file->fsBuffer[i] = 0x00; } file->fsBuffer[0x1e4] = 0x72; file->fsBuffer[0x1e5] = 0x72; file->fsBuffer[0x1e6] = 0x61; file->fsBuffer[0x1e7] = 0x41; Int32ToFATData(file->fsBuffer + 0x1e8, file->fs->numFreeClusters); Int32ToFATData(file->fsBuffer + 0x1ec, file->fs->mostRecentCluster); for (i=0x1f0;i<0x1fe;i++) { file->fsBuffer[i] = 0x00; } file->fsBuffer[0x1fe] = 0x55; file->fsBuffer[0x1ff] = 0xaa; }
void FAT32_TerminateFATBlock(FS_File *file, uint8_t *data) { uint32_t currCluster = file->currCluster; uint16_t pos = GetClusterFATOffset(file->fs, currCluster); uint16_t end = GetClusterFATOffset(file->fs, file->currFATClusterEnd); file->fs->numFreeClusters -= (end - pos) / file->fs->clusterPointerSize; file->currFATLBA = GetClusterFATLBA(file->fs, currCluster); Int32ToFATData(data+pos, FAT32_CLUSTER_EOC); file->currFATClusterEnd = FAT32_CLUSTER_EOC; file->currFATBlockOffset = pos; file->fs->mostRecentCluster = currCluster; file->fs->fsInfoDirty = 1; pos += file->fs->clusterPointerSize; for (;pos<=end;pos+=file->fs->clusterPointerSize) { Int32ToFATData(data+pos, 0x00000000); } }
void FAT32_AllocateFATBlock(FS_File *file, uint8_t *data) { uint32_t currCluster = file->currCluster; uint16_t pos = GetClusterFATOffset(file->fs, currCluster); file->fs->numFreeClusters -= (file->fs->bytesPerSector - pos) / file->fs->clusterPointerSize; file->currFATLBA = GetClusterFATLBA(file->fs, currCluster); for (;pos<file->fs->bytesPerSector;pos+=file->fs->clusterPointerSize) { currCluster++; Int32ToFATData(data+pos, currCluster); } currCluster--; pos -= file->fs->clusterPointerSize; file->currFATBlockOffset = pos; file->currFATClusterEnd = currCluster; file->fs->mostRecentCluster = currCluster; file->fs->fsInfoDirty = 1; }
void FAT32_Terminate(FAT32FileOpt *file) { DBG_DATA_printf("Terminate: data buffers remaining=%u", file->dataBufferNumFilled); // Wait for all outstanding buffers to be committed to disk. while (file->dataBufferNumFilled > 0 || file->overflowBufferSize > 0) { FAT32_MoveOverflowToData(file); FAT32_Tasks(file); } // If last buffer is partially full, zero the rest of the data and commit it. if (file->dataBufferPos > 0) { uint16_t pos = file->dataBufferPos; uint16_t zeroFill = file->fs->bytesPerSector - file->dataBufferPos; DBG_DATA_printf("Terminate: partial data buffer, position=%u", file->dataBufferPos); for (pos = file->dataBufferPos; pos<file->fs->bytesPerSector; pos++) { file->dataBuffer[file->dataBufferFill][pos] = 0; } file->dataBufferNumFilled++; file->dataBufferFill++; if (file->dataBufferFill >= FAT32_NUM_DATA_BUFFERS) { file->dataBufferFill = 0; } while (file->dataBufferNumFilled > 0) { FAT32_Tasks(file); } file->position -= zeroFill; } DBG_DATA_printf("Terminate: stopping DMA MBW operations"); SD_DMA_MBW_End(); while (SD_DMA_MBW_GetBlockStatus() == 0x00); // Update file size file->size = file->position; FAT32_UpdateDirectoryTableEntry(file); DBG_DATA_printf("Terminate: Updating directory table at LBA=0x%08lx, file size=0x%08lx", file->directoryTableLBA, file->size); SD_SPI_WriteSingleBlock(file->fs->card, file->directoryTableLBA, file->directoryTableBlockData); file->directoryTableDirty = 0; // Update FAT // Deallocate unused clusters uint16_t clusterBegin = GetClusterFATOffset(file->fs, file->currentCluster); DBG_DATA_printf("Terminate: Deallocating previous FAT block starting cluster=0x%08lx, offset=%u", file->currentCluster, clusterBegin); Int32ToFATData(file->previousFATBlockData + clusterBegin, 0x0fffffff); clusterBegin+= file->fs->clusterPointerSize; for (; clusterBegin < file->fs->bytesPerSector; clusterBegin += file->fs->clusterPointerSize) { Int32ToFATData(file->previousFATBlockData + clusterBegin, 0x00000000); } DBG_DATA_printf("Terminate: Updating previous FAT block at LBA=0x%08lx", file->previousFATLBA); SD_SPI_WriteSingleBlock(file->fs->card, file->previousFATLBA, file->previousFATBlockData); // Deallocate the next block if (file->currentFATAllocated && !file->currentFATDirty) { DBG_DATA_printf("Terminate: Deallocating current FAT block"); for (clusterBegin = 0; clusterBegin < file->fs->bytesPerSector; clusterBegin += file->fs->clusterPointerSize) { Int32ToFATData(file->currentFATBlockData + clusterBegin, 0x00000000); } DBG_DATA_printf("Terminate: Updating current FAT block at LBA=0x%08lx", file->currentFATLBA); SD_SPI_WriteSingleBlock(file->fs->card, file->currentFATLBA, file->currentFATBlockData); } // Update FS Information Sector file->fs->mostRecentCluster = file->currentCluster; }
/** * Updates the file's directory table entry with current paramters like size. * @param file File for which the directory table entry is updated. */ void FAT32_UpdateDirectoryTableEntry(FAT32FileOpt *file) { Int32ToFATData(file->directoryTableBlockData + file->directoryTableBlockOffset + 0x1c, file->size); file->directoryTableDirty = 1; }
void FAT32_UpdateDirectoryTableEntry(FS_File *file, uint8_t *data) { Int32ToFATData(data + file->dirTableBlockOffset + 0x1c, file->size); }