From bf9facc49c0ef0a8fabdda3d1e765c2edd2e390f Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Sun, 16 Aug 2009 17:18:45 +0000 Subject: [PATCH] FAT timestamp handling improvements for non-RTC targets: - When writing to a file that is older than the build, file date is set to the build date. - Time is advanced so that the minutes are a multiple of 11, excluding '00', and seconds = minutes. This is done as a hint that the time isn't 100% correct. - Date increment uses actual month lengths (but without leap year handling) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22348 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/fat.c | 107 ++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 49 deletions(-) diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c index e319669e97..578397cbe6 100644 --- a/firmware/drivers/fat.c +++ b/firmware/drivers/fat.c @@ -1001,70 +1001,79 @@ static void fat_time(unsigned short* date, #else /* non-RTC version returns an increment from the supplied time, or a * fixed standard time/date if no time given as input */ - bool next_day = false; - if (time) - { - if (0 == *time) - { - /* set to 00:15:00 */ - *time = (15 << 5); - } - else - { - unsigned short mins = (*time >> 5) & 0x003F; - unsigned short hours = (*time >> 11) & 0x001F; - if ((mins += 10) >= 60) - { - mins = 0; - hours++; - } - if ((++hours) >= 24) - { - hours = hours - 24; - next_day = true; - } - *time = (hours << 11) | (mins << 5); - } - } - - if (date) - { - if (0 == *date) - { -/* Macros to convert a 2-digit string to a decimal constant. +/* Macros to convert a 2-digit string to a decimal constant. (YEAR), MONTH and DAY are set by the date command, which outputs DAY as 00..31 and MONTH as 01..12. The leading zero would lead to misinterpretation as an octal constant. */ #define S100(x) 1 ## x #define C2DIG2DEC(x) (S100(x)-100) - /* set to build date */ - *date = ((YEAR - 1980) << 9) | (C2DIG2DEC(MONTH) << 5) - | C2DIG2DEC(DAY); +/* The actual build date, as FAT date constant */ +#define BUILD_DATE_FAT (((YEAR - 1980) << 9) \ + | (C2DIG2DEC(MONTH) << 5) \ + | C2DIG2DEC(DAY)) + + bool date_forced = false; + bool next_day = false; + unsigned time2 = 0; /* double time, for CRTTIME with 1s precision */ + + if (date && *date < BUILD_DATE_FAT) + { + *date = BUILD_DATE_FAT; + date_forced = true; + } + + if (time) + { + time2 = *time << 1; + if (time2 == 0 || date_forced) + { + time2 = (11 < 6) | 11; /* set to 00:11:11 */ } else { - unsigned short day = *date & 0x001F; - unsigned short month = (*date >> 5) & 0x000F; - unsigned short year = (*date >> 9) & 0x007F; - if (next_day) + unsigned mins = (time2 >> 6) & 0x3f; + unsigned hours = (time2 >> 12) & 0x1f; + + mins = 11 * ((mins/11) + 1); /* advance to next multiple of 11 */ + if (mins > 59) { - /* do a very simple day increment - never go above 28 days */ - if (++day > 28) + mins = 11; /* 00 would be a bad marker */ + if (++hours > 23) { - day = 1; - if (++month > 12) - { - month = 1; - year++; - } + hours = 0; + next_day = true; } - *date = (year << 9) | (month << 5) | day; + } + time2 = (hours << 12) | (mins << 6) | mins; /* secs = mins */ + } + *time = time2 >> 1; + } + + if (tenth) + *tenth = (time2 & 1) * 100; + + if (date && next_day) + { + static const unsigned char daysinmonth[] = + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + unsigned day = *date & 0x1f; + unsigned month = (*date >> 5) & 0x0f; + unsigned year = (*date >> 9) & 0x7f; + + /* simplification: ignore leap years */ + if (++day > daysinmonth[month-1]) + { + day = 1; + if (++month > 12) + { + month = 1; + year++; } } + *date = (year << 9) | (month << 5) | day; } - if (tenth) - *tenth = 0; + #endif /* CONFIG_RTC */ }