diff --git a/companion/src/firmwares/opentx/opentxGruvin9xsimulator.cpp b/companion/src/firmwares/opentx/opentxGruvin9xsimulator.cpp index de6feeb74..0da2fe515 100644 --- a/companion/src/firmwares/opentx/opentxGruvin9xsimulator.cpp +++ b/companion/src/firmwares/opentx/opentxGruvin9xsimulator.cpp @@ -61,6 +61,7 @@ namespace Open9xGruvin9x { #include "radio/src/eeprom_common.cpp" #include "radio/src/eeprom_rlc.cpp" #include "radio/src/opentx.cpp" +#include "radio/src/switches.cpp" #include "radio/src/protocols/pulses_avr.cpp" #include "radio/src/stamp.cpp" #include "radio/src/maths.cpp" diff --git a/companion/src/firmwares/opentx/opentxM128simulator.cpp b/companion/src/firmwares/opentx/opentxM128simulator.cpp index 5bb512116..30b5b1352 100644 --- a/companion/src/firmwares/opentx/opentxM128simulator.cpp +++ b/companion/src/firmwares/opentx/opentxM128simulator.cpp @@ -60,6 +60,7 @@ namespace Open9xM128 { #include "radio/src/eeprom_common.cpp" #include "radio/src/eeprom_rlc.cpp" #include "radio/src/opentx.cpp" +#include "radio/src/switches.cpp" #include "radio/src/protocols/pulses_avr.cpp" #include "radio/src/stamp.cpp" #include "radio/src/maths.cpp" diff --git a/companion/src/firmwares/opentx/opentxSky9xsimulator.cpp b/companion/src/firmwares/opentx/opentxSky9xsimulator.cpp index e6632c8ee..c18c7adcc 100644 --- a/companion/src/firmwares/opentx/opentxSky9xsimulator.cpp +++ b/companion/src/firmwares/opentx/opentxSky9xsimulator.cpp @@ -75,6 +75,7 @@ namespace Open9xSky9x { #include "radio/src/eeprom_raw.cpp" #include "radio/src/eeprom_conversions.cpp" #include "radio/src/opentx.cpp" +#include "radio/src/switches.cpp" #include "radio/src/targets/sky9x/pulses_driver.cpp" #include "radio/src/protocols/pulses_arm.cpp" #include "radio/src/stamp.cpp" diff --git a/companion/src/firmwares/opentx/opentxTaranisSimulator.cpp b/companion/src/firmwares/opentx/opentxTaranisSimulator.cpp index 19cc53057..5c4474b07 100644 --- a/companion/src/firmwares/opentx/opentxTaranisSimulator.cpp +++ b/companion/src/firmwares/opentx/opentxTaranisSimulator.cpp @@ -78,6 +78,7 @@ inline int geteepromsize() { #include "radio/src/eeprom_conversions.cpp" #include "radio/src/eeprom_rlc.cpp" #include "radio/src/opentx.cpp" +#include "radio/src/switches.cpp" #include "radio/src/targets/taranis/pulses_driver.cpp" #include "radio/src/targets/taranis/rtc_driver.cpp" #include "radio/src/targets/taranis/trainer_driver.cpp" diff --git a/companion/src/firmwares/opentx/opentxsimulator.cpp b/companion/src/firmwares/opentx/opentxsimulator.cpp index b9d487a96..d20ba68f1 100644 --- a/companion/src/firmwares/opentx/opentxsimulator.cpp +++ b/companion/src/firmwares/opentx/opentxsimulator.cpp @@ -66,6 +66,7 @@ namespace Open9x { #include "radio/src/eeprom_common.cpp" #include "radio/src/eeprom_rlc.cpp" #include "radio/src/opentx.cpp" +#include "radio/src/switches.cpp" #include "radio/src/protocols/pulses_avr.cpp" #include "radio/src/stamp.cpp" #include "radio/src/maths.cpp" diff --git a/radio/src/Makefile b/radio/src/Makefile index 235573ac7..945329b88 100644 --- a/radio/src/Makefile +++ b/radio/src/Makefile @@ -759,7 +759,7 @@ else TTS_SRC = $(shell sh -c "if test -f $(STD_TTS_SRC); then echo $(STD_TTS_SRC); else echo translations/tts_en.cpp; fi") endif -CPPSRC += opentx.cpp $(PULSESSRC) stamp.cpp gui/menus.cpp gui/menu_model.cpp gui/menu_general.cpp gui/view_main.cpp gui/view_statistics.cpp $(EEPROMSRC) lcd.cpp keys.cpp maths.cpp translations.cpp fonts.cpp $(TTS_SRC) +CPPSRC += opentx.cpp $(PULSESSRC) switches.cpp stamp.cpp gui/menus.cpp gui/menu_model.cpp gui/menu_general.cpp gui/view_main.cpp gui/view_statistics.cpp $(EEPROMSRC) lcd.cpp keys.cpp maths.cpp translations.cpp fonts.cpp $(TTS_SRC) # Debugging format. # Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs. diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 546585f04..04b7c78db 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -1348,425 +1348,6 @@ getvalue_t getValue(uint8_t i) else return 0; } -#if defined(CPUARM) - #define GETSWITCH_RECURSIVE_TYPE uint32_t -#else - #define GETSWITCH_RECURSIVE_TYPE uint16_t -#endif - -volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_used = 0; -volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_value = 0; - -#if defined(CPUARM) -uint32_t cswDelays[NUM_LOGICAL_SWITCH]; -uint32_t cswDurations[NUM_LOGICAL_SWITCH]; -uint8_t cswStates[NUM_LOGICAL_SWITCH]; -#endif - -#if defined(PCBTARANIS) -tmr10ms_t switchesMidposStart[6] = { 0 }; -uint32_t switchesPos = 0; -tmr10ms_t potsLastposStart[NUM_XPOTS]; -uint8_t potsPos[NUM_XPOTS]; - -uint32_t check2PosSwitchPosition(EnumKeys sw) -{ - uint32_t result; - uint32_t index; - - if (switchState(sw)) - index = sw - SW_SA0; - else - index = sw - SW_SA0 + 1; - - result = (1 << index); - - if (!(switchesPos & result)) { - PLAY_SWITCH_MOVED(index); - } - - return result; -} - -#define DELAY_SWITCH_3POS 15/*150ms*/ -uint32_t check3PosSwitchPosition(uint8_t idx, EnumKeys sw, bool startup) -{ - uint32_t result; - uint32_t index; - - if (switchState(sw)) { - index = sw - SW_SA0; - result = (1 << index); - switchesMidposStart[idx] = 0; - } - else if (switchState(EnumKeys(sw+2))) { - index = sw - SW_SA0 + 2; - result = (1 << index); - switchesMidposStart[idx] = 0; - } - else if (startup || (switchesPos & (1 << (sw - SW_SA0 + 1))) || (switchesMidposStart[idx] && (tmr10ms_t)(get_tmr10ms() - switchesMidposStart[idx]) > DELAY_SWITCH_3POS)) { - index = sw - SW_SA0 + 1; - result = (1 << index); - switchesMidposStart[idx] = 0; - } - else { - index = sw - SW_SA0 + 1; - if (!switchesMidposStart[idx]) { - switchesMidposStart[idx] = get_tmr10ms(); - } - result = (switchesPos & (0x7 << (sw - SW_SA0))); - } - - if (!(switchesPos & result)) { - PLAY_SWITCH_MOVED(index); - } - - return result; -} - -#define CHECK_2POS(sw) newPos |= check2PosSwitchPosition(sw ## 0) -#define CHECK_3POS(idx, sw) newPos |= check3PosSwitchPosition(idx, sw ## 0, startup) - -void getSwitchesPosition(bool startup) -{ - uint32_t newPos = 0; - CHECK_3POS(0, SW_SA); - CHECK_3POS(1, SW_SB); - CHECK_3POS(2, SW_SC); - CHECK_3POS(3, SW_SD); - CHECK_3POS(4, SW_SE); - CHECK_2POS(SW_SF); - CHECK_3POS(5, SW_SG); - CHECK_2POS(SW_SH); - switchesPos = newPos; - - for (int i=0; icount>0 && calib->countcount); - uint8_t previousPos = potsPos[i] >> 4; - uint8_t previousStoredPos = potsPos[i] & 0x0F; - if (pos != previousPos) { - potsLastposStart[i] = get_tmr10ms(); - potsPos[i] = (pos << 4) | previousStoredPos; - } - else if (startup || (tmr10ms_t)(get_tmr10ms() - potsLastposStart[i]) > DELAY_SWITCH_3POS) { - potsLastposStart[i] = 0; - potsPos[i] = (pos << 4) | pos; - if (previousStoredPos != pos) { - PLAY_SWITCH_MOVED(SWSRC_LAST_SWITCH+i*XPOTS_MULTIPOS_COUNT+pos); - } - } - } - } - } -} -#define SWITCH_POSITION(sw) (switchesPos & (1<<(sw))) -#define POT_POSITION(sw) ((potsPos[(sw)/XPOTS_MULTIPOS_COUNT] & 0x0f) == ((sw) % XPOTS_MULTIPOS_COUNT)) -#else -#define getSwitchesPosition(...) -#define SWITCH_POSITION(idx) switchState((EnumKeys)(SW_BASE+(idx))) -#endif - -int16_t csLastValue[NUM_LOGICAL_SWITCH]; -#define CS_LAST_VALUE_INIT -32768 - -/* recursive function. stack as of today (16/03/2012) grows by 8bytes at each call, which is ok! */ -bool getSwitch(int8_t swtch) -{ - bool result; - - if (swtch == SWSRC_NONE) - return true; - - uint8_t cs_idx = abs(swtch); - - if (cs_idx == SWSRC_ON) { - result = true; - } - else if (cs_idx <= SWSRC_LAST_SWITCH) { - result = SWITCH_POSITION(cs_idx-SWSRC_FIRST_SWITCH); -#if defined(MODULE_ALWAYS_SEND_PULSES) - if (startupWarningState < STARTUP_WARNING_DONE) { - // if throttle or switch warning is currently active, ignore actual stick position and use wanted values - if (cs_idx <= 3) { - if (!(g_model.nSwToWarn&1)) { // ID1 to ID3 is just one bit in nSwToWarn - result = (cs_idx)==((g_model.switchWarningStates&3)+1); // overwrite result with desired value - } - } - else if (!(g_model.nSwToWarn & (1<<(cs_idx-3)))) { - // current switch should not be ignored for warning - result = g_model.switchWarningStates & (1<<(cs_idx-2)); // overwrite result with desired value - } - } -#endif - } -#if defined(PCBTARANIS) - else if (cs_idx <= SWSRC_LAST_MULTIPOS_SWITCH) { - result = POT_POSITION(cs_idx-SWSRC_FIRST_MULTIPOS_SWITCH); - } -#endif - else if (cs_idx <= SWSRC_LAST_TRIM) { - uint8_t idx = cs_idx - SWSRC_FIRST_TRIM; - idx = (CONVERT_MODE(idx/2) << 1) + (idx & 1); - result = trimDown(idx); - } -#if ROTARY_ENCODERS > 0 - else if (cs_idx == SWSRC_REa) { - result = REA_DOWN(); - } -#endif -#if ROTARY_ENCODERS > 1 - else if (cs_idx == SWSRC_REb) { - result = REB_DOWN(); - } -#endif -#if defined(CPUARM) && defined(FLIGHT_MODES) - else if (cs_idx >= SWSRC_FIRST_FLIGHT_MODE) { - uint8_t idx = cs_idx - SWSRC_FIRST_FLIGHT_MODE; - result = (idx == s_perout_flight_mode); - } -#endif - else { - cs_idx -= SWSRC_FIRST_LOGICAL_SWITCH; - - GETSWITCH_RECURSIVE_TYPE mask = ((GETSWITCH_RECURSIVE_TYPE)1 << cs_idx); - if (s_last_switch_used & mask) { - result = (s_last_switch_value & mask); - } - else { - s_last_switch_used |= mask; - - LogicalSwitchData * cs = cswAddress(cs_idx); -#if defined(CPUARM) - int8_t s = cs->andsw; -#else - uint8_t s = cs->andsw; - if (s > SWSRC_LAST_SWITCH) { - s += SWSRC_SW1-SWSRC_LAST_SWITCH-1; - } -#endif - if (cs->func == LS_FUNC_NONE || (s && !getSwitch(s))) { - csLastValue[cs_idx] = CS_LAST_VALUE_INIT; - result = false; - } - else if ((s=cswFamily(cs->func)) == LS_FAMILY_BOOL) { - bool res1 = getSwitch(cs->v1); - bool res2 = getSwitch(cs->v2); - switch (cs->func) { - case LS_FUNC_AND: - result = (res1 && res2); - break; - case LS_FUNC_OR: - result = (res1 || res2); - break; - // case LS_FUNC_XOR: - default: - result = (res1 ^ res2); - break; - } - } - else if (s == LS_FAMILY_TIMER) { - result = (csLastValue[cs_idx] <= 0); - } - else if (s == LS_FAMILY_STICKY) { - result = (csLastValue[cs_idx] & (1<<0)); - } -#if defined(CPUARM) - else if (s == LS_FAMILY_STAY) { - result = (csLastValue[cs_idx] & (1<<0)); - } -#endif - else { - getvalue_t x = getValue(cs->v1); - getvalue_t y; - if (s == LS_FAMILY_COMP) { - y = getValue(cs->v2); - - switch (cs->func) { - case LS_FUNC_EQUAL: - result = (x==y); - break; - case LS_FUNC_GREATER: - result = (x>y); - break; - default: - result = (xv1; -#if defined(FRSKY) - // Telemetry - if (v1 >= MIXSRC_FIRST_TELEM) { - if ((!TELEMETRY_STREAMING() && v1 >= MIXSRC_FIRST_TELEM+TELEM_FIRST_STREAMED_VALUE-1) || IS_FAI_FORBIDDEN(v1-1)) - return swtch > 0 ? false : true; - - y = convertCswTelemValue(cs); - -#if defined(FRSKY_HUB) && defined(GAUGES) - if (s == LS_FAMILY_OFS) { - uint8_t idx = v1-MIXSRC_FIRST_TELEM+1-TELEM_ALT; - if (idx < THLD_MAX) { - // Fill the threshold array - barsThresholds[idx] = 128 + cs->v2; - } - } -#endif - } - else if (v1 >= MIXSRC_GVAR1) { - y = cs->v2; - } - else { - y = calc100toRESX(cs->v2); - } -#else - if (v1 >= MIXSRC_FIRST_TELEM) { - y = (int16_t)3 * (128+cs->v2); // it's a Timer - } - else if (v1 >= MIXSRC_GVAR1) { - y = cs->v2; // it's a GVAR - } - else { - y = calc100toRESX(cs->v2); - } -#endif - - switch (cs->func) { -#if defined(CPUARM) - case LS_FUNC_VEQUAL: - result = (x==y); - break; -#endif - case LS_FUNC_VALMOSTEQUAL: -#if defined(GVARS) - if (v1 >= MIXSRC_GVAR1 && v1 <= MIXSRC_LAST_GVAR) - result = (x==y); - else -#endif - result = (abs(x-y) < (1024 / STICK_TOLERANCE)); - break; - case LS_FUNC_VPOS: - result = (x>y); - break; - case LS_FUNC_VNEG: - result = (xy); - break; - case LS_FUNC_ANEG: - result = (abs(x)func == LS_FUNC_DIFFEGREATER) - result = (y >= 0 ? (diff >= y) : (diff <= y)); - else - result = (abs(diff) >= y); - if (result) - csLastValue[cs_idx] = x; - break; - } - } - } - } - -#if defined(CPUARM) - if (cs->delay) { - if (result) { - if (cswDelays[cs_idx] > get_tmr10ms()) - result = false; - } - else { - cswDelays[cs_idx] = get_tmr10ms() + (cs->delay*10); - } - } - - if (cs->duration) { - if (result && !cswStates[cs_idx]) { - cswDurations[cs_idx] = get_tmr10ms() + (cs->duration*10); - } - - cswStates[cs_idx] = result; - result = false; - - if (cswDurations[cs_idx] > get_tmr10ms()) { - result = true; - } - } -#endif - - if (result) { - if (!(s_last_switch_value&mask)) PLAY_LOGICAL_SWITCH_ON(cs_idx); - s_last_switch_value |= mask; - } - else { - if (s_last_switch_value&mask) PLAY_LOGICAL_SWITCH_OFF(cs_idx); - s_last_switch_value &= ~mask; - } - } - } - - return swtch > 0 ? result : !result; -} - -swstate_t switches_states = 0; -int8_t getMovedSwitch() -{ - static tmr10ms_t s_move_last_time = 0; - int8_t result = 0; - -#if defined(PCBTARANIS) - for (uint8_t i=0; i> (i*2); - uint8_t next = (1024+getValue(MIXSRC_SA+i)) / 1024; - if (prev != next) { - switches_states = (switches_states & (~mask)) | (next << (i*2)); - if (i<5) - result = 1+(3*i)+next; - else if (i==5) - result = 1+(3*5)+(next!=0); - else if (i==6) - result = 1+(3*5)+2+next; - else - result = 1+(3*5)+2+3+(next!=0); - } - } -#else - // return delivers 1 to 3 for ID1 to ID3 - // 4..8 for all other switches if changed to true - // -4..-8 for all other switches if changed to false - // 9 for Trainer switch if changed to true; Change to false is ignored - swstate_t mask = 0x80; - for (uint8_t i=NUM_PSWITCH; i>1; i--) { - bool prev; - prev = (switches_states & mask); - // don't use getSwitch here to always get the proper value, even getSwitch manipulates - bool next = switchState((EnumKeys)(SW_BASE+i-1)); - if (prev != next) { - if (((i3)) || next==true) - result = next ? i : -i; - if (i<=3 && result==0) result = 1; - switches_states ^= mask; - } - mask >>= 1; - } -#endif - - if ((tmr10ms_t)(get_tmr10ms() - s_move_last_time) > 10) - result = 0; - - s_move_last_time = get_tmr10ms(); - return result; -} - #if defined(AUTOSOURCE) int8_t getMovedSource(GET_MOVED_SOURCE_PARAMS) { @@ -1886,7 +1467,7 @@ void setTrimValue(uint8_t phase, uint8_t idx, int trim) #elif defined(PCBSTD) PhaseData *p = phaseAddress(phase); p->trim[idx] = (int8_t)(trim >> 2); - idx <<= 1; + idx <<= 1; p->trim_ext = (p->trim_ext & ~(0x03 << idx)) + (((trim & 0x03) << idx)); #else PhaseData *p = phaseAddress(phase); @@ -2433,9 +2014,9 @@ void checkTHR() } else { calibratedStick[thrchn] = -1024; -#if !defined(PCBTARANIS) +#if !defined(PCBTARANIS) rawAnas[thrchn] = anas[thrchn] = calibratedStick[thrchn]; -#endif +#endif MESSAGE(STR_THROTTLEWARN, STR_THROTTLENOTIDLE, STR_PRESSANYKEYTOSKIP, AU_THROTTLE_ALERT); } #else @@ -2443,26 +2024,26 @@ void checkTHR() getADC(); evalInputs(e_perout_mode_notrainer); // let do evalInputs do the job - int16_t v = calibratedStick[thrchn]; + int16_t v = calibratedStick[thrchn]; if (v<=(THRCHK_DEADBAND-1024)) return; // prevent warning if throttle input OK // first - display warning; also deletes inputs if any have been before - MESSAGE(STR_THROTTLEWARN, STR_THROTTLENOTIDLE, STR_PRESSANYKEYTOSKIP, AU_THROTTLE_ALERT); - + MESSAGE(STR_THROTTLEWARN, STR_THROTTLENOTIDLE, STR_PRESSANYKEYTOSKIP, AU_THROTTLE_ALERT); + while (1) { - + SIMU_SLEEP(1); getADC(); evalInputs(e_perout_mode_notrainer); // let do evalInputs do the job - v = calibratedStick[thrchn]; + v = calibratedStick[thrchn]; if (pwrCheck()==e_power_off || keyDown() || v<=(THRCHK_DEADBAND-1024)) break; - + checkBacklight(); - + wdt_reset(); } #endif @@ -2470,152 +2051,13 @@ void checkTHR() void checkAlarm() // added by Gohst { - if (g_eeGeneral.disableAlarmWarning) + if (g_eeGeneral.disableAlarmWarning) return; if (IS_SOUND_OFF()) ALERT(STR_ALARMSWARN, STR_ALARMSDISABLED, AU_ERROR); } -void checkSwitches() -{ -#if defined(MODULE_ALWAYS_SEND_PULSES) - static swstate_t last_bad_switches = 0xff; -#else - swstate_t last_bad_switches = 0xff; -#endif - swstate_t states = g_model.switchWarningStates; - -#if defined(PCBTARANIS) - uint8_t bad_pots = 0, last_bad_pots = 0xff; -#endif - -#if !defined(MODULE_ALWAYS_SEND_PULSES) - while (1) { - -#if defined(TELEMETRY_MOD_14051) || defined(PCBTARANIS) - getADC(); -#endif -#endif // !defined(MODULE_ALWAYS_SEND_PULSES) - - getMovedSwitch(); - - bool warn = false; -#if defined(PCBTARANIS) - for (uint8_t i=0; i> 6; - if (potMode) { - perOut(e_perout_mode_normal, 0); - bad_pots = 0; - for (uint8_t i=0; i> 4)) > 1)) { - warn = true; - bad_pots |= (1<> (i*2)]; - lcd_putcAtt(60+i*(2*FW+FW/2), 4*FH+3, 'A'+i, attr); - lcd_putcAtt(60+i*(2*FW+FW/2)+FW, 4*FH+3, c, attr); - } - } - if (potMode) { - for (uint8_t i=0; i> 4)) > 1) { - switch (i) { - case 0: - case 1: - case 2: - lcd_putc(60+i*(5*FW)+2*FW+2, 6*FH-2, g_model.potPosition[i] > (getValue(MIXSRC_FIRST_POT+i) >> 4) ? 126 : 127); - break; - case 3: - case 4: - lcd_putc(60+i*(5*FW)+2*FW+2, 6*FH-2, g_model.potPosition[i] > (getValue(MIXSRC_FIRST_POT+i) >> 4) ? '\300' : '\301'); - break; - } - flags = INVERS; - } - lcd_putsiAtt(60+i*(5*FW), 6*FH-2, STR_VSRCRAW, NUM_STICKS+1+i, flags); - } - } - } - last_bad_pots = bad_pots; -#else - if (last_bad_switches != switches_states) { - MESSAGE(STR_SWITCHWARN, NULL, STR_PRESSANYKEYTOSKIP, last_bad_switches == 0xff ? AU_SWITCH_ALERT : AU_NONE); - uint8_t x = 2; - for (uint8_t i=0; i0?(i+3):(states&0x3)+1), attr); - x += 3*FW+FW/2; - } -#endif - lcdRefresh(); - last_bad_switches = switches_states; - } - -#if defined(MODULE_ALWAYS_SEND_PULSES) - if (pwrCheck()==e_power_off || keyDown()) { - startupWarningState = STARTUP_WARNING_SWITCHES+1; - last_bad_switches = 0xff; - } -#else - if (pwrCheck()==e_power_off || keyDown()) return; - - checkBacklight(); - - wdt_reset(); - - SIMU_SLEEP(1); - } -#endif -} - void alert(const pm_char * t, const pm_char *s MESSAGE_SOUND_ARG) { MESSAGE(t, s, STR_PRESSANYKEY, sound); diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 0a04d46ec..e59ab631f 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -672,7 +672,13 @@ void perMain(); NOINLINE void per10ms(); getvalue_t getValue(uint8_t i); -bool getSwitch(int8_t swtch); +bool getSwitch(int8_t swtch); + +#if defined(PCBTARANIS) + void getSwitchesPosition(bool startup); +#else + #define getSwitchesPosition(...) +#endif extern swstate_t switches_states; int8_t getMovedSwitch(); diff --git a/radio/src/switches.cpp b/radio/src/switches.cpp new file mode 100644 index 000000000..6b6991be2 --- /dev/null +++ b/radio/src/switches.cpp @@ -0,0 +1,594 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx 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 "opentx.h" + +#if defined(CPUARM) + #define GETSWITCH_RECURSIVE_TYPE uint32_t +#else + #define GETSWITCH_RECURSIVE_TYPE uint16_t +#endif + +volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_used = 0; +volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_value = 0; + +#if defined(CPUARM) +uint32_t cswDelays[NUM_LOGICAL_SWITCH]; +uint32_t cswDurations[NUM_LOGICAL_SWITCH]; +uint8_t cswStates[NUM_LOGICAL_SWITCH]; +#endif + +#if defined(PCBTARANIS) +tmr10ms_t switchesMidposStart[6] = { 0 }; +uint32_t switchesPos = 0; +tmr10ms_t potsLastposStart[NUM_XPOTS]; +uint8_t potsPos[NUM_XPOTS]; + +uint32_t check2PosSwitchPosition(EnumKeys sw) +{ + uint32_t result; + uint32_t index; + + if (switchState(sw)) + index = sw - SW_SA0; + else + index = sw - SW_SA0 + 1; + + result = (1 << index); + + if (!(switchesPos & result)) { + PLAY_SWITCH_MOVED(index); + } + + return result; +} + +#define DELAY_SWITCH_3POS 15/*150ms*/ +uint32_t check3PosSwitchPosition(uint8_t idx, EnumKeys sw, bool startup) +{ + uint32_t result; + uint32_t index; + + if (switchState(sw)) { + index = sw - SW_SA0; + result = (1 << index); + switchesMidposStart[idx] = 0; + } + else if (switchState(EnumKeys(sw+2))) { + index = sw - SW_SA0 + 2; + result = (1 << index); + switchesMidposStart[idx] = 0; + } + else if (startup || (switchesPos & (1 << (sw - SW_SA0 + 1))) || (switchesMidposStart[idx] && (tmr10ms_t)(get_tmr10ms() - switchesMidposStart[idx]) > DELAY_SWITCH_3POS)) { + index = sw - SW_SA0 + 1; + result = (1 << index); + switchesMidposStart[idx] = 0; + } + else { + index = sw - SW_SA0 + 1; + if (!switchesMidposStart[idx]) { + switchesMidposStart[idx] = get_tmr10ms(); + } + result = (switchesPos & (0x7 << (sw - SW_SA0))); + } + + if (!(switchesPos & result)) { + PLAY_SWITCH_MOVED(index); + } + + return result; +} + +#define CHECK_2POS(sw) newPos |= check2PosSwitchPosition(sw ## 0) +#define CHECK_3POS(idx, sw) newPos |= check3PosSwitchPosition(idx, sw ## 0, startup) + +void getSwitchesPosition(bool startup) +{ + uint32_t newPos = 0; + CHECK_3POS(0, SW_SA); + CHECK_3POS(1, SW_SB); + CHECK_3POS(2, SW_SC); + CHECK_3POS(3, SW_SD); + CHECK_3POS(4, SW_SE); + CHECK_2POS(SW_SF); + CHECK_3POS(5, SW_SG); + CHECK_2POS(SW_SH); + switchesPos = newPos; + + for (int i=0; icount>0 && calib->countcount); + uint8_t previousPos = potsPos[i] >> 4; + uint8_t previousStoredPos = potsPos[i] & 0x0F; + if (pos != previousPos) { + potsLastposStart[i] = get_tmr10ms(); + potsPos[i] = (pos << 4) | previousStoredPos; + } + else if (startup || (tmr10ms_t)(get_tmr10ms() - potsLastposStart[i]) > DELAY_SWITCH_3POS) { + potsLastposStart[i] = 0; + potsPos[i] = (pos << 4) | pos; + if (previousStoredPos != pos) { + PLAY_SWITCH_MOVED(SWSRC_LAST_SWITCH+i*XPOTS_MULTIPOS_COUNT+pos); + } + } + } + } + } +} +#define SWITCH_POSITION(sw) (switchesPos & (1<<(sw))) +#define POT_POSITION(sw) ((potsPos[(sw)/XPOTS_MULTIPOS_COUNT] & 0x0f) == ((sw) % XPOTS_MULTIPOS_COUNT)) +#else +#define SWITCH_POSITION(idx) switchState((EnumKeys)(SW_BASE+(idx))) +#endif + +int16_t csLastValue[NUM_LOGICAL_SWITCH]; +#define CS_LAST_VALUE_INIT -32768 + +/* recursive function. stack as of today (16/03/2012) grows by 8bytes at each call, which is ok! */ +bool getSwitch(int8_t swtch) +{ + bool result; + + if (swtch == SWSRC_NONE) + return true; + + uint8_t cs_idx = abs(swtch); + + if (cs_idx == SWSRC_ON) { + result = true; + } + else if (cs_idx <= SWSRC_LAST_SWITCH) { + result = SWITCH_POSITION(cs_idx-SWSRC_FIRST_SWITCH); +#if defined(MODULE_ALWAYS_SEND_PULSES) + if (startupWarningState < STARTUP_WARNING_DONE) { + // if throttle or switch warning is currently active, ignore actual stick position and use wanted values + if (cs_idx <= 3) { + if (!(g_model.nSwToWarn&1)) { // ID1 to ID3 is just one bit in nSwToWarn + result = (cs_idx)==((g_model.switchWarningStates&3)+1); // overwrite result with desired value + } + } + else if (!(g_model.nSwToWarn & (1<<(cs_idx-3)))) { + // current switch should not be ignored for warning + result = g_model.switchWarningStates & (1<<(cs_idx-2)); // overwrite result with desired value + } + } +#endif + } +#if defined(PCBTARANIS) + else if (cs_idx <= SWSRC_LAST_MULTIPOS_SWITCH) { + result = POT_POSITION(cs_idx-SWSRC_FIRST_MULTIPOS_SWITCH); + } +#endif + else if (cs_idx <= SWSRC_LAST_TRIM) { + uint8_t idx = cs_idx - SWSRC_FIRST_TRIM; + idx = (CONVERT_MODE(idx/2) << 1) + (idx & 1); + result = trimDown(idx); + } +#if ROTARY_ENCODERS > 0 + else if (cs_idx == SWSRC_REa) { + result = REA_DOWN(); + } +#endif +#if ROTARY_ENCODERS > 1 + else if (cs_idx == SWSRC_REb) { + result = REB_DOWN(); + } +#endif +#if defined(CPUARM) && defined(FLIGHT_MODES) + else if (cs_idx >= SWSRC_FIRST_FLIGHT_MODE) { + uint8_t idx = cs_idx - SWSRC_FIRST_FLIGHT_MODE; + result = (idx == s_perout_flight_mode); + } +#endif + else { + cs_idx -= SWSRC_FIRST_LOGICAL_SWITCH; + + GETSWITCH_RECURSIVE_TYPE mask = ((GETSWITCH_RECURSIVE_TYPE)1 << cs_idx); + if (s_last_switch_used & mask) { + result = (s_last_switch_value & mask); + } + else { + s_last_switch_used |= mask; + + LogicalSwitchData * cs = cswAddress(cs_idx); +#if defined(CPUARM) + int8_t s = cs->andsw; +#else + uint8_t s = cs->andsw; + if (s > SWSRC_LAST_SWITCH) { + s += SWSRC_SW1-SWSRC_LAST_SWITCH-1; + } +#endif + if (cs->func == LS_FUNC_NONE || (s && !getSwitch(s))) { + csLastValue[cs_idx] = CS_LAST_VALUE_INIT; + result = false; + } + else if ((s=cswFamily(cs->func)) == LS_FAMILY_BOOL) { + bool res1 = getSwitch(cs->v1); + bool res2 = getSwitch(cs->v2); + switch (cs->func) { + case LS_FUNC_AND: + result = (res1 && res2); + break; + case LS_FUNC_OR: + result = (res1 || res2); + break; + // case LS_FUNC_XOR: + default: + result = (res1 ^ res2); + break; + } + } + else if (s == LS_FAMILY_TIMER) { + result = (csLastValue[cs_idx] <= 0); + } + else if (s == LS_FAMILY_STICKY) { + result = (csLastValue[cs_idx] & (1<<0)); + } +#if defined(CPUARM) + else if (s == LS_FAMILY_STAY) { + result = (csLastValue[cs_idx] & (1<<0)); + } +#endif + else { + getvalue_t x = getValue(cs->v1); + getvalue_t y; + if (s == LS_FAMILY_COMP) { + y = getValue(cs->v2); + + switch (cs->func) { + case LS_FUNC_EQUAL: + result = (x==y); + break; + case LS_FUNC_GREATER: + result = (x>y); + break; + default: + result = (xv1; +#if defined(FRSKY) + // Telemetry + if (v1 >= MIXSRC_FIRST_TELEM) { + if ((!TELEMETRY_STREAMING() && v1 >= MIXSRC_FIRST_TELEM+TELEM_FIRST_STREAMED_VALUE-1) || IS_FAI_FORBIDDEN(v1-1)) + return swtch > 0 ? false : true; + + y = convertCswTelemValue(cs); + +#if defined(FRSKY_HUB) && defined(GAUGES) + if (s == LS_FAMILY_OFS) { + uint8_t idx = v1-MIXSRC_FIRST_TELEM+1-TELEM_ALT; + if (idx < THLD_MAX) { + // Fill the threshold array + barsThresholds[idx] = 128 + cs->v2; + } + } +#endif + } + else if (v1 >= MIXSRC_GVAR1) { + y = cs->v2; + } + else { + y = calc100toRESX(cs->v2); + } +#else + if (v1 >= MIXSRC_FIRST_TELEM) { + y = (int16_t)3 * (128+cs->v2); // it's a Timer + } + else if (v1 >= MIXSRC_GVAR1) { + y = cs->v2; // it's a GVAR + } + else { + y = calc100toRESX(cs->v2); + } +#endif + + switch (cs->func) { +#if defined(CPUARM) + case LS_FUNC_VEQUAL: + result = (x==y); + break; +#endif + case LS_FUNC_VALMOSTEQUAL: +#if defined(GVARS) + if (v1 >= MIXSRC_GVAR1 && v1 <= MIXSRC_LAST_GVAR) + result = (x==y); + else +#endif + result = (abs(x-y) < (1024 / STICK_TOLERANCE)); + break; + case LS_FUNC_VPOS: + result = (x>y); + break; + case LS_FUNC_VNEG: + result = (xy); + break; + case LS_FUNC_ANEG: + result = (abs(x)func == LS_FUNC_DIFFEGREATER) + result = (y >= 0 ? (diff >= y) : (diff <= y)); + else + result = (abs(diff) >= y); + if (result) + csLastValue[cs_idx] = x; + break; + } + } + } + } + +#if defined(CPUARM) + if (cs->delay) { + if (result) { + if (cswDelays[cs_idx] > get_tmr10ms()) + result = false; + } + else { + cswDelays[cs_idx] = get_tmr10ms() + (cs->delay*10); + } + } + + if (cs->duration) { + if (result && !cswStates[cs_idx]) { + cswDurations[cs_idx] = get_tmr10ms() + (cs->duration*10); + } + + cswStates[cs_idx] = result; + result = false; + + if (cswDurations[cs_idx] > get_tmr10ms()) { + result = true; + } + } +#endif + + if (result) { + if (!(s_last_switch_value&mask)) PLAY_LOGICAL_SWITCH_ON(cs_idx); + s_last_switch_value |= mask; + } + else { + if (s_last_switch_value&mask) PLAY_LOGICAL_SWITCH_OFF(cs_idx); + s_last_switch_value &= ~mask; + } + } + } + + return swtch > 0 ? result : !result; +} + +swstate_t switches_states = 0; +int8_t getMovedSwitch() +{ + static tmr10ms_t s_move_last_time = 0; + int8_t result = 0; + +#if defined(PCBTARANIS) + for (uint8_t i=0; i> (i*2); + uint8_t next = (1024+getValue(MIXSRC_SA+i)) / 1024; + if (prev != next) { + switches_states = (switches_states & (~mask)) | (next << (i*2)); + if (i<5) + result = 1+(3*i)+next; + else if (i==5) + result = 1+(3*5)+(next!=0); + else if (i==6) + result = 1+(3*5)+2+next; + else + result = 1+(3*5)+2+3+(next!=0); + } + } +#else + // return delivers 1 to 3 for ID1 to ID3 + // 4..8 for all other switches if changed to true + // -4..-8 for all other switches if changed to false + // 9 for Trainer switch if changed to true; Change to false is ignored + swstate_t mask = 0x80; + for (uint8_t i=NUM_PSWITCH; i>1; i--) { + bool prev; + prev = (switches_states & mask); + // don't use getSwitch here to always get the proper value, even getSwitch manipulates + bool next = switchState((EnumKeys)(SW_BASE+i-1)); + if (prev != next) { + if (((i3)) || next==true) + result = next ? i : -i; + if (i<=3 && result==0) result = 1; + switches_states ^= mask; + } + mask >>= 1; + } +#endif + + if ((tmr10ms_t)(get_tmr10ms() - s_move_last_time) > 10) + result = 0; + + s_move_last_time = get_tmr10ms(); + return result; +} + +void checkSwitches() +{ +#if defined(MODULE_ALWAYS_SEND_PULSES) + static swstate_t last_bad_switches = 0xff; +#else + swstate_t last_bad_switches = 0xff; +#endif + swstate_t states = g_model.switchWarningStates; + +#if defined(PCBTARANIS) + uint8_t bad_pots = 0, last_bad_pots = 0xff; +#endif + +#if !defined(MODULE_ALWAYS_SEND_PULSES) + while (1) { + +#if defined(TELEMETRY_MOD_14051) || defined(PCBTARANIS) + getADC(); +#endif +#endif // !defined(MODULE_ALWAYS_SEND_PULSES) + + getMovedSwitch(); + + bool warn = false; +#if defined(PCBTARANIS) + for (uint8_t i=0; i> 6; + if (potMode) { + perOut(e_perout_mode_normal, 0); + bad_pots = 0; + for (uint8_t i=0; i> 4)) > 1)) { + warn = true; + bad_pots |= (1<> (i*2)]; + lcd_putcAtt(60+i*(2*FW+FW/2), 4*FH+3, 'A'+i, attr); + lcd_putcAtt(60+i*(2*FW+FW/2)+FW, 4*FH+3, c, attr); + } + } + if (potMode) { + for (uint8_t i=0; i> 4)) > 1) { + switch (i) { + case 0: + case 1: + case 2: + lcd_putc(60+i*(5*FW)+2*FW+2, 6*FH-2, g_model.potPosition[i] > (getValue(MIXSRC_FIRST_POT+i) >> 4) ? 126 : 127); + break; + case 3: + case 4: + lcd_putc(60+i*(5*FW)+2*FW+2, 6*FH-2, g_model.potPosition[i] > (getValue(MIXSRC_FIRST_POT+i) >> 4) ? '\300' : '\301'); + break; + } + flags = INVERS; + } + lcd_putsiAtt(60+i*(5*FW), 6*FH-2, STR_VSRCRAW, NUM_STICKS+1+i, flags); + } + } + } + last_bad_pots = bad_pots; +#else + if (last_bad_switches != switches_states) { + MESSAGE(STR_SWITCHWARN, NULL, STR_PRESSANYKEYTOSKIP, last_bad_switches == 0xff ? AU_SWITCH_ALERT : AU_NONE); + uint8_t x = 2; + for (uint8_t i=0; i0?(i+3):(states&0x3)+1), attr); + x += 3*FW+FW/2; + } +#endif + lcdRefresh(); + last_bad_switches = switches_states; + } + +#if defined(MODULE_ALWAYS_SEND_PULSES) + if (pwrCheck()==e_power_off || keyDown()) { + startupWarningState = STARTUP_WARNING_SWITCHES+1; + last_bad_switches = 0xff; + } +#else + if (pwrCheck()==e_power_off || keyDown()) return; + + checkBacklight(); + + wdt_reset(); + + SIMU_SLEEP(1); + } +#endif +}