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
29 #define SWITCH_WARNING_LIST_X 60
30 #define SWITCH_WARNING_LIST_Y 4*FH+4
32 #define SWITCH_WARNING_LIST_X 4
33 #define SWITCH_WARNING_LIST_Y 4*FH+4
36 enum LogicalSwitchContextState
{
42 PACK(struct LogicalSwitchContext
{
50 PACK(struct LogicalSwitchesFlightModeContext
{
51 LogicalSwitchContext lsw
[MAX_LOGICAL_SWITCHES
];
53 LogicalSwitchesFlightModeContext lswFm
[MAX_FLIGHT_MODES
];
55 #define LS_LAST_VALUE(fm, idx) lswFm[fm].lsw[idx].lastValue
57 #if defined(PCBTARANIS) || defined(PCBHORUS)
59 tmr10ms_t switchesMidposStart
[16];
61 tmr10ms_t switchesMidposStart
[6]; // TODO constant
63 uint64_t switchesPos
= 0;
64 tmr10ms_t potsLastposStart
[NUM_XPOTS
];
65 uint8_t potsPos
[NUM_XPOTS
];
67 #define SWITCH_POSITION(sw) (switchesPos & ((MASK_CFN_TYPE)1<<(sw)))
68 #define POT_POSITION(sw) ((potsPos[(sw)/XPOTS_MULTIPOS_COUNT] & 0x0f) == ((sw) % XPOTS_MULTIPOS_COUNT))
70 div_t switchInfo(int switchPosition
)
72 return div(switchPosition
-SWSRC_FIRST_SWITCH
, 3);
75 uint64_t check2PosSwitchPosition(uint8_t sw
)
77 uint32_t index
= (switchState(sw
) ? sw
: sw
+ 2);
78 uint64_t result
= ((uint64_t)1 << index
);
80 if (!(switchesPos
& result
)) {
81 PLAY_SWITCH_MOVED(index
);
87 uint64_t check3PosSwitchPosition(uint8_t idx
, uint8_t sw
, bool startup
)
92 if (switchState(sw
)) {
94 result
= ((MASK_CFN_TYPE
)1 << index
);
95 switchesMidposStart
[idx
] = 0;
97 else if (switchState(sw
+2)) {
99 result
= ((MASK_CFN_TYPE
)1 << index
);
100 switchesMidposStart
[idx
] = 0;
104 if (startup
|| SWITCH_POSITION(index
) || g_eeGeneral
.switchesDelay
==SWITCHES_DELAY_NONE
|| (switchesMidposStart
[idx
] && (tmr10ms_t
)(get_tmr10ms() - switchesMidposStart
[idx
]) > SWITCHES_DELAY())) {
105 result
= ((MASK_CFN_TYPE
)1 << index
);
106 switchesMidposStart
[idx
] = 0;
109 result
= (switchesPos
& ((MASK_CFN_TYPE
)0x7 << sw
));
110 if (!switchesMidposStart
[idx
]) {
111 switchesMidposStart
[idx
] = get_tmr10ms();
116 if (!(switchesPos
& result
)) {
117 PLAY_SWITCH_MOVED(index
);
123 #define CHECK_2POS(sw) newPos |= check2PosSwitchPosition(sw ## 0)
124 #define CHECK_3POS(idx, sw) newPos |= check3PosSwitchPosition(idx, sw ## 0, startup)
126 void getSwitchesPosition(bool startup
)
129 CHECK_3POS(0, SW_SA
);
130 CHECK_3POS(1, SW_SB
);
131 CHECK_3POS(2, SW_SC
);
133 #if defined(PCBX9LITES)
138 #elif defined(PCBX9LITE)
141 #elif defined(PCBXLITES)
142 CHECK_3POS(3, SW_SD
);
145 // no SWG and SWH on XLITES
146 #elif defined(PCBXLITE)
147 CHECK_3POS(3, SW_SD
);
148 // no SWE, SWF, SWG and SWH on XLITE
150 CHECK_3POS(3, SW_SD
);
154 CHECK_3POS(3, SW_SD
);
155 CHECK_3POS(4, SW_SE
);
157 CHECK_3POS(5, SW_SG
);
161 #if defined(PCBX9DP) && PCBREV >= 2019
165 #if defined(PCBX7ACCESS)
167 #elif defined(PCBHORUS) || defined(PCBX7)
173 CHECK_3POS(6, SW_SI
);
174 CHECK_3POS(7, SW_SJ
);
175 CHECK_3POS(8, SW_SK
);
176 CHECK_3POS(9, SW_SL
);
177 CHECK_3POS(10, SW_SM
);
178 CHECK_3POS(11, SW_SN
);
179 CHECK_3POS(12, SW_SO
);
180 CHECK_3POS(13, SW_SP
);
181 CHECK_3POS(14, SW_SQ
);
182 CHECK_3POS(15, SW_SR
);
185 switchesPos
= newPos
;
187 for (int i
=0; i
<NUM_XPOTS
; i
++) {
188 if (IS_POT_MULTIPOS(POT1
+i
)) {
189 StepsCalibData
* calib
= (StepsCalibData
*) &g_eeGeneral
.calib
[POT1
+i
];
190 if (IS_MULTIPOS_CALIBRATED(calib
)) {
191 uint8_t pos
= anaIn(POT1
+i
) / (2*RESX
/calib
->count
);
192 uint8_t previousPos
= potsPos
[i
] >> 4;
193 uint8_t previousStoredPos
= potsPos
[i
] & 0x0F;
195 potsPos
[i
] = (pos
<< 4) | pos
;
197 else if (pos
!= previousPos
) {
198 potsLastposStart
[i
] = get_tmr10ms();
199 potsPos
[i
] = (pos
<< 4) | previousStoredPos
;
201 else if (g_eeGeneral
.switchesDelay
==SWITCHES_DELAY_NONE
|| (tmr10ms_t
)(get_tmr10ms() - potsLastposStart
[i
]) > SWITCHES_DELAY()) {
202 potsLastposStart
[i
] = 0;
203 potsPos
[i
] = (pos
<< 4) | pos
;
204 if (previousStoredPos
!= pos
) {
205 PLAY_SWITCH_MOVED(SWSRC_LAST_SWITCH
+i
*XPOTS_MULTIPOS_COUNT
+pos
);
214 getvalue_t
getValueForLogicalSwitch(mixsrc_t i
)
216 getvalue_t result
= getValue(i
);
217 if (i
>=MIXSRC_FIRST_INPUT
&& i
<=MIXSRC_LAST_INPUT
) {
218 int8_t trimIdx
= virtualInputsTrims
[i
-MIXSRC_FIRST_INPUT
];
220 int16_t trim
= trims
[trimIdx
];
221 if (trimIdx
== THR_STICK
&& g_model
.throttleReversed
)
230 #define getValueForLogicalSwitch(i) getValue(i)
233 PACK(typedef struct {
238 PACK(typedef struct {
240 uint16_t duration
:15;
243 bool getLogicalSwitch(uint8_t idx
)
245 LogicalSwitchData
* ls
= lswAddress(idx
);
248 swsrc_t s
= ls
->andsw
;
250 if (ls
->func
== LS_FUNC_NONE
|| (s
&& !getSwitch(s
))) {
251 if (ls
->func
!= LS_FUNC_STICKY
&& ls
->func
!= LS_FUNC_EDGE
) {
252 // AND switch must not affect STICKY and EDGE processing
253 LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) = CS_LAST_VALUE_INIT
;
257 else if ((s
=lswFamily(ls
->func
)) == LS_FAMILY_BOOL
) {
258 bool res1
= getSwitch(ls
->v1
);
259 bool res2
= getSwitch(ls
->v2
);
262 result
= (res1
&& res2
);
265 result
= (res1
|| res2
);
269 result
= (res1
^ res2
);
273 else if (s
== LS_FAMILY_TIMER
) {
274 result
= (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) <= 0);
276 else if (s
== LS_FAMILY_STICKY
) {
277 result
= (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) & (1<<0));
279 else if (s
== LS_FAMILY_EDGE
) {
280 result
= (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) & (1<<0));
283 getvalue_t x
= getValueForLogicalSwitch(ls
->v1
);
285 if (s
== LS_FAMILY_COMP
) {
286 y
= getValueForLogicalSwitch(ls
->v2
);
292 case LS_FUNC_GREATER
:
301 mixsrc_t v1
= ls
->v1
;
303 if (v1
>= MIXSRC_FIRST_TELEM
) {
304 if (!TELEMETRY_STREAMING() || IS_FAI_FORBIDDEN(v1
-1)) {
306 goto DurationAndDelayProcessing
;
309 y
= convertLswTelemValue(ls
);
313 else if (v1
>= MIXSRC_GVAR1
) {
317 y
= calc100toRESX(ls
->v2
);
324 case LS_FUNC_VALMOSTEQUAL
:
326 if (v1
>= MIXSRC_GVAR1
&& v1
<= MIXSRC_LAST_GVAR
)
330 result
= (abs(x
-y
) < (1024 / STICK_TOLERANCE
));
346 if (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) == CS_LAST_VALUE_INIT
) {
347 LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) = x
;
349 int16_t diff
= x
- LS_LAST_VALUE(mixerCurrentFlightMode
, idx
);
351 if (ls
->func
== LS_FUNC_DIFFEGREATER
) {
353 result
= (diff
>= y
);
358 result
= (diff
<= y
);
364 result
= (abs(diff
) >= y
);
366 if (result
|| update
) {
367 LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) = x
;
375 DurationAndDelayProcessing
:
377 if (ls
->delay
|| ls
->duration
) {
378 LogicalSwitchContext
&context
= lswFm
[mixerCurrentFlightMode
].lsw
[idx
];
380 if (context
.timerState
== SWITCH_START
) {
382 context
.timerState
= SWITCH_DELAY
;
383 context
.timer
= (ls
->func
== LS_FUNC_EDGE
? 0 : ls
->delay
);
386 if (context
.timerState
== SWITCH_DELAY
) {
388 result
= false; // return false while delay timer running
391 // set duration timer
392 context
.timerState
= SWITCH_ENABLE
;
393 context
.timer
= ls
->duration
;
397 if (context
.timerState
== SWITCH_ENABLE
) {
398 result
= (ls
->duration
==0 || context
.timer
>0); // return false after duration timer runs out
399 if (!result
&& ls
->func
== LS_FUNC_STICKY
) {
400 ls_sticky_struct
& lastValue
= (ls_sticky_struct
&)context
.lastValue
;
405 else if (context
.timerState
== SWITCH_ENABLE
&& ls
->duration
> 0 && context
.timer
> 0) {
409 context
.timerState
= SWITCH_START
;
417 bool getSwitch(swsrc_t swtch
, uint8_t flags
)
421 if (swtch
== SWSRC_NONE
)
424 uint8_t cs_idx
= abs(swtch
);
426 if (cs_idx
== SWSRC_ONE
) {
427 result
= !s_mixer_first_run_done
;
429 else if (cs_idx
== SWSRC_ON
) {
432 #if defined(DEBUG_LATENCY)
433 else if (cs_idx
== SWSRC_LATENCY_TOGGLE
) {
434 result
= latencyToggleSwitch
;
437 else if (cs_idx
<= SWSRC_LAST_SWITCH
) {
438 #if defined(PCBTARANIS) || defined(PCBHORUS)
439 if (flags
& GETSWITCH_MIDPOS_DELAY
)
440 result
= SWITCH_POSITION(cs_idx
-SWSRC_FIRST_SWITCH
);
442 result
= switchState(cs_idx
-SWSRC_FIRST_SWITCH
);
444 result
= switchState(cs_idx
-SWSRC_FIRST_SWITCH
);
449 else if (cs_idx
<= SWSRC_LAST_MULTIPOS_SWITCH
) {
450 result
= POT_POSITION(cs_idx
-SWSRC_FIRST_MULTIPOS_SWITCH
);
453 else if (cs_idx
<= SWSRC_LAST_TRIM
) {
454 uint8_t idx
= cs_idx
- SWSRC_FIRST_TRIM
;
455 idx
= (CONVERT_MODE_TRIMS(idx
/2) << 1) + (idx
& 1);
456 result
= trimDown(idx
);
458 else if (cs_idx
== SWSRC_RADIO_ACTIVITY
) {
459 result
= (inactivity
.counter
< 2);
461 else if (cs_idx
>= SWSRC_FIRST_SENSOR
) {
462 result
= !telemetryItems
[cs_idx
-SWSRC_FIRST_SENSOR
].isOld();
464 else if (cs_idx
== SWSRC_TELEMETRY_STREAMING
) {
465 result
= TELEMETRY_STREAMING();
467 else if (cs_idx
>= SWSRC_FIRST_FLIGHT_MODE
) {
468 #if defined(FLIGHT_MODES)
469 uint8_t idx
= cs_idx
- SWSRC_FIRST_FLIGHT_MODE
;
470 if (flags
& GETSWITCH_MIDPOS_DELAY
)
471 result
= (idx
== flightModeTransitionLast
);
473 result
= (idx
== mixerCurrentFlightMode
);
479 cs_idx
-= SWSRC_FIRST_LOGICAL_SWITCH
;
480 result
= lswFm
[mixerCurrentFlightMode
].lsw
[cs_idx
].state
;
483 return swtch
> 0 ? result
: !result
;
487 @brief Calculates new state of logical switches for mixerCurrentFlightMode
489 void evalLogicalSwitches(bool isCurrentFlightmode
)
491 for (unsigned int idx
=0; idx
<MAX_LOGICAL_SWITCHES
; idx
++) {
492 LogicalSwitchContext
& context
= lswFm
[mixerCurrentFlightMode
].lsw
[idx
];
493 bool result
= getLogicalSwitch(idx
);
494 if (isCurrentFlightmode
) {
496 if (!context
.state
) PLAY_LOGICAL_SWITCH_ON(idx
);
499 if (context
.state
) PLAY_LOGICAL_SWITCH_OFF(idx
);
502 context
.state
= result
;
506 swarnstate_t switches_states
= 0;
507 swsrc_t
getMovedSwitch()
509 static tmr10ms_t s_move_last_time
= 0;
512 #if defined(PCBTARANIS) || defined(PCBHORUS)
513 for (int i
=0; i
<NUM_SWITCHES
; i
++) {
514 if (SWITCH_EXISTS(i
)) {
515 swarnstate_t mask
= ((swarnstate_t
)0x03 << (i
*2));
516 uint8_t prev
= (switches_states
& mask
) >> (i
*2);
517 uint8_t next
= (1024+getValue(MIXSRC_SA
+i
)) / 1024;
519 switches_states
= (switches_states
& (~mask
)) | ((swarnstate_t
)next
<< (i
*2));
520 result
= 1+(3*i
)+next
;
525 // return delivers 1 to 3 for ID1 to ID3
526 // 4..8 for all other switches if changed to true
527 // -4..-8 for all other switches if changed to false
528 // 9 for Trainer switch if changed to true; Change to false is ignored
529 swarnstate_t mask
= 0x80;
530 for (uint8_t i
=NUM_SWITCHES_POSITIONS
; i
>1; i
--) {
532 prev
= (switches_states
& mask
);
533 // don't use getSwitch here to always get the proper value, even getSwitch manipulates
534 bool next
= switchState(i
-1);
536 if (((i
<NUM_SWITCHES_POSITIONS
) && (i
>3)) || next
==true)
537 result
= next
? i
: -i
;
538 if (i
<=3 && result
==0) result
= 1;
539 switches_states
^= mask
;
545 if ((tmr10ms_t
)(get_tmr10ms() - s_move_last_time
) > 10)
548 s_move_last_time
= get_tmr10ms();
555 swarnstate_t last_bad_switches
= 0xff;
556 swarnstate_t states
= g_model
.switchWarningState
;
558 #if defined(PCBTARANIS) || defined(PCBHORUS)
559 uint8_t bad_pots
= 0, last_bad_pots
= 0xff;
562 #if defined(PWR_BUTTON_PRESS)
563 bool refresh
= false;
567 #if defined(PCBTARANIS) || defined(PCBHORUS)
568 #define GETADC_COUNT 1
572 for (uint8_t i
=0; i
<GETADC_COUNT
; i
++) {
573 GET_ADC_IF_MIXER_NOT_RUNNING();
581 #if defined(COLORLCD)
582 for (int i
=0; i
<NUM_SWITCHES
; i
++) {
583 if (SWITCH_WARNING_ALLOWED(i
)) {
584 unsigned int state
= ((states
>> (3*i
)) & 0x07);
585 if (state
&& state
-1 != ((switches_states
>> (i
*2)) & 0x03)) {
590 if (g_model
.potsWarnMode
) {
591 evalFlightModeMixes(e_perout_mode_normal
, 0);
593 for (int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; i
++) {
594 if (!IS_POT_SLIDER_AVAILABLE(POT1
+i
)) {
597 if (!(g_model
.potsWarnEnabled
& (1 << i
)) && (abs(g_model
.potsWarnPosition
[i
] - GET_LOWRES_POT_POSITION(i
)) > 1)) {
603 #elif defined(PCBTARANIS)
604 for (int i
=0; i
<NUM_SWITCHES
; i
++) {
605 if (SWITCH_WARNING_ALLOWED(i
) && !(g_model
.switchWarningEnable
& (1<<i
))) {
606 swarnstate_t mask
= ((swarnstate_t
)0x03 << (i
*2));
607 if (!((states
& mask
) == (switches_states
& mask
))) {
612 if (g_model
.potsWarnMode
) {
613 evalFlightModeMixes(e_perout_mode_normal
, 0);
615 for (int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; i
++) {
616 if (!IS_POT_SLIDER_AVAILABLE(POT1
+i
)) {
619 if (!(g_model
.potsWarnEnabled
& (1 << i
)) && (abs(g_model
.potsWarnPosition
[i
] - GET_LOWRES_POT_POSITION(i
)) > 1)) {
626 for (int i
=0; i
<NUM_SWITCHES
-1; i
++) {
627 if (!(g_model
.switchWarningEnable
& (1<<i
))) {
629 if ((states
& 0x03) != (switches_states
& 0x03)) {
633 else if ((states
& (1<<(i
+1))) != (switches_states
& (1<<(i
+1)))) {
647 // first - display warning
648 #if defined(PCBTARANIS) || defined(PCBHORUS)
649 if (last_bad_switches
!= switches_states
|| last_bad_pots
!= bad_pots
) {
650 drawAlertBox(STR_SWITCHWARN
, nullptr, STR_PRESSANYKEYTOSKIP
);
651 if (last_bad_switches
== 0xff || last_bad_pots
== 0xff) {
652 AUDIO_ERROR_MESSAGE(AU_SWITCH_ALERT
);
654 int x
= SWITCH_WARNING_LIST_X
;
655 int y
= SWITCH_WARNING_LIST_Y
;
657 for (int i
=0; i
<NUM_SWITCHES
; ++i
) {
658 #if defined(COLORLCD)
659 if (SWITCH_WARNING_ALLOWED(i
)) {
660 unsigned int state
= ((g_model
.switchWarningState
>> (3*i
)) & 0x07);
661 if (state
&& state
-1 != ((switches_states
>> (i
*2)) & 0x03)) {
662 if (++numWarnings
< 6) {
663 // LcdFlags attr = ((states & mask) == (switches_states & mask)) ? TEXT_COLOR : ALARM_COLOR;
664 LcdFlags attr
= ALARM_COLOR
;
665 drawSwitch(x
, y
, SWSRC_FIRST_SWITCH
+i
*3+state
-1, attr
);
671 if (SWITCH_WARNING_ALLOWED(i
) && !(g_model
.switchWarningEnable
& (1<<i
))) {
672 swarnstate_t mask
= ((swarnstate_t
)0x03 << (i
*2));
673 LcdFlags attr
= ((states
& mask
) == (switches_states
& mask
)) ? 0 : INVERS
;
675 if (++numWarnings
< 6) {
676 char c
= "\300-\301"[(states
& mask
) >> (i
*2)];
677 drawSource(x
, y
, MIXSRC_FIRST_SWITCH
+i
, attr
);
678 lcdDrawChar(lcdNextPos
, y
, c
, attr
);
686 if (g_model
.potsWarnMode
) {
687 for (int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; i
++) {
688 if (!IS_POT_SLIDER_AVAILABLE(POT1
+i
)) {
691 if (!(g_model
.potsWarnEnabled
& (1 << i
))) {
692 if (abs(g_model
.potsWarnPosition
[i
] - GET_LOWRES_POT_POSITION(i
)) > 1) {
693 if (++numWarnings
< 6) {
694 #if defined(COLORLCD)
696 // TODO add an helper
697 strncpy(s
, &STR_VSRCRAW
[1+(NUM_STICKS
+1+i
)*STR_VSRCRAW
[0]], STR_VSRCRAW
[0]);
698 s
[int(STR_VSRCRAW
[0])] = '\0';
699 lcdDrawText(x
, y
, s
, ALARM_COLOR
);
702 lcdDrawTextAtIndex(x
, y
, STR_VSRCRAW
, NUM_STICKS
+ 1 + i
, INVERS
);
703 if (IS_POT(POT1
+ i
))
704 lcdDrawChar(lcdNextPos
, y
, g_model
.potsWarnPosition
[i
] > GET_LOWRES_POT_POSITION(i
) ? 126 : 127, INVERS
);
706 lcdDrawChar(lcdNextPos
, y
, g_model
.potsWarnPosition
[i
] > GET_LOWRES_POT_POSITION(i
) ? '\300' : '\301', INVERS
);
715 if (numWarnings
>= 6) {
716 #if defined(COLORLCD)
717 lcdDrawText(x
, y
, "...", ALARM_COLOR
);
719 lcdDrawText(x
, y
, "...", 0);
723 last_bad_pots
= bad_pots
;
725 if (last_bad_switches
!= switches_states
) {
726 RAISE_ALERT(STR_SWITCHWARN
, NULL
, STR_PRESSANYKEYTOSKIP
, last_bad_switches
== 0xff ? AU_SWITCH_ALERT
: AU_NONE
);
728 for (uint8_t i
=0; i
<NUM_SWITCHES
-1; i
++) {
731 attr
= ((states
& 0x03) != (switches_states
& 0x03)) ? INVERS
: 0;
733 attr
= (states
& (1 << (i
+1))) == (switches_states
& (1 << (i
+1))) ? 0 : INVERS
;
734 if (!(g_model
.switchWarningEnable
& (1<<i
)))
735 drawSwitch(x
, 5*FH
, (i
>0?(i
+3):(states
&0x3)+1), attr
);
744 last_bad_switches
= switches_states
;
750 #if defined(PWR_BUTTON_PRESS)
751 uint32_t power
= pwrCheck();
752 if (power
== e_power_off
) {
757 else if (power
== e_power_press
) {
760 else if (power
== e_power_on
&& refresh
) {
761 last_bad_switches
= 0xff;
762 last_bad_pots
= 0xff;
766 if (pwrCheck() == e_power_off
) {
782 void logicalSwitchesTimerTick()
784 for (uint8_t fm
=0; fm
<MAX_FLIGHT_MODES
; fm
++) {
785 for (uint8_t i
=0; i
<MAX_LOGICAL_SWITCHES
; i
++) {
786 LogicalSwitchData
* ls
= lswAddress(i
);
787 if (ls
->func
== LS_FUNC_TIMER
) {
788 int16_t * lastValue
= &LS_LAST_VALUE(fm
, i
);
789 if (*lastValue
== 0 || *lastValue
== CS_LAST_VALUE_INIT
) {
790 *lastValue
= -lswTimerValue(ls
->v1
);
793 else if (*lastValue
< 0) {
794 if (++(*lastValue
) == 0)
795 *lastValue
= lswTimerValue(ls
->v2
);
797 else { // if (*lastValue > 0)
801 else if (ls
->func
== LS_FUNC_STICKY
) {
802 ls_sticky_struct
& lastValue
= (ls_sticky_struct
&)LS_LAST_VALUE(fm
, i
);
803 bool before
= lastValue
.last
& 0x01;
804 if (lastValue
.state
) {
805 bool now
= getSwitch(ls
->v2
);
814 bool now
= getSwitch(ls
->v1
);
823 else if (ls
->func
== LS_FUNC_EDGE
) {
824 ls_stay_struct
& lastValue
= (ls_stay_struct
&)LS_LAST_VALUE(fm
, i
);
825 // if this ls was reset by the logicalSwitchesReset() the lastValue will be set to CS_LAST_VALUE_INIT(0x8000)
826 // when it is unpacked into ls_stay_struct the lastValue.duration will have a value of 0x4000
827 // this will produce an instant true for edge logical switch if the second parameter is big enough.
828 // So we reset it here.
829 if (LS_LAST_VALUE(fm
, i
) == CS_LAST_VALUE_INIT
) {
830 lastValue
.duration
= 0;
832 lastValue
.state
= false;
833 bool state
= getSwitch(ls
->v1
);
835 if (ls
->v3
== -1 && lastValue
.duration
== lswTimerValue(ls
->v2
))
836 lastValue
.state
= true;
837 if (lastValue
.duration
< 1000)
838 lastValue
.duration
++;
841 if (lastValue
.duration
> lswTimerValue(ls
->v2
) && (ls
->v3
== 0 || lastValue
.duration
<= lswTimerValue(ls
->v2
+ls
->v3
)))
842 lastValue
.state
= true;
843 lastValue
.duration
= 0;
847 // decrement delay/duration timer
848 LogicalSwitchContext
&context
= lswFm
[fm
].lsw
[i
];
856 LogicalSwitchData
* lswAddress(uint8_t idx
)
858 return &g_model
.logicalSw
[idx
];
861 uint8_t lswFamily(uint8_t func
)
863 if (func
<= LS_FUNC_ANEG
)
864 return LS_FAMILY_OFS
;
865 else if (func
<= LS_FUNC_XOR
)
866 return LS_FAMILY_BOOL
;
867 else if (func
== LS_FUNC_EDGE
)
868 return LS_FAMILY_EDGE
;
869 else if (func
<= LS_FUNC_LESS
)
870 return LS_FAMILY_COMP
;
871 else if (func
<= LS_FUNC_ADIFFEGREATER
)
872 return LS_FAMILY_DIFF
;
874 return LS_FAMILY_TIMER
+func
-LS_FUNC_TIMER
;
877 int16_t lswTimerValue(delayval_t val
)
879 return (val
< -109 ? 129+val
: (val
< 7 ? (113+val
)*5 : (53+val
)*10));
882 void logicalSwitchesReset()
884 memset(lswFm
, 0, sizeof(lswFm
));
886 for (uint8_t fm
=0; fm
<MAX_FLIGHT_MODES
; fm
++) {
887 for (uint8_t i
=0; i
<MAX_LOGICAL_SWITCHES
; i
++) {
888 LS_LAST_VALUE(fm
, i
) = CS_LAST_VALUE_INIT
;
893 getvalue_t
convertLswTelemValue(LogicalSwitchData
* ls
)
896 val
= convert16bitsTelemValue(ls
->v1
- MIXSRC_FIRST_TELEM
+ 1, ls
->v2
);
900 void logicalSwitchesCopyState(uint8_t src
, uint8_t dst
)
902 lswFm
[dst
] = lswFm
[src
];