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 CustomFunctionsContext modelFunctionsContext
= { 0 };
26 CustomFunctionsContext globalFunctionsContext
= { 0 };
31 * This is a test function for debugging purpose, you may insert there your code and compile with the option DEBUG=YES
36 printf("testFunc\n"); fflush(stdout
);
42 PLAY_FUNCTION(playValue
, source_t idx
)
44 if (IS_FAI_FORBIDDEN(idx
))
47 if (idx
== MIXSRC_NONE
)
50 getvalue_t val
= getValue(idx
);
53 if (idx
>= MIXSRC_FIRST_TELEM
) {
54 TelemetrySensor
& telemetrySensor
= g_model
.telemetrySensors
[(idx
-MIXSRC_FIRST_TELEM
) / 3];
56 if (telemetrySensor
.prec
> 0) {
57 if (telemetrySensor
.prec
== 2) {
59 val
= div_and_round(val
, 100);
62 val
= div_and_round(val
, 10);
68 val
= div_and_round(val
, 10);
75 PLAY_NUMBER(val
, telemetrySensor
.unit
== UNIT_CELLS
? UNIT_VOLTS
: telemetrySensor
.unit
, attr
);
77 else if (idx
>= MIXSRC_FIRST_TIMER
&& idx
<= MIXSRC_LAST_TIMER
) {
78 PLAY_DURATION(val
, 0);
80 else if (idx
== MIXSRC_TX_TIME
) {
81 PLAY_DURATION(val
*60, PLAY_TIME
);
83 else if (idx
== MIXSRC_TX_VOLTAGE
) {
84 PLAY_NUMBER(val
, UNIT_VOLTS
, PREC1
);
87 if (idx
<= MIXSRC_LAST_CH
) {
88 val
= calcRESXto100(val
);
90 PLAY_NUMBER(val
, 0, 0);
94 case MIXSRC_FIRST_TELEM
+TELEM_TX_VOLTAGE
-1:
95 PLAY_NUMBER(val
, 1+UNIT_VOLTS
, PREC1
);
97 case MIXSRC_FIRST_TELEM
+TELEM_TIMER1
-1:
98 case MIXSRC_FIRST_TELEM
+TELEM_TIMER2
-1:
99 PLAY_DURATION(val
, 0);
101 #if defined(TELEMETRY_FRSKY)
102 case MIXSRC_FIRST_TELEM
+TELEM_RSSI_TX
-1:
103 case MIXSRC_FIRST_TELEM
+TELEM_RSSI_RX
-1:
104 PLAY_NUMBER(val
, 1+UNIT_DB
, 0);
106 case MIXSRC_FIRST_TELEM
+TELEM_MIN_A1
-1:
107 case MIXSRC_FIRST_TELEM
+TELEM_MIN_A2
-1:
108 idx
-= TELEM_MIN_A1
-TELEM_A1
;
110 case MIXSRC_FIRST_TELEM
+TELEM_A1
-1:
111 case MIXSRC_FIRST_TELEM
+TELEM_A2
-1:
112 if (TELEMETRY_STREAMING()) {
113 idx
-= (MIXSRC_FIRST_TELEM
+TELEM_A1
-1);
115 int16_t converted_value
= div_and_round(applyChannelRatio(idx
, val
), 10);
116 if (ANA_CHANNEL_UNIT(idx
) < UNIT_RAW
) {
119 PLAY_NUMBER(converted_value
, 1+ANA_CHANNEL_UNIT(idx
), att
);
122 case MIXSRC_FIRST_TELEM
+TELEM_CELL
-1:
123 case MIXSRC_FIRST_TELEM
+TELEM_MIN_CELL
-1:
124 PLAY_NUMBER(div_and_round(val
, 10), 1+UNIT_VOLTS
, PREC1
);
127 case MIXSRC_FIRST_TELEM
+TELEM_VFAS
-1:
128 case MIXSRC_FIRST_TELEM
+TELEM_CELLS_SUM
-1:
129 case MIXSRC_FIRST_TELEM
+TELEM_MIN_CELLS_SUM
-1:
130 case MIXSRC_FIRST_TELEM
+TELEM_MIN_VFAS
-1:
131 PLAY_NUMBER(val
, 1+UNIT_VOLTS
, PREC1
);
134 case MIXSRC_FIRST_TELEM
+TELEM_CURRENT
-1:
135 case MIXSRC_FIRST_TELEM
+TELEM_MAX_CURRENT
-1:
136 PLAY_NUMBER(val
, 1+UNIT_AMPS
, PREC1
);
139 case MIXSRC_FIRST_TELEM
+TELEM_ACCx
-1:
140 case MIXSRC_FIRST_TELEM
+TELEM_ACCy
-1:
141 case MIXSRC_FIRST_TELEM
+TELEM_ACCz
-1:
142 PLAY_NUMBER(div_and_round(val
, 10), 1+UNIT_G
, PREC1
);
145 case MIXSRC_FIRST_TELEM
+TELEM_VSPEED
-1:
146 PLAY_NUMBER(div_and_round(val
, 10), 1+UNIT_METERS_PER_SECOND
, PREC1
);
149 case MIXSRC_FIRST_TELEM
+TELEM_ASPEED
-1:
150 case MIXSRC_FIRST_TELEM
+TELEM_MAX_ASPEED
-1:
151 PLAY_NUMBER(val
/10, 1+UNIT_KTS
, 0);
154 case MIXSRC_FIRST_TELEM
+TELEM_CONSUMPTION
-1:
155 PLAY_NUMBER(val
, 1+UNIT_MAH
, 0);
158 case MIXSRC_FIRST_TELEM
+TELEM_POWER
-1:
159 PLAY_NUMBER(val
, 1+UNIT_WATTS
, 0);
162 case MIXSRC_FIRST_TELEM
+TELEM_ALT
-1:
163 case MIXSRC_FIRST_TELEM
+TELEM_MIN_ALT
-1:
164 case MIXSRC_FIRST_TELEM
+TELEM_MAX_ALT
-1:
165 #if defined(WS_HOW_HIGH)
166 if (IS_IMPERIAL_ENABLE() && IS_USR_PROTO_WS_HOW_HIGH())
167 PLAY_NUMBER(val
, 1+UNIT_FEET
, 0);
170 PLAY_NUMBER(val
, 1+UNIT_DIST
, 0);
173 case MIXSRC_FIRST_TELEM
+TELEM_RPM
-1:
174 case MIXSRC_FIRST_TELEM
+TELEM_MAX_RPM
-1:
176 getvalue_t rpm
= val
;
178 rpm
= 10 * div_and_round(rpm
, 10);
180 rpm
= 10 * div_and_round(rpm
, 10);
181 PLAY_NUMBER(rpm
, 1+UNIT_RPMS
, 0);
185 case MIXSRC_FIRST_TELEM
+TELEM_HDG
-1:
186 PLAY_NUMBER(val
, 1+UNIT_HDG
, 0);
192 if (idx
< MIXSRC_GVAR1
)
193 val
= calcRESXto100(val
);
194 if (idx
>= MIXSRC_FIRST_TELEM
+TELEM_ALT
-1 && idx
<= MIXSRC_FIRST_TELEM
+TELEM_GPSALT
-1)
195 unit
= idx
- (MIXSRC_FIRST_TELEM
+TELEM_ALT
-1);
196 else if (idx
>= MIXSRC_FIRST_TELEM
+TELEM_MAX_T1
-1 && idx
<= MIXSRC_FIRST_TELEM
+TELEM_MAX_DIST
-1)
197 unit
= 3 + idx
- (MIXSRC_FIRST_TELEM
+TELEM_MAX_T1
-1);
199 unit
= pgm_read_byte(bchunit_ar
+unit
);
200 PLAY_NUMBER(val
, unit
== UNIT_RAW
? 0 : unit
+1, 0);
205 PLAY_NUMBER(val
, 0, 0);
214 void playCustomFunctionFile(const CustomFunctionData
* sd
, uint8_t id
)
216 if (sd
->play
.name
[0] != '\0') {
217 char filename
[sizeof(SOUNDS_PATH
)+sizeof(sd
->play
.name
)+sizeof(SOUNDS_EXT
)] = SOUNDS_PATH
"/";
218 strncpy(filename
+SOUNDS_PATH_LNG_OFS
, currentLanguagePack
->id
, 2);
219 strncpy(filename
+sizeof(SOUNDS_PATH
), sd
->play
.name
, sizeof(sd
->play
.name
));
220 filename
[sizeof(SOUNDS_PATH
)+sizeof(sd
->play
.name
)] = '\0';
221 strcat(filename
+sizeof(SOUNDS_PATH
), SOUNDS_EXT
);
222 PLAY_FILE(filename
, sd
->func
==FUNC_BACKGND_MUSIC
? PLAY_BACKGROUND
: 0, id
);
228 bool isRepeatDelayElapsed(const CustomFunctionData
* functions
, CustomFunctionsContext
& functionsContext
, uint8_t index
)
230 const CustomFunctionData
* cfn
= &functions
[index
];
231 tmr10ms_t tmr10ms
= get_tmr10ms();
232 uint8_t repeatParam
= CFN_PLAY_REPEAT(cfn
);
233 if (!IS_SILENCE_PERIOD_ELAPSED() && repeatParam
== CFN_PLAY_REPEAT_NOSTART
) {
234 functionsContext
.lastFunctionTime
[index
] = tmr10ms
;
236 if (!functionsContext
.lastFunctionTime
[index
] || (repeatParam
&& repeatParam
!=CFN_PLAY_REPEAT_NOSTART
&& (signed)(tmr10ms
-functionsContext
.lastFunctionTime
[index
])>=100*repeatParam
)) {
237 functionsContext
.lastFunctionTime
[index
] = tmr10ms
;
245 #define isRepeatDelayElapsed(...) true
249 #define VOLUME_HYSTERESIS 10 // how much must a input value change to actually be considered for new volume setting
250 getvalue_t requiredSpeakerVolumeRawLast
= 1024 + 1; //initial value must be outside normal range
254 void evalFunctions(const CustomFunctionData
* functions
, CustomFunctionsContext
& functionsContext
)
256 #define functions g_model.customFn
257 #define functionsContext modelFunctionsContext
261 MASK_FUNC_TYPE newActiveFunctions
= 0;
262 MASK_CFN_TYPE newActiveSwitches
= 0;
265 uint8_t playFirstIndex
= (functions
== g_model
.customFn
? 1 : 1+MAX_SPECIAL_FUNCTIONS
);
266 #define PLAY_INDEX (i+playFirstIndex)
268 #define PLAY_INDEX (i+1)
271 #if defined(ROTARY_ENCODERS) && defined(GVARS)
272 static rotenc_t rePreviousValues
[ROTARY_ENCODERS
];
275 #if defined(OVERRIDE_CHANNEL_FUNCTION)
276 for (uint8_t i
=0; i
<MAX_OUTPUT_CHANNELS
; i
++) {
277 safetyCh
[i
] = OVERRIDE_CHANNEL_UNDEFINED
;
282 for (uint8_t i
=0; i
<NUM_TRIMS
; i
++) {
287 for (uint8_t i
=0; i
<MAX_SPECIAL_FUNCTIONS
; i
++) {
288 const CustomFunctionData
* cfn
= &functions
[i
];
289 swsrc_t swtch
= CFN_SWITCH(cfn
);
291 MASK_CFN_TYPE switch_mask
= ((MASK_CFN_TYPE
)1 << i
);
294 bool active
= getSwitch(swtch
, IS_PLAY_FUNC(CFN_FUNC(cfn
)) ? GETSWITCH_MIDPOS_DELAY
: 0);
296 bool active
= getSwitch(swtch
);
299 if (HAS_ENABLE_PARAM(CFN_FUNC(cfn
))) {
300 active
&= (bool)CFN_ACTIVE(cfn
);
303 if (active
|| IS_PLAY_BOTH_FUNC(CFN_FUNC(cfn
))) {
305 switch (CFN_FUNC(cfn
)) {
307 #if defined(OVERRIDE_CHANNEL_FUNCTION)
308 case FUNC_OVERRIDE_CHANNEL
:
309 safetyCh
[CFN_CH_INDEX(cfn
)] = CFN_PARAM(cfn
);
316 if (CFN_CH_INDEX(cfn
) > 0) {
317 mask
= (1<<(CFN_CH_INDEX(cfn
)-1));
319 newActiveFunctions
|= mask
;
323 case FUNC_INSTANT_TRIM
:
324 newActiveFunctions
|= (1 << FUNCTION_INSTANT_TRIM
);
325 if (!isFunctionActive(FUNCTION_INSTANT_TRIM
)) {
326 if (IS_INSTANT_TRIM_ALLOWED()) {
333 switch (CFN_PARAM(cfn
)) {
334 case FUNC_RESET_TIMER1
:
335 case FUNC_RESET_TIMER2
:
337 case FUNC_RESET_TIMER3
:
339 timerReset(CFN_PARAM(cfn
));
341 case FUNC_RESET_FLIGHT
:
342 if (!(functionsContext
.activeSwitches
& switch_mask
)) {
344 mainRequestFlags
|= (1 << REQUEST_FLIGHT_RESET
); // on systems with threads flightReset() must not be called from the mixers thread!
347 #endif // defined(CPUARM)
350 #if defined(TELEMETRY_FRSKY)
351 case FUNC_RESET_TELEMETRY
:
356 #if ROTARY_ENCODERS > 0
357 case FUNC_RESET_ROTENC1
:
358 #if ROTARY_ENCODERS > 1
359 case FUNC_RESET_ROTENC2
:
361 rotencValue
[CFN_PARAM(cfn
)-FUNC_RESET_ROTENC1
] = 0;
366 if (CFN_PARAM(cfn
)>=FUNC_RESET_PARAM_FIRST_TELEM
) {
367 uint8_t item
= CFN_PARAM(cfn
)-FUNC_RESET_PARAM_FIRST_TELEM
;
368 if (item
< MAX_TELEMETRY_SENSORS
) {
369 telemetryItems
[item
].clear();
377 timerSet(CFN_TIMER_INDEX(cfn
), CFN_PARAM(cfn
));
380 case FUNC_SET_FAILSAFE
:
382 setCustomFailsafe(CFN_PARAM(cfn
));
385 #if defined(DANGEROUS_MODULE_FUNCTIONS)
386 case FUNC_RANGECHECK
:
389 unsigned int moduleIndex
= CFN_PARAM(cfn
);
390 if (moduleIndex
< NUM_MODULES
) {
391 moduleFlag
[moduleIndex
] = 1 + CFN_FUNC(cfn
) - FUNC_RANGECHECK
;
396 #endif // defined(CPUARM)
399 case FUNC_ADJUST_GVAR
:
400 if (CFN_GVAR_MODE(cfn
) == FUNC_ADJUST_GVAR_CONSTANT
) {
401 SET_GVAR(CFN_GVAR_INDEX(cfn
), CFN_PARAM(cfn
), mixerCurrentFlightMode
);
403 else if (CFN_GVAR_MODE(cfn
) == FUNC_ADJUST_GVAR_GVAR
) {
404 SET_GVAR(CFN_GVAR_INDEX(cfn
), GVAR_VALUE(CFN_PARAM(cfn
), getGVarFlightMode(mixerCurrentFlightMode
, CFN_PARAM(cfn
))), mixerCurrentFlightMode
);
406 else if (CFN_GVAR_MODE(cfn
) == FUNC_ADJUST_GVAR_INCDEC
) {
407 if (!(functionsContext
.activeSwitches
& switch_mask
)) {
409 SET_GVAR(CFN_GVAR_INDEX(cfn
), limit
<int16_t>(MODEL_GVAR_MIN(CFN_GVAR_INDEX(cfn
)), GVAR_VALUE(CFN_GVAR_INDEX(cfn
), getGVarFlightMode(mixerCurrentFlightMode
, CFN_GVAR_INDEX(cfn
))) + CFN_PARAM(cfn
), MODEL_GVAR_MAX(CFN_GVAR_INDEX(cfn
))), mixerCurrentFlightMode
);
411 SET_GVAR(CFN_GVAR_INDEX(cfn
), GVAR_VALUE(CFN_GVAR_INDEX(cfn
), getGVarFlightMode(mixerCurrentFlightMode
, CFN_GVAR_INDEX(cfn
))) + (CFN_PARAM(cfn
) ? +1 : -1), mixerCurrentFlightMode
);
415 else if (CFN_PARAM(cfn
) >= MIXSRC_FIRST_TRIM
&& CFN_PARAM(cfn
) <= MIXSRC_LAST_TRIM
) {
416 trimGvar
[CFN_PARAM(cfn
)-MIXSRC_FIRST_TRIM
] = CFN_GVAR_INDEX(cfn
);
418 #if defined(ROTARY_ENCODERS)
419 else if (CFN_PARAM(cfn
) >= MIXSRC_REa
&& CFN_PARAM(cfn
) < MIXSRC_TrimRud
) {
420 int8_t scroll
= rePreviousValues
[CFN_PARAM(cfn
)-MIXSRC_REa
] - (rotencValue
[CFN_PARAM(cfn
)-MIXSRC_REa
] / ROTARY_ENCODER_GRANULARITY
);
423 SET_GVAR(CFN_GVAR_INDEX(cfn
), limit
<int16_t>(MODEL_GVAR_MIN(CFN_GVAR_INDEX(cfn
)), GVAR_VALUE(CFN_GVAR_INDEX(cfn
), getGVarFlightMode(mixerCurrentFlightMode
, CFN_GVAR_INDEX(cfn
))) + scroll
, MODEL_GVAR_MAX(CFN_GVAR_INDEX(cfn
))), mixerCurrentFlightMode
);
425 SET_GVAR(CFN_GVAR_INDEX(cfn
), GVAR_VALUE(CFN_GVAR_INDEX(cfn
), getGVarFlightMode(mixerCurrentFlightMode
, CFN_GVAR_INDEX(cfn
))) + scroll
, mixerCurrentFlightMode
);
432 SET_GVAR(CFN_GVAR_INDEX(cfn
), limit
<int16_t>(MODEL_GVAR_MIN(CFN_GVAR_INDEX(cfn
)), calcRESXto100(getValue(CFN_PARAM(cfn
))), MODEL_GVAR_MAX(CFN_GVAR_INDEX(cfn
))), mixerCurrentFlightMode
);
434 SET_GVAR(CFN_GVAR_INDEX(cfn
), calcRESXto100(getValue(CFN_PARAM(cfn
))), mixerCurrentFlightMode
);
440 #if defined(MASTER_VOLUME)
443 getvalue_t raw
= getValue(CFN_PARAM(cfn
));
444 // only set volume if input changed more than hysteresis
445 if (abs(requiredSpeakerVolumeRawLast
- raw
) > VOLUME_HYSTERESIS
) {
446 requiredSpeakerVolumeRawLast
= raw
;
448 requiredSpeakerVolume
= ((1024 + requiredSpeakerVolumeRawLast
) * VOLUME_LEVEL_MAX
) / 2048;
453 #if defined(CPUARM) && defined(SDCARD)
454 case FUNC_PLAY_SOUND
:
455 case FUNC_PLAY_TRACK
:
456 case FUNC_PLAY_VALUE
:
461 if (isRepeatDelayElapsed(functions
, functionsContext
, i
)) {
462 if (!IS_PLAYING(PLAY_INDEX
)) {
463 if (CFN_FUNC(cfn
) == FUNC_PLAY_SOUND
) {
464 if (audioQueue
.isEmpty()) {
465 AUDIO_PLAY(AU_SPECIAL_SOUND_FIRST
+ CFN_PARAM(cfn
));
468 else if (CFN_FUNC(cfn
) == FUNC_PLAY_VALUE
) {
469 PLAY_VALUE(CFN_PARAM(cfn
), PLAY_INDEX
);
472 else if (CFN_FUNC(cfn
) == FUNC_HAPTIC
) {
473 haptic
.event(AU_SPECIAL_SOUND_LAST
+CFN_PARAM(cfn
));
477 playCustomFunctionFile(cfn
, PLAY_INDEX
);
484 case FUNC_BACKGND_MUSIC
:
485 if (!(newActiveFunctions
& (1 << FUNCTION_BACKGND_MUSIC
))) {
486 newActiveFunctions
|= (1 << FUNCTION_BACKGND_MUSIC
);
487 if (!IS_PLAYING(PLAY_INDEX
)) {
488 playCustomFunctionFile(cfn
, PLAY_INDEX
);
493 case FUNC_BACKGND_MUSIC_PAUSE
:
494 newActiveFunctions
|= (1 << FUNCTION_BACKGND_MUSIC_PAUSE
);
498 case FUNC_PLAY_SOUND
:
499 case FUNC_PLAY_TRACK
:
501 case FUNC_PLAY_VALUE
:
503 tmr10ms_t tmr10ms
= get_tmr10ms();
504 uint8_t repeatParam
= CFN_PLAY_REPEAT(cfn
);
505 if (!functionsContext
.lastFunctionTime
[i
] || (CFN_FUNC(cfn
)==FUNC_PLAY_BOTH
&& active
!=(bool)(functionsContext
.activeSwitches
&switch_mask
)) || (repeatParam
&& (signed)(tmr10ms
-functionsContext
.lastFunctionTime
[i
])>=1000*repeatParam
)) {
506 functionsContext
.lastFunctionTime
[i
] = tmr10ms
;
507 uint8_t param
= CFN_PARAM(cfn
);
508 if (CFN_FUNC(cfn
) == FUNC_PLAY_SOUND
) {
509 AUDIO_PLAY(AU_SPECIAL_SOUND_FIRST
+param
);
511 else if (CFN_FUNC(cfn
) == FUNC_PLAY_VALUE
) {
512 PLAY_VALUE(param
, PLAY_INDEX
);
516 if (CFN_FUNC(cfn
) == FUNC_PLAY_TRACK
&& param
> 250)
517 param
= GVAR_VALUE(param
-251, getGVarFlightMode(mixerCurrentFlightMode
, param
-251));
519 PUSH_CUSTOM_PROMPT(active
? param
: param
+1, PLAY_INDEX
);
523 // PLAY_BOTH would change activeFnSwitches otherwise
529 case FUNC_PLAY_SOUND
:
531 tmr10ms_t tmr10ms
= get_tmr10ms();
532 uint8_t repeatParam
= CFN_PLAY_REPEAT(cfn
);
533 if (!functionsContext
.lastFunctionTime
[i
] || (repeatParam
&& (signed)(tmr10ms
-functionsContext
.lastFunctionTime
[i
])>=1000*repeatParam
)) {
534 functionsContext
.lastFunctionTime
[i
] = tmr10ms
;
535 AUDIO_PLAY(AU_SPECIAL_SOUND_FIRST
+CFN_PARAM(cfn
));
541 #if defined(TELEMETRY_FRSKY) && defined(VARIO)
543 newActiveFunctions
|= (1 << FUNCTION_VARIO
);
547 #if defined(HAPTIC) && !defined(CPUARM)
550 tmr10ms_t tmr10ms
= get_tmr10ms();
551 uint8_t repeatParam
= CFN_PLAY_REPEAT(cfn
);
552 if (!functionsContext
.lastFunctionTime
[i
] || (repeatParam
&& (signed)(tmr10ms
-functionsContext
.lastFunctionTime
[i
])>=1000*repeatParam
)) {
553 functionsContext
.lastFunctionTime
[i
] = tmr10ms
;
554 haptic
.event(AU_SPECIAL_SOUND_LAST
+CFN_PARAM(cfn
));
562 if (CFN_PARAM(cfn
)) {
563 newActiveFunctions
|= (1 << FUNCTION_LOGS
);
564 logDelay
= CFN_PARAM(cfn
);
570 newActiveFunctions
|= (1 << FUNCTION_BACKLIGHT
);
573 #if defined(PCBTARANIS)
574 case FUNC_SCREENSHOT
:
575 if (!(functionsContext
.activeSwitches
& switch_mask
)) {
576 mainRequestFlags
|= (1 << REQUEST_SCREENSHOT
);
588 newActiveSwitches
|= switch_mask
;
591 functionsContext
.lastFunctionTime
[i
] = 0;
592 #if defined(CPUARM) && defined(DANGEROUS_MODULE_FUNCTIONS)
593 if (functionsContext
.activeSwitches
& switch_mask
) {
594 switch (CFN_FUNC(cfn
)) {
595 case FUNC_RANGECHECK
:
598 unsigned int moduleIndex
= CFN_PARAM(cfn
);
599 if (moduleIndex
< NUM_MODULES
) {
600 moduleFlag
[moduleIndex
] = 0;
611 functionsContext
.activeSwitches
= newActiveSwitches
;
612 functionsContext
.activeFunctions
= newActiveFunctions
;
614 #if defined(ROTARY_ENCODERS) && defined(GVARS)
615 for (uint8_t i
=0; i
<ROTARY_ENCODERS
; i
++) {
616 rePreviousValues
[i
] = (rotencValue
[i
] / ROTARY_ENCODER_GRANULARITY
);
623 #undef functionsContext