Ejemplo n.º 1
0
uint16_t DataloggerFile_WriteAtomic(DataloggerFile *dlgFile, uint8_t *data,
		uint16_t dataLen) {
	// Check if there is enough free space in the buffer for an atomic write
	if (dataLen > dlgFile->bufferFree) {
		return 0;
	}
	if (dlgFile->requestClose) {
		return 0;
	}

	// If the buffer is clear and the file is ready, write directly to the file
	if (dlgFile->bufferFree == dlgFile->bufferSize
			&& dlgFile->file->state != FILE_Uninitialized
			&& dlgFile->file->state != FILE_Creating) {
		fs_length_t writeLength = FS_WriteFile(dlgFile->file, data, dataLen);
		data += writeLength;
		dataLen -= writeLength;

		DBG_SPAM_printf("DLGFile: write->card %u bytes", writeLength);
	}
	while (dataLen > 0) {
		fs_length_t writeLength;
		// Determine maximum contigious write length
		if (dlgFile->readPos > dlgFile->writePos) {
			writeLength = dlgFile->bufferFree;
		} else {
			writeLength = dlgFile->bufferSize - dlgFile->writePos;
		}
		// Cap write length at data length
		if (dataLen < writeLength) {
			writeLength = dataLen;
		}
		// Write data and update buffer variables
		memcpy(dlgFile->buffer + dlgFile->writePos, data, writeLength);
		dlgFile->writePos += writeLength;
		if (dlgFile->writePos >= dlgFile->bufferSize) {
			dlgFile->writePos = 0;
		}
		dlgFile->bufferFree -= writeLength;

		// Update remaining data
		dataLen -= writeLength;
		data += writeLength;

		DBG_SPAM_printf("DLGFile: write->buffer %u bytes, bufFree = %u", writeLength, dlgFile->bufferFree);
	}

	return 1;
}
Ejemplo n.º 2
0
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;
	}
}
Ejemplo n.º 3
0
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);
		}
	}
}
Ejemplo n.º 4
0
/**
 * 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++;
		}
	}
}