From 002447dbb5863e5668f2fdc7852e25dd77985b10 Mon Sep 17 00:00:00 2001 From: bsongis Date: Mon, 1 Oct 2012 19:58:10 +0000 Subject: [PATCH] [sky9x] RTC Clock on FAT (not tested) [gruvin9x] RTC Menu redesigned [stock] ~50bytes flash saved --- src/FatFs/fattime.c | 479 +-------------------- src/Makefile | 10 +- src/board_ersky9x.cpp | 2 + src/board_gruvin9x.cpp | 18 +- src/{gruvin9x/rtc.h => board_gruvin9x.h} | 22 +- src/drivers.cpp | 4 +- src/ersky9x/diskio.c | 16 +- src/ersky9x/rtc_driver.cpp | 61 +++ src/ersky9x/sound_driver.cpp | 29 +- src/general_menus.cpp | 256 +++++------- src/gruvin9x/{rtc.cpp => rtc_driver.cpp} | 62 ++- src/logs.cpp | 40 +- src/menus.h | 2 +- src/open9x.cpp | 4 +- src/open9x.h | 20 +- src/rtc.cpp | 507 +++++++++++++++++++++++ src/{FatFs/fattime.h => rtc.h} | 132 +++--- src/sdcard.h | 1 - 18 files changed, 855 insertions(+), 810 deletions(-) rename src/{gruvin9x/rtc.h => board_gruvin9x.h} (65%) create mode 100644 src/ersky9x/rtc_driver.cpp rename src/gruvin9x/{rtc.cpp => rtc_driver.cpp} (78%) create mode 100644 src/rtc.cpp rename src/{FatFs/fattime.h => rtc.h} (81%) diff --git a/src/FatFs/fattime.c b/src/FatFs/fattime.c index baae1b91d..3eaea5a03 100644 --- a/src/FatFs/fattime.c +++ b/src/FatFs/fattime.c @@ -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) diff --git a/src/Makefile b/src/Makefile index 0eab6e307..df637a61b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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) diff --git a/src/board_ersky9x.cpp b/src/board_ersky9x.cpp index 87e9d1926..447f037d1 100644 --- a/src/board_ersky9x.cpp +++ b/src/board_ersky9x.cpp @@ -792,6 +792,8 @@ void board_init() alawInit(); + rtc_init(); + eeprom_init(); init_rotary_encoder(); diff --git a/src/board_gruvin9x.cpp b/src/board_gruvin9x.cpp index 7b0917a26..fce1c5c54 100644 --- a/src/board_gruvin9x.cpp +++ b/src/board_gruvin9x.cpp @@ -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<HSMCI_SR); diff --git a/src/ersky9x/rtc_driver.cpp b/src/ersky9x/rtc_driver.cpp new file mode 100644 index 000000000..231a4864f --- /dev/null +++ b/src/ersky9x/rtc_driver.cpp @@ -0,0 +1,61 @@ +/* + * Authors (alphabetical order) + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - 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(); +} diff --git a/src/ersky9x/sound_driver.cpp b/src/ersky9x/sound_driver.cpp index 468e9e84a..4c1c31819 100644 --- a/src/ersky9x/sound_driver.cpp +++ b/src/ersky9x/sound_driver.cpp @@ -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 } } diff --git a/src/general_menus.cpp b/src/general_menus.cpp index 92eca6a12..6446072a6 100644 --- a/src/general_menus.cpp +++ b/src/general_menus.cpp @@ -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); diff --git a/src/gruvin9x/rtc.cpp b/src/gruvin9x/rtc_driver.cpp similarity index 78% rename from src/gruvin9x/rtc.cpp rename to src/gruvin9x/rtc_driver.cpp index a85e0c86f..6ad69daa0 100644 --- a/src/gruvin9x/rtc.cpp +++ b/src/gruvin9x/rtc_driver.cpp @@ -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); } diff --git a/src/logs.cpp b/src/logs.cpp index f59ab005e..0c6a2a654 100644 --- a/src/logs.cpp +++ b/src/logs.cpp @@ -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; } diff --git a/src/menus.h b/src/menus.h index 64125046a..14bcec08a 100644 --- a/src/menus.h +++ b/src/menus.h @@ -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(); diff --git a/src/open9x.cpp b/src/open9x.cpp index 69e7991af..e7ac85c8b 100644 --- a/src/open9x.cpp +++ b/src/open9x.cpp @@ -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; diff --git a/src/open9x.h b/src/open9x.h index 19e53c514..376b2aa73 100644 --- a/src/open9x.h +++ b/src/open9x.h @@ -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 diff --git a/src/rtc.cpp b/src/rtc.cpp new file mode 100644 index 000000000..89177f549 --- /dev/null +++ b/src/rtc.cpp @@ -0,0 +1,507 @@ +/* + * Authors (alphabetical order) + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - 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 +#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 +} + + diff --git a/src/FatFs/fattime.h b/src/rtc.h similarity index 81% rename from src/FatFs/fattime.h rename to src/rtc.h index ec5acebac..17d1704b0 100644 --- a/src/FatFs/fattime.h +++ b/src/rtc.h @@ -1,65 +1,67 @@ -/* - * Authors (alphabetical order) - * - Bertrand Songis - * - Bryan J. Rentoul (Gruvin) - * - Cameron Weeks - * - Erez Raviv - * - Jean-Pierre Parisy - * - Karl Szmutny - * - Michael Blandford - * - Michal Hlavinka - * - Pat Mackenzie - * - Philip Moss - * - Rob Thomson - * - Romolo Manfredini - * - 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 -#include - -#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 + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - 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 + +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 diff --git a/src/sdcard.h b/src/sdcard.h index 543e4c755..b0d7f397d 100644 --- a/src/sdcard.h +++ b/src/sdcard.h @@ -35,7 +35,6 @@ #define sdcard_h #include "FatFs/ff.h" -#include "FatFs/fattime.h" #ifdef SIMU #define MODELS_PATH "."