Rework rssi code a bit (#5507)
[opentx.git] / radio / src / opentx.h
blob371ab215c85194fbf11d8f69673e4d4621c7be79
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(STM32)
54 #define CASE_STM32(x) x,
55 #else
56 #define CASE_STM32(x)
57 #endif
59 #if defined(VARIO) && defined(CPUARM)
60 #define CASE_VARIO_CPUARM(x) x,
61 #else
62 #define CASE_VARIO_CPUARM(x)
63 #endif
65 #if defined(LUA)
66 #define CASE_LUA(x) x,
67 #else
68 #define CASE_LUA(x)
69 #endif
71 #if defined(CPUARM) || defined(CPUM2560)
72 #define CASE_PERSISTENT_TIMERS(x) x,
73 #else
74 #define CASE_PERSISTENT_TIMERS(x)
75 #endif
77 #if defined(RTCLOCK)
78 #define CASE_RTCLOCK(x) x,
79 #else
80 #define CASE_RTCLOCK(x)
81 #endif
83 #if defined(BUZZER)
84 #define CASE_BUZZER(x) x,
85 #else
86 #define CASE_BUZZER(x)
87 #endif
89 #if defined(AUDIO)
90 #define CASE_AUDIO(x) x,
91 #else
92 #define CASE_AUDIO(x)
93 #endif
95 #if defined(VOICE)
96 #define CASE_VOICE(x) x,
97 #else
98 #define CASE_VOICE(x)
99 #endif
101 #if defined(PWM_BACKLIGHT)
102 #define CASE_PWM_BACKLIGHT(x) x,
103 #else
104 #define CASE_PWM_BACKLIGHT(x)
105 #endif
107 #if defined(TELEMETRY_FRSKY) && defined(FRSKY_HUB) && defined(GPS)
108 #define CASE_GPS(x) x,
109 #else
110 #define CASE_GPS(x)
111 #endif
113 #if defined(VARIO)
114 #define CASE_VARIO(x) x,
115 #else
116 #define CASE_VARIO(x)
117 #endif
119 #if defined(HAPTIC)
120 #define CASE_HAPTIC(x) x,
121 #else
122 #define CASE_HAPTIC(x)
123 #endif
125 #if defined(SPLASH)
126 #define CASE_SPLASH(x) x,
127 #else
128 #define CASE_SPLASH(x)
129 #endif
131 #if defined(TELEMETRY_FRSKY)
132 #define CASE_FRSKY(x) x,
133 #else
134 #define CASE_FRSKY(x)
135 #endif
137 #if defined(TELEMETRY_MAVLINK)
138 #define CASE_MAVLINK(x) x,
139 #else
140 #define CASE_MAVLINK(x)
141 #endif
143 #if defined(PXX)
144 #define CASE_PXX(x) x,
145 #else
146 #define CASE_PXX(x)
147 #endif
149 #if defined(SDCARD)
150 #define CASE_SDCARD(x) x,
151 #else
152 #define CASE_SDCARD(x)
153 #endif
155 #if defined(BLUETOOTH) && !(defined(PCBX9E) && !defined(USEHORUSBT))
156 #define CASE_BLUETOOTH(x) x,
157 #else
158 #define CASE_BLUETOOTH(x)
159 #endif
161 #if defined(HELI)
162 #define CASE_HELI(x) x,
163 #else
164 #define CASE_HELI(x)
165 #endif
167 #if defined(TEMPLATES)
168 #define CASE_TEMPLATES(x) x,
169 #else
170 #define CASE_TEMPLATES(x)
171 #endif
173 #if defined(FLIGHT_MODES)
174 #define CASE_FLIGHT_MODES(x) x,
175 #else
176 #define CASE_FLIGHT_MODES(x)
177 #endif
179 #if defined(CURVES)
180 #define CASE_CURVES(x) x,
181 #else
182 #define CASE_CURVES(x)
183 #endif
185 #if defined(GVARS)
186 #define CASE_GVARS(x) x,
187 #else
188 #define CASE_GVARS(x)
189 #endif
191 #if defined(PCBX9DP) || defined(PCBX9E)
192 #define CASE_PCBX9E_PCBX9DP(x) x,
193 #else
194 #define CASE_PCBX9E_PCBX9DP(x)
195 #endif
197 #if defined(PCBX9E)
198 #define CASE_PCBX9E(x) x,
199 #else
200 #define CASE_PCBX9E(x)
201 #endif
203 #if defined(PCBX10)
204 #define CASE_PCBX10(x) x,
205 #else
206 #define CASE_PCBX10(x)
207 #endif
209 #if defined(BLUETOOTH) && !(defined(PCBX9E) && !defined(USEHORUSBT))
210 #define CASE_BLUETOOTH(x) x,
211 #else
212 #define CASE_BLUETOOTH(x)
213 #endif
215 #if defined(PCBSKY9X) && !defined(AR9X) && !defined(REVA)
216 #define TX_CAPACITY_MEASUREMENT
217 #define CASE_CAPACITY(x) x,
218 #else
219 #define CASE_CAPACITY(x)
220 #endif
222 #if ROTARY_ENCODERS > 0
223 #define ROTARY_ENCODER_NAVIGATION
224 #endif
226 #if defined(FAI)
227 #define IS_FAI_ENABLED() true
228 #define IF_FAI_CHOICE(x)
229 #elif defined(FAI_CHOICE)
230 #define IS_FAI_ENABLED() g_eeGeneral.fai
231 #define IF_FAI_CHOICE(x) x,
232 #else
233 #define IS_FAI_ENABLED() false
234 #define IF_FAI_CHOICE(x)
235 #endif
237 #define IS_FAI_FORBIDDEN(idx) (IS_FAI_ENABLED() && idx >= MIXSRC_FIRST_TELEM)
239 #if defined(BLUETOOTH)
240 #if defined(X9E) && !defined(USEHORUSBT)
241 #define IS_BLUETOOTH_TRAINER() (g_model.trainerMode == TRAINER_MODE_SLAVE_BLUETOOTH)
242 #define IS_SLAVE_TRAINER() (g_model.trainerMode == TRAINER_MODE_SLAVE)
243 #else
244 #define IS_BLUETOOTH_TRAINER() (g_model.trainerMode == TRAINER_MODE_MASTER_BLUETOOTH || g_model.trainerMode == TRAINER_MODE_SLAVE_BLUETOOTH)
245 #define IS_SLAVE_TRAINER() (g_model.trainerMode == TRAINER_MODE_SLAVE || g_model.trainerMode == TRAINER_MODE_SLAVE_BLUETOOTH)
246 #endif
247 #else
248 #define IS_BLUETOOTH_TRAINER() false
249 #define IS_SLAVE_TRAINER() (g_model.trainerMode == TRAINER_MODE_SLAVE)
250 #endif
252 #if defined(CPUARM)
253 #define MASTER_VOLUME
254 #endif
256 #if !defined(CPUM64) && !defined(ACCURAT_THROTTLE_TIMER)
257 // code cost is about 16 bytes for higher throttle accuracy for timer
258 // would not be noticable anyway, because all version up to this change had only 16 steps;
259 // now it has already 32 steps; this define would increase to 128 steps
260 #if !defined(ACCURAT_THROTTLE_TIMER)
261 #define ACCURAT_THROTTLE_TIMER
262 #endif
263 #endif
265 // 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
266 #define RESX_SHIFT 10
267 #define RESX 1024
268 #define RESXu 1024u
269 #define RESXul 1024ul
270 #define RESXl 1024l
272 #include "board.h"
274 #if defined(DISK_CACHE)
275 #include "disk_cache.h"
276 #endif
278 #if defined(SIMU)
279 #include "targets/simu/simpgmspace.h"
280 #elif defined(CPUARM)
281 typedef const unsigned char pm_uchar;
282 typedef const char pm_char;
283 typedef const uint16_t pm_uint16_t;
284 typedef const uint8_t pm_uint8_t;
285 typedef const int16_t pm_int16_t;
286 typedef const int8_t pm_int8_t;
287 #define pgm_read_byte(address_short) (*(uint8_t*)(address_short))
288 #define PSTR(adr) adr
289 #define PROGMEM
290 #define pgm_read_adr(x) *(x)
291 #define cli()
292 #define sei()
293 #endif
295 #include "debug.h"
297 #if defined(PCBFLAMENCO)
298 #elif defined(PCBTARANIS) || defined(PCBHORUS)
299 #define SWSRC_THR SWSRC_SF2
300 #define SWSRC_GEA SWSRC_SG2
301 #define SWSRC_ID0 SWSRC_SA0
302 #define SWSRC_ID1 SWSRC_SA1
303 #define SWSRC_ID2 SWSRC_SA2
304 #define IS_MOMENTARY(sw) false // TODO
305 #else
306 #define SW_DSM2_BIND SW_TRN
307 #endif
309 #define NUM_PSWITCH (SWSRC_LAST_SWITCH-SWSRC_FIRST_SWITCH+1)
311 #include "myeeprom.h"
313 #if defined(CPUM64)
314 void memclear(void * ptr, uint8_t size);
315 #else
316 #define memclear(p, s) memset(p, 0, s)
317 #endif
319 void memswap(void * a, void * b, uint8_t size);
321 #if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || defined(PCBHORUS)
322 #define POT_CONFIG(x) ((g_eeGeneral.potsConfig >> (2*((x)-POT1)))&0x03)
323 #define IS_POT_MULTIPOS(x) (IS_POT(x) && POT_CONFIG(x)==POT_MULTIPOS_SWITCH)
324 #define IS_POT_WITHOUT_DETENT(x) (IS_POT(x) && POT_CONFIG(x)==POT_WITHOUT_DETENT)
325 #define IS_SLIDER_AVAILABLE(x) ((x) == SLIDER1 || (x) == SLIDER2 || (IS_SLIDER(x) && (g_eeGeneral.slidersConfig & (0x01 << ((x)-SLIDER1)))))
326 #define IS_POT_AVAILABLE(x) (IS_POT(x) && POT_CONFIG(x)!=POT_NONE)
327 #define IS_POT_SLIDER_AVAILABLE(x) (IS_POT_AVAILABLE(x) || IS_SLIDER_AVAILABLE(x))
328 #define IS_MULTIPOS_CALIBRATED(cal) (cal->count>0 && cal->count<XPOTS_MULTIPOS_COUNT)
329 #elif defined(PCBX7)
330 #define IS_POT_MULTIPOS(x) (false)
331 #define IS_POT_WITHOUT_DETENT(x) (false)
332 #define IS_POT_SLIDER_AVAILABLE(x) (true)
333 #define IS_MULTIPOS_CALIBRATED(cal) (false)
334 #elif defined(PCBFLAMENCO)
335 #define IS_POT_MULTIPOS(x) (false)
336 #define IS_POT_WITHOUT_DETENT(x) (false)
337 #define IS_POT_SLIDER_AVAILABLE(x) (true)
338 #define IS_MULTIPOS_CALIBRATED(cal) (false)
339 #else
340 #define IS_POT_MULTIPOS(x) (false)
341 #define IS_POT_WITHOUT_DETENT(x) (true)
342 #define IS_POT_SLIDER_AVAILABLE(x) (true)
343 #define IS_MULTIPOS_CALIBRATED(cal) (false)
344 #endif
346 #if defined(PWR_BUTTON_PRESS)
347 #define pwrOffPressed() pwrPressed()
348 #else
349 #define pwrOffPressed() (!pwrPressed())
350 #endif
352 #define PWR_PRESS_SHUTDOWN_DELAY 300 // 3s
354 #define GET_LOWRES_POT_POSITION(i) (getValue(MIXSRC_FIRST_POT+(i)) >> 4)
355 #define SAVE_POT_POSITION(i) g_model.potsWarnPosition[i] = GET_LOWRES_POT_POSITION(i)
357 #if ROTARY_ENCODERS > 0
358 #define IF_ROTARY_ENCODERS(x) x,
359 #else
360 #define IF_ROTARY_ENCODERS(x)
361 #endif
363 #define PPM_CENTER 1500
365 #if defined(PPM_CENTER_ADJUSTABLE)
366 #define PPM_CH_CENTER(ch) (PPM_CENTER + limitAddress(ch)->ppmCenter)
367 #else
368 #define PPM_CH_CENTER(ch) (PPM_CENTER)
369 #endif
371 #if defined(CPUARM)
372 #include "fifo.h"
373 #include "io/io_arm.h"
374 // This doesn't need protection on this processor
375 extern volatile tmr10ms_t g_tmr10ms;
376 #define get_tmr10ms() g_tmr10ms
377 #else
378 extern volatile tmr10ms_t g_tmr10ms;
379 extern inline uint16_t get_tmr10ms()
381 uint16_t time ;
382 cli();
383 time = g_tmr10ms ;
384 sei();
385 return time ;
387 #endif
389 #if defined(NAVIGATION_STICKS)
390 extern uint8_t StickScrollAllowed;
391 extern uint8_t StickScrollTimer;
392 #define STICK_SCROLL_TIMEOUT 9
393 #define STICK_SCROLL_DISABLE() StickScrollAllowed = 0
394 #else
395 #define STICK_SCROLL_DISABLE()
396 #endif
398 #if defined(CLI)
399 #include "cli.h"
400 #endif
402 #include "timers.h"
403 #include "storage/storage.h"
404 #include "pulses/pulses.h"
406 #if defined(CPUARM)
407 // Order is the same as in enum Protocols in myeeprom.h (none, ppm, xjt, dsm, crossfire, multi, r9m, sbus)
408 static const int8_t maxChannelsModules[] = { 0, 8, 8, -2, 8, 4, 8, 8}; // relative to 8!
409 static const int8_t maxChannelsXJT[] = { 0, 8, 0, 4 }; // relative to 8!
410 #define MAX_TRAINER_CHANNELS_M8() (MAX_TRAINER_CHANNELS-8)
411 #endif
415 #if defined(MULTIMODULE)
416 #define IS_MODULE_MULTIMODULE(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_MULTIMODULE)
417 #else
418 #define IS_MODULE_MULTIMODULE(idx) (false)
419 #endif
421 #if defined(PCBTARANIS) || defined(PCBHORUS)
422 #if defined(TARANIS_INTERNAL_PPM)
423 #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))
424 #else
425 #define IS_MODULE_PPM(idx) (idx==TRAINER_MODULE || (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_PPM))
426 #endif
427 #define IS_MODULE_XJT(idx) (g_model.moduleData[idx].type==MODULE_TYPE_XJT)
429 #if defined(CROSSFIRE)
430 #define IS_MODULE_CROSSFIRE(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_CROSSFIRE)
431 #else
432 #define IS_MODULE_CROSSFIRE(idx) (false)
433 #endif
434 #if defined(TARANIS_INTERNAL_PPM)
435 #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])
436 #else
437 #define MAX_INTERNAL_MODULE_CHANNELS() (maxChannelsXJT[1+g_model.moduleData[INTERNAL_MODULE].rfProtocol])
438 #endif
439 #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])
440 #define MAX_CHANNELS(idx) (idx==INTERNAL_MODULE ? MAX_INTERNAL_MODULE_CHANNELS() : (idx==EXTERNAL_MODULE ? MAX_EXTERNAL_MODULE_CHANNELS() : MAX_TRAINER_CHANNELS_M8()))
441 #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))
442 #elif defined(PCBSKY9X) && !defined(REVA)
443 #define IS_MODULE_PPM(idx) (idx==TRAINER_MODULE || idx==EXTRA_MODULE || (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_PPM))
444 #define IS_MODULE_XJT(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_XJT)
445 #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])
446 #define MAX_EXTRA_MODULE_CHANNELS() (8) // Only PPM (16ch PPM)
447 #define MAX_CHANNELS(idx) (idx==EXTERNAL_MODULE ? MAX_EXTERNAL_MODULE_CHANNELS() : (idx==EXTRA_MODULE ? MAX_EXTRA_MODULE_CHANNELS() : MAX_TRAINER_CHANNELS_M8()))
448 #define NUM_CHANNELS(idx) (8+g_model.moduleData[idx].channelsCount)
449 #define IS_MODULE_CROSSFIRE(idx) (false)
450 #else
451 #define IS_MODULE_PPM(idx) (idx==TRAINER_MODULE || (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_PPM))
452 #define IS_MODULE_XJT(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_XJT)
453 #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])
454 #define MAX_CHANNELS(idx) (idx==EXTERNAL_MODULE ? MAX_EXTERNAL_MODULE_CHANNELS() : MAX_TRAINER_CHANNELS_M8())
455 #define NUM_CHANNELS(idx) (8+g_model.moduleData[idx].channelsCount)
456 #endif
457 #define IS_MODULE_R9M(idx) (g_model.moduleData[idx].type == MODULE_TYPE_R9M)
458 #define IS_MODULE_R9M_FCC(idx) (IS_MODULE_R9M(idx) && g_model.moduleData[idx].subType == MODULE_SUBTYPE_R9M_FCC)
459 #define IS_MODULE_R9M_LBT(idx) (IS_MODULE_R9M(idx) && g_model.moduleData[idx].subType == MODULE_SUBTYPE_R9M_LBT)
460 #define IS_MODULE_PXX(idx) (IS_MODULE_XJT(idx) || IS_MODULE_R9M(idx))
462 #if defined(DSM2)
463 #define IS_MODULE_DSM2(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_DSM2)
464 #define IS_MODULE_SBUS(idx) (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_SBUS)
465 #else
466 #define IS_MODULE_DSM2(idx) (false)
467 #endif
470 #if defined(MULTIMODULE)
471 #define IS_MULTIMODULE_DSM(idx) (IS_MODULE_MULTIMODULE(idx) && g_model.moduleData[idx].getMultiProtocol(true) == MM_RF_PROTO_DSM2)
472 #define DEFAULT_CHANNELS(idx) (IS_MODULE_PPM(idx) ? 0 : IS_MULTIMODULE_DSM(idx) ? -1 : MAX_CHANNELS(idx))
473 #else
474 #define DEFAULT_CHANNELS(idx) (IS_MODULE_PPM(idx) ? 0 : MAX_CHANNELS(idx))
475 #endif
477 #if defined(CPUARM)
478 #define MASK_CFN_TYPE uint64_t // current max = 64 function switches
479 #define MASK_FUNC_TYPE uint32_t // current max = 32 functions
480 #elif defined(CPUM64)
481 #define MASK_CFN_TYPE uint16_t // current max = 16 function switches
482 #define MASK_FUNC_TYPE uint8_t // current max = 8 functions
483 #else
484 #define MASK_CFN_TYPE uint32_t // current max = 32 function switches
485 #define MASK_FUNC_TYPE uint8_t // current max = 8 functions
486 #endif
488 typedef struct {
489 MASK_FUNC_TYPE activeFunctions;
490 MASK_CFN_TYPE activeSwitches;
491 tmr10ms_t lastFunctionTime[MAX_SPECIAL_FUNCTIONS];
493 inline bool isFunctionActive(uint8_t func)
495 return activeFunctions & ((MASK_FUNC_TYPE)1 << func);
498 void reset()
500 memclear(this, sizeof(*this));
502 } CustomFunctionsContext;
504 #include "strhelpers.h"
505 #include "gui.h"
507 #if defined(TEMPLATES)
508 #include "templates.h"
509 #endif
511 #if !defined(SIMU)
512 #define assert(x)
513 #if !defined(CPUARM) || !defined(DEBUG)
514 #define printf printf_not_allowed
515 #endif
516 #endif
518 extern const pm_uint8_t bchout_ar[];
519 extern const pm_uint8_t modn12x3[];
521 //convert from mode 1 to mode stickMode
522 //NOTICE! => 0..3 -> 0..3
523 #define RUD_STICK 0
524 #define ELE_STICK 1
525 #define THR_STICK 2
526 #define AIL_STICK 3
527 #define CONVERT_MODE(x) (((x)<=AIL_STICK) ? pgm_read_byte(modn12x3 + 4*g_eeGeneral.stickMode + (x)) : (x) )
529 extern uint8_t channel_order(uint8_t x);
531 #define THRCHK_DEADBAND 16
533 #if defined(COLORLCD)
534 #define SPLASH_NEEDED() (false)
535 #elif defined(PCBTARANIS)
536 #define SPLASH_NEEDED() (g_eeGeneral.splashMode != 3)
537 #elif defined(CPUARM)
538 #define SPLASH_NEEDED() (g_model.moduleData[EXTERNAL_MODULE].type != MODULE_TYPE_DSM2 && !g_eeGeneral.splashMode)
539 #else
540 #define SPLASH_NEEDED() (!IS_DSM2_PROTOCOL(g_model.protocol) && !g_eeGeneral.splashMode)
541 #endif
543 #if defined(PCBHORUS)
544 #define SPLASH_TIMEOUT 0 /* we use the splash duration to load stuff from the SD */
545 #elif defined(FSPLASH)
546 #define SPLASH_TIMEOUT (g_eeGeneral.splashMode == 0 ? 60000/*infinite=10mn*/ : ((4*100) * (g_eeGeneral.splashMode & 0x03)))
547 #elif defined(PCBTARANIS) || defined(PCBFLAMENCO)
548 #define SPLASH_TIMEOUT (g_eeGeneral.splashMode==-4 ? 1500 : (g_eeGeneral.splashMode<=0 ? (400-g_eeGeneral.splashMode*200) : (400-g_eeGeneral.splashMode*100)))
549 #else
550 #define SPLASH_TIMEOUT (4*100) // 4 seconds
551 #endif
553 #if defined(ROTARY_ENCODERS)
554 #define IS_ROTARY_ENCODER_NAVIGATION_ENABLE() g_eeGeneral.reNavigation
555 extern volatile rotenc_t rotencValue[ROTARY_ENCODERS];
556 #define ROTARY_ENCODER_NAVIGATION_VALUE rotencValue[g_eeGeneral.reNavigation - 1]
557 #elif defined(ROTARY_ENCODER_NAVIGATION)
558 #define IS_ROTARY_ENCODER_NAVIGATION_ENABLE() true
559 extern volatile rotenc_t rotencValue[1];
560 #define ROTARY_ENCODER_NAVIGATION_VALUE rotencValue[0]
561 #endif
563 #if defined(CPUARM) && defined(ROTARY_ENCODER_NAVIGATION)
564 extern uint8_t rotencSpeed;
565 #define ROTENC_LOWSPEED 1
566 #define ROTENC_MIDSPEED 5
567 #define ROTENC_HIGHSPEED 50
568 #define ROTENC_DELAY_MIDSPEED 32
569 #define ROTENC_DELAY_HIGHSPEED 16
570 #endif
572 #define HEART_TIMER_10MS 1
573 #define HEART_TIMER_PULSES 2 // when multiple modules this is the first one
574 #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS)
575 #define HEART_WDT_CHECK (HEART_TIMER_10MS + (HEART_TIMER_PULSES << 0) + (HEART_TIMER_PULSES << 1))
576 #else
577 #define HEART_WDT_CHECK (HEART_TIMER_10MS + HEART_TIMER_PULSES)
578 #endif
579 extern uint8_t heartbeat;
581 #if defined(CPUARM) && !defined(BOOT)
582 void watchdogSuspend(uint32_t timeout);
583 #define WATCHDOG_SUSPEND(x) watchdogSuspend(x)
584 #else
585 #define WATCHDOG_SUSPEND(...)
586 #endif
588 #define MAX_ALERT_TIME 60
590 struct t_inactivity
592 uint16_t counter;
593 uint8_t sum;
596 extern struct t_inactivity inactivity;
598 #define LEN_STD_CHARS 40
600 #if defined(TRANSLATIONS_CZ)
601 #define ZCHAR_MAX (LEN_STD_CHARS)
602 #else
603 #define ZCHAR_MAX (LEN_STD_CHARS + LEN_SPECIAL_CHARS)
604 #endif
606 char hex2zchar(uint8_t hex);
607 char idx2char(int8_t idx);
608 #if defined(CPUARM) || defined(SIMU)
609 int8_t char2idx(char c);
610 void str2zchar(char *dest, const char *src, int size);
611 int zchar2str(char *dest, const char *src, int size);
612 #endif
614 #include "keys.h"
615 #include "pwr.h"
617 #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS)
618 div_t switchInfo(int switchPosition);
619 extern uint8_t potsPos[NUM_XPOTS];
620 #endif
622 #if defined(PCBHORUS)
623 uint16_t trimDown(uint16_t idx); // TODO why?
624 #else
625 uint8_t trimDown(uint8_t idx);
626 #endif
627 void readKeysAndTrims();
629 uint16_t evalChkSum();
631 #if !defined(GUI)
632 #define RAISE_ALERT(...)
633 #define ALERT(...)
634 #elif defined(VOICE)
635 #define RAISE_ALERT(title, msg, info, sound) showAlertBox(title, msg, info, sound)
636 #define ALERT(title, msg, sound) alert(title, msg, sound)
637 #else
638 #define RAISE_ALERT(title, msg, info, sound) showAlertBox(title, msg, info)
639 #define ALERT(title, msg, sound) alert(title, msg)
640 #endif
642 void alert(const pm_char * t, const pm_char * s ALERT_SOUND_ARG);
644 enum PerOutMode {
645 e_perout_mode_normal = 0,
646 e_perout_mode_inactive_flight_mode = 1,
647 e_perout_mode_notrainer = 2,
648 e_perout_mode_notrims = 4,
649 e_perout_mode_nosticks = 8,
650 e_perout_mode_noinput = e_perout_mode_notrainer+e_perout_mode_notrims+e_perout_mode_nosticks
654 #if defined(MODULE_ALWAYS_SEND_PULSES)
655 extern uint8_t startupWarningState;
657 enum StartupWarningStates {
658 STARTUP_WARNING_THROTTLE,
659 STARTUP_WARNING_SWITCHES,
660 STARTUP_WARNING_DONE,
662 #endif
665 // Fiddle to force compiler to use a pointer
666 #if defined(CPUARM) || defined(SIMU)
667 #define FORCE_INDIRECT(ptr)
668 #else
669 #define FORCE_INDIRECT(ptr) __asm__ __volatile__ ("" : "=e" (ptr) : "0" (ptr))
670 #endif
672 extern uint8_t mixerCurrentFlightMode;
673 extern uint8_t lastFlightMode;
674 extern uint8_t flightModeTransitionLast;
676 #if defined(CPUARM)
677 #define bitfield_channels_t uint32_t
678 #else
679 #define bitfield_channels_t uint16_t
680 #endif
682 #if defined(SIMU)
683 inline int availableMemory() { return 1000; }
684 #elif defined(CPUARM) && !defined(SIMU)
685 extern unsigned char *heap;
686 extern int _end;
687 extern int _estack;
688 extern int _main_stack_start;
689 extern int _heap_end;
690 #define availableMemory() ((unsigned int)((unsigned char *)&_heap_end - heap))
691 #endif
693 void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms);
694 void evalMixes(uint8_t tick10ms);
695 void doMixerCalculations();
696 void scheduleNextMixerCalculation(uint8_t module, uint16_t delay);
698 #if defined(CPUARM)
699 void checkTrims();
700 #endif
701 void perMain();
702 NOINLINE void per10ms();
704 getvalue_t getValue(mixsrc_t i);
706 #if defined(CPUARM)
707 #define GETSWITCH_MIDPOS_DELAY 1
708 bool getSwitch(swsrc_t swtch, uint8_t flags=0);
709 #else
710 bool getSwitch(swsrc_t swtch);
711 #endif
713 void logicalSwitchesTimerTick();
714 void logicalSwitchesReset();
716 #if defined(CPUARM)
717 void evalLogicalSwitches(bool isCurrentPhase=true);
718 void logicalSwitchesCopyState(uint8_t src, uint8_t dst);
719 #define LS_RECURSIVE_EVALUATION_RESET()
720 #else
721 #define evalLogicalSwitches(xxx)
722 #define GETSWITCH_RECURSIVE_TYPE uint16_t
723 extern volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_used;
724 extern volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_value;
725 #define LS_RECURSIVE_EVALUATION_RESET() s_last_switch_used = 0
726 #endif
728 #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS)
729 void getSwitchesPosition(bool startup);
730 #else
731 #define getSwitchesPosition(...)
732 #endif
734 extern swarnstate_t switches_states;
735 swsrc_t getMovedSwitch();
737 #if defined(CPUARM)
738 #define GET_MOVED_SOURCE_PARAMS uint8_t min
739 int8_t getMovedSource(GET_MOVED_SOURCE_PARAMS);
740 #define GET_MOVED_SOURCE(min, max) getMovedSource(min)
741 #else
742 #define GET_MOVED_SOURCE_PARAMS
743 int8_t getMovedSource();
744 #define GET_MOVED_SOURCE(min, max) getMovedSource()
745 #endif
747 #if defined(FLIGHT_MODES)
748 extern uint8_t getFlightMode();
749 #else
750 #define getFlightMode() 0
751 #endif
753 #if !defined(CPUARM)
754 uint8_t getTrimFlightMode(uint8_t phase, uint8_t idx);
755 #else
756 #define getTrimFlightMode(phase, idx) (phase)
757 #endif
759 #if defined(GVARS)
760 extern int8_t trimGvar[NUM_STICKS+NUM_AUX_TRIMS];
761 #define TRIM_REUSED(idx) trimGvar[idx] >= 0
762 #else
763 #define TRIM_REUSED(idx) 0
764 #endif
766 trim_t getRawTrimValue(uint8_t phase, uint8_t idx);
767 int getTrimValue(uint8_t phase, uint8_t idx);
769 #if defined(CPUARM)
770 bool setTrimValue(uint8_t phase, uint8_t idx, int trim);
771 #else
772 void setTrimValue(uint8_t phase, uint8_t idx, int trim);
773 #endif
775 #if defined(ROTARY_ENCODERS)
776 int16_t getRotaryEncoder(uint8_t idx);
777 void incRotaryEncoder(uint8_t idx, int8_t inc);
778 #endif
780 #if defined(PCBGRUVIN9X) || defined(PCBMEGA2560)
781 #define ROTARY_ENCODER_GRANULARITY (1)
782 #elif defined(PCBSKY9X)
783 #define ROTARY_ENCODER_GRANULARITY (2 << g_eeGeneral.rotarySteps)
784 #else
785 #define ROTARY_ENCODER_GRANULARITY (2)
786 #endif
788 #include "gvars.h"
790 extern uint16_t sessionTimer;
791 extern uint16_t s_timeCumThr;
792 extern uint16_t s_timeCum16ThrP;
794 #if defined(OVERRIDE_CHANNEL_FUNCTION)
795 #if defined(CPUARM)
796 #define OVERRIDE_CHANNEL_UNDEFINED -4096
797 #else
798 #define OVERRIDE_CHANNEL_UNDEFINED -128
799 #endif
800 extern safetych_t safetyCh[MAX_OUTPUT_CHANNELS];
801 #endif
803 extern uint8_t trimsCheckTimer;
805 #if defined(CPUARM)
806 extern uint8_t trimsDisplayTimer;
807 extern uint8_t trimsDisplayMask;
808 #endif
810 void flightReset(uint8_t check=true);
812 extern uint8_t unexpectedShutdown;
814 extern uint16_t maxMixerDuration;
816 #if !defined(CPUARM)
817 extern uint8_t g_tmr1Latency_max;
818 extern uint8_t g_tmr1Latency_min;
819 extern uint16_t lastMixerDuration;
820 #endif
822 #if defined(CPUARM)
823 #define DURATION_MS_PREC2(x) ((x)/20)
824 #else
825 #define DURATION_MS_PREC2(x) ((x)*100)/16
826 #endif
828 #if defined(THRTRACE)
829 #if defined(COLORLCD)
830 #define MAXTRACE (LCD_W-2*10)
831 #else
832 #define MAXTRACE (LCD_W - 8)
833 #endif
834 extern uint8_t s_traceBuf[MAXTRACE];
835 extern uint16_t s_traceWr;
836 extern uint8_t s_cnt_10s;
837 extern uint16_t s_cnt_samples_thr_10s;
838 extern uint16_t s_sum_samples_thr_10s;
839 #define RESET_THR_TRACE() s_traceWr = s_cnt_10s = s_cnt_samples_thr_10s = s_sum_samples_thr_10s = s_timeCum16ThrP = s_timeCumThr = 0
840 #else
841 #define RESET_THR_TRACE() s_timeCum16ThrP = s_timeCumThr = 0
842 #endif
844 #if defined(SIMU)
845 uint16_t getTmr2MHz();
846 uint16_t getTmr16KHz();
847 #elif defined(STM32)
848 static inline uint16_t getTmr2MHz() { return TIMER_2MHz_TIMER->CNT; }
849 #elif defined(PCBSKY9X)
850 static inline uint16_t getTmr2MHz() { return TC1->TC_CHANNEL[0].TC_CV; }
851 #else
852 uint16_t getTmr16KHz();
853 #endif
855 #if !defined(CPUARM)
856 uint16_t stackAvailable();
857 #endif
859 #if defined(SPLASH)
860 void doSplash();
861 #endif
863 #if MENUS_LOCK == 1
864 extern bool readonly;
865 extern bool readonlyUnlocked();
866 #define READ_ONLY() readonly
867 #define READ_ONLY_UNLOCKED() readonlyUnlocked()
868 #else
869 #define READ_ONLY() false
870 #define READ_ONLY_UNLOCKED() true
871 #endif
873 void checkLowEEPROM();
874 void checkTHR();
875 void checkSwitches();
876 void checkAlarm();
877 void checkAll();
879 #if !defined(SIMU)
880 void getADC();
881 #if defined(CPUARM)
882 #define GET_ADC_IF_MIXER_NOT_RUNNING() do { if (s_pulses_paused) getADC(); } while(0)
883 #else
884 #define GET_ADC_IF_MIXER_NOT_RUNNING() getADC()
885 #endif
886 #endif
888 #if defined(SBUS)
889 #include "sbus.h"
890 #endif
892 void backlightOn();
893 void checkBacklight();
894 void doLoopCommonActions();
896 #define BITMASK(bit) (1<<(bit))
898 #if !defined(UNUSED)
899 #define UNUSED(x) ((void)(x)) /* to avoid warnings */
900 #endif
902 /// returns the number of elements of an array
903 #define DIM(arr) (sizeof((arr))/sizeof((arr)[0]))
905 template<class t> FORCEINLINE t min(t a, t b) { return a<b?a:b; }
906 template<class t> FORCEINLINE t max(t a, t b) { return a>b?a:b; }
907 template<class t> FORCEINLINE t sgn(t a) { return a>0 ? 1 : (a < 0 ? -1 : 0); }
908 template<class t> FORCEINLINE t limit(t mi, t x, t ma) { return min(max(mi,x),ma); }
909 template<class t> void SWAP(t & a, t & b) { t tmp = b; b = a; a = tmp; }
911 uint16_t isqrt32(uint32_t n);
913 #if defined(CPUARM) && !defined(BOOT)
914 #include "tasks_arm.h"
915 extern OS_MutexID mixerMutex;
916 inline void pauseMixerCalculations()
918 CoEnterMutexSection(mixerMutex);
921 inline void resumeMixerCalculations()
923 CoLeaveMutexSection(mixerMutex);
925 #else
926 #define pauseMixerCalculations()
927 #define resumeMixerCalculations()
928 #endif
930 void generalDefault();
931 void modelDefault(uint8_t id);
933 #if defined(CPUARM)
934 void checkModelIdUnique(uint8_t index, uint8_t module);
935 #endif
937 #if defined(CPUARM)
938 uint32_t hash(const void * ptr, uint32_t size);
939 inline int divRoundClosest(const int n, const int d)
941 if (d == 0)
942 return 0;
943 else
944 return ((n < 0) ^ (d < 0)) ? ((n - d/2)/d) : ((n + d/2)/d);
947 #define calc100to256_16Bits(x) calc100to256(x)
948 #define calc100toRESX_16Bits(x) calc100toRESX(x)
950 inline int calc100to256(int x)
952 return divRoundClosest(x*256, 100);
955 inline int calc100toRESX(int x)
957 return divRoundClosest(x*RESX, 100);
960 inline int calc1000toRESX(int x)
962 return divRoundClosest(x*RESX, 1000);
965 inline int calcRESXto1000(int x)
967 return divRoundClosest(x*1000, RESX);
970 inline int calcRESXto100(int x)
972 return divRoundClosest(x*100, RESX);
975 #else
976 extern int16_t calc100to256_16Bits(int16_t x); // @@@2 open.20.fsguruh: return x*2.56
977 extern int16_t calc100to256(int8_t x); // @@@2 open.20.fsguruh: return x*2.56
978 extern int16_t calc100toRESX_16Bits(int16_t x); // @@@ open.20.fsguruh
979 extern int16_t calc100toRESX(int8_t x);
980 extern int16_t calc1000toRESX(int16_t x);
981 extern int16_t calcRESXto1000(int16_t x);
982 extern int8_t calcRESXto100(int16_t x);
983 #endif
985 #if defined(COLORLCD)
986 extern const char vers_stamp[];
987 extern const char date_stamp[];
988 extern const char time_stamp[];
989 extern const char eeprom_stamp[];
990 #else
991 extern const char vers_stamp[];
992 #endif
994 extern uint8_t g_vbat100mV;
995 #if LCD_W > 128
996 #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))
997 #else
998 #define GET_TXBATT_BARS() (limit<int8_t>(2, 20 * (g_vbat100mV - g_eeGeneral.vBatMin - 90) / (30 + g_eeGeneral.vBatMax - g_eeGeneral.vBatMin), 20))
999 #endif
1000 #define IS_TXBATT_WARNING() (g_vbat100mV <= g_eeGeneral.vBatWarn)
1003 #define g_blinkTmr10ms (*(uint8_t*)&g_tmr10ms)
1004 extern uint8_t g_beepCnt;
1005 extern uint8_t g_beepVal[5];
1007 #include "trainer_input.h"
1009 extern int32_t chans[MAX_OUTPUT_CHANNELS];
1010 extern int16_t ex_chans[MAX_OUTPUT_CHANNELS]; // Outputs (before LIMITS) of the last perMain
1011 extern int16_t channelOutputs[MAX_OUTPUT_CHANNELS];
1012 extern uint16_t BandGap;
1014 #if defined(CPUARM)
1015 #define NUM_INPUTS (MAX_INPUTS)
1016 #else
1017 #define NUM_INPUTS (NUM_STICKS)
1018 #endif
1020 int expo(int x, int k);
1022 #if defined(CPUARM)
1023 inline int getMaximumValue(int source)
1025 if (source < MIXSRC_FIRST_CH)
1026 return 100;
1027 else if (source <= MIXSRC_LAST_CH)
1028 return g_model.extendedLimits ? 150 : 100;
1029 else if (source >= MIXSRC_FIRST_TIMER && source <= MIXSRC_LAST_TIMER)
1030 return (23*60)+59;
1031 else
1032 return 30000;
1034 #endif
1036 // Curves
1037 enum BaseCurves {
1038 CURVE_NONE,
1039 CURVE_X_GT0,
1040 CURVE_X_LT0,
1041 CURVE_ABS_X,
1042 CURVE_F_GT0,
1043 CURVE_F_LT0,
1044 CURVE_ABS_F,
1045 CURVE_BASE
1047 int8_t * curveAddress(uint8_t idx);
1048 struct point_t
1050 coord_t x;
1051 coord_t y;
1053 point_t getPoint(uint8_t i);
1054 #if !defined(CURVES)
1055 #define LOAD_MODEL_CURVES()
1056 #define applyCurve(x, idx) (x)
1057 #elif defined(CPUARM)
1058 typedef CurveData CurveInfo;
1059 void loadCurves();
1060 #define LOAD_MODEL_CURVES() loadCurves()
1061 int intpol(int x, uint8_t idx);
1062 int applyCurve(int x, CurveRef & curve);
1063 int applyCustomCurve(int x, uint8_t idx);
1064 int applyCurrentCurve(int x);
1065 int8_t getCurveX(int noPoints, int point);
1066 void resetCustomCurveX(int8_t * points, int noPoints);
1067 bool moveCurve(uint8_t index, int8_t shift); // TODO bool?
1068 #else
1069 struct CurveInfo {
1070 int8_t * crv;
1071 uint8_t points:7;
1072 uint8_t custom:1;
1074 CurveInfo curveInfo(uint8_t idx);
1075 int intpol(int x, uint8_t idx);
1076 int applyCurve(int x, int8_t idx);
1077 #define LOAD_MODEL_CURVES()
1078 #define applyCustomCurve(x, idx) intpol(x, idx)
1079 int applyCurrentCurve(int x);
1080 bool moveCurve(uint8_t index, int8_t shift, int8_t custom=0);
1081 #endif
1083 #if defined(CPUARM)
1084 #define APPLY_EXPOS_EXTRA_PARAMS_INC , uint8_t ovwrIdx=0, int16_t ovwrValue=0
1085 #define APPLY_EXPOS_EXTRA_PARAMS , uint8_t ovwrIdx, int16_t ovwrValue
1086 #else
1087 #define APPLY_EXPOS_EXTRA_PARAMS_INC
1088 #define APPLY_EXPOS_EXTRA_PARAMS
1089 #endif
1091 #if defined(CPUARM)
1092 void clearInputs();
1093 void defaultInputs();
1094 #endif
1096 void applyExpos(int16_t * anas, uint8_t mode APPLY_EXPOS_EXTRA_PARAMS_INC);
1097 int16_t applyLimits(uint8_t channel, int32_t value);
1099 void evalInputs(uint8_t mode);
1100 uint16_t anaIn(uint8_t chan);
1102 extern int16_t calibratedAnalogs[NUM_CALIBRATED_ANALOGS];
1104 #define FLASH_DURATION 20 /*200ms*/
1106 extern uint8_t beepAgain;
1107 extern uint16_t lightOffCounter;
1108 extern uint8_t flashCounter;
1109 extern uint8_t mixWarning;
1111 FlightModeData * flightModeAddress(uint8_t idx);
1112 ExpoData * expoAddress(uint8_t idx);
1113 MixData * mixAddress(uint8_t idx);
1114 LimitData * limitAddress(uint8_t idx);
1115 LogicalSwitchData * lswAddress(uint8_t idx);
1117 // static variables used in evalFlightModeMixes - moved here so they don't interfere with the stack
1118 // It's also easier to initialize them here.
1119 #if defined(CPUARM)
1120 extern int8_t virtualInputsTrims[NUM_INPUTS];
1121 #else
1122 extern int16_t rawAnas[NUM_INPUTS];
1123 #endif
1125 extern int16_t anas [NUM_INPUTS];
1126 extern int16_t trims[NUM_STICKS+NUM_AUX_TRIMS];
1127 extern BeepANACenter bpanaCenter;
1129 extern uint8_t s_mixer_first_run_done;
1131 void applyDefaultTemplate();
1133 void incSubtrim(uint8_t idx, int16_t inc);
1134 void instantTrim();
1135 void evalTrims();
1136 void copyTrimsToOffset(uint8_t ch);
1137 void copySticksToOffset(uint8_t ch);
1138 void moveTrimsToOffsets();
1140 #if defined(CPUARM)
1141 #define ACTIVE_PHASES_TYPE uint16_t
1142 #define DELAY_POS_SHIFT 0
1143 #define DELAY_POS_MARGIN 3
1144 #define delayval_t int16_t
1145 PACK(typedef struct {
1146 uint16_t delay;
1147 int16_t now; // timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw
1148 int16_t prev;
1149 uint8_t activeMix;
1150 uint8_t activeExpo;
1151 }) SwOn;
1152 #else
1153 #define ACTIVE_PHASES_TYPE uint8_t
1154 #define DELAY_POS_SHIFT 10
1155 #define DELAY_POS_MARGIN 0
1156 #define delayval_t int8_t
1157 PACK(typedef struct {
1158 uint16_t delay:10;
1159 int16_t now:2; // timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw
1160 int16_t prev:2;
1161 int16_t activeMix:1;
1162 int16_t activeExpo:1;
1163 }) SwOn;
1164 #endif
1166 extern SwOn swOn[MAX_MIXERS];
1167 extern int24_t act[MAX_MIXERS];
1169 #if defined(BOLD_FONT)
1170 inline bool isExpoActive(uint8_t expo)
1172 return swOn[expo].activeExpo;
1175 inline bool isMixActive(uint8_t mix)
1177 return swOn[mix].activeMix;
1179 #else
1180 #define isExpoActive(x) false
1181 #define isMixActive(x) false
1182 #endif
1184 enum LogicalSwitchFamilies {
1185 LS_FAMILY_OFS,
1186 LS_FAMILY_BOOL,
1187 LS_FAMILY_COMP,
1188 LS_FAMILY_DIFF,
1189 LS_FAMILY_TIMER,
1190 LS_FAMILY_STICKY,
1191 LS_FAMILY_RANGE,
1192 LS_FAMILY_EDGE
1195 uint8_t lswFamily(uint8_t func);
1196 int16_t lswTimerValue(delayval_t val);
1198 enum FunctionsActive {
1199 FUNCTION_TRAINER,
1200 FUNCTION_INSTANT_TRIM = FUNCTION_TRAINER+4,
1201 FUNCTION_VARIO,
1202 FUNCTION_BACKLIGHT,
1203 #if defined(SDCARD)
1204 FUNCTION_LOGS,
1205 #endif
1206 #if defined(CPUARM)
1207 FUNCTION_BACKGND_MUSIC,
1208 FUNCTION_BACKGND_MUSIC_PAUSE,
1209 #endif
1212 #define VARIO_FREQUENCY_ZERO 700/*Hz*/
1213 #define VARIO_FREQUENCY_RANGE 1000/*Hz*/
1214 #define VARIO_REPEAT_ZERO 500/*ms*/
1215 #define VARIO_REPEAT_MAX 80/*ms*/
1217 #if defined(CPUARM)
1218 extern CustomFunctionsContext modelFunctionsContext;
1219 extern CustomFunctionsContext globalFunctionsContext;
1220 inline bool isFunctionActive(uint8_t func)
1222 return globalFunctionsContext.isFunctionActive(func) || modelFunctionsContext.isFunctionActive(func);
1224 void evalFunctions(const CustomFunctionData * functions, CustomFunctionsContext & functionsContext);
1225 inline void customFunctionsReset()
1227 globalFunctionsContext.reset();
1228 modelFunctionsContext.reset();
1230 #else
1231 extern CustomFunctionsContext modelFunctionsContext;
1232 #define isFunctionActive(func) modelFunctionsContext.isFunctionActive(func)
1233 void evalFunctions();
1234 #define customFunctionsReset() modelFunctionsContext.reset()
1235 #endif
1237 #include "telemetry/telemetry.h"
1239 #if defined(CPUARM)
1240 uint8_t crc8(const uint8_t * ptr, uint32_t len);
1241 uint16_t crc16(const uint8_t * ptr, uint32_t len);
1242 #endif
1244 #define PLAY_REPEAT(x) (x) /* Range 0 to 15 */
1245 #define PLAY_NOW 0x10
1246 #define PLAY_BACKGROUND 0x20
1247 #define PLAY_INCREMENT(x) ((uint8_t)(((uint8_t)x) << 6)) /* -1, 0, 1, 2 */
1249 enum AUDIO_SOUNDS {
1250 AUDIO_HELLO,
1251 #if defined(CPUARM)
1252 AU_BYE,
1253 #endif
1254 #if defined(VOICE)
1255 AU_THROTTLE_ALERT,
1256 AU_SWITCH_ALERT,
1257 AU_BAD_RADIODATA,
1258 #endif
1259 AU_TX_BATTERY_LOW,
1260 AU_INACTIVITY,
1261 #if defined(CPUARM)
1262 AU_RSSI_ORANGE,
1263 AU_RSSI_RED,
1264 AU_SWR_RED,
1265 AU_TELEMETRY_LOST,
1266 AU_TELEMETRY_BACK,
1267 AU_TRAINER_LOST,
1268 AU_TRAINER_BACK,
1269 AU_SENSOR_LOST,
1270 AU_SERVO_KO,
1271 AU_RX_OVERLOAD,
1272 AU_MODEL_STILL_POWERED,
1273 #endif
1274 #if defined(PCBSKY9X)
1275 AU_TX_MAH_HIGH,
1276 AU_TX_TEMP_HIGH,
1277 #endif
1278 AU_ERROR,
1279 AU_WARNING1,
1280 AU_WARNING2,
1281 AU_WARNING3,
1282 AU_TRIM_MIDDLE,
1283 #if defined(CPUARM)
1284 AU_TRIM_MIN,
1285 AU_TRIM_MAX,
1286 #endif
1287 #if defined(CPUARM)
1288 AU_STICK1_MIDDLE,
1289 AU_STICK2_MIDDLE,
1290 AU_STICK3_MIDDLE,
1291 AU_STICK4_MIDDLE,
1292 #endif
1293 #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS)
1294 AU_POT1_MIDDLE,
1295 AU_POT2_MIDDLE,
1296 AU_SLIDER1_MIDDLE,
1297 AU_SLIDER2_MIDDLE,
1298 #if defined(PCBX9E)
1299 AU_SLIDER3_MIDDLE,
1300 AU_SLIDER4_MIDDLE,
1301 #endif
1302 #elif defined(CPUARM)
1303 AU_POT1_MIDDLE,
1304 AU_POT2_MIDDLE,
1305 AU_POT3_MIDDLE,
1306 #else
1307 AU_POT_MIDDLE,
1308 #endif
1309 AU_MIX_WARNING_1,
1310 AU_MIX_WARNING_2,
1311 AU_MIX_WARNING_3,
1312 #if defined(CPUARM)
1313 AU_TIMER1_ELAPSED,
1314 AU_TIMER2_ELAPSED,
1315 AU_TIMER3_ELAPSED,
1316 #endif
1318 AU_SPECIAL_SOUND_FIRST,
1319 AU_SPECIAL_SOUND_BEEP1 = AU_SPECIAL_SOUND_FIRST,
1320 AU_SPECIAL_SOUND_BEEP2,
1321 AU_SPECIAL_SOUND_BEEP3,
1322 AU_SPECIAL_SOUND_WARN1,
1323 AU_SPECIAL_SOUND_WARN2,
1324 AU_SPECIAL_SOUND_CHEEP,
1325 AU_SPECIAL_SOUND_RATATA,
1326 AU_SPECIAL_SOUND_TICK,
1327 AU_SPECIAL_SOUND_SIREN,
1328 AU_SPECIAL_SOUND_RING,
1329 AU_SPECIAL_SOUND_SCIFI,
1330 AU_SPECIAL_SOUND_ROBOT,
1331 AU_SPECIAL_SOUND_CHIRP,
1332 AU_SPECIAL_SOUND_TADA,
1333 AU_SPECIAL_SOUND_CRICKET,
1334 AU_SPECIAL_SOUND_ALARMC,
1335 AU_SPECIAL_SOUND_LAST,
1337 AU_NONE=0xff
1340 #if defined(AUDIO)
1341 #if defined(CPUARM)
1342 #include "audio_arm.h"
1343 #else
1344 #include "audio_avr.h"
1345 #endif
1346 #endif
1348 #include "buzzer.h"
1350 #if defined(PCBSTD) && defined(VOICE)
1351 #include "targets/9x/voice.h"
1352 #endif
1354 #if defined(PCBGRUVIN9X) && defined(VOICE)
1355 #include "targets/gruvin9x/voice.h"
1356 #endif
1358 #if defined(PCBMEGA2560) && defined(VOICE)
1359 #include "targets/mega2560/voice.h"
1360 #endif
1362 #include "translations.h"
1363 #include "fonts.h"
1365 #if defined(HAPTIC)
1366 #include "haptic.h"
1367 #endif
1369 #if defined(SDCARD)
1370 #include "sdcard.h"
1371 #endif
1373 #if defined(RTCLOCK)
1374 #include "rtc.h"
1375 #endif
1377 #if defined(REVX)
1378 void setMFP();
1379 void clearMFP();
1380 #endif
1382 #if defined(CPUARM)
1383 extern uint8_t requiredSpeakerVolume;
1384 #endif
1386 #if defined(CPUARM)
1387 enum MainRequest {
1388 REQUEST_SCREENSHOT,
1389 REQUEST_FLIGHT_RESET,
1392 extern uint8_t mainRequestFlags;
1393 #endif
1395 void checkBattery();
1396 void opentxClose(uint8_t shutdown=true);
1397 void opentxInit();
1398 void opentxResume();
1400 #if defined(PCBHORUS) || defined(PCBX7)
1401 #define LED_ERROR_BEGIN() ledRed()
1402 #define LED_ERROR_END() ledBlue()
1403 #else
1404 #define LED_ERROR_BEGIN()
1405 #define LED_ERROR_END()
1406 #endif
1408 // Re-useable byte array to save having multiple buffers
1409 #if LCD_W <= 212
1410 #define SD_SCREEN_FILE_LENGTH 32
1411 #else
1412 #define SD_SCREEN_FILE_LENGTH 64
1413 #endif
1414 union ReusableBuffer
1416 // 275 bytes
1417 struct
1419 #if !defined(CPUARM)
1420 char listnames[NUM_BODY_LINES][LEN_MODEL_NAME];
1421 #endif
1422 #if defined(EEPROM_RLC) && LCD_W < 212
1423 uint16_t eepromfree;
1424 #endif
1425 #if defined(SDCARD)
1426 char menu_bss[POPUP_MENU_MAX_LINES][MENU_LINE_LENGTH];
1427 char mainname[45]; // because reused for SD backup / restore, max backup filename 44 chars: "/MODELS/MODEL0134353-2014-06-19-04-51-27.bin"
1428 #else
1429 char mainname[LEN_MODEL_NAME];
1430 #endif
1431 } modelsel;
1433 struct {
1434 char msg[64];
1435 } msgbuf; // used in modelsel and modelsetup (only in a warning message)
1437 // 103 bytes
1438 struct
1440 int16_t midVals[NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_MOUSE_ANALOGS];
1441 int16_t loVals[NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_MOUSE_ANALOGS];
1442 int16_t hiVals[NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_MOUSE_ANALOGS];
1443 uint8_t state;
1444 #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS)
1445 struct {
1446 uint8_t stepsCount;
1447 int16_t steps[XPOTS_MULTIPOS_COUNT];
1448 uint8_t lastCount;
1449 int16_t lastPosition;
1450 } xpotsCalib[NUM_XPOTS];
1451 #endif
1452 } calib;
1454 #if defined(SDCARD)
1455 // 274 bytes
1456 struct
1458 char lines[NUM_BODY_LINES][SD_SCREEN_FILE_LENGTH+1+1]; // the last char is used to store the flags (directory) of the line
1459 uint32_t available;
1460 uint16_t offset;
1461 uint16_t count;
1462 char originalName[SD_SCREEN_FILE_LENGTH+1];
1463 } sdmanager;
1464 #endif
1466 #if defined(STM32)
1467 struct
1469 char id[27];
1470 } version;
1471 #endif
1472 struct
1474 uint8_t stickMode;
1475 } generalSettings;
1478 extern union ReusableBuffer reusableBuffer;
1480 void checkFlashOnBeep();
1482 #if defined(CPUARM)
1483 uint8_t zlen(const char *str, uint8_t size);
1484 bool zexist(const char *str, uint8_t size);
1485 unsigned int effectiveLen(const char * str, unsigned int size);
1486 char * strcat_zchar(char *dest, const char *name, uint8_t size, const char *defaultName=NULL, uint8_t defaultNameSize=0, uint8_t defaultIdx=0);
1487 #define strcat_phasename(dest, idx) strcat_zchar(dest, g_model.flightModeData[idx].name, LEN_FLIGHT_MODE_NAME, STR_FP, PSIZE(TR_FP), idx+1)
1488 #if defined(EEPROM)
1489 #define strcat_modelname(dest, idx) strcat_zchar(dest, modelHeaders[idx].name, LEN_MODEL_NAME, STR_MODEL, PSIZE(TR_MODEL), idx+1)
1490 #define strcat_currentmodelname(dest) strcat_modelname(dest, g_eeGeneral.currModel)
1491 #else
1492 #define strcat_currentmodelname(dest) strcat_zchar(dest, g_model.header.name, LEN_MODEL_NAME)
1493 #endif
1494 #define ZLEN(s) zlen(s, sizeof(s))
1495 #define ZEXIST(s) zexist(s, sizeof(s))
1496 #endif
1498 // Stick tolerance varies between transmitters, Higher is better
1499 #if defined (PCB9XR) || defined (PCB9XR128)
1500 #define STICK_TOLERANCE 16
1501 #else
1502 #define STICK_TOLERANCE 64
1503 #endif
1505 #if defined(FRSKY_HUB) && defined(GAUGES)
1506 enum BarThresholdIdx {
1507 THLD_ALT,
1508 THLD_RPM,
1509 THLD_FUEL,
1510 THLD_T1,
1511 THLD_T2,
1512 THLD_SPEED,
1513 THLD_DIST,
1514 THLD_GPSALT,
1515 THLD_CELL,
1516 THLD_CELLS_SUM,
1517 THLD_VFAS,
1518 THLD_CURRENT,
1519 THLD_CONSUMPTION,
1520 THLD_MAX,
1523 #if defined(CPUARM)
1524 #define FILL_THRESHOLD(idx, val) barsThresholds[idx] = (val)
1525 #else
1526 #define FILL_THRESHOLD(idx, val) barsThresholds[idx] = 128 + (val)
1527 #endif
1529 extern bar_threshold_t barsThresholds[THLD_MAX];
1530 #else
1531 #define FILL_THRESHOLD(idx, val)
1532 #endif
1534 #if defined(TELEMETRY_FRSKY)
1535 ls_telemetry_value_t minTelemValue(source_t channel);
1536 ls_telemetry_value_t maxTelemValue(source_t channel);
1537 #else
1538 #define minTelemValue(channel) 255
1539 #define maxTelemValue(channel) 255
1540 #endif
1542 #if defined(CPUARM)
1543 getvalue_t convert16bitsTelemValue(source_t channel, ls_telemetry_value_t value);
1544 ls_telemetry_value_t max8bitsTelemValue(source_t channel);
1545 #endif
1547 getvalue_t convert8bitsTelemValue(source_t channel, ls_telemetry_value_t value);
1548 getvalue_t convertLswTelemValue(LogicalSwitchData * cs);
1550 #if defined(CPUARM)
1551 #define convertTelemValue(channel, value) convert16bitsTelemValue(channel, value)
1552 #define convertBarTelemValue(channel, value) convert8bitsTelemValue(channel, value)
1553 #define maxBarTelemValue(channel) max8bitsTelemValue(channel)
1554 #else
1555 #define convertTelemValue(channel, value) convert8bitsTelemValue(channel, value)
1556 #define convertBarTelemValue(channel, value) convert8bitsTelemValue(channel, value)
1557 #define maxBarTelemValue(channel) maxTelemValue(channel)
1558 #endif
1560 #if defined(TELEMETRY_FRSKY) || defined(CPUARM)
1561 lcdint_t applyChannelRatio(source_t channel, lcdint_t val);
1562 #define ANA_CHANNEL_UNIT(channel) g_model.frsky.channels[channel].type
1563 #endif
1565 inline int div_and_round(int num, int den)
1567 if (den == 0) {
1568 return 0;
1570 else if (num >= 0) {
1571 num += den / 2;
1573 else {
1574 num -= den / 2;
1576 return num / den;
1579 #if defined(TELEMETRY_FRSKY)
1580 #if !defined(CPUARM)
1581 NOINLINE uint8_t getRssiAlarmValue(uint8_t alarm);
1582 #endif
1584 extern const pm_uint8_t bchunit_ar[];
1586 #if defined(CPUARM)
1587 #define FRSKY_MULTIPLIER_MAX 5
1588 #else
1589 #define FRSKY_MULTIPLIER_MAX 3
1590 #endif
1592 enum TelemetryViews {
1593 TELEMETRY_CUSTOM_SCREEN_1,
1594 TELEMETRY_CUSTOM_SCREEN_2,
1595 #if defined(CPUARM)
1596 TELEMETRY_CUSTOM_SCREEN_3,
1597 TELEMETRY_CUSTOM_SCREEN_4,
1598 TELEMETRY_VIEW_MAX = TELEMETRY_CUSTOM_SCREEN_4
1599 #else
1600 TELEMETRY_VOLTAGES_SCREEN,
1601 TELEMETRY_AFTER_FLIGHT_SCREEN,
1602 TELEMETRY_VIEW_MAX = TELEMETRY_AFTER_FLIGHT_SCREEN
1603 #endif
1606 extern uint8_t s_frsky_view;
1608 #endif
1610 #define EARTH_RADIUSKM ((uint32_t)6371)
1611 #define EARTH_RADIUS ((uint32_t)111194) // meters * pi / 180°
1613 void getGpsPilotPosition();
1614 void getGpsDistance();
1615 void varioWakeup();
1617 #if defined(AUDIO) && defined(BUZZER)
1618 #define IS_SOUND_OFF() (g_eeGeneral.buzzerMode==e_mode_quiet && g_eeGeneral.beepMode==e_mode_quiet)
1619 #else
1620 #define IS_SOUND_OFF() (g_eeGeneral.beepMode == e_mode_quiet)
1621 #endif
1623 #if defined(CPUARM)
1624 #define IS_IMPERIAL_ENABLE() (g_eeGeneral.imperial)
1625 #elif defined(IMPERIAL_UNITS)
1626 #define IS_IMPERIAL_ENABLE() (1)
1627 #else
1628 #define IS_IMPERIAL_ENABLE() (0)
1629 #endif
1631 #if defined(CPUARM)
1632 #elif defined(TELEMETRY_FRSKY)
1633 FORCEINLINE void convertUnit(getvalue_t & val, uint8_t & unit)
1635 if (IS_IMPERIAL_ENABLE()) {
1636 if (unit == UNIT_TEMPERATURE) {
1637 val += 18;
1638 val *= 115;
1639 val >>= 6;
1641 if (unit == UNIT_DIST) {
1642 // m to ft *105/32
1643 val = val * 3 + (val >> 2) + (val >> 5);
1645 if (unit == UNIT_FEET) {
1646 unit = UNIT_DIST;
1648 if (unit == UNIT_KTS) {
1649 // kts to mph
1650 unit = UNIT_SPEED;
1651 val = (val * 23) / 20;
1654 else {
1655 if (unit == UNIT_KTS) {
1656 // kts to km/h
1657 unit = UNIT_SPEED;
1658 val = (val * 50) / 27;
1662 if (unit == UNIT_HDG) {
1663 unit = UNIT_TEMPERATURE;
1666 #else
1667 #define convertUnit(...)
1668 #endif
1670 #if !defined(CPUARM)
1671 #define IS_USR_PROTO_FRSKY_HUB() (g_model.frsky.usrProto == USR_PROTO_FRSKY)
1672 #define IS_USR_PROTO_WS_HOW_HIGH() (g_model.frsky.usrProto == USR_PROTO_WS_HOW_HIGH)
1673 #endif
1675 #if defined(TELEMETRY_FRSKY) && defined(FRSKY_HUB) && defined(GPS)
1676 #define IS_GPS_AVAILABLE() IS_USR_PROTO_FRSKY_HUB()
1677 #else
1678 #define IS_GPS_AVAILABLE() (0)
1679 #endif
1681 #if defined(PCBTARANIS)
1682 extern const pm_uchar logo_taranis[];
1683 #endif
1685 #if defined(STM32)
1686 void usbPluggedIn();
1687 #endif
1689 #include "lua/lua_api.h"
1691 #if defined(SDCARD)
1692 enum ClipboardType {
1693 CLIPBOARD_TYPE_NONE,
1694 CLIPBOARD_TYPE_CUSTOM_SWITCH,
1695 CLIPBOARD_TYPE_CUSTOM_FUNCTION,
1696 CLIPBOARD_TYPE_SD_FILE,
1699 #if defined(SIMU)
1700 #define CLIPBOARD_PATH_LEN 1024
1701 #else
1702 #define CLIPBOARD_PATH_LEN 32
1703 #endif
1705 struct Clipboard {
1706 ClipboardType type;
1707 union {
1708 LogicalSwitchData csw;
1709 CustomFunctionData cfn;
1710 struct {
1711 char directory[CLIPBOARD_PATH_LEN];
1712 char filename[CLIPBOARD_PATH_LEN];
1713 } sd;
1714 } data;
1717 extern Clipboard clipboard;
1718 #endif
1720 #if !defined(SIMU)
1721 extern uint16_t s_anaFilt[NUM_ANALOGS];
1722 #endif
1724 #if defined(JITTER_MEASURE)
1725 extern JitterMeter<uint16_t> rawJitter[NUM_ANALOGS];
1726 extern JitterMeter<uint16_t> avgJitter[NUM_ANALOGS];
1727 #if defined(PCBHORUS)
1728 #define JITTER_MEASURE_ACTIVE() (menuHandlers[menuLevel] == menuStatsAnalogs)
1729 #elif defined(PCBTARANIS)
1730 #define JITTER_MEASURE_ACTIVE() (menuHandlers[menuLevel] == menuRadioDiagAnalogs)
1731 #elif defined(CLI)
1732 #define JITTER_MEASURE_ACTIVE() (1)
1733 #else
1734 #define JITTER_MEASURE_ACTIVE() (0)
1735 #endif
1736 #endif
1738 #if defined(INTERNAL_GPS)
1739 #include "gps.h"
1740 #endif
1742 #if defined(BLUETOOTH)
1743 #include "bluetooth.h"
1744 #endif
1746 #endif // _OPENTX_H_