diff --git a/src/usb/uf2/ghostfat.c b/src/usb/uf2/ghostfat.c index 674ba1a..b3b3cbe 100644 --- a/src/usb/uf2/ghostfat.c +++ b/src/usb/uf2/ghostfat.c @@ -9,6 +9,8 @@ #include "bootloader_settings.h" #include "bootloader.h" +// #define CREATE_MANY_FILES + typedef struct { uint8_t JumpInstruction[3]; @@ -48,7 +50,6 @@ typedef struct { uint16_t startCluster; uint32_t size; } __attribute__((packed)) DirEntry; - STATIC_ASSERT(sizeof(DirEntry) == 32); struct TextFile { @@ -78,9 +79,56 @@ const char indexFile[] = // "" "\n"; +#ifdef CREATE_MANY_FILES +const char dataFile00[] = "This is the data for File 00\r\n"; +const char dataFile01[] = "This is the data for File 01\r\n"; +const char dataFile02[] = "This is the data for File 02\r\n"; +const char dataFile03[] = "This is the data for File 03\r\n"; +const char dataFile04[] = "This is the data for File 04\r\n"; +const char dataFile05[] = "This is the data for File 05\r\n"; +const char dataFile06[] = "This is the data for File 06\r\n"; +const char dataFile07[] = "This is the data for File 07\r\n"; +const char dataFile08[] = "This is the data for File 08\r\n"; +const char dataFile09[] = "This is the data for File 09\r\n"; +const char dataFile10[] = "This is the data for File 10\r\n"; +const char dataFile11[] = "This is the data for File 11\r\n"; +const char dataFile12[] = "This is the data for File 12\r\n"; +const char dataFile13[] = "This is the data for File 13\r\n"; +const char dataFile14[] = "This is the data for File 14\r\n"; +const char dataFile15[] = "This is the data for File 15\r\n"; +const char dataFile16[] = "This is the data for File 16\r\n"; +const char dataFile17[] = "This is the data for File 17\r\n"; +const char dataFile18[] = "This is the data for File 18\r\n"; +const char dataFile19[] = "This is the data for File 19\r\n"; +#endif // CREATE_MANY_FILES + +// WARNING -- code presumes only one NULL .content for .UF2 file +// and requires it be the last element of the array static struct TextFile const info[] = { {.name = "INFO_UF2TXT", .content = infoUf2File}, {.name = "INDEX HTM", .content = indexFile}, +#ifdef CREATE_MANY_FILES + {.name = "FILE00 TXT", .content = dataFile00}, + {.name = "FILE01 TXT", .content = dataFile01}, + {.name = "FILE02 TXT", .content = dataFile02}, + {.name = "FILE03 TXT", .content = dataFile03}, + {.name = "FILE04 TXT", .content = dataFile04}, + {.name = "FILE05 TXT", .content = dataFile05}, + {.name = "FILE06 TXT", .content = dataFile06}, + {.name = "FILE07 TXT", .content = dataFile07}, + {.name = "FILE08 TXT", .content = dataFile08}, + {.name = "FILE09 TXT", .content = dataFile09}, + {.name = "FILE10 TXT", .content = dataFile10}, + {.name = "FILE11 TXT", .content = dataFile11}, + {.name = "FILE12 TXT", .content = dataFile12}, + {.name = "FILE13 TXT", .content = dataFile13}, + {.name = "FILE14 TXT", .content = dataFile14}, + {.name = "FILE15 TXT", .content = dataFile15}, + {.name = "FILE16 TXT", .content = dataFile16}, + {.name = "FILE17 TXT", .content = dataFile17}, + {.name = "FILE18 TXT", .content = dataFile18}, + {.name = "FILE19 TXT", .content = dataFile19}, +#endif {.name = "CURRENT UF2"}, }; @@ -110,8 +158,9 @@ STATIC_ASSERT(ARRAY_SIZE2(indexFile) < 512); // all directory entries must fit in a single sector // because otherwise current code overflows buffer -STATIC_ASSERT(NUM_DIRENTRIES < (512 / sizeof(DirEntry))); -// STATIC_ASSERT(NUM_DIRENTRIES < (512 / sizeof(DirEntry)) * ROOT_DIR_SECTORS); +#define DIRENTRIES_PER_SECTOR (512/sizeof(DirEntry)) + +STATIC_ASSERT(NUM_DIRENTRIES < DIRENTRIES_PER_SECTOR * ROOT_DIR_SECTORS); static FAT_BootBlock const BootBlock = { @@ -121,7 +170,7 @@ static FAT_BootBlock const BootBlock = { .SectorsPerCluster = 1, .ReservedSectors = RESERVED_SECTORS, .FATCopies = 2, - .RootDirectoryEntries = (ROOT_DIR_SECTORS * 512 / 32), + .RootDirectoryEntries = (ROOT_DIR_SECTORS * DIRENTRIES_PER_SECTOR), .TotalSectors16 = NUM_FAT_BLOCKS - 2, .MediaDescriptor = 0xF8, .SectorsPerFAT = SECTORS_PER_FAT, @@ -205,8 +254,11 @@ void read_block(uint32_t block_no, uint8_t *data) { sectionIdx -= SECTORS_PER_FAT; if (sectionIdx == 0) { data[0] = 0xf0; + // WARNING -- code presumes only one NULL .content for .UF2 file + // and all non-NULL .content fit in one sector + // and requires it be the last element of the array for (int i = 1; i < NUM_FILES * 2 + 4; ++i) { - data[i] = 0xff; // WARNING -- code presumes each non-UF2 file content fits in single sector + data[i] = 0xff; } } for (int i = 0; i < 256; ++i) { @@ -215,20 +267,33 @@ void read_block(uint32_t block_no, uint8_t *data) { ((uint16_t *)(void *)data)[i] = v == UF2_LAST_SECTOR ? 0xffff : v + 1; } } else if (block_no < START_CLUSTERS) { - // Use STATIC_ASSERT() above to ensure only first sector has entries + sectionIdx -= START_ROOTDIR; - if (sectionIdx == 0) { - DirEntry *d = (void *)data; + + DirEntry *d = (void *)data; + int remainingEntries = DIRENTRIES_PER_SECTOR; + if (sectionIdx == 0) { // volume label first + // volume label is first directory entry padded_memcpy(d->name, (char const *) BootBlock.VolumeLabel, 11); d->attrs = 0x28; - for (int i = 0; i < NUM_FILES; ++i) { - d++; - struct TextFile const *inf = &info[i]; - d->size = inf->content ? strlen(inf->content) : UF2_SIZE; - d->startCluster = i + 2; - padded_memcpy(d->name, inf->name, 11); - } + remainingEntries--; } + + for (int i = DIRENTRIES_PER_SECTOR * sectionIdx; + remainingEntries > 0 && i < NUM_FILES; + i++, d++) { + struct TextFile const * inf = &info[i]; + // WARNING -- code presumes only one NULL .content for .UF2 file + // and requires it be the last element of the array + d->size = inf->content ? strlen(inf->content) : UF2_SIZE; + d->startCluster = i + 2; + padded_memcpy(d->name, inf->name, 11); + // DIR_WrtTime and DIR_WrtDate must be supported + d->updateDate = __DOSDATE__; + d->lastAccessDate = __DOSDATE__; + d->createDate = __DOSDATE__; + } + } else { sectionIdx -= START_CLUSTERS; if (sectionIdx < NUM_FILES - 1) { diff --git a/src/usb/uf2/uf2.h b/src/usb/uf2/uf2.h index 8d82d28..eee26d6 100644 --- a/src/usb/uf2/uf2.h +++ b/src/usb/uf2/uf2.h @@ -296,3 +296,38 @@ static inline void check_uf2_handover(uint8_t *buffer, uint32_t blocks_remaining #endif // ARRAYSIZE2_H +#ifndef COMPILE_DATE_H +#define COMPILE_DATE_H + +#define __YEAR_INT__ ((( \ + (__DATE__ [ 7u] - '0') * 10u + \ + (__DATE__ [ 8u] - '0')) * 10u + \ + (__DATE__ [ 9u] - '0')) * 10u + \ + (__DATE__ [10u] - '0')) + +#define __MONTH_INT__ ( \ + (__DATE__ [2u] == 'n' && __DATE__ [1u] == 'a') ? 1u /*Jan*/ \ +: (__DATE__ [2u] == 'b' ) ? 2u /*Feb*/ \ +: (__DATE__ [2u] == 'r' && __DATE__ [1u] == 'a') ? 3u /*Mar*/ \ +: (__DATE__ [2u] == 'r' ) ? 4u /*Apr*/ \ +: (__DATE__ [2u] == 'y' ) ? 5u /*May*/ \ +: (__DATE__ [2u] == 'n' ) ? 6u /*Jun*/ \ +: (__DATE__ [2u] == 'l' ) ? 7u /*Jul*/ \ +: (__DATE__ [2u] == 'g' ) ? 8u /*Jul*/ \ +: (__DATE__ [2u] == 'p' ) ? 9u /*Jul*/ \ +: (__DATE__ [2u] == 't' ) ? 10u /*Jul*/ \ +: (__DATE__ [2u] == 'v' ) ? 11u /*Jul*/ \ +: 12u /*Dec*/ ) + +#define __DAY_INT__ ( \ + (__DATE__ [4u] == ' ' ? 0u : __DATE__ [4u] - '0') * 10u \ + + (__DATE__ [5u] - '0') ) + +#define __DOSDATE__ ( \ + ((__YEAR_INT__ - 1980u) << 9u) | \ + ( __MONTH_INT__ << 5u) | \ + ( __DAY_INT__ << 0u) ) + + +#endif // COMPILE_DATE_H +