//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // FAT16/32 File IO Library // V2.6 // Ultra-Embedded.com // Copyright 2003 - 2012 // // Email: admin@ultra-embedded.com // // License: GPL // If you would like a version with a more permissive license for use in // closed source commercial applications please contact me for details. //----------------------------------------------------------------------------- // // This file is part of FAT File IO Library. // // FAT File IO Library is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // FAT File IO Library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with FAT File IO Library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- #include #include #include "fat_misc.h" //----------------------------------------------------------------------------- // fatfs_lfn_cache_init: Clear long file name cache //----------------------------------------------------------------------------- void fatfs_lfn_cache_init(struct lfn_cache *lfn, int wipeTable) { int i = 0; lfn->no_of_strings = 0; #if FATFS_INC_LFN_SUPPORT // Zero out buffer also if (wipeTable) for (i=0;iString[i], 0x00, MAX_LFN_ENTRY_LENGTH); #endif } //----------------------------------------------------------------------------- // fatfs_lfn_cache_entry - Function extracts long file name text from sector // at a specific offset //----------------------------------------------------------------------------- #if FATFS_INC_LFN_SUPPORT void fatfs_lfn_cache_entry(struct lfn_cache *lfn, uint8 *entryBuffer) { uint8 LFNIndex, i; LFNIndex = entryBuffer[0] & 0x1F; // Limit file name to cache size! if (LFNIndex > MAX_LONGFILENAME_ENTRIES) return ; // This is an error condition if (LFNIndex == 0) return ; if (lfn->no_of_strings == 0) lfn->no_of_strings = LFNIndex; lfn->String[LFNIndex-1][0] = entryBuffer[1]; lfn->String[LFNIndex-1][1] = entryBuffer[3]; lfn->String[LFNIndex-1][2] = entryBuffer[5]; lfn->String[LFNIndex-1][3] = entryBuffer[7]; lfn->String[LFNIndex-1][4] = entryBuffer[9]; lfn->String[LFNIndex-1][5] = entryBuffer[0x0E]; lfn->String[LFNIndex-1][6] = entryBuffer[0x10]; lfn->String[LFNIndex-1][7] = entryBuffer[0x12]; lfn->String[LFNIndex-1][8] = entryBuffer[0x14]; lfn->String[LFNIndex-1][9] = entryBuffer[0x16]; lfn->String[LFNIndex-1][10] = entryBuffer[0x18]; lfn->String[LFNIndex-1][11] = entryBuffer[0x1C]; lfn->String[LFNIndex-1][12] = entryBuffer[0x1E]; for (i=0; iString[LFNIndex-1][i]==0xFF) lfn->String[LFNIndex-1][i] = 0x20; // Replace with spaces } #endif //----------------------------------------------------------------------------- // fatfs_lfn_cache_get: Get a reference to the long filename //----------------------------------------------------------------------------- #if FATFS_INC_LFN_SUPPORT char* fatfs_lfn_cache_get(struct lfn_cache *lfn) { // Null terminate long filename if (lfn->no_of_strings == MAX_LONGFILENAME_ENTRIES) lfn->Null = '\0'; else if (lfn->no_of_strings) lfn->String[lfn->no_of_strings][0] = '\0'; else lfn->String[0][0] = '\0'; return (char*)&lfn->String[0][0]; } #endif //----------------------------------------------------------------------------- // fatfs_entry_lfn_text: If LFN text entry found //----------------------------------------------------------------------------- #if FATFS_INC_LFN_SUPPORT int fatfs_entry_lfn_text(struct fat_dir_entry *entry) { if ((entry->Attr & FILE_ATTR_LFN_TEXT) == FILE_ATTR_LFN_TEXT) return 1; else return 0; } #endif //----------------------------------------------------------------------------- // fatfs_entry_lfn_invalid: If SFN found not relating to LFN //----------------------------------------------------------------------------- #if FATFS_INC_LFN_SUPPORT int fatfs_entry_lfn_invalid(struct fat_dir_entry *entry) { if ( (entry->Name[0]==FILE_HEADER_BLANK) || (entry->Name[0]==FILE_HEADER_DELETED)|| (entry->Attr==FILE_ATTR_VOLUME_ID) || (entry->Attr & FILE_ATTR_SYSHID) ) return 1; else return 0; } #endif //----------------------------------------------------------------------------- // fatfs_entry_lfn_exists: If LFN exists and correlation SFN found //----------------------------------------------------------------------------- #if FATFS_INC_LFN_SUPPORT int fatfs_entry_lfn_exists(struct lfn_cache *lfn, struct fat_dir_entry *entry) { if ( (entry->Attr!=FILE_ATTR_LFN_TEXT) && (entry->Name[0]!=FILE_HEADER_BLANK) && (entry->Name[0]!=FILE_HEADER_DELETED) && (entry->Attr!=FILE_ATTR_VOLUME_ID) && (!(entry->Attr&FILE_ATTR_SYSHID)) && (lfn->no_of_strings) ) return 1; else return 0; } #endif //----------------------------------------------------------------------------- // fatfs_entry_sfn_only: If SFN only exists //----------------------------------------------------------------------------- int fatfs_entry_sfn_only(struct fat_dir_entry *entry) { if ( (entry->Attr!=FILE_ATTR_LFN_TEXT) && (entry->Name[0]!=FILE_HEADER_BLANK) && (entry->Name[0]!=FILE_HEADER_DELETED) && (entry->Attr!=FILE_ATTR_VOLUME_ID) && (!(entry->Attr&FILE_ATTR_SYSHID)) ) return 1; else return 0; } // TODO: FILE_ATTR_SYSHID ?!?!??! //----------------------------------------------------------------------------- // fatfs_entry_is_dir: Returns 1 if a directory //----------------------------------------------------------------------------- int fatfs_entry_is_dir(struct fat_dir_entry *entry) { if (entry->Attr & FILE_TYPE_DIR) return 1; else return 0; } //----------------------------------------------------------------------------- // fatfs_entry_is_file: Returns 1 is a file entry //----------------------------------------------------------------------------- int fatfs_entry_is_file(struct fat_dir_entry *entry) { if (entry->Attr & FILE_TYPE_FILE) return 1; else return 0; } //----------------------------------------------------------------------------- // fatfs_lfn_entries_required: Calculate number of 13 characters entries //----------------------------------------------------------------------------- #if FATFS_INC_LFN_SUPPORT int fatfs_lfn_entries_required(char *filename) { int length = (int)strlen(filename); if (length) return (length + MAX_LFN_ENTRY_LENGTH - 1) / MAX_LFN_ENTRY_LENGTH; else return 0; } #endif //----------------------------------------------------------------------------- // fatfs_filename_to_lfn: //----------------------------------------------------------------------------- #if FATFS_INC_LFN_SUPPORT void fatfs_filename_to_lfn(char *filename, uint8 *buffer, int entry, uint8 sfnChk) { int i; int nameIndexes[MAX_LFN_ENTRY_LENGTH] = {1,3,5,7,9,0x0E,0x10,0x12,0x14,0x16,0x18,0x1C,0x1E}; // 13 characters entries int length = (int)strlen(filename); int entriesRequired = fatfs_lfn_entries_required(filename); // Filename offset int start = entry * MAX_LFN_ENTRY_LENGTH; // Initialise to zeros memset(buffer, 0x00, FAT_DIR_ENTRY_SIZE); // LFN entry number buffer[0] = (uint8)(((entriesRequired-1)==entry)?(0x40|(entry+1)):(entry+1)); // LFN flag buffer[11] = 0x0F; // Checksum of short filename buffer[13] = sfnChk; // Copy to buffer for (i=0;iName[i] = shortfilename[i]; // Unless we have a RTC we might as well set these to 1980 entry->CrtTimeTenth = 0x00; entry->CrtTime[1] = entry->CrtTime[0] = 0x00; entry->CrtDate[1] = 0x00; entry->CrtDate[0] = 0x20; entry->LstAccDate[1] = 0x00; entry->LstAccDate[0] = 0x20; entry->WrtTime[1] = entry->WrtTime[0] = 0x00; entry->WrtDate[1] = 0x00; entry->WrtDate[0] = 0x20; if (!dir) entry->Attr = FILE_TYPE_FILE; else entry->Attr = FILE_TYPE_DIR; entry->NTRes = 0x00; entry->FstClusHI = FAT_HTONS((uint16)((startCluster>>16) & 0xFFFF)); entry->FstClusLO = FAT_HTONS((uint16)((startCluster>>0) & 0xFFFF)); entry->FileSize = FAT_HTONL(size); } #endif //----------------------------------------------------------------------------- // fatfs_lfn_create_sfn: Create a padded SFN //----------------------------------------------------------------------------- #if FATFS_INC_WRITE_SUPPORT int fatfs_lfn_create_sfn(char *sfn_output, char *filename) { int i; int dotPos = -1; char ext[3]; int pos; int len = (int)strlen(filename); // Invalid to start with . if (filename[0]=='.') return 0; memset(sfn_output, ' ', FAT_SFN_SIZE_FULL); memset(ext, ' ', 3); // Find dot seperator for (i = 0; i< len; i++) { if (filename[i]=='.') dotPos = i; } // Extract extensions if (dotPos!=-1) { // Copy first three chars of extension for (i = (dotPos+1); i < (dotPos+1+3); i++) if (i= 'a' && filename[i] <= 'z') sfn_output[pos++] = filename[i] - 'a' + 'A'; else sfn_output[pos++] = filename[i]; } // Fill upto 8 characters if (pos==FAT_SFN_SIZE_PARTIAL) break; } // Add extension part for (i=FAT_SFN_SIZE_PARTIAL;i= 'a' && ext[i-FAT_SFN_SIZE_PARTIAL] <= 'z') sfn_output[i] = ext[i-FAT_SFN_SIZE_PARTIAL] - 'a' + 'A'; else sfn_output[i] = ext[i-FAT_SFN_SIZE_PARTIAL]; } return 1; } //----------------------------------------------------------------------------- // fatfs_itoa: //----------------------------------------------------------------------------- static void fatfs_itoa(uint32 num, char *s) { char* cp; char outbuf[12]; const char digits[] = "0123456789ABCDEF"; // Build string backwards cp = outbuf; do { *cp++ = digits[(int)(num % 10)]; } while ((num /= 10) > 0); *cp-- = 0; // Copy in forwards while (cp >= outbuf) *s++ = *cp--; *s = 0; } #endif //----------------------------------------------------------------------------- // fatfs_lfn_generate_tail: // sfn_input = Input short filename, spaced format & in upper case // sfn_output = Output short filename with tail //----------------------------------------------------------------------------- #if FATFS_INC_LFN_SUPPORT #if FATFS_INC_WRITE_SUPPORT int fatfs_lfn_generate_tail(char *sfn_output, char *sfn_input, uint32 tailNum) { int tail_chars; char tail_str[12]; if (tailNum > 99999) return 0; // Convert to number memset(tail_str, 0x00, sizeof(tail_str)); tail_str[0] = '~'; fatfs_itoa(tailNum, tail_str+1); // Copy in base filename memcpy(sfn_output, sfn_input, FAT_SFN_SIZE_FULL); // Overwrite with tail tail_chars = (int)strlen(tail_str); memcpy(sfn_output+(FAT_SFN_SIZE_PARTIAL-tail_chars), tail_str, tail_chars); return 1; } #endif #endif //----------------------------------------------------------------------------- // fatfs_convert_from_fat_time: Convert FAT time to h/m/s //----------------------------------------------------------------------------- #if FATFS_INC_TIME_DATE_SUPPORT void fatfs_convert_from_fat_time(uint16 fat_time, int *hours, int *minutes, int *seconds) { *hours = (fat_time >> FAT_TIME_HOURS_SHIFT) & FAT_TIME_HOURS_MASK; *minutes = (fat_time >> FAT_TIME_MINUTES_SHIFT) & FAT_TIME_MINUTES_MASK; *seconds = (fat_time >> FAT_TIME_SECONDS_SHIFT) & FAT_TIME_SECONDS_MASK; *seconds = *seconds * FAT_TIME_SECONDS_SCALE; } //----------------------------------------------------------------------------- // fatfs_convert_from_fat_date: Convert FAT date to d/m/y //----------------------------------------------------------------------------- void fatfs_convert_from_fat_date(uint16 fat_date, int *day, int *month, int *year) { *day = (fat_date >> FAT_DATE_DAY_SHIFT) & FAT_DATE_DAY_MASK; *month = (fat_date >> FAT_DATE_MONTH_SHIFT) & FAT_DATE_MONTH_MASK; *year = (fat_date >> FAT_DATE_YEAR_SHIFT) & FAT_DATE_YEAR_MASK; *year = *year + FAT_DATE_YEAR_OFFSET; } //----------------------------------------------------------------------------- // fatfs_convert_to_fat_time: Convert h/m/s to FAT time //----------------------------------------------------------------------------- uint16 fatfs_convert_to_fat_time(int hours, int minutes, int seconds) { uint16 fat_time = 0; // Most FAT times are to a resolution of 2 seconds seconds /= FAT_TIME_SECONDS_SCALE; fat_time = (hours & FAT_TIME_HOURS_MASK) << FAT_TIME_HOURS_SHIFT; fat_time|= (minutes & FAT_TIME_MINUTES_MASK) << FAT_TIME_MINUTES_SHIFT; fat_time|= (seconds & FAT_TIME_SECONDS_MASK) << FAT_TIME_SECONDS_SHIFT; return fat_time; } //----------------------------------------------------------------------------- // fatfs_convert_to_fat_date: Convert d/m/y to FAT date //----------------------------------------------------------------------------- uint16 fatfs_convert_to_fat_date(int day, int month, int year) { uint16 fat_date = 0; // FAT dates are relative to 1980 if (year >= FAT_DATE_YEAR_OFFSET) year -= FAT_DATE_YEAR_OFFSET; fat_date = (day & FAT_DATE_DAY_MASK) << FAT_DATE_DAY_SHIFT; fat_date|= (month & FAT_DATE_MONTH_MASK) << FAT_DATE_MONTH_SHIFT; fat_date|= (year & FAT_DATE_YEAR_MASK) << FAT_DATE_YEAR_SHIFT; return fat_date; } #endif //----------------------------------------------------------------------------- // fatfs_print_sector: //----------------------------------------------------------------------------- #ifdef FATFS_DEBUG void fatfs_print_sector(uint32 sector, uint8 *data) { int i; int j; FAT_PRINTF(("Sector %d:\n", sector)); for (i=0;i 31 && ch < 127) { FAT_PRINTF(("%c", ch)); } else { FAT_PRINTF((".")); } } FAT_PRINTF(("\n")); } } } #endif