/* * 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. */ #ifndef _OPENTX_H_ #define _OPENTX_H_ #include #include #include #include #include "definitions.h" #if defined(SIMU) #define SWITCH_SIMU(a, b) (a) #else #define SWITCH_SIMU(a, b) (b) #endif #if defined(PCBSKY9X) #define IS_PCBSKY9X true #define CASE_PCBSKY9X(x) x, #else #define IS_PCBSKY9X false #define CASE_PCBSKY9X(x) #endif #if defined(CPUARM) #define CASE_CPUARM(x) x, #define IF_CPUARM(x) x #else #define CASE_CPUARM(x) #define IF_CPUARM(x) #endif #if defined(VARIO) && defined(CPUARM) #define CASE_VARIO_CPUARM(x) x, #else #define CASE_VARIO_CPUARM(x) #endif #if defined(LUA) #define CASE_LUA(x) x, #else #define CASE_LUA(x) #endif #if defined(CPUARM) || defined(CPUM2560) #define CASE_PERSISTENT_TIMERS(x) x, #else #define CASE_PERSISTENT_TIMERS(x) #endif #if defined(RTCLOCK) #define CASE_RTCLOCK(x) x, #else #define CASE_RTCLOCK(x) #endif #if defined(BUZZER) #define CASE_BUZZER(x) x, #else #define CASE_BUZZER(x) #endif #if defined(AUDIO) #define CASE_AUDIO(x) x, #else #define CASE_AUDIO(x) #endif #if defined(VOICE) #define CASE_VOICE(x) x, #else #define CASE_VOICE(x) #endif #if defined(PWM_BACKLIGHT) #define CASE_PWM_BACKLIGHT(x) x, #else #define CASE_PWM_BACKLIGHT(x) #endif #if defined(TELEMETRY_FRSKY) && defined(FRSKY_HUB) && defined(GPS) #define CASE_GPS(x) x, #else #define CASE_GPS(x) #endif #if defined(VARIO) #define CASE_VARIO(x) x, #else #define CASE_VARIO(x) #endif #if defined(HAPTIC) #define CASE_HAPTIC(x) x, #else #define CASE_HAPTIC(x) #endif #if defined(SPLASH) #define CASE_SPLASH(x) x, #else #define CASE_SPLASH(x) #endif #if defined(TELEMETRY_FRSKY) #define CASE_FRSKY(x) x, #else #define CASE_FRSKY(x) #endif #if defined(TELEMETRY_MAVLINK) #define CASE_MAVLINK(x) x, #else #define CASE_MAVLINK(x) #endif #if defined(PXX) #define CASE_PXX(x) x, #else #define CASE_PXX(x) #endif #if defined(SDCARD) #define CASE_SDCARD(x) x, #else #define CASE_SDCARD(x) #endif #if defined(BLUETOOTH) #define CASE_BLUETOOTH(x) x, #else #define CASE_BLUETOOTH(x) #endif #if defined(HELI) #define CASE_HELI(x) x, #else #define CASE_HELI(x) #endif #if defined(TEMPLATES) #define CASE_TEMPLATES(x) x, #else #define CASE_TEMPLATES(x) #endif #if defined(FLIGHT_MODES) #define CASE_FLIGHT_MODES(x) x, #else #define CASE_FLIGHT_MODES(x) #endif #if defined(CURVES) #define CASE_CURVES(x) x, #else #define CASE_CURVES(x) #endif #if defined(GVARS) #define CASE_GVARS(x) x, #else #define CASE_GVARS(x) #endif #if defined(PCBX9DP) || defined(PCBX9E) #define CASE_PCBX9E_PCBX9DP(x) x, #else #define CASE_PCBX9E_PCBX9DP(x) #endif #if defined(PCBX9E) #define CASE_PCBX9E(x) x, #else #define CASE_PCBX9E(x) #endif #if defined(PCBSKY9X) && !defined(AR9X) && !defined(REVA) #define TX_CAPACITY_MEASUREMENT #define CASE_CAPACITY(x) x, #else #define CASE_CAPACITY(x) #endif #if ROTARY_ENCODERS > 0 #define ROTARY_ENCODER_NAVIGATION #endif #if defined(FAI) #define IS_FAI_ENABLED() true #define IF_FAI_CHOICE(x) #elif defined(FAI_CHOICE) #define IS_FAI_ENABLED() g_eeGeneral.fai #define IF_FAI_CHOICE(x) x, #else #define IS_FAI_ENABLED() false #define IF_FAI_CHOICE(x) #endif #define IS_FAI_FORBIDDEN(idx) (IS_FAI_ENABLED() && idx >= MIXSRC_FIRST_TELEM) #if defined(CPUARM) #define MASTER_VOLUME #endif #if !defined(CPUM64) && !defined(ACCURAT_THROTTLE_TIMER) // code cost is about 16 bytes for higher throttle accuracy for timer // would not be noticable anyway, because all version up to this change had only 16 steps; // now it has already 32 steps; this define would increase to 128 steps #if !defined(ACCURAT_THROTTLE_TIMER) #define ACCURAT_THROTTLE_TIMER #endif #endif // RESX range is used for internal calculation; The menu says -100.0 to 100.0; internally it is -1024 to 1024 to allow some optimizations #define RESX_SHIFT 10 #define RESX 1024 #define RESXu 1024u #define RESXul 1024ul #define RESXl 1024l #include "board.h" #if defined(DISK_CACHE) #include "disk_cache.h" #endif #if defined(SIMU) #include "targets/simu/simpgmspace.h" #elif defined(CPUARM) typedef const unsigned char pm_uchar; typedef const char pm_char; typedef const uint16_t pm_uint16_t; typedef const uint8_t pm_uint8_t; typedef const int16_t pm_int16_t; typedef const int8_t pm_int8_t; #define pgm_read_byte(address_short) (*(uint8_t*)(address_short)) #define PSTR(adr) adr #define PROGMEM #define pgm_read_adr(x) *(x) #define cli() #define sei() #else #include #include #include "pgmtypes.h" #include #include #include #define F_CPU 16000000UL // 16 MHz #include #define pgm_read_adr(address_short) pgm_read_word(address_short) #include #endif #include "debug.h" #if defined(PCBFLAMENCO) #elif defined(PCBTARANIS) || defined(PCBHORUS) #define SWSRC_THR SWSRC_SF2 #define SWSRC_GEA SWSRC_SG2 #define SWSRC_ID0 SWSRC_SA0 #define SWSRC_ID1 SWSRC_SA1 #define SWSRC_ID2 SWSRC_SA2 #define IS_MOMENTARY(sw) false // TODO #else #define SW_DSM2_BIND SW_TRN #endif #define NUM_PSWITCH (SWSRC_LAST_SWITCH-SWSRC_FIRST_SWITCH+1) #include "myeeprom.h" #if defined(CPUM64) void memclear(void *ptr, uint8_t size); #else #define memclear(p, s) memset(p, 0, s) #endif void memswap(void * a, void * b, uint8_t size); #if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || defined(PCBHORUS) #define POT_CONFIG(x) ((g_eeGeneral.potsConfig >> (2*((x)-POT1)))&0x03) #define IS_POT_MULTIPOS(x) (IS_POT(x) && POT_CONFIG(x)==POT_MULTIPOS_SWITCH) #define IS_POT_WITHOUT_DETENT(x) (IS_POT(x) && POT_CONFIG(x)==POT_WITHOUT_DETENT) #define IS_SLIDER_AVAILABLE(x) ((x) == SLIDER1 || (x) == SLIDER2 || (IS_SLIDER(x) && (g_eeGeneral.slidersConfig & (0x01 << ((x)-SLIDER1))))) #define IS_POT_AVAILABLE(x) (IS_POT(x) && POT_CONFIG(x)!=POT_NONE) #define IS_POT_OR_SLIDER_AVAILABLE(x) (IS_POT_AVAILABLE(x) || IS_SLIDER_AVAILABLE(x)) #define IS_MULTIPOS_CALIBRATED(cal) (cal->count>0 && cal->count> 4) #define SAVE_POT_POSITION(i) g_model.potsWarnPosition[i] = GET_LOWRES_POT_POSITION(i) #if ROTARY_ENCODERS > 0 #define IF_ROTARY_ENCODERS(x) x, #else #define IF_ROTARY_ENCODERS(x) #endif #define PPM_CENTER 1500 #if defined(PPM_CENTER_ADJUSTABLE) #define PPM_CH_CENTER(ch) (PPM_CENTER+limitAddress(ch)->ppmCenter) #else #define PPM_CH_CENTER(ch) (PPM_CENTER) #endif #if defined(CPUARM) #include "fifo.h" #include "io/io_arm.h" // This doesn't need protection on this processor typedef uint32_t tmr10ms_t; extern volatile tmr10ms_t g_tmr10ms; #define get_tmr10ms() g_tmr10ms typedef int32_t rotenc_t; typedef int32_t getvalue_t; typedef uint32_t mixsrc_t; typedef int32_t swsrc_t; #else typedef uint16_t tmr10ms_t; extern volatile tmr10ms_t g_tmr10ms; extern inline uint16_t get_tmr10ms() { uint16_t time ; cli(); time = g_tmr10ms ; sei(); return time ; } typedef int8_t rotenc_t; typedef int16_t getvalue_t; typedef uint8_t mixsrc_t; typedef int8_t swsrc_t; #endif #if defined(NAVIGATION_STICKS) extern uint8_t StickScrollAllowed; extern uint8_t StickScrollTimer; #define STICK_SCROLL_TIMEOUT 9 #define STICK_SCROLL_DISABLE() StickScrollAllowed = 0 #else #define STICK_SCROLL_DISABLE() #endif #if defined(CLI) #include "cli.h" #endif #include "timers.h" #include "storage/storage.h" #include "pulses/pulses.h" #if defined(CPUARM) // Order is the same as in enum Protocols in myeeprom.h (none, ppm, xjt, dsm, crossfire, multi) static const int8_t maxChannelsModules[] = { 0, 8, 8, -2, 8, 4 }; // relative to 8! static const int8_t maxChannelsXJT[] = { 0, 8, 0, 4 }; // relative to 8! #define MAX_TRAINER_CHANNELS_M8() (MAX_TRAINER_CHANNELS-8) #endif #if defined(MULTIMODULE) #define IS_MODULE_MULTIMODULE(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_MULTIMODULE) #else #define IS_MODULE_MULTIMODULE(idx) (false) #endif #if defined(PCBTARANIS) || defined(PCBHORUS) #if defined(TARANIS_INTERNAL_PPM) #define IS_MODULE_PPM(idx) (idx==TRAINER_MODULE || (idx==INTERNAL_MODULE && g_model.moduleData[INTERNAL_MODULE].type==MODULE_TYPE_PPM)|| (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_PPM)) #define IS_MODULE_XJT(idx) (((idx==INTERNAL_MODULE && g_model.moduleData[INTERNAL_MODULE].type==MODULE_TYPE_XJT)|| (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_XJT)) && (g_model.moduleData[idx].rfProtocol != RF_PROTO_OFF)) #else #define IS_MODULE_PPM(idx) (idx==TRAINER_MODULE || (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_PPM)) #define IS_MODULE_XJT(idx) ((idx==INTERNAL_MODULE || g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_XJT) && (g_model.moduleData[idx].rfProtocol != RF_PROTO_OFF)) #endif #if defined(DSM2) #define IS_MODULE_DSM2(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_DSM2) #else #define IS_MODULE_DSM2(idx) (false) #endif #if defined(CROSSFIRE) #define IS_MODULE_CROSSFIRE(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_CROSSFIRE) #else #define IS_MODULE_CROSSFIRE(idx) (false) #endif #if defined(TARANIS_INTERNAL_PPM) #define MAX_INTERNAL_MODULE_CHANNELS() ((g_model.moduleData[INTERNAL_MODULE].type == MODULE_TYPE_XJT) ? maxChannelsXJT[1+g_model.moduleData[0].rfProtocol] : maxChannelsModules[g_model.moduleData[INTERNAL_MODULE].type]) #else #define MAX_INTERNAL_MODULE_CHANNELS() (maxChannelsXJT[1+g_model.moduleData[INTERNAL_MODULE].rfProtocol]) #endif #define MAX_EXTERNAL_MODULE_CHANNELS() ((g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_XJT) ? maxChannelsXJT[1+g_model.moduleData[1].rfProtocol] : maxChannelsModules[g_model.moduleData[EXTERNAL_MODULE].type]) #define MAX_CHANNELS(idx) (idx==INTERNAL_MODULE ? MAX_INTERNAL_MODULE_CHANNELS() : (idx==EXTERNAL_MODULE ? MAX_EXTERNAL_MODULE_CHANNELS() : MAX_TRAINER_CHANNELS_M8())) #define NUM_CHANNELS(idx) ((IS_MODULE_CROSSFIRE(idx) || (IS_MODULE_MULTIMODULE(idx) && (g_model.moduleData[idx].getMultiProtocol(true) != MM_RF_PROTO_DSM2))) ? CROSSFIRE_CHANNELS_COUNT : (8+g_model.moduleData[idx].channelsCount)) #elif defined(PCBSKY9X) && !defined(REVA) #define IS_MODULE_PPM(idx) (idx==TRAINER_MODULE || idx==EXTRA_MODULE || (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_PPM)) #define IS_MODULE_XJT(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_XJT) #define IS_MODULE_DSM2(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_DSM2) #define MAX_EXTERNAL_MODULE_CHANNELS() ((g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_XJT) ? maxChannelsXJT[1+g_model.moduleData[0].rfProtocol] : maxChannelsModules[g_model.moduleData[EXTERNAL_MODULE].type]) #define MAX_EXTRA_MODULE_CHANNELS() (8) // Only PPM (16ch PPM) #define MAX_CHANNELS(idx) (idx==EXTERNAL_MODULE ? MAX_EXTERNAL_MODULE_CHANNELS() : (idx==EXTRA_MODULE ? MAX_EXTRA_MODULE_CHANNELS() : MAX_TRAINER_CHANNELS_M8())) #define NUM_CHANNELS(idx) (8+g_model.moduleData[idx].channelsCount) #define IS_MODULE_CROSSFIRE(idx) (false) #else #define IS_MODULE_PPM(idx) (idx==TRAINER_MODULE || (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_PPM)) #define IS_MODULE_XJT(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_XJT) #define IS_MODULE_DSM2(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_DSM2) #define MAX_EXTERNAL_MODULE_CHANNELS() ((g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_XJT) ? maxChannelsXJT[1+g_model.moduleData[EXTERNAL_MODULE].rfProtocol] : maxChannelsModules[g_model.moduleData[EXTERNAL_MODULE].type]) #define MAX_CHANNELS(idx) (idx==EXTERNAL_MODULE ? MAX_EXTERNAL_MODULE_CHANNELS() : MAX_TRAINER_CHANNELS_M8()) #define NUM_CHANNELS(idx) (8+g_model.moduleData[idx].channelsCount) #endif #if defined(MULTIMODULE) #define IS_MULTIMODULE_DSM(idx) (IS_MODULE_MULTIMODULE(idx) && g_model.moduleData[idx].getMultiProtocol(true) == MM_RF_PROTO_DSM2) #define DEFAULT_CHANNELS(idx) (IS_MODULE_PPM(idx) ? 0 : IS_MULTIMODULE_DSM(idx) ? -1 : MAX_CHANNELS(idx)) #else #define DEFAULT_CHANNELS(idx) (IS_MODULE_PPM(idx) ? 0 : MAX_CHANNELS(idx)) #endif #if defined(CPUARM) #define MASK_CFN_TYPE uint64_t // current max = 64 function switches #define MASK_FUNC_TYPE uint32_t // current max = 32 functions #elif defined(CPUM64) #define MASK_CFN_TYPE uint16_t // current max = 16 function switches #define MASK_FUNC_TYPE uint8_t // current max = 8 functions #else #define MASK_CFN_TYPE uint32_t // current max = 32 function switches #define MASK_FUNC_TYPE uint8_t // current max = 8 functions #endif typedef struct { MASK_FUNC_TYPE activeFunctions; MASK_CFN_TYPE activeSwitches; tmr10ms_t lastFunctionTime[MAX_SPECIAL_FUNCTIONS]; inline bool isFunctionActive(uint8_t func) { return activeFunctions & ((MASK_FUNC_TYPE)1 << func); } void reset() { memclear(this, sizeof(*this)); } } CustomFunctionsContext; #include "strhelpers.h" #include "gui.h" #if defined(TEMPLATES) #include "templates.h" #endif #if !defined(SIMU) #define assert(x) #if !defined(CPUARM) || !defined(DEBUG) #define printf printf_not_allowed #endif #endif extern const pm_uint8_t bchout_ar[]; extern const pm_uint8_t modn12x3[]; //convert from mode 1 to mode stickMode //NOTICE! => 0..3 -> 0..3 #define RUD_STICK 0 #define ELE_STICK 1 #define THR_STICK 2 #define AIL_STICK 3 #define CONVERT_MODE(x) (((x)<=AIL_STICK) ? pgm_read_byte(modn12x3 + 4*g_eeGeneral.stickMode + (x)) : (x) ) extern uint8_t channel_order(uint8_t x); #define THRCHK_DEADBAND 16 #if defined(COLORLCD) #define SPLASH_NEEDED() (true) #elif defined(PCBTARANIS) #define SPLASH_NEEDED() (g_eeGeneral.splashMode != 3) #elif defined(CPUARM) #define SPLASH_NEEDED() (g_model.moduleData[EXTERNAL_MODULE].type != MODULE_TYPE_DSM2 && !g_eeGeneral.splashMode) #else #define SPLASH_NEEDED() (!IS_DSM2_PROTOCOL(g_model.protocol) && !g_eeGeneral.splashMode) #endif #if defined(PCBHORUS) #define SPLASH_TIMEOUT 300 /* 3s */ #elif defined(FSPLASH) #define SPLASH_TIMEOUT (g_eeGeneral.splashMode == 0 ? 60000/*infinite=10mn*/ : ((4*100) * (g_eeGeneral.splashMode & 0x03))) #elif defined(PCBTARANIS) || defined(PCBFLAMENCO) #define SPLASH_TIMEOUT (g_eeGeneral.splashMode==-4 ? 1500 : (g_eeGeneral.splashMode<=0 ? (400-g_eeGeneral.splashMode*200) : (400-g_eeGeneral.splashMode*100))) #else #define SPLASH_TIMEOUT (4*100) // 4 seconds #endif #if defined(ROTARY_ENCODERS) #define IS_ROTARY_ENCODER_NAVIGATION_ENABLE() g_eeGeneral.reNavigation extern volatile rotenc_t rotencValue[ROTARY_ENCODERS]; #define ROTARY_ENCODER_NAVIGATION_VALUE rotencValue[g_eeGeneral.reNavigation - 1] #elif defined(ROTARY_ENCODER_NAVIGATION) #define IS_ROTARY_ENCODER_NAVIGATION_ENABLE() true extern volatile rotenc_t rotencValue[1]; #define ROTARY_ENCODER_NAVIGATION_VALUE rotencValue[0] #endif #if defined(CPUARM) && defined(ROTARY_ENCODER_NAVIGATION) extern uint8_t rotencSpeed; #define ROTENC_LOWSPEED 1 #define ROTENC_MIDSPEED 5 #define ROTENC_HIGHSPEED 50 #define ROTENC_DELAY_MIDSPEED 32 #define ROTENC_DELAY_HIGHSPEED 16 #endif #define HEART_TIMER_10MS 1 #define HEART_TIMER_PULSES 2 // when multiple modules this is the first one #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) #define HEART_WDT_CHECK (HEART_TIMER_10MS + (HEART_TIMER_PULSES << 0) + (HEART_TIMER_PULSES << 1)) #else #define HEART_WDT_CHECK (HEART_TIMER_10MS + HEART_TIMER_PULSES) #endif extern uint8_t heartbeat; #if defined(CPUARM) && !defined(BOOT) void watchdogSuspend(uint32_t timeout); #define WATCHDOG_SUSPEND(x) watchdogSuspend(x) #else #define WATCHDOG_SUSPEND(...) #endif #define MAX_ALERT_TIME 60 struct t_inactivity { uint16_t counter; uint8_t sum; }; extern struct t_inactivity inactivity; #define LEN_STD_CHARS 40 #if defined(TRANSLATIONS_CZ) #define ZCHAR_MAX (LEN_STD_CHARS) #else #define ZCHAR_MAX (LEN_STD_CHARS + LEN_SPECIAL_CHARS) #endif char hex2zchar(uint8_t hex); char idx2char(int8_t idx); #if defined(CPUARM) || defined(SIMU) int8_t char2idx(char c); void str2zchar(char *dest, const char *src, int size); int zchar2str(char *dest, const char *src, int size); #endif #include "keys.h" #include "pwr.h" #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) div_t switchInfo(int switchPosition); extern uint8_t potsPos[NUM_XPOTS]; #endif #if defined(PCBHORUS) uint16_t trimDown(uint16_t idx); // TODO why? #else uint8_t trimDown(uint8_t idx); #endif void readKeysAndTrims(); uint16_t evalChkSum(); #if !defined(GUI) #define RAISE_ALERT(...) #define ALERT(...) #elif defined(VOICE) #define RAISE_ALERT(title, msg, info, sound) showAlertBox(title, msg, info, sound) #define ALERT(title, msg, sound) alert(title, msg, sound) #else #define RAISE_ALERT(title, msg, info, sound) showAlertBox(title, msg, info) #define ALERT(title, msg, sound) alert(title, msg) #endif void alert(const pm_char * t, const pm_char * s ALERT_SOUND_ARG); enum PerOutMode { e_perout_mode_normal = 0, e_perout_mode_inactive_flight_mode = 1, e_perout_mode_notrainer = 2, e_perout_mode_notrims = 4, e_perout_mode_nosticks = 8, e_perout_mode_noinput = e_perout_mode_notrainer+e_perout_mode_notrims+e_perout_mode_nosticks }; #if defined(MODULE_ALWAYS_SEND_PULSES) extern uint8_t startupWarningState; enum StartupWarningStates { STARTUP_WARNING_THROTTLE, STARTUP_WARNING_SWITCHES, STARTUP_WARNING_DONE, }; #endif // Fiddle to force compiler to use a pointer #if defined(CPUARM) || defined(SIMU) #define FORCE_INDIRECT(ptr) #else #define FORCE_INDIRECT(ptr) __asm__ __volatile__ ("" : "=e" (ptr) : "0" (ptr)) #endif extern uint8_t mixerCurrentFlightMode; extern uint8_t lastFlightMode; extern uint8_t flightModeTransitionLast; #if defined(CPUARM) #define bitfield_channels_t uint32_t #else #define bitfield_channels_t uint16_t #endif #if defined(SIMU) inline int availableMemory() { return 1000; } #elif defined(CPUARM) && !defined(SIMU) extern unsigned char *heap; extern int _end; extern int _estack; extern int _main_stack_start; extern int _heap_end; #define availableMemory() ((unsigned int)((unsigned char *)&_heap_end - heap)) #endif void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms); void evalMixes(uint8_t tick10ms); void doMixerCalculations(); void scheduleNextMixerCalculation(uint8_t module, uint16_t delay); #if defined(CPUARM) void checkTrims(); #endif void perMain(); NOINLINE void per10ms(); getvalue_t getValue(mixsrc_t i); #if defined(CPUARM) #define GETSWITCH_MIDPOS_DELAY 1 bool getSwitch(swsrc_t swtch, uint8_t flags=0); #else bool getSwitch(swsrc_t swtch); #endif void logicalSwitchesTimerTick(); void logicalSwitchesReset(); #if defined(CPUARM) void evalLogicalSwitches(bool isCurrentPhase=true); void logicalSwitchesCopyState(uint8_t src, uint8_t dst); #define LS_RECURSIVE_EVALUATION_RESET() #else #define evalLogicalSwitches(xxx) #define GETSWITCH_RECURSIVE_TYPE uint16_t extern volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_used; extern volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_value; #define LS_RECURSIVE_EVALUATION_RESET() s_last_switch_used = 0 #endif #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) void getSwitchesPosition(bool startup); #else #define getSwitchesPosition(...) #endif extern swarnstate_t switches_states; swsrc_t getMovedSwitch(); #if defined(CPUARM) #define GET_MOVED_SOURCE_PARAMS uint8_t min int8_t getMovedSource(GET_MOVED_SOURCE_PARAMS); #define GET_MOVED_SOURCE(min, max) getMovedSource(min) #else #define GET_MOVED_SOURCE_PARAMS int8_t getMovedSource(); #define GET_MOVED_SOURCE(min, max) getMovedSource() #endif #if defined(FLIGHT_MODES) extern uint8_t getFlightMode(); #else #define getFlightMode() 0 #endif #if !defined(CPUARM) uint8_t getTrimFlightMode(uint8_t phase, uint8_t idx); #else #define getTrimFlightMode(phase, idx) (phase) #endif #if defined(GVARS) extern int8_t trimGvar[NUM_STICKS+NUM_AUX_TRIMS]; #define TRIM_REUSED(idx) trimGvar[idx] >= 0 #else #define TRIM_REUSED(idx) 0 #endif trim_t getRawTrimValue(uint8_t phase, uint8_t idx); int getTrimValue(uint8_t phase, uint8_t idx); #if defined(CPUARM) bool setTrimValue(uint8_t phase, uint8_t idx, int trim); #else void setTrimValue(uint8_t phase, uint8_t idx, int trim); #endif #if defined(ROTARY_ENCODERS) int16_t getRotaryEncoder(uint8_t idx); void incRotaryEncoder(uint8_t idx, int8_t inc); #endif #if defined(PCBGRUVIN9X) || defined(PCBMEGA2560) #define ROTARY_ENCODER_GRANULARITY (1) #elif defined(PCBSKY9X) #define ROTARY_ENCODER_GRANULARITY (2 << g_eeGeneral.rotarySteps) #else #define ROTARY_ENCODER_GRANULARITY (2) #endif #include "gvars.h" extern uint16_t sessionTimer; extern uint16_t s_timeCumThr; extern uint16_t s_timeCum16ThrP; #if defined(OVERRIDE_CHANNEL_FUNCTION) #if defined(CPUARM) typedef int16_t safetych_t; #define OVERRIDE_CHANNEL_UNDEFINED -4096 #else typedef int8_t safetych_t; #define OVERRIDE_CHANNEL_UNDEFINED -128 #endif extern safetych_t safetyCh[MAX_OUTPUT_CHANNELS]; #endif extern uint8_t trimsCheckTimer; #if defined(CPUARM) extern uint8_t trimsDisplayTimer; extern uint8_t trimsDisplayMask; #endif void flightReset(uint8_t check=true); extern uint8_t unexpectedShutdown; extern uint16_t maxMixerDuration; #if !defined(CPUARM) extern uint8_t g_tmr1Latency_max; extern uint8_t g_tmr1Latency_min; extern uint16_t lastMixerDuration; #endif #if defined(CPUARM) #define DURATION_MS_PREC2(x) ((x)/20) #else #define DURATION_MS_PREC2(x) ((x)*100)/16 #endif #if defined(THRTRACE) #if defined(COLORLCD) #define MAXTRACE (LCD_W-2*10) #else #define MAXTRACE (LCD_W - 8) #endif extern uint8_t s_traceBuf[MAXTRACE]; extern uint16_t s_traceWr; extern uint8_t s_cnt_10s; extern uint16_t s_cnt_samples_thr_10s; extern uint16_t s_sum_samples_thr_10s; #define RESET_THR_TRACE() s_traceWr = s_cnt_10s = s_cnt_samples_thr_10s = s_sum_samples_thr_10s = s_timeCum16ThrP = s_timeCumThr = 0 #else #define RESET_THR_TRACE() s_timeCum16ThrP = s_timeCumThr = 0 #endif #if defined(SIMU) uint16_t getTmr2MHz(); uint16_t getTmr16KHz(); #elif defined(STM32) static inline uint16_t getTmr2MHz() { return TIMER_2MHz_TIMER->CNT; } #elif defined(PCBSKY9X) static inline uint16_t getTmr2MHz() { return TC1->TC_CHANNEL[0].TC_CV; } #else uint16_t getTmr16KHz(); #endif #if !defined(CPUARM) uint16_t stackAvailable(); #endif #if defined(SPLASH) void doSplash(); #endif #if MENUS_LOCK == 1 extern bool readonly; extern bool readonlyUnlocked(); #define READ_ONLY() readonly #define READ_ONLY_UNLOCKED() readonlyUnlocked() #else #define READ_ONLY() false #define READ_ONLY_UNLOCKED() true #endif void checkLowEEPROM(); void checkTHR(); void checkSwitches(); void checkAlarm(); void checkAll(); #if !defined(SIMU) void getADC(); #if defined(CPUARM) #define GET_ADC_IF_MIXER_NOT_RUNNING() do { if (s_pulses_paused) getADC(); } while(0) #else #define GET_ADC_IF_MIXER_NOT_RUNNING() getADC() #endif #endif #if defined(SBUS) #include "sbus.h" #endif void backlightOn(); void checkBacklight(); void doLoopCommonActions(); #define BITMASK(bit) (1<<(bit)) /// returns the number of elements of an array #define DIM(arr) (sizeof((arr))/sizeof((arr)[0])) template FORCEINLINE t min(t a, t b) { return a FORCEINLINE t max(t a, t b) { return a>b?a:b; } template FORCEINLINE t sgn(t a) { return a>0 ? 1 : (a < 0 ? -1 : 0); } template FORCEINLINE t limit(t mi, t x, t ma) { return min(max(mi,x),ma); } template void SWAP(t & a, t & b) { t tmp = b; b = a; a = tmp; } uint16_t isqrt32(uint32_t n); #if defined(CPUARM) && !defined(BOOT) #include "tasks_arm.h" extern OS_MutexID mixerMutex; inline void pauseMixerCalculations() { CoEnterMutexSection(mixerMutex); } inline void resumeMixerCalculations() { CoLeaveMutexSection(mixerMutex); } #else #define pauseMixerCalculations() #define resumeMixerCalculations() #endif void generalDefault(); void modelDefault(uint8_t id); #if defined(CPUARM) void checkModelIdUnique(uint8_t index, uint8_t module); #endif #if defined(CPUARM) inline int divRoundClosest(const int n, const int d) { if (d == 0) return 0; else return ((n < 0) ^ (d < 0)) ? ((n - d/2)/d) : ((n + d/2)/d); } #define calc100to256_16Bits(x) calc100to256(x) #define calc100toRESX_16Bits(x) calc100toRESX(x) inline int calc100to256(int x) { return divRoundClosest(x*256, 100); } inline int calc100toRESX(int x) { return divRoundClosest(x*RESX, 100); } inline int calc1000toRESX(int x) { return divRoundClosest(x*RESX, 1000); } inline int calcRESXto1000(int x) { return divRoundClosest(x*1000, RESX); } inline int calcRESXto100(int x) { return divRoundClosest(x*100, RESX); } #else extern int16_t calc100to256_16Bits(int16_t x); // @@@2 open.20.fsguruh: return x*2.56 extern int16_t calc100to256(int8_t x); // @@@2 open.20.fsguruh: return x*2.56 extern int16_t calc100toRESX_16Bits(int16_t x); // @@@ open.20.fsguruh extern int16_t calc100toRESX(int8_t x); extern int16_t calc1000toRESX(int16_t x); extern int16_t calcRESXto1000(int16_t x); extern int8_t calcRESXto100(int16_t x); #endif #if defined(COLORLCD) extern const char vers_stamp[]; extern const char date_stamp[]; extern const char time_stamp[]; extern const char eeprom_stamp[]; #else extern const char vers_stamp[]; #endif extern uint8_t g_vbat100mV; #if defined(PCBTARANIS) #define GET_TXBATT_BARS() (limit(0, div_and_round(10 * (g_vbat100mV - g_eeGeneral.vBatMin - 90), 30 + g_eeGeneral.vBatMax - g_eeGeneral.vBatMin), 10)) #else #define GET_TXBATT_BARS() (limit(2, 20 * (g_vbat100mV - g_eeGeneral.vBatMin - 90) / (30 + g_eeGeneral.vBatMax - g_eeGeneral.vBatMin), 20)) #endif #define IS_TXBATT_WARNING() (g_vbat100mV <= g_eeGeneral.vBatWarn) #define g_blinkTmr10ms (*(uint8_t*)&g_tmr10ms) extern uint8_t g_beepCnt; extern uint8_t g_beepVal[5]; #include "trainer_input.h" extern int32_t chans[MAX_OUTPUT_CHANNELS]; extern int16_t ex_chans[MAX_OUTPUT_CHANNELS]; // Outputs (before LIMITS) of the last perMain extern int16_t channelOutputs[MAX_OUTPUT_CHANNELS]; extern uint16_t BandGap; #if defined(CPUARM) #define NUM_INPUTS (MAX_INPUTS) #else #define NUM_INPUTS (NUM_STICKS) #endif int expo(int x, int k); #if defined(CPUARM) inline int getMaximumValue(int source) { if (source < MIXSRC_FIRST_CH) return 100; else if (source <= MIXSRC_LAST_CH) return g_model.extendedLimits ? 150 : 100; else if (source >= MIXSRC_FIRST_TIMER && source <= MIXSRC_LAST_TIMER) return (23*60)+59; else return 30000; } #endif // Curves enum BaseCurves { CURVE_NONE, CURVE_X_GT0, CURVE_X_LT0, CURVE_ABS_X, CURVE_F_GT0, CURVE_F_LT0, CURVE_ABS_F, CURVE_BASE }; int8_t * curveAddress(uint8_t idx); struct point_t { coord_t x; coord_t y; }; point_t getPoint(uint8_t i); #if !defined(CURVES) #define LOAD_MODEL_CURVES() #define applyCurve(x, idx) (x) #elif defined(CPUARM) typedef CurveData CurveInfo; void loadCurves(); #define LOAD_MODEL_CURVES() loadCurves() int intpol(int x, uint8_t idx); int applyCurve(int x, CurveRef & curve); int applyCustomCurve(int x, uint8_t idx); int applyCurrentCurve(int x); int8_t getCurveX(int noPoints, int point); void resetCustomCurveX(int8_t * points, int noPoints); bool moveCurve(uint8_t index, int8_t shift); // TODO bool? #else struct CurveInfo { int8_t * crv; uint8_t points:7; uint8_t custom:1; }; CurveInfo curveInfo(uint8_t idx); int intpol(int x, uint8_t idx); int applyCurve(int x, int8_t idx); #define LOAD_MODEL_CURVES() #define applyCustomCurve(x, idx) intpol(x, idx) int applyCurrentCurve(int x); bool moveCurve(uint8_t index, int8_t shift, int8_t custom=0); #endif #if defined(CPUARM) #define APPLY_EXPOS_EXTRA_PARAMS_INC , uint8_t ovwrIdx=0, int16_t ovwrValue=0 #define APPLY_EXPOS_EXTRA_PARAMS , uint8_t ovwrIdx, int16_t ovwrValue #else #define APPLY_EXPOS_EXTRA_PARAMS_INC #define APPLY_EXPOS_EXTRA_PARAMS #endif #if defined(CPUARM) void clearInputs(); void defaultInputs(); #endif void applyExpos(int16_t * anas, uint8_t mode APPLY_EXPOS_EXTRA_PARAMS_INC); int16_t applyLimits(uint8_t channel, int32_t value); void evalInputs(uint8_t mode); uint16_t anaIn(uint8_t chan); extern int16_t calibratedStick[NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_MOUSE_ANALOGS]; #define FLASH_DURATION 20 /*200ms*/ extern uint8_t beepAgain; extern uint16_t lightOffCounter; extern uint8_t flashCounter; extern uint8_t mixWarning; FlightModeData * flightModeAddress(uint8_t idx); ExpoData * expoAddress(uint8_t idx); MixData * mixAddress(uint8_t idx); LimitData * limitAddress(uint8_t idx); LogicalSwitchData * lswAddress(uint8_t idx); // static variables used in evalFlightModeMixes - moved here so they don't interfere with the stack // It's also easier to initialize them here. #if defined(CPUARM) extern int8_t virtualInputsTrims[NUM_INPUTS]; #else extern int16_t rawAnas[NUM_INPUTS]; #endif extern int16_t anas [NUM_INPUTS]; extern int16_t trims[NUM_STICKS+NUM_AUX_TRIMS]; extern BeepANACenter bpanaCenter; extern uint8_t s_mixer_first_run_done; void applyDefaultTemplate(); void incSubtrim(uint8_t idx, int16_t inc); void instantTrim(); void evalTrims(); void copyTrimsToOffset(uint8_t ch); void copySticksToOffset(uint8_t ch); void moveTrimsToOffsets(); #if defined(CPUARM) #define ACTIVE_PHASES_TYPE uint16_t #define DELAY_POS_SHIFT 0 #define DELAY_POS_MARGIN 3 #define delayval_t int16_t PACK(typedef struct { uint16_t delay; int16_t now; // timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw int16_t prev; uint8_t activeMix; uint8_t activeExpo; }) SwOn; #else #define ACTIVE_PHASES_TYPE uint8_t #define DELAY_POS_SHIFT 10 #define DELAY_POS_MARGIN 0 #define delayval_t int8_t PACK(typedef struct { uint16_t delay:10; int16_t now:2; // timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw int16_t prev:2; int16_t activeMix:1; int16_t activeExpo:1; }) SwOn; #endif extern SwOn swOn[MAX_MIXERS]; extern int24_t act[MAX_MIXERS]; #if defined(BOLD_FONT) inline bool isExpoActive(uint8_t expo) { return swOn[expo].activeExpo; } inline bool isMixActive(uint8_t mix) { return swOn[mix].activeMix; } #else #define isExpoActive(x) false #define isMixActive(x) false #endif enum LogicalSwitchFamilies { LS_FAMILY_OFS, LS_FAMILY_BOOL, LS_FAMILY_COMP, LS_FAMILY_DIFF, LS_FAMILY_TIMER, LS_FAMILY_STICKY, LS_FAMILY_RANGE, LS_FAMILY_EDGE }; uint8_t lswFamily(uint8_t func); int16_t lswTimerValue(delayval_t val); enum FunctionsActive { FUNCTION_TRAINER, FUNCTION_INSTANT_TRIM = FUNCTION_TRAINER+4, FUNCTION_VARIO, FUNCTION_BACKLIGHT, #if defined(SDCARD) FUNCTION_LOGS, #endif #if defined(CPUARM) FUNCTION_BACKGND_MUSIC, FUNCTION_BACKGND_MUSIC_PAUSE, #endif }; #define VARIO_FREQUENCY_ZERO 700/*Hz*/ #define VARIO_FREQUENCY_RANGE 1000/*Hz*/ #define VARIO_REPEAT_ZERO 500/*ms*/ #define VARIO_REPEAT_MAX 80/*ms*/ #if defined(CPUARM) extern CustomFunctionsContext modelFunctionsContext; extern CustomFunctionsContext globalFunctionsContext; inline bool isFunctionActive(uint8_t func) { return globalFunctionsContext.isFunctionActive(func) || modelFunctionsContext.isFunctionActive(func); } void evalFunctions(const CustomFunctionData * functions, CustomFunctionsContext & functionsContext); inline void customFunctionsReset() { globalFunctionsContext.reset(); modelFunctionsContext.reset(); } #else extern CustomFunctionsContext modelFunctionsContext; #define isFunctionActive(func) modelFunctionsContext.isFunctionActive(func) void evalFunctions(); #define customFunctionsReset() modelFunctionsContext.reset() #endif #include "telemetry/telemetry.h" #if defined(CPUARM) uint8_t crc8(const uint8_t * ptr, uint32_t len); uint16_t crc16(const uint8_t * ptr, uint32_t len); #endif #define PLAY_REPEAT(x) (x) /* Range 0 to 15 */ #define PLAY_NOW 0x10 #define PLAY_BACKGROUND 0x20 #define PLAY_INCREMENT(x) ((uint8_t)(((uint8_t)x) << 6)) /* -1, 0, 1, 2 */ enum AUDIO_SOUNDS { AUDIO_HELLO, #if defined(CPUARM) AU_BYE, #endif #if defined(VOICE) AU_THROTTLE_ALERT, AU_SWITCH_ALERT, AU_BAD_RADIODATA, #endif AU_TX_BATTERY_LOW, AU_INACTIVITY, #if defined(CPUARM) AU_RSSI_ORANGE, AU_RSSI_RED, AU_SWR_RED, AU_TELEMETRY_LOST, AU_TELEMETRY_BACK, AU_TRAINER_LOST, AU_TRAINER_BACK, AU_SENSOR_LOST, AU_SERVO_KO, AU_RX_OVERLOAD, #endif #if defined(PCBSKY9X) AU_TX_MAH_HIGH, AU_TX_TEMP_HIGH, #endif AU_ERROR, AU_WARNING1, AU_WARNING2, AU_WARNING3, AU_TRIM_MIDDLE, #if defined(CPUARM) AU_TRIM_MIN, AU_TRIM_MAX, #endif #if defined(CPUARM) AU_STICK1_MIDDLE, AU_STICK2_MIDDLE, AU_STICK3_MIDDLE, AU_STICK4_MIDDLE, #endif #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) AU_POT1_MIDDLE, AU_POT2_MIDDLE, AU_SLIDER1_MIDDLE, AU_SLIDER2_MIDDLE, #elif defined(CPUARM) AU_POT1_MIDDLE, AU_POT2_MIDDLE, AU_POT3_MIDDLE, #else AU_POT_MIDDLE, #endif AU_MIX_WARNING_1, AU_MIX_WARNING_2, AU_MIX_WARNING_3, #if defined(CPUARM) AU_TIMER1_ELAPSED, AU_TIMER2_ELAPSED, AU_TIMER3_ELAPSED, #endif AU_SPECIAL_SOUND_FIRST, AU_SPECIAL_SOUND_BEEP1 = AU_SPECIAL_SOUND_FIRST, AU_SPECIAL_SOUND_BEEP2, AU_SPECIAL_SOUND_BEEP3, AU_SPECIAL_SOUND_WARN1, AU_SPECIAL_SOUND_WARN2, AU_SPECIAL_SOUND_CHEEP, AU_SPECIAL_SOUND_RATATA, AU_SPECIAL_SOUND_TICK, AU_SPECIAL_SOUND_SIREN, AU_SPECIAL_SOUND_RING, AU_SPECIAL_SOUND_SCIFI, AU_SPECIAL_SOUND_ROBOT, AU_SPECIAL_SOUND_CHIRP, AU_SPECIAL_SOUND_TADA, AU_SPECIAL_SOUND_CRICKET, AU_SPECIAL_SOUND_ALARMC, AU_SPECIAL_SOUND_LAST, AU_NONE=0xff }; #if defined(AUDIO) #if defined(CPUARM) #include "audio_arm.h" #else #include "audio_avr.h" #endif #endif #include "buzzer.h" #if defined(PCBSTD) && defined(VOICE) #include "targets/9x/voice.h" #endif #if defined(PCBGRUVIN9X) && defined(VOICE) #include "targets/gruvin9x/voice.h" #endif #if defined(PCBMEGA2560) && defined(VOICE) #include "targets/mega2560/voice.h" #endif #include "translations.h" #include "fonts.h" #if defined(HAPTIC) #include "haptic.h" #endif #if defined(SDCARD) #include "sdcard.h" #endif #if defined(RTCLOCK) #include "rtc.h" #endif #if defined(REVX) void setMFP(); void clearMFP(); #endif #if defined(CPUARM) extern uint8_t requiredSpeakerVolume; #endif #if defined(CPUARM) enum MainRequest { REQUEST_SCREENSHOT, REQUEST_FLIGHT_RESET, }; extern uint8_t mainRequestFlags; #endif void checkBattery(); void opentxClose(uint8_t shutdown=true); void opentxInit(); void opentxResume(); #if defined(PCBHORUS) || defined(PCBX7D) #define LED_ERROR_BEGIN() ledRed() #define LED_ERROR_END() ledBlue() #else #define LED_ERROR_BEGIN() #define LED_ERROR_END() #endif // Re-useable byte array to save having multiple buffers #define SD_SCREEN_FILE_LENGTH (64) union ReusableBuffer { // 275 bytes struct { char listnames[NUM_BODY_LINES][LEN_MODEL_NAME]; #if defined(EEPROM_RLC) && LCD_W < 212 uint16_t eepromfree; #endif #if defined(SDCARD) char menu_bss[POPUP_MENU_MAX_LINES][MENU_LINE_LENGTH]; char mainname[45]; // because reused for SD backup / restore, max backup filename 44 chars: "/MODELS/MODEL0134353-2014-06-19-04-51-27.bin" #else char mainname[LEN_MODEL_NAME]; #endif } modelsel; // 103 bytes struct { int16_t midVals[NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_MOUSE_ANALOGS]; int16_t loVals[NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_MOUSE_ANALOGS]; int16_t hiVals[NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_MOUSE_ANALOGS]; uint8_t state; #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) struct { uint8_t stepsCount; int16_t steps[XPOTS_MULTIPOS_COUNT]; uint8_t lastCount; int16_t lastPosition; } xpotsCalib[NUM_XPOTS]; #endif } calib; #if defined(SDCARD) // 274 bytes struct { char lines[NUM_BODY_LINES][SD_SCREEN_FILE_LENGTH+1+1]; // the last char is used to store the flags (directory) of the line uint32_t available; uint16_t offset; uint16_t count; char originalName[SD_SCREEN_FILE_LENGTH+1]; } sdmanager; #endif #if defined(STM32) struct { char id[27]; } version; #endif struct { uint8_t stickMode; } generalSettings; }; extern union ReusableBuffer reusableBuffer; void checkFlashOnBeep(); #if defined(CPUARM) uint8_t zlen(const char *str, uint8_t size); bool zexist(const char *str, uint8_t size); unsigned int effectiveLen(const char * str, unsigned int size); char * strcat_zchar(char *dest, const char *name, uint8_t size, const char *defaultName=NULL, uint8_t defaultNameSize=0, uint8_t defaultIdx=0); #define strcat_phasename(dest, idx) strcat_zchar(dest, g_model.flightModeData[idx].name, LEN_FLIGHT_MODE_NAME, STR_FP, PSIZE(TR_FP), idx+1) #if defined(EEPROM) #define strcat_modelname(dest, idx) strcat_zchar(dest, modelHeaders[idx].name, LEN_MODEL_NAME, STR_MODEL, PSIZE(TR_MODEL), idx+1) #define strcat_currentmodelname(dest) strcat_modelname(dest, g_eeGeneral.currModel) #else #define strcat_currentmodelname(dest) strcat_zchar(dest, g_model.header.name, LEN_MODEL_NAME) #endif #define ZLEN(s) zlen(s, sizeof(s)) #define ZEXIST(s) zexist(s, sizeof(s)) #endif // Stick tolerance varies between transmitters, Higher is better #if defined (PCB9XR) || defined (PCB9XR128) #define STICK_TOLERANCE 16 #else #define STICK_TOLERANCE 64 #endif #if defined(FRSKY_HUB) && defined(GAUGES) enum BarThresholdIdx { THLD_ALT, THLD_RPM, THLD_FUEL, THLD_T1, THLD_T2, THLD_SPEED, THLD_DIST, THLD_GPSALT, THLD_CELL, THLD_CELLS_SUM, THLD_VFAS, THLD_CURRENT, THLD_CONSUMPTION, THLD_MAX, }; #if defined(CPUARM) typedef uint16_t bar_threshold_t; #define FILL_THRESHOLD(idx, val) barsThresholds[idx] = (val) #else typedef uint8_t bar_threshold_t; #define FILL_THRESHOLD(idx, val) barsThresholds[idx] = 128 + (val) #endif extern bar_threshold_t barsThresholds[THLD_MAX]; #else #define FILL_THRESHOLD(idx, val) #endif #if defined(TELEMETRY_FRSKY) ls_telemetry_value_t minTelemValue(source_t channel); ls_telemetry_value_t maxTelemValue(source_t channel); #else #define minTelemValue(channel) 255 #define maxTelemValue(channel) 255 #endif #if defined(CPUARM) getvalue_t convert16bitsTelemValue(source_t channel, ls_telemetry_value_t value); ls_telemetry_value_t max8bitsTelemValue(source_t channel); #endif getvalue_t convert8bitsTelemValue(source_t channel, ls_telemetry_value_t value); getvalue_t convertLswTelemValue(LogicalSwitchData * cs); #if defined(CPUARM) #define convertTelemValue(channel, value) convert16bitsTelemValue(channel, value) #define convertBarTelemValue(channel, value) convert8bitsTelemValue(channel, value) #define maxBarTelemValue(channel) max8bitsTelemValue(channel) #else #define convertTelemValue(channel, value) convert8bitsTelemValue(channel, value) #define convertBarTelemValue(channel, value) convert8bitsTelemValue(channel, value) #define maxBarTelemValue(channel) maxTelemValue(channel) #endif #if defined(TELEMETRY_FRSKY) || defined(CPUARM) lcdint_t applyChannelRatio(source_t channel, lcdint_t val); #define ANA_CHANNEL_UNIT(channel) g_model.frsky.channels[channel].type #endif inline int div_and_round(int num, int den) { if (den == 0) { return 0; } else if (num >= 0) { num += den / 2; } else { num -= den / 2; } return num / den; } #if defined(TELEMETRY_FRSKY) NOINLINE uint8_t getRssiAlarmValue(uint8_t alarm); extern const pm_uint8_t bchunit_ar[]; #if defined(CPUARM) #define FRSKY_MULTIPLIER_MAX 5 #else #define FRSKY_MULTIPLIER_MAX 3 #endif enum TelemetryViews { TELEMETRY_CUSTOM_SCREEN_1, TELEMETRY_CUSTOM_SCREEN_2, #if defined(CPUARM) TELEMETRY_CUSTOM_SCREEN_3, TELEMETRY_CUSTOM_SCREEN_4, TELEMETRY_VIEW_MAX = TELEMETRY_CUSTOM_SCREEN_4 #else TELEMETRY_VOLTAGES_SCREEN, TELEMETRY_AFTER_FLIGHT_SCREEN, TELEMETRY_VIEW_MAX = TELEMETRY_AFTER_FLIGHT_SCREEN #endif }; extern uint8_t s_frsky_view; #endif #define EARTH_RADIUSKM ((uint32_t)6371) #define EARTH_RADIUS ((uint32_t)111194) void getGpsPilotPosition(); void getGpsDistance(); void varioWakeup(); #if defined(AUDIO) && defined(BUZZER) #define IS_SOUND_OFF() (g_eeGeneral.buzzerMode==e_mode_quiet && g_eeGeneral.beepMode==e_mode_quiet) #else #define IS_SOUND_OFF() (g_eeGeneral.beepMode == e_mode_quiet) #endif #if defined(CPUARM) #define IS_IMPERIAL_ENABLE() (g_eeGeneral.imperial) #elif defined(IMPERIAL_UNITS) #define IS_IMPERIAL_ENABLE() (1) #else #define IS_IMPERIAL_ENABLE() (0) #endif #if defined(CPUARM) #elif defined(TELEMETRY_FRSKY) FORCEINLINE void convertUnit(getvalue_t & val, uint8_t & unit) { if (IS_IMPERIAL_ENABLE()) { if (unit == UNIT_TEMPERATURE) { val += 18; val *= 115; val >>= 6; } if (unit == UNIT_DIST) { // m to ft *105/32 val = val * 3 + (val >> 2) + (val >> 5); } if (unit == UNIT_FEET) { unit = UNIT_DIST; } if (unit == UNIT_KTS) { // kts to mph unit = UNIT_SPEED; val = (val * 23) / 20; } } else { if (unit == UNIT_KTS) { // kts to km/h unit = UNIT_SPEED; val = (val * 50) / 27; } } if (unit == UNIT_HDG) { unit = UNIT_TEMPERATURE; } } #else #define convertUnit(...) #endif #if !defined(CPUARM) #define IS_USR_PROTO_FRSKY_HUB() (g_model.frsky.usrProto == USR_PROTO_FRSKY) #define IS_USR_PROTO_WS_HOW_HIGH() (g_model.frsky.usrProto == USR_PROTO_WS_HOW_HIGH) #endif #if defined(TELEMETRY_FRSKY) && defined(FRSKY_HUB) && defined(GPS) #define IS_GPS_AVAILABLE() IS_USR_PROTO_FRSKY_HUB() #else #define IS_GPS_AVAILABLE() (0) #endif #if defined(PCBTARANIS) extern const pm_uchar logo_taranis[]; #endif #if defined(USB_MASS_STORAGE) void usbPluggedIn(); #endif #include "lua/lua_api.h" #if defined(SDCARD) enum ClipboardType { CLIPBOARD_TYPE_NONE, CLIPBOARD_TYPE_CUSTOM_SWITCH, CLIPBOARD_TYPE_CUSTOM_FUNCTION, CLIPBOARD_TYPE_SD_FILE, }; #if defined(SIMU) #define CLIPBOARD_PATH_LEN 1024 #else #define CLIPBOARD_PATH_LEN 32 #endif struct Clipboard { ClipboardType type; union { LogicalSwitchData csw; CustomFunctionData cfn; struct { char directory[CLIPBOARD_PATH_LEN]; char filename[CLIPBOARD_PATH_LEN]; } sd; } data; }; extern Clipboard clipboard; #endif #if !defined(SIMU) extern uint16_t s_anaFilt[NUMBER_ANALOG]; #endif #if defined(JITTER_MEASURE) extern JitterMeter rawJitter[NUMBER_ANALOG]; extern JitterMeter avgJitter[NUMBER_ANALOG]; #if defined(PCBHORUS) #define JITTER_MEASURE_ACTIVE() (menuHandlers[menuLevel] == menuStatsAnalogs) #elif defined(PCBTARANIS) #define JITTER_MEASURE_ACTIVE() (menuHandlers[menuLevel] == menuRadioDiagAnalogs) #elif defined(CLI) #define JITTER_MEASURE_ACTIVE() (1) #else #define JITTER_MEASURE_ACTIVE() (0) #endif #endif #if defined(INTERNAL_GPS) #include "gps.h" #endif #endif // _OPENTX_H_