/* * 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. * */ #ifndef opentx_h #define opentx_h #include #include #include #include // TODO change all IF_xxx by CASE_xxx when used with a comma! #if defined(PCBSKY9X) #define IF_PCBSKY9X(x) x, #else #define IF_PCBSKY9X(x) #endif #if defined(PCBTARANIS) #define IS_PCBTARANIS() true #define IF_PCBTARANIS(x) (x) #define CASE_PCBTARANIS(x) x, #define IF_9X(x) (0) #define CASE_9X(x) #else #define IS_PCBTARANIS() false #define IF_PCBTARANIS(x) (0) #define CASE_PCBTARANIS(x) #define IF_9X(x) (x) #define CASE_9X(x) x, #endif #if defined(CPUARM) #define IF_CPUARM(x) x, #else #define IF_CPUARM(x) #endif #if defined(LUA) #define IF_LUA(x) x, #else #define IF_LUA(x) #endif #if defined(BATTGRAPH) || defined(PCBTARANIS) #define IF_BATTGRAPH(x) x, #else #define IF_BATTGRAPH(x) #endif #if defined(CPUARM) || defined(CPUM2560) #define IF_PERSISTENT_TIMERS(x) x, #else #define IF_PERSISTENT_TIMERS(x) #endif #if defined(RTCLOCK) #define IF_RTCLOCK(x) x, #else #define IF_RTCLOCK(x) #endif #if defined(BUZZER) #define IF_BUZZER(x) x, #else #define IF_BUZZER(x) #endif #if defined(AUDIO) #define IF_AUDIO(x) x, #else #define IF_AUDIO(x) #endif #if defined(VOICE) #define IF_VOICE(x) x, #else #define IF_VOICE(x) #endif #if defined(PWM_BACKLIGHT) #define CASE_PWM_BACKLIGHT(x) x, #else #define CASE_PWM_BACKLIGHT(x) #endif #if defined(FRSKY) && defined(FRSKY_HUB) && defined(GPS) #define IF_GPS(x) x, #else #define IF_GPS(x) #endif #if defined(VARIO) #define IF_VARIO(x) x, #else #define IF_VARIO(x) #endif #if defined(HAPTIC) #define IF_HAPTIC(x) x, #else #define IF_HAPTIC(x) #endif #if defined(SPLASH) #define IF_SPLASH(x) x, #else #define IF_SPLASH(x) #endif #if defined(FRSKY) #define IF_FRSKY(x) x, #else #define IF_FRSKY(x) #endif #if defined(MAVLINK) #define IF_MAVLINK(x) x, #else #define IF_MAVLINK(x) #endif #if defined(PXX) #define IF_PXX(x) x, #else #define IF_PXX(x) #endif #if defined(SDCARD) #define IF_SDCARD(x) x, #else #define IF_SDCARD(x) #endif #if defined(BLUETOOTH) #define IF_BLUETOOTH(x) x, #else #define IF_BLUETOOTH(x) #endif #if defined(HELI) #define IF_HELI(x) x, #else #define IF_HELI(x) #endif #if defined(TEMPLATES) #define IF_TEMPLATES(x) x, #else #define IF_TEMPLATES(x) #endif #if defined(FLIGHT_MODES) #define IF_FLIGHT_MODES(x) x, #else #define IF_FLIGHT_MODES(x) #endif #if defined(CURVES) #define IF_CURVES(x) x, #else #define IF_CURVES(x) #endif #if defined(GVARS) #define IF_GVARS(x) x, #else #define IF_GVARS(x) #endif #if ROTARY_ENCODERS > 0 #define ROTARY_ENCODER_NAVIGATION #endif #if defined(SIMU) || defined(CPUARM) || GCC_VERSION < 472 typedef int32_t int24_t; #else typedef __int24 int24_t; #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-1+TELEM_A2-1) #if defined(SIMU) #ifndef FORCEINLINE #define FORCEINLINE #endif #if !defined(NOINLINE) #define NOINLINE #endif #define CONVERT_PTR(x) ((uint32_t)(uint64_t)(x)) char *convertSimuPath(const char *path); #else #define FORCEINLINE inline __attribute__ ((always_inline)) #define NOINLINE __attribute__ ((noinline)) #define SIMU_SLEEP(x) #define CONVERT_PTR(x) ((uint32_t)(x)) #define convertSimuPath(x) (x) #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 #if defined(PCBTARANIS) #include "targets/taranis/board_taranis.h" #elif defined(PCBSKY9X) #include "targets/sky9x/board_sky9x.h" #elif defined(PCBGRUVIN9X) #include "targets/gruvin9x/board_gruvin9x.h" #elif defined(PCBMEGA2560) #include "targets/mega2560/board_mega2560.h" #else #include "targets/stock/board_stock.h" #endif #include "debug.h" #if defined(SIMU) #include "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() extern void boardInit(); #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 #define NUM_STICKS 4 enum EnumKeys { KEY_MENU, KEY_EXIT, #if defined(PCBTARANIS) KEY_ENTER, KEY_PAGE, KEY_PLUS, KEY_MINUS, #else KEY_DOWN, KEY_UP, KEY_RIGHT, KEY_LEFT, #endif TRM_BASE, TRM_LH_DWN = TRM_BASE, TRM_LH_UP, TRM_LV_DWN, TRM_LV_UP, TRM_RV_DWN, TRM_RV_UP, TRM_RH_DWN, TRM_RH_UP, #if ROTARY_ENCODERS > 0 || defined(ROTARY_ENCODER_NAVIGATION) BTN_REa, #endif #if ROTARY_ENCODERS > 0 BTN_REb, #endif NUM_KEYS, SW_BASE=NUM_KEYS, #if defined(PCBTARANIS) SW_SA0=SW_BASE, SW_SA1, SW_SA2, SW_SB0, SW_SB1, SW_SB2, SW_SC0, SW_SC1, SW_SC2, SW_SD0, SW_SD1, SW_SD2, SW_SE0, SW_SE1, SW_SE2, SW_SF0, SW_SF2, SW_SG0, SW_SG1, SW_SG2, SW_SH0, SW_SH2, #else SW_ID0=SW_BASE, SW_ID1, SW_ID2, #if defined(EXTRA_3POS) SW_ID3, SW_ID4, SW_ID5, #endif SW_THR, SW_RUD, SW_ELE, SW_AIL, SW_GEA, SW_TRN, #endif }; #if defined(PCBTARANIS) #define NUM_SWITCHES 8 #define IS_3POS(sw) ((sw) != 5 && (sw) != 7) #define NUM_POTS 4 #define NUM_XPOTS 2 #define NUM_SW_SRCRAW 8 #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 SW_DSM2_BIND SW_SH2 #else #define NUM_SWITCHES 7 #define IS_3POS(sw) ((sw) == 0) #define IS_MOMENTARY(sw) (sw == SWSRC_TRN) #define NUM_POTS 3 #define NUM_XPOTS 0 #define NUM_SW_SRCRAW 1 #define SW_DSM2_BIND SW_TRN #endif #define NUM_PSWITCH (SWSRC_LAST_SWITCH-SWSRC_FIRST_SWITCH+1) #define NUM_POTSSW (NUM_XPOTS*6) #define NUM_SWITCH (NUM_PSWITCH+NUM_CSW+NUM_POTSSW) #if defined(PCBTARANIS) #define KEY_RIGHT KEY_PLUS #define KEY_LEFT KEY_MINUS #define KEY_UP KEY_PLUS #define KEY_DOWN KEY_MINUS #else #define KEY_ENTER KEY_MENU #define KEY_PLUS KEY_RIGHT #define KEY_MINUS KEY_LEFT #endif #include "myeeprom.h" #if defined(PCBTARANIS) #define IS_MULTIPOS_POT(x) ((x)>=POT1 && (x)<=POT_LAST && (g_eeGeneral.potsType & (1 << ((x)-POT1)))) #else #define IS_MULTIPOS_POT(x) (false) #endif #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" // This doesn't need protection on this processor #define tmr10ms_t uint32_t extern volatile tmr10ms_t g_tmr10ms; #define get_tmr10ms() g_tmr10ms typedef int32_t rotenc_t; typedef int32_t getvalue_t; #else #define tmr10ms_t uint16_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; void watchdogSetTimeout(uint32_t timeout); #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 #include "eeprom_common.h" #if defined(PCBSKY9X) #include "eeprom_raw.h" #else #include "eeprom_rlc.h" #endif #if defined(CPUARM) #include "protocols/pulses_arm.h" #else #include "protocols/pulses_avr.h" #endif #if defined(PCBTARANIS) #define MODEL_BITMAP_WIDTH 64 #define MODEL_BITMAP_HEIGHT 32 #define MODEL_BITMAP_SIZE (2+4*(MODEL_BITMAP_WIDTH*MODEL_BITMAP_HEIGHT/8)) extern uint8_t modelBitmap[MODEL_BITMAP_SIZE]; void loadModelBitmap(char *name, uint8_t *bitmap); #define LOAD_MODEL_BITMAP() loadModelBitmap(g_model.header.bitmap, modelBitmap) #else #define LOAD_MODEL_BITMAP() #endif #if defined(PCBTARANIS) void loadCurves(); #define LOAD_MODEL_CURVES() loadCurves() #else #define LOAD_MODEL_CURVES() #endif // TODO elsewhere ... #if defined(DSM2) #define DSM2_BIND_FLAG 0x80 #define DSM2_RANGECHECK_FLAG 0x20 extern uint8_t dsm2Flag; #if !defined(PCBTARANIS) extern uint8_t s_bind_allowed; #endif #endif #if defined(CPUARM) #define IS_PPM_PROTOCOL(protocol) (protocol==PROTO_PPM) #else #define IS_PPM_PROTOCOL(protocol) (protocol<=PROTO_PPMSIM) #endif #if defined(PXX) #define IS_PXX_PROTOCOL(protocol) (protocol==PROTO_PXX) #else #define IS_PXX_PROTOCOL(protocol) (0) #endif #if defined(DSM2) #define IS_DSM2_PROTOCOL(protocol) (protocol>=PROTO_DSM2_LP45 && protocol<=PROTO_DSM2_DSMX) #else #define IS_DSM2_PROTOCOL(protocol) (0) #endif #if defined(DSM2_SERIAL) #define IS_DSM2_SERIAL_PROTOCOL(protocol) (IS_DSM2_PROTOCOL(protocol)) #else #define IS_DSM2_SERIAL_PROTOCOL(protocol) (0) #endif #if defined(PCBTARANIS) static const int8_t maxChannelsModules[] = { 0, 8, 8, 0, -2 }; static const int8_t maxChannelsXJT[] = { 0, 8, 0, 4 }; #define IS_MODULE_XJT(idx) ((idx==0 || g_model.externalModule == MODULE_TYPE_XJT) && (g_model.moduleData[idx].rfProtocol != RF_PROTO_OFF)) #define IS_MODULE_PPM(idx) (idx==2 || (idx==1 && g_model.externalModule == MODULE_TYPE_PPM)) #if defined(DSM2) #define IS_MODULE_DSM2(idx) (idx==1 && g_model.externalModule == MODULE_TYPE_DSM2) #else #define IS_MODULE_DSM2(idx) false #endif #define NUM_CHANNELS(idx) (8+g_model.moduleData[idx].channelsCount) #define MAX_PORT1_CHANNELS() (maxChannelsXJT[1+g_model.moduleData[0].rfProtocol]) #define MAX_PORT2_CHANNELS() ((g_model.externalModule == MODULE_TYPE_XJT) ? maxChannelsXJT[1+g_model.moduleData[1].rfProtocol] : maxChannelsModules[g_model.externalModule]) #define MAX_TRAINER_CHANNELS() (8) #define MAX_CHANNELS(idx) (idx==0 ? MAX_PORT1_CHANNELS() : (idx==1 ? MAX_PORT2_CHANNELS() : MAX_TRAINER_CHANNELS())) #elif defined(PCBSKY9X) #define NUM_PORT1_CHANNELS() (IS_PXX_PROTOCOL(g_model.protocol) ? 8 : (IS_DSM2_PROTOCOL(g_model.protocol) ? 6 : (8+g_model.moduleData[0].channelsCount))) #define NUM_PORT2_CHANNELS() (8+g_model.moduleData[1].channelsCount) #define NUM_CHANNELS(idx) (idx==0 ? NUM_PORT1_CHANNELS() : (8+g_model.moduleData[idx].channelsCount)) #endif #include "lcd.h" #include "gui/menus.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[]; extern uint8_t stickMode; //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*stickMode + (x)) : (x) ) extern uint8_t channel_order(uint8_t x); class Key { #define FILTERBITS 4 #ifdef SIMU #define FFVAL 1 #else #define FFVAL ((1< 0; } void pauseEvents() { m_state = KSTATE_PAUSE; m_cnt = 0; } void killEvents() { m_state = KSTATE_KILLED; } }; extern Key keys[NUM_KEYS]; enum BaseCurves { CURVE_NONE, CURVE_X_GT0, CURVE_X_LT0, CURVE_ABS_X, CURVE_F_GT0, CURVE_F_LT0, CURVE_ABS_F, CURVE_BASE }; #define SWASH_TYPE_120 1 #define SWASH_TYPE_120X 2 #define SWASH_TYPE_140 3 #define SWASH_TYPE_90 4 #define SWASH_TYPE_NUM 4 enum CswFunctions { CS_OFF, CS_VEQUAL, // v==offset CS_VPOS, // v>offset CS_VNEG, // voffset CS_ANEG, // |v|= 0x0e) #define CASE_EVT_ROTARY_BREAK case EVT_ROTARY_BREAK: #define CASE_EVT_ROTARY_LONG case EVT_ROTARY_LONG: #define CASE_EVT_ROTARY_LEFT case EVT_ROTARY_LEFT: #define CASE_EVT_ROTARY_RIGHT case EVT_ROTARY_RIGHT: #else #define IS_ROTARY_LEFT(evt) (0) #define IS_ROTARY_RIGHT(evt) (0) #define IS_ROTARY_UP(evt) (0) #define IS_ROTARY_DOWN(evt) (0) #define IS_ROTARY_BREAK(evt) (0) #define IS_ROTARY_LONG(evt) (0) #define IS_ROTARY_EVENT(evt) (0) #define CASE_EVT_ROTARY_BREAK #define CASE_EVT_ROTARY_LONG #define CASE_EVT_ROTARY_LEFT #define CASE_EVT_ROTARY_RIGHT #endif #if defined(PCBTARANIS) #define IS_RE_NAVIGATION_ENABLE() true #define NAVIGATION_RE_IDX() 0 #elif defined(ROTARY_ENCODERS) #define NAVIGATION_RE_IDX() (g_eeGeneral.reNavigation - 1) #define IS_RE_NAVIGATION_ENABLE() g_eeGeneral.reNavigation #elif defined(ROTARY_ENCODER_NAVIGATION) #define IS_RE_NAVIGATION_ENABLE() true #define NAVIGATION_RE_IDX() 0 #endif #define HEART_TIMER_10MS 1 #define HEART_TIMER_PULSES 2 // when multiple modules this is the first one #if defined(PCBTARANIS) #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) void watchdogSetTimeout(uint32_t timeout); #endif #define MAX_ALERT_TIME 60 struct t_inactivity { uint16_t counter; uint8_t sum; }; extern struct t_inactivity inactivity; #if defined(PXX) extern uint8_t pxxFlag[NUM_MODULES]; #endif #define PXX_SEND_RXNUM 0x01 #define PXX_SEND_FAILSAFE (1 << 4) #define PXX_SEND_RANGECHECK (1 << 5) #define LEN_STD_CHARS 40 #define ZCHAR_MAX (LEN_STD_CHARS + LEN_SPECIAL_CHARS) char idx2char(int8_t idx); #if defined(PCBTARANIS) int8_t char2idx(char c); void str2zchar(char *dest, const char *src, int size); void zchar2str(char *dest, const char *src, int size); #endif extern uint8_t s_evt; #define putEvent(evt) s_evt = evt void clearKeyEvents(); void pauseEvents(uint8_t enuk); void killEvents(uint8_t enuk); #if defined(CPUARM) uint8_t getEvent(bool trim); #else uint8_t getEvent(); #endif uint8_t keyDown(); enum PowerState { e_power_on, e_power_trainer, e_power_usb, e_power_off }; bool switchState(EnumKeys enuk); void readKeysAndTrims(); uint16_t evalChkSum(); #if defined(VOICE) #define MESSAGE_SOUND_ARG , uint8_t sound #define MESSAGE(title, msg, info, sound) message(title, msg, info, sound) #define ALERT(title, msg, sound) alert(title, msg, sound) #else #define MESSAGE_SOUND_ARG #define MESSAGE(title, msg, info, sound) message(title, msg, info) #define ALERT(title, msg, sound) alert(title, msg) #endif extern void message(const pm_char *title, const pm_char *s, const char *last MESSAGE_SOUND_ARG); extern void alert(const pm_char * t, const pm_char * s MESSAGE_SOUND_ARG); enum PerOutMode { e_perout_mode_normal = 0, e_perout_mode_inactive_phase = 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 }; // 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 s_perout_flight_phase; #if defined(CPUARM) #define bitfield_channels_t uint32_t #else #define bitfield_channels_t uint16_t #endif #if defined(CPUARM) && !defined(SIMU) extern unsigned char *heap; extern int _end; extern unsigned char *_estack; #endif void perOut(uint8_t mode, uint8_t tick10ms); void perMain(); NOINLINE void per10ms(); getvalue_t getValue(uint8_t i); bool getSwitch(int8_t swtch); extern swstate_t switches_states; int8_t getMovedSwitch(); #if defined(PCBTARANIS) #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 getFlightPhase(); #else #define getFlightPhase() 0 #endif extern uint8_t getTrimFlightPhase(uint8_t phase, uint8_t idx); extern int16_t getRawTrimValue(uint8_t phase, uint8_t idx); extern int16_t getTrimValue(uint8_t phase, uint8_t idx); extern void setTrimValue(uint8_t phase, uint8_t idx, int16_t trim); #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(CPUARM) #define ROTARY_ENCODER_GRANULARITY (2 << g_eeGeneral.rotarySteps) #else #define ROTARY_ENCODER_GRANULARITY (2) #endif #if defined(GVARS) #if defined(PCBSTD) int16_t getGVarValue(int16_t x, int16_t min, int16_t max); void setGVarValue(uint8_t x, int8_t value); #define GET_GVAR(x, min, max, p) getGVarValue(x, min, max) #define SET_GVAR(idx, val, p) setGVarValue(idx, val) #else uint8_t getGVarFlightPhase(uint8_t phase, uint8_t idx); int16_t getGVarValue(int16_t x, int16_t min, int16_t max, int8_t phase); void setGVarValue(uint8_t x, int16_t value, int8_t phase); #define GET_GVAR(x, min, max, p) getGVarValue(x, min, max, p) #define SET_GVAR(idx, val, p) setGVarValue(idx, val, p) #define GVAR_DISPLAY_TIME 100 /*1 second*/; extern uint8_t s_gvar_timer; extern uint8_t s_gvar_last; #endif #else #define GET_GVAR(x, ...) (x) #endif #if defined(CPUARM) #define GV1_SMALL 128 #define GV1_LARGE 4096 #define GV_GET_GV1_VALUE(max) ( (max<=GV_RANGESMALL && min>=GV_RANGESMALL_NEG) ? GV1_SMALL : GV1_LARGE ) #define GV_INDEX_CALCULATION(x,max) ( (max<=GV_RANGESMALL && min>=GV_RANGESMALL_NEG) ? (uint8_t) x-GV1_SMALL : ((x&(GV1_LARGE*2-1))-GV1_LARGE) ) #else #define GV1_SMALL 128 #define GV1_LARGE 256 #define GV_GET_GV1_VALUE(max) ( (max<=GV_RANGESMALL) ? GV1_SMALL : GV1_LARGE ) #define GV_INDEX_CALCULATION(x,max) ( (max<=GV1_SMALL) ? (uint8_t) x-GV1_SMALL : ((x&(GV1_LARGE*2-1))-GV1_LARGE) ) #endif #define GV_IS_GV_VALUE(x,min,max) ( (x>max) || (xCNT; } #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 stack_free(uint8_t tid); #else uint16_t stack_free(); #endif #if defined(CPUM64) void memclear(void *ptr, uint8_t size); #else #define memclear(p, s) memset(p, 0, s) #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(); #define ADC_VREF_TYPE 0x40 // AVCC with external capacitor at AREF pin #if !defined(SIMU) void getADC(); #endif extern void backlightOn(); enum Analogs { STICK1, STICK2, STICK3, STICK4, #if defined(PCBTARANIS) POT1, POT2, POT_LAST = POT2, SLIDER1, SLIDER2, #else POT1, POT2, POT3, POT_LAST = POT3, #endif TX_VOLTAGE, #if defined(PCBSKY9X) && !defined(REVA) TX_CURRENT, #endif NUMBER_ANALOG }; #if defined(PCBSTD) && defined(VOICE) && !defined(SIMU) #define BACKLIGHT_ON() (Voice.Backlight = 1) #define BACKLIGHT_OFF() (Voice.Backlight = 0) #else #define BACKLIGHT_ON() __BACKLIGHT_ON #define BACKLIGHT_OFF() __BACKLIGHT_OFF #endif #define BUZZER_ON PORTE |= (1 << OUT_E_BUZZER) #define BUZZER_OFF PORTE &= ~(1 << OUT_E_BUZZER) #if defined(HAPTIC) #if defined(PCBSKY9X) #define HAPTIC_OFF hapticOff() #elif defined(PCBGRUVIN9X) #define HAPTIC_ON PORTD &= ~(1 << OUT_D_HAPTIC) #define HAPTIC_OFF PORTD |= (1 << OUT_D_HAPTIC) #else #define HAPTIC_ON PORTG |= (1 << OUT_G_HAPTIC) #define HAPTIC_OFF PORTG &= ~(1 << OUT_G_HAPTIC) #endif #else #define HAPTIC_ON #define HAPTIC_OFF #endif #define BITMASK(bit) (1<<(bit)) /// liefert Dimension eines Arrays #define DIM(arr) (sizeof((arr))/sizeof((arr)[0])) /// liefert Betrag des Arguments template FORCEINLINE t abs(t a) { return a>0?a:-a; } /// liefert das Minimum der Argumente 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; } #if defined(HELI) || defined(FRSKY_HUB) uint16_t isqrt32(uint32_t n); #endif #if defined(CPUARM) #if !defined(SIMU) extern "C" { #include } #endif extern OS_MutexID mixerMutex; inline void pauseMixerCalculations() { CoEnterMutexSection(mixerMutex); } inline void resumeMixerCalculations() { CoLeaveMutexSection(mixerMutex); } #else #define pauseMixerCalculations() #define resumeMixerCalculations() #endif #if defined(CPUARM) || defined(CPUM2560) void saveTimers(); #else #define saveTimers() #endif void generalDefault(); void modelDefault(uint8_t id); #if defined(PXX) && defined(CPUARM) void checkModelIdUnique(uint8_t id); #endif #if defined(CPUARM) inline int divRoundClosest(const int n, const int d) { 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(register int x) { return divRoundClosest(x*256, 100); } inline int calc100toRESX(register int x) { return divRoundClosest(x*RESX, 100); } inline int calc1000toRESX(register int x) { return divRoundClosest(x*RESX, 1000); } inline int calcRESXto1000(register int x) { return divRoundClosest(x*1000, RESX); } inline int calcRESXto100(register 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 #define TMR_VAROFS 5 extern const char stamp1[]; extern const char stamp2[]; extern const char stamp3[]; extern const char eeprom_stamp[]; extern uint8_t g_vbat100mV; #define g_blinkTmr10ms (*(uint8_t*)&g_tmr10ms) extern uint8_t g_beepCnt; extern uint8_t g_beepVal[5]; extern uint8_t ppmInState; //0=unsync 1..8= wait for value i-1 extern int16_t g_ppmIns[8]; extern int32_t chans[NUM_CHNOUT]; extern int16_t ex_chans[NUM_CHNOUT]; // Outputs (before LIMITS) of the last perMain extern int16_t channelOutputs[NUM_CHNOUT]; extern uint16_t BandGap; #if defined(PCBTARANIS) #define NUM_INPUTS (MAX_INPUTS) #else #define NUM_INPUTS (NUM_STICKS) #endif int intpol(int x, uint8_t idx); int expo(int x, int k); int applyCurve(int x, int8_t idx); #if defined(PCBTARANIS) int applyCustomCurve(int x, uint8_t idx); #else #define applyCustomCurve(x, idx) intpol(x, idx) #endif #if defined(PCBTARANIS) #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 void applyExpos(int16_t *anas, uint8_t mode APPLY_EXPOS_EXTRA_PARAMS_INC); int16_t applyLimits(uint8_t channel, int32_t value); uint16_t anaIn(uint8_t chan); int16_t thrAnaIn(uint8_t chan); extern int16_t calibratedStick[NUM_STICKS+NUM_POTS]; #define FLASH_DURATION 20 /*200ms*/ extern uint8_t beepAgain; extern uint16_t lightOffCounter; extern uint8_t flashCounter; extern uint8_t mixWarning; PhaseData *phaseAddress(uint8_t idx); ExpoData *expoAddress(uint8_t idx); MixData *mixAddress(uint8_t idx); LimitData *limitAddress(uint8_t idx); int8_t *curveAddress(uint8_t idx); CustomSwData *cswAddress(uint8_t idx); #if !defined(PCBTARANIS) struct CurveInfo { int8_t *crv; uint8_t points; bool custom; }; extern CurveInfo curveInfo(uint8_t idx); #endif extern int8_t s_currCh; uint8_t getExpoMixCount(uint8_t expo); void deleteExpoMix(uint8_t expo, uint8_t idx); void insertExpoMix(uint8_t expo, uint8_t idx); void applyDefaultTemplate(); void incSubtrim(uint8_t idx, int16_t inc); void instantTrim(); void copyTrimsToOffset(uint8_t ch); void moveTrimsToOffsets(); #if defined(CPUARM) #define ACTIVE_PHASES_TYPE uint16_t #define DELAY_POS_SHIFT 0 #define delayval_t int16_t PACK(typedef struct t_SwOn { 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 delayval_t int8_t PACK(typedef struct t_SwOn { 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]; #ifdef 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 #if defined(CPUARM) #define MASK_CFN_TYPE uint32_t // current max = 32 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 uint16_t // current max = 16 functions #else #define MASK_CFN_TYPE uint32_t // current max = 32 function switches #define MASK_FUNC_TYPE uint16_t // current max = 16 functions #endif extern MASK_CFN_TYPE activeSwitches; extern MASK_CFN_TYPE activeFnSwitches; extern MASK_FUNC_TYPE activeFunctions; extern tmr10ms_t lastFunctionTime[NUM_CFN]; #if defined(CPUARM) extern bool evalFunctionsFirstTime; #endif inline bool isFunctionActive(uint8_t func) { return activeFunctions & ((MASK_FUNC_TYPE)1 << (func-FUNC_TRAINER)); } #if defined(ROTARY_ENCODERS) // Global rotary encoder registers extern volatile rotenc_t g_rotenc[ROTARY_ENCODERS]; #elif defined(ROTARY_ENCODER_NAVIGATION) extern volatile rotenc_t g_rotenc[1]; #endif #if defined(FRSKY_SPORT) // FrSky SPORT Telemetry #include "telemetry/frsky_sport.h" #elif defined (FRSKY) // FrSky Telemetry #include "telemetry/frsky.h" #elif defined(JETI) // Jeti-DUPLEX Telemetry #include "telemetry/jeti.h" #elif defined(ARDUPILOT) // ArduPilot Telemetry #include "telemetry/ardupilot.h" #elif defined(NMEA) // NMEA Telemetry #include "telemetry/nmea.h" #elif defined(MAVLINK) // Mavlink Telemetry #include "telemetry/mavlink.h" #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 */ /* make sure the defines below always go in numeric order */ enum AUDIO_SOUNDS { AU_TADA, #if defined(VOICE) AU_THROTTLE_ALERT, AU_SWITCH_ALERT, AU_BAD_EEPROM, AU_EEPROM_FORMATTING, #endif AU_TX_BATTERY_LOW, AU_INACTIVITY, #if defined(PCBSKY9X) AU_TX_MAH_HIGH, AU_TX_TEMP_HIGH, #endif AU_ERROR, AU_KEYPAD_UP, AU_KEYPAD_DOWN, AU_MENUS, AU_TRIM_MOVE, AU_WARNING1, AU_WARNING2, AU_WARNING3, AU_TRIM_MIDDLE, #if defined(CPUARM) AU_TRIM_END, #endif #if defined(PCBTARANIS) AU_STICK1_MIDDLE, AU_STICK2_MIDDLE, AU_STICK3_MIDDLE, AU_STICK4_MIDDLE, AU_POT1_MIDDLE, AU_POT2_MIDDLE, AU_SLIDER1_MIDDLE, AU_SLIDER2_MIDDLE, #elif defined(CPUARM) AU_STICK1_MIDDLE, AU_STICK2_MIDDLE, AU_STICK3_MIDDLE, AU_STICK4_MIDDLE, 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, AU_TIMER_00, AU_TIMER_LT10, AU_TIMER_20, AU_TIMER_30, #if defined(PCBTARANIS) AU_A1_ORANGE, AU_A1_RED, AU_A2_ORANGE, AU_A2_RED, AU_RSSI_ORANGE, AU_RSSI_RED, AU_SWR_RED, #endif #if defined(CPUARM) AU_TELEMETRY_LOST, AU_TELEMETRY_BACK, #endif AU_FRSKY_FIRST, AU_FRSKY_BEEP1 = AU_FRSKY_FIRST, AU_FRSKY_BEEP2, AU_FRSKY_BEEP3, AU_FRSKY_WARN1, AU_FRSKY_WARN2, AU_FRSKY_CHEEP, AU_FRSKY_RATATA, AU_FRSKY_TICK, AU_FRSKY_SIREN, AU_FRSKY_RING, AU_FRSKY_SCIFI, AU_FRSKY_ROBOT, AU_FRSKY_CHIRP, AU_FRSKY_TADA, AU_FRSKY_CRICKET, AU_FRSKY_ALARMC, AU_FRSKY_LAST, AU_NONE=0xff }; #if defined(AUDIO) #if defined(CPUARM) #include "audio_arm.h" #else #include "audio_avr.h" #endif #endif #if defined(BUZZER) #include "buzzer.h" #endif #if defined(PCBSTD) && defined(VOICE) #include "targets/stock/voice.h" #endif #if defined(PCBGRUVIN9X) && defined(VOICE) #include "targets/gruvin9x/somo14d.h" #endif #include "translations.h" #if defined(HAPTIC) #include "haptic.h" #endif #if defined(SDCARD) #include "sdcard.h" #endif #if defined(RTCLOCK) #include "rtc.h" #endif #if defined(LUA) struct ScriptInput { const char *name; uint8_t type; int16_t min; int16_t max; int16_t def; }; struct ScriptOutput { const char *name; int16_t value; }; enum ScriptState { SCRIPT_OK, SCRIPT_NOFILE, SCRIPT_SYNTAX_ERROR, SCRIPT_KILLED, SCRIPT_LEAK }; struct ScriptInternalData { uint8_t state; int run; uint8_t instructions; uint8_t memory; uint8_t inputsCount; ScriptInput inputs[MAX_SCRIPT_INPUTS]; uint8_t outputsCount; ScriptOutput outputs[MAX_SCRIPT_OUTPUTS]; }; #define LUASTATE_STANDALONE_SCRIPT_RUNNING 1 #define LUASTATE_RELOAD_MODEL_SCRIPTS 2 extern uint8_t luaState; extern ScriptInternalData scriptInternalData[MAX_SCRIPTS]; extern ScriptInternalData standaloneScript; void luaInit(); void luaTask(uint8_t evt); void luaExec(const char *filename); void luaLoadModelScript(uint8_t index); void luaLoadModelScripts(); #define luaGetMemUsed(idx) scriptInternalData[idx].memory #define luaGetCpuUsed(idx) scriptInternalData[idx].instructions #define LUA_INIT() #define LUA_RESET() luaInit() #define LUA_LOAD_MODEL_SCRIPTS() luaState |= LUASTATE_RELOAD_MODEL_SCRIPTS #define LUA_LOAD_MODEL_SCRIPT(idx) luaState |= LUASTATE_RELOAD_MODEL_SCRIPTS #else #define LUA_INIT() #define LUA_RESET() #define LUA_LOAD_MODEL_SCRIPTS() #define LUA_LOAD_MODEL_SCRIPT(idx) #endif #if defined(CPUARM) extern uint8_t requiredSpeakerVolume; #endif // Re-useable byte array to save having multiple buffers #define SD_SCREEN_FILE_LENGTH (32) union ReusableBuffer { struct { char listnames[LCD_LINES-1][LEN_MODEL_NAME]; uint16_t eepromfree; #if defined(SDCARD) char menu_bss[MENU_MAX_LINES][MENU_LINE_LENGTH]; char mainname[42]; // because reused for SD backup / restore #else char mainname[LEN_MODEL_NAME]; #endif } modelsel; struct { int16_t midVals[NUM_STICKS+NUM_POTS]; int16_t loVals[NUM_STICKS+NUM_POTS]; int16_t hiVals[NUM_STICKS+NUM_POTS]; uint8_t state; #if defined(PCBTARANIS) struct { uint8_t stepsCount; int16_t steps[POTS_POS_COUNT]; uint8_t lastCount; int16_t lastPosition; } xpotsCalib[NUM_XPOTS]; #endif } calib; #if defined(SDCARD) struct { char lines[LCD_LINES-1][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; } sdmanager; #endif }; extern union ReusableBuffer reusableBuffer; void checkFlashOnBeep(); #if defined(FRSKY) || defined(CPUARM) FORCEINLINE void convertUnit(getvalue_t & val, uint8_t & unit); void putsTelemetryValue(xcoord_t x, uint8_t y, lcdint_t val, uint8_t unit, uint8_t att); #else #define convertUnit(...) #endif #if defined(CPUARM) uint8_t zlen(const char *str, uint8_t size); bool zexist(const char *str, uint8_t size); char * strcat_zchar(char * dest, char * name, uint8_t size, const char *defaultName, uint8_t defaultNameSize, uint8_t defaultIdx); #define strcat_modelname(dest, idx) strcat_zchar(dest, modelHeaders[idx].name, LEN_MODEL_NAME, STR_MODEL, PSIZE(TR_MODEL), idx+1) #define strcat_phasename(dest, idx) strcat_zchar(dest, g_model.phaseData[idx].name, LEN_FP_NAME, NULL, 0, 0) #define strcat_mixername(dest, idx) strcat_zchar(dest, g_model.mixData[idx].name, LEN_EXPOMIX_NAME, NULL, 0, 0) #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_CURRENT, THLD_CONSUMPTION, THLD_MAX, }; extern uint8_t barsThresholds[THLD_MAX]; #endif #if defined(FRSKY) csw_telemetry_value_t minTelemValue(uint8_t channel); csw_telemetry_value_t maxTelemValue(uint8_t channel); #else #define minTelemValue(channel) 255 #define maxTelemValue(channel) 255 #endif #if defined(CPUARM) getvalue_t convert16bitsTelemValue(uint8_t channel, csw_telemetry_value_t value); csw_telemetry_value_t max8bitsTelemValue(uint8_t channel); #endif getvalue_t convert8bitsTelemValue(uint8_t channel, csw_telemetry_value_t value); getvalue_t convertCswTelemValue(CustomSwData * 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(FRSKY) || defined(CPUARM) lcdint_t applyChannelRatio(uint8_t channel, lcdint_t val); #endif #if defined(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 #define IS_BARS_SCREEN(screenIndex) (g_model.frsky.screensType & (1<<(screenIndex))) #endif #define EARTH_RADIUSKM ((uint32_t)6371) #define EARTH_RADIUS ((uint32_t)111194) #if defined(PCBTARANIS) double gpsToDouble(bool neg, int16_t bp, int16_t ap); extern double pilotLatitude; extern double pilotLongitude; #endif 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(PCBTARANIS) #define IS_USR_PROTO_FRSKY_HUB() (1) #define IS_USR_PROTO_WS_HOW_HIGH() (0) #else #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(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 #endif