Some time manipulation. Added the targets to the .gitignore file.

This commit is contained in:
lephe 2016-08-08 15:01:33 +02:00
parent 1f223f807f
commit 58db663ae6
19 changed files with 268 additions and 71 deletions

5
.gitignore vendored
View file

@ -10,3 +10,8 @@ build/**
# Some notes.
LIBC
# Output files
libc.a
libgint.a
gintdemo.g1a

View file

@ -14,7 +14,7 @@
# Modules
modules-gint = core keyboard mmu mpu rtc screen timer \
bopti display gray tales
modules-libc = setjmp string stdio stdlib
modules-libc = setjmp string stdio stdlib time
# Targets
target-g1a = gintdemo.g1a

View file

@ -38,7 +38,7 @@ register access and implements a few standard functions.
Building and installing
-----------------------
There a some dependencies:
There are some dependencies:
* The `sh3eb-elf` toolchain somewhere in the PATH
* The fxSDK installed and available in the PATH

3
TODO
View file

@ -18,11 +18,10 @@
+ partial transparency
+ gint vs. ML with 248x124 at (-60, -28)
+ call exit handlers
+ compute frequencies
+ compute frequencies and CLOCKS_PER_SEC
+ test all font encodings
- improve exception handler debugging information (if possible)
- full rtc driver (time)
- callbacks and complete user API
~ packed bit fields

Binary file not shown.

16
include/internals/time.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef _INTERNALS_TIME_H
#define _INTERNALS_TIME_H 1
/*
isLeap()
Determines whether the given year is a leap year.
*/
int isLeap(int year);
/*
daysInMonth()
Returns number of days for the given month (between 0 and 11) and year.
*/
int daysInMonth(int month, int year);
#endif // _INTERNALS_TIME_H

View file

@ -15,9 +15,7 @@
/*
struct RTCTime
Defines a point in time. This structure *is* the standard struct tm to
avoid useless data copy in the interface between this module and the
standard time module.
Defines a point in time.
*/
struct RTCTime
{
@ -26,21 +24,21 @@ struct RTCTime
int hours; // Hours in range 0-23
int month_day; // Day of month in range 1-31
int month; // Month in range 0-11
int year; // Number of years since 1900
int year; // Years (full value)
int week_day; // Day of week in range 0(Sunday)-6(Saturday).
int year_day; // Day of the year in range 0-365.
int daylight_saving; // As far as I known the RTC does not use DST.
};
/*
rtc_getTime()
Reads the current time from the RTC.
Reads the current time from the RTC. There is no guarantee that the
week day is correct (use the time API for that).
*/
struct RTCTime rtc_getTime(void);
/*
rtc_setTime()
Sets the time in the RTC registers.
Sets the time in the RTC registers. The week day is set to 0 if greater
than 6. Other fields are not checked.
*/
void rtc_setTime(struct RTCTime time);

View file

@ -29,7 +29,7 @@ struct tm
int tm_year; // Number of years since 1900
int tm_wday; // Day of week in range 0(Sunday)-6(Saturday).
int tm_yday; // Day of the year in range 0-365.
int tm_isdst; // Always -1 (not available).
int tm_isdst; // This will always be 0.
};
/*
@ -57,6 +57,17 @@ typedef signed int time_t;
*/
clock_t clock(void);
/*
time()
Returns the current time as calendar time. If you need a broken-down
time, either use the RTC API or gmtime(). However, this function is
already based on mktime() (for hardware reasons) so it would be much
faster to use the RTC API if possible.
If timeptr is not NULL, it is set to the current time, that is, the
value that is returned.
*/
time_t time(time_t *timeptr);
/*
difftime()
Returns the number of seconds between the given points.
@ -71,15 +82,45 @@ double difftime(time_t end, time_t beginning);
// Time representation.
//---
/*
asctime()
Converts broken-down time to string representation on the form
"Wed Jun 30 21:49:08 1993\n". The returned string is statically
allocated and may be overwritten by any subsequent call to a time
function.
*/
char *asctime(const struct tm *time);
/*
ctime()
Converts calendar time to string representation on the form
"Wed Jun 30 21:49:08 1993\n". The returned string is statically
allocated and may be overwritten by any subsequent call to a time
function.
*/
char *ctime(const time_t *timer);
//---
//
// Time conversion.
//---
/*
mktime()
Computes fields tm_wday and tm_yday using the other fields. Member
structures outside their range are normalized and tm_isdst is set.
Converts broken-down time to calendar time. Computes structure fields
tm_wday and tm_yday using the other fields. Member structures outside
their range are normalized (e.g. 40 October becomes 9 November) and
tm_isdst is set.
*/
time_t mktime(struct tm *time);
/*
gmtime()
Converts calendar time to broken-down time. The returned pointer is
statically allocated and may be overwritten by any subsequent call to
a time function.
*/
struct tm *gmtime(const time_t *t);
#endif // _TIME_H

BIN
libc.a

Binary file not shown.

BIN
libgint.a

Binary file not shown.

View file

@ -16,23 +16,11 @@ static int integer16(int bcd)
+ 1000 * (bcd >> 12);
}
static int year_day(int year, int year_bcd, int month, int month_day)
{
int days_in_month[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int leap;
int hundreds = integer8(year_bcd >> 8);
int day, i;
leap = !(year & 3); // Take multiples of 4
if(!((year_bcd >> 8) & 0xf)) leap = 0; // Remove multiples of 100
if(!(hundreds & 3)) leap = 1; // Take multiples of 400
day = leap && (month > 2);
for(i = 0; i < month - 1; i++) day += days_in_month[i];
return day + month_day - 1;
}
/*
rtc_getTime()
Reads the current time from the RTC. There is no guarantee that the
week day is correct (use the time API for that).
*/
struct RTCTime rtc_getTime(void)
{
volatile struct mod_rtc *rtc = isSH3() ? RTC_SH7705 : RTC_SH7305;
@ -43,11 +31,8 @@ struct RTCTime rtc_getTime(void)
time.hours = integer8(rtc->RHRCNT.BYTE);
time.month_day = integer8(rtc->RDAYCNT.BYTE);
time.month = integer8(rtc->RMONCNT.BYTE);
time.year = integer16(rtc->RYRCNT.WORD) - 1900;
time.year = integer16(rtc->RYRCNT.WORD);
time.week_day = rtc->RWKCNT;
time.year_day = year_day(time.year + 1900, rtc->RYRCNT.WORD,
time.month, time.month_day);
time.daylight_saving = 0;
return time;
}

View file

@ -17,6 +17,11 @@ static int bcd16(int integer)
return (bcd8(integer / 100) << 8) | bcd8(integer % 100);
}
/*
rtc_setTime()
Sets the time in the RTC registers. The week day is set to 0 if greater
than 6. Other fields are not checked.
*/
void rtc_setTime(struct RTCTime time)
{
volatile struct mod_rtc *rtc = isSH3() ? RTC_SH7705 : RTC_SH7305;
@ -26,6 +31,6 @@ void rtc_setTime(struct RTCTime time)
rtc->RHRCNT.BYTE = bcd8(time.hours);
rtc->RDAYCNT.BYTE = bcd8(time.month_day);
rtc->RMONCNT.BYTE = bcd8(time.month);
rtc->RYRCNT.WORD = bcd16(time.year + 1900);
rtc->RYRCNT.WORD = bcd16(time.year);
rtc->RWKCNT = time.week_day < 7 ? time.week_day : 0;
}

57
src/time/asctime.c Normal file
View file

@ -0,0 +1,57 @@
#include <time.h>
static char str[26];
/*
asctime()
Converts broken-down time to string representation on the form
"Wed Jun 30 21:49:08 1993\n". The returned string is statically
allocated and may be overwritten by any subsequent call to a time
function.
*/
char *asctime(const struct tm *time)
{
const char *days[] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
}, *months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec"
};
int year = time->tm_year + 1900;
str[0] = days[time->tm_wday][0];
str[1] = days[time->tm_wday][1];
str[2] = days[time->tm_wday][2];
str[3] = ' ';
str[4] = months[time->tm_mon][0];
str[5] = months[time->tm_mon][1];
str[6] = months[time->tm_mon][2];
str[7] = ' ';
str[8] = '0' + (time->tm_mday / 10);
str[9] = '0' + (time->tm_mday % 10);
str[10] = ' ';
str[11] = '0' + (time->tm_hour / 10);
str[12] = '0' + (time->tm_hour % 10);
str[13] = ':';
str[14] = '0' + (time->tm_min / 10);
str[15] = '0' + (time->tm_min % 10);
str[16] = ':';
str[17] = '0' + (time->tm_sec / 10);
str[18] = '0' + (time->tm_sec % 10);
str[19] = ' ';
str[20] = '0' + (year / 1000);
year %= 1000;
str[21] = '0' + (year / 100);
year %= 100;
str[22] = '0' + (year / 10);
str[23] = '0' + (year % 10);
str[24] = '\n';
str[25] = 0;
return str;
}

13
src/time/ctime.c Normal file
View file

@ -0,0 +1,13 @@
#include <time.h>
/*
ctime()
Converts calendar time to string representation on the form
"Wed Jun 30 21:49:08 1993\n". The returned string is statically
allocated and may be overwritten by any subsequent call to a time
function.
*/
char *ctime(const time_t *timer)
{
return asctime(gmtime(timer));
}

45
src/time/gmtime.c Normal file
View file

@ -0,0 +1,45 @@
#include <time.h>
#include <internals/time.h>
#include <stdlib.h>
static struct tm tm;
/*
gmtime()
Converts calendar time to broken-down time. The returned pointer is
statically allocated and may be overwritten by any subsequent call to
a time function.
*/
struct tm *gmtime(const time_t *timeptr)
{
time_t t = *timeptr;
div_t d;
int sec;
tm.tm_year = 1970;
tm.tm_mon = 0;
sec = daysInMonth(tm.tm_mon, tm.tm_year) * 24 * 3600;
while(t >= sec)
{
t -= sec;
if(++tm.tm_mon == 12)
{
tm.tm_year++;
tm.tm_mon = 0;
}
sec = daysInMonth(tm.tm_mon, tm.tm_year) * 24 * 3600;
}
tm.tm_year -= 1900;
d = div(sec, 24 * 3600);
tm.tm_mday = d.quot;
d = div(d.rem, 3600);
tm.tm_hour = d.quot;
d = div(d.rem, 60);
tm.tm_min = d.quot;
tm.tm_sec = d.rem;
mktime(&tm);
return &tm;
}

View file

@ -1,42 +1,17 @@
#include <time.h>
/*
isLeap()
Determines whether the given year is a leap year.
*/
int isLeap(int year)
{
int leap = !(year & 3); // Take multiples of 4
if(!(year % 100)) leap = 0; // Remove multiples of 100
if(!(year % 400)) leap = 1; // Take multiples of 400
return leap;
}
/*
daysInMonth()
Returns number of days for the given month (between 0 and 11) and year.
*/
int daysInMonth(int month, int year)
{
int days[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
if(month != 1) return days[month];
return days[month] + isLeap(year);
}
#include <internals/time.h>
/*
mktime()
Computes fields tm_wday and tm_yday using the other fields. Member
structures outside their range are normalized and tm_isdst is set.
Converts broken-down time to calendar time. Computes structure fields
tm_wday and tm_yday using the other fields. Member structures outside
their range are normalized (e.g. 40 October becomes 9 November) and
tm_isdst is set.
*/
time_t mktime(struct tm *time)
{
int first, leaps, yr;
int leaps, yr;
int days, i;
time_t elapsed;
// Normalizing time.
time->tm_min += (time->tm_sec / 60);
@ -88,6 +63,6 @@ time_t mktime(struct tm *time)
// days may become negative, so add the calendar period.
if(days < 0) days += 146097;
return (24 * 3600) * days + 3600 * time->tm_hour + 60 * time->tm_min +
time->tm_sec;
return (time_t)((24 * 3600) * days + 3600 * time->tm_hour +
60 * time->tm_min + time->tm_sec);
}

29
src/time/time.c Normal file
View file

@ -0,0 +1,29 @@
#include <time.h>
#include <rtc.h>
/*
time()
Returns the current time as calendar time. If you need a broken-down
time, either use the RTC API or gmtime(). However, this function is
already based on mktime() (for hardware reasons) so it would be much
faster to use the RTC API if possible.
If timeptr is not NULL, it is set to the current time, that is, the
value that is returned.
*/
time_t time(time_t *timeptr)
{
struct RTCTime rtc = rtc_getTime();
struct tm tm;
time_t calendar;
tm.tm_sec = rtc.seconds;
tm.tm_min = rtc.minutes;
tm.tm_hour = rtc.hours;
tm.tm_mday = rtc.month_day;
tm.tm_mon = rtc.month;
tm.tm_year = rtc.year - 1900;
calendar = mktime(&tm);
if(timeptr) *timeptr = calendar;
return calendar;
}

View file

@ -1,4 +1,5 @@
#include <time.h>
#undef difftime
/*
clock()

28
src/time/time_util.c Normal file
View file

@ -0,0 +1,28 @@
#include <internals/time.h>
/*
isLeap()
Determines whether the given year is a leap year.
*/
int isLeap(int year)
{
int leap = !(year & 3); // Take multiples of 4
if(!(year % 100)) leap = 0; // Remove multiples of 100
if(!(year % 400)) leap = 1; // Take multiples of 400
return leap;
}
/*
daysInMonth()
Returns number of days for the given month (between 0 and 11) and year.
*/
int daysInMonth(int month, int year)
{
int days[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
if(month != 1) return days[month];
return days[month] + isLeap(year);
}