// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define FAT_U8(v) ((v) & 0xFF) #define FAT_U16(v) FAT_U8(v), FAT_U8((v) >> 8) #define FAT_U32(v) FAT_U8(v), FAT_U8((v) >> 8), FAT_U8((v) >> 16), FAT_U8((v) >> 24) #define FAT12_TBL2B(l,h) FAT_U8(l), FAT_U8(((l >> 8) & 0xF) | ((h << 4) & 0xF0)), FAT_U8(h >> 4) #define FAT_MS2B(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10) #define FAT_HMS2B(h,m,s) FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x7)|((h) << 3)) #define FAT_YMD2B(y,m,d) FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1)) #define FAT_MS2V(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10) #define FAT_HMS2V(h,m,s) (FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)) | (FAT_U8((((m) >> 3) & 0x7)|((h) << 3)) << 8)) #define FAT_YMD2V(y,m,d) (FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)) | (FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1)) << 8)) #define FAT_B2HMS(hms) ((hms >> 11) & 0x1F), ((hms >> 5) & 0x3F), ((hms & 0x1F) << 1) #define FAT_B2YMD(ymd) (((ymd >> 9) & 0x7F) + 1980), ((ymd >> 5) & 0x0F), (ymd & 0x1F) #define FAT_FILE_ATTR_READ_ONLY 0x01 #define FAT_FILE_ATTR_HIDDEN 0x02 #define FAT_FILE_ATTR_SYSTEM 0x04 #define FAT_FILE_ATTR_VOLUME_LABEL 0x08 #define FAT_FILE_ATTR_SUBDIRECTORY 0x10 #define FAT_FILE_ATTR_ARCHIVE 0x20 #define FAT_FILE_ATTR_DEVICE 0x40 static const uint16_t DISK_SECTOR_SIZE = 512; #define FAT_SIZE_TO_SECTORS(bytes) ((bytes) / DISK_SECTOR_SIZE) + (((bytes) % DISK_SECTOR_SIZE)?1:0) typedef struct __attribute__ ((packed)) { uint8_t jump_instruction[3]; char oem_name[8];//padded with spaces (0x20) uint16_t bytes_per_sector;//DISK_SECTOR_SIZE usually 512 uint8_t sectors_per_cluster;//Allowed values are 1, 2, 4, 8, 16, 32, 64, and 128 uint16_t reserved_sectors_count;//At least 1 for this sector, usually 32 for FAT32 uint8_t file_alloc_tables_num;//Almost always 2; RAM disks might use 1 uint16_t max_root_dir_entries;//FAT12 and FAT16 uint16_t fat12_sector_num;//DISK_SECTOR_NUM FAT12 and FAT16 uint8_t media_descriptor; uint16_t sectors_per_alloc_table;//FAT12 and FAT16 uint16_t sectors_per_track;//A value of 0 may indicate LBA-only access uint16_t num_heads; uint32_t hidden_sectors_count; uint32_t total_sectors_32; uint8_t physical_drive_number;//0x00 for (first) removable media, 0x80 for (first) fixed disk uint8_t reserved0; uint8_t extended_boot_signature;//should be 0x29 uint32_t serial_number;//0x1234 => 1234 char volume_label[11];//padded with spaces (0x20) char file_system_type[8];//padded with spaces (0x20) uint8_t reserved[448]; uint16_t signature;//should be 0xAA55 } fat_boot_sector_t; typedef struct __attribute__ ((packed)) { union { struct { char file_name[8];//padded with spaces (0x20) char file_extension[3];//padded with spaces (0x20) }; struct { uint8_t file_magic;// 0xE5:deleted, 0x05:will_be_deleted, 0x00:end_marker, 0x2E:dot_marker(. or ..) char file_magic_data[10]; }; char volume_label[11];//padded with spaces (0x20) }; uint8_t file_attr;//mask of FAT_FILE_ATTR_* uint8_t reserved;//always 0 uint8_t creation_time_ms;//ms * 10; max 1990 (1s 990ms) uint16_t creation_time_hms; // [5:6:5] => h:m:(s/2) uint16_t creation_time_ymd; // [7:4:5] => (y+1980):m:d uint16_t last_access_ymd; uint16_t extended_attr; uint16_t last_modified_hms; uint16_t last_modified_ymd; uint16_t data_start_sector; uint32_t file_size; } fat_dir_entry_t; typedef struct __attribute__ ((packed)) { union { struct { uint8_t number:5; uint8_t reserved0:1; uint8_t llfp:1; uint8_t reserved1:1; } seq; uint8_t seq_num; //0xE5: Deleted Entry }; uint16_t name0[5]; uint8_t attr; //ALWAYS 0x0F uint8_t type; //ALWAYS 0x00 uint8_t dos_checksum; uint16_t name1[6]; uint16_t first_cluster; //ALWAYS 0x0000 uint16_t name2[2]; } fat_lfn_entry_t; typedef union { fat_dir_entry_t dir; fat_lfn_entry_t lfn; } fat_entry_t; const char * fat_file_system_type(bool fat16); uint16_t fat_sectors_per_alloc_table(uint32_t sector_num, bool fat16); uint8_t * fat_add_table(uint8_t * dst, fat_boot_sector_t * boot, bool fat16); void fat_set_table_index(uint8_t * table, uint16_t index, uint16_t value, bool fat16); fat_boot_sector_t * fat_add_boot_sector(uint8_t * dst, uint16_t sector_num, uint16_t table_sectors, const char * file_system_type, const char * volume_label, uint32_t serial_number); fat_dir_entry_t * fat_add_label(uint8_t * dst, const char * volume_label); fat_dir_entry_t * fat_add_root_file(uint8_t * dst, uint8_t index, const char * file_name, const char * file_extension, size_t file_size, uint16_t data_start_sector, bool is_fat16); uint8_t fat_lfn_checksum(const uint8_t *short_filename); #ifdef __cplusplus } #endif