@@ -55,10 +55,38 @@ enum LogicalSwitchContextState {
5555 SWITCH_ENABLE
5656};
5757
58- LogicalSwitchesFlightModeContext lswFm[MAX_FLIGHT_MODES];
58+ PACK (struct LogicalSwitchContext {
59+ uint8_t state:1 ;
60+ uint8_t timerState:2 ;
61+ uint8_t spare:1 ;
62+ uint8_t deltaTimer:4 ;
63+ uint8_t timer;
64+ int16_t lastValue;
65+ });
66+
67+ static LogicalSwitchContext lswCtx[MAX_LOGICAL_SWITCHES];
68+
69+ // Frozen LS state bitmaps for FM fade transitions.
70+ // When transitioning between flight modes with fade, the fading-out FM's
71+ // LS state is frozen at the moment of transition so that mix evaluation
72+ // during the fade sees the pre-transition LS values (preserving smooth
73+ // cross-fade behavior for LS-conditioned mixes).
74+ #define FROZEN_LS_WORDS ((MAX_LOGICAL_SWITCHES + 31 ) / 32 )
75+ static uint32_t frozenLsState[MAX_FLIGHT_MODES][FROZEN_LS_WORDS];
76+
77+ static inline void frozenLsSet (uint8_t fm, uint8_t idx)
78+ {
79+ frozenLsState[fm][idx >> 5 ] |= (1u << (idx & 31 ));
80+ }
81+
82+ static inline bool frozenLsGet (uint8_t fm, uint8_t idx)
83+ {
84+ return (frozenLsState[fm][idx >> 5 ] >> (idx & 31 )) & 1 ;
85+ }
86+
5987CircularBuffer<uint8_t , 8 > luaSetStickySwitchBuffer;
6088
61- #define LS_LAST_VALUE (fm, idx ) lswFm[fm].lsw [idx].lastValue
89+ #define LS_LAST_VALUE (idx ) lswCtx [idx].lastValue
6290
6391tmr10ms_t switchesMidposStart[MAX_SWITCHES];
6492uint64_t switchesPos = 0 ;
@@ -475,23 +503,23 @@ PACK(typedef struct {
475503
476504bool getLSStickyState (uint8_t idx)
477505{
478- return lswFm[mixerCurrentFlightMode]. lsw [idx].lastValue & 1 ;
506+ return lswCtx [idx].lastValue & 1 ;
479507}
480508
481509void logicalSwitchesInit (bool force)
482510{
483511 for (unsigned int idx=0 ; idx<MAX_LOGICAL_SWITCHES; idx++) {
484512 LogicalSwitchData * ls = lswAddress (idx);
485513 if (ls->func == LS_FUNC_STICKY && (force || ls->lsPersist )) {
486- lswFm[mixerCurrentFlightMode]. lsw [idx].lastValue = ls->lsState ;
514+ lswCtx [idx].lastValue = ls->lsState ;
487515 }
488516 }
489517}
490518
491519bool getLogicalSwitch (uint8_t idx)
492520{
493521 LogicalSwitchData * ls = lswAddress (idx);
494- LogicalSwitchContext &context = lswFm[mixerCurrentFlightMode]. lsw [idx];
522+ LogicalSwitchContext &context = lswCtx [idx];
495523 bool result;
496524
497525 if (ls->func == LS_FUNC_NONE || (!ls->andsw .isNone () && !getSwitch (ls->andsw ))) {
@@ -713,7 +741,10 @@ bool getSwitch(const SwitchRef& ref, uint8_t flags)
713741 }
714742
715743 case SWITCH_TYPE_LOGICAL:
716- result = lswFm[mixerCurrentFlightMode].lsw [ref.index ].state ;
744+ if (mixerCurrentFlightMode != mixerActiveFlightMode)
745+ result = frozenLsGet (mixerCurrentFlightMode, ref.index );
746+ else
747+ result = lswCtx[ref.index ].state ;
717748 break ;
718749
719750 case SWITCH_TYPE_FLIGHT_MODE: {
@@ -767,7 +798,7 @@ uint8_t getXPotPosition(uint8_t idx)
767798void evalLogicalSwitches (bool isCurrentFlightmode)
768799{
769800 for (unsigned int idx=0 ; idx<MAX_LOGICAL_SWITCHES; idx++) {
770- LogicalSwitchContext & context = lswFm[mixerCurrentFlightMode]. lsw [idx];
801+ LogicalSwitchContext & context = lswCtx [idx];
771802 bool result = getLogicalSwitch (idx);
772803 if (isCurrentFlightmode) {
773804 if (result) {
@@ -1044,91 +1075,86 @@ void logicalSwitchesTimerTick()
10441075 uint8_t s = msg >> 7 ;
10451076 LogicalSwitchData * ls = lswAddress (i);
10461077 if (ls->func == LS_FUNC_STICKY) {
1047- for (uint8_t fm=0 ; fm<MAX_FLIGHT_MODES; fm++) {
1048- ls_sticky_struct & lastValue = (ls_sticky_struct &)LS_LAST_VALUE (fm, i);
1049- lastValue.state = s;
1050- bool now;
1051- if (s)
1052- now = getSwitch (ls->v2 .swtch );
1053- else
1054- now = getSwitch (ls->v1 .swtch );
1055- if (now)
1056- lastValue.last |= 1 ;
1057- else
1058- lastValue.last &= ~1 ;
1059- }
1078+ ls_sticky_struct & lastValue = (ls_sticky_struct &)LS_LAST_VALUE (i);
1079+ lastValue.state = s;
1080+ bool now;
1081+ if (s)
1082+ now = getSwitch (ls->v2 .swtch );
1083+ else
1084+ now = getSwitch (ls->v1 .swtch );
1085+ if (now)
1086+ lastValue.last |= 1 ;
1087+ else
1088+ lastValue.last &= ~1 ;
10601089 }
10611090 msg = luaSetStickySwitchBuffer.read ();
10621091 }
10631092
10641093 // Update logical switches
1065- for (uint8_t fm=0 ; fm<MAX_FLIGHT_MODES; fm++) {
1066- for (uint8_t i=0 ; i<MAX_LOGICAL_SWITCHES; i++) {
1067- LogicalSwitchData * ls = lswAddress (i);
1068- if (ls->func == LS_FUNC_TIMER) {
1069- int16_t *lastValue = &LS_LAST_VALUE (fm, i);
1070- if (*lastValue == 0 || *lastValue == CS_LAST_VALUE_INIT) {
1071- *lastValue = -lswTimerValue (ls->v1 .value );
1072- } else if (*lastValue < 0 ) {
1073- if (++(*lastValue) == 0 ) *lastValue = lswTimerValue (ls->v2 .value );
1074- } else { // if (*lastValue > 0)
1075- if (--(*lastValue) == 0 ) *lastValue = -lswTimerValue (ls->v1 .value );
1076- }
1077- } else if (ls->func == LS_FUNC_STICKY) {
1078- ls_sticky_struct & lastValue = (ls_sticky_struct &)LS_LAST_VALUE (fm, i);
1079- bool before = lastValue.last & 0x01 ;
1080- if (lastValue.state ) {
1081- if (!ls->v2 .swtch .isNone ()) { // only if used / source set
1082- bool now = getSwitch (ls->v2 .swtch );
1083- if (now != before) {
1084- lastValue.last ^= 1 ;
1085- if (!before) {
1086- lastValue.state = 0 ;
1087- }
1094+ for (uint8_t i=0 ; i<MAX_LOGICAL_SWITCHES; i++) {
1095+ LogicalSwitchData * ls = lswAddress (i);
1096+ if (ls->func == LS_FUNC_TIMER) {
1097+ int16_t *lastValue = &LS_LAST_VALUE (i);
1098+ if (*lastValue == 0 || *lastValue == CS_LAST_VALUE_INIT) {
1099+ *lastValue = -lswTimerValue (ls->v1 .value );
1100+ } else if (*lastValue < 0 ) {
1101+ if (++(*lastValue) == 0 ) *lastValue = lswTimerValue (ls->v2 .value );
1102+ } else { // if (*lastValue > 0)
1103+ if (--(*lastValue) == 0 ) *lastValue = -lswTimerValue (ls->v1 .value );
1104+ }
1105+ } else if (ls->func == LS_FUNC_STICKY) {
1106+ ls_sticky_struct & lastValue = (ls_sticky_struct &)LS_LAST_VALUE (i);
1107+ bool before = lastValue.last & 0x01 ;
1108+ if (lastValue.state ) {
1109+ if (!ls->v2 .swtch .isNone ()) { // only if used / source set
1110+ bool now = getSwitch (ls->v2 .swtch );
1111+ if (now != before) {
1112+ lastValue.last ^= 1 ;
1113+ if (!before) {
1114+ lastValue.state = 0 ;
10881115 }
1089- }
1090- }
1091- else {
1092- if (!ls-> v1 . swtch . isNone ()) { // only if used / source set
1093- bool now = getSwitch ( ls->v1 .swtch );
1094- if (before != now) {
1095- lastValue. last ^= 1 ;
1096- if (!before) {
1097- lastValue. state = 1 ;
1098- }
1116+ }
1117+ }
1118+ }
1119+ else {
1120+ if (! ls->v1 .swtch . isNone ()) { // only if used / source set
1121+ bool now = getSwitch (ls-> v1 . swtch );
1122+ if (before != now) {
1123+ lastValue. last ^= 1 ;
1124+ if (!before) {
1125+ lastValue. state = 1 ;
10991126 }
1100- }
1101- }
1102- } else if (ls->func == LS_FUNC_EDGE) {
1103- ls_stay_struct & lastValue = (ls_stay_struct &)LS_LAST_VALUE (fm, i);
1104- // if this ls was reset by the logicalSwitchesReset() the lastValue will be set to CS_LAST_VALUE_INIT(0x8000)
1105- // when it is unpacked into ls_stay_struct the lastValue.duration will have a value of 0x4000
1106- // this will produce an instant true for edge logical switch if the second parameter is big enough.
1107- // So we reset it here.
1108- if (LS_LAST_VALUE (fm, i) == CS_LAST_VALUE_INIT) {
1109- lastValue.duration = 0 ;
1110- }
1111- lastValue.state = false ;
1112- bool state = getSwitch (ls->v1 .swtch );
1113- if (state) {
1114- if (ls->v3 == -1 && lastValue.duration == lswTimerValue (ls->v2 .value ))
1115- lastValue.state = true ;
1116- if (lastValue.duration < 1000 )
1117- lastValue.duration ++;
1118- }
1119- else {
1120- if (lastValue.duration > lswTimerValue (ls->v2 .value ) && (ls->v3 == 0 || lastValue.duration <= lswTimerValue (ls->v2 .value +ls->v3 )))
1121- lastValue.state = true ;
1122- lastValue.duration = 0 ;
1123- }
1127+ }
1128+ }
11241129 }
1125-
1126- // decrement delay/duration timer
1127- LogicalSwitchContext &context = lswFm[fm].lsw [i];
1128- if (context.timer ) {
1129- context.timer --;
1130+ } else if (ls->func == LS_FUNC_EDGE) {
1131+ ls_stay_struct & lastValue = (ls_stay_struct &)LS_LAST_VALUE (i);
1132+ // if this ls was reset by the logicalSwitchesReset() the lastValue will be set to CS_LAST_VALUE_INIT(0x8000)
1133+ // when it is unpacked into ls_stay_struct the lastValue.duration will have a value of 0x4000
1134+ // this will produce an instant true for edge logical switch if the second parameter is big enough.
1135+ // So we reset it here.
1136+ if (LS_LAST_VALUE (i) == CS_LAST_VALUE_INIT) {
1137+ lastValue.duration = 0 ;
1138+ }
1139+ lastValue.state = false ;
1140+ bool state = getSwitch (ls->v1 .swtch );
1141+ if (state) {
1142+ if (ls->v3 == -1 && lastValue.duration == lswTimerValue (ls->v2 .value ))
1143+ lastValue.state = true ;
1144+ if (lastValue.duration < 1000 )
1145+ lastValue.duration ++;
1146+ }
1147+ else {
1148+ if (lastValue.duration > lswTimerValue (ls->v2 .value ) && (ls->v3 == 0 || lastValue.duration <= lswTimerValue (ls->v2 .value +ls->v3 )))
1149+ lastValue.state = true ;
1150+ lastValue.duration = 0 ;
11301151 }
11311152 }
1153+
1154+ // decrement delay/duration timer
1155+ if (lswCtx[i].timer ) {
1156+ lswCtx[i].timer --;
1157+ }
11321158 }
11331159}
11341160
@@ -1189,28 +1215,48 @@ int16_t lswTimerValue(delayval_t val)
11891215
11901216void logicalSwitchesReset ()
11911217{
1192- memset (lswFm , 0 , sizeof (lswFm ));
1218+ memset (lswCtx , 0 , sizeof (lswCtx ));
11931219
1194- for (uint8_t fm=0 ; fm<MAX_FLIGHT_MODES; fm++) {
1195- for (uint8_t i=0 ; i<MAX_LOGICAL_SWITCHES; i++) {
1196- LS_LAST_VALUE (fm, i) = CS_LAST_VALUE_INIT;
1197- }
1220+ for (uint8_t i=0 ; i<MAX_LOGICAL_SWITCHES; i++) {
1221+ LS_LAST_VALUE (i) = CS_LAST_VALUE_INIT;
11981222 }
11991223
12001224 luaSetStickySwitchBuffer.clear ();
12011225}
12021226
1227+ void lswFreezeState (uint8_t fm)
1228+ {
1229+ memset (frozenLsState[fm], 0 , sizeof (frozenLsState[fm]));
1230+ for (uint8_t i = 0 ; i < MAX_LOGICAL_SWITCHES; i++) {
1231+ if (lswCtx[i].state )
1232+ frozenLsSet (fm, i);
1233+ }
1234+ }
1235+
1236+ bool lswGetState (uint8_t idx)
1237+ {
1238+ return lswCtx[idx].state ;
1239+ }
1240+
1241+ int16_t lswGetLastValue (uint8_t idx)
1242+ {
1243+ return lswCtx[idx].lastValue ;
1244+ }
1245+
1246+ void lswSetState (uint8_t idx, uint8_t state, uint8_t timer, int16_t lastValue)
1247+ {
1248+ lswCtx[idx].state = state;
1249+ lswCtx[idx].timer = timer;
1250+ lswCtx[idx].lastValue = lastValue;
1251+ }
1252+
12031253getvalue_t convertLswTelemValue (LogicalSwitchData * ls)
12041254{
12051255 getvalue_t val;
12061256 val = convert16bitsTelemValue (ls->v1 .source .index + 1 , ls->v2 .value );
12071257 return val;
12081258}
12091259
1210- void logicalSwitchesCopyState (uint8_t src, uint8_t dst)
1211- {
1212- lswFm[dst] = lswFm[src];
1213- }
12141260
12151261void setAllPreflightSwitchStates ()
12161262{
0 commit comments