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.
23 #define CS_LAST_VALUE_INIT -32768
25 #if defined(PCBFLAMENCO)
26 #define SWITCH_WARNING_LIST_X 60
27 #define SWITCH_WARNING_LIST_Y 4*FH+3
28 #define SWITCH_WARNING_LIST_INTERVAL 20
29 #elif defined(PCBHORUS)
30 #define SWITCH_WARNING_LIST_X WARNING_LINE_X
31 #define SWITCH_WARNING_LIST_Y WARNING_LINE_Y+3*FH
32 #define SWITCH_WARNING_LIST_INTERVAL 35
34 #define SWITCH_WARNING_LIST_X 60
35 #define SWITCH_WARNING_LIST_Y 4*FH+3
37 #define SWITCH_WARNING_LIST_X 4
38 #define SWITCH_WARNING_LIST_Y 4*FH+4
43 enum LogicalSwitchContextState
{
55 }) LogicalSwitchContext
;
58 LogicalSwitchContext lsw
[MAX_LOGICAL_SWITCHES
];
59 }) LogicalSwitchesFlightModeContext
;
60 LogicalSwitchesFlightModeContext lswFm
[MAX_FLIGHT_MODES
];
62 #define LS_LAST_VALUE(fm, idx) lswFm[fm].lsw[idx].lastValue
66 int16_t lsLastValue
[MAX_LOGICAL_SWITCHES
];
67 #define LS_LAST_VALUE(fm, idx) lsLastValue[idx]
69 volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_used
= 0;
70 volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_value
= 0;
74 #if defined(PCBFLAMENCO)
75 tmr10ms_t potsLastposStart
[1];
77 tmr10ms_t switchesMidposStart
[2];
78 uint64_t switchesPos
= 0;
79 div_t switchInfo(int switchPosition
)
81 const div_t infos
[] = {
82 { 0, 0 }, { 0, 1 }, { 0, 2 },
84 { 2, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 }, { 2, 4 }, { 2, 5 },
86 { 5, 0 }, { 5, 1 }, { 5, 2 },
88 return infos
[switchPosition
-SWSRC_FIRST_SWITCH
];
91 uint32_t check2PosSwitchPosition(uint8_t sw
)
93 uint32_t index
= (switchState(sw
) ? sw
: sw
+ 1);
94 uint32_t result
= ((uint32_t)1 << index
);
96 if (!(switchesPos
& result
)) {
97 PLAY_SWITCH_MOVED(index
);
103 uint32_t check3PosSwitchPosition(int idx
, uint8_t sw
, bool startup
)
108 if (switchState(sw
)) {
110 result
= (1 << index
);
111 switchesMidposStart
[idx
] = 0;
113 else if (switchState(sw
+2)) {
115 result
= (1 << index
);
116 switchesMidposStart
[idx
] = 0;
118 else if (startup
|| (switchesPos
& (1 << (sw
+ 1))) || g_eeGeneral
.switchesDelay
==SWITCHES_DELAY_NONE
|| (switchesMidposStart
[idx
] && (tmr10ms_t
)(get_tmr10ms() - switchesMidposStart
[idx
]) > SWITCHES_DELAY())) {
120 result
= (1 << index
);
121 switchesMidposStart
[idx
] = 0;
125 if (!switchesMidposStart
[idx
]) {
126 switchesMidposStart
[idx
] = get_tmr10ms();
128 result
= (switchesPos
& (0x7 << sw
));
131 if (!(switchesPos
& result
)) {
132 PLAY_SWITCH_MOVED(index
);
138 #define CHECK_2POS(sw) newPos |= check2PosSwitchPosition(sw ## 0)
139 #define CHECK_3POS(idx, sw) newPos |= check3PosSwitchPosition(idx, sw ## 0, startup)
141 void getSwitchesPosition(bool startup
)
144 CHECK_3POS(0, SW_SA
);
147 CHECK_3POS(1, SW_SF
);
148 switchesPos
= newPos
;
152 #if defined(PCBTARANIS) || defined(PCBHORUS)
154 tmr10ms_t switchesMidposStart
[16];
156 tmr10ms_t switchesMidposStart
[6]; // TODO constant
158 uint64_t switchesPos
= 0;
159 tmr10ms_t potsLastposStart
[NUM_XPOTS
];
160 uint8_t potsPos
[NUM_XPOTS
];
162 #define SWITCH_POSITION(sw) (switchesPos & ((MASK_CFN_TYPE)1<<(sw)))
163 #define POT_POSITION(sw) ((potsPos[(sw)/XPOTS_MULTIPOS_COUNT] & 0x0f) == ((sw) % XPOTS_MULTIPOS_COUNT))
165 div_t switchInfo(int switchPosition
)
167 return div(switchPosition
-SWSRC_FIRST_SWITCH
, 3);
170 uint64_t check2PosSwitchPosition(uint8_t sw
)
172 uint32_t index
= (switchState(sw
) ? sw
: sw
+ 2);
173 uint64_t result
= ((uint64_t)1 << index
);
175 if (!(switchesPos
& result
)) {
176 PLAY_SWITCH_MOVED(index
);
182 uint64_t check3PosSwitchPosition(uint8_t idx
, uint8_t sw
, bool startup
)
187 if (switchState(sw
)) {
189 result
= ((MASK_CFN_TYPE
)1 << index
);
190 switchesMidposStart
[idx
] = 0;
192 else if (switchState(sw
+2)) {
194 result
= ((MASK_CFN_TYPE
)1 << index
);
195 switchesMidposStart
[idx
] = 0;
199 if (startup
|| SWITCH_POSITION(index
) || g_eeGeneral
.switchesDelay
==SWITCHES_DELAY_NONE
|| (switchesMidposStart
[idx
] && (tmr10ms_t
)(get_tmr10ms() - switchesMidposStart
[idx
]) > SWITCHES_DELAY())) {
200 result
= ((MASK_CFN_TYPE
)1 << index
);
201 switchesMidposStart
[idx
] = 0;
204 result
= (switchesPos
& ((MASK_CFN_TYPE
)0x7 << sw
));
205 if (!switchesMidposStart
[idx
]) {
206 switchesMidposStart
[idx
] = get_tmr10ms();
211 if (!(switchesPos
& result
)) {
212 PLAY_SWITCH_MOVED(index
);
218 #define CHECK_2POS(sw) newPos |= check2PosSwitchPosition(sw ## 0)
219 #define CHECK_3POS(idx, sw) newPos |= check3PosSwitchPosition(idx, sw ## 0, startup)
221 void getSwitchesPosition(bool startup
)
224 CHECK_3POS(0, SW_SA
);
225 CHECK_3POS(1, SW_SB
);
226 CHECK_3POS(2, SW_SC
);
227 CHECK_3POS(3, SW_SD
);
229 CHECK_3POS(4, SW_SE
);
233 CHECK_3POS(5, SW_SG
);
237 CHECK_3POS(6, SW_SI
);
238 CHECK_3POS(7, SW_SJ
);
239 CHECK_3POS(8, SW_SK
);
240 CHECK_3POS(9, SW_SL
);
241 CHECK_3POS(10, SW_SM
);
242 CHECK_3POS(11, SW_SN
);
243 CHECK_3POS(12, SW_SO
);
244 CHECK_3POS(13, SW_SP
);
245 CHECK_3POS(14, SW_SQ
);
246 CHECK_3POS(15, SW_SR
);
249 switchesPos
= newPos
;
251 for (int i
=0; i
<NUM_XPOTS
; i
++) {
252 if (IS_POT_MULTIPOS(POT1
+i
)) {
253 StepsCalibData
* calib
= (StepsCalibData
*) &g_eeGeneral
.calib
[POT1
+i
];
254 if (IS_MULTIPOS_CALIBRATED(calib
)) {
255 uint8_t pos
= anaIn(POT1
+i
) / (2*RESX
/calib
->count
);
256 uint8_t previousPos
= potsPos
[i
] >> 4;
257 uint8_t previousStoredPos
= potsPos
[i
] & 0x0F;
259 potsPos
[i
] = (pos
<< 4) | pos
;
261 else if (pos
!= previousPos
) {
262 potsLastposStart
[i
] = get_tmr10ms();
263 potsPos
[i
] = (pos
<< 4) | previousStoredPos
;
265 else if (g_eeGeneral
.switchesDelay
==SWITCHES_DELAY_NONE
|| (tmr10ms_t
)(get_tmr10ms() - potsLastposStart
[i
]) > SWITCHES_DELAY()) {
266 potsLastposStart
[i
] = 0;
267 potsPos
[i
] = (pos
<< 4) | pos
;
268 if (previousStoredPos
!= pos
) {
269 PLAY_SWITCH_MOVED(SWSRC_LAST_SWITCH
+i
*XPOTS_MULTIPOS_COUNT
+pos
);
278 getvalue_t
getValueForLogicalSwitch(mixsrc_t i
)
280 getvalue_t result
= getValue(i
);
281 if (i
>=MIXSRC_FIRST_INPUT
&& i
<=MIXSRC_LAST_INPUT
) {
282 int8_t trimIdx
= virtualInputsTrims
[i
-MIXSRC_FIRST_INPUT
];
284 int16_t trim
= trims
[trimIdx
];
285 if (trimIdx
== THR_STICK
&& g_model
.throttleReversed
)
294 #define getValueForLogicalSwitch(i) getValue(i)
297 PACK(typedef struct {
302 PACK(typedef struct {
304 uint16_t duration
:15;
307 bool getLogicalSwitch(uint8_t idx
)
309 LogicalSwitchData
* ls
= lswAddress(idx
);
313 swsrc_t s
= ls
->andsw
;
315 uint8_t s
= ls
->andsw
;
316 if (s
> SWSRC_LAST_SWITCH
) {
317 s
+= SWSRC_SW1
-SWSRC_LAST_SWITCH
-1;
321 if (ls
->func
== LS_FUNC_NONE
|| (s
&& !getSwitch(s
))) {
323 if (ls
->func
!= LS_FUNC_STICKY
&& ls
->func
!= LS_FUNC_EDGE
) {
325 if (ls
->func
!= LS_FUNC_STICKY
) {
327 // AND switch must not affect STICKY and EDGE processing
328 LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) = CS_LAST_VALUE_INIT
;
332 else if ((s
=lswFamily(ls
->func
)) == LS_FAMILY_BOOL
) {
333 bool res1
= getSwitch(ls
->v1
);
334 bool res2
= getSwitch(ls
->v2
);
337 result
= (res1
&& res2
);
340 result
= (res1
|| res2
);
344 result
= (res1
^ res2
);
348 else if (s
== LS_FAMILY_TIMER
) {
349 result
= (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) <= 0);
351 else if (s
== LS_FAMILY_STICKY
) {
352 result
= (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) & (1<<0));
355 else if (s
== LS_FAMILY_EDGE
) {
356 result
= (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) & (1<<0));
360 getvalue_t x
= getValueForLogicalSwitch(ls
->v1
);
362 if (s
== LS_FAMILY_COMP
) {
363 y
= getValueForLogicalSwitch(ls
->v2
);
369 case LS_FUNC_GREATER
:
378 mixsrc_t v1
= ls
->v1
;
379 #if defined(TELEMETRY_FRSKY)
381 if (v1
>= MIXSRC_FIRST_TELEM
) {
383 if (!TELEMETRY_STREAMING() || IS_FAI_FORBIDDEN(v1
-1)) {
385 if ((!TELEMETRY_STREAMING() && v1
>= MIXSRC_FIRST_TELEM
+TELEM_FIRST_STREAMED_VALUE
-1) || IS_FAI_FORBIDDEN(v1
-1)) {
388 goto DurationAndDelayProcessing
;
391 y
= convertLswTelemValue(ls
);
393 #if defined(GAUGES) && !defined(CPUARM)
394 // Fill the telemetry bars threshold array
395 if (s
== LS_FAMILY_OFS
) {
396 uint8_t idx
= v1
-MIXSRC_FIRST_TELEM
+1-TELEM_ALT
;
397 if (idx
< THLD_MAX
) {
398 FILL_THRESHOLD(idx
, ls
->v2
);
404 else if (v1
>= MIXSRC_GVAR1
) {
408 y
= calc100toRESX(ls
->v2
);
411 if (v1
>= MIXSRC_FIRST_TELEM
) {
412 y
= (int16_t)3 * (128+ls
->v2
); // it's a Timer
414 else if (v1
>= MIXSRC_GVAR1
) {
415 y
= ls
->v2
; // it's a GVAR
418 y
= calc100toRESX(ls
->v2
);
428 case LS_FUNC_VALMOSTEQUAL
:
430 if (v1
>= MIXSRC_GVAR1
&& v1
<= MIXSRC_LAST_GVAR
)
434 result
= (abs(x
-y
) < (1024 / STICK_TOLERANCE
));
450 if (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) == CS_LAST_VALUE_INIT
) {
451 LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) = x
;
453 int16_t diff
= x
- LS_LAST_VALUE(mixerCurrentFlightMode
, idx
);
455 if (ls
->func
== LS_FUNC_DIFFEGREATER
) {
457 result
= (diff
>= y
);
462 result
= (diff
<= y
);
468 result
= (abs(diff
) >= y
);
470 if (result
|| update
) {
471 LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) = x
;
479 #if defined(TELEMETRY_FRSKY)
480 DurationAndDelayProcessing
:
484 if (ls
->delay
|| ls
->duration
) {
485 LogicalSwitchContext
&context
= lswFm
[mixerCurrentFlightMode
].lsw
[idx
];
487 if (context
.timerState
== SWITCH_START
) {
489 context
.timerState
= SWITCH_DELAY
;
490 context
.timer
= (ls
->func
== LS_FUNC_EDGE
? 0 : ls
->delay
);
493 if (context
.timerState
== SWITCH_DELAY
) {
495 result
= false; // return false while delay timer running
498 // set duration timer
499 context
.timerState
= SWITCH_ENABLE
;
500 context
.timer
= ls
->duration
;
504 if (context
.timerState
== SWITCH_ENABLE
) {
505 result
= (ls
->duration
==0 || context
.timer
>0); // return false after duration timer runs out
506 if (!result
&& ls
->func
== LS_FUNC_STICKY
) {
507 ls_sticky_struct
& lastValue
= (ls_sticky_struct
&)context
.lastValue
;
512 else if (context
.timerState
== SWITCH_ENABLE
&& ls
->duration
> 0 && context
.timer
> 0) {
516 context
.timerState
= SWITCH_START
;
526 bool getSwitch(swsrc_t swtch
, uint8_t flags
)
528 bool getSwitch(swsrc_t swtch
)
533 if (swtch
== SWSRC_NONE
)
536 uint8_t cs_idx
= abs(swtch
);
538 if (cs_idx
== SWSRC_ONE
) {
539 result
= !s_mixer_first_run_done
;
541 else if (cs_idx
== SWSRC_ON
) {
544 else if (cs_idx
<= SWSRC_LAST_SWITCH
) {
545 #if defined(PCBTARANIS) || defined(PCBHORUS) // TODO || defined(PCBFLAMENCO)
546 if (flags
& GETSWITCH_MIDPOS_DELAY
)
547 result
= SWITCH_POSITION(cs_idx
-SWSRC_FIRST_SWITCH
);
549 result
= switchState(cs_idx
-SWSRC_FIRST_SWITCH
);
551 result
= switchState(cs_idx
-SWSRC_FIRST_SWITCH
);
554 #if defined(MODULE_ALWAYS_SEND_PULSES)
555 if (startupWarningState
< STARTUP_WARNING_DONE
) {
556 // if throttle or switch warning is currently active, ignore actual stick position and use wanted values
558 if (!(g_model
.switchWarningEnable
& 1)) { // ID1 to ID3 is just one bit in switchWarningEnable
559 result
= (cs_idx
)==((g_model
.switchWarningState
& 3)+1); // overwrite result with desired value
562 else if (!(g_model
.switchWarningEnable
& (1<<(cs_idx
-3)))) {
563 // current switch should not be ignored for warning
564 result
= g_model
.switchWarningState
& (1<<(cs_idx
-2)); // overwrite result with desired value
570 else if (cs_idx
<= SWSRC_LAST_MULTIPOS_SWITCH
) {
571 result
= POT_POSITION(cs_idx
-SWSRC_FIRST_MULTIPOS_SWITCH
);
574 else if (cs_idx
<= SWSRC_LAST_TRIM
) {
575 uint8_t idx
= cs_idx
- SWSRC_FIRST_TRIM
;
576 idx
= (CONVERT_MODE(idx
/2) << 1) + (idx
& 1);
577 result
= trimDown(idx
);
579 #if ROTARY_ENCODERS > 0
580 else if (cs_idx
== SWSRC_REa
) {
584 #if ROTARY_ENCODERS > 1
585 else if (cs_idx
== SWSRC_REb
) {
590 else if (cs_idx
>= SWSRC_FIRST_SENSOR
) {
591 result
= !telemetryItems
[cs_idx
-SWSRC_FIRST_SENSOR
].isOld();
593 else if (cs_idx
== SWSRC_TELEMETRY_STREAMING
) {
594 result
= TELEMETRY_STREAMING();
596 else if (cs_idx
>= SWSRC_FIRST_FLIGHT_MODE
) {
597 #if defined(FLIGHT_MODES)
598 uint8_t idx
= cs_idx
- SWSRC_FIRST_FLIGHT_MODE
;
599 if (flags
& GETSWITCH_MIDPOS_DELAY
)
600 result
= (idx
== flightModeTransitionLast
);
602 result
= (idx
== mixerCurrentFlightMode
);
609 cs_idx
-= SWSRC_FIRST_LOGICAL_SWITCH
;
611 result
= lswFm
[mixerCurrentFlightMode
].lsw
[cs_idx
].state
;
613 GETSWITCH_RECURSIVE_TYPE mask
= ((GETSWITCH_RECURSIVE_TYPE
)1 << cs_idx
);
614 if (s_last_switch_used
& mask
) {
615 result
= (s_last_switch_value
& mask
);
618 s_last_switch_used
|= mask
;
619 result
= getLogicalSwitch(cs_idx
);
621 s_last_switch_value
|= mask
;
624 s_last_switch_value
&= ~mask
;
630 return swtch
> 0 ? result
: !result
;
635 @brief Calculates new state of logical switches for mixerCurrentFlightMode
637 void evalLogicalSwitches(bool isCurrentPhase
)
639 for (unsigned int idx
=0; idx
<MAX_LOGICAL_SWITCHES
; idx
++) {
640 LogicalSwitchContext
& context
= lswFm
[mixerCurrentFlightMode
].lsw
[idx
];
641 bool result
= getLogicalSwitch(idx
);
642 if (isCurrentPhase
) {
644 if (!context
.state
) PLAY_LOGICAL_SWITCH_ON(idx
);
647 if (context
.state
) PLAY_LOGICAL_SWITCH_OFF(idx
);
650 context
.state
= result
;
655 swarnstate_t switches_states
= 0;
656 swsrc_t
getMovedSwitch()
658 static tmr10ms_t s_move_last_time
= 0;
661 #if defined(PCBFLAMENCO)
663 for (int i
=0; i
<NUM_SWITCHES
; i
++) {
664 swarnstate_t mask
= ((swarnstate_t
)0x07 << (i
*3));
665 uint8_t prev
= (switches_states
& mask
) >> (i
*3);
666 uint8_t next
= (1024+getValue(MIXSRC_SA
+i
)) / 1024;
668 switches_states
= (switches_states
& (~mask
)) | ((swarnstate_t
)next
<< (i
*3));
672 result
= 1+(3*1)+(next
!=0);
674 result
= 12+(next
!=0);
682 #elif defined(PCBTARANIS) || defined(PCBHORUS)
683 for (int i
=0; i
<NUM_SWITCHES
; i
++) {
684 if (SWITCH_EXISTS(i
)) {
685 swarnstate_t mask
= ((swarnstate_t
)0x03 << (i
*2));
686 uint8_t prev
= (switches_states
& mask
) >> (i
*2);
687 uint8_t next
= (1024+getValue(MIXSRC_SA
+i
)) / 1024;
689 switches_states
= (switches_states
& (~mask
)) | ((swarnstate_t
)next
<< (i
*2));
690 result
= 1+(3*i
)+next
;
695 // return delivers 1 to 3 for ID1 to ID3
696 // 4..8 for all other switches if changed to true
697 // -4..-8 for all other switches if changed to false
698 // 9 for Trainer switch if changed to true; Change to false is ignored
699 swarnstate_t mask
= 0x80;
700 for (uint8_t i
=NUM_PSWITCH
; i
>1; i
--) {
702 prev
= (switches_states
& mask
);
703 // don't use getSwitch here to always get the proper value, even getSwitch manipulates
704 bool next
= switchState(i
-1);
706 if (((i
<NUM_PSWITCH
) && (i
>3)) || next
==true)
707 result
= next
? i
: -i
;
708 if (i
<=3 && result
==0) result
= 1;
709 switches_states
^= mask
;
715 if ((tmr10ms_t
)(get_tmr10ms() - s_move_last_time
) > 10)
718 s_move_last_time
= get_tmr10ms();
725 #if defined(MODULE_ALWAYS_SEND_PULSES)
726 static swarnstate_t last_bad_switches
= 0xff;
728 swarnstate_t last_bad_switches
= 0xff;
730 swarnstate_t states
= g_model
.switchWarningState
;
732 #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS)
733 uint8_t bad_pots
= 0, last_bad_pots
= 0xff;
736 #if !defined(MODULE_ALWAYS_SEND_PULSES)
739 #if defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED)
740 #define GETADC_COUNT (MUX_MAX+1)
741 #elif defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS)
742 #define GETADC_COUNT 1
745 for (uint8_t i
=0; i
<GETADC_COUNT
; i
++) {
746 GET_ADC_IF_MIXER_NOT_RUNNING();
750 #endif // !defined(MODULE_ALWAYS_SEND_PULSES)
755 #if defined(COLORLCD)
756 for (int i
=0; i
<NUM_SWITCHES
; i
++) {
757 if (SWITCH_WARNING_ALLOWED(i
)) {
758 unsigned int state
= ((states
>> (3*i
)) & 0x07);
759 if (state
&& state
-1 != ((switches_states
>> (i
*2)) & 0x03)) {
764 if (g_model
.potsWarnMode
) {
765 evalFlightModeMixes(e_perout_mode_normal
, 0);
767 for (int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; i
++) {
768 if (!IS_POT_SLIDER_AVAILABLE(POT1
+i
)) {
771 if (!(g_model
.potsWarnEnabled
& (1 << i
)) && (abs(g_model
.potsWarnPosition
[i
] - GET_LOWRES_POT_POSITION(i
)) > 1)) {
777 #elif defined(PCBTARANIS)
778 for (int i
=0; i
<NUM_SWITCHES
; i
++) {
779 if (SWITCH_WARNING_ALLOWED(i
) && !(g_model
.switchWarningEnable
& (1<<i
))) {
780 swarnstate_t mask
= ((swarnstate_t
)0x03 << (i
*2));
781 if (!((states
& mask
) == (switches_states
& mask
))) {
786 if (g_model
.potsWarnMode
) {
787 evalFlightModeMixes(e_perout_mode_normal
, 0);
789 for (int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; i
++) {
790 if (!IS_POT_SLIDER_AVAILABLE(POT1
+i
)) {
793 if (!(g_model
.potsWarnEnabled
& (1 << i
)) && (abs(g_model
.potsWarnPosition
[i
] - GET_LOWRES_POT_POSITION(i
)) > 1)) {
800 for (int i
=0; i
<NUM_SWITCHES
-1; i
++) {
801 if (!(g_model
.switchWarningEnable
& (1<<i
))) {
803 if ((states
& 0x03) != (switches_states
& 0x03)) {
807 else if ((states
& (1<<(i
+1))) != (switches_states
& (1<<(i
+1)))) {
815 #if defined(MODULE_ALWAYS_SEND_PULSES)
816 startupWarningState
= STARTUP_WARNING_SWITCHES
+1;
817 last_bad_switches
= 0xff;
824 // first - display warning
825 #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS)
826 if ((last_bad_switches
!= switches_states
) || (last_bad_pots
!= bad_pots
)) {
827 drawAlertBox(STR_SWITCHWARN
, NULL
, STR_PRESSANYKEYTOSKIP
);
828 if (last_bad_switches
== 0xff || last_bad_pots
== 0xff) {
829 AUDIO_ERROR_MESSAGE(AU_SWITCH_ALERT
);
831 int x
= SWITCH_WARNING_LIST_X
, y
= SWITCH_WARNING_LIST_Y
;
833 for (int i
=0; i
<NUM_SWITCHES
; ++i
) {
834 #if defined(COLORLCD)
835 if (SWITCH_WARNING_ALLOWED(i
)) {
836 unsigned int state
= ((g_model
.switchWarningState
>> (3*i
)) & 0x07);
837 if (state
&& state
-1 != ((switches_states
>> (i
*2)) & 0x03)) {
838 if (++numWarnings
< 6) {
839 // LcdFlags attr = ((states & mask) == (switches_states & mask)) ? TEXT_COLOR : ALARM_COLOR;
840 LcdFlags attr
= ALARM_COLOR
;
841 drawSwitch(x
, y
, SWSRC_FIRST_SWITCH
+i
*3+state
-1, attr
);
842 x
+= SWITCH_WARNING_LIST_INTERVAL
;
844 else if (numWarnings
== 6) {
845 lcdDrawText(x
, y
, "...", ALARM_COLOR
);
850 if (SWITCH_WARNING_ALLOWED(i
) && !(g_model
.switchWarningEnable
& (1<<i
))) {
851 swarnstate_t mask
= ((swarnstate_t
)0x03 << (i
*2));
852 LcdFlags attr
= ((states
& mask
) == (switches_states
& mask
)) ? 0 : INVERS
;
854 if (++numWarnings
< 7) {
855 char c
= "\300-\301"[(states
& mask
) >> (i
*2)];
856 drawSource(x
, y
, MIXSRC_FIRST_SWITCH
+i
, attr
);
857 lcdDrawChar(lcdNextPos
, y
, c
, attr
);
860 else if (numWarnings
== 7) {
861 lcdDrawText(x
, y
, "...", 0);
868 if (g_model
.potsWarnMode
) {
873 for (int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; i
++) {
874 if (!IS_POT_SLIDER_AVAILABLE(POT1
+i
)) {
877 if (!(g_model
.potsWarnEnabled
& (1 << i
))) {
878 if (abs(g_model
.potsWarnPosition
[i
] - GET_LOWRES_POT_POSITION(i
)) > 1) {
879 #if defined(COLORLCD)
881 // TODO add an helper
882 strncpy(s
, &STR_VSRCRAW
[1+(NUM_STICKS
+1+i
)*STR_VSRCRAW
[0]], STR_VSRCRAW
[0]);
883 s
[int(STR_VSRCRAW
[0])] = '\0';
885 lcdDrawTextAtIndex(x
, y
, STR_VSRCRAW
, NUM_STICKS
+1+i
, INVERS
);
887 lcdDrawChar(lcdNextPos
, y
, g_model
.potsWarnPosition
[i
] > GET_LOWRES_POT_POSITION(i
) ? 126 : 127, INVERS
);
889 lcdDrawChar(lcdNextPos
, y
, g_model
.potsWarnPosition
[i
] > GET_LOWRES_POT_POSITION(i
) ? '\300' : '\301', INVERS
);
891 #if defined(COLORLCD)
892 if (++numWarnings
< 6) {
893 lcdDrawText(x
, y
, s
, ALARM_COLOR
);
895 else if (numWarnings
== 6) {
896 lcdDrawText(x
, y
, "...", ALARM_COLOR
);
907 last_bad_pots
= bad_pots
;
909 if (last_bad_switches
!= switches_states
) {
910 RAISE_ALERT(STR_SWITCHWARN
, NULL
, STR_PRESSANYKEYTOSKIP
, last_bad_switches
== 0xff ? AU_SWITCH_ALERT
: AU_NONE
);
912 for (uint8_t i
=0; i
<NUM_SWITCHES
-1; i
++) {
915 attr
= ((states
& 0x03) != (switches_states
& 0x03)) ? INVERS
: 0;
917 attr
= (states
& (1 << (i
+1))) == (switches_states
& (1 << (i
+1))) ? 0 : INVERS
;
918 if (!(g_model
.switchWarningEnable
& (1<<i
)))
919 drawSwitch(x
, 5*FH
, (i
>0?(i
+3):(states
&0x3)+1), attr
);
928 last_bad_switches
= switches_states
;
931 #if defined(MODULE_ALWAYS_SEND_PULSES)
932 if (pwrCheck()==e_power_off
|| keyDown()) {
933 startupWarningState
= STARTUP_WARNING_SWITCHES
+1;
934 last_bad_switches
= 0xff;
937 if (pwrCheck()==e_power_off
|| keyDown()) break;
939 doLoopCommonActions();
954 void logicalSwitchesTimerTick()
957 for (uint8_t fm
=0; fm
<MAX_FLIGHT_MODES
; fm
++) {
959 for (uint8_t i
=0; i
<MAX_LOGICAL_SWITCHES
; i
++) {
960 LogicalSwitchData
* ls
= lswAddress(i
);
961 if (ls
->func
== LS_FUNC_TIMER
) {
962 int16_t *lastValue
= &LS_LAST_VALUE(fm
, i
);
963 if (*lastValue
== 0 || *lastValue
== CS_LAST_VALUE_INIT
) {
964 *lastValue
= -lswTimerValue(ls
->v1
);
966 else if (*lastValue
< 0) {
967 if (++(*lastValue
) == 0)
968 *lastValue
= lswTimerValue(ls
->v2
);
970 else { // if (*lastValue > 0)
974 else if (ls
->func
== LS_FUNC_STICKY
) {
975 ls_sticky_struct
& lastValue
= (ls_sticky_struct
&)LS_LAST_VALUE(fm
, i
);
976 bool before
= lastValue
.last
& 0x01;
977 if (lastValue
.state
) {
978 bool now
= getSwitch(ls
->v2
);
987 bool now
= getSwitch(ls
->v1
);
997 else if (ls
->func
== LS_FUNC_EDGE
) {
998 ls_stay_struct
& lastValue
= (ls_stay_struct
&)LS_LAST_VALUE(fm
, i
);
999 // if this ls was reset by the logicalSwitchesReset() the lastValue will be set to CS_LAST_VALUE_INIT(0x8000)
1000 // when it is unpacked into ls_stay_struct the lastValue.duration will have a value of 0x4000
1001 // this will produce an instant true for edge logical switch if the second parameter is big enough.
1002 // So we reset it here.
1003 if (LS_LAST_VALUE(fm
, i
) == CS_LAST_VALUE_INIT
) {
1004 lastValue
.duration
= 0;
1006 lastValue
.state
= false;
1007 bool state
= getSwitch(ls
->v1
);
1009 if (ls
->v3
== -1 && lastValue
.duration
== lswTimerValue(ls
->v2
))
1010 lastValue
.state
= true;
1011 if (lastValue
.duration
< 1000)
1012 lastValue
.duration
++;
1015 if (lastValue
.duration
> lswTimerValue(ls
->v2
) && (ls
->v3
== 0 || lastValue
.duration
<= lswTimerValue(ls
->v2
+ls
->v3
)))
1016 lastValue
.state
= true;
1017 lastValue
.duration
= 0;
1021 // decrement delay/duration timer
1022 LogicalSwitchContext
&context
= lswFm
[fm
].lsw
[i
];
1023 if (context
.timer
) {
1033 LogicalSwitchData
* lswAddress(uint8_t idx
)
1035 return &g_model
.logicalSw
[idx
];
1038 uint8_t lswFamily(uint8_t func
)
1040 if (func
<= LS_FUNC_ANEG
)
1041 return LS_FAMILY_OFS
;
1042 else if (func
<= LS_FUNC_XOR
)
1043 return LS_FAMILY_BOOL
;
1045 else if (func
== LS_FUNC_EDGE
)
1046 return LS_FAMILY_EDGE
;
1048 else if (func
<= LS_FUNC_LESS
)
1049 return LS_FAMILY_COMP
;
1050 else if (func
<= LS_FUNC_ADIFFEGREATER
)
1051 return LS_FAMILY_DIFF
;
1053 return LS_FAMILY_TIMER
+func
-LS_FUNC_TIMER
;
1056 int16_t lswTimerValue(delayval_t val
)
1058 return (val
< -109 ? 129+val
: (val
< 7 ? (113+val
)*5 : (53+val
)*10));
1061 void logicalSwitchesReset()
1064 flightModeTransitionLast
= 255;
1065 memset(lswFm
, 0, sizeof(lswFm
));
1067 s_last_switch_value
= 0;
1071 for (uint8_t fm
=0; fm
<MAX_FLIGHT_MODES
; fm
++) {
1073 for (uint8_t i
=0; i
<MAX_LOGICAL_SWITCHES
; i
++) {
1074 LS_LAST_VALUE(fm
, i
) = CS_LAST_VALUE_INIT
;
1081 getvalue_t
convertLswTelemValue(LogicalSwitchData
* ls
)
1085 val
= convert16bitsTelemValue(ls
->v1
- MIXSRC_FIRST_TELEM
+ 1, ls
->v2
);
1087 if (lswFamily(ls
->func
)==LS_FAMILY_OFS
)
1088 val
= convert8bitsTelemValue(ls
->v1
- MIXSRC_FIRST_TELEM
+ 1, 128+ls
->v2
);
1090 val
= convert8bitsTelemValue(ls
->v1
- MIXSRC_FIRST_TELEM
+ 1, 128+ls
->v2
) - convert8bitsTelemValue(ls
->v1
- MIXSRC_FIRST_TELEM
+ 1, 128);
1096 void logicalSwitchesCopyState(uint8_t src
, uint8_t dst
)
1098 lswFm
[dst
] = lswFm
[src
];