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
26 #define SWITCH_WARNING_LIST_X WARNING_LINE_X
27 #define SWITCH_WARNING_LIST_Y WARNING_LINE_Y+3*FH
28 #define SWITCH_WARNING_LIST_INTERVAL 35
30 #define SWITCH_WARNING_LIST_X 60
31 #define SWITCH_WARNING_LIST_Y 4*FH+3
33 #define SWITCH_WARNING_LIST_X 4
34 #define SWITCH_WARNING_LIST_Y 4*FH+4
39 enum LogicalSwitchContextState
{
51 }) LogicalSwitchContext
;
54 LogicalSwitchContext lsw
[MAX_LOGICAL_SWITCHES
];
55 }) LogicalSwitchesFlightModeContext
;
56 LogicalSwitchesFlightModeContext lswFm
[MAX_FLIGHT_MODES
];
58 #define LS_LAST_VALUE(fm, idx) lswFm[fm].lsw[idx].lastValue
62 int16_t lsLastValue
[MAX_LOGICAL_SWITCHES
];
63 #define LS_LAST_VALUE(fm, idx) lsLastValue[idx]
65 volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_used
= 0;
66 volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_value
= 0;
70 #if defined(PCBTARANIS) || defined(PCBHORUS)
72 tmr10ms_t switchesMidposStart
[16];
74 tmr10ms_t switchesMidposStart
[6]; // TODO constant
76 uint64_t switchesPos
= 0;
77 tmr10ms_t potsLastposStart
[NUM_XPOTS
];
78 uint8_t potsPos
[NUM_XPOTS
];
80 #define SWITCH_POSITION(sw) (switchesPos & ((MASK_CFN_TYPE)1<<(sw)))
81 #define POT_POSITION(sw) ((potsPos[(sw)/XPOTS_MULTIPOS_COUNT] & 0x0f) == ((sw) % XPOTS_MULTIPOS_COUNT))
83 div_t switchInfo(int switchPosition
)
85 return div(switchPosition
-SWSRC_FIRST_SWITCH
, 3);
88 uint64_t check2PosSwitchPosition(uint8_t sw
)
90 uint32_t index
= (switchState(sw
) ? sw
: sw
+ 2);
91 uint64_t result
= ((uint64_t)1 << index
);
93 if (!(switchesPos
& result
)) {
94 PLAY_SWITCH_MOVED(index
);
100 uint64_t check3PosSwitchPosition(uint8_t idx
, uint8_t sw
, bool startup
)
105 if (switchState(sw
)) {
107 result
= ((MASK_CFN_TYPE
)1 << index
);
108 switchesMidposStart
[idx
] = 0;
110 else if (switchState(sw
+2)) {
112 result
= ((MASK_CFN_TYPE
)1 << index
);
113 switchesMidposStart
[idx
] = 0;
117 if (startup
|| SWITCH_POSITION(index
) || g_eeGeneral
.switchesDelay
==SWITCHES_DELAY_NONE
|| (switchesMidposStart
[idx
] && (tmr10ms_t
)(get_tmr10ms() - switchesMidposStart
[idx
]) > SWITCHES_DELAY())) {
118 result
= ((MASK_CFN_TYPE
)1 << index
);
119 switchesMidposStart
[idx
] = 0;
122 result
= (switchesPos
& ((MASK_CFN_TYPE
)0x7 << sw
));
123 if (!switchesMidposStart
[idx
]) {
124 switchesMidposStart
[idx
] = get_tmr10ms();
129 if (!(switchesPos
& result
)) {
130 PLAY_SWITCH_MOVED(index
);
136 #define CHECK_2POS(sw) newPos |= check2PosSwitchPosition(sw ## 0)
137 #define CHECK_3POS(idx, sw) newPos |= check3PosSwitchPosition(idx, sw ## 0, startup)
139 void getSwitchesPosition(bool startup
)
142 CHECK_3POS(0, SW_SA
);
143 CHECK_3POS(1, SW_SB
);
144 CHECK_3POS(2, SW_SC
);
145 CHECK_3POS(3, SW_SD
);
146 #if !defined(PCBX7) && !defined(PCBXLITE)
147 CHECK_3POS(4, SW_SE
);
149 #if !defined(PCBXLITE)
152 #if !defined(PCBX7) && !defined(PCBXLITE)
153 CHECK_3POS(5, SW_SG
);
155 #if !defined(PCBXLITE)
159 CHECK_3POS(6, SW_SI
);
160 CHECK_3POS(7, SW_SJ
);
161 CHECK_3POS(8, SW_SK
);
162 CHECK_3POS(9, SW_SL
);
163 CHECK_3POS(10, SW_SM
);
164 CHECK_3POS(11, SW_SN
);
165 CHECK_3POS(12, SW_SO
);
166 CHECK_3POS(13, SW_SP
);
167 CHECK_3POS(14, SW_SQ
);
168 CHECK_3POS(15, SW_SR
);
171 switchesPos
= newPos
;
173 for (int i
=0; i
<NUM_XPOTS
; i
++) {
174 if (IS_POT_MULTIPOS(POT1
+i
)) {
175 StepsCalibData
* calib
= (StepsCalibData
*) &g_eeGeneral
.calib
[POT1
+i
];
176 if (IS_MULTIPOS_CALIBRATED(calib
)) {
177 uint8_t pos
= anaIn(POT1
+i
) / (2*RESX
/calib
->count
);
178 uint8_t previousPos
= potsPos
[i
] >> 4;
179 uint8_t previousStoredPos
= potsPos
[i
] & 0x0F;
181 potsPos
[i
] = (pos
<< 4) | pos
;
183 else if (pos
!= previousPos
) {
184 potsLastposStart
[i
] = get_tmr10ms();
185 potsPos
[i
] = (pos
<< 4) | previousStoredPos
;
187 else if (g_eeGeneral
.switchesDelay
==SWITCHES_DELAY_NONE
|| (tmr10ms_t
)(get_tmr10ms() - potsLastposStart
[i
]) > SWITCHES_DELAY()) {
188 potsLastposStart
[i
] = 0;
189 potsPos
[i
] = (pos
<< 4) | pos
;
190 if (previousStoredPos
!= pos
) {
191 PLAY_SWITCH_MOVED(SWSRC_LAST_SWITCH
+i
*XPOTS_MULTIPOS_COUNT
+pos
);
200 getvalue_t
getValueForLogicalSwitch(mixsrc_t i
)
202 getvalue_t result
= getValue(i
);
203 if (i
>=MIXSRC_FIRST_INPUT
&& i
<=MIXSRC_LAST_INPUT
) {
204 int8_t trimIdx
= virtualInputsTrims
[i
-MIXSRC_FIRST_INPUT
];
206 int16_t trim
= trims
[trimIdx
];
207 if (trimIdx
== THR_STICK
&& g_model
.throttleReversed
)
216 #define getValueForLogicalSwitch(i) getValue(i)
219 PACK(typedef struct {
224 PACK(typedef struct {
226 uint16_t duration
:15;
229 bool getLogicalSwitch(uint8_t idx
)
231 LogicalSwitchData
* ls
= lswAddress(idx
);
235 swsrc_t s
= ls
->andsw
;
237 uint8_t s
= ls
->andsw
;
238 if (s
> SWSRC_LAST_SWITCH
) {
239 s
+= SWSRC_SW1
-SWSRC_LAST_SWITCH
-1;
243 if (ls
->func
== LS_FUNC_NONE
|| (s
&& !getSwitch(s
))) {
245 if (ls
->func
!= LS_FUNC_STICKY
&& ls
->func
!= LS_FUNC_EDGE
) {
247 if (ls
->func
!= LS_FUNC_STICKY
) {
249 // AND switch must not affect STICKY and EDGE processing
250 LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) = CS_LAST_VALUE_INIT
;
254 else if ((s
=lswFamily(ls
->func
)) == LS_FAMILY_BOOL
) {
255 bool res1
= getSwitch(ls
->v1
);
256 bool res2
= getSwitch(ls
->v2
);
259 result
= (res1
&& res2
);
262 result
= (res1
|| res2
);
266 result
= (res1
^ res2
);
270 else if (s
== LS_FAMILY_TIMER
) {
271 result
= (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) <= 0);
273 else if (s
== LS_FAMILY_STICKY
) {
274 result
= (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) & (1<<0));
277 else if (s
== LS_FAMILY_EDGE
) {
278 result
= (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) & (1<<0));
282 getvalue_t x
= getValueForLogicalSwitch(ls
->v1
);
284 if (s
== LS_FAMILY_COMP
) {
285 y
= getValueForLogicalSwitch(ls
->v2
);
291 case LS_FUNC_GREATER
:
300 mixsrc_t v1
= ls
->v1
;
301 #if defined(TELEMETRY_FRSKY)
303 if (v1
>= MIXSRC_FIRST_TELEM
) {
305 if (!TELEMETRY_STREAMING() || IS_FAI_FORBIDDEN(v1
-1)) {
307 if ((!TELEMETRY_STREAMING() && v1
>= MIXSRC_FIRST_TELEM
+TELEM_FIRST_STREAMED_VALUE
-1) || IS_FAI_FORBIDDEN(v1
-1)) {
310 goto DurationAndDelayProcessing
;
313 y
= convertLswTelemValue(ls
);
315 #if defined(GAUGES) && !defined(CPUARM)
316 // Fill the telemetry bars threshold array
317 if (s
== LS_FAMILY_OFS
) {
318 uint8_t idx
= v1
-MIXSRC_FIRST_TELEM
+1-TELEM_ALT
;
319 if (idx
< THLD_MAX
) {
320 FILL_THRESHOLD(idx
, ls
->v2
);
326 else if (v1
>= MIXSRC_GVAR1
) {
330 y
= calc100toRESX(ls
->v2
);
333 if (v1
>= MIXSRC_FIRST_TELEM
) {
334 y
= (int16_t)3 * (128+ls
->v2
); // it's a Timer
336 else if (v1
>= MIXSRC_GVAR1
) {
337 y
= ls
->v2
; // it's a GVAR
340 y
= calc100toRESX(ls
->v2
);
350 case LS_FUNC_VALMOSTEQUAL
:
352 if (v1
>= MIXSRC_GVAR1
&& v1
<= MIXSRC_LAST_GVAR
)
356 result
= (abs(x
-y
) < (1024 / STICK_TOLERANCE
));
372 if (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) == CS_LAST_VALUE_INIT
) {
373 LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) = x
;
375 int16_t diff
= x
- LS_LAST_VALUE(mixerCurrentFlightMode
, idx
);
377 if (ls
->func
== LS_FUNC_DIFFEGREATER
) {
379 result
= (diff
>= y
);
384 result
= (diff
<= y
);
390 result
= (abs(diff
) >= y
);
392 if (result
|| update
) {
393 LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) = x
;
401 #if defined(TELEMETRY_FRSKY)
402 DurationAndDelayProcessing
:
406 if (ls
->delay
|| ls
->duration
) {
407 LogicalSwitchContext
&context
= lswFm
[mixerCurrentFlightMode
].lsw
[idx
];
409 if (context
.timerState
== SWITCH_START
) {
411 context
.timerState
= SWITCH_DELAY
;
412 context
.timer
= (ls
->func
== LS_FUNC_EDGE
? 0 : ls
->delay
);
415 if (context
.timerState
== SWITCH_DELAY
) {
417 result
= false; // return false while delay timer running
420 // set duration timer
421 context
.timerState
= SWITCH_ENABLE
;
422 context
.timer
= ls
->duration
;
426 if (context
.timerState
== SWITCH_ENABLE
) {
427 result
= (ls
->duration
==0 || context
.timer
>0); // return false after duration timer runs out
428 if (!result
&& ls
->func
== LS_FUNC_STICKY
) {
429 ls_sticky_struct
& lastValue
= (ls_sticky_struct
&)context
.lastValue
;
434 else if (context
.timerState
== SWITCH_ENABLE
&& ls
->duration
> 0 && context
.timer
> 0) {
438 context
.timerState
= SWITCH_START
;
448 bool getSwitch(swsrc_t swtch
, uint8_t flags
)
450 bool getSwitch(swsrc_t swtch
)
455 if (swtch
== SWSRC_NONE
)
458 uint8_t cs_idx
= abs(swtch
);
460 if (cs_idx
== SWSRC_ONE
) {
461 result
= !s_mixer_first_run_done
;
463 else if (cs_idx
== SWSRC_ON
) {
466 else if (cs_idx
<= SWSRC_LAST_SWITCH
) {
467 #if defined(PCBTARANIS) || defined(PCBHORUS)
468 if (flags
& GETSWITCH_MIDPOS_DELAY
)
469 result
= SWITCH_POSITION(cs_idx
-SWSRC_FIRST_SWITCH
);
471 result
= switchState(cs_idx
-SWSRC_FIRST_SWITCH
);
473 result
= switchState(cs_idx
-SWSRC_FIRST_SWITCH
);
476 #if defined(MODULE_ALWAYS_SEND_PULSES)
477 if (startupWarningState
< STARTUP_WARNING_DONE
) {
478 // if throttle or switch warning is currently active, ignore actual stick position and use wanted values
480 if (!(g_model
.switchWarningEnable
& 1)) { // ID1 to ID3 is just one bit in switchWarningEnable
481 result
= (cs_idx
)==((g_model
.switchWarningState
& 3)+1); // overwrite result with desired value
484 else if (!(g_model
.switchWarningEnable
& (1<<(cs_idx
-3)))) {
485 // current switch should not be ignored for warning
486 result
= g_model
.switchWarningState
& (1<<(cs_idx
-2)); // overwrite result with desired value
492 else if (cs_idx
<= SWSRC_LAST_MULTIPOS_SWITCH
) {
493 result
= POT_POSITION(cs_idx
-SWSRC_FIRST_MULTIPOS_SWITCH
);
496 else if (cs_idx
<= SWSRC_LAST_TRIM
) {
497 uint8_t idx
= cs_idx
- SWSRC_FIRST_TRIM
;
498 idx
= (CONVERT_MODE_TRIMS(idx
/2) << 1) + (idx
& 1);
499 result
= trimDown(idx
);
501 #if ROTARY_ENCODERS > 0
502 else if (cs_idx
== SWSRC_REa
) {
506 #if ROTARY_ENCODERS > 1
507 else if (cs_idx
== SWSRC_REb
) {
512 else if (cs_idx
>= SWSRC_FIRST_SENSOR
) {
513 result
= !telemetryItems
[cs_idx
-SWSRC_FIRST_SENSOR
].isOld();
515 else if (cs_idx
== SWSRC_TELEMETRY_STREAMING
) {
516 result
= TELEMETRY_STREAMING();
518 else if (cs_idx
>= SWSRC_FIRST_FLIGHT_MODE
) {
519 #if defined(FLIGHT_MODES)
520 uint8_t idx
= cs_idx
- SWSRC_FIRST_FLIGHT_MODE
;
521 if (flags
& GETSWITCH_MIDPOS_DELAY
)
522 result
= (idx
== flightModeTransitionLast
);
524 result
= (idx
== mixerCurrentFlightMode
);
531 cs_idx
-= SWSRC_FIRST_LOGICAL_SWITCH
;
533 result
= lswFm
[mixerCurrentFlightMode
].lsw
[cs_idx
].state
;
535 GETSWITCH_RECURSIVE_TYPE mask
= ((GETSWITCH_RECURSIVE_TYPE
)1 << cs_idx
);
536 if (s_last_switch_used
& mask
) {
537 result
= (s_last_switch_value
& mask
);
540 s_last_switch_used
|= mask
;
541 result
= getLogicalSwitch(cs_idx
);
543 s_last_switch_value
|= mask
;
546 s_last_switch_value
&= ~mask
;
552 return swtch
> 0 ? result
: !result
;
557 @brief Calculates new state of logical switches for mixerCurrentFlightMode
559 void evalLogicalSwitches(bool isCurrentPhase
)
561 for (unsigned int idx
=0; idx
<MAX_LOGICAL_SWITCHES
; idx
++) {
562 LogicalSwitchContext
& context
= lswFm
[mixerCurrentFlightMode
].lsw
[idx
];
563 bool result
= getLogicalSwitch(idx
);
564 if (isCurrentPhase
) {
566 if (!context
.state
) PLAY_LOGICAL_SWITCH_ON(idx
);
569 if (context
.state
) PLAY_LOGICAL_SWITCH_OFF(idx
);
572 context
.state
= result
;
577 swarnstate_t switches_states
= 0;
578 swsrc_t
getMovedSwitch()
580 static tmr10ms_t s_move_last_time
= 0;
583 #if defined(PCBTARANIS) || defined(PCBHORUS)
584 for (int i
=0; i
<NUM_SWITCHES
; i
++) {
585 if (SWITCH_EXISTS(i
)) {
586 swarnstate_t mask
= ((swarnstate_t
)0x03 << (i
*2));
587 uint8_t prev
= (switches_states
& mask
) >> (i
*2);
588 uint8_t next
= (1024+getValue(MIXSRC_SA
+i
)) / 1024;
590 switches_states
= (switches_states
& (~mask
)) | ((swarnstate_t
)next
<< (i
*2));
591 result
= 1+(3*i
)+next
;
596 // return delivers 1 to 3 for ID1 to ID3
597 // 4..8 for all other switches if changed to true
598 // -4..-8 for all other switches if changed to false
599 // 9 for Trainer switch if changed to true; Change to false is ignored
600 swarnstate_t mask
= 0x80;
601 for (uint8_t i
=NUM_PSWITCH
; i
>1; i
--) {
603 prev
= (switches_states
& mask
);
604 // don't use getSwitch here to always get the proper value, even getSwitch manipulates
605 bool next
= switchState(i
-1);
607 if (((i
<NUM_PSWITCH
) && (i
>3)) || next
==true)
608 result
= next
? i
: -i
;
609 if (i
<=3 && result
==0) result
= 1;
610 switches_states
^= mask
;
616 if ((tmr10ms_t
)(get_tmr10ms() - s_move_last_time
) > 10)
619 s_move_last_time
= get_tmr10ms();
626 #if defined(MODULE_ALWAYS_SEND_PULSES)
627 static swarnstate_t last_bad_switches
= 0xff;
629 swarnstate_t last_bad_switches
= 0xff;
631 swarnstate_t states
= g_model
.switchWarningState
;
633 #if defined(PCBTARANIS) || defined(PCBHORUS)
634 uint8_t bad_pots
= 0, last_bad_pots
= 0xff;
637 #if !defined(MODULE_ALWAYS_SEND_PULSES)
640 #if defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED)
641 #define GETADC_COUNT (MUX_MAX+1)
642 #elif defined(PCBTARANIS) || defined(PCBHORUS)
643 #define GETADC_COUNT 1
646 for (uint8_t i
=0; i
<GETADC_COUNT
; i
++) {
647 GET_ADC_IF_MIXER_NOT_RUNNING();
651 #endif // !defined(MODULE_ALWAYS_SEND_PULSES)
656 #if defined(COLORLCD)
657 for (int i
=0; i
<NUM_SWITCHES
; i
++) {
658 if (SWITCH_WARNING_ALLOWED(i
)) {
659 unsigned int state
= ((states
>> (3*i
)) & 0x07);
660 if (state
&& state
-1 != ((switches_states
>> (i
*2)) & 0x03)) {
665 if (g_model
.potsWarnMode
) {
666 evalFlightModeMixes(e_perout_mode_normal
, 0);
668 for (int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; i
++) {
669 if (!IS_POT_SLIDER_AVAILABLE(POT1
+i
)) {
672 if (!(g_model
.potsWarnEnabled
& (1 << i
)) && (abs(g_model
.potsWarnPosition
[i
] - GET_LOWRES_POT_POSITION(i
)) > 1)) {
678 #elif defined(PCBTARANIS)
679 for (int i
=0; i
<NUM_SWITCHES
; i
++) {
680 if (SWITCH_WARNING_ALLOWED(i
) && !(g_model
.switchWarningEnable
& (1<<i
))) {
681 swarnstate_t mask
= ((swarnstate_t
)0x03 << (i
*2));
682 if (!((states
& mask
) == (switches_states
& mask
))) {
687 if (g_model
.potsWarnMode
) {
688 evalFlightModeMixes(e_perout_mode_normal
, 0);
690 for (int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; i
++) {
691 if (!IS_POT_SLIDER_AVAILABLE(POT1
+i
)) {
694 if (!(g_model
.potsWarnEnabled
& (1 << i
)) && (abs(g_model
.potsWarnPosition
[i
] - GET_LOWRES_POT_POSITION(i
)) > 1)) {
701 for (int i
=0; i
<NUM_SWITCHES
-1; i
++) {
702 if (!(g_model
.switchWarningEnable
& (1<<i
))) {
704 if ((states
& 0x03) != (switches_states
& 0x03)) {
708 else if ((states
& (1<<(i
+1))) != (switches_states
& (1<<(i
+1)))) {
716 #if defined(MODULE_ALWAYS_SEND_PULSES)
717 startupWarningState
= STARTUP_WARNING_SWITCHES
+1;
718 last_bad_switches
= 0xff;
726 // first - display warning
727 #if defined(PCBTARANIS) || defined(PCBHORUS)
728 if ((last_bad_switches
!= switches_states
) || (last_bad_pots
!= bad_pots
)) {
729 drawAlertBox(STR_SWITCHWARN
, NULL
, STR_PRESSANYKEYTOSKIP
);
730 if (last_bad_switches
== 0xff || last_bad_pots
== 0xff) {
731 AUDIO_ERROR_MESSAGE(AU_SWITCH_ALERT
);
733 int x
= SWITCH_WARNING_LIST_X
, y
= SWITCH_WARNING_LIST_Y
;
735 for (int i
=0; i
<NUM_SWITCHES
; ++i
) {
736 #if defined(COLORLCD)
737 if (SWITCH_WARNING_ALLOWED(i
)) {
738 unsigned int state
= ((g_model
.switchWarningState
>> (3*i
)) & 0x07);
739 if (state
&& state
-1 != ((switches_states
>> (i
*2)) & 0x03)) {
740 if (++numWarnings
< 6) {
741 // LcdFlags attr = ((states & mask) == (switches_states & mask)) ? TEXT_COLOR : ALARM_COLOR;
742 LcdFlags attr
= ALARM_COLOR
;
743 drawSwitch(x
, y
, SWSRC_FIRST_SWITCH
+i
*3+state
-1, attr
);
744 x
+= SWITCH_WARNING_LIST_INTERVAL
;
746 else if (numWarnings
== 6) {
747 lcdDrawText(x
, y
, "...", ALARM_COLOR
);
752 if (SWITCH_WARNING_ALLOWED(i
) && !(g_model
.switchWarningEnable
& (1<<i
))) {
753 swarnstate_t mask
= ((swarnstate_t
)0x03 << (i
*2));
754 LcdFlags attr
= ((states
& mask
) == (switches_states
& mask
)) ? 0 : INVERS
;
756 if (++numWarnings
< 7) {
757 char c
= "\300-\301"[(states
& mask
) >> (i
*2)];
758 drawSource(x
, y
, MIXSRC_FIRST_SWITCH
+i
, attr
);
759 lcdDrawChar(lcdNextPos
, y
, c
, attr
);
762 else if (numWarnings
== 7) {
763 lcdDrawText(x
, y
, "...", 0);
770 if (g_model
.potsWarnMode
) {
775 for (int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; i
++) {
776 if (!IS_POT_SLIDER_AVAILABLE(POT1
+i
)) {
779 if (!(g_model
.potsWarnEnabled
& (1 << i
))) {
780 if (abs(g_model
.potsWarnPosition
[i
] - GET_LOWRES_POT_POSITION(i
)) > 1) {
781 #if defined(COLORLCD)
783 // TODO add an helper
784 strncpy(s
, &STR_VSRCRAW
[1+(NUM_STICKS
+1+i
)*STR_VSRCRAW
[0]], STR_VSRCRAW
[0]);
785 s
[int(STR_VSRCRAW
[0])] = '\0';
787 lcdDrawTextAtIndex(x
, y
, STR_VSRCRAW
, NUM_STICKS
+1+i
, INVERS
);
789 lcdDrawChar(lcdNextPos
, y
, g_model
.potsWarnPosition
[i
] > GET_LOWRES_POT_POSITION(i
) ? 126 : 127, INVERS
);
791 lcdDrawChar(lcdNextPos
, y
, g_model
.potsWarnPosition
[i
] > GET_LOWRES_POT_POSITION(i
) ? '\300' : '\301', INVERS
);
793 #if defined(COLORLCD)
794 if (++numWarnings
< 6) {
795 lcdDrawText(x
, y
, s
, ALARM_COLOR
);
797 else if (numWarnings
== 6) {
798 lcdDrawText(x
, y
, "...", ALARM_COLOR
);
809 last_bad_pots
= bad_pots
;
811 if (last_bad_switches
!= switches_states
) {
812 RAISE_ALERT(STR_SWITCHWARN
, NULL
, STR_PRESSANYKEYTOSKIP
, last_bad_switches
== 0xff ? AU_SWITCH_ALERT
: AU_NONE
);
814 for (uint8_t i
=0; i
<NUM_SWITCHES
-1; i
++) {
817 attr
= ((states
& 0x03) != (switches_states
& 0x03)) ? INVERS
: 0;
819 attr
= (states
& (1 << (i
+1))) == (switches_states
& (1 << (i
+1))) ? 0 : INVERS
;
820 if (!(g_model
.switchWarningEnable
& (1<<i
)))
821 drawSwitch(x
, 5*FH
, (i
>0?(i
+3):(states
&0x3)+1), attr
);
830 last_bad_switches
= switches_states
;
833 #if defined(MODULE_ALWAYS_SEND_PULSES)
834 if (pwrCheck()==e_power_off
|| keyDown()) {
835 startupWarningState
= STARTUP_WARNING_SWITCHES
+1;
836 last_bad_switches
= 0xff;
839 if (pwrCheck() == e_power_off
|| keyDown()) break;
841 doLoopCommonActions();
856 void logicalSwitchesTimerTick()
859 for (uint8_t fm
=0; fm
<MAX_FLIGHT_MODES
; fm
++) {
861 for (uint8_t i
=0; i
<MAX_LOGICAL_SWITCHES
; i
++) {
862 LogicalSwitchData
* ls
= lswAddress(i
);
863 if (ls
->func
== LS_FUNC_TIMER
) {
864 int16_t *lastValue
= &LS_LAST_VALUE(fm
, i
);
865 if (*lastValue
== 0 || *lastValue
== CS_LAST_VALUE_INIT
) {
866 *lastValue
= -lswTimerValue(ls
->v1
);
868 else if (*lastValue
< 0) {
869 if (++(*lastValue
) == 0)
870 *lastValue
= lswTimerValue(ls
->v2
);
872 else { // if (*lastValue > 0)
876 else if (ls
->func
== LS_FUNC_STICKY
) {
877 ls_sticky_struct
& lastValue
= (ls_sticky_struct
&)LS_LAST_VALUE(fm
, i
);
878 bool before
= lastValue
.last
& 0x01;
879 if (lastValue
.state
) {
880 bool now
= getSwitch(ls
->v2
);
889 bool now
= getSwitch(ls
->v1
);
899 else if (ls
->func
== LS_FUNC_EDGE
) {
900 ls_stay_struct
& lastValue
= (ls_stay_struct
&)LS_LAST_VALUE(fm
, i
);
901 // if this ls was reset by the logicalSwitchesReset() the lastValue will be set to CS_LAST_VALUE_INIT(0x8000)
902 // when it is unpacked into ls_stay_struct the lastValue.duration will have a value of 0x4000
903 // this will produce an instant true for edge logical switch if the second parameter is big enough.
904 // So we reset it here.
905 if (LS_LAST_VALUE(fm
, i
) == CS_LAST_VALUE_INIT
) {
906 lastValue
.duration
= 0;
908 lastValue
.state
= false;
909 bool state
= getSwitch(ls
->v1
);
911 if (ls
->v3
== -1 && lastValue
.duration
== lswTimerValue(ls
->v2
))
912 lastValue
.state
= true;
913 if (lastValue
.duration
< 1000)
914 lastValue
.duration
++;
917 if (lastValue
.duration
> lswTimerValue(ls
->v2
) && (ls
->v3
== 0 || lastValue
.duration
<= lswTimerValue(ls
->v2
+ls
->v3
)))
918 lastValue
.state
= true;
919 lastValue
.duration
= 0;
923 // decrement delay/duration timer
924 LogicalSwitchContext
&context
= lswFm
[fm
].lsw
[i
];
935 LogicalSwitchData
* lswAddress(uint8_t idx
)
937 return &g_model
.logicalSw
[idx
];
940 uint8_t lswFamily(uint8_t func
)
942 if (func
<= LS_FUNC_ANEG
)
943 return LS_FAMILY_OFS
;
944 else if (func
<= LS_FUNC_XOR
)
945 return LS_FAMILY_BOOL
;
947 else if (func
== LS_FUNC_EDGE
)
948 return LS_FAMILY_EDGE
;
950 else if (func
<= LS_FUNC_LESS
)
951 return LS_FAMILY_COMP
;
952 else if (func
<= LS_FUNC_ADIFFEGREATER
)
953 return LS_FAMILY_DIFF
;
955 return LS_FAMILY_TIMER
+func
-LS_FUNC_TIMER
;
958 int16_t lswTimerValue(delayval_t val
)
960 return (val
< -109 ? 129+val
: (val
< 7 ? (113+val
)*5 : (53+val
)*10));
963 void logicalSwitchesReset()
966 memset(lswFm
, 0, sizeof(lswFm
));
968 s_last_switch_value
= 0;
972 for (uint8_t fm
=0; fm
<MAX_FLIGHT_MODES
; fm
++) {
974 for (uint8_t i
=0; i
<MAX_LOGICAL_SWITCHES
; i
++) {
975 LS_LAST_VALUE(fm
, i
) = CS_LAST_VALUE_INIT
;
982 getvalue_t
convertLswTelemValue(LogicalSwitchData
* ls
)
986 val
= convert16bitsTelemValue(ls
->v1
- MIXSRC_FIRST_TELEM
+ 1, ls
->v2
);
988 if (lswFamily(ls
->func
)==LS_FAMILY_OFS
)
989 val
= convert8bitsTelemValue(ls
->v1
- MIXSRC_FIRST_TELEM
+ 1, 128+ls
->v2
);
991 val
= convert8bitsTelemValue(ls
->v1
- MIXSRC_FIRST_TELEM
+ 1, 128+ls
->v2
) - convert8bitsTelemValue(ls
->v1
- MIXSRC_FIRST_TELEM
+ 1, 128);
997 void logicalSwitchesCopyState(uint8_t src
, uint8_t dst
)
999 lswFm
[dst
] = lswFm
[src
];