[sky9x] RTC Clock on FAT (not tested)
[gruvin9x] RTC Menu redesigned [stock] ~50bytes flash saved
This commit is contained in:
+4
-475
@@ -31,488 +31,17 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ff.h"
|
||||
#include "fattime.h"
|
||||
#include "integer.h"
|
||||
|
||||
#define LEAP_SECONDS_POSSIBLE 0
|
||||
|
||||
/* Shift A right by B bits portably, by dividing A by 2**B and
|
||||
truncating towards minus infinity. A and B should be free of side
|
||||
effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
|
||||
INT_BITS is the number of useful bits in an int. GNU code can
|
||||
assume that INT_BITS is at least 32.
|
||||
|
||||
ISO C99 says that A >> B is implementation-defined if A < 0. Some
|
||||
implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
|
||||
right in the usual way when A < 0, so SHR falls back on division if
|
||||
ordinary A >> B doesn't seem to be the usual signed shift. */
|
||||
#define SHR(a, b) \
|
||||
(-1 >> 1 == -1 \
|
||||
? (a) >> (b) \
|
||||
: (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
|
||||
|
||||
/* The extra casts in the following macros work around compiler bugs,
|
||||
e.g., in Cray C 5.0.3.0. */
|
||||
|
||||
/* True if the arithmetic type T is an integer type. bool counts as
|
||||
an integer. */
|
||||
#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
|
||||
|
||||
/* True if negative values of the signed integer type T use two's
|
||||
complement, ones' complement, or signed magnitude representation,
|
||||
respectively. Much GNU code assumes two's complement, but some
|
||||
people like to be portable to all possible C hosts. */
|
||||
#define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
|
||||
#define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
|
||||
#define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
|
||||
|
||||
/* True if the arithmetic type T is signed. */
|
||||
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
|
||||
|
||||
/* The maximum and minimum values for the integer type T. These
|
||||
macros have undefined behavior if T is signed and has padding bits.
|
||||
If this is a problem for you, please let us know how to fix it for
|
||||
your host. */
|
||||
#define TYPE_MINIMUM(t) \
|
||||
((t) (! TYPE_SIGNED (t) \
|
||||
? (t) 0 \
|
||||
: TYPE_SIGNED_MAGNITUDE (t) \
|
||||
? ~ (t) 0 \
|
||||
: ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
|
||||
#define TYPE_MAXIMUM(t) \
|
||||
((t) (! TYPE_SIGNED (t) \
|
||||
? (t) -1 \
|
||||
: ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
|
||||
|
||||
#ifndef TIME_T_MIN
|
||||
# define TIME_T_MIN TYPE_MINIMUM (gtime_t)
|
||||
#endif
|
||||
#ifndef TIME_T_MAX
|
||||
# define TIME_T_MAX TYPE_MAXIMUM (gtime_t)
|
||||
#endif
|
||||
#define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1)
|
||||
|
||||
/* Verify a requirement at compile-time (unlike assert, which is runtime). */
|
||||
#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
|
||||
|
||||
verify (gtime_t_is_integer, TYPE_IS_INTEGER (gtime_t));
|
||||
verify (twos_complement_arithmetic, TYPE_TWOS_COMPLEMENT (int));
|
||||
/* The code also assumes that signed integer overflow silently wraps
|
||||
around, but this assumption can't be stated without causing a
|
||||
diagnostic on some hosts. */
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
#define TM_YEAR_BASE 1900
|
||||
verify (base_year_is_a_multiple_of_100, TM_YEAR_BASE % 100 == 0);
|
||||
|
||||
#define SECS_PER_HOUR 3600ul
|
||||
#define SECS_PER_DAY 86400ul
|
||||
|
||||
/* Return 1 if YEAR + TM_YEAR_BASE is a leap year. */
|
||||
static inline int
|
||||
leapyear (long int year)
|
||||
{
|
||||
/* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
|
||||
Also, work even if YEAR is negative. */
|
||||
return
|
||||
((year & 3) == 0
|
||||
&& (year % 100 != 0
|
||||
|| ((year / 100) & 3) == (- (TM_YEAR_BASE / 100) & 3)));
|
||||
}
|
||||
|
||||
const unsigned short int __mon_yday[2][13] =
|
||||
{
|
||||
/* Normal years. */
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
|
||||
/* Leap years. */
|
||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
|
||||
};
|
||||
|
||||
/* Compute the `struct tm' representation of *T,
|
||||
offset OFFSET seconds east of UTC,
|
||||
and store year, yday, mon, mday, wday, hour, min, sec into *TP.
|
||||
Return nonzero if successful. */
|
||||
int
|
||||
__offtime (
|
||||
gtime_t *t,
|
||||
long int offset,
|
||||
struct gtm *tp)
|
||||
{
|
||||
long int days, rem, y;
|
||||
const unsigned short int *ip;
|
||||
|
||||
days = *t / SECS_PER_DAY;
|
||||
rem = *t % SECS_PER_DAY;
|
||||
rem += offset;
|
||||
while (rem < 0)
|
||||
{
|
||||
rem += SECS_PER_DAY;
|
||||
--days;
|
||||
}
|
||||
while (rem >= (long int)SECS_PER_DAY)
|
||||
{
|
||||
rem -= SECS_PER_DAY;
|
||||
++days;
|
||||
}
|
||||
tp->tm_hour = rem / SECS_PER_HOUR;
|
||||
rem %= SECS_PER_HOUR;
|
||||
tp->tm_min = rem / 60;
|
||||
tp->tm_sec = rem % 60;
|
||||
/* January 1, 1970 was a Thursday. */
|
||||
tp->tm_wday = (4 + days) % 7;
|
||||
if (tp->tm_wday < 0)
|
||||
tp->tm_wday += 7;
|
||||
y = 1970;
|
||||
|
||||
#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
|
||||
#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
|
||||
|
||||
while (days < 0 || days >= (leapyear (y) ? 366 : 365))
|
||||
{
|
||||
/* Guess a corrected year, assuming 365 days per year. */
|
||||
long int yg = y + days / 365 - (days % 365 < 0);
|
||||
|
||||
/* Adjust DAYS and Y to match the guessed year. */
|
||||
days -= ((yg - y) * 365
|
||||
+ LEAPS_THRU_END_OF (yg - 1)
|
||||
- LEAPS_THRU_END_OF (y - 1));
|
||||
y = yg;
|
||||
}
|
||||
tp->tm_year = y - 1900;
|
||||
if (tp->tm_year != y - 1900)
|
||||
{
|
||||
/* The year cannot be represented due to overflow. */
|
||||
// __set_errno (EOVERFLOW);
|
||||
return 0;
|
||||
}
|
||||
tp->tm_yday = days;
|
||||
ip = __mon_yday[leapyear(y)];
|
||||
for (y = 11; days < (long int) ip[y]; --y)
|
||||
continue;
|
||||
days -= ip[y];
|
||||
tp->tm_mon = y;
|
||||
tp->tm_mday = days + 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* time_r function implementations */
|
||||
// G: No time zones in our implementation so just do the converion from gtime_t to struct tm
|
||||
struct gtm *
|
||||
__localtime_r (gtime_t * t, struct gtm * tp)
|
||||
{
|
||||
__offtime(t, 0, tp);
|
||||
return tp;
|
||||
}
|
||||
|
||||
|
||||
/* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
|
||||
(YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
|
||||
were not adjusted between the time stamps.
|
||||
|
||||
The YEAR values uses the same numbering as TP->tm_year. Values
|
||||
need not be in the usual range. However, YEAR1 must not be less
|
||||
than 2 * INT_MIN or greater than 2 * INT_MAX.
|
||||
|
||||
The result may overflow. It is the caller's responsibility to
|
||||
detect overflow. */
|
||||
|
||||
static inline gtime_t
|
||||
ydhms_diff (long int year1, long int yday1, int hour1, int min1, int sec1,
|
||||
int year0, int yday0, int hour0, int min0, int sec0)
|
||||
{
|
||||
verify (C99_integer_division, -1 / 2 == 0);
|
||||
verify (long_int_year_and_yday_are_wide_enough,
|
||||
INT_MAX <= LONG_MAX / 2 || TIME_T_MAX <= UINT_MAX);
|
||||
|
||||
/* Compute intervening leap days correctly even if year is negative.
|
||||
Take care to avoid integer overflow here. */
|
||||
int a4 = SHR (year1, 2) + SHR (TM_YEAR_BASE, 2) - ! (year1 & 3);
|
||||
int b4 = SHR (year0, 2) + SHR (TM_YEAR_BASE, 2) - ! (year0 & 3);
|
||||
int a100 = a4 / 25 - (a4 % 25 < 0);
|
||||
int b100 = b4 / 25 - (b4 % 25 < 0);
|
||||
int a400 = SHR (a100, 2);
|
||||
int b400 = SHR (b100, 2);
|
||||
int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
|
||||
|
||||
/* Compute the desired time in gtime_t precision. Overflow might
|
||||
occur here. */
|
||||
gtime_t tyear1 = year1;
|
||||
gtime_t years = tyear1 - year0;
|
||||
gtime_t days = 365 * years + yday1 - yday0 + intervening_leap_days;
|
||||
gtime_t hours = 24 * days + hour1 - hour0;
|
||||
gtime_t minutes = 60 * hours + min1 - min0;
|
||||
gtime_t seconds = 60 * minutes + sec1 - sec0;
|
||||
return seconds;
|
||||
}
|
||||
|
||||
/* Return a gtime_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
|
||||
assuming that *T corresponds to *TP and that no clock adjustments
|
||||
occurred between *TP and the desired time.
|
||||
If TP is null, return a value not equal to *T; this avoids false matches.
|
||||
If overflow occurs, yield the minimal or maximal value, except do not
|
||||
yield a value equal to *T. */
|
||||
static gtime_t
|
||||
guess_time_tm (long int year, long int yday, int hour, int min, int sec,
|
||||
gtime_t *t, struct gtm *tp)
|
||||
{
|
||||
if (tp)
|
||||
{
|
||||
gtime_t d = ydhms_diff (year, yday, hour, min, sec,
|
||||
tp->tm_year, tp->tm_yday,
|
||||
tp->tm_hour, tp->tm_min, tp->tm_sec);
|
||||
gtime_t t1 = *t + d;
|
||||
if ((t1 < *t) == (TYPE_SIGNED (gtime_t) ? d < 0 : TIME_T_MAX / 2 < d))
|
||||
return t1;
|
||||
}
|
||||
|
||||
/* Overflow occurred one way or another. Return the nearest result
|
||||
that is actually in range, except don't report a zero difference
|
||||
if the actual difference is nonzero, as that would cause a false
|
||||
match; and don't oscillate between two values, as that would
|
||||
confuse the spring-forward gap detector. */
|
||||
return (*t < TIME_T_MIDPOINT
|
||||
? (*t <= TIME_T_MIN + 1 ? *t + 1 : TIME_T_MIN)
|
||||
: (TIME_T_MAX - 1 <= *t ? *t - 1 : TIME_T_MAX));
|
||||
}
|
||||
|
||||
/* Use CONVERT to convert *T to a broken down time in *TP.
|
||||
If *T is out of range for conversion, adjust it so that
|
||||
it is the nearest in-range value and then convert that. */
|
||||
static struct gtm *
|
||||
ranged_convert (struct gtm *(*convert) (gtime_t *, struct gtm *),
|
||||
gtime_t *t, struct gtm *tp)
|
||||
{
|
||||
struct gtm *r = convert (t, tp);
|
||||
|
||||
if (!r && *t)
|
||||
{
|
||||
gtime_t bad = *t;
|
||||
gtime_t ok = 0;
|
||||
|
||||
/* BAD is a known unconvertible gtime_t, and OK is a known good one.
|
||||
Use binary search to narrow the range between BAD and OK until
|
||||
they differ by 1. */
|
||||
while (bad != ok + (bad < 0 ? -1 : 1))
|
||||
{
|
||||
gtime_t mid = *t = (bad < 0
|
||||
? bad + ((ok - bad) >> 1)
|
||||
: ok + ((bad - ok) >> 1));
|
||||
r = convert (t, tp);
|
||||
if (r)
|
||||
ok = mid;
|
||||
else
|
||||
bad = mid;
|
||||
}
|
||||
|
||||
if (!r && ok)
|
||||
{
|
||||
/* The last conversion attempt failed;
|
||||
revert to the most recent successful attempt. */
|
||||
*t = ok;
|
||||
r = convert (t, tp);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Convert *TP to a gtime_t value, inverting
|
||||
the monotonic and mostly-unit-linear conversion function CONVERT.
|
||||
Use *OFFSET to keep track of a guess at the offset of the result,
|
||||
compared to what the result would be for UTC without leap seconds.
|
||||
If *OFFSET's guess is correct, only one CONVERT call is needed.
|
||||
This function is external because it is used also by timegm.c. */
|
||||
gtime_t
|
||||
__mktime_internal (struct gtm *tp,
|
||||
struct gtm *(*convert) (gtime_t *, struct gtm *),
|
||||
gtime_t *offset)
|
||||
{
|
||||
gtime_t t, gt, t0, t1, t2;
|
||||
struct gtm tm;
|
||||
|
||||
/* The maximum number of probes (calls to CONVERT) should be enough
|
||||
to handle any combinations of time zone rule changes, solar time,
|
||||
leap seconds, and oscillations around a spring-forward gap.
|
||||
POSIX.1 prohibits leap seconds, but some hosts have them anyway. */
|
||||
int remaining_probes = 6;
|
||||
|
||||
/* Time requested. Copy it in case CONVERT modifies *TP; this can
|
||||
occur if TP is localtime's returned value and CONVERT is localtime. */
|
||||
int sec = tp->tm_sec;
|
||||
int min = tp->tm_min;
|
||||
int hour = tp->tm_hour;
|
||||
int mday = tp->tm_mday;
|
||||
int mon = tp->tm_mon;
|
||||
int year_requested = tp->tm_year;
|
||||
|
||||
/* Ensure that mon is in range, and set year accordingly. */
|
||||
int mon_remainder = mon % 12;
|
||||
int negative_mon_remainder = mon_remainder < 0;
|
||||
int mon_years = mon / 12 - negative_mon_remainder;
|
||||
long int lyear_requested = year_requested;
|
||||
long int year = lyear_requested + mon_years;
|
||||
|
||||
/* The other values need not be in range:
|
||||
the remaining code handles minor overflows correctly,
|
||||
assuming int and gtime_t arithmetic wraps around.
|
||||
Major overflows are caught at the end. */
|
||||
|
||||
/* Calculate day of year from year, month, and day of month.
|
||||
The result need not be in range. */
|
||||
int mon_yday = ((__mon_yday[leapyear (year)]
|
||||
[mon_remainder + 12 * negative_mon_remainder])
|
||||
- 1);
|
||||
long int lmday = mday;
|
||||
long int yday = mon_yday + lmday;
|
||||
|
||||
gtime_t guessed_offset = *offset;
|
||||
|
||||
int sec_requested = sec;
|
||||
|
||||
/*
|
||||
if (LEAP_SECONDS_POSSIBLE)
|
||||
{
|
||||
// Handle out-of-range seconds specially,
|
||||
// since ydhms_tm_diff assumes every minute has 60 seconds.
|
||||
if (sec < 0)
|
||||
sec = 0;
|
||||
if (59 < sec)
|
||||
sec = 59;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Invert CONVERT by probing. First assume the same offset as last
|
||||
time. */
|
||||
|
||||
t0 = ydhms_diff (year, yday, hour, min, sec,
|
||||
EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, - guessed_offset);
|
||||
|
||||
if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
|
||||
{
|
||||
/* gtime_t isn't large enough to rule out overflows, so check
|
||||
for major overflows. A gross check suffices, since if t0
|
||||
has overflowed, it is off by a multiple of TIME_T_MAX -
|
||||
TIME_T_MIN + 1. So ignore any component of the difference
|
||||
that is bounded by a small value. */
|
||||
|
||||
/* Approximate log base 2 of the number of time units per
|
||||
biennium. A biennium is 2 years; use this unit instead of
|
||||
years to avoid integer overflow. For example, 2 average
|
||||
Gregorian years are 2 * 365.2425 * 24 * 60 * 60 seconds,
|
||||
which is 63113904 seconds, and rint (log2 (63113904)) is
|
||||
26. */
|
||||
int ALOG2_SECONDS_PER_BIENNIUM = 26;
|
||||
int ALOG2_MINUTES_PER_BIENNIUM = 20;
|
||||
int ALOG2_HOURS_PER_BIENNIUM = 14;
|
||||
int ALOG2_DAYS_PER_BIENNIUM = 10;
|
||||
int LOG2_YEARS_PER_BIENNIUM = 1;
|
||||
|
||||
int approx_requested_biennia =
|
||||
(SHR (year_requested, LOG2_YEARS_PER_BIENNIUM)
|
||||
- SHR (EPOCH_YEAR - TM_YEAR_BASE, LOG2_YEARS_PER_BIENNIUM)
|
||||
+ SHR (mday, ALOG2_DAYS_PER_BIENNIUM)
|
||||
+ SHR (hour, ALOG2_HOURS_PER_BIENNIUM)
|
||||
+ SHR (min, ALOG2_MINUTES_PER_BIENNIUM)
|
||||
+ (LEAP_SECONDS_POSSIBLE
|
||||
? 0
|
||||
: SHR (sec, ALOG2_SECONDS_PER_BIENNIUM)));
|
||||
|
||||
int approx_biennia = SHR (t0, ALOG2_SECONDS_PER_BIENNIUM);
|
||||
int diff = approx_biennia - approx_requested_biennia;
|
||||
int abs_diff = diff < 0 ? - diff : diff;
|
||||
|
||||
/* IRIX 4.0.5 cc miscalculates TIME_T_MIN / 3: it erroneously
|
||||
gives a positive value of 715827882. Setting a variable
|
||||
first then doing math on it seems to work.
|
||||
(ghazi@caip.rutgers.edu) */
|
||||
gtime_t time_t_max = TIME_T_MAX;
|
||||
gtime_t time_t_min = TIME_T_MIN;
|
||||
gtime_t overflow_threshold =
|
||||
(time_t_max / 3 - time_t_min / 3) >> ALOG2_SECONDS_PER_BIENNIUM;
|
||||
|
||||
if (overflow_threshold < abs_diff)
|
||||
{
|
||||
/* Overflow occurred. Try repairing it; this might work if
|
||||
the time zone offset is enough to undo the overflow. */
|
||||
gtime_t repaired_t0 = -1 - t0;
|
||||
approx_biennia = SHR (repaired_t0, ALOG2_SECONDS_PER_BIENNIUM);
|
||||
diff = approx_biennia - approx_requested_biennia;
|
||||
abs_diff = diff < 0 ? - diff : diff;
|
||||
if (overflow_threshold < abs_diff)
|
||||
return -1;
|
||||
guessed_offset += repaired_t0 - t0;
|
||||
t0 = repaired_t0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Repeatedly use the error to improve the guess. */
|
||||
|
||||
for (t = t1 = t2 = t0;
|
||||
(gt = guess_time_tm (year, yday, hour, min, sec, &t,
|
||||
ranged_convert (convert, &t, &tm)),
|
||||
t != gt);
|
||||
t1 = t2, t2 = t, t = gt)
|
||||
if (t == t1 && t != t2)
|
||||
goto offset_found;
|
||||
else if (--remaining_probes == 0)
|
||||
return -1;
|
||||
|
||||
offset_found:
|
||||
*offset = guessed_offset + t - t0;
|
||||
|
||||
if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
|
||||
{
|
||||
/* Adjust time to reflect the tm_sec requested, not the normalized value.
|
||||
Also, repair any damage from a false match due to a leap second. */
|
||||
int sec_adjustment = (sec == 0 && tm.tm_sec == 60) - sec;
|
||||
t1 = t + sec_requested;
|
||||
t2 = t1 + sec_adjustment;
|
||||
if (((t1 < t) != (sec_requested < 0))
|
||||
| ((t2 < t1) != (sec_adjustment < 0))
|
||||
| ! convert (&t2, &tm))
|
||||
return -1;
|
||||
t = t2;
|
||||
}
|
||||
|
||||
*tp = tm;
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Convert *TP to a gtime_t value. */
|
||||
gtime_t
|
||||
gmktime (struct gtm *tp)
|
||||
{
|
||||
// no time zone stuff. Just do the math ;)
|
||||
static gtime_t localtime_offset;
|
||||
return __mktime_internal (tp, __localtime_r, &localtime_offset);
|
||||
}
|
||||
|
||||
/* Fill a (struct tm) TP* from a given gtime_t time stamp */
|
||||
gtime_t
|
||||
filltm(gtime_t *t, struct gtm *tp)
|
||||
{
|
||||
return __offtime(t, 0, tp);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------*/
|
||||
/* User Provided Date/Time Function for FatFs module */
|
||||
/*---------------------------------------------------------*/
|
||||
/* This is a real time clock service to be called from */
|
||||
/* FatFs module. Any valid time must be returned even if */
|
||||
/* the system does not support a real time clock. */
|
||||
/* This is not required in read-only configuration. */
|
||||
|
||||
gtime_t g_unixTime; // Global date/time register, incremented each second in per10ms()
|
||||
#include "../rtc.h"
|
||||
|
||||
DWORD get_fattime(void)
|
||||
{
|
||||
struct gtm t;
|
||||
filltm(&g_unixTime, &t); // create a struct tm date/time structure from global unix time stamp
|
||||
|
||||
gettime(&t);
|
||||
|
||||
/* Pack date and time into a DWORD variable */
|
||||
return ((DWORD)(t.tm_year - 80) << 25)
|
||||
return ((DWORD)(t.tm_year - 80) << 25)
|
||||
| ((uint32_t)(t.tm_mon+1) << 21)
|
||||
| ((uint32_t)t.tm_mday << 16)
|
||||
| ((uint32_t)t.tm_hour << 11)
|
||||
|
||||
+6
-4
@@ -464,9 +464,9 @@ endif
|
||||
ifeq ($(PCB), ARM)
|
||||
# ARM, so ...
|
||||
OPT = 2
|
||||
CPPDEFS += -DPCBARM -DAUDIO -DHAPTIC -DPXX -DDSM2 -DDSM2_PPM -DROTARY_ENCODERS=1
|
||||
CPPDEFS += -DPCBARM -DAUDIO -DHAPTIC -DRTCLOCK -DPXX -DDSM2 -DDSM2_PPM -DROTARY_ENCODERS=1
|
||||
EXTRAINCDIRS += ersky9x CoOS/kernel CoOS/portable
|
||||
BOARDSRC = board_ersky9x.cpp
|
||||
BOARDSRC = board_ersky9x.cpp
|
||||
SRC += ersky9x/core_cm3.c ersky9x/board_lowlevel.c ersky9x/crt.c ersky9x/vectors_sam3s.c
|
||||
SRC += CoOS/kernel/core.c CoOS/kernel/hook.c CoOS/kernel/task.c CoOS/kernel/event.c CoOS/kernel/time.c CoOS/kernel/timer.c CoOS/kernel/flag.c CoOS/kernel/mutex.c CoOS/kernel/serviceReq.c CoOS/portable/GCC/port.c CoOS/portable/arch.c
|
||||
SRC += ersky9x/usb/device/core/USBD_UDP.c ersky9x/usb/device/core/USBDDriver.c ersky9x/usb/device/core/USBDCallbacks.c
|
||||
@@ -476,6 +476,7 @@ ifeq ($(PCB), ARM)
|
||||
SRC += ersky9x/MEDSdcard.c
|
||||
EEPROMSRC = eeprom_arm.cpp
|
||||
PULSESSRC = pulses_arm.cpp
|
||||
CPPSRC += rtc.cpp ersky9x/rtc_driver.cpp
|
||||
CPPSRC += ersky9x/audio.cpp haptic.cpp
|
||||
CPPSRC += ersky9x/sound_driver.cpp ersky9x/haptic_driver.cpp ersky9x/sdcard_driver.cpp ersky9x/massstorage.cpp
|
||||
|
||||
@@ -506,8 +507,9 @@ ifeq ($(PCB), V4)
|
||||
CPPSRC += stock/audio.cpp haptic.cpp
|
||||
|
||||
ifeq ($(SDCARD), YES)
|
||||
CPPSRC += FatFs/fattime.c gruvin9x/rtc.cpp gruvin9x/diskio.cpp
|
||||
EXTRABOARDSRC += FatFs/ff.c FatFs/option/ccsbcs.c
|
||||
CPPDEFS += -DRTCLOCK
|
||||
CPPSRC += rtc.cpp gruvin9x/rtc_driver.cpp gruvin9x/diskio.cpp
|
||||
EXTRABOARDSRC += FatFs/ff.c FatFs/fattime.c FatFs/option/ccsbcs.c
|
||||
endif
|
||||
|
||||
ifeq ($(VOICE), YES)
|
||||
|
||||
@@ -792,6 +792,8 @@ void board_init()
|
||||
|
||||
alawInit();
|
||||
|
||||
rtc_init();
|
||||
|
||||
eeprom_init();
|
||||
|
||||
init_rotary_encoder();
|
||||
|
||||
+2
-16
@@ -33,10 +33,6 @@
|
||||
|
||||
#include "open9x.h"
|
||||
|
||||
#ifdef SDCARD
|
||||
uint8_t g_ms100 = 0; // global to allow time set function to reset to zero
|
||||
#endif
|
||||
|
||||
#ifndef SIMU
|
||||
inline void board_init()
|
||||
{
|
||||
@@ -76,19 +72,9 @@ inline void board_init()
|
||||
TCCR0B = (1<<WGM02) | (0b011 << CS00);
|
||||
TCCR0A = (0b01<<WGM00);
|
||||
|
||||
#if defined(SDCARD)
|
||||
#if defined(RTCLOCK)
|
||||
// Initialise global unix timestamp with current time from RTC chip on SD card interface
|
||||
RTC rtc = {0,0,0,0,0,0,0};
|
||||
struct gtm utm;
|
||||
rtc_gettime(&rtc);
|
||||
utm.tm_year = rtc.year - 1900;
|
||||
utm.tm_mon = rtc.month - 1;
|
||||
utm.tm_mday = rtc.mday;
|
||||
utm.tm_hour = rtc.hour;
|
||||
utm.tm_min = rtc.min;
|
||||
utm.tm_sec = rtc.sec;
|
||||
utm.tm_wday = rtc.wday - 1;
|
||||
g_unixTime = gmktime(&utm);
|
||||
rtc_init();
|
||||
#endif
|
||||
|
||||
/***************************************************/
|
||||
|
||||
@@ -31,26 +31,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RTC_H
|
||||
#define RTC_H
|
||||
#ifndef board_gruvin9x_h
|
||||
#define board_gruvin9x_h
|
||||
|
||||
#include "../FatFs/integer.h"
|
||||
|
||||
typedef struct {
|
||||
WORD year; /* 2000..2099 */
|
||||
BYTE month; /* 1..12 */
|
||||
BYTE mday; /* 1.. 31 */
|
||||
BYTE wday; /* 1..7 */
|
||||
BYTE hour; /* 0..23 */
|
||||
BYTE min; /* 0..59 */
|
||||
BYTE sec; /* 0..59 */
|
||||
} RTC;
|
||||
|
||||
int iic_write (BYTE, UINT, UINT, const void*); /* Write to IIC device */
|
||||
int iic_read (BYTE, UINT, UINT, void*); /* Read from IIC device */
|
||||
|
||||
int rtc_init (void); /* Initialize RTC */
|
||||
int rtc_gettime (RTC*); /* Get time */
|
||||
int rtc_settime (const RTC*); /* Set time */
|
||||
|
||||
#endif
|
||||
+2
-2
@@ -161,10 +161,10 @@ void per10ms()
|
||||
Tenms |= 1 ; // 10 mS has passed
|
||||
#endif
|
||||
|
||||
#if defined (PCBV4) && defined(SDCARD)
|
||||
#if defined(RTCLOCK)
|
||||
/* Update gloabal Date/Time every 100 per10ms cycles */
|
||||
if (++g_ms100 == 100) {
|
||||
g_unixTime++; // inc global unix timestamp one second
|
||||
g_rtcTime++; // inc global unix timestamp one second
|
||||
g_ms100 = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1303,6 +1303,8 @@ DSTATUS disk_status (
|
||||
/* Read Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
uint32_t dma_sd_buffer[512/4];
|
||||
|
||||
DRESULT disk_read (
|
||||
BYTE drv, /* Physical drive nmuber (0) */
|
||||
BYTE *buff, /* Pointer to the data buffer to store read data */
|
||||
@@ -1311,16 +1313,15 @@ DRESULT disk_read (
|
||||
)
|
||||
{
|
||||
uint32_t result ;
|
||||
BYTE copy[512];
|
||||
|
||||
if (drv || !count) return RES_PARERR;
|
||||
|
||||
if ( sd_card_ready() == 0 ) return RES_NOTRDY;
|
||||
|
||||
do {
|
||||
result = sd_read_block( sector, (uint32_t *)copy) ;
|
||||
result = sd_read_block(sector, dma_sd_buffer) ;
|
||||
if (result) {
|
||||
memcpy(buff, copy, 512);
|
||||
memcpy(buff, dma_sd_buffer, 512);
|
||||
sector += 1 ;
|
||||
buff += 512 ;
|
||||
count -= 1 ;
|
||||
@@ -1355,7 +1356,6 @@ DRESULT disk_write (
|
||||
)
|
||||
{
|
||||
uint32_t result ;
|
||||
BYTE copy[512];
|
||||
|
||||
if (drv || !count) return RES_PARERR;
|
||||
|
||||
@@ -1367,13 +1367,13 @@ DRESULT disk_write (
|
||||
|
||||
while (1) {
|
||||
|
||||
memcpy(copy, buff, 512);
|
||||
memcpy(dma_sd_buffer, buff, 512);
|
||||
|
||||
result = sd_write_block( sector, ( uint32_t *)copy ) ;
|
||||
result = sd_write_block(sector, dma_sd_buffer) ;
|
||||
|
||||
sd_read_block( sector, ( uint32_t *)copy ) ;
|
||||
sd_read_block(sector, dma_sd_buffer) ;
|
||||
|
||||
if (!memcmp(copy, buff, 512))
|
||||
if (!memcmp(dma_sd_buffer, buff, 512))
|
||||
break;
|
||||
else {
|
||||
TRACE_ERROR("Block %d ko SR=%.2X\r\n", sector, HSMCI->HSMCI_SR);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny <shadow@privy.de>
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* open9x is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../open9x.h"
|
||||
|
||||
struct t_i2cTime
|
||||
{
|
||||
uint8_t setCode ;
|
||||
uint8_t Time[7] ;
|
||||
} I2CTime ;
|
||||
|
||||
void rtc_settime(struct gtm * t)
|
||||
{
|
||||
g_rtcTime = gmktime(t); // update local timestamp and get wday calculated
|
||||
g_ms100 = 0; // start of next second begins now
|
||||
|
||||
I2CTime.setCode = 0x74 ; // Tiny SET TIME CODE command
|
||||
I2CTime.Time[0] = t->tm_sec ;
|
||||
I2CTime.Time[1] = t->tm_min ;
|
||||
I2CTime.Time[2] = t->tm_hour ;
|
||||
I2CTime.Time[3] = t->tm_mday ;
|
||||
I2CTime.Time[4] = t->tm_mon+1 ;
|
||||
I2CTime.Time[5] = (uint8_t) (t->tm_year+1900) ;
|
||||
I2CTime.Time[6] = (t->tm_year+1900) >> 8 ;
|
||||
write_coprocessor( (uint8_t *) &I2CTime, 8 ) ;
|
||||
}
|
||||
|
||||
void rtc_init()
|
||||
{
|
||||
read_coprocessor();
|
||||
}
|
||||
@@ -227,7 +227,7 @@ void init_twi()
|
||||
NVIC_EnableIRQ(TWI0_IRQn) ;
|
||||
setVolume(2) ;
|
||||
}
|
||||
extern t_time Time;
|
||||
|
||||
static int8_t Volume_required ;
|
||||
static uint8_t Volume_read_pending ;
|
||||
static uint8_t CoProc_read_pending ;
|
||||
@@ -413,25 +413,24 @@ extern "C" void TWI0_IRQHandler()
|
||||
{
|
||||
Coproc_valid = 1 ;
|
||||
Coproc_read = Co_proc_status[0] ;
|
||||
if ( Coproc_read & 0x80 ) // Bootloader
|
||||
{
|
||||
if ( Coproc_read & 0x80 ) {
|
||||
// Bootloader
|
||||
CoProc_appgo_pending = 1 ; // Action application
|
||||
}
|
||||
else
|
||||
{ // Got data from tiny app
|
||||
else {
|
||||
// Got data from tiny app
|
||||
// Set the date and time
|
||||
t_time *p = &Time ;
|
||||
|
||||
p->second = Co_proc_status[1] ;
|
||||
p->minute = Co_proc_status[2] ;
|
||||
p->hour = Co_proc_status[3] ;
|
||||
p->date= Co_proc_status[4] ;
|
||||
p->month = Co_proc_status[5] ;
|
||||
p->year = Co_proc_status[6] + ( Co_proc_status[7] << 8 ) ;
|
||||
struct gtm utm;
|
||||
utm.tm_sec = Co_proc_status[1] ;
|
||||
utm.tm_min = Co_proc_status[2] ;
|
||||
utm.tm_hour = Co_proc_status[3] ;
|
||||
utm.tm_mday = Co_proc_status[4] ;
|
||||
utm.tm_mon = Co_proc_status[5] - 1;
|
||||
utm.tm_year = (Co_proc_status[6] + ( Co_proc_status[7] << 8 )) - 1900;
|
||||
g_rtcTime = gmktime(&utm);
|
||||
}
|
||||
TWI0->TWI_PTCR = TWI_PTCR_RXTDIS ; // Stop transfers
|
||||
if ( TWI0->TWI_SR & TWI_SR_RXRDY )
|
||||
{
|
||||
if ( TWI0->TWI_SR & TWI_SR_RXRDY ) {
|
||||
(void) TWI0->TWI_RHR ; // Discard any rubbish data
|
||||
}
|
||||
}
|
||||
|
||||
+111
-145
@@ -37,19 +37,8 @@ const pm_uchar sticks[] PROGMEM = {
|
||||
#include "sticks.lbm"
|
||||
};
|
||||
|
||||
#if defined(PCBARM)
|
||||
struct t_i2cTime
|
||||
{
|
||||
uint8_t setCode ;
|
||||
uint8_t Time[7] ;
|
||||
} I2CTime ;
|
||||
#endif
|
||||
|
||||
enum EnumTabDiag {
|
||||
e_Setup,
|
||||
#if (defined(PCBV4) && defined(SDCARD)) || defined(PCBARM)
|
||||
e_FrskyTime,
|
||||
#endif
|
||||
#if defined(SDCARD)
|
||||
e_Sd,
|
||||
#endif
|
||||
@@ -57,13 +46,13 @@ enum EnumTabDiag {
|
||||
e_Vers,
|
||||
e_Keys,
|
||||
e_Ana,
|
||||
#if defined(PCBARM)
|
||||
e_Hardware,
|
||||
#endif
|
||||
e_Calib
|
||||
};
|
||||
|
||||
void menuProcSetup(uint8_t event);
|
||||
#if (defined(PCBV4) && defined(SDCARD)) || defined (PCBARM)
|
||||
void menuProcTime(uint8_t event);
|
||||
#endif
|
||||
#if defined(SDCARD)
|
||||
void menuProcSd(uint8_t event);
|
||||
#endif
|
||||
@@ -71,13 +60,11 @@ void menuProcTrainer(uint8_t event);
|
||||
void menuProcDiagVers(uint8_t event);
|
||||
void menuProcDiagKeys(uint8_t event);
|
||||
void menuProcDiagAna(uint8_t event);
|
||||
void menuProcHardware(uint8_t event);
|
||||
void menuProcDiagCalib(uint8_t event);
|
||||
|
||||
const MenuFuncP_PROGMEM menuTabDiag[] PROGMEM = {
|
||||
menuProcSetup,
|
||||
#if (defined(PCBV4) && defined(SDCARD)) || defined (PCBARM)
|
||||
menuProcTime,
|
||||
#endif
|
||||
#if defined(SDCARD)
|
||||
menuProcSd,
|
||||
#endif
|
||||
@@ -85,6 +72,9 @@ const MenuFuncP_PROGMEM menuTabDiag[] PROGMEM = {
|
||||
menuProcDiagVers,
|
||||
menuProcDiagKeys,
|
||||
menuProcDiagAna,
|
||||
#if defined(PCBARM)
|
||||
menuProcHardware,
|
||||
#endif
|
||||
menuProcDiagCalib
|
||||
};
|
||||
|
||||
@@ -108,6 +98,9 @@ void displaySlider(uint8_t x, uint8_t y, uint8_t value, uint8_t attr)
|
||||
#endif
|
||||
|
||||
enum menuProcSetupItems {
|
||||
#if defined(RTCLOCK)
|
||||
ITEM_SETUP_RTC,
|
||||
#endif
|
||||
ITEM_SETUP_BEEPER_MODE,
|
||||
ITEM_SETUP_BEEPER_LENGTH,
|
||||
#if defined(AUDIO)
|
||||
@@ -122,7 +115,6 @@ enum menuProcSetupItems {
|
||||
ITEM_SETUP_HAPTIC_STRENGTH,
|
||||
#endif
|
||||
#if defined(PCBARM)
|
||||
ITEM_SETUP_OPTREX_DISPLAY,
|
||||
ITEM_SETUP_BRIGHTNESS,
|
||||
#endif
|
||||
ITEM_SETUP_CONTRAST,
|
||||
@@ -155,12 +147,18 @@ enum menuProcSetupItems {
|
||||
ITEM_SETUP_GPSFORMAT,
|
||||
#endif
|
||||
ITEM_SETUP_RX_CHANNEL_ORD,
|
||||
ITEM_SETUP_STICK_MODE_LABELS,
|
||||
ITEM_SETUP_STICK_MODE,
|
||||
ITEM_SETUP_MAX
|
||||
};
|
||||
|
||||
void menuProcSetup(uint8_t event)
|
||||
{
|
||||
#ifdef RTCLOCK
|
||||
#define RTC_ZEROS 5,
|
||||
#else
|
||||
#define RTC_ZEROS
|
||||
#endif
|
||||
#ifdef AUDIO
|
||||
#define AUDIO_ZEROS 0,
|
||||
#else
|
||||
@@ -187,7 +185,7 @@ void menuProcSetup(uint8_t event)
|
||||
#define FRSKY_ZEROS
|
||||
#endif
|
||||
#ifdef PCBARM
|
||||
#define ARM_ZEROS 0, 0, 0, 0,
|
||||
#define ARM_ZEROS 0, 0, 0,
|
||||
#else
|
||||
#define ARM_ZEROS
|
||||
#endif
|
||||
@@ -202,10 +200,14 @@ void menuProcSetup(uint8_t event)
|
||||
#define ROTARY_ENCODERS_ZEROS
|
||||
#endif
|
||||
|
||||
MENU(STR_MENURADIOSETUP, menuTabDiag, e_Setup, ITEM_SETUP_MAX+2, {0, 0, AUDIO_ZEROS VOICE_ZEROS HAPTIC_ZEROS ARM_ZEROS BLUETOOTH_ZEROS ROTARY_ENCODERS_ZEROS 0, 0, 0, 0, 0, 0, 0, 0, 0, SPLASH_ZEROS 0, 0, 0, 0, FRSKY_ZEROS 0, (uint8_t)-1, 1});
|
||||
MENU(STR_MENURADIOSETUP, menuTabDiag, e_Setup, ITEM_SETUP_MAX+1, {0, RTC_ZEROS 0, 0, AUDIO_ZEROS VOICE_ZEROS HAPTIC_ZEROS ARM_ZEROS BLUETOOTH_ZEROS ROTARY_ENCODERS_ZEROS 0, 0, 0, 0, 0, 0, 0, 0, 0, SPLASH_ZEROS 0, 0, 0, 0, FRSKY_ZEROS 0, (uint8_t)-1, 1});
|
||||
|
||||
uint8_t sub = m_posVert - 1;
|
||||
|
||||
#if defined(RTCLOCK)
|
||||
static struct gtm t;
|
||||
#endif
|
||||
|
||||
for (uint8_t i=0; i<7; i++) {
|
||||
uint8_t y = 1*FH + i*FH;
|
||||
uint8_t k = i+s_pgOfs;
|
||||
@@ -213,6 +215,57 @@ void menuProcSetup(uint8_t event)
|
||||
uint8_t attr = (sub == k ? blink : 0);
|
||||
|
||||
switch(k) {
|
||||
#if defined(RTCLOCK)
|
||||
case ITEM_SETUP_RTC:
|
||||
lcd_putsLeft(y, PSTR("Time"));
|
||||
lcd_putc(FW*7+6, y, '-'); lcd_putc(FW*10+4, y, '-');
|
||||
lcd_putc(FW*15+5, y, ':'); lcd_putc(FW*18+3, y, ':');
|
||||
for (uint8_t j=0; j<6; j++) { // 3 settings each for date and time (YMD and HMS)
|
||||
uint8_t rowattr = (m_posHorz==j) ? attr : 0;
|
||||
switch (j) {
|
||||
case 0:
|
||||
lcd_outdezAtt(FW*7+6, y, t.tm_year+1900, rowattr);
|
||||
if (rowattr && (s_editMode>0 || p1valdiff)) t.tm_year = checkIncDec(event, t.tm_year, 112, 200, 0);
|
||||
break;
|
||||
case 1:
|
||||
lcd_outdezNAtt(FW*10+4, y, t.tm_mon+1, rowattr|LEADING0, 2);
|
||||
if (rowattr && (s_editMode>0 || p1valdiff)) t.tm_mon = checkIncDec(event, t.tm_mon, 0, 11, 0);
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
int16_t year = 1900 + t.tm_year;
|
||||
int8_t dlim = (((((year%4==0) && (year %100!=0)) || (year%400==0)) && (t.tm_mon==1)) ? 1 : 0);
|
||||
int8_t dmon[] = {31,28,31,30,31,30,31,31,30,31,30,31}; // TODO in flash
|
||||
dlim += dmon[t.tm_mon];
|
||||
lcd_outdezNAtt(FW*13+2, y, t.tm_mday, rowattr|LEADING0, 2);
|
||||
if (rowattr && (s_editMode>0 || p1valdiff)) t.tm_mday = checkIncDec(event, t.tm_mday, 1, dlim, 0);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
lcd_outdezNAtt(FW*15+5, y, t.tm_hour, rowattr|LEADING0, 2);
|
||||
if (rowattr && (s_editMode>0 || p1valdiff)) t.tm_hour = checkIncDec( event, t.tm_hour, 0, 23, 0);
|
||||
break;
|
||||
case 4:
|
||||
lcd_outdezNAtt(FW*18+3, y, t.tm_min, rowattr|LEADING0, 2);
|
||||
if (rowattr && (s_editMode>0 || p1valdiff)) t.tm_min = checkIncDec( event, t.tm_min, 0, 59, 0);
|
||||
break;
|
||||
case 5:
|
||||
lcd_outdezNAtt(FW*21+2, y, t.tm_sec, rowattr|LEADING0, 2);
|
||||
if (rowattr && (s_editMode>0 || p1valdiff)) t.tm_sec = checkIncDec( event, t.tm_sec, 0, 59, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (attr && s_editMode<=0 && event == EVT_KEY_FIRST(KEY_MENU)) {
|
||||
// set the date and time into RTC chip
|
||||
rtc_settime(&t);
|
||||
}
|
||||
else if (sub!=ITEM_SETUP_RTC || s_editMode<=0) {
|
||||
gettime(&t);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case ITEM_SETUP_BEEPER_MODE:
|
||||
g_eeGeneral.beeperMode = selectMenuItem(GENERAL_PARAM_OFS, y, STR_BEEPERMODE, STR_VBEEPMODE, g_eeGeneral.beeperMode, -2, 1, attr, event);
|
||||
#if defined(FRSKY)
|
||||
@@ -278,10 +331,6 @@ void menuProcSetup(uint8_t event)
|
||||
#endif
|
||||
|
||||
#if defined(PCBARM)
|
||||
case ITEM_SETUP_OPTREX_DISPLAY:
|
||||
g_eeGeneral.optrexDisplay = onoffMenuItem( g_eeGeneral.optrexDisplay, GENERAL_PARAM_OFS, y, STR_OPTREX_DISPLAY, attr, event );
|
||||
break;
|
||||
|
||||
case ITEM_SETUP_BRIGHTNESS:
|
||||
lcd_putsLeft(y, STR_BRIGHTNESS);
|
||||
lcd_outdezAtt(GENERAL_PARAM_OFS, y, 100-g_eeGeneral.backlightBright, attr|LEFT) ;
|
||||
@@ -421,17 +470,18 @@ void menuProcSetup(uint8_t event)
|
||||
lcd_putsLeft( y,STR_RXCHANNELORD);// RAET->AETR
|
||||
for (uint8_t i=1; i<=4; i++)
|
||||
putsChnLetter(GENERAL_PARAM_OFS - FW + i*FW, y, channel_order(i), attr);
|
||||
if(attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.templateSetup, 0, 23);
|
||||
if (attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.templateSetup, 0, 23);
|
||||
break;
|
||||
|
||||
case ITEM_SETUP_STICK_MODE_LABELS:
|
||||
lcd_putsLeft(y, STR_MODE);
|
||||
for (uint8_t i=0; i<4; i++) lcd_img((6+4*i)*FW, y, sticks, i, 0);
|
||||
break;
|
||||
|
||||
case ITEM_SETUP_STICK_MODE:
|
||||
lcd_puts( 1*FW, y, STR_MODE);
|
||||
for(uint8_t i=0; i<4; i++) lcd_img((6+4*i)*FW, y, sticks,i,0);
|
||||
if((y+=FH)>7*FH) return;
|
||||
lcd_putcAtt( 3*FW, y, '1'+g_eeGeneral.stickMode,(sub==k+1) ? (s_editMode>0 ? BLINK|INVERS : INVERS) : 0);
|
||||
for(uint8_t i=0; i<4; i++) putsChnRaw( (6+4*i)*FW, y, pgm_read_byte(modn12x3 + 4*g_eeGeneral.stickMode + i), 0);
|
||||
|
||||
if (sub==k+1 && s_editMode>0) {
|
||||
lcd_putcAtt(2*FW, y, '1'+g_eeGeneral.stickMode, attr);
|
||||
for (uint8_t i=0; i<4; i++) putsChnRaw( (6+4*i)*FW, y, pgm_read_byte(modn12x3 + 4*g_eeGeneral.stickMode + i), 0);
|
||||
if (attr && s_editMode>0) {
|
||||
CHECK_INCDEC_GENVAR(event, g_eeGeneral.stickMode, 0, 3);
|
||||
}
|
||||
else if (stickMode != g_eeGeneral.stickMode) {
|
||||
@@ -446,119 +496,6 @@ void menuProcSetup(uint8_t event)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if (defined(PCBV4) && defined(SDCARD)) || defined(PCBARM)
|
||||
// SD card interface contains Real-Time-Clock chip
|
||||
void menuProcTime(uint8_t event)
|
||||
{
|
||||
MENU(STR_MENUDATEANDTIME, menuTabDiag, e_FrskyTime, 3, {0, 2/*, 2*/});
|
||||
|
||||
int8_t sub = m_posVert - 1; // vertical position (1 = page counter, top/right)
|
||||
uint8_t subSub = m_posHorz; // horizontal position
|
||||
static struct gtm t;
|
||||
struct gtm *at = &t;
|
||||
|
||||
switch(event)
|
||||
{
|
||||
case EVT_KEY_LONG(KEY_MENU):
|
||||
// get data time from RTC chip (may not implement)
|
||||
killEvents(event);
|
||||
break;
|
||||
case EVT_KEY_FIRST(KEY_MENU):
|
||||
if (sub >= 0 && s_editMode<=0) // set the date and time into RTC chip
|
||||
{
|
||||
#if (defined(PCBV4) && defined(SDCARD))
|
||||
g_unixTime = gmktime(&t); // update local timestamp and get wday calculated
|
||||
g_ms100 = 0; // start of next second begins now
|
||||
RTC rtc;
|
||||
rtc.year = t.tm_year + 1900;
|
||||
rtc.month = t.tm_mon + 1;
|
||||
rtc.mday = t.tm_mday;
|
||||
rtc.hour = t.tm_hour;
|
||||
rtc.min = t.tm_min;
|
||||
rtc.sec = t.tm_sec;
|
||||
rtc.wday = t.tm_wday + 1;
|
||||
rtc_settime(&rtc);
|
||||
#else
|
||||
I2CTime.setCode = 0x74 ; // Tiny SET TIME CODE command
|
||||
I2CTime.Time[0] = t.tm_sec ;
|
||||
I2CTime.Time[1] = t.tm_min ;
|
||||
I2CTime.Time[2] = t.tm_hour ;
|
||||
I2CTime.Time[3] = t.tm_mday ;
|
||||
I2CTime.Time[4] = t.tm_mon+1 ;
|
||||
I2CTime.Time[5] = (uint8_t) (t.tm_year+1900) ;
|
||||
I2CTime.Time[6] = (t.tm_year+1900) >> 8 ;
|
||||
write_coprocessor( (uint8_t *) &I2CTime, 8 ) ;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#if (defined(PCBV4) && defined(SDCARD))
|
||||
if (s_editMode<=0) filltm(&g_unixTime, &t);
|
||||
#endif
|
||||
|
||||
lcd_putc(FW*10+2, FH*2, '-'); lcd_putc(FW*13, FH*2, '-');
|
||||
lcd_putc(FW*10+1, FH*4, ':'); lcd_putc(FW*13-1, FH*4, ':');
|
||||
|
||||
for(uint8_t i=0; i<2; i++) // 2 rows, date then time
|
||||
{
|
||||
uint8_t y=(i*2+2)*FH;
|
||||
|
||||
lcd_putsiAtt(0, y, STR_DATETIME, i, 0);
|
||||
|
||||
for(uint8_t j=0; j<3;j++) // 3 settings each for date and time (YMD and HMS)
|
||||
{
|
||||
uint8_t attr = (sub==i && subSub==j) ? (s_editMode>0 ? BLINK|INVERS : INVERS) : 0;
|
||||
switch(i)
|
||||
{
|
||||
case 0: // DATE
|
||||
switch(j)
|
||||
{
|
||||
case 0:
|
||||
lcd_outdezAtt(FW*10+2, y, at->tm_year+1900, attr);
|
||||
if(attr && (s_editMode>0 || p1valdiff)) at->tm_year = checkIncDec( event, at->tm_year, 112, 200, 0);
|
||||
break;
|
||||
case 1:
|
||||
lcd_outdezNAtt(FW*13, y, at->tm_mon+1, attr|LEADING0, 2);
|
||||
if(attr && (s_editMode>0 || p1valdiff)) at->tm_mon = checkIncDec( event, at->tm_mon, 0, 11, 0);
|
||||
break;
|
||||
case 2:
|
||||
int16_t year=1900 + at->tm_year;
|
||||
int8_t dlim = (((((year%4==0) && (year %100!=0)) || (year%400==0)) && (at->tm_mon==1)) ? 1 : 0);
|
||||
int8_t dmon[]={31,28,31,30,31,30,31,31,30,31,30,31};
|
||||
dlim+=dmon[at->tm_mon];
|
||||
lcd_outdezNAtt(FW*16-2, y, at->tm_mday, attr|LEADING0, 2);
|
||||
if(attr && (s_editMode>0 || p1valdiff)) at->tm_mday = checkIncDec( event, at->tm_mday, 1, dlim, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
switch (j)
|
||||
{
|
||||
case 0:
|
||||
lcd_outdezNAtt(FW*10+1, y, at->tm_hour, attr|LEADING0, 2);
|
||||
if(attr && (s_editMode>0 || p1valdiff)) at->tm_hour = checkIncDec( event, at->tm_hour, 0, 23, 0);
|
||||
break;
|
||||
case 1:
|
||||
lcd_outdezNAtt(FW*13-1, y, at->tm_min, attr|LEADING0, 2);
|
||||
if(attr && (s_editMode>0 || p1valdiff)) at->tm_min = checkIncDec( event, at->tm_min, 0, 59, 0);
|
||||
break;
|
||||
case 2:
|
||||
lcd_outdezNAtt(FW*16-2, y, at->tm_sec, attr|LEADING0, 2);
|
||||
|
||||
if(attr && (s_editMode>0 || p1valdiff)) at->tm_sec = checkIncDec( event, at->tm_sec, 0, 59, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PCBARM)
|
||||
extern uint32_t sdAvailableAudioFiles; // TODO move that!
|
||||
#endif
|
||||
@@ -1005,6 +942,35 @@ void menuProcDiagAna(uint8_t event)
|
||||
|
||||
}
|
||||
|
||||
#if defined(PCBARM)
|
||||
enum menuProcHwItems {
|
||||
ITEM_SETUP_HW_OPTREX_DISPLAY,
|
||||
ITEM_SETUP_HW_MAX
|
||||
};
|
||||
|
||||
#define GENERAL_HW_PARAM_OFS (2+(15*FW))
|
||||
void menuProcHardware(uint8_t event)
|
||||
{
|
||||
MENU(PSTR("Hardware"), menuTabDiag, e_Hardware, ITEM_SETUP_HW_MAX+1, {0, 0});
|
||||
|
||||
uint8_t sub = m_posVert - 1;
|
||||
|
||||
for (uint8_t i=0; i<7; i++) {
|
||||
uint8_t y = 1*FH + i*FH;
|
||||
uint8_t k = i+s_pgOfs;
|
||||
uint8_t blink = ((s_editMode>0) ? BLINK|INVERS : INVERS);
|
||||
uint8_t attr = (sub == k ? blink : 0);
|
||||
|
||||
switch(k) {
|
||||
case ITEM_SETUP_HW_OPTREX_DISPLAY:
|
||||
// TODO remove STR_OPTREX_DISPLAY + translations here
|
||||
g_eeGeneral.optrexDisplay = selectMenuItem(GENERAL_HW_PARAM_OFS, y, PSTR("LCD"), PSTR("\006NormalOptrex"), g_eeGeneral.optrexDisplay, 0, 1, attr, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void menuProcDiagCalib(uint8_t event)
|
||||
{
|
||||
SIMPLE_MENU(STR_MENUCALIBRATION, menuTabDiag, e_Calib, 1);
|
||||
|
||||
@@ -36,7 +36,17 @@
|
||||
/* RTC controls */
|
||||
|
||||
#include "../open9x.h"
|
||||
#include "rtc.h"
|
||||
#include "../FatFs/integer.h"
|
||||
|
||||
typedef struct {
|
||||
WORD year; /* 2000..2099 */
|
||||
BYTE month; /* 1..12 */
|
||||
BYTE mday; /* 1.. 31 */
|
||||
BYTE wday; /* 1..7 */
|
||||
BYTE hour; /* 0..23 */
|
||||
BYTE min; /* 0..59 */
|
||||
BYTE sec; /* 0..59 */
|
||||
} RTC;
|
||||
|
||||
#define SCL_LOW() DDRD |= 0x01 /* SCL = LOW */
|
||||
#define SCL_HIGH() DDRD &= ~0x01 /* SCL = High-Z */
|
||||
@@ -224,11 +234,10 @@ int iic_write (
|
||||
/* RTC functions */
|
||||
|
||||
|
||||
int rtc_gettime (RTC *rtc)
|
||||
int g9x_rtc_gettime (RTC *rtc)
|
||||
{
|
||||
BYTE buf[8];
|
||||
|
||||
|
||||
if (!iic_read(0xD0, 0, 7, buf)) return 0;
|
||||
|
||||
rtc->sec = (buf[0] & 0x0F) + ((buf[0] >> 4) & 7) * 10;
|
||||
@@ -242,15 +251,10 @@ int rtc_gettime (RTC *rtc)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int rtc_settime (const RTC *rtc)
|
||||
int g9x_rtc_settime (const RTC *rtc)
|
||||
{
|
||||
|
||||
BYTE buf[8];
|
||||
|
||||
|
||||
buf[0] = rtc->sec / 10 * 16 + rtc->sec % 10;
|
||||
buf[1] = rtc->min / 10 * 16 + rtc->min % 10;
|
||||
buf[2] = rtc->hour / 10 * 16 + rtc->hour % 10;
|
||||
@@ -264,14 +268,45 @@ int rtc_settime (const RTC *rtc)
|
||||
|
||||
|
||||
|
||||
int rtc_init (void)
|
||||
void rtc_gettime(struct gtm * utm)
|
||||
{
|
||||
RTC rtc = {0,0,0,0,0,0,0};
|
||||
|
||||
g9x_rtc_gettime(&rtc);
|
||||
|
||||
utm->tm_year = rtc.year - 1900;
|
||||
utm->tm_mon = rtc.month - 1;
|
||||
utm->tm_mday = rtc.mday;
|
||||
utm->tm_hour = rtc.hour;
|
||||
utm->tm_min = rtc.min;
|
||||
utm->tm_sec = rtc.sec;
|
||||
utm->tm_wday = rtc.wday - 1;
|
||||
}
|
||||
|
||||
void rtc_settime(struct gtm * t)
|
||||
{
|
||||
g_rtcTime = gmktime(t); // update local timestamp and get wday calculated
|
||||
g_ms100 = 0; // start of next second begins now
|
||||
|
||||
RTC rtc;
|
||||
rtc.year = t->tm_year + 1900;
|
||||
rtc.month = t->tm_mon + 1;
|
||||
rtc.mday = t->tm_mday;
|
||||
rtc.hour = t->tm_hour;
|
||||
rtc.min = t->tm_min;
|
||||
rtc.sec = t->tm_sec;
|
||||
rtc.wday = t->tm_wday + 1;
|
||||
g9x_rtc_settime(&rtc);
|
||||
}
|
||||
|
||||
void rtc_init (void)
|
||||
{
|
||||
BYTE buf[8]; /* RTC R/W buffer */
|
||||
UINT adr;
|
||||
|
||||
|
||||
/* Read RTC registers */
|
||||
if (!iic_read(0xD0, 0, 8, buf)) return 0; /* IIC error */
|
||||
if (!iic_read(0xD0, 0, 8, buf)) return; /* IIC error */
|
||||
|
||||
if (buf[7] & 0x20) { /* When data has been volatiled, set default time */
|
||||
/* Clear nv-ram. Reg[8..63] */
|
||||
@@ -282,6 +317,9 @@ int rtc_init (void)
|
||||
buf[4] = 1; buf[5] = 1; buf[6] = 8;
|
||||
iic_write(0x0D, 0, 8, buf);
|
||||
}
|
||||
return 1;
|
||||
|
||||
struct gtm utm;
|
||||
rtc_gettime(&utm);
|
||||
g_rtcTime = gmktime(&utm);
|
||||
}
|
||||
|
||||
+13
-27
@@ -92,7 +92,7 @@ const pm_char * openLogs()
|
||||
}
|
||||
|
||||
if (f_size(&g_oLogFile) == 0) {
|
||||
#if defined(PCBV4)
|
||||
#if defined(RTCLOCK)
|
||||
f_puts("Date,Time,", &g_oLogFile);
|
||||
#endif
|
||||
|
||||
@@ -151,21 +151,18 @@ void writeLogs()
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(PCBV4)
|
||||
static struct gtm t;
|
||||
struct gtm *at = &t;
|
||||
filltm(&g_unixTime, &t);
|
||||
|
||||
f_printf(&g_oLogFile, "%4d-%02d-%02d,", at->tm_year+1900, at->tm_mon+1, at->tm_mday);
|
||||
f_printf(&g_oLogFile, "%02d:%02d:%02d,", at->tm_hour, at->tm_min, at->tm_sec);
|
||||
#if defined(RTCLOCK)
|
||||
struct gtm utm;
|
||||
gettime(&utm);
|
||||
f_printf(&g_oLogFile, "%4d-%02d-%02d,%02d:%02d:%02d,", utm.tm_year+1900, utm.tm_mon+1, utm.tm_mday, utm.tm_hour, utm.tm_min, utm.tm_sec);
|
||||
#endif
|
||||
|
||||
#if defined(FRSKY)
|
||||
f_printf(&g_oLogFile, "%d,", frskyStreaming);
|
||||
f_printf(&g_oLogFile, "%d,", frskyData.rssi[0].value);
|
||||
f_printf(&g_oLogFile, "%d,", frskyData.rssi[1].value);
|
||||
f_printf(&g_oLogFile, "%d,", frskyData.analog[0].value);
|
||||
f_printf(&g_oLogFile, "%d,", frskyData.analog[1].value);
|
||||
f_printf(&g_oLogFile, "%d,%d,%d,", frskyStreaming, frskyData.rssi[0].value, frskyData.rssi[1].value);
|
||||
for (uint8_t i=0; i<2; i++) {
|
||||
int16_t converted_value = applyChannelRatio(i, frskyData.analog[i].value);
|
||||
f_printf(&g_oLogFile, "%d.%02d,", converted_value/100, converted_value%100);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FRSKY_HUB)
|
||||
@@ -180,14 +177,11 @@ void writeLogs()
|
||||
f_printf(&g_oLogFile, "%d.%d,", frskyData.hub.gpsSpeed_bp, frskyData.hub.gpsSpeed_ap);
|
||||
f_printf(&g_oLogFile, "%03d.%d,", frskyData.hub.gpsAltitude_bp, frskyData.hub.gpsAltitude_ap);
|
||||
f_printf(&g_oLogFile, "%d.%d,", frskyData.hub.baroAltitude_bp, frskyData.hub.baroAltitude_ap);
|
||||
f_printf(&g_oLogFile, "%d,", frskyData.hub.temperature1);
|
||||
f_printf(&g_oLogFile, "%d,", frskyData.hub.temperature2);
|
||||
f_printf(&g_oLogFile, "%d,%d,", frskyData.hub.temperature1, frskyData.hub.temperature2);
|
||||
f_printf(&g_oLogFile, "%d,", frskyData.hub.rpm);
|
||||
f_printf(&g_oLogFile, "%d,", frskyData.hub.fuelLevel);
|
||||
f_printf(&g_oLogFile, "%d,", frskyData.hub.volts);
|
||||
f_printf(&g_oLogFile, "%d,", frskyData.hub.accelX);
|
||||
f_printf(&g_oLogFile, "%d,", frskyData.hub.accelY);
|
||||
f_printf(&g_oLogFile, "%d,", frskyData.hub.accelZ);
|
||||
f_printf(&g_oLogFile, "%d,%d,%d,", frskyData.hub.accelX, frskyData.hub.accelY, frskyData.hub.accelZ);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -201,15 +195,7 @@ void writeLogs()
|
||||
f_printf(&g_oLogFile, "%d,", calibratedStick[i]);
|
||||
}
|
||||
|
||||
f_printf(&g_oLogFile, "%d,", keyState(SW_ThrCt));
|
||||
f_printf(&g_oLogFile, "%d,", keyState(SW_RuddDR));
|
||||
f_printf(&g_oLogFile, "%d,", keyState(SW_ElevDR));
|
||||
f_printf(&g_oLogFile, "%d,", keyState(SW_ID0));
|
||||
f_printf(&g_oLogFile, "%d,", keyState(SW_ID1));
|
||||
f_printf(&g_oLogFile, "%d,", keyState(SW_ID2));
|
||||
f_printf(&g_oLogFile, "%d,", keyState(SW_AileDR));
|
||||
f_printf(&g_oLogFile, "%d,", keyState(SW_Gear));
|
||||
if (f_printf(&g_oLogFile, "%d\n", keyState(SW_Trainer)) < 0 && !error_displayed) {
|
||||
if (f_printf(&g_oLogFile, "%d,%d,%d,%d,%d,%d,%d,%d,%d\n", keyState(SW_ThrCt), keyState(SW_RuddDR), keyState(SW_ElevDR), keyState(SW_ID0), keyState(SW_ID1), keyState(SW_ID2), keyState(SW_AileDR), keyState(SW_Gear), keyState(SW_Trainer)) < 0 && !error_displayed) {
|
||||
error_displayed = STR_SDCARD_ERROR;
|
||||
s_global_warning = STR_SDCARD_ERROR;
|
||||
}
|
||||
|
||||
+1
-1
@@ -238,7 +238,7 @@ extern uint8_t s_menu_offset;
|
||||
extern bool s_menu_more;
|
||||
const char * displayMenu(uint8_t event);
|
||||
|
||||
#define STATUS_LINE_LENGTH 22
|
||||
#define STATUS_LINE_LENGTH 32
|
||||
extern char statusLineMsg[STATUS_LINE_LENGTH];
|
||||
void showStatusLine();
|
||||
void drawStatusLine();
|
||||
|
||||
+1
-3
@@ -35,7 +35,7 @@
|
||||
|
||||
#if defined(PCBARM)
|
||||
#define MIXER_STACK_SIZE 500
|
||||
#define MENUS_STACK_SIZE 2000
|
||||
#define MENUS_STACK_SIZE 2500
|
||||
#define AUDIO_STACK_SIZE 500
|
||||
#define BT_STACK_SIZE 500
|
||||
#define DEBUG_STACK_SIZE 500
|
||||
@@ -87,8 +87,6 @@ ModelData g_model;
|
||||
#if !defined(PCBARM)
|
||||
uint8_t g_tmr1Latency_max;
|
||||
uint8_t g_tmr1Latency_min;
|
||||
#else
|
||||
t_time Time;
|
||||
#endif
|
||||
|
||||
uint8_t unexpectedShutdown = 0;
|
||||
|
||||
+4
-16
@@ -52,6 +52,8 @@
|
||||
|
||||
#if defined(PCBARM)
|
||||
#include "board_ersky9x.h"
|
||||
#elif defined(PCBV4)
|
||||
#include "board_gruvin9x.h"
|
||||
#endif
|
||||
|
||||
#if defined(SIMU)
|
||||
@@ -904,19 +906,6 @@ extern void deleteExpoMix(uint8_t expo, uint8_t idx);
|
||||
extern void incSubtrim(uint8_t idx, int16_t inc);
|
||||
extern void instantTrim();
|
||||
extern void moveTrimsToOffsets();
|
||||
#if defined(PCBARM)
|
||||
typedef struct
|
||||
{
|
||||
unsigned char second; //enter the current time, date, month, and year
|
||||
unsigned char minute;
|
||||
unsigned char hour;
|
||||
unsigned char date;
|
||||
unsigned char month;
|
||||
unsigned int year;
|
||||
} t_time ;
|
||||
|
||||
extern t_time Time ;
|
||||
#endif
|
||||
|
||||
#if defined(PCBARM)
|
||||
#define ACTIVE_EXPOS_TYPE uint32_t
|
||||
@@ -1084,9 +1073,8 @@ enum AUDIO_SOUNDS {
|
||||
#include "sdcard.h"
|
||||
#endif
|
||||
|
||||
#if defined(PCBV4)
|
||||
#include "gruvin9x/rtc.h"
|
||||
extern uint8_t g_ms100; // global to allow time set function to reset to zero
|
||||
#if defined(RTCLOCK)
|
||||
#include "rtc.h"
|
||||
#endif
|
||||
|
||||
// Re-useable byte array to save having multiple buffers
|
||||
|
||||
+507
@@ -0,0 +1,507 @@
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny <shadow@privy.de>
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* open9x is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include "open9x.h"
|
||||
|
||||
extern void rtcdriver_settime(struct gtm * t);
|
||||
|
||||
#define LEAP_SECONDS_POSSIBLE 0
|
||||
|
||||
/* Shift A right by B bits portably, by dividing A by 2**B and
|
||||
truncating towards minus infinity. A and B should be free of side
|
||||
effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
|
||||
INT_BITS is the number of useful bits in an int. GNU code can
|
||||
assume that INT_BITS is at least 32.
|
||||
|
||||
ISO C99 says that A >> B is implementation-defined if A < 0. Some
|
||||
implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
|
||||
right in the usual way when A < 0, so SHR falls back on division if
|
||||
ordinary A >> B doesn't seem to be the usual signed shift. */
|
||||
#define SHR(a, b) \
|
||||
(-1 >> 1 == -1 \
|
||||
? (a) >> (b) \
|
||||
: (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
|
||||
|
||||
/* The extra casts in the following macros work around compiler bugs,
|
||||
e.g., in Cray C 5.0.3.0. */
|
||||
|
||||
/* True if the arithmetic type T is an integer type. bool counts as
|
||||
an integer. */
|
||||
#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
|
||||
|
||||
/* True if negative values of the signed integer type T use two's
|
||||
complement, ones' complement, or signed magnitude representation,
|
||||
respectively. Much GNU code assumes two's complement, but some
|
||||
people like to be portable to all possible C hosts. */
|
||||
#define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
|
||||
#define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
|
||||
#define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
|
||||
|
||||
/* True if the arithmetic type T is signed. */
|
||||
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
|
||||
|
||||
/* The maximum and minimum values for the integer type T. These
|
||||
macros have undefined behavior if T is signed and has padding bits.
|
||||
If this is a problem for you, please let us know how to fix it for
|
||||
your host. */
|
||||
#define TYPE_MINIMUM(t) \
|
||||
((t) (! TYPE_SIGNED (t) \
|
||||
? (t) 0 \
|
||||
: TYPE_SIGNED_MAGNITUDE (t) \
|
||||
? ~ (t) 0 \
|
||||
: ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
|
||||
#define TYPE_MAXIMUM(t) \
|
||||
((t) (! TYPE_SIGNED (t) \
|
||||
? (t) -1 \
|
||||
: ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
|
||||
|
||||
#ifndef TIME_T_MIN
|
||||
# define TIME_T_MIN TYPE_MINIMUM (gtime_t)
|
||||
#endif
|
||||
#ifndef TIME_T_MAX
|
||||
# define TIME_T_MAX TYPE_MAXIMUM (gtime_t)
|
||||
#endif
|
||||
#define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1)
|
||||
|
||||
/* Verify a requirement at compile-time (unlike assert, which is runtime). */
|
||||
#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
|
||||
|
||||
verify (gtime_t_is_integer, TYPE_IS_INTEGER (gtime_t));
|
||||
verify (twos_complement_arithmetic, TYPE_TWOS_COMPLEMENT (int));
|
||||
/* The code also assumes that signed integer overflow silently wraps
|
||||
around, but this assumption can't be stated without causing a
|
||||
diagnostic on some hosts. */
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
#define TM_YEAR_BASE 1900
|
||||
verify (base_year_is_a_multiple_of_100, TM_YEAR_BASE % 100 == 0);
|
||||
|
||||
#define SECS_PER_HOUR 3600ul
|
||||
#define SECS_PER_DAY 86400ul
|
||||
|
||||
/* Return 1 if YEAR + TM_YEAR_BASE is a leap year. */
|
||||
static inline int
|
||||
leapyear (long int year)
|
||||
{
|
||||
/* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
|
||||
Also, work even if YEAR is negative. */
|
||||
return
|
||||
((year & 3) == 0
|
||||
&& (year % 100 != 0
|
||||
|| ((year / 100) & 3) == (- (TM_YEAR_BASE / 100) & 3)));
|
||||
}
|
||||
|
||||
const unsigned short int __mon_yday[2][13] =
|
||||
{
|
||||
/* Normal years. */
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
|
||||
/* Leap years. */
|
||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
|
||||
};
|
||||
|
||||
/* Compute the `struct tm' representation of *T,
|
||||
offset OFFSET seconds east of UTC,
|
||||
and store year, yday, mon, mday, wday, hour, min, sec into *TP.
|
||||
Return nonzero if successful. */
|
||||
int
|
||||
__offtime (
|
||||
gtime_t *t,
|
||||
long int offset,
|
||||
struct gtm *tp)
|
||||
{
|
||||
long int days, rem, y;
|
||||
const unsigned short int *ip;
|
||||
|
||||
days = *t / SECS_PER_DAY;
|
||||
rem = *t % SECS_PER_DAY;
|
||||
rem += offset;
|
||||
while (rem < 0)
|
||||
{
|
||||
rem += SECS_PER_DAY;
|
||||
--days;
|
||||
}
|
||||
while (rem >= (long int)SECS_PER_DAY)
|
||||
{
|
||||
rem -= SECS_PER_DAY;
|
||||
++days;
|
||||
}
|
||||
tp->tm_hour = rem / SECS_PER_HOUR;
|
||||
rem %= SECS_PER_HOUR;
|
||||
tp->tm_min = rem / 60;
|
||||
tp->tm_sec = rem % 60;
|
||||
/* January 1, 1970 was a Thursday. */
|
||||
tp->tm_wday = (4 + days) % 7;
|
||||
if (tp->tm_wday < 0)
|
||||
tp->tm_wday += 7;
|
||||
y = 1970;
|
||||
|
||||
#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
|
||||
#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
|
||||
|
||||
while (days < 0 || days >= (leapyear (y) ? 366 : 365))
|
||||
{
|
||||
/* Guess a corrected year, assuming 365 days per year. */
|
||||
long int yg = y + days / 365 - (days % 365 < 0);
|
||||
|
||||
/* Adjust DAYS and Y to match the guessed year. */
|
||||
days -= ((yg - y) * 365
|
||||
+ LEAPS_THRU_END_OF (yg - 1)
|
||||
- LEAPS_THRU_END_OF (y - 1));
|
||||
y = yg;
|
||||
}
|
||||
tp->tm_year = y - 1900;
|
||||
if (tp->tm_year != y - 1900)
|
||||
{
|
||||
/* The year cannot be represented due to overflow. */
|
||||
// __set_errno (EOVERFLOW);
|
||||
return 0;
|
||||
}
|
||||
tp->tm_yday = days;
|
||||
ip = __mon_yday[leapyear(y)];
|
||||
for (y = 11; days < (long int) ip[y]; --y)
|
||||
continue;
|
||||
days -= ip[y];
|
||||
tp->tm_mon = y;
|
||||
tp->tm_mday = days + 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* time_r function implementations */
|
||||
// G: No time zones in our implementation so just do the converion from gtime_t to struct tm
|
||||
struct gtm *
|
||||
__localtime_r (gtime_t * t, struct gtm * tp)
|
||||
{
|
||||
__offtime(t, 0, tp);
|
||||
return tp;
|
||||
}
|
||||
|
||||
|
||||
/* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
|
||||
(YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
|
||||
were not adjusted between the time stamps.
|
||||
|
||||
The YEAR values uses the same numbering as TP->tm_year. Values
|
||||
need not be in the usual range. However, YEAR1 must not be less
|
||||
than 2 * INT_MIN or greater than 2 * INT_MAX.
|
||||
|
||||
The result may overflow. It is the caller's responsibility to
|
||||
detect overflow. */
|
||||
|
||||
static inline gtime_t
|
||||
ydhms_diff (long int year1, long int yday1, int hour1, int min1, int sec1,
|
||||
int year0, int yday0, int hour0, int min0, int sec0)
|
||||
{
|
||||
verify (C99_integer_division, -1 / 2 == 0);
|
||||
verify (long_int_year_and_yday_are_wide_enough,
|
||||
INT_MAX <= LONG_MAX / 2 || TIME_T_MAX <= UINT_MAX);
|
||||
|
||||
/* Compute intervening leap days correctly even if year is negative.
|
||||
Take care to avoid integer overflow here. */
|
||||
int a4 = SHR (year1, 2) + SHR (TM_YEAR_BASE, 2) - ! (year1 & 3);
|
||||
int b4 = SHR (year0, 2) + SHR (TM_YEAR_BASE, 2) - ! (year0 & 3);
|
||||
int a100 = a4 / 25 - (a4 % 25 < 0);
|
||||
int b100 = b4 / 25 - (b4 % 25 < 0);
|
||||
int a400 = SHR (a100, 2);
|
||||
int b400 = SHR (b100, 2);
|
||||
int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
|
||||
|
||||
/* Compute the desired time in gtime_t precision. Overflow might
|
||||
occur here. */
|
||||
gtime_t tyear1 = year1;
|
||||
gtime_t years = tyear1 - year0;
|
||||
gtime_t days = 365 * years + yday1 - yday0 + intervening_leap_days;
|
||||
gtime_t hours = 24 * days + hour1 - hour0;
|
||||
gtime_t minutes = 60 * hours + min1 - min0;
|
||||
gtime_t seconds = 60 * minutes + sec1 - sec0;
|
||||
return seconds;
|
||||
}
|
||||
|
||||
/* Return a gtime_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
|
||||
assuming that *T corresponds to *TP and that no clock adjustments
|
||||
occurred between *TP and the desired time.
|
||||
If TP is null, return a value not equal to *T; this avoids false matches.
|
||||
If overflow occurs, yield the minimal or maximal value, except do not
|
||||
yield a value equal to *T. */
|
||||
static gtime_t
|
||||
guess_time_tm (long int year, long int yday, int hour, int min, int sec,
|
||||
gtime_t *t, struct gtm *tp)
|
||||
{
|
||||
if (tp)
|
||||
{
|
||||
gtime_t d = ydhms_diff (year, yday, hour, min, sec,
|
||||
tp->tm_year, tp->tm_yday,
|
||||
tp->tm_hour, tp->tm_min, tp->tm_sec);
|
||||
gtime_t t1 = *t + d;
|
||||
if ((t1 < *t) == (TYPE_SIGNED (gtime_t) ? d < 0 : TIME_T_MAX / 2 < d))
|
||||
return t1;
|
||||
}
|
||||
|
||||
/* Overflow occurred one way or another. Return the nearest result
|
||||
that is actually in range, except don't report a zero difference
|
||||
if the actual difference is nonzero, as that would cause a false
|
||||
match; and don't oscillate between two values, as that would
|
||||
confuse the spring-forward gap detector. */
|
||||
return (*t < TIME_T_MIDPOINT
|
||||
? (*t <= TIME_T_MIN + 1 ? *t + 1 : TIME_T_MIN)
|
||||
: (TIME_T_MAX - 1 <= *t ? *t - 1 : TIME_T_MAX));
|
||||
}
|
||||
|
||||
/* Use CONVERT to convert *T to a broken down time in *TP.
|
||||
If *T is out of range for conversion, adjust it so that
|
||||
it is the nearest in-range value and then convert that. */
|
||||
static struct gtm *
|
||||
ranged_convert (struct gtm *(*convert) (gtime_t *, struct gtm *),
|
||||
gtime_t *t, struct gtm *tp)
|
||||
{
|
||||
struct gtm *r = convert (t, tp);
|
||||
|
||||
if (!r && *t)
|
||||
{
|
||||
gtime_t bad = *t;
|
||||
gtime_t ok = 0;
|
||||
|
||||
/* BAD is a known unconvertible gtime_t, and OK is a known good one.
|
||||
Use binary search to narrow the range between BAD and OK until
|
||||
they differ by 1. */
|
||||
while (bad != ok + (bad < 0 ? -1 : 1))
|
||||
{
|
||||
gtime_t mid = *t = (bad < 0
|
||||
? bad + ((ok - bad) >> 1)
|
||||
: ok + ((bad - ok) >> 1));
|
||||
r = convert (t, tp);
|
||||
if (r)
|
||||
ok = mid;
|
||||
else
|
||||
bad = mid;
|
||||
}
|
||||
|
||||
if (!r && ok)
|
||||
{
|
||||
/* The last conversion attempt failed;
|
||||
revert to the most recent successful attempt. */
|
||||
*t = ok;
|
||||
r = convert (t, tp);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Convert *TP to a gtime_t value, inverting
|
||||
the monotonic and mostly-unit-linear conversion function CONVERT.
|
||||
Use *OFFSET to keep track of a guess at the offset of the result,
|
||||
compared to what the result would be for UTC without leap seconds.
|
||||
If *OFFSET's guess is correct, only one CONVERT call is needed.
|
||||
This function is external because it is used also by timegm.c. */
|
||||
gtime_t
|
||||
__mktime_internal (struct gtm *tp,
|
||||
struct gtm *(*convert) (gtime_t *, struct gtm *),
|
||||
gtime_t *offset)
|
||||
{
|
||||
gtime_t t, gt, t0, t1, t2;
|
||||
struct gtm tm;
|
||||
|
||||
/* The maximum number of probes (calls to CONVERT) should be enough
|
||||
to handle any combinations of time zone rule changes, solar time,
|
||||
leap seconds, and oscillations around a spring-forward gap.
|
||||
POSIX.1 prohibits leap seconds, but some hosts have them anyway. */
|
||||
int remaining_probes = 6;
|
||||
|
||||
/* Time requested. Copy it in case CONVERT modifies *TP; this can
|
||||
occur if TP is localtime's returned value and CONVERT is localtime. */
|
||||
int sec = tp->tm_sec;
|
||||
int min = tp->tm_min;
|
||||
int hour = tp->tm_hour;
|
||||
int mday = tp->tm_mday;
|
||||
int mon = tp->tm_mon;
|
||||
int year_requested = tp->tm_year;
|
||||
|
||||
/* Ensure that mon is in range, and set year accordingly. */
|
||||
int mon_remainder = mon % 12;
|
||||
int negative_mon_remainder = mon_remainder < 0;
|
||||
int mon_years = mon / 12 - negative_mon_remainder;
|
||||
long int lyear_requested = year_requested;
|
||||
long int year = lyear_requested + mon_years;
|
||||
|
||||
/* The other values need not be in range:
|
||||
the remaining code handles minor overflows correctly,
|
||||
assuming int and gtime_t arithmetic wraps around.
|
||||
Major overflows are caught at the end. */
|
||||
|
||||
/* Calculate day of year from year, month, and day of month.
|
||||
The result need not be in range. */
|
||||
int mon_yday = ((__mon_yday[leapyear (year)]
|
||||
[mon_remainder + 12 * negative_mon_remainder])
|
||||
- 1);
|
||||
long int lmday = mday;
|
||||
long int yday = mon_yday + lmday;
|
||||
|
||||
gtime_t guessed_offset = *offset;
|
||||
|
||||
int sec_requested = sec;
|
||||
|
||||
/*
|
||||
if (LEAP_SECONDS_POSSIBLE)
|
||||
{
|
||||
// Handle out-of-range seconds specially,
|
||||
// since ydhms_tm_diff assumes every minute has 60 seconds.
|
||||
if (sec < 0)
|
||||
sec = 0;
|
||||
if (59 < sec)
|
||||
sec = 59;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Invert CONVERT by probing. First assume the same offset as last
|
||||
time. */
|
||||
|
||||
t0 = ydhms_diff (year, yday, hour, min, sec,
|
||||
EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, - guessed_offset);
|
||||
|
||||
if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
|
||||
{
|
||||
/* gtime_t isn't large enough to rule out overflows, so check
|
||||
for major overflows. A gross check suffices, since if t0
|
||||
has overflowed, it is off by a multiple of TIME_T_MAX -
|
||||
TIME_T_MIN + 1. So ignore any component of the difference
|
||||
that is bounded by a small value. */
|
||||
|
||||
/* Approximate log base 2 of the number of time units per
|
||||
biennium. A biennium is 2 years; use this unit instead of
|
||||
years to avoid integer overflow. For example, 2 average
|
||||
Gregorian years are 2 * 365.2425 * 24 * 60 * 60 seconds,
|
||||
which is 63113904 seconds, and rint (log2 (63113904)) is
|
||||
26. */
|
||||
int ALOG2_SECONDS_PER_BIENNIUM = 26;
|
||||
int ALOG2_MINUTES_PER_BIENNIUM = 20;
|
||||
int ALOG2_HOURS_PER_BIENNIUM = 14;
|
||||
int ALOG2_DAYS_PER_BIENNIUM = 10;
|
||||
int LOG2_YEARS_PER_BIENNIUM = 1;
|
||||
|
||||
int approx_requested_biennia =
|
||||
(SHR (year_requested, LOG2_YEARS_PER_BIENNIUM)
|
||||
- SHR (EPOCH_YEAR - TM_YEAR_BASE, LOG2_YEARS_PER_BIENNIUM)
|
||||
+ SHR (mday, ALOG2_DAYS_PER_BIENNIUM)
|
||||
+ SHR (hour, ALOG2_HOURS_PER_BIENNIUM)
|
||||
+ SHR (min, ALOG2_MINUTES_PER_BIENNIUM)
|
||||
+ (LEAP_SECONDS_POSSIBLE
|
||||
? 0
|
||||
: SHR (sec, ALOG2_SECONDS_PER_BIENNIUM)));
|
||||
|
||||
int approx_biennia = SHR (t0, ALOG2_SECONDS_PER_BIENNIUM);
|
||||
int diff = approx_biennia - approx_requested_biennia;
|
||||
int abs_diff = diff < 0 ? - diff : diff;
|
||||
|
||||
/* IRIX 4.0.5 cc miscalculates TIME_T_MIN / 3: it erroneously
|
||||
gives a positive value of 715827882. Setting a variable
|
||||
first then doing math on it seems to work.
|
||||
(ghazi@caip.rutgers.edu) */
|
||||
gtime_t time_t_max = TIME_T_MAX;
|
||||
gtime_t time_t_min = TIME_T_MIN;
|
||||
gtime_t overflow_threshold =
|
||||
(time_t_max / 3 - time_t_min / 3) >> ALOG2_SECONDS_PER_BIENNIUM;
|
||||
|
||||
if (overflow_threshold < abs_diff)
|
||||
{
|
||||
/* Overflow occurred. Try repairing it; this might work if
|
||||
the time zone offset is enough to undo the overflow. */
|
||||
gtime_t repaired_t0 = -1 - t0;
|
||||
approx_biennia = SHR (repaired_t0, ALOG2_SECONDS_PER_BIENNIUM);
|
||||
diff = approx_biennia - approx_requested_biennia;
|
||||
abs_diff = diff < 0 ? - diff : diff;
|
||||
if (overflow_threshold < abs_diff)
|
||||
return -1;
|
||||
guessed_offset += repaired_t0 - t0;
|
||||
t0 = repaired_t0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Repeatedly use the error to improve the guess. */
|
||||
|
||||
for (t = t1 = t2 = t0;
|
||||
(gt = guess_time_tm (year, yday, hour, min, sec, &t,
|
||||
ranged_convert (convert, &t, &tm)),
|
||||
t != gt);
|
||||
t1 = t2, t2 = t, t = gt)
|
||||
if (t == t1 && t != t2)
|
||||
goto offset_found;
|
||||
else if (--remaining_probes == 0)
|
||||
return -1;
|
||||
|
||||
offset_found:
|
||||
*offset = guessed_offset + t - t0;
|
||||
|
||||
if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
|
||||
{
|
||||
/* Adjust time to reflect the tm_sec requested, not the normalized value.
|
||||
Also, repair any damage from a false match due to a leap second. */
|
||||
int sec_adjustment = (sec == 0 && tm.tm_sec == 60) - sec;
|
||||
t1 = t + sec_requested;
|
||||
t2 = t1 + sec_adjustment;
|
||||
if (((t1 < t) != (sec_requested < 0))
|
||||
| ((t2 < t1) != (sec_adjustment < 0))
|
||||
| ! convert (&t2, &tm))
|
||||
return -1;
|
||||
t = t2;
|
||||
}
|
||||
|
||||
*tp = tm;
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Convert *TP to a gtime_t value. */
|
||||
gtime_t
|
||||
gmktime (struct gtm *tp)
|
||||
{
|
||||
// no time zone stuff. Just do the math ;)
|
||||
static gtime_t localtime_offset;
|
||||
return __mktime_internal (tp, __localtime_r, &localtime_offset);
|
||||
}
|
||||
|
||||
/* Fill a (struct tm) TP* from a given gtime_t time stamp */
|
||||
gtime_t
|
||||
filltm(gtime_t *t, struct gtm *tp)
|
||||
{
|
||||
return __offtime(t, 0, tp);
|
||||
}
|
||||
|
||||
gtime_t g_rtcTime;
|
||||
uint8_t g_ms100 = 0; // global to allow time set function to reset to zero
|
||||
|
||||
void gettime(struct gtm * tm)
|
||||
{
|
||||
filltm(&g_rtcTime, tm); // create a struct tm date/time structure from global unix time stamp
|
||||
}
|
||||
|
||||
|
||||
@@ -1,65 +1,67 @@
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny <shadow@privy.de>
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* open9x is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef fattime_h
|
||||
#define fattime_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
|
||||
#undef CHAR_BIT
|
||||
#define CHAR_BIT 8
|
||||
|
||||
typedef long int gtime_t;
|
||||
|
||||
struct gtm
|
||||
{
|
||||
int8_t tm_sec; /* Seconds. [0-60] (1 leap second) */
|
||||
int8_t tm_min; /* Minutes. [0-59] */
|
||||
int8_t tm_hour; /* Hours. [0-23] */
|
||||
int8_t tm_mday; /* Day. [1-31] */
|
||||
int8_t tm_mon; /* Month. [0-11] */
|
||||
int8_t tm_year; /* Year - 1900. Limited to the year 2115. Oh no! :P */
|
||||
int8_t tm_wday; /* Day of week. [0-6] */
|
||||
int16_t tm_yday; /* Day of year. [0-365] Needed internally for calculations */
|
||||
};
|
||||
|
||||
extern const unsigned short int __mon_yday[2][13];
|
||||
|
||||
extern gtime_t gmktime(struct gtm *tp);
|
||||
extern gtime_t filltm(gtime_t *t, struct gtm *tp);
|
||||
|
||||
extern gtime_t g_unixTime; // Global date/time register, incremented each second in per10ms()
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny <shadow@privy.de>
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* open9x is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RTC_H
|
||||
#define RTC_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef long int gtime_t;
|
||||
|
||||
struct gtm
|
||||
{
|
||||
int8_t tm_sec; /* Seconds. [0-60] (1 leap second) */
|
||||
int8_t tm_min; /* Minutes. [0-59] */
|
||||
int8_t tm_hour; /* Hours. [0-23] */
|
||||
int8_t tm_mday; /* Day. [1-31] */
|
||||
int8_t tm_mon; /* Month. [0-11] */
|
||||
int8_t tm_year; /* Year - 1900. Limited to the year 2115. Oh no! :P */
|
||||
int8_t tm_wday; /* Day of week. [0-6] */
|
||||
int16_t tm_yday; /* Day of year. [0-365] Needed internally for calculations */
|
||||
};
|
||||
|
||||
extern gtime_t g_rtcTime;
|
||||
extern uint8_t g_ms100; // global to allow time set function to reset to zero
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern void rtc_init();
|
||||
extern void rtc_settime(struct gtm * tm);
|
||||
extern void gettime(struct gtm * tm);
|
||||
extern gtime_t gmktime (struct gtm *tm);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -35,7 +35,6 @@
|
||||
#define sdcard_h
|
||||
|
||||
#include "FatFs/ff.h"
|
||||
#include "FatFs/fattime.h"
|
||||
|
||||
#ifdef SIMU
|
||||
#define MODELS_PATH "."
|
||||
|
||||
Reference in New Issue
Block a user