From bf9facc49c0ef0a8fabdda3d1e765c2edd2e390f Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Sun, 16 Aug 2009 17:18:45 +0000 Subject: 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 | 99 +++++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 45 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 */ + +/* 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) +/* 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) { - if (0 == *time) + time2 = *time << 1; + if (time2 == 0 || date_forced) { - /* set to 00:15:00 */ - *time = (15 << 5); + time2 = (11 < 6) | 11; /* set to 00:11:11 */ } else { - unsigned short mins = (*time >> 5) & 0x003F; - unsigned short hours = (*time >> 11) & 0x001F; - if ((mins += 10) >= 60) - { - mins = 0; - hours++; - } - if ((++hours) >= 24) + unsigned mins = (time2 >> 6) & 0x3f; + unsigned hours = (time2 >> 12) & 0x1f; + + mins = 11 * ((mins/11) + 1); /* advance to next multiple of 11 */ + if (mins > 59) { - hours = hours - 24; - next_day = true; + mins = 11; /* 00 would be a bad marker */ + if (++hours > 23) + { + hours = 0; + next_day = true; + } } - *time = (hours << 11) | (mins << 5); + time2 = (hours << 12) | (mins << 6) | mins; /* secs = mins */ } + *time = time2 >> 1; } + + if (tenth) + *tenth = (time2 & 1) * 100; - if (date) + if (date && next_day) { - if (0 == *date) - { -/* 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); - } - else + 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]) { - unsigned short day = *date & 0x001F; - unsigned short month = (*date >> 5) & 0x000F; - unsigned short year = (*date >> 9) & 0x007F; - if (next_day) + day = 1; + if (++month > 12) { - /* do a very simple day increment - never go above 28 days */ - if (++day > 28) - { - day = 1; - if (++month > 12) - { - month = 1; - year++; - } - } - *date = (year << 9) | (month << 5) | day; + month = 1; + year++; } } + *date = (year << 9) | (month << 5) | day; } - if (tenth) - *tenth = 0; + #endif /* CONFIG_RTC */ } -- cgit v1.2.3