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(PCBHORUS) || defined(PCBX7)
171 CHECK_3POS(6, SW_SI
);
172 CHECK_3POS(7, SW_SJ
);
173 CHECK_3POS(8, SW_SK
);
174 CHECK_3POS(9, SW_SL
);
175 CHECK_3POS(10, SW_SM
);
176 CHECK_3POS(11, SW_SN
);
177 CHECK_3POS(12, SW_SO
);
178 CHECK_3POS(13, SW_SP
);
179 CHECK_3POS(14, SW_SQ
);
180 CHECK_3POS(15, SW_SR
);
183 switchesPos
= newPos
;
185 for (int i
=0; i
<NUM_XPOTS
; i
++) {
186 if (IS_POT_MULTIPOS(POT1
+i
)) {
187 StepsCalibData
* calib
= (StepsCalibData
*) &g_eeGeneral
.calib
[POT1
+i
];
188 if (IS_MULTIPOS_CALIBRATED(calib
)) {
189 uint8_t pos
= anaIn(POT1
+i
) / (2*RESX
/calib
->count
);
190 uint8_t previousPos
= potsPos
[i
] >> 4;
191 uint8_t previousStoredPos
= potsPos
[i
] & 0x0F;
193 potsPos
[i
] = (pos
<< 4) | pos
;
195 else if (pos
!= previousPos
) {
196 potsLastposStart
[i
] = get_tmr10ms();
197 potsPos
[i
] = (pos
<< 4) | previousStoredPos
;
199 else if (g_eeGeneral
.switchesDelay
==SWITCHES_DELAY_NONE
|| (tmr10ms_t
)(get_tmr10ms() - potsLastposStart
[i
]) > SWITCHES_DELAY()) {
200 potsLastposStart
[i
] = 0;
201 potsPos
[i
] = (pos
<< 4) | pos
;
202 if (previousStoredPos
!= pos
) {
203 PLAY_SWITCH_MOVED(SWSRC_LAST_SWITCH
+i
*XPOTS_MULTIPOS_COUNT
+pos
);
212 getvalue_t
getValueForLogicalSwitch(mixsrc_t i
)
214 getvalue_t result
= getValue(i
);
215 if (i
>=MIXSRC_FIRST_INPUT
&& i
<=MIXSRC_LAST_INPUT
) {
216 int8_t trimIdx
= virtualInputsTrims
[i
-MIXSRC_FIRST_INPUT
];
218 int16_t trim
= trims
[trimIdx
];
219 if (trimIdx
== THR_STICK
&& g_model
.throttleReversed
)
228 #define getValueForLogicalSwitch(i) getValue(i)
231 PACK(typedef struct {
236 PACK(typedef struct {
238 uint16_t duration
:15;
241 bool getLogicalSwitch(uint8_t idx
)
243 LogicalSwitchData
* ls
= lswAddress(idx
);
246 swsrc_t s
= ls
->andsw
;
248 if (ls
->func
== LS_FUNC_NONE
|| (s
&& !getSwitch(s
))) {
249 if (ls
->func
!= LS_FUNC_STICKY
&& ls
->func
!= LS_FUNC_EDGE
) {
250 // AND switch must not affect STICKY and EDGE processing
251 LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) = CS_LAST_VALUE_INIT
;
255 else if ((s
=lswFamily(ls
->func
)) == LS_FAMILY_BOOL
) {
256 bool res1
= getSwitch(ls
->v1
);
257 bool res2
= getSwitch(ls
->v2
);
260 result
= (res1
&& res2
);
263 result
= (res1
|| res2
);
267 result
= (res1
^ res2
);
271 else if (s
== LS_FAMILY_TIMER
) {
272 result
= (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) <= 0);
274 else if (s
== LS_FAMILY_STICKY
) {
275 result
= (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) & (1<<0));
277 else if (s
== LS_FAMILY_EDGE
) {
278 result
= (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) & (1<<0));
281 getvalue_t x
= getValueForLogicalSwitch(ls
->v1
);
283 if (s
== LS_FAMILY_COMP
) {
284 y
= getValueForLogicalSwitch(ls
->v2
);
290 case LS_FUNC_GREATER
:
299 mixsrc_t v1
= ls
->v1
;
301 if (v1
>= MIXSRC_FIRST_TELEM
) {
302 if (!TELEMETRY_STREAMING() || IS_FAI_FORBIDDEN(v1
-1)) {
304 goto DurationAndDelayProcessing
;
307 y
= convertLswTelemValue(ls
);
311 else if (v1
>= MIXSRC_GVAR1
) {
315 y
= calc100toRESX(ls
->v2
);
322 case LS_FUNC_VALMOSTEQUAL
:
324 if (v1
>= MIXSRC_GVAR1
&& v1
<= MIXSRC_LAST_GVAR
)
328 result
= (abs(x
-y
) < (1024 / STICK_TOLERANCE
));
344 if (LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) == CS_LAST_VALUE_INIT
) {
345 LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) = x
;
347 int16_t diff
= x
- LS_LAST_VALUE(mixerCurrentFlightMode
, idx
);
349 if (ls
->func
== LS_FUNC_DIFFEGREATER
) {
351 result
= (diff
>= y
);
356 result
= (diff
<= y
);
362 result
= (abs(diff
) >= y
);
364 if (result
|| update
) {
365 LS_LAST_VALUE(mixerCurrentFlightMode
, idx
) = x
;
373 DurationAndDelayProcessing
:
375 if (ls
->delay
|| ls
->duration
) {
376 LogicalSwitchContext
&context
= lswFm
[mixerCurrentFlightMode
].lsw
[idx
];
378 if (context
.timerState
== SWITCH_START
) {
380 context
.timerState
= SWITCH_DELAY
;
381 context
.timer
= (ls
->func
== LS_FUNC_EDGE
? 0 : ls
->delay
);
384 if (context
.timerState
== SWITCH_DELAY
) {
386 result
= false; // return false while delay timer running
389 // set duration timer
390 context
.timerState
= SWITCH_ENABLE
;
391 context
.timer
= ls
->duration
;
395 if (context
.timerState
== SWITCH_ENABLE
) {
396 result
= (ls
->duration
==0 || context
.timer
>0); // return false after duration timer runs out
397 if (!result
&& ls
->func
== LS_FUNC_STICKY
) {
398 ls_sticky_struct
& lastValue
= (ls_sticky_struct
&)context
.lastValue
;
403 else if (context
.timerState
== SWITCH_ENABLE
&& ls
->duration
> 0 && context
.timer
> 0) {
407 context
.timerState
= SWITCH_START
;
415 bool getSwitch(swsrc_t swtch
, uint8_t flags
)
419 if (swtch
== SWSRC_NONE
)
422 uint8_t cs_idx
= abs(swtch
);
424 if (cs_idx
== SWSRC_ONE
) {
425 result
= !s_mixer_first_run_done
;
427 else if (cs_idx
== SWSRC_ON
) {
430 #if defined(DEBUG_LATENCY)
431 else if (cs_idx
== SWSRC_LATENCY_TOGGLE
) {
432 result
= latencyToggleSwitch
;
435 else if (cs_idx
<= SWSRC_LAST_SWITCH
) {
436 #if defined(PCBTARANIS) || defined(PCBHORUS)
437 if (flags
& GETSWITCH_MIDPOS_DELAY
)
438 result
= SWITCH_POSITION(cs_idx
-SWSRC_FIRST_SWITCH
);
440 result
= switchState(cs_idx
-SWSRC_FIRST_SWITCH
);
442 result
= switchState(cs_idx
-SWSRC_FIRST_SWITCH
);
447 else if (cs_idx
<= SWSRC_LAST_MULTIPOS_SWITCH
) {
448 result
= POT_POSITION(cs_idx
-SWSRC_FIRST_MULTIPOS_SWITCH
);
451 else if (cs_idx
<= SWSRC_LAST_TRIM
) {
452 uint8_t idx
= cs_idx
- SWSRC_FIRST_TRIM
;
453 idx
= (CONVERT_MODE_TRIMS(idx
/2) << 1) + (idx
& 1);
454 result
= trimDown(idx
);
456 else if (cs_idx
== SWSRC_RADIO_ACTIVITY
) {
457 result
= (inactivity
.counter
< 2);
459 else if (cs_idx
>= SWSRC_FIRST_SENSOR
) {
460 result
= !telemetryItems
[cs_idx
-SWSRC_FIRST_SENSOR
].isOld();
462 else if (cs_idx
== SWSRC_TELEMETRY_STREAMING
) {
463 result
= TELEMETRY_STREAMING();
465 else if (cs_idx
>= SWSRC_FIRST_FLIGHT_MODE
) {
466 #if defined(FLIGHT_MODES)
467 uint8_t idx
= cs_idx
- SWSRC_FIRST_FLIGHT_MODE
;
468 if (flags
& GETSWITCH_MIDPOS_DELAY
)
469 result
= (idx
== flightModeTransitionLast
);
471 result
= (idx
== mixerCurrentFlightMode
);
477 cs_idx
-= SWSRC_FIRST_LOGICAL_SWITCH
;
478 result
= lswFm
[mixerCurrentFlightMode
].lsw
[cs_idx
].state
;
481 return swtch
> 0 ? result
: !result
;
485 @brief Calculates new state of logical switches for mixerCurrentFlightMode
487 void evalLogicalSwitches(bool isCurrentFlightmode
)
489 for (unsigned int idx
=0; idx
<MAX_LOGICAL_SWITCHES
; idx
++) {
490 LogicalSwitchContext
& context
= lswFm
[mixerCurrentFlightMode
].lsw
[idx
];
491 bool result
= getLogicalSwitch(idx
);
492 if (isCurrentFlightmode
) {
494 if (!context
.state
) PLAY_LOGICAL_SWITCH_ON(idx
);
497 if (context
.state
) PLAY_LOGICAL_SWITCH_OFF(idx
);
500 context
.state
= result
;
504 swarnstate_t switches_states
= 0;
505 swsrc_t
getMovedSwitch()
507 static tmr10ms_t s_move_last_time
= 0;
510 #if defined(PCBTARANIS) || defined(PCBHORUS)
511 for (int i
=0; i
<NUM_SWITCHES
; i
++) {
512 if (SWITCH_EXISTS(i
)) {
513 swarnstate_t mask
= ((swarnstate_t
)0x03 << (i
*2));
514 uint8_t prev
= (switches_states
& mask
) >> (i
*2);
515 uint8_t next
= (1024+getValue(MIXSRC_SA
+i
)) / 1024;
517 switches_states
= (switches_states
& (~mask
)) | ((swarnstate_t
)next
<< (i
*2));
518 result
= 1+(3*i
)+next
;
523 // return delivers 1 to 3 for ID1 to ID3
524 // 4..8 for all other switches if changed to true
525 // -4..-8 for all other switches if changed to false
526 // 9 for Trainer switch if changed to true; Change to false is ignored
527 swarnstate_t mask
= 0x80;
528 for (uint8_t i
=NUM_SWITCHES_POSITIONS
; i
>1; i
--) {
530 prev
= (switches_states
& mask
);
531 // don't use getSwitch here to always get the proper value, even getSwitch manipulates
532 bool next
= switchState(i
-1);
534 if (((i
<NUM_SWITCHES_POSITIONS
) && (i
>3)) || next
==true)
535 result
= next
? i
: -i
;
536 if (i
<=3 && result
==0) result
= 1;
537 switches_states
^= mask
;
543 if ((tmr10ms_t
)(get_tmr10ms() - s_move_last_time
) > 10)
546 s_move_last_time
= get_tmr10ms();
553 swarnstate_t last_bad_switches
= 0xff;
554 swarnstate_t states
= g_model
.switchWarningState
;
556 #if defined(PCBTARANIS) || defined(PCBHORUS)
557 uint8_t bad_pots
= 0, last_bad_pots
= 0xff;
560 #if defined(PWR_BUTTON_PRESS)
561 bool refresh
= false;
565 #if defined(PCBTARANIS) || defined(PCBHORUS)
566 #define GETADC_COUNT 1
570 for (uint8_t i
=0; i
<GETADC_COUNT
; i
++) {
571 GET_ADC_IF_MIXER_NOT_RUNNING();
579 #if defined(COLORLCD)
580 for (int i
=0; i
<NUM_SWITCHES
; i
++) {
581 if (SWITCH_WARNING_ALLOWED(i
)) {
582 unsigned int state
= ((states
>> (3*i
)) & 0x07);
583 if (state
&& state
-1 != ((switches_states
>> (i
*2)) & 0x03)) {
588 if (g_model
.potsWarnMode
) {
589 evalFlightModeMixes(e_perout_mode_normal
, 0);
591 for (int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; i
++) {
592 if (!IS_POT_SLIDER_AVAILABLE(POT1
+i
)) {
595 if (!(g_model
.potsWarnEnabled
& (1 << i
)) && (abs(g_model
.potsWarnPosition
[i
] - GET_LOWRES_POT_POSITION(i
)) > 1)) {
601 #elif defined(PCBTARANIS)
602 for (int i
=0; i
<NUM_SWITCHES
; i
++) {
603 if (SWITCH_WARNING_ALLOWED(i
) && !(g_model
.switchWarningEnable
& (1<<i
))) {
604 swarnstate_t mask
= ((swarnstate_t
)0x03 << (i
*2));
605 if (!((states
& mask
) == (switches_states
& mask
))) {
610 if (g_model
.potsWarnMode
) {
611 evalFlightModeMixes(e_perout_mode_normal
, 0);
613 for (int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; i
++) {
614 if (!IS_POT_SLIDER_AVAILABLE(POT1
+i
)) {
617 if (!(g_model
.potsWarnEnabled
& (1 << i
)) && (abs(g_model
.potsWarnPosition
[i
] - GET_LOWRES_POT_POSITION(i
)) > 1)) {
624 for (int i
=0; i
<NUM_SWITCHES
-1; i
++) {
625 if (!(g_model
.switchWarningEnable
& (1<<i
))) {
627 if ((states
& 0x03) != (switches_states
& 0x03)) {
631 else if ((states
& (1<<(i
+1))) != (switches_states
& (1<<(i
+1)))) {
645 // first - display warning
646 #if defined(PCBTARANIS) || defined(PCBHORUS)
647 if (last_bad_switches
!= switches_states
|| last_bad_pots
!= bad_pots
) {
648 drawAlertBox(STR_SWITCHWARN
, nullptr, STR_PRESSANYKEYTOSKIP
);
649 if (last_bad_switches
== 0xff || last_bad_pots
== 0xff) {
650 AUDIO_ERROR_MESSAGE(AU_SWITCH_ALERT
);
652 int x
= SWITCH_WARNING_LIST_X
;
653 int y
= SWITCH_WARNING_LIST_Y
;
655 for (int i
=0; i
<NUM_SWITCHES
; ++i
) {
656 #if defined(COLORLCD)
657 if (SWITCH_WARNING_ALLOWED(i
)) {
658 unsigned int state
= ((g_model
.switchWarningState
>> (3*i
)) & 0x07);
659 if (state
&& state
-1 != ((switches_states
>> (i
*2)) & 0x03)) {
660 if (++numWarnings
< 6) {
661 // LcdFlags attr = ((states & mask) == (switches_states & mask)) ? TEXT_COLOR : ALARM_COLOR;
662 LcdFlags attr
= ALARM_COLOR
;
663 drawSwitch(x
, y
, SWSRC_FIRST_SWITCH
+i
*3+state
-1, attr
);
669 if (SWITCH_WARNING_ALLOWED(i
) && !(g_model
.switchWarningEnable
& (1<<i
))) {
670 swarnstate_t mask
= ((swarnstate_t
)0x03 << (i
*2));
671 LcdFlags attr
= ((states
& mask
) == (switches_states
& mask
)) ? 0 : INVERS
;
673 if (++numWarnings
< 6) {
674 char c
= "\300-\301"[(states
& mask
) >> (i
*2)];
675 drawSource(x
, y
, MIXSRC_FIRST_SWITCH
+i
, attr
);
676 lcdDrawChar(lcdNextPos
, y
, c
, attr
);
684 if (g_model
.potsWarnMode
) {
685 for (int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; i
++) {
686 if (!IS_POT_SLIDER_AVAILABLE(POT1
+i
)) {
689 if (!(g_model
.potsWarnEnabled
& (1 << i
))) {
690 if (abs(g_model
.potsWarnPosition
[i
] - GET_LOWRES_POT_POSITION(i
)) > 1) {
691 if (++numWarnings
< 6) {
692 #if defined(COLORLCD)
694 // TODO add an helper
695 strncpy(s
, &STR_VSRCRAW
[1+(NUM_STICKS
+1+i
)*STR_VSRCRAW
[0]], STR_VSRCRAW
[0]);
696 s
[int(STR_VSRCRAW
[0])] = '\0';
697 lcdDrawText(x
, y
, s
, ALARM_COLOR
);
700 lcdDrawTextAtIndex(x
, y
, STR_VSRCRAW
, NUM_STICKS
+ 1 + i
, INVERS
);
701 if (IS_POT(POT1
+ i
))
702 lcdDrawChar(lcdNextPos
, y
, g_model
.potsWarnPosition
[i
] > GET_LOWRES_POT_POSITION(i
) ? 126 : 127, INVERS
);
704 lcdDrawChar(lcdNextPos
, y
, g_model
.potsWarnPosition
[i
] > GET_LOWRES_POT_POSITION(i
) ? '\300' : '\301', INVERS
);
713 if (numWarnings
>= 6) {
714 #if defined(COLORLCD)
715 lcdDrawText(x
, y
, "...", ALARM_COLOR
);
717 lcdDrawText(x
, y
, "...", 0);
721 last_bad_pots
= bad_pots
;
723 if (last_bad_switches
!= switches_states
) {
724 RAISE_ALERT(STR_SWITCHWARN
, NULL
, STR_PRESSANYKEYTOSKIP
, last_bad_switches
== 0xff ? AU_SWITCH_ALERT
: AU_NONE
);
726 for (uint8_t i
=0; i
<NUM_SWITCHES
-1; i
++) {
729 attr
= ((states
& 0x03) != (switches_states
& 0x03)) ? INVERS
: 0;
731 attr
= (states
& (1 << (i
+1))) == (switches_states
& (1 << (i
+1))) ? 0 : INVERS
;
732 if (!(g_model
.switchWarningEnable
& (1<<i
)))
733 drawSwitch(x
, 5*FH
, (i
>0?(i
+3):(states
&0x3)+1), attr
);
742 last_bad_switches
= switches_states
;
748 #if defined(PWR_BUTTON_PRESS)
749 uint32_t power
= pwrCheck();
750 if (power
== e_power_off
) {
755 else if (power
== e_power_press
) {
758 else if (power
== e_power_on
&& refresh
) {
759 last_bad_switches
= 0xff;
760 last_bad_pots
= 0xff;
764 if (pwrCheck() == e_power_off
) {
769 doLoopCommonActions();
780 void logicalSwitchesTimerTick()
782 for (uint8_t fm
=0; fm
<MAX_FLIGHT_MODES
; fm
++) {
783 for (uint8_t i
=0; i
<MAX_LOGICAL_SWITCHES
; i
++) {
784 LogicalSwitchData
* ls
= lswAddress(i
);
785 if (ls
->func
== LS_FUNC_TIMER
) {
786 int16_t * lastValue
= &LS_LAST_VALUE(fm
, i
);
787 if (*lastValue
== 0 || *lastValue
== CS_LAST_VALUE_INIT
) {
788 *lastValue
= -lswTimerValue(ls
->v1
);
791 else if (*lastValue
< 0) {
792 if (++(*lastValue
) == 0)
793 *lastValue
= lswTimerValue(ls
->v2
);
795 else { // if (*lastValue > 0)
799 else if (ls
->func
== LS_FUNC_STICKY
) {
800 ls_sticky_struct
& lastValue
= (ls_sticky_struct
&)LS_LAST_VALUE(fm
, i
);
801 bool before
= lastValue
.last
& 0x01;
802 if (lastValue
.state
) {
803 bool now
= getSwitch(ls
->v2
);
812 bool now
= getSwitch(ls
->v1
);
821 else if (ls
->func
== LS_FUNC_EDGE
) {
822 ls_stay_struct
& lastValue
= (ls_stay_struct
&)LS_LAST_VALUE(fm
, i
);
823 // if this ls was reset by the logicalSwitchesReset() the lastValue will be set to CS_LAST_VALUE_INIT(0x8000)
824 // when it is unpacked into ls_stay_struct the lastValue.duration will have a value of 0x4000
825 // this will produce an instant true for edge logical switch if the second parameter is big enough.
826 // So we reset it here.
827 if (LS_LAST_VALUE(fm
, i
) == CS_LAST_VALUE_INIT
) {
828 lastValue
.duration
= 0;
830 lastValue
.state
= false;
831 bool state
= getSwitch(ls
->v1
);
833 if (ls
->v3
== -1 && lastValue
.duration
== lswTimerValue(ls
->v2
))
834 lastValue
.state
= true;
835 if (lastValue
.duration
< 1000)
836 lastValue
.duration
++;
839 if (lastValue
.duration
> lswTimerValue(ls
->v2
) && (ls
->v3
== 0 || lastValue
.duration
<= lswTimerValue(ls
->v2
+ls
->v3
)))
840 lastValue
.state
= true;
841 lastValue
.duration
= 0;
845 // decrement delay/duration timer
846 LogicalSwitchContext
&context
= lswFm
[fm
].lsw
[i
];
854 LogicalSwitchData
* lswAddress(uint8_t idx
)
856 return &g_model
.logicalSw
[idx
];
859 uint8_t lswFamily(uint8_t func
)
861 if (func
<= LS_FUNC_ANEG
)
862 return LS_FAMILY_OFS
;
863 else if (func
<= LS_FUNC_XOR
)
864 return LS_FAMILY_BOOL
;
865 else if (func
== LS_FUNC_EDGE
)
866 return LS_FAMILY_EDGE
;
867 else if (func
<= LS_FUNC_LESS
)
868 return LS_FAMILY_COMP
;
869 else if (func
<= LS_FUNC_ADIFFEGREATER
)
870 return LS_FAMILY_DIFF
;
872 return LS_FAMILY_TIMER
+func
-LS_FUNC_TIMER
;
875 int16_t lswTimerValue(delayval_t val
)
877 return (val
< -109 ? 129+val
: (val
< 7 ? (113+val
)*5 : (53+val
)*10));
880 void logicalSwitchesReset()
882 memset(lswFm
, 0, sizeof(lswFm
));
884 for (uint8_t fm
=0; fm
<MAX_FLIGHT_MODES
; fm
++) {
885 for (uint8_t i
=0; i
<MAX_LOGICAL_SWITCHES
; i
++) {
886 LS_LAST_VALUE(fm
, i
) = CS_LAST_VALUE_INIT
;
891 getvalue_t
convertLswTelemValue(LogicalSwitchData
* ls
)
894 val
= convert16bitsTelemValue(ls
->v1
- MIXSRC_FIRST_TELEM
+ 1, ls
->v2
);
898 void logicalSwitchesCopyState(uint8_t src
, uint8_t dst
)
900 lswFm
[dst
] = lswFm
[src
];