Backup after extended trims merge.
This commit is contained in:
+1
-1
@@ -288,7 +288,7 @@ CPPFLAGS += -O$(OPT)
|
||||
#CPPFLAGS += -fshort-enums
|
||||
#CPPFLAGS += -fno-exceptions
|
||||
#CPPFLAGS += -fno-unit-at-a-time
|
||||
#CPPFLAGS += -fno-inline-small-functions
|
||||
CPPFLAGS += -fno-inline-small-functions
|
||||
CPPFLAGS += -Wall
|
||||
CPPFLAGS += -Wno-strict-aliasing
|
||||
#CPPFLAGS += -Wstrict-prototypes
|
||||
|
||||
+37
-65
@@ -305,16 +305,29 @@ uint8_t getFlightPhase()
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t getTrimFlightPhase(uint8_t idx, int8_t phase)
|
||||
int16_t getTrimValue(uint8_t phase, uint8_t idx)
|
||||
{
|
||||
PhaseData *p = phaseaddress(phase);
|
||||
return (((int16_t)p->trim[idx]) << 2) + ((p->trim_ext >> (2*idx)) & 0x03);
|
||||
}
|
||||
|
||||
void setTrimValue(uint8_t phase, uint8_t idx, int16_t trim)
|
||||
{
|
||||
PhaseData *p = phaseaddress(phase);
|
||||
p->trim[idx] = (int8_t)(trim >> 2);
|
||||
p->trim_ext = (p->trim_ext & ~(0x03 << (2*idx))) + (((trim & 0x03) << (2*idx)));
|
||||
STORE_MODELVARS;
|
||||
}
|
||||
|
||||
uint8_t getTrimFlightPhase(uint8_t idx, int8_t phase) // TODO uint8_t phase?
|
||||
{
|
||||
if (phase == -1) phase = getFlightPhase();
|
||||
|
||||
for (uint8_t i=0; i<MAX_PHASES; i++) {
|
||||
if (phase == 0) return 0;
|
||||
int8_t trim = g_model.phaseData[phase].trim[idx];
|
||||
if (trim > TRIM_MAX) return 0;
|
||||
if (trim >= TRIM_MIN) return phase;
|
||||
uint8_t result = 129 + trim;
|
||||
int16_t trim = getTrimValue(phase, idx);
|
||||
if (trim <= TRIM_EXTENDED_MAX) return phase;
|
||||
uint8_t result = trim-TRIM_EXTENDED_MAX-1;
|
||||
if (result >= phase) result++;
|
||||
phase = result;
|
||||
}
|
||||
@@ -411,27 +424,19 @@ bool getSwitch(int8_t swtch, bool nc, uint8_t level)
|
||||
break;
|
||||
case (CS_EQUAL):
|
||||
return (x==y);
|
||||
break;
|
||||
case (CS_NEQUAL):
|
||||
return (x!=y);
|
||||
break;
|
||||
case (CS_GREATER):
|
||||
return (x>y);
|
||||
break;
|
||||
case (CS_LESS):
|
||||
return (x<y);
|
||||
break;
|
||||
case (CS_EGREATER):
|
||||
return (x>=y);
|
||||
break;
|
||||
case (CS_ELESS):
|
||||
return (x<=y);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -675,30 +680,6 @@ void alert(const prog_char * s, bool defaults)
|
||||
}
|
||||
}
|
||||
|
||||
void incSubtrim(uint8_t idx, int16_t inc)
|
||||
{
|
||||
for (int8_t i=0; i<MAX_PHASES; i++) {
|
||||
PhaseData *phase = phaseaddress(i);
|
||||
int16_t trim = phase->trim[idx];
|
||||
if (trim >= TRIM_MIN && trim <= TRIM_MAX) {
|
||||
int16_t newtrim = trim - inc;
|
||||
if (newtrim < TRIM_MIN) {
|
||||
newtrim = TRIM_MIN;
|
||||
}
|
||||
if (newtrim > TRIM_MAX) {
|
||||
newtrim = TRIM_MAX;
|
||||
}
|
||||
phase->trim[idx] = newtrim;
|
||||
}
|
||||
}
|
||||
int16_t subtrim = g_model.subtrim[idx] + inc;
|
||||
if (subtrim > SUBTRIM_MAX)
|
||||
subtrim = SUBTRIM_MAX;
|
||||
if (subtrim < SUBTRIM_MIN)
|
||||
subtrim = SUBTRIM_MIN;
|
||||
g_model.subtrim[idx] = subtrim;
|
||||
}
|
||||
|
||||
uint8_t checkTrim(uint8_t event)
|
||||
{
|
||||
int8_t k = (event & EVT_KEY_MASK) - TRM_BASE;
|
||||
@@ -708,38 +689,33 @@ uint8_t checkTrim(uint8_t event)
|
||||
//LH_DWN LH_UP LV_DWN LV_UP RV_DWN RV_UP RH_DWN RH_UP
|
||||
uint8_t idx = k/2;
|
||||
uint8_t phase = getTrimFlightPhase(idx);
|
||||
int8_t t = g_model.phaseData[phase].trim[idx];
|
||||
int16_t before = g_model.subtrim[idx] + t;
|
||||
int16_t before = getTrimValue(phase, idx);
|
||||
int8_t v = (s==0) ? min(32, abs(before)/4+1) : 1 << (s-1); // 1=>1 2=>2 3=>4 4=>8
|
||||
bool thro = (((2-(g_eeGeneral.stickMode&1)) == idx) && g_model.thrTrim);
|
||||
if (thro) v = 4; // if throttle trim and trim trottle then step=4
|
||||
int16_t trim = (k&1) ? t + v : t - v; // positive = k&1
|
||||
int16_t after = g_model.subtrim[idx] + trim;
|
||||
int16_t after = (k&1) ? before + v : before - v; // positive = k&1
|
||||
|
||||
bool beepTrim = false;
|
||||
for (int8_t mark=TRIM_MIN; mark!=-6; mark+=TRIM_MAX) { // because (int8_t)125+125==-6
|
||||
for (int16_t mark=TRIM_MIN; mark<=TRIM_MAX; mark+=TRIM_MAX) {
|
||||
if ((mark!=0 || !thro) && ((mark!=TRIM_MIN && after>=mark && before<mark) || (mark!=TRIM_MAX && after<=mark && before>mark))) {
|
||||
trim = mark - g_model.subtrim[idx];
|
||||
after = mark;
|
||||
beepTrim = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((before<after && after>TRIM_MAX) || (before>after && after<TRIM_MIN)) {
|
||||
if (!g_model.extendedTrims) trim = t;
|
||||
if (!g_model.extendedTrims) after = before;
|
||||
beepTrim = true; // no repetition, it could be dangerous
|
||||
}
|
||||
|
||||
if (trim < TRIM_MIN) {
|
||||
incSubtrim(idx, trim-TRIM_MIN);
|
||||
trim = TRIM_MIN;
|
||||
if (after < TRIM_EXTENDED_MIN) {
|
||||
after = TRIM_EXTENDED_MIN;
|
||||
}
|
||||
else if (trim > TRIM_MAX) {
|
||||
incSubtrim(idx, trim-TRIM_MAX);
|
||||
trim = TRIM_MAX;
|
||||
if (after > TRIM_EXTENDED_MAX) {
|
||||
after = TRIM_EXTENDED_MAX;
|
||||
}
|
||||
|
||||
g_model.phaseData[phase].trim[idx] = (int8_t)trim;
|
||||
STORE_MODELVARS;
|
||||
setTrimValue(phase, idx, after);
|
||||
|
||||
#if defined (BEEPSPKR)
|
||||
// toneFreq higher/lower according to trim position
|
||||
@@ -1147,7 +1123,7 @@ inline void evalTrims()
|
||||
// do trim -> throttle trim if applicable
|
||||
int16_t v = anas[i];
|
||||
int32_t vv = 2*RESX;
|
||||
int16_t trim = g_model.subtrim[i] + g_model.phaseData[getTrimFlightPhase(i)].trim[i];
|
||||
int16_t trim = getTrimValue(getTrimFlightPhase(i), i);
|
||||
if (IS_THROTTLE(i) && g_model.thrTrim) {
|
||||
vv = (g_eeGeneral.throttleReversed) ?
|
||||
((int32_t)trim+TRIM_MIN)*(RESX+v)/(2*RESX) :
|
||||
@@ -2060,17 +2036,14 @@ void instantTrim()
|
||||
evalSticks();
|
||||
s_noStickInputs = false;
|
||||
int16_t trim = (anas[i] + trims[i]) / 2;
|
||||
trim -= g_model.subtrim[i];
|
||||
// printf("anas[%d]=%d, trims[%d]=%d, trim=%d, subtrim=%d => trim=%d\n", i, anas[i], i, trims[i], g_model.phaseData[phase].trim[i], g_model.subtrim[i], trim);
|
||||
if (trim < TRIM_MIN) {
|
||||
incSubtrim(i, trim-TRIM_MIN);
|
||||
trim = TRIM_MIN;
|
||||
if (trim < TRIM_EXTENDED_MIN) {
|
||||
trim = TRIM_EXTENDED_MIN;
|
||||
}
|
||||
if (trim > TRIM_MAX) {
|
||||
incSubtrim(i, trim-TRIM_MAX);
|
||||
trim = TRIM_MAX;
|
||||
if (trim > TRIM_EXTENDED_MAX) {
|
||||
trim = TRIM_EXTENDED_MAX;
|
||||
}
|
||||
g_model.phaseData[phase].trim[i] = (int8_t)trim;
|
||||
setTrimValue(phase, i, trim);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2092,11 +2065,10 @@ void moveTrimsToOffsets() // copy state of 3 primary to subtrim
|
||||
// reset all trims, except throttle
|
||||
for (uint8_t i=0; i<4; i++) {
|
||||
if (!IS_THROTTLE(i)) {
|
||||
g_model.subtrim[i] = 0;
|
||||
for (uint8_t phase=0; phase<MAX_PHASES; phase++) {
|
||||
int8_t trim = g_model.phaseData[phase].trim[i];
|
||||
if (trim >= TRIM_MIN && trim <= TRIM_MAX)
|
||||
g_model.phaseData[phase].trim[i] = 0;
|
||||
int16_t trim = getTrimValue(phase, i);
|
||||
if (trim <= TRIM_EXTENDED_MAX)
|
||||
setTrimValue(phase, i, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,6 +495,8 @@ bool getSwitch(int8_t swtch, bool nc, uint8_t level=0);
|
||||
|
||||
uint8_t getFlightPhase();
|
||||
uint8_t getTrimFlightPhase(uint8_t idx, int8_t phase=-1);
|
||||
extern int16_t getTrimValue(uint8_t phase, uint8_t idx);
|
||||
extern void setTrimValue(uint8_t phase, uint8_t idx, int16_t trim);
|
||||
|
||||
extern uint16_t s_timeCumTot;
|
||||
extern uint16_t s_timeCumAbs; //laufzeit in 1/16 sec
|
||||
|
||||
+12
-32
@@ -27,51 +27,31 @@ uint16_t anaIn(uint8_t chan)
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(incSubtrim, test1) {
|
||||
memset(&g_model, 0, sizeof(g_model));
|
||||
incSubtrim(0, 10);
|
||||
for (int p=0; p<MAX_PHASES; p++) {
|
||||
PhaseData *phase = phaseaddress(p);
|
||||
EXPECT_EQ(phase->trim[0], -10) << "Should be equal to -10";
|
||||
}
|
||||
EXPECT_EQ(g_model.subtrim[0], 10) << "Should be equal to 10";
|
||||
}
|
||||
|
||||
TEST(incSubtrim, test2) {
|
||||
memset(&g_model, 0, sizeof(g_model));
|
||||
phaseaddress(0)->trim[0] = -120;
|
||||
phaseaddress(1)->trim[0] = +125;
|
||||
incSubtrim(0, +10); // FP1 is trimmed by +10
|
||||
EXPECT_EQ(phaseaddress(0)->trim[0], TRIM_MIN);
|
||||
EXPECT_EQ(phaseaddress(1)->trim[0], +115); // and set to 125 just after
|
||||
EXPECT_EQ(g_model.subtrim[0], 10);
|
||||
}
|
||||
|
||||
TEST(trims, greaterTrimLink)
|
||||
{
|
||||
memset(&g_model, 0, sizeof(g_model));
|
||||
phaseaddress(1)->trim[0] = -127; // link to FP3 trim
|
||||
phaseaddress(3)->trim[0] = 32;
|
||||
EXPECT_EQ(phaseaddress(getTrimFlightPhase(0, 1))->trim[0], 32);
|
||||
setTrimValue(1, 0, TRIM_EXTENDED_MAX+3); // link to FP3 trim
|
||||
setTrimValue(3, 0, 32);
|
||||
EXPECT_EQ(getTrimValue(getTrimFlightPhase(0, 1), 0), 32);
|
||||
}
|
||||
|
||||
TEST(trims, chainedTrims)
|
||||
{
|
||||
memset(&g_model, 0, sizeof(g_model));
|
||||
phaseaddress(0)->trim[0] = 32;
|
||||
phaseaddress(1)->trim[0] = +127; // link to FP0 trim
|
||||
phaseaddress(2)->trim[0] = -128; // link to FP1 trim
|
||||
EXPECT_EQ(phaseaddress(getTrimFlightPhase(0, 2))->trim[0], 32);
|
||||
setTrimValue(0, 0, 32);
|
||||
setTrimValue(1, 0, TRIM_EXTENDED_MAX+1); // link to FP0 trim
|
||||
setTrimValue(2, 0, TRIM_EXTENDED_MAX+2); // link to FP1 trim
|
||||
EXPECT_EQ(getTrimValue(getTrimFlightPhase(0, 2), 0), 32);
|
||||
}
|
||||
|
||||
TEST(trims, infiniteChainedTrims)
|
||||
{
|
||||
memset(&g_model, 0, sizeof(g_model));
|
||||
phaseaddress(0)->trim[0] = 32;
|
||||
phaseaddress(1)->trim[0] = -127; // link to FP3 trim
|
||||
phaseaddress(2)->trim[0] = -128; // link to FP1 trim
|
||||
phaseaddress(3)->trim[0] = -127; // link to FP2 trim
|
||||
EXPECT_EQ(phaseaddress(getTrimFlightPhase(0, 2))->trim[0], 32);
|
||||
setTrimValue(0, 0, 32);
|
||||
setTrimValue(1, 0, TRIM_EXTENDED_MAX+3); // link to FP3 trim
|
||||
setTrimValue(2, 0, TRIM_EXTENDED_MAX+2); // link to FP1 trim
|
||||
setTrimValue(3, 0, TRIM_EXTENDED_MAX+3); // link to FP2 trim
|
||||
EXPECT_EQ(getTrimValue(getTrimFlightPhase(0, 2), 0), 32);
|
||||
}
|
||||
|
||||
TEST(outdezNAtt, test_unsigned) {
|
||||
|
||||
+1
-1
@@ -188,7 +188,7 @@ void menuMainView(uint8_t event)
|
||||
xm = x[i];
|
||||
|
||||
uint8_t att = 0;
|
||||
int16_t val = g_model.subtrim[i] + phaseaddress(getTrimFlightPhase(i, phase))->trim[i];
|
||||
int16_t val = getTrimValue(getTrimFlightPhase(i, phase), i);;
|
||||
|
||||
if (val < -125 || val > 125)
|
||||
att = BLINK;
|
||||
|
||||
+21
-22
@@ -442,7 +442,7 @@ void menuProcPhaseOne(uint8_t event)
|
||||
// TODO if last MENU/SUBMENU numbers are 0 they may be skipped
|
||||
|
||||
int8_t sub = m_posVert;
|
||||
PhaseData *p = phaseaddress(s_currIdx);
|
||||
PhaseData *phase = phaseaddress(s_currIdx);
|
||||
|
||||
putsFlightPhase(18*FW, 0, s_currIdx+1, 0);
|
||||
|
||||
@@ -452,45 +452,44 @@ void menuProcPhaseOne(uint8_t event)
|
||||
switch(i) {
|
||||
case 0:
|
||||
lcd_puts_P(0, y, PSTR("Name"));
|
||||
EditName(10*FW, y, p->name, sizeof(p->name), event, attr, m_posHorz);
|
||||
EditName(10*FW, y, phase->name, sizeof(phase->name), event, attr, m_posHorz);
|
||||
break;
|
||||
case 1:
|
||||
lcd_puts_P(0, y, PSTR("Switch"));
|
||||
putsSwitches(10*FW, y, p->swtch, attr);
|
||||
if(attr) CHECK_INCDEC_MODELVAR(event, p->swtch, -MAX_DRSWITCH, MAX_DRSWITCH);
|
||||
putsSwitches(10*FW, y, phase->swtch, attr);
|
||||
if(attr) CHECK_INCDEC_MODELVAR(event, phase->swtch, -MAX_DRSWITCH, MAX_DRSWITCH);
|
||||
break;
|
||||
case 2:
|
||||
lcd_puts_P(0, y, PSTR("Trims"));
|
||||
for (uint8_t t=0; t<NUM_STICKS; t++) {
|
||||
int16_t v = p->trim[t];
|
||||
if (v > 125) v = -129;
|
||||
if (v < -125) {
|
||||
uint8_t c = v < 0 ? 129 + v : 0;
|
||||
if (c >= s_currIdx) c++;
|
||||
lcd_putcAtt((10+t)*FW, y, '0'+c, (attr && m_posHorz==t) ? (s_editMode ? BLINK : INVERS) : 0);
|
||||
int16_t v = getTrimValue(s_currIdx, t);
|
||||
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);
|
||||
}
|
||||
else {
|
||||
v = -130;
|
||||
v = TRIM_EXTENDED_MAX;
|
||||
putsChnLetter((10+t)*FW, y, t+1, (attr && m_posHorz==t) ? (s_editMode ? BLINK : INVERS) : 0);
|
||||
}
|
||||
if (attr && m_posHorz==t && (s_editMode || p1valdiff)) {
|
||||
v = checkIncDec(event, v, -130, -126, EE_MODEL);
|
||||
v = checkIncDec(event, v, TRIM_EXTENDED_MAX, TRIM_EXTENDED_MAX+MAX_PHASES-1, EE_MODEL);
|
||||
if (checkIncDec_Ret) {
|
||||
if (v == -130) v = 0;
|
||||
p->trim[t] = (int8_t)v;
|
||||
if (v == TRIM_EXTENDED_MAX) v = 0;
|
||||
setTrimValue(s_currIdx, t, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
lcd_puts_P(0, y, PSTR("Fade In"));
|
||||
lcd_outdezAtt(10*FW, y, p->fadeIn, attr|LEFT);
|
||||
if(attr) CHECK_INCDEC_MODELVAR(event, p->fadeIn, 0, 15);
|
||||
lcd_outdezAtt(10*FW, y, phase->fadeIn, attr|LEFT);
|
||||
if(attr) CHECK_INCDEC_MODELVAR(event, phase->fadeIn, 0, 15);
|
||||
break;
|
||||
case 4:
|
||||
lcd_puts_P(0, y, PSTR("Fade Out"));
|
||||
lcd_outdezAtt(10*FW, y, p->fadeOut, attr|LEFT);
|
||||
if(attr) CHECK_INCDEC_MODELVAR(event, p->fadeOut, 0, 15);
|
||||
lcd_outdezAtt(10*FW, y, phase->fadeOut, attr|LEFT);
|
||||
if(attr) CHECK_INCDEC_MODELVAR(event, phase->fadeOut, 0, 15);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -529,10 +528,10 @@ void menuProcPhasesAll(uint8_t event)
|
||||
else {
|
||||
putsSwitches(11*FW+FW/2, y, p->swtch, 0);
|
||||
for (uint8_t t=0; t<NUM_STICKS; t++) {
|
||||
int16_t v = p->trim[t];
|
||||
if (v > 125) v = -129;
|
||||
if (v < -125) {
|
||||
uint8_t c = v < 0 ? 129 + v : 0;
|
||||
// TODO duplicated code
|
||||
int16_t v = getTrimValue(i, t);
|
||||
if (v > TRIM_EXTENDED_MAX) {
|
||||
uint8_t c = v - TRIM_EXTENDED_MAX - 1;
|
||||
if (c >= i) c++;
|
||||
lcd_putc((16+t)*FW-FW/2, y, '0'+c);
|
||||
}
|
||||
|
||||
+3
-3
@@ -193,9 +193,12 @@ typedef struct t_SwashRingData { // Swash Ring data
|
||||
} __attribute__((packed)) SwashRingData;
|
||||
|
||||
typedef struct t_PhaseData {
|
||||
#define TRIM_EXTENDED_MAX 500
|
||||
#define TRIM_EXTENDED_MIN (-TRIM_EXTENDED_MAX)
|
||||
#define TRIM_MAX 125
|
||||
#define TRIM_MIN (-TRIM_MAX)
|
||||
int8_t trim[4]; // -125..125 => trim value, 127 => use trim of phase 0, -128, -127, -126 => use trim of phases 1|2|3|4 instead
|
||||
int8_t trim_ext:8;
|
||||
int8_t swtch; // swtch of phase[0] is not used
|
||||
char name[6];
|
||||
uint8_t fadeIn:4;
|
||||
@@ -246,9 +249,6 @@ typedef struct t_ModelData {
|
||||
FuncSwData funcSw[NUM_FSW];
|
||||
SwashRingData swashR;
|
||||
PhaseData phaseData[MAX_PHASES];
|
||||
#define SUBTRIM_MAX (1024-TRIM_MAX)
|
||||
#define SUBTRIM_MIN (-SUBTRIM_MAX)
|
||||
int16_t subtrim[NUM_STICKS];
|
||||
FrSkyData frsky;
|
||||
} __attribute__((packed)) ModelData;
|
||||
|
||||
|
||||
+3
-2
@@ -186,13 +186,14 @@ uint8_t Translate()
|
||||
g_model.frsky.channels[i].barMax = 0;
|
||||
}
|
||||
}
|
||||
memset(&g_model.phaseData[0], 0, sizeof(g_model.phaseData) + sizeof(g_model.subtrim));
|
||||
memset(&g_model.phaseData[0], 0, sizeof(g_model.phaseData));
|
||||
memset(&g_model.funcSw[0], 0, sizeof(g_model.funcSw));
|
||||
if (trimSw) {
|
||||
g_model.funcSw[0].swtch = trimSw;
|
||||
g_model.funcSw[0].func = FUNC_INSTANT_TRIM;
|
||||
}
|
||||
memcpy(&g_model.phaseData[0].trim[0], &trims[0], 4);
|
||||
for (uint8_t i=0; i<NUM_STICKS; i++)
|
||||
setTrimValue(0, i, trims[i]);
|
||||
theFile.writeRlc(FILE_MODEL(id), FILE_TYP_MODEL, (uint8_t*)&g_model, sizeof(g_model), true);
|
||||
}
|
||||
}
|
||||
|
||||
+21
@@ -1,3 +1,24 @@
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, 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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user