/** * 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; }
/** * Moves data from the overflow buffer to the main data buffer. * @param file */ void FAT32_MoveOverflowToData(FAT32FileOpt *file) { while (file->overflowBufferSize > 0) { if (file->dataBufferNumFilled < FAT32_NUM_DATA_BUFFERS) { // if data buffers are available fs_length_t writeLength = file->overflowBufferSize; if (writeLength > FAT32_OVERFLOW_BUFFER_SIZE - file->overflowBufferBegin) { writeLength = FAT32_OVERFLOW_BUFFER_SIZE - file->overflowBufferBegin; } if (writeLength > BLOCK_SIZE - file->dataBufferPos) { writeLength = BLOCK_SIZE - file->dataBufferPos; } memcpy(file->dataBuffer[file->dataBufferFill] + file->dataBufferPos, file->overflowBuffer + file->overflowBufferBegin, writeLength); file->overflowBufferSize -= writeLength; file->overflowBufferBegin += writeLength; if (file->overflowBufferBegin >= FAT32_OVERFLOW_BUFFER_SIZE) { file->overflowBufferBegin = 0; } file->dataBufferPos += writeLength; DBG_DATA_printf("Copied %u bytes from overflow into DMA buffer %u, DMA size=%u, overflow size = %u", writeLength, file->dataBufferFill, file->dataBufferPos, file->overflowBufferSize); if (file->dataBufferPos >= BLOCK_SIZE) { file->dataBufferPos = 0; file->dataBufferNumFilled++; file->dataBufferFill++; if (file->dataBufferFill >= FAT32_NUM_DATA_BUFFERS) { file->dataBufferFill = 0; } DBG_DATA_printf("Advanced to DMA buffer %u, numDataBuffers=%u", file->dataBufferFill, file->dataBufferNumFilled); } } else { return; } } }
fs_result_t DataloggerFile_Tasks(DataloggerFile *dlgFile) { // Check if there is data to write if (dlgFile->file->state != FILE_Uninitialized && dlgFile->file->state != FILE_Creating) { while (dlgFile->bufferFree != dlgFile->bufferSize) { fs_length_t writeLength; if (dlgFile->writePos > dlgFile->readPos) { writeLength = dlgFile->writePos - dlgFile->readPos; } else { writeLength = dlgFile->bufferSize - dlgFile->readPos; } writeLength = FS_WriteFile(dlgFile->file, dlgFile->buffer + dlgFile->readPos, writeLength); if (writeLength > 0) { dlgFile->readPos += writeLength; if (dlgFile->readPos >= dlgFile->bufferSize) { dlgFile->readPos = 0; } dlgFile->bufferFree += writeLength; DBG_SPAM_printf("DLGFile: buffer->card %u bytes, bufFree = %u", writeLength, dlgFile->bufferFree); } else { // No data written (no filesystem file buffer left), we're done break; } } } // Check if we want to close the file if (dlgFile->requestClose && !dlgFile->file->requestClose && dlgFile->bufferFree == dlgFile->bufferSize) { DBG_DATA_printf("DLGFile: Request file close"); FS_RequestFileClose(dlgFile->file); } if (T1CON == 0x00) { DBG_ERR_printf("T1CON = 0"); T1CON = 0x8002; } // Do filesystem tasks if (dlgFile->file->state != FILE_Uninitialized && dlgFile->file->state != FILE_Creating) { return FS_FileTasks(dlgFile->file); } else { return FS_UNREADY; } }
/** * Writes /a data into the file buffers. * @param file File. * @param data Pointer to the beginning of the data to write. * @param length Length, in bytes, of the data to write. * @return Number of bytes written to the buffer. Usually the length of the input data, * unless the buffers are full. */ fs_length_t FAT32_WriteBuffer(FAT32FileOpt *file, uint8_t *data, fs_length_t length) { fs_length_t remaining = length; if (file->overflowBufferSize > 0 && file->dataBufferNumFilled < FAT32_NUM_DATA_BUFFERS) { FAT32_MoveOverflowToData(file); } while (remaining > 0) { if (file->dataBufferNumFilled >= FAT32_NUM_DATA_BUFFERS) { // All DMA buffers full, go to overflow buffer if (file->overflowBufferSize >= FAT32_OVERFLOW_BUFFER_SIZE) { // Overflow buffer is full - operation fails to write all data return length - remaining; } else { // Overflow buffer has positions available fs_length_t writeLength = remaining; if (remaining > FAT32_OVERFLOW_BUFFER_SIZE - file->overflowBufferSize) { writeLength = FAT32_OVERFLOW_BUFFER_SIZE - file->overflowBufferSize; } FAT32_WriteOverflowBuffer(file, data, writeLength); remaining -= writeLength; data += writeLength; } } else { // Empty positions available in DMA buffers, fill those fs_length_t writeLength = remaining; if (remaining > BLOCK_SIZE - file->dataBufferPos) { writeLength = BLOCK_SIZE - file->dataBufferPos; } memcpy(file->dataBuffer[file->dataBufferFill] + file->dataBufferPos, data, writeLength); file->dataBufferPos += writeLength; if (file->dataBufferPos >= BLOCK_SIZE) { file->dataBufferPos = 0; file->dataBufferNumFilled++; file->dataBufferFill++; if (file->dataBufferFill >= FAT32_NUM_DATA_BUFFERS) { file->dataBufferFill = 0; } DBG_DATA_printf("Advanced to DMA buffer %u, numDataBuffers=%u", file->dataBufferFill, file->dataBufferNumFilled); } remaining -= writeLength; data += writeLength; } } return length; }
/** * Initializes FAT data for a new file. * This fills in the first FAT block and updates the directory table entry. * No data is committed not is data moved to the FS buffer - that must be done separately. * * @pre The file is new (just created). * * @param file File to initialize. * @return Status. * @retval 0 Success. * @retval -1 Failure. */ int8_t FAT32_InitializeFileFAT(FAT32FileOpt *file) { // Fill the first FAT block FAT32_AllocateFATBlock(file); // Use the newly allocated FAT block FAT32_SwitchNextBlock(file); // Fill out file parameters using allocated data file->startCluster = file->currentCluster; Int32ToFATSplitData(file->directoryTableBlockData + file->directoryTableBlockOffset + 0x14, file->directoryTableBlockData + file->directoryTableBlockOffset + 0x1a, file->startCluster); FAT32_UpdateDirectoryTableEntry(file); DBG_DATA_printf("File initialized (cluster=0x%08lx, block=0x%08lx, size=%lu)", file->currentCluster, file->currentLBA, file->size); }
int main(void) { uint16_t i = 0; OscInit(); AnalogInit(); OutputInit(); PPSInit(); Timing_Init(); UART_DMA_Init(); UI_LED_Initialize(); for (i=0; i<UI_LED_Count; i++) { UI_LED_SetState(UI_LED_List[i], LED_On); } UI_LED_Update(); DBG_printf("\r\n"); DBG_printf("\2330;36mCalsol Datalogger v%u.%u (alpha)\23337m", VERSION_MAJ, VERSION_MIN); DBG_printf("\23336m Built %s %s with C30 ver %i\23337m", __DATE__, __TIME__, __C30_VERSION__); DBG_DATA_printf("\23336mDevice reset:%s%s%s%s%s%s%s%s\23337m", (RCONbits.TRAPR? " Trap" : ""), (RCONbits.IOPUWR? " IllegalOpcode/UninitializedW" : ""), (RCONbits.CM? " ConfigMismatch" : ""), (RCONbits.EXTR? " ExternalReset" : ""), (RCONbits.SWR? " SoftwareReset" : ""), (RCONbits.WDTO? " WatchdogTimeout" : ""), (RCONbits.BOR? " BrownOutReset" : ""), (RCONbits.POR? " PowerOnReset" : "") ); ECAN_Init(); ECAN_Config(); C1FCTRLbits.FSA = 4; // FIFO starts C1FEN1 = 0; ECAN_SetStandardFilter(0, 0x00, 0, 15); ECAN_SetStandardMask(0, 0x00); ECAN_SetMode(ECAN_MODE_OPERATE); ECAN_SetupDMA(); UI_Switch_Update(); if (UI_Switch_GetTest()) { DBG_printf("Entering test mode"); UI_LED_SetState(&UI_LED_Fault, LED_Blink); while (UI_Switch_GetTest()) { UI_LED_Update(); UI_Switch_Update(); } UI_LED_SetState(&UI_LED_Fault, LED_Off); UI_LED_Update(); } for (i=0; i<UI_LED_Count; i++) { UI_LED_SetState(UI_LED_List[i], LED_Off); } DBG_printf("Initialization complete"); Datalogger_Init(); while(1) { Datalogger_Loop(); } }
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; }
void FAT32_Tasks(FAT32FileOpt *file) { if (file->currentOperation == FILE_OP_None) { // Check if there is a queued command - and if so, start it if (file->nextOperation == FILE_OP_WritingDataIdle) { SD_DMA_MBW_Start(file->fs->card, file->currentLBA); file->currentOperation = FILE_OP_WritingDataIdle; DBG_SPAM_printf("file->currentOperation going to FILE_OP_WritingDataIdle (queued)"); } else if (file->nextOperation == FILE_OP_WritingDirectoryTable) { SD_DMA_MBW_Start(file->fs->card, file->directoryTableLBA); SD_DMA_MBW_SendBlock(2); file->currentOperation = FILE_OP_WritingDirectoryTable; DBG_SPAM_printf("file->currentOperation going to FILE_OP_WritingDirectoryTable (queued)"); } else if (file->nextOperation == FILE_OP_WritingFAT) { SD_DMA_MBW_Start(file->fs->card, file->currentFATLBA); SD_DMA_MBW_SendBlock(2); file->currentOperation = FILE_OP_WritingFAT; DBG_SPAM_printf("file->currentOperation going to FILE_OP_WritingFAT (queued)"); } else if (file->nextOperation == FILE_OP_WritingFSInformation) { SD_DMA_MBW_Start(file->fs->card, file->fs->FS_info_LBA); SD_DMA_MBW_SendBlock(2); file->currentOperation = FILE_OP_WritingFSInformation; DBG_SPAM_printf("file->currentOperation going to FILE_OP_WritingFSInformation (queued)"); } // Check if we passed the allocation boundaries if (file->currentCluster > file->currentClusterEnd) { // Check if more bookkeeping needs to be done if (!file->currentFATAllocated) { FAT32_AllocateFATBlock(file); FAT32_FillCurrentFATBlock(file); SD_DMA_MBW_Start(file->fs->card, file->currentFATLBA); SD_DMA_MBW_SendBlock(2); file->currentOperation = FILE_OP_WritingFAT; DBG_SPAM_printf("file->currentOperation going to FILE_OP_WritingFAT (end of allocation)"); } else if (file->currentFATDirty) { FAT32_FillCurrentFATBlock(file); SD_DMA_MBW_Start(file->fs->card, file->currentFATLBA); SD_DMA_MBW_SendBlock(2); file->currentOperation = FILE_OP_WritingFAT; DBG_SPAM_printf("file->currentOperation going to FILE_OP_WritingFAT (end of allocation)"); } else if (file->directoryTableDirty) { FAT32_FillDirectoryTableBlock(file); SD_DMA_MBW_Start(file->fs->card, file->directoryTableLBA); SD_DMA_MBW_SendBlock(2); file->currentOperation = FILE_OP_WritingDirectoryTable; DBG_SPAM_printf("file->currentOperation going to FILE_OP_WritingDirectoryTable (end of allocation)"); } else if (file->fs->fsInfoDirty) { FAT32_FillFSInformationSector(file); SD_DMA_MBW_Start(file->fs->card, file->fs->FS_info_LBA); SD_DMA_MBW_SendBlock(2); file->currentOperation = FILE_OP_WritingFSInformation; DBG_SPAM_printf("file->currentOperation going to FILE_OP_WritingFSInformation (end of allocation)"); } else { FAT32_SwitchNextBlock(file); DBG_DATA_printf("Switching to next block"); } } else { SD_DMA_MBW_Start(file->fs->card, file->currentLBA); file->currentOperation = FILE_OP_WritingDataIdle; } } else if (file->currentOperation == FILE_OP_WritingDataIdle) { // Check the current SD DMA state if (SD_DMA_MBW_GetIdle()) { // Check is we have passed the allocation boundaries if (file->currentCluster > file->currentClusterEnd) { SD_DMA_MBW_End(); file->currentOperation = FILE_OP_MultipleBlockWriteTerminate; file->nextOperation = FILE_OP_None; DBG_SPAM_printf("file->currentOperation going to FILE_OP_MultipleBlockWriteTerminate (allocation exceeded)"); } else { // Check is there is a new block ready to send if (file->dataBufferNumFilled > 0) { DBG_SPAM_printf("Writing data block at LBA=0x%08lx, cluster=0x%08lx, allocated end=0x%08lx, buffer=%u", file->currentLBA, file->currentCluster, file->currentClusterEnd, file->dataBufferWrite); // Send the new block SD_DMA_MBW_SendBlock(file->dataBufferWrite); file->currentOperation = FILE_OP_WritingData; } else { // No data available, check if we have bookkeeping to do // TODO Terminate block write mid-write and do bookkeeping } } } } else if (file->currentOperation == FILE_OP_WritingData) { uint8_t status = SD_DMA_MBW_GetBlockStatus(); if (status != 0x00) { // Current block is done, advance the data buffers DBG_SPAM_printf("SD_DMA_MBW_GetBlockStatus returned 0x%02x", status); file->dataBufferWrite++; if (file->dataBufferWrite >= FAT32_NUM_DATA_BUFFERS) { file->dataBufferWrite = 0; } file->dataBufferNumFilled--; file->currentLBA++; file->currentClusterLBAOffset++; if (file->currentClusterLBAOffset >= file->fs->sectorsPerCluster) { file->currentCluster++; file->currentClusterLBAOffset = 0; } file->position += file->fs->bytesPerSector; file->currentOperation = FILE_OP_WritingDataIdle; } } else if (file->currentOperation == FILE_OP_WritingDirectoryTable || file->currentOperation == FILE_OP_WritingFAT || file->currentOperation == FILE_OP_WritingFSInformation) { uint8_t status = SD_DMA_MBW_GetBlockStatus(); if (status != 0x00) { // Block complete, terminate command SD_DMA_MBW_End(); if (file->currentOperation == FILE_OP_WritingDirectoryTable) { file->directoryTableDirty = 0; } else if (file->currentOperation == FILE_OP_WritingFAT) { file->currentFATDirty = 0; } else if (file->currentOperation == FILE_OP_WritingFSInformation) { file->fs->fsInfoDirty = 0; } file->currentOperation = FILE_OP_MultipleBlockWriteTerminate; file->nextOperation = FILE_OP_None; DBG_SPAM_printf("file->currentOperation going to FILE_OP_MultipleBlockWriteTerminate (operation complete)"); } else { DBG_SPAM_printf("SD_DMA_MBW_GetBlockStatus returned 0x%02x", status); } } else if (file->currentOperation == FILE_OP_MultipleBlockWriteTerminate) { uint8_t status = SD_DMA_MBW_GetBlockStatus(); if (status != 0x00) { file->currentOperation = FILE_OP_None; DBG_SPAM_printf("file->currentOperation going to FILE_OP_None"); } else { DBG_SPAM_printf("SD_DMA_MBW_GetBlockStatus returned 0x%02x", status); } } }
/** * Creates a file (creates the directory entry for a file) for optimized write. * After this function returns successfully, it should be possible to do optimized * writes on the file starting at the beginning. * No checks are done against duplicate file name, and no clusters are allocated. * File space is allocated during write operations. * * @param[in] fs Filesystem structure. * @param[in] dir Directory structure. * @param[out] fileOpt Output optimized file structure. * @param[in] name File name, up to 8 characters. * @param[in] ext File extension, up to 3 characters. * @retval 1 Success * @retval -1 Error creating file * @retval -2 SD Card Error * @retval -128 General error */ int8_t FAT32_CreateFileOpt(FAT32FS *fs, FAT32Directory *dir, FAT32FileOpt *file, char *name, char *ext) { uint32_t currentCluster = dir->directoryTableAvailableCluster; fs_addr_t currentLBA = dir->directoryTableAvailableLBA; uint8_t clusterOffset = dir->directoryTableAvailableClusterOffset; // block number within the cluster fs_length_t iii = 0; DBG_DATA_printf("Starting cluster = 0x%08lx", currentCluster); // Search for an empty file while (1) { if (BLOCK_SIZE != SD_SPI_ReadSingleBlock(fs->card, currentLBA, file->directoryTableBlockData)) { DBG_printf("Error creating file (SD Read error on LBA = 0x%08lx).", currentLBA); return -2; // Sanity check: Not reading the correct number of bytes } DBG_DATA_printf("Read Directory Table LBA = 0x%08lx", currentLBA) // Search Directory Table for desired entry for (iii = 0; iii < fs->bytesPerSector; iii += 32) { DBG_SPAM_printf("Searching record '%8.8s.%3.3s'.", file->directoryTableBlockData + iii, file->directoryTableBlockData + iii + 8); if (file->directoryTableBlockData[iii] == 0x00 || file->directoryTableBlockData[iii] == 0xe5) { // Available entry DBG_printf("Available entry found."); // Update directory structure with new end dir->directoryTableAvailableCluster = currentCluster; dir->directoryTableAvailableClusterOffset = clusterOffset; dir->directoryTableAvailableLBA = currentLBA; FATCreateDirectoryTableEntry(file->directoryTableBlockData+iii, name, ext); // Fill out file structure strncpy((char *) file->name, (char*)file->directoryTableBlockData+iii, 8); strncpy((char *) file->ext, (char*)file->directoryTableBlockData+iii+8, 3); file->fs = fs; file->directoryTableLBA = currentLBA; file->directoryTableBlockOffset = iii; file->directoryTableDirty = 0; file->startCluster = 0; file->size = 0; file->previousFATBlockData = file->previousFATData; file->currentFATBlockData = file->currentFATData; file->previousFATBlockOffset = 0; file->previousFATDirty = 0; file->previousFileSize = 0; file->currentCluster = 0; file->currentLBA = 0; file->position = 0; file->currentOperation = FILE_OP_None; file->nextOperation = FILE_OP_WritingDataIdle; file->dataBuffer[0] = SD_DMA_GetBuffer(0); if (file->dataBuffer[0] == NULL) { DBG_ERR_printf("Error allocating DMA buffer 0"); return -128; } file->dataBuffer[1] = SD_DMA_GetBuffer(1); if (file->dataBuffer[1] == NULL) { DBG_ERR_printf("Error allocating DMA buffer 1"); return -128; } file->fsBuffer = SD_DMA_GetBuffer(2); if (file->fs == NULL) { DBG_ERR_printf("Error allocating DMA FS buffer"); return -128; } file->dataBufferWrite = 0; file->dataBufferFill = 0; file->dataBufferNumFilled = 0; file->dataBufferPos = 0; file->overflowBufferBegin = 0; file->overflowBufferEnd = 0; file->overflowBufferSize = 0; FAT32_InitializeFileFAT(file); SD_SPI_WriteSingleBlock(fs->card, file->directoryTableLBA, file->directoryTableBlockData); file->directoryTableDirty = 0; SD_SPI_WriteSingleBlock(fs->card, file->currentFATLBA, file->currentFATBlockData); file->currentFATAllocated = 0; FAT32_FillFSInformationSector(file); SD_SPI_WriteSingleBlock(fs->card, fs->FS_info_LBA, file->fsBuffer); file->fs->fsInfoDirty = 0; return 1; } } // Advance to next block clusterOffset++; if (clusterOffset >= fs->sectorsPerCluster) { // End of cluster currentCluster = getNextCluster(fs, currentCluster); DBG_DATA_printf("Next cluster = 0x%08lx", currentCluster); // Sanity check: ensure Directory Table cluster is valid if (currentCluster >= 0xF0000000) { DBG_printf("Error creating file (searched past end of Directory Table Cluster)."); return -1; } currentLBA = GetClusterLBA(fs, currentCluster); clusterOffset = 0; } else { // Advance to next block within cluster currentLBA++; } } }