#pragma once #include "fat12.h" #include #include #include #include #include namespace esphome { namespace grub_boot_switch { constexpr uint32_t SECTOR_COUNT = 128; constexpr uint32_t SECTOR_SIZE = 512; constexpr uint32_t SECTORS_PER_CLUSTER = 1; constexpr uint32_t RESERVED_SECTORS = 1; constexpr uint32_t FAT_COPIES = 2; constexpr uint32_t ROOT_ENTRIES = 512; constexpr uint32_t ROOT_ENTRY_LENGTH = 32; constexpr uint32_t FILEDATA_START_CLUSTER = 3; constexpr uint32_t DATA_REGION_SECTOR = RESERVED_SECTORS + FAT_COPIES + (ROOT_ENTRIES * ROOT_ENTRY_LENGTH) / SECTOR_SIZE; constexpr uint32_t FILEDATA_START_SECTOR = DATA_REGION_SECTOR + (FILEDATA_START_CLUSTER - 2) * SECTORS_PER_CLUSTER; using FileReadCallback = std::function; struct VirtualFile { std::string long_name; FatDirEntry dir; FileReadCallback read; }; class MscDisk { public: MscDisk(); // Volume serial baked into the FAT boot sector. // Default 0x55AA6922 matches the upstream stecman/hw-boot-selection firmware // so existing GRUB hooks (search --fs-uuid 55AA-6922) keep working unchanged. void set_volume_serial(uint32_t serial) { volume_serial_ = serial; } void set_volume_label(const char *label); // 11 chars, space-padded // Date stamped on every directory entry. GRUB 2.06 rejects 0-valued dates. void set_file_date(uint16_t year, uint8_t month, uint8_t day); // Register a file. Short name must be 8.3 with space padding handled by caller // (use add_file() helper below for typical cases). size is the file's logical // size in bytes; content_cb is called once per host read of the file's sector. void add_file(const std::string &long_name, const std::string &short_name, const std::string &short_ext, uint32_t size, FileReadCallback content_cb); // Synthesise a single 512-byte sector for LBA `lba` into `out`. // out is zeroed first. Returns 0 on success. int read_lba(uint32_t lba, uint8_t *out); uint32_t sector_count() const { return SECTOR_COUNT; } uint32_t sector_size() const { return SECTOR_SIZE; } protected: void write_boot_sector(uint8_t *out); void write_fat_sector(uint8_t *out); void write_dir_sector(uint8_t *out); uint32_t volume_serial_ = 0x55AA6922u; char volume_label_[11] = {'S', 'W', 'I', 'T', 'C', 'H', ' ', ' ', ' ', ' ', ' '}; uint16_t file_date_ = 0; std::vector files_; }; } // namespace grub_boot_switch } // namespace esphome