/** * Write an uf2 block wrapped by 512 sector. * @return number of bytes processed, only 3 following values * -1 : if not an uf2 block * 512 : write is successful (BPB_SECTOR_SIZE == 512) * 0 : is busy with flashing, tinyusb stack will call write_block again with the same parameters later on */intuf2_write_block(uint32_t block_index, uint8_t *data) { (void) block_index; UF2_Block *bl = (void*) data; if ( !is_uf2_block(bl) ) return-1; if (bl->familyID == 0x5ee21072) { // generic family ID LOG(INFO, "get uf2 file\n"); // TODO: check first get address is app start board_flash_write(bl->data, bl->targetAddr, bl->payloadSize); }else { // TODO family matches VID/PID return-1; } WriteState* state = &_write_state; /*------------- Update written blocks -------------*/ if ( bl->numBlocks ) { // Update state num blocks if needed if ( state->numBlocks != bl->numBlocks ) { if ( bl->numBlocks >= MAX_BLOCKS || state->numBlocks ) { state->numBlocks = 0xffffffff; } else { state->numBlocks = bl->numBlocks; } } if ( bl->blockNo < MAX_BLOCKS ) { uint8_tconst mask = 1 << (bl->blockNo % 8); uint32_tconst pos = bl->blockNo / 8; // only increase written number with new write (possibly prevent overwriting from OS) if ( !(state->writtenMask[pos] & mask) ) { state->writtenMask[pos] |= mask; state->numWritten++; } // flush last blocks // TODO numWritten can be smaller than numBlocks if return early if ( state->numWritten >= state->numBlocks ) { board_flash_flush(); } } } return BPB_SECTOR_SIZE; }
voiduf2_read_block(uint32_t block_index, uint8_t* data) { memset(data, 0, FAT16_SECTOR_SIZE); uint32_t sectionRelativeSector = block_index; if(block_index == 0) { // Request was for the Boot block memcpy(data, &BootBlock, sizeof(BootBlock)); data[510] = 0x55; // Always at offsets 510/511, even when BPB_SECTOR_SIZE is larger data[511] = 0xaa; // Always at offsets 510/511, even when BPB_SECTOR_SIZE is larger } elseif(block_index < FS_START_ROOTDIR_SECTOR) { // Request was for a FAT table sector sectionRelativeSector -= FS_START_FAT0_SECTOR; if ( sectionRelativeSector >= BPB_SECTORS_PER_FAT ) { sectionRelativeSector -= BPB_SECTORS_PER_FAT; } uint16_t* data16 = (uint16_t*) (void*) data; uint32_t sectorFirstCluster = sectionRelativeSector * FAT_ENTRIES_PER_SECTOR; uint32_t firstUnusedCluster = info[0].cluster_end + 1; // OPTIMIZATION: // Because all files are contiguous, the FAT CHAIN entries // are all set to (cluster+1) to point to the next cluster. // All clusters past the last used cluster of the last file // are set to zero. // // EXCEPTIONS: // 1. Clusters 0 and 1 require special handling // 2. Final cluster of each file must be set to END_OF_CHAIN // // Set default FAT values first. for (uint16_t i = 0; i < FAT_ENTRIES_PER_SECTOR; i++) { uint32_t cluster = i + sectorFirstCluster; if (cluster >= firstUnusedCluster) { data16[i] = 0; } else { data16[i] = cluster + 1; } } // Exception #1: clusters 0 and 1 need special handling if (sectionRelativeSector == 0) { data[0] = BPB_MEDIA_DESCRIPTOR_BYTE; data[1] = 0xff; data16[1] = FAT_END_OF_CHAIN; // cluster 1 is reserved } // Exception #2: the final cluster of each file must be set to END_OF_CHAIN for (uint32_t i = 0; i < 2; i++) { uint32_t lastClusterOfFile = info[i].cluster_end; if (lastClusterOfFile >= sectorFirstCluster) { uint32_t idx = lastClusterOfFile - sectorFirstCluster; if (idx < FAT_ENTRIES_PER_SECTOR) { // that last cluster of the file is in this sector data16[idx] = FAT_END_OF_CHAIN; } } } } elseif ( block_index < FS_START_CLUSTERS_SECTOR ) { // Request was for a (root) directory sector .. root because not supporting subdirectories (yet) sectionRelativeSector -= FS_START_ROOTDIR_SECTOR; DirEntry *d = (void*) data; // pointer to next free DirEntry this sector int remainingEntries = DIRENTRIES_PER_SECTOR; // remaining count of DirEntries this sector uint32_t startingFileIndex; if ( sectionRelativeSector == 0 ) { // volume label is first directory entry memcpy(d->name, (charconst*) BootBlock.VolumeLabel, 11); d->attrs = 0x28; d++; remainingEntries--; startingFileIndex = 0; }else { // -1 to account for volume label in first sector startingFileIndex = DIRENTRIES_PER_SECTOR * sectionRelativeSector - 1; } for ( uint32_t fileIndex = startingFileIndex; remainingEntries > 0 && fileIndex < NUM_FILES; // while space remains in buffer and more files to add... fileIndex++, d++ ) { // WARNING -- code presumes all files take exactly one directory entry (no long file names!) uint32_tconst startCluster = info[fileIndex].cluster_start; FileContent_t const *inf = &info[fileIndex]; memcpy(d->name, inf->name, 11); d->createTimeFine = COMPILE_SECONDS_INT % 2 * 100; d->createTime = COMPILE_DOS_TIME; d->createDate = COMPILE_DOS_DATE; d->lastAccessDate = COMPILE_DOS_DATE; d->highStartCluster = startCluster >> 16; d->updateTime = COMPILE_DOS_TIME; d->updateDate = COMPILE_DOS_DATE; d->startCluster = startCluster & 0xFFFF; d->size = (inf->content ? inf->size : 0xffff); } } elseif ( block_index < BPB_TOTAL_SECTORS ) { // Request was to read from the data area (files, unused space, ...) sectionRelativeSector -= FS_START_CLUSTERS_SECTOR; // plus 2 for first data cluster offset uint32_t fid = info_index_of(2 + sectionRelativeSector); FileContent_t const * inf = &info[fid]; uint32_t fileRelativeSector = sectionRelativeSector - (info[fid].cluster_start-2); if ( fid != FID_UF2 ) { // Handle all files other than CURRENT.UF2 size_t fileContentStartOffset = fileRelativeSector * BPB_SECTOR_SIZE; size_t fileContentLength = inf->size; // nothing to copy if already past the end of the file (only when >1 sector per cluster) if (fileContentLength > fileContentStartOffset) { // obviously, 2nd and later sectors should not copy data from the start constvoid * dataStart = (inf->content) + fileContentStartOffset; // limit number of bytes of data to be copied to remaining valid bytes size_t bytesToCopy = fileContentLength - fileContentStartOffset; // and further limit that to a single sector at a time if (bytesToCopy > BPB_SECTOR_SIZE) { bytesToCopy = BPB_SECTOR_SIZE; } memcpy(data, dataStart, bytesToCopy); } } else { // CURRENT.UF2: generate data on-the-fly uint32_t addr = BOARD_FLASH_APP_START + (fileRelativeSector * UF2_FIRMWARE_BYTES_PER_SECTOR); if ( addr < (BOARD_FLASH_ADDR_BASE + _flash_size) ) { UF2_Block *bl = (void*) data; bl->magicStart0 = UF2_MAGIC_START0; bl->magicStart1 = UF2_MAGIC_START1; bl->magicEnd = UF2_MAGIC_END; bl->blockNo = fileRelativeSector; bl->numBlocks = UF2_SECTOR_COUNT; bl->targetAddr = addr; bl->payloadSize = UF2_FIRMWARE_BYTES_PER_SECTOR; bl->flags = UF2_FLAG_FAMILYID; bl->familyID = BOARD_UF2_FAMILY_ID; board_flash_read(bl->data, addr, bl->payloadSize); } // memset(data, 0, 512); } } }