/**
 * Updates switch states.
 * If the switches are controlled through a GPIO expander, this reads the data
 * from the expander.
 * If the switch is directly controlled by the MCU, this does nothing.
 */
inline void UI_Switch_Update() {
	if (!MCP23018_SingleRegisterRead(0b000, MCP23018_ADDR_GPIOA, &GPIO_GPIOA)) {
		DBG_ERR_printf("I2C MCP23018 GPIOA read failed");
	}
	if (!MCP23018_SingleRegisterRead(0b000, MCP23018_ADDR_GPIOB, &GPIO_GPIOB)) {
		DBG_ERR_printf("I2C MCP23018 GPIOB read failed");
	}
}
sd_result_t SD_DMA_SingleBlockRead(SD_Card *card, sd_block_t addr, SD_Data_Block *data) {
    uint8_t result;
    uint8_t args[4];
    uint16_t i=0;

    if (card->State != SD_IDLE) {
        DBG_ERR_printf("SBR failed: Card not in idle state, state is 0x%02x", card->State);
        return SD_FAILED;
    }

    if (!card->SDHC) {
        addr = addr * card->BlockSize;
    }

    args[0] = (uint8_t)((addr >> 24) & 0xff);
    args[1] = (uint8_t)((addr >> 16) & 0xff);
    args[2] = (uint8_t)((addr >> 8) & 0xff);
    args[3] = (uint8_t)((addr >> 0) & 0xff);

    SD_SPI_Open(card);
    result = SD_SendCommand(card, SD_CMD_READ_SINGLE_BLOCK, args, 0x00);
    if (result != 0x00) {
        DBG_ERR_printf("SBR failed: Bad response to READ_SINGLE_BLOCK - got 0x%02x", result);

        SD_SPI_Terminate(card);
        SD_SPI_Close(card);

        return SD_PHY_ERR;
    }

    // wait for the start block token
    result = 0xff;
    while (result != SD_TOKEN_START_BLOCK && i < SD_BLOCK_TIMEOUT) {
        result = SD_SPI_Transfer(card, SD_DUMMY_BYTE);
        i++;
    }
    if (result != SD_TOKEN_START_BLOCK) {
        DBG_ERR_printf("SBR failed: Card did not send block, got 0x%02x", result);

        SD_SPI_Terminate(card);
        SD_SPI_Close(card);

        return SD_PHY_ERR;
    }

    data->StartOffset = 2;
    data->BlockLen = 514;
    SD_DMA_ReceiveBlock(card, data);

    SD_DMA_OnBlockRead();

    card->State = SD_DMA_SBR;
    card->SubState = 0;

    return SD_BUSY;
}
/**
 * Updates LED states.
 * If the LEDs are controlled through a GPIO expander, this writes the data
 * to the expander.
 * If the LED is directly controlled by the MCU, this does nothing.
 */
inline void UI_HW_LED_Update() {
	if (GPIO_OLATA != GPIO_OLATA_Old) {
		if (!MCP23018_SingleRegisterWrite(0b000, MCP23018_ADDR_OLATA, GPIO_OLATA)) {
			DBG_ERR_printf("I2C MCP23018 OLATA update failed");
		}
	}
	GPIO_OLATA_Old = GPIO_OLATA;
}
/**
 * Initializes everything for the user interface, such as setting pin direction
 * and enabling pull-ups.
 */
inline void UI_HW_Initialize() {
	if (!MCP23018_SingleRegisterWrite(0b000, MCP23018_ADDR_IODIRA, 0b00011111)) {
		DBG_ERR_printf("I2C MCP23018 IODIRA failed");
	}
	if (!MCP23018_SingleRegisterWrite(0b000, MCP23018_ADDR_IODIRB, 0b11111111)) {
		DBG_ERR_printf("I2C MCP23018 IODIRB failed");
	}

	if (!MCP23018_SingleRegisterWrite(0b000, MCP23018_ADDR_GPPUA, 0b00011111)) {
		DBG_ERR_printf("I2C MCP23018 GPPUA failed");
	}
	if (!MCP23018_SingleRegisterWrite(0b000, MCP23018_ADDR_GPPUB, 0b11111111)) {
		DBG_ERR_printf("I2C MCP23018 GPPUB failed");
	}

	LED_FAULT_IO = 0;
	LED_FAULT_TRIS = 0;
}
Пример #5
0
/**
 * 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;
}
Пример #6
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;
	}
}
sd_result_t SD_DMA_GetSingleBlockReadResult(SD_Card *card) {
    if (card->State != SD_DMA_SBR) {
        DBG_ERR_printf("SBR failed: Card not in Single Block Read state");
        return SD_FAILED;
    }

    if (SD_DMA_GetTransferComplete(card)) {
        SD_SPI_Terminate(card);
        SD_SPI_Close(card);

        card->State = SD_IDLE;

        return SD_SUCCESS;
    } else {
        return SD_BUSY;
    }
}
Пример #8
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++;
		}
	}
}