/* * Copyright (C) OpenTX * * Based on code named * th9x - http://code.google.com/p/th9x * er9x - http://code.google.com/p/er9x * gruvin9x - http://code.google.com/p/gruvin9x * * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html * * 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) int circularIncDec(int current, int inc, int min, int max, IsValueAvailable isValueAvailable) { do { current += inc; if (current < min) current = max; else if (current > max) current = min; if (!isValueAvailable || isValueAvailable(current)) return current; } while(1); return 0; } #if defined(VIRTUALINPUTS) bool isInputAvailable(int input) { for (int i=0; ichn == input) return true; } return false; } #endif bool isChannelUsed(int channel) { for (int i=0; isrcRaw == 0) return false; if (md->destCh == channel) return true; if (md->destCh > channel) return false; } return false; } int getChannelsUsed() { int result = 0; int lastCh = -1; for (int i=0; isrcRaw == 0) return result; if (md->destCh != lastCh) { ++result; lastCh = md->destCh; } } return result; } bool isSourceAvailable(int source) { #if defined(VIRTUALINPUTS) if (source>=MIXSRC_FIRST_INPUT && source<=MIXSRC_LAST_INPUT) { return isInputAvailable(source - MIXSRC_FIRST_INPUT); } #endif #if defined(LUA_MODEL_SCRIPTS) if (source>=MIXSRC_FIRST_LUA && source<=MIXSRC_LAST_LUA) { div_t qr = div(source-MIXSRC_FIRST_LUA, MAX_SCRIPT_OUTPUTS); return (qr.rem=MIXSRC_FIRST_LUA && source<=MIXSRC_LAST_LUA) return false; #endif if (source>=MIXSRC_FIRST_POT && source<=MIXSRC_LAST_POT) { return IS_POT_AVAILABLE(POT1+source-MIXSRC_FIRST_POT); } if (source>=MIXSRC_FIRST_SWITCH && source<=MIXSRC_LAST_SWITCH) { return SWITCH_EXISTS(source-MIXSRC_FIRST_SWITCH); } #if !defined(HELI) if (source>=MIXSRC_CYC1 && source<=MIXSRC_CYC3) return false; #endif if (source>=MIXSRC_FIRST_CH && source<=MIXSRC_LAST_CH) { return isChannelUsed(source-MIXSRC_FIRST_CH); } if (source>=MIXSRC_FIRST_LOGICAL_SWITCH && source<=MIXSRC_LAST_LOGICAL_SWITCH) { LogicalSwitchData * cs = lswAddress(source-MIXSRC_FIRST_LOGICAL_SWITCH); return (cs->func != LS_FUNC_NONE); } #if !defined(GVARS) if (source>=MIXSRC_GVAR1 && source<=MIXSRC_LAST_GVAR) return false; #endif if (source>=MIXSRC_RESERVE1 && source<=MIXSRC_RESERVE5) return false; if (source>=MIXSRC_FIRST_TELEM && source<=MIXSRC_LAST_TELEM) { div_t qr = div(source-MIXSRC_FIRST_TELEM, 3); if (qr.rem == 0) return isTelemetryFieldAvailable(qr.quot); else return isTelemetryFieldComparisonAvailable(qr.quot); } return true; } bool isSourceAvailableInGlobalFunctions(int source) { if (source>=MIXSRC_FIRST_TELEM && source<=MIXSRC_LAST_TELEM) { return false; } return isSourceAvailable(source); } bool isSourceAvailableInCustomSwitches(int source) { bool result = isSourceAvailable(source); #if defined(FRSKY) if (result && source>=MIXSRC_FIRST_TELEM && source<=MIXSRC_LAST_TELEM) { div_t qr = div(source-MIXSRC_FIRST_TELEM, 3); result = isTelemetryFieldComparisonAvailable(qr.quot); } #endif return result; } bool isInputSourceAvailable(int source) { if (source>=MIXSRC_FIRST_POT && source<=MIXSRC_LAST_POT) { return IS_POT_AVAILABLE(POT1+source-MIXSRC_FIRST_POT); } if (source>=MIXSRC_Rud && source<=MIXSRC_MAX) return true; if (source>=MIXSRC_FIRST_TRIM && source<=MIXSRC_LAST_TRIM) return true; if (source>=MIXSRC_FIRST_SWITCH && source<=MIXSRC_LAST_SWITCH) return SWITCH_EXISTS(source-MIXSRC_FIRST_SWITCH); if (source>=MIXSRC_FIRST_CH && source<=MIXSRC_LAST_CH) return true; if (source>=MIXSRC_FIRST_TRAINER && source<=MIXSRC_LAST_TRAINER) return true; if (source>=MIXSRC_FIRST_TELEM && source<=MIXSRC_LAST_TELEM) { div_t qr = div(source-MIXSRC_FIRST_TELEM, 3); return isTelemetryFieldAvailable(qr.quot) && isTelemetryFieldComparisonAvailable(qr.quot); } return false; } enum SwitchContext { LogicalSwitchesContext, ModelCustomFunctionsContext, GeneralCustomFunctionsContext, TimersContext, MixesContext }; bool isLogicalSwitchAvailable(int index) { LogicalSwitchData * lsw = lswAddress(index); return (lsw->func != LS_FUNC_NONE); } bool isSwitchAvailable(int swtch, SwitchContext context) { bool negative = false; if (swtch < 0) { negative = true; if (swtch == -SWSRC_ON || swtch == -SWSRC_ONE) { return false; } swtch = -swtch; } #if defined(PCBSKY9X) if (swtch >= SWSRC_FIRST_SWITCH && swtch <= SWSRC_LAST_SWITCH) { negative = negative; return true; } #else if (swtch >= SWSRC_FIRST_SWITCH && swtch <= SWSRC_LAST_SWITCH) { div_t swinfo = switchInfo(swtch); if (!SWITCH_EXISTS(swinfo.quot)) { return false; } if (!IS_3POS(swinfo.quot)) { if (negative) { return false; } if (IS_3POS_MIDDLE(swinfo.rem)) { return false; } } return true; } #endif #if NUM_XPOTS > 0 if (swtch >= SWSRC_FIRST_MULTIPOS_SWITCH && swtch <= SWSRC_LAST_MULTIPOS_SWITCH) { int index = (swtch - SWSRC_FIRST_MULTIPOS_SWITCH) / XPOTS_MULTIPOS_COUNT; if (IS_POT_MULTIPOS(POT1+index)) { StepsCalibData * calib = (StepsCalibData *) &g_eeGeneral.calib[POT1+index]; return (calib->count >= ((swtch - SWSRC_FIRST_MULTIPOS_SWITCH) % XPOTS_MULTIPOS_COUNT)); } else { return false; } } #endif if (swtch >= SWSRC_FIRST_LOGICAL_SWITCH && swtch <= SWSRC_LAST_LOGICAL_SWITCH) { if (context == GeneralCustomFunctionsContext) { return false; } else if (context != LogicalSwitchesContext) { return isLogicalSwitchAvailable(swtch - SWSRC_FIRST_LOGICAL_SWITCH); } } if (context != ModelCustomFunctionsContext && context != GeneralCustomFunctionsContext && (swtch == SWSRC_ON || swtch == SWSRC_ONE)) { return false; } if (swtch >= SWSRC_FIRST_FLIGHT_MODE && swtch <= SWSRC_LAST_FLIGHT_MODE) { if (context == MixesContext || context == GeneralCustomFunctionsContext) { return false; } else { swtch -= SWSRC_FIRST_FLIGHT_MODE; if (swtch == 0) { return true; } FlightModeData * fm = flightModeAddress(swtch); return (fm->swtch != SWSRC_NONE); } } if (swtch >= SWSRC_FIRST_SENSOR && swtch <= SWSRC_LAST_SENSOR) { return isTelemetryFieldAvailable(swtch - SWSRC_FIRST_SENSOR); } return true; } bool isSwitchAvailableInLogicalSwitches(int swtch) { return isSwitchAvailable(swtch, LogicalSwitchesContext); } bool isSwitchAvailableInCustomFunctions(int swtch) { if (menuHandlers[menuLevel] == menuModelCustomFunctions) return isSwitchAvailable(swtch, ModelCustomFunctionsContext); else return isSwitchAvailable(swtch, GeneralCustomFunctionsContext); } bool isSwitchAvailableInMixes(int swtch) { return isSwitchAvailable(swtch, MixesContext); } bool isSwitchAvailableInTimers(int swtch) { if (swtch >= 0) { if (swtch < TMRMODE_COUNT) return true; else swtch -= TMRMODE_COUNT-1; } else { if (swtch > -TMRMODE_COUNT) return false; else swtch += TMRMODE_COUNT-1; } return isSwitchAvailable(swtch, TimersContext); } bool isThrottleSourceAvailable(int source) { if (source >= THROTTLE_SOURCE_FIRST_POT && source < THROTTLE_SOURCE_FIRST_POT+NUM_POTS && !IS_POT_AVAILABLE(POT1+source-THROTTLE_SOURCE_FIRST_POT)) return false; else return true; } bool isLogicalSwitchFunctionAvailable(int function) { return function != LS_FUNC_RANGE; } bool isAssignableFunctionAvailable(int function) { #if defined(OVERRIDE_CHANNEL_FUNCTION) || defined(GVARS) bool modelFunctions = (menuHandlers[menuLevel] == menuModelCustomFunctions); #endif switch (function) { case FUNC_OVERRIDE_CHANNEL: #if defined(OVERRIDE_CHANNEL_FUNCTION) return modelFunctions; #else return false; #endif case FUNC_ADJUST_GVAR: #if defined(GVARS) return modelFunctions; #else return false; #endif #if !defined(HAPTIC) case FUNC_HAPTIC: #endif case FUNC_RESERVE4: #if !defined(DANGEROUS_MODULE_FUNCTIONS) case FUNC_RANGECHECK: case FUNC_BIND: #endif #if !defined(LUA) case FUNC_PLAY_SCRIPT: #endif case FUNC_RESERVE5: return false; default: return true; } } bool isSourceAvailableInGlobalResetSpecialFunction(int index) { if (index >= FUNC_RESET_PARAM_FIRST_TELEM) return false; else return isSourceAvailableInResetSpecialFunction(index); } bool isSourceAvailableInResetSpecialFunction(int index) { if (index >= FUNC_RESET_PARAM_FIRST_TELEM) { TelemetrySensor & telemetrySensor = g_model.telemetrySensors[index-FUNC_RESET_PARAM_FIRST_TELEM]; return telemetrySensor.isAvailable(); } #if TIMERS < 3 else if (index == FUNC_RESET_TIMER3) { return false; } #endif #if TIMERS < 2 else if (index == FUNC_RESET_TIMER2) { return false; } #endif else { return true; } } bool isModuleAvailable(int module) { return true; } bool isRfProtocolAvailable(int protocol) { #if defined(MODULE_D16_EU_ONLY_SUPPORT) if (protocol == RF_PROTO_D8) { return false; } #endif return true; } bool modelHasNotes() { char filename[sizeof(MODELS_PATH)+1+sizeof(g_model.header.name)+sizeof(TEXT_EXT)] = MODELS_PATH "/"; char *buf = strcat_currentmodelname(&filename[sizeof(MODELS_PATH)]); strcpy(buf, TEXT_EXT); return isFileAvailable(filename); } int getFirstAvailable(int min, int max, IsValueAvailable isValueAvailable) { int retval = 0; for (int i = min; i <= max; i++) { if (isValueAvailable(i)) { retval = i; break; } } return retval; } #endif