diff --git a/src/Makefile b/src/Makefile index 1077a4465..519cbcffa 100644 --- a/src/Makefile +++ b/src/Makefile @@ -48,6 +48,19 @@ HELI = NO # Values = YES, NO TEMPLATES = YES +# Enable navigation with Pots / Rotary encoders +# Values = NO +# POT1 (only POT1 available for fields modification), +# POT2 (menus scroll), +# POT3 (cursor down/up), +# POTS (POT1, POT2, POT3), +# RE1 (Rotary encoder 1, on V3/V4 boards) +ifeq ($(PCB), V4) +NAVIGATION = RE1 +else +NAVIGATION = POTS +endif + # gruvin: BEEPER. Values = BUZZER, BUZZER_MOD or SPEAKER # (without a mod, BUZZER can make PPM jack output switch from output to input at random) # SPEAKER mode actually works on the stock radio, using the stock beeper. Sort of sound OK(ish). @@ -122,7 +135,7 @@ endif # Disk IO support (PCB V2+ only) ifneq ($(PCB), STD) - CPPSRC += time.cpp + CPPSRC += gtime.cpp CPPSRC += rtc.cpp CPPSRC += ff.cpp CPPSRC += diskio.cpp @@ -178,6 +191,21 @@ CPPDEFS = -DF_CPU=$(F_CPU)UL # NOTE: PCB version now overrides all the earlier individual settings # These individual settings work only for PCB=STD +# If POT1/POTS/RE1 is used for fields modification +ifeq ($(NAVIGATION), POT1) + CPPDEFS += -DNAVIGATION_POT1 +endif +ifeq ($(NAVIGATION), POT2) + CPPDEFS += -DNAVIGATION_POT2 +endif +ifeq ($(NAVIGATION), POT3) + CPPDEFS += -DNAVIGATION_POT3 +endif +ifeq ($(NAVIGATION), POTS) + CPPDEFS += -DNAVIGATION_POT1 -DNAVIGATION_POT2 -DNAVIGATION_POT3 +endif + + ifeq ($(PCB), STD) # STD PCB, so ... @@ -220,7 +248,7 @@ ifeq ($(PCB), STD) ifeq ($(BATT), UNSTABLE_BANDGAP) CPPDEFS += -DBATT_UNSTABLE_BANDGAP endif - + # gruvin: Legacy support for hardware mod freeing USART1 [DEPRECATED] ifeq ($(USART1), FREED) CPPDEFS += -DUSART1FREED @@ -232,6 +260,11 @@ ifeq ($(PCB), STD) endif else + + ifeq ($(NAVIGATION), RE1) + CPPDEFS += -DNAVIGATION_RE1 + endif + # not PCB=STD, so ... CPPSRC += frsky.cpp CPPDEFS += -DPCBV3 -DFRSKY -DFRSKY_HUB diff --git a/src/diskio.cpp b/src/diskio.cpp index c565f76e8..9671f3674 100644 --- a/src/diskio.cpp +++ b/src/diskio.cpp @@ -26,11 +26,9 @@ /* are platform dependent. */ /*-----------------------------------------------------------------------*/ - -#include +#include "gruvin9x.h" #include "diskio.h" - /* Definitions for MMC/SDC command */ #define CMD0 (0) /* GO_IDLE_STATE */ #define CMD1 (1) /* SEND_OP_COND (MMC) */ @@ -59,8 +57,13 @@ /* Port Controls (Platform dependent) */ // GCC optimisation should result in a single CBI/SBI instructions here -#define CS_LOW() PORTB &= ~0x10 /* MMC CS = L */ -#define CS_HIGH() PORTB |= 0x10 /* MMC CS = H */ +#if defined (PCBV4) +# define CS_LOW() PORTB &= ~0x01 /* MMC CS = L */ +# define CS_HIGH() PORTB |= 0x01 /* MMC CS = H */ +#else +# define CS_LOW() PORTB &= ~0x10 /* MMC CS = L */ +# define CS_HIGH() PORTB |= 0x10 /* MMC CS = H */ +#endif #define SOCKPORT PINB /* Socket contact port */ #define SOCKWP 0x00 // not implemented /* Write protect switch */ @@ -175,7 +178,9 @@ static void power_on (void) { // PORTE &= ~0x80; // Socket power on +#ifndef SIMU for (Timer1 = 2; Timer1; ); // Wait for 20ms +#endif //PORTB = 0b10110101; // Enable drivers //DDRB = 0b11000111; diff --git a/src/drivers.cpp b/src/drivers.cpp index 138ac755f..e0e3c1fc8 100644 --- a/src/drivers.cpp +++ b/src/drivers.cpp @@ -121,7 +121,6 @@ public: uint8_t getDbl() { return m_dblcnt; } }; - Key keys[NUM_KEYS]; void Key::input(bool val, EnumKeys enuk) { @@ -214,10 +213,6 @@ bool keyState(EnumKeys enuk) case SW_Trainer: return PINB & (1<= 0 && !s_editMode) // set the date and time into RTC chip + if (sub >= 0 && s_editMode<=0) // set the date and time into RTC chip { g_ms100 = 0; // start of next second begins now g_unixTime = mktime(&t); // update local timestamp and get wday calculated @@ -286,7 +286,7 @@ void menuProcTime(uint8_t event) break; } - if (!s_editMode) filltm(&g_unixTime, &t); + if (s_editMode<=0) filltm(&g_unixTime, &t); 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, ':'); @@ -299,7 +299,7 @@ void menuProcTime(uint8_t event) 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 ? BLINK : INVERS) : 0; + uint8_t attr = (sub==i && subSub==j) ? (s_editMode>0 ? BLINK : INVERS) : 0; switch(i) { case 0: // DATE @@ -307,15 +307,15 @@ void menuProcTime(uint8_t event) { case 0: lcd_outdezAtt(FW*10+2, y, at->tm_year+1900, attr); - if(attr && (s_editMode || p1valdiff)) at->tm_year = checkIncDec( event, at->tm_year, 110, 200, 0); + if(attr && (s_editMode>0 || p1valdiff)) at->tm_year = checkIncDec( event, at->tm_year, 110, 200, 0); break; case 1: lcd_outdezNAtt(FW*13, y, at->tm_mon+1, attr|LEADING0, 2); - if(attr && (s_editMode || p1valdiff)) at->tm_mon = checkIncDec( event, at->tm_mon, 0, 11, 0); + if(attr && (s_editMode>0 || p1valdiff)) at->tm_mon = checkIncDec( event, at->tm_mon, 0, 11, 0); break; case 2: lcd_outdezNAtt(FW*16-2, y, at->tm_mday, attr|LEADING0, 2); - if(attr && (s_editMode || p1valdiff)) at->tm_mday = checkIncDec( event, at->tm_mday, 1, 31, 0); + if(attr && (s_editMode>0 || p1valdiff)) at->tm_mday = checkIncDec( event, at->tm_mday, 1, 31, 0); break; } break; @@ -325,15 +325,15 @@ void menuProcTime(uint8_t event) { case 0: lcd_outdezNAtt(FW*10+1, y, at->tm_hour, attr|LEADING0, 2); - if(attr && (s_editMode || p1valdiff)) at->tm_hour = checkIncDec( event, at->tm_hour, 0, 23, 0); + 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 || p1valdiff)) at->tm_min = checkIncDec( event, at->tm_min, 0, 59, 0); + 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 || p1valdiff)) at->tm_sec = checkIncDec( event, at->tm_sec, 0, 59, 0); + if(attr && (s_editMode>0 || p1valdiff)) at->tm_sec = checkIncDec( event, at->tm_sec, 0, 59, 0); break; } break; @@ -363,7 +363,7 @@ void menuProcTrainer(uint8_t event) sub--; y = 2*FH; - blink = s_editMode ? BLINK : INVERS ; + blink = (s_editMode>0) ? BLINK : INVERS ; for (uint8_t i=0; i<4; i++) { uint8_t chan = pgm_read_byte(chout_ar+g_eeGeneral.templateSetup*4+i); // G: Issue 30. @@ -374,17 +374,17 @@ void menuProcTrainer(uint8_t event) edit = (sub==i && subSub==0); lcd_putsnAtt(4*FW, y, PSTR("off += :=")+3*td->mode, 3, edit ? blink : 0); - if (edit && s_editMode) + if (edit && s_editMode>0) CHECK_INCDEC_GENVAR(event, td->mode, 0, 2); edit = (sub==i && subSub==1); lcd_outdezAtt(11*FW, y, td->studWeight, edit ? blink : 0); - if (edit && s_editMode) + if (edit && s_editMode>0) CHECK_INCDEC_GENVAR(event, td->studWeight, -100, 100); edit = (sub==i && subSub==2); lcd_putsnAtt(12*FW, y, PSTR("ch1ch2ch3ch4")+3*td->srcChn, 3, edit ? blink : 0); - if (edit && s_editMode) + if (edit && s_editMode>0) CHECK_INCDEC_GENVAR(event, td->srcChn, 0, 3); edit = (sub==i && subSub==3); @@ -455,7 +455,7 @@ void menuProcDiagKeys(uint8_t event) for(uint8_t i=0; i<2; i++) { uint8_t y = i*FH + FH; lcd_putsn_P(14*FW, y, PSTR("RE1RE2")+3*i, 3); - lcd_outdezNAtt(18*FW, y, g_rotenc[i], LEFT|(keyState((EnumKeys)(SW_RE1+i)) ? INVERS : 0)); + lcd_outdezNAtt(18*FW, y, g_rotenc[i], LEFT|(keyState((EnumKeys)(BTN_RE1+i)) ? INVERS : 0)); } #endif diff --git a/src/gruvin9x.cpp b/src/gruvin9x.cpp index aa14e4f7d..b0fccab3e 100644 --- a/src/gruvin9x.cpp +++ b/src/gruvin9x.cpp @@ -25,11 +25,6 @@ // MM/SD card Disk IO Support #if defined (PCBV3) -#include "integer.h" -#include "time.h" -#include "rtc.h" -#include "ff.h" -#include "diskio.h" time_t g_unixTime; // Global date/time register, incremented each second in per10ms() #endif @@ -816,7 +811,7 @@ void getADC_bandgap() { #if defined(PCBSTD) ADMUX=0x1E|ADC_VREF_TYPE; // Switch MUX to internal 1.22V reference - _delay_us(5); // short delay to stabilise reference voltage + _delay_us(7); // short delay to stabilise reference voltage ADCSRA|=0x40; while ((ADCSRA & 0x10)==0); ADCSRA|=0x10; // grab a sample @@ -864,7 +859,6 @@ uint16_t g_LightOffCounter; uint8_t beepAgain = 0; uint8_t beepAgainOrig = 0; uint8_t beepOn = false; -int16_t p1val; inline bool checkSlaveMode() { @@ -1695,18 +1689,6 @@ void perMain() else BACKLIGHT_OFF; - //////////////// - // G: TODO This shouldn't be in perMain(). It should be in the same place - // all the other ADC samples happen - static int16_t p1valprev; - p1valdiff = (p1val-calibratedStick[6])/32; - if(p1valdiff) { - p1valdiff = (p1valprev-calibratedStick[6])/2; - p1val = calibratedStick[6]; - } - p1valprev = calibratedStick[6]; - ///////////////// - g_menuStack[g_menuStackPtr](evt); refreshDisplay(); @@ -2028,30 +2010,6 @@ ISR(TIMER3_CAPT_vect) // G: High frequency noise can cause stack overflo with IS #endif } -#if defined (PCBV3) -/*---------------------------------------------------------*/ -/* 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. */ - -uint32_t get_fattime(void) -{ - struct tm t; - filltm(&g_unixTime, &t); // create a struct tm date/time structure from global unix time stamp - - /* Pack date and time into a DWORD variable */ - 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) - | ((uint32_t)t.tm_min << 5) - | ((uint32_t)t.tm_sec >> 1); -} -#endif - extern uint16_t g_timeMain; /* @@ -2089,6 +2047,29 @@ uint16_t DEBUG2 = 0; #endif +#if defined (PCBV3) +/*---------------------------------------------------------*/ +/* 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. */ + +uint32_t get_fattime(void) // TODO why not in ff.cpp? +{ + struct gtm t; + filltm(&g_unixTime, &t); // create a struct tm date/time structure from global unix time stamp + + /* Pack date and time into a DWORD variable */ + 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) + | ((uint32_t)t.tm_min << 5) + | ((uint32_t)t.tm_sec >> 1); +} +#endif void instantTrim() { @@ -2144,7 +2125,12 @@ void moveTrimsToOffsets() // copy state of 3 primary to subtrim #if defined (PCBV4) // Rotary encoder interrupts -volatile uint8_t g_rotenc[2] = {0}; +volatile uint8_t g_rotenc[2] = {0}; +#endif + +#ifndef SIMU + +#if defined (PCBV4) ISR(INT2_vect) { uint8_t input = PIND & 0b00001100; @@ -2166,10 +2152,8 @@ ISR(INT6_vect) uint8_t input = PINE & 0b01100000; if (input == 0 || input == 0b01100000) g_rotenc[1]--; } -#endif +#endif -#ifndef SIMU - extern unsigned char __bss_end ; uint16_t stack_free() @@ -2295,13 +2279,13 @@ int main(void) } } - sei(); // interrupts needed for eeReadAll function (soon). - g_menuStack[0] = menuMainView; g_menuStack[1] = menuProcModelSelect; lcdSetRefVolt(25); + sei(); // interrupts needed for FRSKY_Init and eeReadAll. + #if defined (FRSKY) FRSKY_Init(); #endif @@ -2341,7 +2325,7 @@ int main(void) #if defined (PCBV3) // Initialise global unix timestamp with current time from RTC chip on SD card interface RTC rtc; - struct tm utm; + struct gtm utm; rtc_gettime(&rtc); utm.tm_year = rtc.year - 1900; utm.tm_mon = rtc.month - 1; diff --git a/src/gruvin9x.h b/src/gruvin9x.h index 8d7a1fcc3..1c8f03d28 100644 --- a/src/gruvin9x.h +++ b/src/gruvin9x.h @@ -30,7 +30,7 @@ #if defined(PCBV3) #include "ff.h" -#include "time.h" +#include "gtime.h" #endif #ifdef SIMU @@ -280,6 +280,10 @@ enum EnumKeys { TRM_RV_UP , TRM_RH_DWN , TRM_RH_UP , +#ifdef PCBV4 + BTN_RE1, + BTN_RE2, +#endif //SW_NC , //SW_ON , SW_ThrCt , @@ -291,8 +295,8 @@ enum EnumKeys { SW_AileDR , SW_Gear , SW_Trainer, - SW_RE1, - SW_RE2 + NUM_KEYS = SW_ThrCt + }; #define CURVE_BASE 7 @@ -376,7 +380,6 @@ enum EnumKeys { #define THRCHK_DEADBAND 16 #define SPLASH_TIMEOUT (4*100) //400 msec - 4 seconds -#define NUM_KEYS TRM_RH_UP+1 #define TRM_BASE TRM_LH_DWN //#define _MSK_KEY_FIRST (_MSK_KEY_REPT|0x20) @@ -732,7 +735,7 @@ extern char userDataDisplayBuf[TELEM_SCREEN_BUFFER_SIZE]; // text buffer for frs #endif #if defined (PCBV3) -extern char g_logFilename[21]; // pers.cpp::resetTelemetry() +extern char g_logFilename[22]; // pers.cpp::resetTelemetry() extern FATFS FATFS_Obj; // pers.cpp::resetTelemetry() extern FIL g_oLogFile; // pers.cpp::resetTelemetry() #endif diff --git a/src/gtime.cpp b/src/gtime.cpp new file mode 100644 index 000000000..ccb460a3e --- /dev/null +++ b/src/gtime.cpp @@ -0,0 +1,485 @@ +/* + * Authors (alphabetical order) + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * + * gruvin9x is based on code named er9x by + * Author - Erez Raviv , which is in turn + * was based on 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 "gtime.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 (time_t) +#endif +#ifndef TIME_T_MAX +# define TIME_T_MAX TYPE_MAXIMUM (time_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 (time_t_is_integer, TYPE_IS_INTEGER (time_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 +#define EOVERFLOW 0 + +/* 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 ( + time_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 >= 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 time_t to struct tm +struct gtm * +__localtime_r (time_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 time_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 time_t precision. Overflow might + occur here. */ + time_t tyear1 = year1; + time_t years = tyear1 - year0; + time_t days = 365 * years + yday1 - yday0 + intervening_leap_days; + time_t hours = 24 * days + hour1 - hour0; + time_t minutes = 60 * hours + min1 - min0; + time_t seconds = 60 * minutes + sec1 - sec0; + return seconds; +} + +/* Return a time_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 time_t +guess_time_tm (long int year, long int yday, int hour, int min, int sec, + time_t *t, struct gtm *tp) +{ + if (tp) + { + time_t d = ydhms_diff (year, yday, hour, min, sec, + tp->tm_year, tp->tm_yday, + tp->tm_hour, tp->tm_min, tp->tm_sec); + time_t t1 = *t + d; + if ((t1 < *t) == (TYPE_SIGNED (time_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) (time_t *, struct gtm *), + time_t *t, struct gtm *tp) +{ + struct gtm *r = convert (t, tp); + + if (!r && *t) + { + time_t bad = *t; + time_t ok = 0; + + /* BAD is a known unconvertible time_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)) + { + time_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 time_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. */ +time_t +__mktime_internal (struct gtm *tp, + struct gtm *(*convert) (time_t *, struct gtm *), + time_t *offset) +{ + time_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 time_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; + + time_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) + { + /* time_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) */ + time_t time_t_max = TIME_T_MAX; + time_t time_t_min = TIME_T_MIN; + time_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. */ + time_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 time_t value. */ +time_t +mktime (struct gtm *tp) +{ + // no time zone stuff. Just do the math ;) + static time_t localtime_offset; + return __mktime_internal (tp, __localtime_r, &localtime_offset); +} + +/* Fill a (struct tm) TP* from a given time_t time stamp */ +time_t +filltm(time_t *t, struct gtm *tp) +{ + return __offtime(t, 0, tp); +} + diff --git a/src/gtime.h b/src/gtime.h new file mode 100644 index 000000000..4c9313db9 --- /dev/null +++ b/src/gtime.h @@ -0,0 +1,55 @@ +/* + * Authors (alphabetical order) + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * + * gruvin9x is based on code named er9x by + * Author - Erez Raviv , which is in turn + * was based on 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 g9x_time_h +#define g9x_time_h + +#include + +#define CHAR_BIT 8 +#define INT_MAX 32767 +#define INT_MIN -32767 +#define LONG_MAX 0x7FFFFFFFL +#define LONG_MIN ((long) 0x80000000L) +#define UINT_MAX 0xFFFFU/0xFFFFFFFFUL +#define ULONG_MAX 0xFFFFFFFFUL + +typedef long int time_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 time_t mktime(struct gtm *tp); +extern time_t filltm(time_t *t, struct gtm *tp); + +#endif + diff --git a/src/menus.cpp b/src/menus.cpp index 2fc9d2fa1..d184073d1 100644 --- a/src/menus.cpp +++ b/src/menus.cpp @@ -27,11 +27,11 @@ int16_t calibratedStick[NUM_STICKS+NUM_POTS]; int16_t ex_chans[NUM_CHNOUT]; // Outputs + intermidiates uint8_t s_pgOfs; -uint8_t s_editMode; +int8_t s_editMode; uint8_t s_noHi; uint8_t s_noScroll; -int16_t g_chans512[NUM_CHNOUT]; +int16_t g_chans512[NUM_CHNOUT]; // TODO not here! void menu_lcd_onoff( uint8_t x,uint8_t y, uint8_t value, uint8_t mode ) { @@ -50,7 +50,10 @@ void DisplayScreenIndex(uint8_t index, uint8_t count, uint8_t attr) lcd_outdezAtt(1+128-FW*(count>9 ? 3 : 2),0,index+1,attr); } +#if defined(NAVIGATION_POT1) || defined(NAVIGATION_RE1) int16_t p1valdiff; +#endif + int8_t checkIncDec_Ret; int16_t checkIncDec(uint8_t event, int16_t val, int16_t i_min, int16_t i_max, uint8_t i_flags) { @@ -63,7 +66,7 @@ int16_t checkIncDec(uint8_t event, int16_t val, int16_t i_min, int16_t i_max, ui kmi=hlp; event=EVT_KEY_FIRST(EVT_KEY_MASK & event); } - if(event==EVT_KEY_FIRST(kpl) || event== EVT_KEY_REPT(kpl) || (s_editMode && (event==EVT_KEY_FIRST(KEY_UP) || event== EVT_KEY_REPT(KEY_UP))) ) { + if(event==EVT_KEY_FIRST(kpl) || event== EVT_KEY_REPT(kpl) || (s_editMode>0 && (event==EVT_KEY_FIRST(KEY_UP) || event== EVT_KEY_REPT(KEY_UP))) ) { newval++; #if defined (BEEPSPKR) beepKeySpkr(BEEP_KEY_UP_FREQ); @@ -71,7 +74,7 @@ int16_t checkIncDec(uint8_t event, int16_t val, int16_t i_min, int16_t i_max, ui beepKey(); #endif kother=kmi; - }else if(event==EVT_KEY_FIRST(kmi) || event== EVT_KEY_REPT(kmi) || (s_editMode && (event==EVT_KEY_FIRST(KEY_DOWN) || event== EVT_KEY_REPT(KEY_DOWN))) ) { + }else if(event==EVT_KEY_FIRST(kmi) || event== EVT_KEY_REPT(kmi) || (s_editMode>0 && (event==EVT_KEY_FIRST(KEY_DOWN) || event== EVT_KEY_REPT(KEY_DOWN))) ) { newval--; #if defined (BEEPSPKR) beepKeySpkr(BEEP_KEY_DOWN_FREQ); @@ -86,13 +89,15 @@ int16_t checkIncDec(uint8_t event, int16_t val, int16_t i_min, int16_t i_max, ui killEvents(kpl); } if(i_min==0 && i_max==1 && event==EVT_KEY_FIRST(KEY_MENU)) { - s_editMode = false; + s_editMode = 0; newval=!val; killEvents(event); } +#if defined(NAVIGATION_POT1) || defined (NAVIGATION_RE1) //change values based on P1 newval -= p1valdiff; +#endif if(newval > i_max) { @@ -155,30 +160,93 @@ bool check_submenu_simple(uint8_t event, uint8_t maxrow) return check_simple(event, 0, 0, 0, maxrow); } +#define SCROLL_TH 64 +#define SCROLL_POT1_TH 32 + #define MAXCOL(row) (horTab ? pgm_read_byte(horTab+min(row, horTabMax)) : (const uint8_t)0) #define INC(val,max) if(val0 ) {val--;} else {val=max;} bool check(uint8_t event, uint8_t curr, MenuFuncP *menuTab, uint8_t menuTabSize, prog_uint8_t *horTab, uint8_t horTabMax, uint8_t maxrow) { +#ifdef NAVIGATION_RE1 + // check rotary encoder 1 if changed -> cursor down/up + static int16_t re1valprev; + p1valdiff = 0; + int8_t scrollRE = re1valprev - g_rotenc[0]; + if (scrollRE) { + re1valprev = g_rotenc[0]; + if (s_editMode > 0) { + p1valdiff = scrollRE; + scrollRE = 0; + } + } + if (event == EVT_KEY_FIRST(BTN_RE1)) { + scrollRE = 0; + if (s_editMode++ > 0) s_editMode = 0; + if (s_editMode > 0 && m_posVert == 0) s_editMode = -1; + } +#else +#define scrollRE 0 +#endif + +#ifdef NAVIGATION_POT1 + // check pot 1 - if changed -> scroll values + static int16_t p1valprev; + p1valdiff = (p1valprev-calibratedStick[6]) / SCROLL_POT1_TH; + if (p1valdiff) p1valprev = calibratedStick[6]; +#endif + +#ifdef NAVIGATION_POT2 + // check pot 2 - if changed -> scroll menu + static int16_t p2valprev; + int8_t scrollLR = (p2valprev-calibratedStick[4]) / SCROLL_TH; + if (scrollLR) p2valprev = calibratedStick[4]; +#else +#define scrollLR 0 +#endif + +#ifdef NAVIGATION_POT3 + // check pot 3 if changed -> cursor down/up + static int16_t p3valprev; + int8_t scrollUD = (p3valprev-calibratedStick[5]) / SCROLL_TH; + if (scrollUD) p3valprev = calibratedStick[5]; +#else +#define scrollUD 0 +#endif + + if(scrollLR || scrollUD || p1valdiff) g_LightOffCounter = g_eeGeneral.lightAutoOff*500; // on keypress turn the light on 5*100 + if (menuTab) { uint8_t attr = 0; if (m_posVert==0 && !s_noScroll) { attr = INVERS; - switch(event) - { + + int8_t cc = curr; + + if (scrollLR || (scrollRE && s_editMode < 0)) { + cc = limit((int8_t)0, (int8_t)(curr - scrollLR - scrollRE), (int8_t)(menuTabSize-1)); + } + + switch(event) { case EVT_KEY_FIRST(KEY_LEFT): - if(curr>0) - chainMenu((MenuFuncP)pgm_read_adr(&menuTab[curr-1])); + if (curr > 0) + cc = curr - 1; else - chainMenu((MenuFuncP)pgm_read_adr(&menuTab[menuTabSize-1])); - return false; + cc = menuTabSize-1; + break; + case EVT_KEY_FIRST(KEY_RIGHT): - if(curr < (menuTabSize-1)) - chainMenu((MenuFuncP)pgm_read_adr(&menuTab[curr+1])); + if (curr < (menuTabSize-1)) + cc = curr + 1; else - chainMenu((MenuFuncP)pgm_read_adr(&menuTab[0])); - return false; + cc = 0; + break; + } + + if (cc != curr) { + chainMenu((MenuFuncP)pgm_read_adr(&menuTab[cc])); + return false; } } s_noScroll = 0; @@ -188,23 +256,67 @@ bool check(uint8_t event, uint8_t curr, MenuFuncP *menuTab, uint8_t menuTabSize, theFile.DisplayProgressBar(menuTab ? lcd_lastPos-2*FW-((curr+1)/10*FWNUM)-2 : 20*FW+1); uint8_t maxcol = MAXCOL(m_posVert); + + if (s_editMode<=0) { + if (scrollUD) { + m_posVert = limit((int8_t)0, (int8_t)(m_posVert - scrollUD), (int8_t)maxrow); + m_posHorz = min(m_posHorz, MAXCOL(m_posVert)); + BLINK_SYNC; + } + + if (scrollLR && m_posVert>0) { + m_posHorz = limit((int8_t)0, (int8_t)(m_posHorz - scrollLR), (int8_t)maxcol); + BLINK_SYNC; + } + +#ifdef NAVIGATION_RE1 + while (scrollRE) { + if (scrollRE > 0) { + --scrollRE; + if (++m_posHorz > MAXCOL(m_posVert)) { + m_posHorz = 0; + if (++m_posVert > maxrow) { + m_posVert = maxrow; + m_posHorz = MAXCOL(m_posVert); + scrollRE = 0; + } + } + } + else { + ++scrollRE; + if (m_posHorz-- == 0) { + if (m_posVert-- == 0) { + m_posVert = 0; + m_posHorz = 0; + scrollRE = 0; + } + else { + m_posHorz = MAXCOL(m_posVert); + } + } + } + } +#endif + + } + switch(event) { case EVT_ENTRY: minit(); - s_editMode = false; + s_editMode = -1; break; case EVT_KEY_FIRST(KEY_MENU): if (maxcol > 0) - s_editMode = !s_editMode; + s_editMode = (s_editMode<=0); break; case EVT_KEY_LONG(KEY_EXIT): - s_editMode = false; + s_editMode = 0; popMenu(); break; case EVT_KEY_BREAK(KEY_EXIT): - if(s_editMode) { - s_editMode = false; + if(s_editMode>0) { + s_editMode = 0; break; } if(m_posVert==0 || !menuTab) { @@ -219,7 +331,7 @@ bool check(uint8_t event, uint8_t curr, MenuFuncP *menuTab, uint8_t menuTabSize, case EVT_KEY_REPT(KEY_RIGHT): //inc if(m_posHorz==maxcol) break; case EVT_KEY_FIRST(KEY_RIGHT)://inc - if(!horTab || s_editMode)break; + if(!horTab || s_editMode>0)break; INC(m_posHorz,maxcol); BLINK_SYNC; break; @@ -227,7 +339,7 @@ bool check(uint8_t event, uint8_t curr, MenuFuncP *menuTab, uint8_t menuTabSize, case EVT_KEY_REPT(KEY_LEFT): //dec if(m_posHorz==0) break; case EVT_KEY_FIRST(KEY_LEFT)://dec - if(!horTab || s_editMode)break; + if(!horTab || s_editMode>0)break; DEC(m_posHorz,maxcol); BLINK_SYNC; break; @@ -235,7 +347,7 @@ bool check(uint8_t event, uint8_t curr, MenuFuncP *menuTab, uint8_t menuTabSize, case EVT_KEY_REPT(KEY_DOWN): //inc if(m_posVert==maxrow) break; case EVT_KEY_FIRST(KEY_DOWN): //inc - if(s_editMode)break; + if(s_editMode>0)break; do { INC(m_posVert,maxrow); } while(MAXCOL(m_posVert) == (uint8_t)-1); @@ -246,7 +358,7 @@ bool check(uint8_t event, uint8_t curr, MenuFuncP *menuTab, uint8_t menuTabSize, case EVT_KEY_REPT(KEY_UP): //dec if(m_posVert==0) break; case EVT_KEY_FIRST(KEY_UP): //dec - if(s_editMode)break; + if(s_editMode>0)break; do { DEC(m_posVert,maxrow); } while(MAXCOL(m_posVert) == (uint8_t)-1); diff --git a/src/menus.h b/src/menus.h index 6f2e7c7ae..ba3f292d8 100644 --- a/src/menus.h +++ b/src/menus.h @@ -69,18 +69,23 @@ void menuProcModelSelect(uint8_t event); void menuProcStatistic(uint8_t event); void menuProcStatistic2(uint8_t event); +#if defined(NAVIGATION_POT1) || defined(NAVIGATION_RE1) extern int16_t p1valdiff; +#else +#define p1valdiff 0 +#endif + extern int8_t checkIncDec_Ret; // global helper vars -extern uint8_t s_editMode; // global editmode +extern int8_t s_editMode; // global editmode int16_t checkIncDec(uint8_t event, int16_t i_pval, int16_t i_min, int16_t i_max, uint8_t i_flags); int8_t checkIncDecModel(uint8_t event, int8_t i_val, int8_t i_min, int8_t i_max); int8_t checkIncDecGen(uint8_t event, int8_t i_val, int8_t i_min, int8_t i_max); -#define CHECK_INCDEC_MODELVAR( event, var, min, max) \ +#define CHECK_INCDEC_MODELVAR( event, var, min, max) \ var = checkIncDecModel(event,var,min,max) -#define CHECK_INCDEC_GENVAR( event, var, min, max) \ +#define CHECK_INCDEC_GENVAR( event, var, min, max) \ var = checkIncDecGen(event,var,min,max) // Menus related stuff ... diff --git a/src/model_menus.cpp b/src/model_menus.cpp index 48954501d..8f56a2c2c 100644 --- a/src/model_menus.cpp +++ b/src/model_menus.cpp @@ -345,7 +345,7 @@ void menuProcModelSelect(uint8_t event) void EditName(uint8_t x, uint8_t y, char *name, uint8_t size, uint8_t event, bool active, uint8_t & cur) { if (active) { - if (s_editMode) { + if (s_editMode>0) { switch(event) { case EVT_KEY_BREAK(KEY_LEFT): if (cur>0) cur--; @@ -360,8 +360,8 @@ void EditName(uint8_t x, uint8_t y, char *name, uint8_t size, uint8_t event, boo } } - lcd_putsnAtt(x, y, name, size, ZCHAR | (active ? (s_editMode ? 0 : INVERS) : 0)); - if (active && s_editMode) { + lcd_putsnAtt(x, y, name, size, ZCHAR | (active ? ((s_editMode>0) ? 0 : INVERS) : 0)); + if (active && s_editMode>0) { char c = name[cur]; char v = c; if (p1valdiff || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_FIRST(KEY_UP) @@ -402,12 +402,12 @@ void menuProcModel(uint8_t event) for (uint8_t i=0; i<2; i++, timer=&g_model.timer2) { if (s_pgOfsmode, sub==subN && m_posHorz==0 ? (s_editMode ? BLINK : INVERS) : 0); + putsTmrMode(PARAM_OFS, y, timer->mode, sub==subN && m_posHorz==0 ? ((s_editMode>0) ? BLINK : INVERS) : 0); putsTime(14*FW-3, y, timer->val, - (sub==subN && m_posHorz==1 ? (s_editMode ? BLINK : INVERS):0), - (sub==subN && m_posHorz==2 ? (s_editMode ? BLINK : INVERS):0) ); - lcd_putsnAtt(19*FW, y, PSTR("\x7e\x7f")+1-timer->dir,1,sub==subN && m_posHorz==3 ? (s_editMode ? BLINK : INVERS) : 0); - if (sub==subN && (s_editMode || p1valdiff)) { + (sub==subN && m_posHorz==1 ? ((s_editMode>0) ? BLINK : INVERS):0), + (sub==subN && m_posHorz==2 ? ((s_editMode>0) ? BLINK : INVERS):0) ); + lcd_putsnAtt(19*FW, y, PSTR("\x7e\x7f")+1-timer->dir,1,sub==subN && m_posHorz==3 ? ((s_editMode>0) ? BLINK : INVERS) : 0); + if (sub==subN && (s_editMode>0 || p1valdiff)) { switch (m_posHorz) { case 0: CHECK_INCDEC_MODELVAR(event, timer->mode, -(13+2*MAX_SWITCH),(13+2*MAX_SWITCH)); @@ -461,7 +461,7 @@ void menuProcModel(uint8_t event) lcd_puts_P( 0, y, PSTR("T-Trim")); menu_lcd_onoff(PARAM_OFS, y, g_model.thrTrim, sub==subN && m_posHorz==0) ; lcd_putsnAtt(PARAM_OFS+4*FW, y, PSTR("LinearExp ")+6*g_model.thrExpo,6,(sub==subN && m_posHorz==1) ? INVERS : 0); - if (sub==subN && (s_editMode || p1valdiff)) { + if (sub==subN && (s_editMode>0 || p1valdiff)) { switch (m_posHorz) { case 0: CHECK_INCDEC_MODELVAR(event,g_model.thrTrim,0,1); @@ -480,7 +480,7 @@ void menuProcModel(uint8_t event) if(sub==subN){ if((event==EVT_KEY_FIRST(KEY_MENU)) || p1valdiff) { killEvents(event); - s_editMode = false; + s_editMode = 0; g_model.beepANACenter ^= (1<0 ? BLINK : INVERS):0)); if(!g_model.protocol) { - lcd_putsnAtt(PARAM_OFS+4*FW, y, PSTR("4CH 6CH 8CH 10CH12CH14CH16CH")+4*(g_model.ppmNCH+2),4,(sub==subN && m_posHorz==1 ? (s_editMode ? BLINK : INVERS):0)); + lcd_putsnAtt(PARAM_OFS+4*FW, y, PSTR("4CH 6CH 8CH 10CH12CH14CH16CH")+4*(g_model.ppmNCH+2),4,(sub==subN && m_posHorz==1 ? ((s_editMode>0) ? BLINK : INVERS):0)); lcd_putsAtt(PARAM_OFS+11*FW, y, PSTR("u"),0); - lcd_outdezAtt(PARAM_OFS+11*FW, y, (g_model.ppmDelay*50)+300, (sub==subN && m_posHorz==2 ? (s_editMode ? BLINK : INVERS):0)); + lcd_outdezAtt(PARAM_OFS+11*FW, y, (g_model.ppmDelay*50)+300, (sub==subN && m_posHorz==2 ? ((s_editMode>0) ? BLINK : INVERS):0)); } else if (sub==subN) { m_posHorz = 0; } - if (sub==subN && (s_editMode || p1valdiff || !g_model.protocol)) { + if (sub==subN && (s_editMode>0 || p1valdiff || !g_model.protocol)) { switch (m_posHorz) { case 0: CHECK_INCDEC_MODELVAR(event,g_model.protocol,0,PROT_MAX); @@ -521,8 +521,8 @@ void menuProcModel(uint8_t event) lcd_puts_P(0, y, PSTR("PPM frame")); lcd_puts_P(PARAM_OFS+3*FW, y, PSTR("ms")); lcd_outdezAtt(PARAM_OFS, y, (int16_t)g_model.ppmFrameLength*5 + 225, ((sub==subN && m_posHorz==0) ? INVERS:0) | PREC1|LEFT); - lcd_putsnAtt(PARAM_OFS+6*FW, y, PSTR("POSNEG")+3*g_model.pulsePol,3,(sub==subN && m_posHorz==1 ? (s_editMode ? BLINK : INVERS):0)); - if(sub==subN && (s_editMode || p1valdiff)) { + lcd_putsnAtt(PARAM_OFS+6*FW, y, PSTR("POSNEG")+3*g_model.pulsePol,3,(sub==subN && m_posHorz==1 ? ((s_editMode>0) ? BLINK : INVERS):0)); + if(sub==subN && (s_editMode>0 || p1valdiff)) { switch (m_posHorz) { case 0: CHECK_INCDEC_MODELVAR(event, g_model.ppmFrameLength, -20, 20); @@ -570,13 +570,13 @@ void menuProcPhaseOne(uint8_t event) if (v > TRIM_EXTENDED_MAX) { uint8_t p = v - TRIM_EXTENDED_MAX - 1; if (p >= s_currIdx) p++; - lcd_putcAtt((10+t)*FW, y, '0'+p, (attr && m_posHorz==t) ? (s_editMode ? BLINK : INVERS) : 0); + lcd_putcAtt((10+t)*FW, y, '0'+p, (attr && m_posHorz==t) ? ((s_editMode>0) ? BLINK : INVERS) : 0); } else { v = TRIM_EXTENDED_MAX; - putsChnLetter((10+t)*FW, y, t+1, (attr && m_posHorz==t) ? (s_editMode ? BLINK : INVERS) : 0); + putsChnLetter((10+t)*FW, y, t+1, (attr && m_posHorz==t) ? ((s_editMode>0) ? BLINK : INVERS) : 0); } - if (attr && m_posHorz==t && (s_editMode || p1valdiff)) { + if (attr && m_posHorz==t && ((s_editMode>0) || p1valdiff)) { v = checkIncDec(event, v, TRIM_EXTENDED_MAX, TRIM_EXTENDED_MAX+MAX_PHASES-1, EE_MODEL); if (checkIncDec_Ret) { if (v == TRIM_EXTENDED_MAX) v = 0; @@ -763,10 +763,10 @@ void menuProcCurveOne(uint8_t event) autoThrStep = 0; break; case EVT_KEY_FIRST(KEY_MENU): - if (!s_editMode) { + if (s_editMode<=0) { switch (m_posHorz) { case 0: - s_editMode = true; + s_editMode = 1; break; case 1: if (++dfltCrv > 4) @@ -787,9 +787,9 @@ void menuProcCurveOne(uint8_t event) if (autoThrStep) { autoThrStep = 0; } - else if (s_editMode) { + else if (s_editMode>0) { m_posHorz = 0; - s_editMode = false; + s_editMode = 0; } else { popMenu(); @@ -801,7 +801,7 @@ void menuProcCurveOne(uint8_t event) break; case EVT_KEY_REPT(KEY_RIGHT): case EVT_KEY_FIRST(KEY_RIGHT): - if (!autoThrStep && m_posHorz<(s_editMode ? points-1 : ((g_menuStack[g_menuStackPtr-1] == menuProcExpoOne && IS_THROTTLE(expoaddress(s_currIdx)->chn)) ? 2 : 1))) m_posHorz++; + if (!autoThrStep && m_posHorz<((s_editMode>0) ? points-1 : ((g_menuStack[g_menuStackPtr-1] == menuProcExpoOne && IS_THROTTLE(expoaddress(s_currIdx)->chn)) ? 2 : 1))) m_posHorz++; break; } @@ -813,14 +813,14 @@ void menuProcCurveOne(uint8_t event) else { x = 4*FW; y = (i+1) * FH; } - uint8_t attr = (s_editMode && m_posHorz == i) ? INVERS : 0; + uint8_t attr = (s_editMode>0 && m_posHorz==i) ? INVERS : 0; lcd_outdezAtt(x, y, crv[i], attr); } lcd_puts_P(0*FW, 7*FH, PSTR("MODE")); - lcd_putsnAtt(5*FW-2, 7*FH, PSTR("EDIT ""PRSET""A.THR")+5*(!s_editMode)*m_posHorz, 5, s_editMode || autoThrStep ? 0 : INVERS); + lcd_putsnAtt(5*FW-2, 7*FH, PSTR("EDIT ""PRSET""A.THR")+5*(s_editMode<=0)*m_posHorz, 5, s_editMode>0 || autoThrStep ? 0 : INVERS); - if (s_editMode || autoThrStep) { + if (s_editMode>0 || autoThrStep) { for (uint8_t i=0; i' for (uint8_t j=0; j<4; j++) { - uint8_t attr = ((sub==k && m_posHorz==j) ? (s_editMode ? BLINK : INVERS) : 0); - uint8_t active = (attr && (s_editMode || p1valdiff)) ; + uint8_t attr = ((sub==k && m_posHorz==j) ? ((s_editMode>0) ? BLINK : INVERS) : 0); + uint8_t active = (attr && (s_editMode>0 || p1valdiff)) ; switch(j) { case 0: @@ -1490,7 +1490,7 @@ void menuProcLimits(uint8_t event) else if (attr && event==EVT_KEY_LONG(KEY_MENU)) { int16_t zero = g_chans512[k]; ld->offset = (ld->revert) ? -zero : zero; - s_editMode = false; + s_editMode = 0; STORE_MODELVARS; } break; @@ -1583,7 +1583,7 @@ void menuProcCustomSwitches(uint8_t event) y=(i+1)*FH; k=i+s_pgOfs; if(k==NUM_CSW) break; - uint8_t attr = (sub==k ? (s_editMode ? BLINK : INVERS) : 0); + uint8_t attr = (sub==k ? ((s_editMode>0) ? BLINK : INVERS) : 0); CustomSwData &cs = g_model.customSw[k]; //write SW names here @@ -1614,7 +1614,7 @@ void menuProcCustomSwitches(uint8_t event) putsChnRaw( 17*FW, y, cs.v2 ,m_posHorz==2 ? attr : 0); } - if((s_editMode || p1valdiff) && attr) + if((s_editMode>0 || p1valdiff) && attr) switch (m_posHorz) { case 0: CHECK_INCDEC_MODELVAR( event, cs.func, 0,CS_MAXF); @@ -1671,8 +1671,8 @@ void menuProcFunctionSwitches(uint8_t event) if(k==NUM_CHNOUT) break; FuncSwData *sd = &g_model.funcSw[k]; for (uint8_t j=0; j<2; j++) { - uint8_t attr = ((sub==k && m_posHorz==j) ? (s_editMode ? BLINK : INVERS) : 0); - uint8_t active = (attr && (s_editMode || p1valdiff)); + uint8_t attr = ((sub==k && m_posHorz==j) ? ((s_editMode>0) ? BLINK : INVERS) : 0); + uint8_t active = (attr && (s_editMode>0 || p1valdiff)); switch (j) { case 0: putsSwitches(1*FW, y, sd->swtch, attr); @@ -1710,8 +1710,8 @@ void menuProcSafetySwitches(uint8_t event) SafetySwData *sd = &g_model.safetySw[k]; putsChn(0,y,k+1,0); for(uint8_t j=0; j<=2;j++){ - uint8_t attr = ((m_posVert-1==k && m_posHorz==j) ? (s_editMode ? BLINK : INVERS) : 0); - uint8_t active = (attr && (s_editMode || p1valdiff)); + uint8_t attr = ((m_posVert-1==k && m_posHorz==j) ? ((s_editMode>0) ? BLINK : INVERS) : 0); + uint8_t active = (attr && (s_editMode>0 || p1valdiff)); switch(j) { case 0: @@ -1745,11 +1745,11 @@ void menuProcTelemetry(uint8_t event) case EVT_KEY_BREAK(KEY_UP): case EVT_KEY_BREAK(KEY_LEFT): case EVT_KEY_BREAK(KEY_RIGHT): - if(s_editMode) // only fr-sky alarm fields have an edit mode + if (s_editMode>0) // only fr-sky alarm fields have an edit mode FRSKY_setModelAlarms(); // update Fr-Sky module when edit mode exited } - blink = s_editMode ? BLINK : INVERS ; + blink = (s_editMode>0) ? BLINK : INVERS ; uint8_t subN = 1; uint8_t t; int16_t val; @@ -1767,7 +1767,7 @@ void menuProcTelemetry(uint8_t event) lcd_putsAtt(4, y, PSTR("Max"), 0); putsTelemetry(8*FW, y, g_model.frsky.channels[i].ratio, g_model.frsky.channels[i].type, (sub==subN && m_posHorz==0 ? blink:0)|NO_UNIT|LEFT); lcd_putsnAtt(lcd_lastPos, y, PSTR("v-")+g_model.frsky.channels[i].type, 1, (sub==subN && m_posHorz==1 ? blink:0)); - if (sub==subN && (s_editMode || p1valdiff)) { + if (sub==subN && (s_editMode>0 || p1valdiff)) { if (m_posHorz == 0) g_model.frsky.channels[i].ratio = checkIncDec(event, g_model.frsky.channels[i].ratio, 0, 255, EE_MODEL); else @@ -1792,8 +1792,8 @@ void menuProcTelemetry(uint8_t event) putsTelemetry(8*FW, y, val, g_model.frsky.channels[i].type, (sub==subN && m_posHorz==0 ? blink:0)|LEFT); val = ((int16_t)g_model.frsky.channels[i].barMax+g_model.frsky.channels[i].offset)*g_model.frsky.channels[i].ratio / 255; putsTelemetry(13*FW, y, val, g_model.frsky.channels[i].type, (sub==subN && m_posHorz==1 ? blink:0)|LEFT); - if(sub==subN && m_posHorz==0 && (s_editMode || p1valdiff)) g_model.frsky.channels[i].barMin = checkIncDec(event, g_model.frsky.channels[i].barMin, 0, 255, EE_MODEL); - if(sub==subN && m_posHorz==1 && (s_editMode || p1valdiff)) g_model.frsky.channels[i].barMax = checkIncDec(event, g_model.frsky.channels[i].barMax, 0, 255, EE_MODEL); + if(sub==subN && m_posHorz==0 && (s_editMode>0 || p1valdiff)) g_model.frsky.channels[i].barMin = checkIncDec(event, g_model.frsky.channels[i].barMin, 0, 255, EE_MODEL); + if(sub==subN && m_posHorz==1 && (s_editMode>0 || p1valdiff)) g_model.frsky.channels[i].barMax = checkIncDec(event, g_model.frsky.channels[i].barMax, 0, 255, EE_MODEL); } subN++; @@ -1806,7 +1806,7 @@ void menuProcTelemetry(uint8_t event) uint8_t alarmValue = ((uint16_t)g_model.frsky.channels[i].alarms_value[j] * g_model.frsky.channels[i].ratio) / 255; putsTelemetry(14*FW, y, alarmValue, g_model.frsky.channels[i].type, (sub==subN && m_posHorz==2 ? blink:0) | LEFT); - if(sub==subN && (s_editMode || p1valdiff)) { + if(sub==subN && (s_editMode>0 || p1valdiff)) { switch (m_posHorz) { case 0: t = ALARM_LEVEL(i, j); diff --git a/src/rtc.cpp b/src/rtc.cpp index 922a454b1..479e493b8 100644 --- a/src/rtc.cpp +++ b/src/rtc.cpp @@ -22,19 +22,23 @@ /*--------------------------------------------------------------------------*/ /* RTC controls */ -#include -#include -#include "rtc.h" - - +#include "gruvin9x.h" +#if defined (PCBV4) +#define SCL_LOW() DDRD |= 0x01 /* SCL = LOW */ +#define SCL_HIGH() DDRD &= ~0x01 /* SCL = High-Z */ +#define SCL_VAL ((PIND & 0x01) ? 1 : 0) /* SCL input level */ +#define SDA_LOW() DDRD |= 0x02 /* SDA = LOW */ +#define SDA_HIGH() DDRD &= ~0x02 /* SDA = High-Z */ +#define SDA_VAL ((PIND & 0x02) ? 1 : 0) /* SDA input level */ +#else // PCBV3 #define SCL_LOW() DDRB |= 0x20 /* SCL = LOW */ #define SCL_HIGH() DDRB &= ~0x20 /* SCL = High-Z */ #define SCL_VAL ((PINB & 0x20) ? 1 : 0) /* SCL input level */ #define SDA_LOW() DDRB |= 0x40 /* SDA = LOW */ #define SDA_HIGH() DDRB &= ~0x40 /* SDA = High-Z */ #define SDA_VAL ((PINB & 0x40) ? 1 : 0) /* SDA input level */ - +#endif /*-------------------------------------------------*/ diff --git a/src/simpgmspace.cpp b/src/simpgmspace.cpp index 59013ae05..c5487440e 100644 --- a/src/simpgmspace.cpp +++ b/src/simpgmspace.cpp @@ -27,7 +27,7 @@ #include "gruvin9x.h" #include "menus.h" -volatile unsigned char pinb=0, pinc=0xff, pind, pine=0xff, ping=0xff; +volatile unsigned char pinb=0, pinc=0xff, pind, pine=0xff, ping=0xff, pinj=0xff, pinl=0; unsigned char portb, dummyport; const char *eepromFile = "eeprom.bin"; diff --git a/src/simpgmspace.h b/src/simpgmspace.h index efad16c06..06ba1b8ec 100644 --- a/src/simpgmspace.h +++ b/src/simpgmspace.h @@ -39,6 +39,9 @@ typedef const int8_t prog_int8_t; extern sem_t eeprom_write_sem; +#define loop_until_bit_is_set( port, bitnum) \ + while ( 0/*! ( (port) & (1 << (bitnum)) )*/ ) ; + #define PROGMEM #define pgm_read_byte(address_short) (*(uint8_t*)(address_short)) #define pgm_read_word(address_short) (*(uint16_t*)(address_short)) @@ -70,6 +73,8 @@ extern sem_t eeprom_write_sem; #define PIND ~pind #define PINE ~pine #define PING ~ping +#define PINJ ~pinj +#define PINL ~pinl #define EEMEM #define UCSR0B dummyport @@ -79,8 +84,38 @@ extern sem_t eeprom_write_sem; #define DDE0 dummyport #define PORTE0 dummyport #define RXCIE0 dummyport +#define OCR0A dummyport -extern volatile unsigned char pinb,pinc,pind,pine,ping; +#define SPDR dummyport +#define SPSR dummyport +#define SPIF dummyport +#define SPCR dummyport + +#define OUT_B_LIGHT 7 +#define INP_E_ElevDR 2 +#define INP_E_Trainer 5 +#define INP_E_Gear 4 +#define INP_C_ThrCt 6 +#define INP_C_AileDR 7 +#define INP_E_ID2 6 + +#define INP_B_KEY_LFT 6 +#define INP_B_KEY_RGT 5 +#define INP_B_KEY_UP 4 +#define INP_B_KEY_DWN 3 +#define INP_B_KEY_EXT 2 +#define INP_B_KEY_MEN 1 + +#define INP_P_SPARE6 7 +#define INP_P_SPARE5 6 +#define INP_P_KEY_EXT 5 +#define INP_P_KEY_MEN 4 +#define INP_P_KEY_LFT 3 +#define INP_P_KEY_RGT 2 +#define INP_P_KEY_UP 1 +#define INP_P_KEY_DWN 0 + +extern volatile unsigned char pinb,pinc,pind,pine,ping,pinj,pinl; extern unsigned char portb,dummyport; void InitEepromThread(); diff --git a/src/simu.cpp b/src/simu.cpp index fbfac1d39..3dfb4aa56 100644 --- a/src/simu.cpp +++ b/src/simu.cpp @@ -269,21 +269,25 @@ void Gruvin9xSim::refreshDiplay() if(hasFocus()) { static FXuint keys1[]={ - KEY_Return, INP_B_KEY_MEN, - KEY_Page_Up, INP_B_KEY_MEN, - KEY_KP_1, INP_B_KEY_MEN, - KEY_Page_Down, INP_B_KEY_EXT, - KEY_BackSpace, INP_B_KEY_EXT, - KEY_KP_0, INP_B_KEY_EXT, - KEY_Down, INP_B_KEY_DWN, - KEY_Up, INP_B_KEY_UP, - KEY_Right, INP_B_KEY_RGT, - KEY_Left, INP_B_KEY_LFT + KEY_Return, INP_B_KEY_MEN, INP_P_KEY_MEN, + KEY_Page_Up, INP_B_KEY_MEN, INP_P_KEY_MEN, + KEY_KP_1, INP_B_KEY_MEN, INP_P_KEY_MEN, + KEY_Page_Down, INP_B_KEY_EXT, INP_P_KEY_EXT, + KEY_BackSpace, INP_B_KEY_EXT, INP_P_KEY_EXT, + KEY_KP_0, INP_B_KEY_EXT, INP_P_KEY_EXT, + KEY_Down, INP_B_KEY_DWN, INP_P_KEY_DWN, + KEY_Up, INP_B_KEY_UP, INP_P_KEY_UP, + KEY_Right, INP_B_KEY_RGT, INP_P_KEY_RGT, + KEY_Left, INP_B_KEY_LFT, INP_P_KEY_LFT }; pinb &= ~ 0x7e; - for(unsigned i=0; igetKeyState(keys1[i])) pinb |= (1<getKeyState(keys1[i])) { + pinb |= (1<