/** * 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; }
/** * 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; }
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; } }
/** * 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++; } } }