Post Reply 
[newRPL] Filesystem related date/time issues
08-14-2016, 11:06 PM
Post: #1
[newRPL] Filesystem related date/time issues
Hi,

Having found some time to inspect the date/time related code in newRPL's FAT implementation, I added some comments (either helping me to understand and validate the code, or pointing at potential issues to be sorted out). The following snippets also illustrate some fixes and sanity checks I recommend to be included.

In order to keep the general newRPL thread readable, I'm opening a new thread for the topic...

https://sourceforge.net/p/newrpl/sources..._50g/rtc.c
Code:

int __getRTCvalue(int offset)
{
   // FIX 2016-08-12 MPL: volatile was missing
   unsigned char a = *((volatile unsigned char *)RTC_REGS + offset); // little endian

   return ((a&0xF0) >> 1) + ((a&0xF0) >> 3) + (a&0x0F); // convert BCD to binary
}

#define __getRTCSec()  __getRTCvalue(0x70) // 0..59
#define __getRTCMin()  __getRTCvalue(0x74) // 0..59
#define __getRTCHour() __getRTCvalue(0x78) // 0..23

#define __getRTCDay()  __getRTCvalue(0x7C) // 1..31
#define __getRTCMon()  __getRTCvalue(0x84) // 1..12
#define __getRTCYear() __getRTCvalue(0x88) // 00..98 (2000..2098), 99 (1999)

int rtc_getday()
{
   // FIX 2016-08-12 MPL: removed bcd definition, added missing return value.
   return __getRTCDay(); // 1-based
}

int rtc_getmon()
{
   return __getRTCMon(); // 1-based
}

int rtc_getyear()
{
   // DBG 2016-08-12 MPL: check RTC leap year & calendar rollover behaviour (99 is apparently defined as for 1999, not 2099 -- to be sorted out)
   return __getRTCYear() + 2000; // 2000-based
}

int rtc_getsec()
{
   return __getRTCSec(); // 0-based
}

int rtc_getmin()
{
   return __getRTCMin(); // 0-based
}

int rtc_gethour()
{
   return __getRTCHour(); // 0-based
}
https://sourceforge.net/p/newrpl/sources.../hal_api.h
Code:

struct compact_tm {
   unsigned tm_sec:6, // seconds after the minute 0-60*
             tm_min:6, // minutes after the hour 0-59
             tm_hour:5, // hours since midnight 0-23
             tm_mday:5, // day of the month 1-31 (0=day not set)
             // DBG 2016-08-12 MPL: Is there a particular reason why the
             // month entry is defined as a 0-based value, while the FAT dir
             // entry and the RTC register are 1-based? The FAT dir entry
             // allows for special value of 0 for "undefined", something we
             // cannot fully cope with at present
             tm_mon:4, // months since January 0-11
             tm_wday:3, // days since Sunday 0-6
             tm_isdst:1;
   unsigned int tm_year; // int years since 1900 (up to 2017 in FAT)
};
https://sourceforge.net/p/newrpl/sources...datetime.c
Code:

void FSGetDateTime(unsigned int *datetime, unsigned int *hundredths)
{
   unsigned int min, sec, hour, day, mon, year, flag = 0;

   do {
      year = rtc_getyear(); // Descending order is important here
      mon = rtc_getmon();
      day = rtc_getday();
      hour = rtc_gethour();
      min = rtc_getmin();
      sec = rtc_getsec();
      if (!sec) // if seconds rollover occured, loop around to reread all values 
         flag = ~flag; 
      // DBG 2016-08-12 MPL: Is one loop cycle enough for rollover
      // to be reliably propagated in RTC hardware? I've seen other code actually
      // looping until seconds become > 0 (which can cause delays up to 1 sec, though).
   } while (flag);
 
   year -= 1980; // fix from 1980 to 2079
   
   *datetime = (sec>>1) | (min<<5) | (hour<<11) | (day<<16) | (mon<<21) | (year<<25);            
   *hundredths = (sec&1) ? 100 : 0;

   return;
}
https://sourceforge.net/p/newrpl/sources...ritetime.c
Code:

// CHG 2016-08-13 MPL: Combined FSGetWriteTime(), FSGetCreatTime(), FSGetAccessDate() to avoid redundancy and save code

void FSGetDirStamp(FS_FILE *file, struct compact_tm *dt, unsigned char type_stamp)
{
   unsigned int a, b;

   // DBG 2016-08-13 MPL: could be much further optimized by
   // changing organization of FS_FILE struct and "dirty" coding
   if (type_stamp == 0) // access
      b = a = file->LastAccDate; // points to 16-bit value only
   else {
      if (type_stamp == 1) // modify
         a = file->WriteTimeDate;
      else // create
         a = file->CreatTimeDate;

      b = (a << 1) & 0x1F;
      // FIX 2016-08-12 MPL: ignore if greater than 29, no (valid) time record
      dt->tm_sec = (b <= 29) ? b : 0;
   
      b = (a >> 5) & 0x3F;
      // FIX 2016-08-12 MPL: ignore if greater than 59, no (valid) time record
      dt->tm_min = (b <= 59) ? b : 0;

      b = (a >> (5+6)) & 0x1F;
      // FIX 2016-08-12 MPL: ignore if greater than 23, no (valid) time record
      dt->tm_hour = (b <= 23) ? b : 0;

      b = a >> (5+6+5);
   }

   b &= 0x1F;
   // FIX 2016-08-12 MPL: set to 0 if greater than 31, indicate invalid day
   dt->tm_day = (b <= 31) ? b : 0; // value 0 = RTC (day) not set

   if (type_stamp) // modify and create
      b = a >> (5+6+5+5);
   else // access
      b = a >> 5;
   b &= 0x0F;
   // FIX 2016-08-12 MPL: set to 0 if greater than 12, indicate invalid month
   // DBG 2016-08-12 MPL: avoid underflow, but value 0 not properly dealt
   // with yet, alternatively we could set dt->tm_day to 0 to invalidate the
   // date as a whole
   dt->tm_mon = (b && (b <= 12)) ? b-1 : 0; // (value 0 = RTC (month) not set)

   if (type_stamp) // modify and create
      b = a >> (5+6+5+5+4);
   else { // access
      b = a >> (5+4);
      b &= 0x7F; // 0..127 for 1980..2107
   }
   dt->tm_year = b + 80; // count years from 1900 instead of 1980

   // DBG 2016-08-12 MPL: To be calculated from date
   dt->tm_wday = 0;
   // dt->tm_yday = 0;

   dt->tm_isdst = 0;

   return;
}

void FSGetWriteTime(FS_FILE *file, struct compact_tm *dt)
{
   FSGetDirStamp(file, dt, 1);

   return;
}
https://sourceforge.net/p/newrpl/sources...reattime.c
Code:

void FSGetCreatTime(FS_FILE *file, struct compact_tm *dt)
{
   FSGetDirStamp(file, dt, 2);

   dt->tm_sec += file->CrtTmTenth/100;

   return;
}
https://sourceforge.net/p/newrpl/sources...cessdate.c
Code:

void FSGetAccessDate(FS_FILE *file, struct compact_tm *dt)
{
   FSGetDirStamp(file, dt, 0);

   dt->tm_sec = 0;
   dt->tm_min = 0;
   dt->tm_hour = 0;

   return;
}
Hope it helps,

Matthias


--
"Programs are poems for computers."
Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
[newRPL] Filesystem related date/time issues - matthiaspaul - 08-14-2016 11:06 PM



User(s) browsing this thread: 1 Guest(s)