Fix #4881 (#4884)
[opentx.git] / radio / src / opentx.h
blob89e0995216b7531ab6d4f3ee17188538b63a4475
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #ifndef _OPENTX_H_
22 #define _OPENTX_H_
24 #include <inttypes.h>
25 #include <string.h>
26 #include <stddef.h>
27 #include <stdlib.h>
28 #include "definitions.h"
29 #include "opentx_types.h"
31 #if defined(SIMU)
32 #define SWITCH_SIMU(a, b) (a)
33 #else
34 #define SWITCH_SIMU(a, b) (b)
35 #endif
37 #if defined(PCBSKY9X)
38 #define IS_PCBSKY9X true
39 #define CASE_PCBSKY9X(x) x,
40 #else
41 #define IS_PCBSKY9X false
42 #define CASE_PCBSKY9X(x)
43 #endif
45 #if defined(CPUARM)
46 #define CASE_CPUARM(x) x,
47 #define IF_CPUARM(x) x
48 #else
49 #define CASE_CPUARM(x)
50 #define IF_CPUARM(x)
51 #endif
53 #if defined(VARIO) && defined(CPUARM)
54 #define CASE_VARIO_CPUARM(x) x,
55 #else
56 #define CASE_VARIO_CPUARM(x)
57 #endif
59 #if defined(LUA)
60 #define CASE_LUA(x) x,
61 #else
62 #define CASE_LUA(x)
63 #endif
65 #if defined(CPUARM) || defined(CPUM2560)
66 #define CASE_PERSISTENT_TIMERS(x) x,
67 #else
68 #define CASE_PERSISTENT_TIMERS(x)
69 #endif
71 #if defined(RTCLOCK)
72 #define CASE_RTCLOCK(x) x,
73 #else
74 #define CASE_RTCLOCK(x)
75 #endif
77 #if defined(BUZZER)
78 #define CASE_BUZZER(x) x,
79 #else
80 #define CASE_BUZZER(x)
81 #endif
83 #if defined(AUDIO)
84 #define CASE_AUDIO(x) x,
85 #else
86 #define CASE_AUDIO(x)
87 #endif
89 #if defined(VOICE)
90 #define CASE_VOICE(x) x,
91 #else
92 #define CASE_VOICE(x)
93 #endif
95 #if defined(PWM_BACKLIGHT)
96 #define CASE_PWM_BACKLIGHT(x) x,
97 #else
98 #define CASE_PWM_BACKLIGHT(x)
99 #endif
101 #if defined(TELEMETRY_FRSKY) && defined(FRSKY_HUB) && defined(GPS)
102 #define CASE_GPS(x) x,
103 #else
104 #define CASE_GPS(x)
105 #endif
107 #if defined(VARIO)
108 #define CASE_VARIO(x) x,
109 #else
110 #define CASE_VARIO(x)
111 #endif
113 #if defined(HAPTIC)
114 #define CASE_HAPTIC(x) x,
115 #else
116 #define CASE_HAPTIC(x)
117 #endif
119 #if defined(SPLASH)
120 #define CASE_SPLASH(x) x,
121 #else
122 #define CASE_SPLASH(x)
123 #endif
125 #if defined(TELEMETRY_FRSKY)
126 #define CASE_FRSKY(x) x,
127 #else
128 #define CASE_FRSKY(x)
129 #endif
131 #if defined(TELEMETRY_MAVLINK)
132 #define CASE_MAVLINK(x) x,
133 #else
134 #define CASE_MAVLINK(x)
135 #endif
137 #if defined(PXX)
138 #define CASE_PXX(x) x,
139 #else
140 #define CASE_PXX(x)
141 #endif
143 #if defined(SDCARD)
144 #define CASE_SDCARD(x) x,
145 #else
146 #define CASE_SDCARD(x)
147 #endif
149 #if defined(BLUETOOTH)
150 #define CASE_BLUETOOTH(x) x,
151 #else
152 #define CASE_BLUETOOTH(x)
153 #endif
155 #if defined(HELI)
156 #define CASE_HELI(x) x,
157 #else
158 #define CASE_HELI(x)
159 #endif
161 #if defined(TEMPLATES)
162 #define CASE_TEMPLATES(x) x,
163 #else
164 #define CASE_TEMPLATES(x)
165 #endif
167 #if defined(FLIGHT_MODES)
168 #define CASE_FLIGHT_MODES(x) x,
169 #else
170 #define CASE_FLIGHT_MODES(x)
171 #endif
173 #if defined(CURVES)
174 #define CASE_CURVES(x) x,
175 #else
176 #define CASE_CURVES(x)
177 #endif
179 #if defined(GVARS)
180 #define CASE_GVARS(x) x,
181 #else
182 #define CASE_GVARS(x)
183 #endif
185 #if defined(PCBX9DP) || defined(PCBX9E)
186 #define CASE_PCBX9E_PCBX9DP(x) x,
187 #else
188 #define CASE_PCBX9E_PCBX9DP(x)
189 #endif
191 #if defined(PCBX9E)
192 #define CASE_PCBX9E(x) x,
193 #else
194 #define CASE_PCBX9E(x)
195 #endif
197 #if defined(PCBSKY9X) && !defined(AR9X) && !defined(REVA)
198 #define TX_CAPACITY_MEASUREMENT
199 #define CASE_CAPACITY(x) x,
200 #else
201 #define CASE_CAPACITY(x)
202 #endif
204 #if ROTARY_ENCODERS > 0
205 #define ROTARY_ENCODER_NAVIGATION
206 #endif
208 #if defined(FAI)
209 #define IS_FAI_ENABLED() true
210 #define IF_FAI_CHOICE(x)
211 #elif defined(FAI_CHOICE)
212 #define IS_FAI_ENABLED() g_eeGeneral.fai
213 #define IF_FAI_CHOICE(x) x,
214 #else
215 #define IS_FAI_ENABLED() false
216 #define IF_FAI_CHOICE(x)
217 #endif
219 #define IS_FAI_FORBIDDEN(idx) (IS_FAI_ENABLED() && idx >= MIXSRC_FIRST_TELEM)
221 #if defined(CPUARM)
222 #define MASTER_VOLUME
223 #endif
225 #if !defined(CPUM64) && !defined(ACCURAT_THROTTLE_TIMER)
226 // code cost is about 16 bytes for higher throttle accuracy for timer
227 // would not be noticable anyway, because all version up to this change had only 16 steps;
228 // now it has already 32 steps; this define would increase to 128 steps
229 #if !defined(ACCURAT_THROTTLE_TIMER)
230 #define ACCURAT_THROTTLE_TIMER
231 #endif
232 #endif
234 // 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
235 #define RESX_SHIFT 10
236 #define RESX 1024
237 #define RESXu 1024u
238 #define RESXul 1024ul
239 #define RESXl 1024l
241 #include "board.h"
243 #if defined(DISK_CACHE)
244 #include "disk_cache.h"
245 #endif
247 #if defined(SIMU)
248 #include "targets/simu/simpgmspace.h"
249 #elif defined(CPUARM)
250 typedef const unsigned char pm_uchar;
251 typedef const char pm_char;
252 typedef const uint16_t pm_uint16_t;
253 typedef const uint8_t pm_uint8_t;
254 typedef const int16_t pm_int16_t;
255 typedef const int8_t pm_int8_t;
256 #define pgm_read_byte(address_short) (*(uint8_t*)(address_short))
257 #define PSTR(adr) adr
258 #define PROGMEM
259 #define pgm_read_adr(x) *(x)
260 #define cli()
261 #define sei()
262 #endif
264 #include "debug.h"
266 #if defined(PCBFLAMENCO)
267 #elif defined(PCBTARANIS) || defined(PCBHORUS)
268 #define SWSRC_THR SWSRC_SF2
269 #define SWSRC_GEA SWSRC_SG2
270 #define SWSRC_ID0 SWSRC_SA0
271 #define SWSRC_ID1 SWSRC_SA1
272 #define SWSRC_ID2 SWSRC_SA2
273 #define IS_MOMENTARY(sw) false // TODO
274 #else
275 #define SW_DSM2_BIND SW_TRN
276 #endif
278 #define NUM_PSWITCH (SWSRC_LAST_SWITCH-SWSRC_FIRST_SWITCH+1)
280 #include "myeeprom.h"
282 #if defined(CPUM64)
283 void memclear(void * ptr, uint8_t size);
284 #else
285 #define memclear(p, s) memset(p, 0, s)
286 #endif
288 void memswap(void * a, void * b, uint8_t size);
290 #if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || defined(PCBHORUS)
291 #define POT_CONFIG(x) ((g_eeGeneral.potsConfig >> (2*((x)-POT1)))&0x03)
292 #define IS_POT_MULTIPOS(x) (IS_POT(x) && POT_CONFIG(x)==POT_MULTIPOS_SWITCH)
293 #define IS_POT_WITHOUT_DETENT(x) (IS_POT(x) && POT_CONFIG(x)==POT_WITHOUT_DETENT)
294 #define IS_SLIDER_AVAILABLE(x) ((x) == SLIDER1 || (x) == SLIDER2 || (IS_SLIDER(x) && (g_eeGeneral.slidersConfig & (0x01 << ((x)-SLIDER1)))))
295 #define IS_POT_AVAILABLE(x) (IS_POT(x) && POT_CONFIG(x)!=POT_NONE)
296 #define IS_POT_SLIDER_AVAILABLE(x) (IS_POT_AVAILABLE(x) || IS_SLIDER_AVAILABLE(x))
297 #define IS_MULTIPOS_CALIBRATED(cal) (cal->count>0 && cal->count<XPOTS_MULTIPOS_COUNT)
298 #elif defined(PCBX7)
299 #define IS_POT_MULTIPOS(x) (false)
300 #define IS_POT_WITHOUT_DETENT(x) (false)
301 #define IS_POT_SLIDER_AVAILABLE(x) (true)
302 #define IS_MULTIPOS_CALIBRATED(cal) (false)
303 #elif defined(PCBFLAMENCO)
304 #define IS_POT_MULTIPOS(x) (false)
305 #define IS_POT_WITHOUT_DETENT(x) (false)
306 #define IS_POT_SLIDER_AVAILABLE(x) (true)
307 #define IS_MULTIPOS_CALIBRATED(cal) (false)
308 #else
309 #define IS_POT_MULTIPOS(x) (false)
310 #define IS_POT_WITHOUT_DETENT(x) (true)
311 #define IS_POT_SLIDER_AVAILABLE(x) (true)
312 #define IS_MULTIPOS_CALIBRATED(cal) (false)
313 #endif
315 #if defined(PWR_BUTTON_PRESS)
316 #define pwrOffPressed() pwrPressed()
317 #else
318 #define pwrOffPressed() (!pwrPressed())
319 #endif
321 #define PWR_PRESS_SHUTDOWN_DELAY 300 // 3s
323 #define GET_LOWRES_POT_POSITION(i) (getValue(MIXSRC_FIRST_POT+(i)) >> 4)
324 #define SAVE_POT_POSITION(i) g_model.potsWarnPosition[i] = GET_LOWRES_POT_POSITION(i)
326 #if ROTARY_ENCODERS > 0
327 #define IF_ROTARY_ENCODERS(x) x,
328 #else
329 #define IF_ROTARY_ENCODERS(x)
330 #endif
332 #define PPM_CENTER 1500
334 #if defined(PPM_CENTER_ADJUSTABLE)
335 #define PPM_CH_CENTER(ch) (PPM_CENTER+limitAddress(ch)->ppmCenter)
336 #else
337 #define PPM_CH_CENTER(ch) (PPM_CENTER)
338 #endif
340 #if defined(CPUARM)
341 #include "fifo.h"
342 #include "io/io_arm.h"
343 // This doesn't need protection on this processor
344 extern volatile tmr10ms_t g_tmr10ms;
345 #define get_tmr10ms() g_tmr10ms
346 #else
347 extern volatile tmr10ms_t g_tmr10ms;
348 extern inline uint16_t get_tmr10ms()
350 uint16_t time ;
351 cli();
352 time = g_tmr10ms ;
353 sei();
354 return time ;
356 #endif
358 #if defined(NAVIGATION_STICKS)
359 extern uint8_t StickScrollAllowed;
360 extern uint8_t StickScrollTimer;
361 #define STICK_SCROLL_TIMEOUT 9
362 #define STICK_SCROLL_DISABLE() StickScrollAllowed = 0
363 #else
364 #define STICK_SCROLL_DISABLE()
365 #endif
367 #if defined(CLI)
368 #include "cli.h"
369 #endif
371 #include "timers.h"
372 #include "storage/storage.h"
373 #include "pulses/pulses.h"
375 #if defined(CPUARM)
376 // Order is the same as in enum Protocols in myeeprom.h (none, ppm, xjt, dsm, crossfire, multi)
377 static const int8_t maxChannelsModules[] = { 0, 8, 8, -2, 8, 4 }; // relative to 8!
378 static const int8_t maxChannelsXJT[] = { 0, 8, 0, 4 }; // relative to 8!
379 #define MAX_TRAINER_CHANNELS_M8() (MAX_TRAINER_CHANNELS-8)
380 #endif
382 #if defined(MULTIMODULE)
383 #define IS_MODULE_MULTIMODULE(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_MULTIMODULE)
384 #else
385 #define IS_MODULE_MULTIMODULE(idx) (false)
386 #endif
388 #if defined(PCBTARANIS) || defined(PCBHORUS)
389 #if defined(TARANIS_INTERNAL_PPM)
390 #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))
391 #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))
392 #else
393 #define IS_MODULE_PPM(idx) (idx==TRAINER_MODULE || (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_PPM))
394 #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))
395 #endif
396 #if defined(DSM2)
397 #define IS_MODULE_DSM2(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_DSM2)
398 #else
399 #define IS_MODULE_DSM2(idx) (false)
400 #endif
401 #if defined(CROSSFIRE)
402 #define IS_MODULE_CROSSFIRE(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_CROSSFIRE)
403 #else
404 #define IS_MODULE_CROSSFIRE(idx) (false)
405 #endif
406 #if defined(TARANIS_INTERNAL_PPM)
407 #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])
408 #else
409 #define MAX_INTERNAL_MODULE_CHANNELS() (maxChannelsXJT[1+g_model.moduleData[INTERNAL_MODULE].rfProtocol])
410 #endif
411 #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])
412 #define MAX_CHANNELS(idx) (idx==INTERNAL_MODULE ? MAX_INTERNAL_MODULE_CHANNELS() : (idx==EXTERNAL_MODULE ? MAX_EXTERNAL_MODULE_CHANNELS() : MAX_TRAINER_CHANNELS_M8()))
413 #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))
414 #elif defined(PCBSKY9X) && !defined(REVA)
415 #define IS_MODULE_PPM(idx) (idx==TRAINER_MODULE || idx==EXTRA_MODULE || (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_PPM))
416 #define IS_MODULE_XJT(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_XJT)
417 #define IS_MODULE_DSM2(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_DSM2)
418 #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])
419 #define MAX_EXTRA_MODULE_CHANNELS() (8) // Only PPM (16ch PPM)
420 #define MAX_CHANNELS(idx) (idx==EXTERNAL_MODULE ? MAX_EXTERNAL_MODULE_CHANNELS() : (idx==EXTRA_MODULE ? MAX_EXTRA_MODULE_CHANNELS() : MAX_TRAINER_CHANNELS_M8()))
421 #define NUM_CHANNELS(idx) (8+g_model.moduleData[idx].channelsCount)
422 #define IS_MODULE_CROSSFIRE(idx) (false)
423 #else
424 #define IS_MODULE_PPM(idx) (idx==TRAINER_MODULE || (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_PPM))
425 #define IS_MODULE_XJT(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_XJT)
426 #define IS_MODULE_DSM2(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_DSM2)
427 #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])
428 #define MAX_CHANNELS(idx) (idx==EXTERNAL_MODULE ? MAX_EXTERNAL_MODULE_CHANNELS() : MAX_TRAINER_CHANNELS_M8())
429 #define NUM_CHANNELS(idx) (8+g_model.moduleData[idx].channelsCount)
430 #endif
432 #if defined(MULTIMODULE)
433 #define IS_MULTIMODULE_DSM(idx) (IS_MODULE_MULTIMODULE(idx) && g_model.moduleData[idx].getMultiProtocol(true) == MM_RF_PROTO_DSM2)
434 #define DEFAULT_CHANNELS(idx) (IS_MODULE_PPM(idx) ? 0 : IS_MULTIMODULE_DSM(idx) ? -1 : MAX_CHANNELS(idx))
435 #else
436 #define DEFAULT_CHANNELS(idx) (IS_MODULE_PPM(idx) ? 0 : MAX_CHANNELS(idx))
437 #endif
439 #if defined(CPUARM)
440 #define MASK_CFN_TYPE uint64_t // current max = 64 function switches
441 #define MASK_FUNC_TYPE uint32_t // current max = 32 functions
442 #elif defined(CPUM64)
443 #define MASK_CFN_TYPE uint16_t // current max = 16 function switches
444 #define MASK_FUNC_TYPE uint8_t // current max = 8 functions
445 #else
446 #define MASK_CFN_TYPE uint32_t // current max = 32 function switches
447 #define MASK_FUNC_TYPE uint8_t // current max = 8 functions
448 #endif
450 typedef struct {
451 MASK_FUNC_TYPE activeFunctions;
452 MASK_CFN_TYPE activeSwitches;
453 tmr10ms_t lastFunctionTime[MAX_SPECIAL_FUNCTIONS];
455 inline bool isFunctionActive(uint8_t func)
457 return activeFunctions & ((MASK_FUNC_TYPE)1 << func);
460 void reset()
462 memclear(this, sizeof(*this));
464 } CustomFunctionsContext;
466 #include "strhelpers.h"
467 #include "gui.h"
469 #if defined(TEMPLATES)
470 #include "templates.h"
471 #endif
473 #if !defined(SIMU)
474 #define assert(x)
475 #if !defined(CPUARM) || !defined(DEBUG)
476 #define printf printf_not_allowed
477 #endif
478 #endif
480 extern const pm_uint8_t bchout_ar[];
481 extern const pm_uint8_t modn12x3[];
483 //convert from mode 1 to mode stickMode
484 //NOTICE! => 0..3 -> 0..3
485 #define RUD_STICK 0
486 #define ELE_STICK 1
487 #define THR_STICK 2
488 #define AIL_STICK 3
489 #define CONVERT_MODE(x) (((x)<=AIL_STICK) ? pgm_read_byte(modn12x3 + 4*g_eeGeneral.stickMode + (x)) : (x) )
491 extern uint8_t channel_order(uint8_t x);
493 #define THRCHK_DEADBAND 16
495 #if defined(COLORLCD)
496 #define SPLASH_NEEDED() (false)
497 #elif defined(PCBTARANIS)
498 #define SPLASH_NEEDED() (g_eeGeneral.splashMode != 3)
499 #elif defined(CPUARM)
500 #define SPLASH_NEEDED() (g_model.moduleData[EXTERNAL_MODULE].type != MODULE_TYPE_DSM2 && !g_eeGeneral.splashMode)
501 #else
502 #define SPLASH_NEEDED() (!IS_DSM2_PROTOCOL(g_model.protocol) && !g_eeGeneral.splashMode)
503 #endif
505 #if defined(PCBHORUS)
506 #define SPLASH_TIMEOUT 0 /* we use the splash duration to load stuff from the SD */
507 #elif defined(FSPLASH)
508 #define SPLASH_TIMEOUT (g_eeGeneral.splashMode == 0 ? 60000/*infinite=10mn*/ : ((4*100) * (g_eeGeneral.splashMode & 0x03)))
509 #elif defined(PCBTARANIS) || defined(PCBFLAMENCO)
510 #define SPLASH_TIMEOUT (g_eeGeneral.splashMode==-4 ? 1500 : (g_eeGeneral.splashMode<=0 ? (400-g_eeGeneral.splashMode*200) : (400-g_eeGeneral.splashMode*100)))
511 #else
512 #define SPLASH_TIMEOUT (4*100) // 4 seconds
513 #endif
515 #if defined(ROTARY_ENCODERS)
516 #define IS_ROTARY_ENCODER_NAVIGATION_ENABLE() g_eeGeneral.reNavigation
517 extern volatile rotenc_t rotencValue[ROTARY_ENCODERS];
518 #define ROTARY_ENCODER_NAVIGATION_VALUE rotencValue[g_eeGeneral.reNavigation - 1]
519 #elif defined(ROTARY_ENCODER_NAVIGATION)
520 #define IS_ROTARY_ENCODER_NAVIGATION_ENABLE() true
521 extern volatile rotenc_t rotencValue[1];
522 #define ROTARY_ENCODER_NAVIGATION_VALUE rotencValue[0]
523 #endif
525 #if defined(CPUARM) && defined(ROTARY_ENCODER_NAVIGATION)
526 extern uint8_t rotencSpeed;
527 #define ROTENC_LOWSPEED 1
528 #define ROTENC_MIDSPEED 5
529 #define ROTENC_HIGHSPEED 50
530 #define ROTENC_DELAY_MIDSPEED 32
531 #define ROTENC_DELAY_HIGHSPEED 16
532 #endif
534 #define HEART_TIMER_10MS 1
535 #define HEART_TIMER_PULSES 2 // when multiple modules this is the first one
536 #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS)
537 #define HEART_WDT_CHECK (HEART_TIMER_10MS + (HEART_TIMER_PULSES << 0) + (HEART_TIMER_PULSES << 1))
538 #else
539 #define HEART_WDT_CHECK (HEART_TIMER_10MS + HEART_TIMER_PULSES)
540 #endif
541 extern uint8_t heartbeat;
543 #if defined(CPUARM) && !defined(BOOT)
544 void watchdogSuspend(uint32_t timeout);
545 #define WATCHDOG_SUSPEND(x) watchdogSuspend(x)
546 #else
547 #define WATCHDOG_SUSPEND(...)
548 #endif
550 #define MAX_ALERT_TIME 60
552 struct t_inactivity
554 uint16_t counter;
555 uint8_t sum;
558 extern struct t_inactivity inactivity;
560 #define LEN_STD_CHARS 40
562 #if defined(TRANSLATIONS_CZ)
563 #define ZCHAR_MAX (LEN_STD_CHARS)
564 #else
565 #define ZCHAR_MAX (LEN_STD_CHARS + LEN_SPECIAL_CHARS)
566 #endif
568 char hex2zchar(uint8_t hex);
569 char idx2char(int8_t idx);
570 #if defined(CPUARM) || defined(SIMU)
571 int8_t char2idx(char c);
572 void str2zchar(char *dest, const char *src, int size);
573 int zchar2str(char *dest, const char *src, int size);
574 #endif
576 #include "keys.h"
577 #include "pwr.h"
579 #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS)
580 div_t switchInfo(int switchPosition);
581 extern uint8_t potsPos[NUM_XPOTS];
582 #endif
584 #if defined(PCBHORUS)
585 uint16_t trimDown(uint16_t idx); // TODO why?
586 #else
587 uint8_t trimDown(uint8_t idx);
588 #endif
589 void readKeysAndTrims();
591 uint16_t evalChkSum();
593 #if !defined(GUI)
594 #define RAISE_ALERT(...)
595 #define ALERT(...)
596 #elif defined(VOICE)
597 #define RAISE_ALERT(title, msg, info, sound) showAlertBox(title, msg, info, sound)
598 #define ALERT(title, msg, sound) alert(title, msg, sound)
599 #else
600 #define RAISE_ALERT(title, msg, info, sound) showAlertBox(title, msg, info)
601 #define ALERT(title, msg, sound) alert(title, msg)
602 #endif
604 void alert(const pm_char * t, const pm_char * s ALERT_SOUND_ARG);
606 enum PerOutMode {
607 e_perout_mode_normal = 0,
608 e_perout_mode_inactive_flight_mode = 1,
609 e_perout_mode_notrainer = 2,
610 e_perout_mode_notrims = 4,
611 e_perout_mode_nosticks = 8,
612 e_perout_mode_noinput = e_perout_mode_notrainer+e_perout_mode_notrims+e_perout_mode_nosticks
616 #if defined(MODULE_ALWAYS_SEND_PULSES)
617 extern uint8_t startupWarningState;
619 enum StartupWarningStates {
620 STARTUP_WARNING_THROTTLE,
621 STARTUP_WARNING_SWITCHES,
622 STARTUP_WARNING_DONE,
624 #endif
627 // Fiddle to force compiler to use a pointer
628 #if defined(CPUARM) || defined(SIMU)
629 #define FORCE_INDIRECT(ptr)
630 #else
631 #define FORCE_INDIRECT(ptr) __asm__ __volatile__ ("" : "=e" (ptr) : "0" (ptr))
632 #endif
634 extern uint8_t mixerCurrentFlightMode;
635 extern uint8_t lastFlightMode;
636 extern uint8_t flightModeTransitionLast;
638 #if defined(CPUARM)
639 #define bitfield_channels_t uint32_t
640 #else
641 #define bitfield_channels_t uint16_t
642 #endif
644 #if defined(SIMU)
645 inline int availableMemory() { return 1000; }
646 #elif defined(CPUARM) && !defined(SIMU)
647 extern unsigned char *heap;
648 extern int _end;
649 extern int _estack;
650 extern int _main_stack_start;
651 extern int _heap_end;
652 #define availableMemory() ((unsigned int)((unsigned char *)&_heap_end - heap))
653 #endif
655 void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms);
656 void evalMixes(uint8_t tick10ms);
657 void doMixerCalculations();
658 void scheduleNextMixerCalculation(uint8_t module, uint16_t delay);
660 #if defined(CPUARM)
661 void checkTrims();
662 #endif
663 void perMain();
664 NOINLINE void per10ms();
666 getvalue_t getValue(mixsrc_t i);
668 #if defined(CPUARM)
669 #define GETSWITCH_MIDPOS_DELAY 1
670 bool getSwitch(swsrc_t swtch, uint8_t flags=0);
671 #else
672 bool getSwitch(swsrc_t swtch);
673 #endif
675 void logicalSwitchesTimerTick();
676 void logicalSwitchesReset();
678 #if defined(CPUARM)
679 void evalLogicalSwitches(bool isCurrentPhase=true);
680 void logicalSwitchesCopyState(uint8_t src, uint8_t dst);
681 #define LS_RECURSIVE_EVALUATION_RESET()
682 #else
683 #define evalLogicalSwitches(xxx)
684 #define GETSWITCH_RECURSIVE_TYPE uint16_t
685 extern volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_used;
686 extern volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_value;
687 #define LS_RECURSIVE_EVALUATION_RESET() s_last_switch_used = 0
688 #endif
690 #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS)
691 void getSwitchesPosition(bool startup);
692 #else
693 #define getSwitchesPosition(...)
694 #endif
696 extern swarnstate_t switches_states;
697 swsrc_t getMovedSwitch();
699 #if defined(CPUARM)
700 #define GET_MOVED_SOURCE_PARAMS uint8_t min
701 int8_t getMovedSource(GET_MOVED_SOURCE_PARAMS);
702 #define GET_MOVED_SOURCE(min, max) getMovedSource(min)
703 #else
704 #define GET_MOVED_SOURCE_PARAMS
705 int8_t getMovedSource();
706 #define GET_MOVED_SOURCE(min, max) getMovedSource()
707 #endif
709 #if defined(FLIGHT_MODES)
710 extern uint8_t getFlightMode();
711 #else
712 #define getFlightMode() 0
713 #endif
715 #if !defined(CPUARM)
716 uint8_t getTrimFlightMode(uint8_t phase, uint8_t idx);
717 #else
718 #define getTrimFlightMode(phase, idx) (phase)
719 #endif
721 #if defined(GVARS)
722 extern int8_t trimGvar[NUM_STICKS+NUM_AUX_TRIMS];
723 #define TRIM_REUSED(idx) trimGvar[idx] >= 0
724 #else
725 #define TRIM_REUSED(idx) 0
726 #endif
728 trim_t getRawTrimValue(uint8_t phase, uint8_t idx);
729 int getTrimValue(uint8_t phase, uint8_t idx);
731 #if defined(CPUARM)
732 bool setTrimValue(uint8_t phase, uint8_t idx, int trim);
733 #else
734 void setTrimValue(uint8_t phase, uint8_t idx, int trim);
735 #endif
737 #if defined(ROTARY_ENCODERS)
738 int16_t getRotaryEncoder(uint8_t idx);
739 void incRotaryEncoder(uint8_t idx, int8_t inc);
740 #endif
742 #if defined(PCBGRUVIN9X) || defined(PCBMEGA2560)
743 #define ROTARY_ENCODER_GRANULARITY (1)
744 #elif defined(PCBSKY9X)
745 #define ROTARY_ENCODER_GRANULARITY (2 << g_eeGeneral.rotarySteps)
746 #else
747 #define ROTARY_ENCODER_GRANULARITY (2)
748 #endif
750 #include "gvars.h"
752 extern uint16_t sessionTimer;
753 extern uint16_t s_timeCumThr;
754 extern uint16_t s_timeCum16ThrP;
756 #if defined(OVERRIDE_CHANNEL_FUNCTION)
757 #if defined(CPUARM)
758 #define OVERRIDE_CHANNEL_UNDEFINED -4096
759 #else
760 #define OVERRIDE_CHANNEL_UNDEFINED -128
761 #endif
762 extern safetych_t safetyCh[MAX_OUTPUT_CHANNELS];
763 #endif
765 extern uint8_t trimsCheckTimer;
767 #if defined(CPUARM)
768 extern uint8_t trimsDisplayTimer;
769 extern uint8_t trimsDisplayMask;
770 #endif
772 void flightReset(uint8_t check=true);
774 extern uint8_t unexpectedShutdown;
776 extern uint16_t maxMixerDuration;
778 #if !defined(CPUARM)
779 extern uint8_t g_tmr1Latency_max;
780 extern uint8_t g_tmr1Latency_min;
781 extern uint16_t lastMixerDuration;
782 #endif
784 #if defined(CPUARM)
785 #define DURATION_MS_PREC2(x) ((x)/20)
786 #else
787 #define DURATION_MS_PREC2(x) ((x)*100)/16
788 #endif
790 #if defined(THRTRACE)
791 #if defined(COLORLCD)
792 #define MAXTRACE (LCD_W-2*10)
793 #else
794 #define MAXTRACE (LCD_W - 8)
795 #endif
796 extern uint8_t s_traceBuf[MAXTRACE];
797 extern uint16_t s_traceWr;
798 extern uint8_t s_cnt_10s;
799 extern uint16_t s_cnt_samples_thr_10s;
800 extern uint16_t s_sum_samples_thr_10s;
801 #define RESET_THR_TRACE() s_traceWr = s_cnt_10s = s_cnt_samples_thr_10s = s_sum_samples_thr_10s = s_timeCum16ThrP = s_timeCumThr = 0
802 #else
803 #define RESET_THR_TRACE() s_timeCum16ThrP = s_timeCumThr = 0
804 #endif
806 #if defined(SIMU)
807 uint16_t getTmr2MHz();
808 uint16_t getTmr16KHz();
809 #elif defined(STM32)
810 static inline uint16_t getTmr2MHz() { return TIMER_2MHz_TIMER->CNT; }
811 #elif defined(PCBSKY9X)
812 static inline uint16_t getTmr2MHz() { return TC1->TC_CHANNEL[0].TC_CV; }
813 #else
814 uint16_t getTmr16KHz();
815 #endif
817 #if !defined(CPUARM)
818 uint16_t stackAvailable();
819 #endif
821 #if defined(SPLASH)
822 void doSplash();
823 #endif
825 #if MENUS_LOCK == 1
826 extern bool readonly;
827 extern bool readonlyUnlocked();
828 #define READ_ONLY() readonly
829 #define READ_ONLY_UNLOCKED() readonlyUnlocked()
830 #else
831 #define READ_ONLY() false
832 #define READ_ONLY_UNLOCKED() true
833 #endif
835 void checkLowEEPROM();
836 void checkTHR();
837 void checkSwitches();
838 void checkAlarm();
839 void checkAll();
841 #if !defined(SIMU)
842 void getADC();
843 #if defined(CPUARM)
844 #define GET_ADC_IF_MIXER_NOT_RUNNING() do { if (s_pulses_paused) getADC(); } while(0)
845 #else
846 #define GET_ADC_IF_MIXER_NOT_RUNNING() getADC()
847 #endif
848 #endif
850 #if defined(SBUS)
851 #include "sbus.h"
852 #endif
854 void backlightOn();
855 void checkBacklight();
856 void doLoopCommonActions();
858 #define BITMASK(bit) (1<<(bit))
860 #if !defined(UNUSED)
861 #define UNUSED(x) ((void)(x)) /* to avoid warnings */
862 #endif
864 /// returns the number of elements of an array
865 #define DIM(arr) (sizeof((arr))/sizeof((arr)[0]))
867 template<class t> FORCEINLINE t min(t a, t b) { return a<b?a:b; }
868 template<class t> FORCEINLINE t max(t a, t b) { return a>b?a:b; }
869 template<class t> FORCEINLINE t sgn(t a) { return a>0 ? 1 : (a < 0 ? -1 : 0); }
870 template<class t> FORCEINLINE t limit(t mi, t x, t ma) { return min(max(mi,x),ma); }
871 template<class t> void SWAP(t & a, t & b) { t tmp = b; b = a; a = tmp; }
873 uint16_t isqrt32(uint32_t n);
875 #if defined(CPUARM) && !defined(BOOT)
876 #include "tasks_arm.h"
877 extern OS_MutexID mixerMutex;
878 inline void pauseMixerCalculations()
880 CoEnterMutexSection(mixerMutex);
883 inline void resumeMixerCalculations()
885 CoLeaveMutexSection(mixerMutex);
887 #else
888 #define pauseMixerCalculations()
889 #define resumeMixerCalculations()
890 #endif
892 void generalDefault();
893 void modelDefault(uint8_t id);
895 #if defined(CPUARM)
896 void checkModelIdUnique(uint8_t index, uint8_t module);
897 #endif
899 #if defined(CPUARM)
900 uint32_t hash(const void * ptr, uint32_t size);
901 inline int divRoundClosest(const int n, const int d)
903 if (d == 0)
904 return 0;
905 else
906 return ((n < 0) ^ (d < 0)) ? ((n - d/2)/d) : ((n + d/2)/d);
909 #define calc100to256_16Bits(x) calc100to256(x)
910 #define calc100toRESX_16Bits(x) calc100toRESX(x)
912 inline int calc100to256(int x)
914 return divRoundClosest(x*256, 100);
917 inline int calc100toRESX(int x)
919 return divRoundClosest(x*RESX, 100);
922 inline int calc1000toRESX(int x)
924 return divRoundClosest(x*RESX, 1000);
927 inline int calcRESXto1000(int x)
929 return divRoundClosest(x*1000, RESX);
932 inline int calcRESXto100(int x)
934 return divRoundClosest(x*100, RESX);
937 #else
938 extern int16_t calc100to256_16Bits(int16_t x); // @@@2 open.20.fsguruh: return x*2.56
939 extern int16_t calc100to256(int8_t x); // @@@2 open.20.fsguruh: return x*2.56
940 extern int16_t calc100toRESX_16Bits(int16_t x); // @@@ open.20.fsguruh
941 extern int16_t calc100toRESX(int8_t x);
942 extern int16_t calc1000toRESX(int16_t x);
943 extern int16_t calcRESXto1000(int16_t x);
944 extern int8_t calcRESXto100(int16_t x);
945 #endif
947 #if defined(COLORLCD)
948 extern const char vers_stamp[];
949 extern const char date_stamp[];
950 extern const char time_stamp[];
951 extern const char eeprom_stamp[];
952 #else
953 extern const char vers_stamp[];
954 #endif
956 extern uint8_t g_vbat100mV;
957 #if LCD_W > 128
958 #define GET_TXBATT_BARS() (limit<int8_t>(0, div_and_round(10 * (g_vbat100mV - g_eeGeneral.vBatMin - 90), 30 + g_eeGeneral.vBatMax - g_eeGeneral.vBatMin), 10))
959 #else
960 #define GET_TXBATT_BARS() (limit<int8_t>(2, 20 * (g_vbat100mV - g_eeGeneral.vBatMin - 90) / (30 + g_eeGeneral.vBatMax - g_eeGeneral.vBatMin), 20))
961 #endif
962 #define IS_TXBATT_WARNING() (g_vbat100mV <= g_eeGeneral.vBatWarn)
965 #define g_blinkTmr10ms (*(uint8_t*)&g_tmr10ms)
966 extern uint8_t g_beepCnt;
967 extern uint8_t g_beepVal[5];
969 #include "trainer_input.h"
971 extern int32_t chans[MAX_OUTPUT_CHANNELS];
972 extern int16_t ex_chans[MAX_OUTPUT_CHANNELS]; // Outputs (before LIMITS) of the last perMain
973 extern int16_t channelOutputs[MAX_OUTPUT_CHANNELS];
974 extern uint16_t BandGap;
976 #if defined(CPUARM)
977 #define NUM_INPUTS (MAX_INPUTS)
978 #else
979 #define NUM_INPUTS (NUM_STICKS)
980 #endif
982 int expo(int x, int k);
984 #if defined(CPUARM)
985 inline int getMaximumValue(int source)
987 if (source < MIXSRC_FIRST_CH)
988 return 100;
989 else if (source <= MIXSRC_LAST_CH)
990 return g_model.extendedLimits ? 150 : 100;
991 else if (source >= MIXSRC_FIRST_TIMER && source <= MIXSRC_LAST_TIMER)
992 return (23*60)+59;
993 else
994 return 30000;
996 #endif
998 // Curves
999 enum BaseCurves {
1000 CURVE_NONE,
1001 CURVE_X_GT0,
1002 CURVE_X_LT0,
1003 CURVE_ABS_X,
1004 CURVE_F_GT0,
1005 CURVE_F_LT0,
1006 CURVE_ABS_F,
1007 CURVE_BASE
1009 int8_t * curveAddress(uint8_t idx);
1010 struct point_t
1012 coord_t x;
1013 coord_t y;
1015 point_t getPoint(uint8_t i);
1016 #if !defined(CURVES)
1017 #define LOAD_MODEL_CURVES()
1018 #define applyCurve(x, idx) (x)
1019 #elif defined(CPUARM)
1020 typedef CurveData CurveInfo;
1021 void loadCurves();
1022 #define LOAD_MODEL_CURVES() loadCurves()
1023 int intpol(int x, uint8_t idx);
1024 int applyCurve(int x, CurveRef & curve);
1025 int applyCustomCurve(int x, uint8_t idx);
1026 int applyCurrentCurve(int x);
1027 int8_t getCurveX(int noPoints, int point);
1028 void resetCustomCurveX(int8_t * points, int noPoints);
1029 bool moveCurve(uint8_t index, int8_t shift); // TODO bool?
1030 #else
1031 struct CurveInfo {
1032 int8_t * crv;
1033 uint8_t points:7;
1034 uint8_t custom:1;
1036 CurveInfo curveInfo(uint8_t idx);
1037 int intpol(int x, uint8_t idx);
1038 int applyCurve(int x, int8_t idx);
1039 #define LOAD_MODEL_CURVES()
1040 #define applyCustomCurve(x, idx) intpol(x, idx)
1041 int applyCurrentCurve(int x);
1042 bool moveCurve(uint8_t index, int8_t shift, int8_t custom=0);
1043 #endif
1045 #if defined(CPUARM)
1046 #define APPLY_EXPOS_EXTRA_PARAMS_INC , uint8_t ovwrIdx=0, int16_t ovwrValue=0
1047 #define APPLY_EXPOS_EXTRA_PARAMS , uint8_t ovwrIdx, int16_t ovwrValue
1048 #else
1049 #define APPLY_EXPOS_EXTRA_PARAMS_INC
1050 #define APPLY_EXPOS_EXTRA_PARAMS
1051 #endif
1053 #if defined(CPUARM)
1054 void clearInputs();
1055 void defaultInputs();
1056 #endif
1058 void applyExpos(int16_t * anas, uint8_t mode APPLY_EXPOS_EXTRA_PARAMS_INC);
1059 int16_t applyLimits(uint8_t channel, int32_t value);
1061 void evalInputs(uint8_t mode);
1062 uint16_t anaIn(uint8_t chan);
1064 extern int16_t calibratedAnalogs[NUM_CALIBRATED_ANALOGS];
1066 #define FLASH_DURATION 20 /*200ms*/
1068 extern uint8_t beepAgain;
1069 extern uint16_t lightOffCounter;
1070 extern uint8_t flashCounter;
1071 extern uint8_t mixWarning;
1073 FlightModeData * flightModeAddress(uint8_t idx);
1074 ExpoData * expoAddress(uint8_t idx);
1075 MixData * mixAddress(uint8_t idx);
1076 LimitData * limitAddress(uint8_t idx);
1077 LogicalSwitchData * lswAddress(uint8_t idx);
1079 // static variables used in evalFlightModeMixes - moved here so they don't interfere with the stack
1080 // It's also easier to initialize them here.
1081 #if defined(CPUARM)
1082 extern int8_t virtualInputsTrims[NUM_INPUTS];
1083 #else
1084 extern int16_t rawAnas[NUM_INPUTS];
1085 #endif
1087 extern int16_t anas [NUM_INPUTS];
1088 extern int16_t trims[NUM_STICKS+NUM_AUX_TRIMS];
1089 extern BeepANACenter bpanaCenter;
1091 extern uint8_t s_mixer_first_run_done;
1093 void applyDefaultTemplate();
1095 void incSubtrim(uint8_t idx, int16_t inc);
1096 void instantTrim();
1097 void evalTrims();
1098 void copyTrimsToOffset(uint8_t ch);
1099 void copySticksToOffset(uint8_t ch);
1100 void moveTrimsToOffsets();
1102 #if defined(CPUARM)
1103 #define ACTIVE_PHASES_TYPE uint16_t
1104 #define DELAY_POS_SHIFT 0
1105 #define DELAY_POS_MARGIN 3
1106 #define delayval_t int16_t
1107 PACK(typedef struct {
1108 uint16_t delay;
1109 int16_t now; // timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw
1110 int16_t prev;
1111 uint8_t activeMix;
1112 uint8_t activeExpo;
1113 }) SwOn;
1114 #else
1115 #define ACTIVE_PHASES_TYPE uint8_t
1116 #define DELAY_POS_SHIFT 10
1117 #define DELAY_POS_MARGIN 0
1118 #define delayval_t int8_t
1119 PACK(typedef struct {
1120 uint16_t delay:10;
1121 int16_t now:2; // timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw
1122 int16_t prev:2;
1123 int16_t activeMix:1;
1124 int16_t activeExpo:1;
1125 }) SwOn;
1126 #endif
1128 extern SwOn swOn[MAX_MIXERS];
1129 extern int24_t act[MAX_MIXERS];
1131 #if defined(BOLD_FONT)
1132 inline bool isExpoActive(uint8_t expo)
1134 return swOn[expo].activeExpo;
1137 inline bool isMixActive(uint8_t mix)
1139 return swOn[mix].activeMix;
1141 #else
1142 #define isExpoActive(x) false
1143 #define isMixActive(x) false
1144 #endif
1146 enum LogicalSwitchFamilies {
1147 LS_FAMILY_OFS,
1148 LS_FAMILY_BOOL,
1149 LS_FAMILY_COMP,
1150 LS_FAMILY_DIFF,
1151 LS_FAMILY_TIMER,
1152 LS_FAMILY_STICKY,
1153 LS_FAMILY_RANGE,
1154 LS_FAMILY_EDGE
1157 uint8_t lswFamily(uint8_t func);
1158 int16_t lswTimerValue(delayval_t val);
1160 enum FunctionsActive {
1161 FUNCTION_TRAINER,
1162 FUNCTION_INSTANT_TRIM = FUNCTION_TRAINER+4,
1163 FUNCTION_VARIO,
1164 FUNCTION_BACKLIGHT,
1165 #if defined(SDCARD)
1166 FUNCTION_LOGS,
1167 #endif
1168 #if defined(CPUARM)
1169 FUNCTION_BACKGND_MUSIC,
1170 FUNCTION_BACKGND_MUSIC_PAUSE,
1171 #endif
1174 #define VARIO_FREQUENCY_ZERO 700/*Hz*/
1175 #define VARIO_FREQUENCY_RANGE 1000/*Hz*/
1176 #define VARIO_REPEAT_ZERO 500/*ms*/
1177 #define VARIO_REPEAT_MAX 80/*ms*/
1179 #if defined(CPUARM)
1180 extern CustomFunctionsContext modelFunctionsContext;
1181 extern CustomFunctionsContext globalFunctionsContext;
1182 inline bool isFunctionActive(uint8_t func)
1184 return globalFunctionsContext.isFunctionActive(func) || modelFunctionsContext.isFunctionActive(func);
1186 void evalFunctions(const CustomFunctionData * functions, CustomFunctionsContext & functionsContext);
1187 inline void customFunctionsReset()
1189 globalFunctionsContext.reset();
1190 modelFunctionsContext.reset();
1192 #else
1193 extern CustomFunctionsContext modelFunctionsContext;
1194 #define isFunctionActive(func) modelFunctionsContext.isFunctionActive(func)
1195 void evalFunctions();
1196 #define customFunctionsReset() modelFunctionsContext.reset()
1197 #endif
1199 #include "telemetry/telemetry.h"
1201 #if defined(CPUARM)
1202 uint8_t crc8(const uint8_t * ptr, uint32_t len);
1203 uint16_t crc16(const uint8_t * ptr, uint32_t len);
1204 #endif
1206 #define PLAY_REPEAT(x) (x) /* Range 0 to 15 */
1207 #define PLAY_NOW 0x10
1208 #define PLAY_BACKGROUND 0x20
1209 #define PLAY_INCREMENT(x) ((uint8_t)(((uint8_t)x) << 6)) /* -1, 0, 1, 2 */
1211 enum AUDIO_SOUNDS {
1212 AUDIO_HELLO,
1213 #if defined(CPUARM)
1214 AU_BYE,
1215 #endif
1216 #if defined(VOICE)
1217 AU_THROTTLE_ALERT,
1218 AU_SWITCH_ALERT,
1219 AU_BAD_RADIODATA,
1220 #endif
1221 AU_TX_BATTERY_LOW,
1222 AU_INACTIVITY,
1223 #if defined(CPUARM)
1224 AU_RSSI_ORANGE,
1225 AU_RSSI_RED,
1226 AU_SWR_RED,
1227 AU_TELEMETRY_LOST,
1228 AU_TELEMETRY_BACK,
1229 AU_TRAINER_LOST,
1230 AU_TRAINER_BACK,
1231 AU_SENSOR_LOST,
1232 AU_SERVO_KO,
1233 AU_RX_OVERLOAD,
1234 #endif
1235 #if defined(PCBSKY9X)
1236 AU_TX_MAH_HIGH,
1237 AU_TX_TEMP_HIGH,
1238 #endif
1239 AU_ERROR,
1240 AU_WARNING1,
1241 AU_WARNING2,
1242 AU_WARNING3,
1243 AU_TRIM_MIDDLE,
1244 #if defined(CPUARM)
1245 AU_TRIM_MIN,
1246 AU_TRIM_MAX,
1247 #endif
1248 #if defined(CPUARM)
1249 AU_STICK1_MIDDLE,
1250 AU_STICK2_MIDDLE,
1251 AU_STICK3_MIDDLE,
1252 AU_STICK4_MIDDLE,
1253 #endif
1254 #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS)
1255 AU_POT1_MIDDLE,
1256 AU_POT2_MIDDLE,
1257 AU_SLIDER1_MIDDLE,
1258 AU_SLIDER2_MIDDLE,
1259 #elif defined(CPUARM)
1260 AU_POT1_MIDDLE,
1261 AU_POT2_MIDDLE,
1262 AU_POT3_MIDDLE,
1263 #else
1264 AU_POT_MIDDLE,
1265 #endif
1266 AU_MIX_WARNING_1,
1267 AU_MIX_WARNING_2,
1268 AU_MIX_WARNING_3,
1269 #if defined(CPUARM)
1270 AU_TIMER1_ELAPSED,
1271 AU_TIMER2_ELAPSED,
1272 AU_TIMER3_ELAPSED,
1273 #endif
1275 AU_SPECIAL_SOUND_FIRST,
1276 AU_SPECIAL_SOUND_BEEP1 = AU_SPECIAL_SOUND_FIRST,
1277 AU_SPECIAL_SOUND_BEEP2,
1278 AU_SPECIAL_SOUND_BEEP3,
1279 AU_SPECIAL_SOUND_WARN1,
1280 AU_SPECIAL_SOUND_WARN2,
1281 AU_SPECIAL_SOUND_CHEEP,
1282 AU_SPECIAL_SOUND_RATATA,
1283 AU_SPECIAL_SOUND_TICK,
1284 AU_SPECIAL_SOUND_SIREN,
1285 AU_SPECIAL_SOUND_RING,
1286 AU_SPECIAL_SOUND_SCIFI,
1287 AU_SPECIAL_SOUND_ROBOT,
1288 AU_SPECIAL_SOUND_CHIRP,
1289 AU_SPECIAL_SOUND_TADA,
1290 AU_SPECIAL_SOUND_CRICKET,
1291 AU_SPECIAL_SOUND_ALARMC,
1292 AU_SPECIAL_SOUND_LAST,
1294 AU_NONE=0xff
1297 #if defined(AUDIO)
1298 #if defined(CPUARM)
1299 #include "audio_arm.h"
1300 #else
1301 #include "audio_avr.h"
1302 #endif
1303 #endif
1305 #include "buzzer.h"
1307 #if defined(PCBSTD) && defined(VOICE)
1308 #include "targets/9x/voice.h"
1309 #endif
1311 #if defined(PCBGRUVIN9X) && defined(VOICE)
1312 #include "targets/gruvin9x/voice.h"
1313 #endif
1315 #if defined(PCBMEGA2560) && defined(VOICE)
1316 #include "targets/mega2560/voice.h"
1317 #endif
1319 #include "translations.h"
1320 #include "fonts.h"
1322 #if defined(HAPTIC)
1323 #include "haptic.h"
1324 #endif
1326 #if defined(SDCARD)
1327 #include "sdcard.h"
1328 #endif
1330 #if defined(RTCLOCK)
1331 #include "rtc.h"
1332 #endif
1334 #if defined(REVX)
1335 void setMFP();
1336 void clearMFP();
1337 #endif
1339 #if defined(CPUARM)
1340 extern uint8_t requiredSpeakerVolume;
1341 #endif
1343 #if defined(CPUARM)
1344 enum MainRequest {
1345 REQUEST_SCREENSHOT,
1346 REQUEST_FLIGHT_RESET,
1349 extern uint8_t mainRequestFlags;
1350 #endif
1352 void checkBattery();
1353 void opentxClose(uint8_t shutdown=true);
1354 void opentxInit();
1355 void opentxResume();
1357 #if defined(PCBHORUS) || defined(PCBX7)
1358 #define LED_ERROR_BEGIN() ledRed()
1359 #define LED_ERROR_END() ledBlue()
1360 #else
1361 #define LED_ERROR_BEGIN()
1362 #define LED_ERROR_END()
1363 #endif
1365 // Re-useable byte array to save having multiple buffers
1366 #if LCD_W <= 212
1367 #define SD_SCREEN_FILE_LENGTH 32
1368 #else
1369 #define SD_SCREEN_FILE_LENGTH 64
1370 #endif
1371 union ReusableBuffer
1373 // 275 bytes
1374 struct
1376 char listnames[NUM_BODY_LINES][LEN_MODEL_NAME];
1377 #if defined(EEPROM_RLC) && LCD_W < 212
1378 uint16_t eepromfree;
1379 #endif
1380 #if defined(SDCARD)
1381 char menu_bss[POPUP_MENU_MAX_LINES][MENU_LINE_LENGTH];
1382 char mainname[45]; // because reused for SD backup / restore, max backup filename 44 chars: "/MODELS/MODEL0134353-2014-06-19-04-51-27.bin"
1383 #else
1384 char mainname[LEN_MODEL_NAME];
1385 #endif
1386 } modelsel;
1388 // 103 bytes
1389 struct
1391 int16_t midVals[NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_MOUSE_ANALOGS];
1392 int16_t loVals[NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_MOUSE_ANALOGS];
1393 int16_t hiVals[NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_MOUSE_ANALOGS];
1394 uint8_t state;
1395 #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS)
1396 struct {
1397 uint8_t stepsCount;
1398 int16_t steps[XPOTS_MULTIPOS_COUNT];
1399 uint8_t lastCount;
1400 int16_t lastPosition;
1401 } xpotsCalib[NUM_XPOTS];
1402 #endif
1403 } calib;
1405 #if defined(SDCARD)
1406 // 274 bytes
1407 struct
1409 char lines[NUM_BODY_LINES][SD_SCREEN_FILE_LENGTH+1+1]; // the last char is used to store the flags (directory) of the line
1410 uint32_t available;
1411 uint16_t offset;
1412 uint16_t count;
1413 char originalName[SD_SCREEN_FILE_LENGTH+1];
1414 } sdmanager;
1415 #endif
1417 #if defined(STM32)
1418 struct
1420 char id[27];
1421 } version;
1422 #endif
1423 struct
1425 uint8_t stickMode;
1426 } generalSettings;
1429 extern union ReusableBuffer reusableBuffer;
1431 void checkFlashOnBeep();
1433 #if defined(CPUARM)
1434 uint8_t zlen(const char *str, uint8_t size);
1435 bool zexist(const char *str, uint8_t size);
1436 unsigned int effectiveLen(const char * str, unsigned int size);
1437 char * strcat_zchar(char *dest, const char *name, uint8_t size, const char *defaultName=NULL, uint8_t defaultNameSize=0, uint8_t defaultIdx=0);
1438 #define strcat_phasename(dest, idx) strcat_zchar(dest, g_model.flightModeData[idx].name, LEN_FLIGHT_MODE_NAME, STR_FP, PSIZE(TR_FP), idx+1)
1439 #if defined(EEPROM)
1440 #define strcat_modelname(dest, idx) strcat_zchar(dest, modelHeaders[idx].name, LEN_MODEL_NAME, STR_MODEL, PSIZE(TR_MODEL), idx+1)
1441 #define strcat_currentmodelname(dest) strcat_modelname(dest, g_eeGeneral.currModel)
1442 #else
1443 #define strcat_currentmodelname(dest) strcat_zchar(dest, g_model.header.name, LEN_MODEL_NAME)
1444 #endif
1445 #define ZLEN(s) zlen(s, sizeof(s))
1446 #define ZEXIST(s) zexist(s, sizeof(s))
1447 #endif
1449 // Stick tolerance varies between transmitters, Higher is better
1450 #if defined (PCB9XR) || defined (PCB9XR128)
1451 #define STICK_TOLERANCE 16
1452 #else
1453 #define STICK_TOLERANCE 64
1454 #endif
1456 #if defined(FRSKY_HUB) && defined(GAUGES)
1457 enum BarThresholdIdx {
1458 THLD_ALT,
1459 THLD_RPM,
1460 THLD_FUEL,
1461 THLD_T1,
1462 THLD_T2,
1463 THLD_SPEED,
1464 THLD_DIST,
1465 THLD_GPSALT,
1466 THLD_CELL,
1467 THLD_CELLS_SUM,
1468 THLD_VFAS,
1469 THLD_CURRENT,
1470 THLD_CONSUMPTION,
1471 THLD_MAX,
1474 #if defined(CPUARM)
1475 #define FILL_THRESHOLD(idx, val) barsThresholds[idx] = (val)
1476 #else
1477 #define FILL_THRESHOLD(idx, val) barsThresholds[idx] = 128 + (val)
1478 #endif
1480 extern bar_threshold_t barsThresholds[THLD_MAX];
1481 #else
1482 #define FILL_THRESHOLD(idx, val)
1483 #endif
1485 #if defined(TELEMETRY_FRSKY)
1486 ls_telemetry_value_t minTelemValue(source_t channel);
1487 ls_telemetry_value_t maxTelemValue(source_t channel);
1488 #else
1489 #define minTelemValue(channel) 255
1490 #define maxTelemValue(channel) 255
1491 #endif
1493 #if defined(CPUARM)
1494 getvalue_t convert16bitsTelemValue(source_t channel, ls_telemetry_value_t value);
1495 ls_telemetry_value_t max8bitsTelemValue(source_t channel);
1496 #endif
1498 getvalue_t convert8bitsTelemValue(source_t channel, ls_telemetry_value_t value);
1499 getvalue_t convertLswTelemValue(LogicalSwitchData * cs);
1501 #if defined(CPUARM)
1502 #define convertTelemValue(channel, value) convert16bitsTelemValue(channel, value)
1503 #define convertBarTelemValue(channel, value) convert8bitsTelemValue(channel, value)
1504 #define maxBarTelemValue(channel) max8bitsTelemValue(channel)
1505 #else
1506 #define convertTelemValue(channel, value) convert8bitsTelemValue(channel, value)
1507 #define convertBarTelemValue(channel, value) convert8bitsTelemValue(channel, value)
1508 #define maxBarTelemValue(channel) maxTelemValue(channel)
1509 #endif
1511 #if defined(TELEMETRY_FRSKY) || defined(CPUARM)
1512 lcdint_t applyChannelRatio(source_t channel, lcdint_t val);
1513 #define ANA_CHANNEL_UNIT(channel) g_model.frsky.channels[channel].type
1514 #endif
1516 inline int div_and_round(int num, int den)
1518 if (den == 0) {
1519 return 0;
1521 else if (num >= 0) {
1522 num += den / 2;
1524 else {
1525 num -= den / 2;
1527 return num / den;
1530 #if defined(TELEMETRY_FRSKY)
1531 NOINLINE uint8_t getRssiAlarmValue(uint8_t alarm);
1533 extern const pm_uint8_t bchunit_ar[];
1535 #if defined(CPUARM)
1536 #define FRSKY_MULTIPLIER_MAX 5
1537 #else
1538 #define FRSKY_MULTIPLIER_MAX 3
1539 #endif
1541 enum TelemetryViews {
1542 TELEMETRY_CUSTOM_SCREEN_1,
1543 TELEMETRY_CUSTOM_SCREEN_2,
1544 #if defined(CPUARM)
1545 TELEMETRY_CUSTOM_SCREEN_3,
1546 TELEMETRY_CUSTOM_SCREEN_4,
1547 TELEMETRY_VIEW_MAX = TELEMETRY_CUSTOM_SCREEN_4
1548 #else
1549 TELEMETRY_VOLTAGES_SCREEN,
1550 TELEMETRY_AFTER_FLIGHT_SCREEN,
1551 TELEMETRY_VIEW_MAX = TELEMETRY_AFTER_FLIGHT_SCREEN
1552 #endif
1555 extern uint8_t s_frsky_view;
1557 #endif
1559 #define EARTH_RADIUSKM ((uint32_t)6371)
1560 #define EARTH_RADIUS ((uint32_t)111194)
1562 void getGpsPilotPosition();
1563 void getGpsDistance();
1564 void varioWakeup();
1566 #if defined(AUDIO) && defined(BUZZER)
1567 #define IS_SOUND_OFF() (g_eeGeneral.buzzerMode==e_mode_quiet && g_eeGeneral.beepMode==e_mode_quiet)
1568 #else
1569 #define IS_SOUND_OFF() (g_eeGeneral.beepMode == e_mode_quiet)
1570 #endif
1572 #if defined(CPUARM)
1573 #define IS_IMPERIAL_ENABLE() (g_eeGeneral.imperial)
1574 #elif defined(IMPERIAL_UNITS)
1575 #define IS_IMPERIAL_ENABLE() (1)
1576 #else
1577 #define IS_IMPERIAL_ENABLE() (0)
1578 #endif
1580 #if defined(CPUARM)
1581 #elif defined(TELEMETRY_FRSKY)
1582 FORCEINLINE void convertUnit(getvalue_t & val, uint8_t & unit)
1584 if (IS_IMPERIAL_ENABLE()) {
1585 if (unit == UNIT_TEMPERATURE) {
1586 val += 18;
1587 val *= 115;
1588 val >>= 6;
1590 if (unit == UNIT_DIST) {
1591 // m to ft *105/32
1592 val = val * 3 + (val >> 2) + (val >> 5);
1594 if (unit == UNIT_FEET) {
1595 unit = UNIT_DIST;
1597 if (unit == UNIT_KTS) {
1598 // kts to mph
1599 unit = UNIT_SPEED;
1600 val = (val * 23) / 20;
1603 else {
1604 if (unit == UNIT_KTS) {
1605 // kts to km/h
1606 unit = UNIT_SPEED;
1607 val = (val * 50) / 27;
1611 if (unit == UNIT_HDG) {
1612 unit = UNIT_TEMPERATURE;
1615 #else
1616 #define convertUnit(...)
1617 #endif
1619 #if !defined(CPUARM)
1620 #define IS_USR_PROTO_FRSKY_HUB() (g_model.frsky.usrProto == USR_PROTO_FRSKY)
1621 #define IS_USR_PROTO_WS_HOW_HIGH() (g_model.frsky.usrProto == USR_PROTO_WS_HOW_HIGH)
1622 #endif
1624 #if defined(TELEMETRY_FRSKY) && defined(FRSKY_HUB) && defined(GPS)
1625 #define IS_GPS_AVAILABLE() IS_USR_PROTO_FRSKY_HUB()
1626 #else
1627 #define IS_GPS_AVAILABLE() (0)
1628 #endif
1630 #if defined(PCBTARANIS)
1631 extern const pm_uchar logo_taranis[];
1632 #endif
1634 #if defined(USB_MASS_STORAGE)
1635 void usbPluggedIn();
1636 #endif
1638 #include "lua/lua_api.h"
1640 #if defined(SDCARD)
1641 enum ClipboardType {
1642 CLIPBOARD_TYPE_NONE,
1643 CLIPBOARD_TYPE_CUSTOM_SWITCH,
1644 CLIPBOARD_TYPE_CUSTOM_FUNCTION,
1645 CLIPBOARD_TYPE_SD_FILE,
1648 #if defined(SIMU)
1649 #define CLIPBOARD_PATH_LEN 1024
1650 #else
1651 #define CLIPBOARD_PATH_LEN 32
1652 #endif
1654 struct Clipboard {
1655 ClipboardType type;
1656 union {
1657 LogicalSwitchData csw;
1658 CustomFunctionData cfn;
1659 struct {
1660 char directory[CLIPBOARD_PATH_LEN];
1661 char filename[CLIPBOARD_PATH_LEN];
1662 } sd;
1663 } data;
1666 extern Clipboard clipboard;
1667 #endif
1669 #if !defined(SIMU)
1670 extern uint16_t s_anaFilt[NUM_ANALOGS];
1671 #endif
1673 #if defined(JITTER_MEASURE)
1674 extern JitterMeter<uint16_t> rawJitter[NUM_ANALOGS];
1675 extern JitterMeter<uint16_t> avgJitter[NUM_ANALOGS];
1676 #if defined(PCBHORUS)
1677 #define JITTER_MEASURE_ACTIVE() (menuHandlers[menuLevel] == menuStatsAnalogs)
1678 #elif defined(PCBTARANIS)
1679 #define JITTER_MEASURE_ACTIVE() (menuHandlers[menuLevel] == menuRadioDiagAnalogs)
1680 #elif defined(CLI)
1681 #define JITTER_MEASURE_ACTIVE() (1)
1682 #else
1683 #define JITTER_MEASURE_ACTIVE() (0)
1684 #endif
1685 #endif
1687 #if defined(INTERNAL_GPS)
1688 #include "gps.h"
1689 #endif
1691 #endif // _OPENTX_H_