x9e with horus bt module (#5214)
[opentx.git] / radio / src / tests / mixer.cpp
blob2f4e9ba86d5f4e39417c4cb97ea419768fa0438a
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
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.
21 #include "gtests.h"
23 class TrimsTest : public OpenTxTest {};
24 class MixerTest : public OpenTxTest {};
26 #define CHECK_NO_MOVEMENT(channel, value, duration) \
27 for (int i=1; i<=(duration); i++) { \
28 evalFlightModeMixes(e_perout_mode_normal, 1); \
29 GTEST_ASSERT_EQ((value), chans[(channel)]); \
32 #define CHECK_SLOW_MOVEMENT(channel, sign, duration) \
33 do { \
34 for (int i=1; i<=(duration); i++) { \
35 evalFlightModeMixes(e_perout_mode_normal, 1); \
36 lastAct = lastAct + (sign) * (1<<19)/500; /* 100 on ARM */ \
37 GTEST_ASSERT_EQ(256 * (lastAct >> 8), chans[(channel)]); \
38 } \
39 } while (0)
41 #define CHECK_DELAY(channel, duration) \
42 do { \
43 int32_t value = chans[(channel)]; \
44 for (int i=1; i<=(duration); i++) { \
45 evalFlightModeMixes(e_perout_mode_normal, 1); \
46 GTEST_ASSERT_EQ(chans[(channel)], value); \
47 } \
48 } while (0)
50 TEST_F(TrimsTest, throttleTrim)
52 g_model.thrTrim = 1;
53 // stick max + trim max
54 anaInValues[THR_STICK] = +1024;
55 setTrimValue(0, THR_STICK, TRIM_MAX);
56 evalMixes(1);
57 EXPECT_EQ(channelOutputs[2], 1024);
58 // stick max + trim min
59 anaInValues[THR_STICK] = +1024;
60 setTrimValue(0, THR_STICK, TRIM_MIN);
61 evalMixes(1);
62 EXPECT_EQ(channelOutputs[2], 1024);
63 // stick min + trim max
64 anaInValues[THR_STICK] = -1024;
65 setTrimValue(0, THR_STICK, TRIM_MAX);
66 evalMixes(1);
67 EXPECT_EQ(channelOutputs[2], -1024+500);
68 // stick min + trim mid
69 anaInValues[THR_STICK] = -1024;
70 setTrimValue(0, THR_STICK, 0);
71 evalMixes(1);
72 EXPECT_EQ(channelOutputs[2], -1024+250);
73 // stick min + trim min
74 anaInValues[THR_STICK] = -1024;
75 setTrimValue(0, THR_STICK, TRIM_MIN);
76 evalMixes(1);
77 EXPECT_EQ(channelOutputs[2], -1024);
79 // now the same tests with extended Trims
80 g_model.extendedTrims = 1;
81 // stick max + trim max
82 anaInValues[THR_STICK] = +1024;
83 setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX);
84 evalMixes(1);
85 EXPECT_EQ(channelOutputs[2], 1024);
86 // stick max + trim min
87 anaInValues[THR_STICK] = +1024;
88 setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN);
89 evalMixes(1);
90 EXPECT_EQ(channelOutputs[2], 1024);
91 // stick min + trim max
92 anaInValues[THR_STICK] = -1024;
93 setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX);
94 evalMixes(1);
95 EXPECT_EQ(channelOutputs[2], -1024+2000);
96 // stick min + trim mid
97 anaInValues[THR_STICK] = -1024;
98 setTrimValue(0, THR_STICK, 0);
99 evalMixes(1);
100 EXPECT_EQ(channelOutputs[2], -1024+1000);
101 // stick min + trim min
102 anaInValues[THR_STICK] = -1024;
103 setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN);
104 evalMixes(1);
105 EXPECT_EQ(channelOutputs[2], -1024);
109 TEST_F(TrimsTest, invertedThrottlePlusThrottleTrim)
111 g_model.throttleReversed = 1;
112 g_model.thrTrim = 1;
113 // stick max + trim max
114 anaInValues[THR_STICK] = +1024;
115 setTrimValue(0, THR_STICK, TRIM_MAX);
116 evalMixes(1);
117 EXPECT_EQ(channelOutputs[2], -1024);
118 // stick max + trim mid
119 anaInValues[THR_STICK] = +1024;
120 setTrimValue(0, THR_STICK, 0);
121 evalMixes(1);
122 EXPECT_EQ(channelOutputs[2], -1024+250);
123 // stick max + trim min
124 anaInValues[THR_STICK] = +1024;
125 setTrimValue(0, THR_STICK, TRIM_MIN);
126 evalMixes(1);
127 EXPECT_EQ(channelOutputs[2], -1024+500);
128 // stick min + trim max
129 anaInValues[THR_STICK] = -1024;
130 setTrimValue(0, THR_STICK, TRIM_MAX);
131 evalMixes(1);
132 EXPECT_EQ(channelOutputs[2], +1024);
133 // stick min + trim min
134 anaInValues[THR_STICK] = -1024;
135 setTrimValue(0, THR_STICK, TRIM_MIN);
136 evalMixes(1);
137 EXPECT_EQ(channelOutputs[2], +1024);
139 // now the same tests with extended Trims
140 g_model.extendedTrims = 1;
141 // stick max + trim max
142 anaInValues[THR_STICK] = +1024;
143 setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX);
144 evalMixes(1);
145 EXPECT_EQ(channelOutputs[2], -1024);
146 // stick max + trim mid
147 anaInValues[THR_STICK] = +1024;
148 setTrimValue(0, THR_STICK, 0);
149 evalMixes(1);
150 EXPECT_EQ(channelOutputs[2], -1024+1000);
151 // stick max + trim min
152 anaInValues[THR_STICK] = +1024;
153 setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN);
154 evalMixes(1);
155 EXPECT_EQ(channelOutputs[2], -1024+2000);
156 // stick min + trim max
157 anaInValues[THR_STICK] = -1024;
158 setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX);
159 evalMixes(1);
160 EXPECT_EQ(channelOutputs[2], +1024);
161 // stick min + trim min
162 anaInValues[THR_STICK] = -1024;
163 setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN);
164 evalMixes(1);
165 EXPECT_EQ(channelOutputs[2], +1024);
168 TEST_F(TrimsTest, throttleTrimWithZeroWeightOnThrottle)
170 g_model.thrTrim = 1;
171 #if defined(VIRTUAL_INPUTS)
172 // the input already exists
173 ExpoData *expo = expoAddress(THR_STICK);
174 #else
175 ExpoData *expo = expoAddress(0);
176 expo->mode = 3;
177 expo->chn = THR_STICK;
178 #endif
179 expo->weight = 0;
180 // stick max + trim max
181 anaInValues[THR_STICK] = +1024;
182 setTrimValue(0, THR_STICK, TRIM_MAX);
183 evalMixes(1);
184 EXPECT_EQ(channelOutputs[2], 250);
185 // stick max + trim mid
186 anaInValues[THR_STICK] = +1024;
187 setTrimValue(0, THR_STICK, 0);
188 evalMixes(1);
189 EXPECT_LE(abs(channelOutputs[2] - 125), 1); //can't use precise comparison here because of lower precision math on 9X
190 // stick max + trim min
191 anaInValues[THR_STICK] = +1024;
192 setTrimValue(0, THR_STICK, TRIM_MIN);
193 evalMixes(1);
194 EXPECT_EQ(channelOutputs[2], 0);
195 // stick min + trim max
196 anaInValues[THR_STICK] = -1024;
197 setTrimValue(0, THR_STICK, TRIM_MAX);
198 evalMixes(1);
199 EXPECT_EQ(channelOutputs[2], 250);
200 // stick min + trim mid
201 anaInValues[THR_STICK] = -1024;
202 setTrimValue(0, THR_STICK, 0);
203 evalMixes(1);
204 EXPECT_LE(abs(channelOutputs[2] - 125), 1);
205 // stick min + trim min
206 anaInValues[THR_STICK] = -1024;
207 setTrimValue(0, THR_STICK, TRIM_MIN);
208 evalMixes(1);
209 EXPECT_EQ(channelOutputs[2], 0);
211 // now some tests with extended Trims
212 g_model.extendedTrims = 1;
213 // trim min + various stick positions = should always be same value
214 setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN);
215 anaInValues[THR_STICK] = -1024;
216 evalMixes(1);
217 EXPECT_EQ(channelOutputs[2], 0);
218 anaInValues[THR_STICK] = -300;
219 evalMixes(1);
220 EXPECT_EQ(channelOutputs[2], 0);
221 anaInValues[THR_STICK] = +300;
222 evalMixes(1);
223 EXPECT_EQ(channelOutputs[2], 0);
224 anaInValues[THR_STICK] = +1024;
225 evalMixes(1);
226 EXPECT_EQ(channelOutputs[2], 0);
228 // trim max + various stick positions = should always be same value
229 setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX);
230 anaInValues[THR_STICK] = -1024;
231 evalMixes(1);
232 EXPECT_EQ(channelOutputs[2], 1000);
233 anaInValues[THR_STICK] = -300;
234 evalMixes(1);
235 EXPECT_EQ(channelOutputs[2], 1000);
236 anaInValues[THR_STICK] = +300;
237 evalMixes(1);
238 EXPECT_EQ(channelOutputs[2], 1000);
239 anaInValues[THR_STICK] = +1024;
240 evalMixes(1);
241 EXPECT_EQ(channelOutputs[2], 1000);
244 TEST_F(TrimsTest, invertedThrottlePlusthrottleTrimWithZeroWeightOnThrottle)
246 g_model.throttleReversed = 1;
247 g_model.thrTrim = 1;
248 #if defined(VIRTUAL_INPUTS)
249 // the input already exists
250 ExpoData *expo = expoAddress(THR_STICK);
251 #else
252 ExpoData *expo = expoAddress(0);
253 expo->mode = 3;
254 expo->chn = THR_STICK;
255 #endif
256 expo->weight = 0;
257 // stick max + trim max
258 anaInValues[THR_STICK] = +1024;
259 setTrimValue(0, THR_STICK, TRIM_MAX);
260 evalMixes(1);
261 EXPECT_EQ(channelOutputs[2], 0);
262 // stick max + trim mid
263 anaInValues[THR_STICK] = +1024;
264 setTrimValue(0, THR_STICK, 0);
265 evalMixes(1);
266 EXPECT_LE(abs(channelOutputs[2] - 125), 1);
267 // stick max + trim min
268 anaInValues[THR_STICK] = +1024;
269 setTrimValue(0, THR_STICK, TRIM_MIN);
270 evalMixes(1);
271 EXPECT_EQ(channelOutputs[2], 250);
272 // stick min + trim max
273 anaInValues[THR_STICK] = -1024;
274 setTrimValue(0, THR_STICK, TRIM_MAX);
275 evalMixes(1);
276 EXPECT_EQ(channelOutputs[2], 0);
277 // stick min + trim mid
278 anaInValues[THR_STICK] = -1024;
279 setTrimValue(0, THR_STICK, 0);
280 evalMixes(1);
281 EXPECT_LE(abs(channelOutputs[2] - 125), 1);
282 // stick min + trim min
283 anaInValues[THR_STICK] = -1024;
284 setTrimValue(0, THR_STICK, TRIM_MIN);
285 evalMixes(1);
286 EXPECT_EQ(channelOutputs[2], 250);
288 // now some tests with extended Trims
289 g_model.extendedTrims = 1;
290 // trim min + various stick positions = should always be same value
291 setTrimValue(0, THR_STICK, TRIM_EXTENDED_MIN);
292 anaInValues[THR_STICK] = -1024;
293 evalMixes(1);
294 EXPECT_EQ(channelOutputs[2], 1000);
295 anaInValues[THR_STICK] = -300;
296 evalMixes(1);
297 EXPECT_EQ(channelOutputs[2], 1000);
298 anaInValues[THR_STICK] = +300;
299 evalMixes(1);
300 EXPECT_EQ(channelOutputs[2], 1000);
301 anaInValues[THR_STICK] = +1024;
302 evalMixes(1);
303 EXPECT_EQ(channelOutputs[2], 1000);
305 // trim max + various stick positions = should always be same value
306 setTrimValue(0, THR_STICK, TRIM_EXTENDED_MAX);
307 anaInValues[THR_STICK] = -1024;
308 evalMixes(1);
309 EXPECT_EQ(channelOutputs[2], 0);
310 anaInValues[THR_STICK] = -300;
311 evalMixes(1);
312 EXPECT_EQ(channelOutputs[2], 0);
313 anaInValues[THR_STICK] = +300;
314 evalMixes(1);
315 EXPECT_EQ(channelOutputs[2], 0);
316 anaInValues[THR_STICK] = +1024;
317 evalMixes(1);
318 EXPECT_EQ(channelOutputs[2], 0);
321 #if !defined(VIRTUAL_INPUTS)
322 TEST_F(TrimsTest, greaterTrimLink)
324 setTrimValue(1, RUD_STICK, TRIM_EXTENDED_MAX+3); // link to FP3 trim
325 setTrimValue(3, RUD_STICK, 32);
326 EXPECT_EQ(getRawTrimValue(getTrimFlightMode(1, RUD_STICK), RUD_STICK), 32);
329 TEST_F(TrimsTest, chainedTrims)
331 setTrimValue(0, RUD_STICK, 32);
332 setTrimValue(1, RUD_STICK, TRIM_EXTENDED_MAX+1); // link to FP0 trim
333 setTrimValue(2, RUD_STICK, TRIM_EXTENDED_MAX+2); // link to FP1 trim
334 EXPECT_EQ(getRawTrimValue(getTrimFlightMode(0, RUD_STICK), RUD_STICK), 32);
337 TEST_F(TrimsTest, infiniteChainedTrims)
339 setTrimValue(0, RUD_STICK, 32);
340 setTrimValue(1, RUD_STICK, TRIM_EXTENDED_MAX+3); // link to FP3 trim
341 setTrimValue(2, RUD_STICK, TRIM_EXTENDED_MAX+2); // link to FP1 trim
342 setTrimValue(3, RUD_STICK, TRIM_EXTENDED_MAX+3); // link to FP2 trim
343 EXPECT_EQ(getRawTrimValue(getTrimFlightMode(0, RUD_STICK), RUD_STICK), 32);
345 #endif
347 TEST_F(TrimsTest, CopyTrimsToOffset)
349 setTrimValue(0, ELE_STICK, -100); // -100 on elevator
350 #if defined(CPUARM)
351 evalFunctions(g_model.customFn, modelFunctionsContext); // it disables all safety channels
352 copyTrimsToOffset(1);
353 EXPECT_EQ(getTrimValue(0, ELE_STICK), -100); // unchanged
354 EXPECT_EQ(g_model.limitData[1].offset, -195);
355 #else
356 evalFunctions(); // it disables all safety channels
357 copyTrimsToOffset(1);
358 EXPECT_EQ(getTrimValue(0, ELE_STICK), -100); // unchanged
359 EXPECT_EQ(g_model.limitData[1].offset, -200);
360 #endif
363 TEST_F(TrimsTest, CopySticksToOffset)
365 anaInValues[ELE_STICK] = -100;
366 evalMixes(1);
367 copySticksToOffset(1);
368 EXPECT_EQ(g_model.limitData[1].offset, -97);
371 TEST_F(TrimsTest, InstantTrim)
373 anaInValues[AIL_STICK] = 50;
374 instantTrim();
375 EXPECT_EQ(25, getTrimValue(0, AIL_STICK));
378 #if defined(VIRTUAL_INPUTS)
379 TEST_F(TrimsTest, InstantTrimNegativeCurve)
381 ExpoData *expo = expoAddress(AIL_STICK);
382 expo->curve.type = CURVE_REF_CUSTOM;
383 expo->curve.value = 1;
384 g_model.points[0] = -100;
385 g_model.points[1] = -75;
386 g_model.points[2] = -50;
387 g_model.points[3] = -25;
388 g_model.points[4] = 0;
389 anaInValues[AIL_STICK] = 512;
390 instantTrim();
391 EXPECT_EQ(128, getTrimValue(0, AIL_STICK));
393 #endif
395 TEST(Curves, LinearIntpol)
397 SYSTEM_RESET();
398 MODEL_RESET();
399 MIXER_RESET();
400 modelDefault(0);
401 for (int8_t i=-2; i<=2; i++) {
402 g_model.points[2+i] = 50*i;
404 EXPECT_EQ(applyCustomCurve(-1024, 0), -1024);
405 EXPECT_EQ(applyCustomCurve(0, 0), 0);
406 EXPECT_EQ(applyCustomCurve(1024, 0), 1024);
407 EXPECT_EQ(applyCustomCurve(-192, 0), -192);
411 #if !defined(CPUARM)
412 TEST(FlightModes, nullFadeOut_posFadeIn)
414 SYSTEM_RESET();
415 MODEL_RESET();
416 MIXER_RESET();
417 modelDefault(0);
418 lastFlightMode = 255;
419 simuSetSwitch(3, 1);
420 g_model.flightModeData[1].swtch = SWSRC_ID1;
421 g_model.flightModeData[1].fadeIn = 15;
422 evalMixes(1);
423 simuSetSwitch(3, 0);
424 evalMixes(1);
425 // run mixes enough time to fade out flight modes (otherwise the mixer internal state flightModesFade could affect other tests)
426 simuSetSwitch(3, 1);
427 for(int n=0; n<200; n++) {
428 evalMixes(1);
432 TEST_F(MixerTest, R2029Comment)
434 SYSTEM_RESET();
435 MODEL_RESET();
436 MIXER_RESET();
437 modelDefault(0);
438 g_model.mixData[0].destCh = 0;
439 g_model.mixData[0].srcRaw = MIXSRC_CH2;
440 g_model.mixData[0].swtch = -SWSRC_THR;
441 g_model.mixData[0].weight = 100;
442 g_model.mixData[1].destCh = 1;
443 g_model.mixData[1].srcRaw = MIXSRC_Thr;
444 g_model.mixData[1].swtch = SWSRC_THR;
445 g_model.mixData[1].weight = 100;
446 anaInValues[THR_STICK] = 1024;
447 simuSetSwitch(0, 1);
448 evalFlightModeMixes(e_perout_mode_normal, 0);
449 EXPECT_EQ(chans[0], 0);
450 EXPECT_EQ(chans[1], CHANNEL_MAX);
451 simuSetSwitch(0, 0);
452 evalFlightModeMixes(e_perout_mode_normal, 0);
453 EXPECT_EQ(chans[0], 0);
454 EXPECT_EQ(chans[1], 0);
455 simuSetSwitch(0, 1);
456 evalFlightModeMixes(e_perout_mode_normal, 0);
457 EXPECT_EQ(chans[0], 0);
458 EXPECT_EQ(chans[1], CHANNEL_MAX);
461 TEST_F(MixerTest, Cascaded3Channels)
463 SYSTEM_RESET();
464 MODEL_RESET();
465 MIXER_RESET();
466 modelDefault(0);
467 g_model.mixData[0].destCh = 0;
468 g_model.mixData[0].srcRaw = MIXSRC_CH2;
469 g_model.mixData[0].weight = 100;
470 g_model.mixData[1].destCh = 1;
471 g_model.mixData[1].srcRaw = MIXSRC_CH3;
472 g_model.mixData[1].weight = 100;
473 g_model.mixData[2].destCh = 2;
474 g_model.mixData[2].srcRaw = MIXSRC_THR;
475 g_model.mixData[2].weight = 100;
476 simuSetSwitch(0, 1);
477 evalFlightModeMixes(e_perout_mode_normal, 0);
478 EXPECT_EQ(chans[0], CHANNEL_MAX);
479 EXPECT_EQ(chans[1], CHANNEL_MAX);
480 EXPECT_EQ(chans[2], CHANNEL_MAX);
483 TEST_F(MixerTest, CascadedOrderedChannels)
485 g_model.mixData[0].destCh = 0;
486 g_model.mixData[0].srcRaw = MIXSRC_THR;
487 g_model.mixData[0].weight = 100;
488 g_model.mixData[1].destCh = 1;
489 g_model.mixData[1].srcRaw = MIXSRC_CH1;
490 g_model.mixData[1].weight = 100;
491 simuSetSwitch(0, 1);
492 evalFlightModeMixes(e_perout_mode_normal, 0);
493 EXPECT_EQ(chans[0], CHANNEL_MAX);
494 EXPECT_EQ(chans[1], CHANNEL_MAX);
497 TEST_F(MixerTest, Cascaded5Channels)
499 g_model.mixData[0].destCh = 0;
500 g_model.mixData[0].srcRaw = MIXSRC_CH2;
501 g_model.mixData[0].weight = 100;
502 g_model.mixData[1].destCh = 1;
503 g_model.mixData[1].srcRaw = MIXSRC_CH3;
504 g_model.mixData[1].weight = 100;
505 g_model.mixData[2].destCh = 2;
506 g_model.mixData[2].srcRaw = MIXSRC_CH4;
507 g_model.mixData[2].weight = 100;
508 g_model.mixData[3].destCh = 3;
509 g_model.mixData[3].srcRaw = MIXSRC_CH5;
510 g_model.mixData[3].weight = 100;
511 g_model.mixData[4].destCh = 4;
512 g_model.mixData[4].srcRaw = MIXSRC_THR;
513 g_model.mixData[4].weight = 100;
514 for (uint8_t i=0; i<10; i++) {
515 simuSetSwitch(0, 1);
516 evalMixes(1);
517 EXPECT_EQ(chans[0], CHANNEL_MAX);
518 EXPECT_EQ(chans[1], CHANNEL_MAX);
519 EXPECT_EQ(chans[2], CHANNEL_MAX);
520 EXPECT_EQ(chans[3], CHANNEL_MAX);
521 EXPECT_EQ(chans[4], CHANNEL_MAX);
522 simuSetSwitch(0, 0);
523 evalMixes(1);
524 EXPECT_EQ(chans[0], -CHANNEL_MAX);
525 EXPECT_EQ(chans[1], -CHANNEL_MAX);
526 EXPECT_EQ(chans[2], -CHANNEL_MAX);
527 EXPECT_EQ(chans[3], -CHANNEL_MAX);
528 EXPECT_EQ(chans[4], -CHANNEL_MAX);
531 #endif
533 TEST_F(MixerTest, InfiniteRecursiveChannels)
535 g_model.mixData[0].destCh = 0;
536 g_model.mixData[0].srcRaw = MIXSRC_CH2;
537 g_model.mixData[0].weight = 100;
538 g_model.mixData[1].destCh = 1;
539 g_model.mixData[1].srcRaw = MIXSRC_CH3;
540 g_model.mixData[1].weight = 100;
541 g_model.mixData[2].destCh = 2;
542 g_model.mixData[2].srcRaw = MIXSRC_CH1;
543 g_model.mixData[2].weight = 100;
544 evalFlightModeMixes(e_perout_mode_normal, 0);
545 EXPECT_EQ(chans[2], 0);
546 EXPECT_EQ(chans[1], 0);
547 EXPECT_EQ(chans[0], 0);
550 TEST_F(MixerTest, BlockingChannel)
552 g_model.mixData[0].destCh = 0;
553 g_model.mixData[0].srcRaw = MIXSRC_CH1;
554 g_model.mixData[0].weight = 100;
555 evalFlightModeMixes(e_perout_mode_normal, 0);
556 EXPECT_EQ(chans[0], 0);
559 TEST_F(MixerTest, RecursiveAddChannel)
561 g_model.mixData[0].destCh = 0;
562 g_model.mixData[0].mltpx = MLTPX_ADD;
563 g_model.mixData[0].srcRaw = MIXSRC_MAX;
564 g_model.mixData[0].weight = 50;
565 g_model.mixData[1].destCh = 0;
566 g_model.mixData[1].mltpx = MLTPX_ADD;
567 g_model.mixData[1].srcRaw = MIXSRC_CH2;
568 g_model.mixData[1].weight = 100;
569 g_model.mixData[2].destCh = 1;
570 g_model.mixData[2].srcRaw = MIXSRC_Rud;
571 g_model.mixData[2].weight = 100;
572 evalFlightModeMixes(e_perout_mode_normal, 0);
573 EXPECT_EQ(chans[0], CHANNEL_MAX/2);
574 EXPECT_EQ(chans[1], 0);
577 TEST_F(MixerTest, RecursiveAddChannelAfterInactivePhase)
579 g_model.flightModeData[1].swtch = SWSRC_ID1;
580 g_model.mixData[0].destCh = 0;
581 g_model.mixData[0].mltpx = MLTPX_ADD;
582 g_model.mixData[0].srcRaw = MIXSRC_CH2;
583 g_model.mixData[0].flightModes = 0b11110;
584 g_model.mixData[0].weight = 50;
585 g_model.mixData[1].destCh = 0;
586 g_model.mixData[1].mltpx = MLTPX_ADD;
587 g_model.mixData[1].srcRaw = MIXSRC_MAX;
588 g_model.mixData[1].flightModes = 0b11101;
589 g_model.mixData[1].weight = 50;
590 g_model.mixData[2].destCh = 1;
591 g_model.mixData[2].srcRaw = MIXSRC_MAX;
592 g_model.mixData[2].weight = 100;
593 simuSetSwitch(3, -1);
594 evalMixes(1);
595 EXPECT_EQ(chans[0], CHANNEL_MAX/2);
596 EXPECT_EQ(chans[1], CHANNEL_MAX);
597 simuSetSwitch(3, 0);
598 evalMixes(1);
599 EXPECT_EQ(chans[0], CHANNEL_MAX/2);
600 EXPECT_EQ(chans[1], CHANNEL_MAX);
603 #if !defined(CPUARM)
604 TEST_F(MixerTest, SlowOnSwitch)
606 g_model.mixData[0].destCh = 0;
607 g_model.mixData[0].mltpx = MLTPX_ADD;
608 g_model.mixData[0].srcRaw = MIXSRC_MAX;
609 g_model.mixData[0].weight = 100;
610 g_model.mixData[0].swtch = SWSRC_THR;
611 g_model.mixData[0].speedUp = SLOW_STEP*5;
612 g_model.mixData[0].speedDown = SLOW_STEP*5;
614 s_mixer_first_run_done = true;
616 evalFlightModeMixes(e_perout_mode_normal, 0);
617 EXPECT_EQ(chans[0], 0);
619 simuSetSwitch(0, 1);
620 CHECK_SLOW_MOVEMENT(0, +1, 250);
622 simuSetSwitch(0, -1);
623 CHECK_SLOW_MOVEMENT(0, -1, 250);
626 TEST_F(MixerTest, SlowUpOnSwitch)
628 g_model.mixData[0].destCh = 0;
629 g_model.mixData[0].mltpx = MLTPX_ADD;
630 g_model.mixData[0].srcRaw = MIXSRC_MAX;
631 g_model.mixData[0].weight = 100;
632 g_model.mixData[0].swtch = SWSRC_THR;
633 g_model.mixData[0].speedUp = SLOW_STEP*5;
634 g_model.mixData[0].speedDown = 0;
636 simuSetSwitch(0, 0);
637 evalFlightModeMixes(e_perout_mode_normal, 0);
638 s_mixer_first_run_done = true;
639 EXPECT_EQ(chans[0], 0);
641 simuSetSwitch(0, 1);
642 CHECK_SLOW_MOVEMENT(0, +1, 250);
644 simuSetSwitch(0, 0);
645 evalFlightModeMixes(e_perout_mode_normal, 1);
646 EXPECT_EQ(chans[0], 0);
648 lastAct = 0;
649 simuSetSwitch(0, 1);
650 CHECK_SLOW_MOVEMENT(0, +1, 100);
652 #endif
654 TEST_F(MixerTest, SlowOnPhase)
656 g_model.flightModeData[1].swtch = TR(SWSRC_THR, SWSRC_SA0);
657 g_model.mixData[0].destCh = 0;
658 g_model.mixData[0].mltpx = MLTPX_ADD;
659 g_model.mixData[0].srcRaw = MIXSRC_MAX;
660 g_model.mixData[0].weight = 100;
661 g_model.mixData[0].flightModes = 0x2 + 0x4 + 0x8 + 0x10 /*only enabled in phase 0*/;
662 g_model.mixData[0].speedUp = SLOW_STEP*5;
663 g_model.mixData[0].speedDown = SLOW_STEP*5;
665 s_mixer_first_run_done = true;
666 mixerCurrentFlightMode = 0;
667 evalFlightModeMixes(e_perout_mode_normal, 0);
668 EXPECT_EQ(chans[0], 0);
670 CHECK_SLOW_MOVEMENT(0, +1, 250);
672 mixerCurrentFlightMode = 1;
673 CHECK_SLOW_MOVEMENT(0, -1, 250);
676 #if !defined(CPUARM)
677 TEST_F(MixerTest, SlowOnSwitchAndPhase)
679 g_model.flightModeData[1].swtch = TR(SWSRC_THR, SWSRC_SA0);
680 g_model.mixData[0].destCh = 0;
681 g_model.mixData[0].mltpx = MLTPX_ADD;
682 g_model.mixData[0].srcRaw = MIXSRC_MAX;
683 g_model.mixData[0].weight = 100;
684 g_model.mixData[0].swtch = TR(SWSRC_THR, SWSRC_SA0);
685 #if defined(CPUARM)
686 g_model.mixData[0].flightModes = 0x2 + 0x4 + 0x8 + 0x10 + 0x20 + 0x40 + 0x80 + 0x100 /*only enabled in phase 0*/;
687 #else
688 g_model.mixData[0].flightModes = 0x2 + 0x4 + 0x8 + 0x10 /*only enabled in phase 0*/;
689 #endif
690 g_model.mixData[0].speedUp = SLOW_STEP*5;
691 g_model.mixData[0].speedDown = SLOW_STEP*5;
693 s_mixer_first_run_done = true;
694 evalFlightModeMixes(e_perout_mode_normal, 0);
695 EXPECT_EQ(chans[0], 0);
697 simuSetSwitch(0, 1);
698 mixerCurrentFlightMode = 0;
699 CHECK_SLOW_MOVEMENT(0, +1, 250);
701 simuSetSwitch(0, -1);
702 mixerCurrentFlightMode = 1;
703 CHECK_SLOW_MOVEMENT(0, -1, 250);
705 #endif
707 TEST_F(MixerTest, SlowOnSwitchSource)
709 g_model.mixData[0].destCh = 0;
710 g_model.mixData[0].mltpx = MLTPX_ADD;
711 #if defined(PCBTARANIS) || defined(PCBHORUS)
712 g_model.mixData[0].srcRaw = MIXSRC_SA;
713 #else
714 g_model.mixData[0].srcRaw = MIXSRC_THR;
715 #endif
716 g_model.mixData[0].weight = 100;
717 g_model.mixData[0].speedUp = SLOW_STEP*5;
718 g_model.mixData[0].speedDown = SLOW_STEP*5;
719 #if defined(PCBTARANIS) || defined(PCBHORUS)
720 g_eeGeneral.switchConfig = 0x03;
721 #endif
723 s_mixer_first_run_done = true;
725 simuSetSwitch(0, -1);
726 CHECK_SLOW_MOVEMENT(0, -1, 250);
727 EXPECT_EQ(chans[0], -CHANNEL_MAX);
729 simuSetSwitch(0, 1);
730 CHECK_SLOW_MOVEMENT(0, +1, 500);
733 TEST_F(MixerTest, SlowDisabledOnStartup)
735 g_model.mixData[0].destCh = 0;
736 g_model.mixData[0].mltpx = MLTPX_ADD;
737 g_model.mixData[0].srcRaw = MIXSRC_MAX;
738 g_model.mixData[0].weight = 100;
739 g_model.mixData[0].speedUp = SLOW_STEP*5;
740 g_model.mixData[0].speedDown = SLOW_STEP*5;
742 evalFlightModeMixes(e_perout_mode_normal, 0);
743 EXPECT_EQ(chans[0], CHANNEL_MAX);
746 TEST_F(MixerTest, DelayOnSwitch)
748 g_model.mixData[0].destCh = 0;
749 g_model.mixData[0].mltpx = MLTPX_ADD;
750 g_model.mixData[0].srcRaw = MIXSRC_MAX;
751 g_model.mixData[0].weight = 100;
752 #if defined(PCBTARANIS) || defined(PCBHORUS)
753 g_model.mixData[0].swtch = SWSRC_SA2;
754 #else
755 g_model.mixData[0].swtch = SWSRC_THR;
756 #endif
757 g_model.mixData[0].delayUp = DELAY_STEP*5;
758 g_model.mixData[0].delayDown = DELAY_STEP*5;
760 evalFlightModeMixes(e_perout_mode_normal, 0);
761 EXPECT_EQ(chans[0], 0);
763 simuSetSwitch(0, 1);
764 CHECK_DELAY(0, 500);
766 evalFlightModeMixes(e_perout_mode_normal, 1);
767 EXPECT_EQ(chans[0], CHANNEL_MAX);
769 simuSetSwitch(0, 0);
770 CHECK_DELAY(0, 500);
772 evalFlightModeMixes(e_perout_mode_normal, 1);
773 EXPECT_EQ(chans[0], 0);
776 #if !defined(CPUARM)
777 TEST_F(MixerTest, SlowAndDelayOnReplace3POSSource)
779 g_model.mixData[0].destCh = 0;
780 g_model.mixData[0].mltpx = MLTPX_REP;
781 g_model.mixData[0].srcRaw = MIXSRC_3POS;
782 g_model.mixData[0].weight = 100;
783 g_model.mixData[0].delayUp = 10;
784 g_model.mixData[0].speedUp = SLOW_STEP*5;
785 g_model.mixData[0].speedDown = SLOW_STEP*5;
787 s_mixer_first_run_done = true;
789 simuSetSwitch(3, -1);
790 CHECK_SLOW_MOVEMENT(0, -1, 250);
791 EXPECT_EQ(chans[0], -CHANNEL_MAX);
793 simuSetSwitch(3, 0);
794 CHECK_DELAY(0, 500);
795 CHECK_SLOW_MOVEMENT(0, +1, 250/*half course*/);
796 EXPECT_EQ(chans[0], 0);
798 simuSetSwitch(3, 1);
799 CHECK_DELAY(0, 500);
800 CHECK_SLOW_MOVEMENT(0, +1, 250);
802 #endif
804 #if !defined(CPUARM)
805 TEST_F(MixerTest, SlowOnSwitchReplace)
807 g_model.mixData[0].destCh = 0;
808 g_model.mixData[0].mltpx = MLTPX_ADD;
809 g_model.mixData[0].srcRaw = MIXSRC_MAX;
810 g_model.mixData[0].weight = 50;
811 g_model.mixData[1].destCh = 0;
812 g_model.mixData[1].mltpx = MLTPX_REP;
813 g_model.mixData[1].srcRaw = MIXSRC_MAX;
814 g_model.mixData[1].weight = 100;
815 g_model.mixData[1].swtch = SWSRC_THR;
816 g_model.mixData[1].speedDown = SLOW_STEP*5;
818 simuSetSwitch(0, 0);
819 evalFlightModeMixes(e_perout_mode_normal, 1);
820 EXPECT_EQ(chans[0], CHANNEL_MAX/2);
822 simuSetSwitch(0, 1);
823 evalFlightModeMixes(e_perout_mode_normal, 1);
824 // slow is not applied, but it's better than the first mix not applied at all!
825 EXPECT_EQ(chans[0], CHANNEL_MAX);
827 simuSetSwitch(0, 0);
828 evalFlightModeMixes(e_perout_mode_normal, 1);
829 // slow is not applied, but it's better than the first mix not applied at all!
830 EXPECT_EQ(chans[0], CHANNEL_MAX/2);
832 #endif
834 #if !defined(VIRTUAL_INPUTS)
835 TEST_F(MixerTest, NoTrimOnInactiveMix)
837 g_model.mixData[0].destCh = 0;
838 g_model.mixData[0].mltpx = MLTPX_ADD;
839 g_model.mixData[0].srcRaw = MIXSRC_Thr;
840 g_model.mixData[0].weight = 100;
841 g_model.mixData[0].swtch = SWSRC_THR;
842 g_model.mixData[0].speedUp = SLOW_STEP*5;
843 g_model.mixData[0].speedDown = SLOW_STEP*5;
844 setTrimValue(0, 2, 256);
846 s_mixer_first_run_done = true;
848 simuSetSwitch(0, 1);
849 CHECK_SLOW_MOVEMENT(0, 1, 100);
851 simuSetSwitch(0, -1);
852 CHECK_SLOW_MOVEMENT(0, -1, 100);
854 #endif
856 TEST_F(MixerTest, SlowOnMultiply)
858 g_model.mixData[0].destCh = 0;
859 g_model.mixData[0].mltpx = MLTPX_ADD;
860 g_model.mixData[0].srcRaw = MIXSRC_MAX;
861 g_model.mixData[0].weight = 100;
862 g_model.mixData[1].destCh = 0;
863 g_model.mixData[1].mltpx = MLTPX_MUL;
864 g_model.mixData[1].srcRaw = MIXSRC_MAX;
865 g_model.mixData[1].weight = 100;
866 g_model.mixData[1].swtch = TR(SWSRC_THR, SWSRC_SA0);
867 g_model.mixData[1].speedUp = SLOW_STEP*5;
868 g_model.mixData[1].speedDown = SLOW_STEP*5;
870 s_mixer_first_run_done = true;
872 simuSetSwitch(0, 1);
873 CHECK_SLOW_MOVEMENT(0, 1, 250);
875 simuSetSwitch(0, -1);
876 CHECK_NO_MOVEMENT(0, CHANNEL_MAX, 250);
878 simuSetSwitch(0, 1);
879 CHECK_NO_MOVEMENT(0, CHANNEL_MAX, 250);
883 #if defined(HELI) && defined(VIRTUAL_INPUTS)
884 TEST(Heli, BasicTest)
886 SYSTEM_RESET();
887 MODEL_RESET();
888 MIXER_RESET();
889 modelDefault(0);
890 g_model.swashR.collectiveSource = MIXSRC_Thr;
891 g_model.swashR.elevatorSource = MIXSRC_Ele;
892 g_model.swashR.aileronSource = MIXSRC_Ail;
893 g_model.swashR.collectiveWeight = 100;
894 g_model.swashR.elevatorWeight = 100;
895 g_model.swashR.aileronWeight = 100;
896 g_model.swashR.type = SWASH_TYPE_120;
897 g_model.mixData[0].destCh = 0;
898 g_model.mixData[0].mltpx = MLTPX_ADD;
899 g_model.mixData[0].srcRaw = MIXSRC_CYC1;
900 g_model.mixData[0].weight = 100;
901 g_model.mixData[1].destCh = 1;
902 g_model.mixData[1].mltpx = MLTPX_ADD;
903 g_model.mixData[1].srcRaw = MIXSRC_CYC2;
904 g_model.mixData[1].weight = 100;
905 g_model.mixData[2].destCh = 2;
906 g_model.mixData[2].mltpx = MLTPX_ADD;
907 g_model.mixData[2].srcRaw = MIXSRC_CYC3;
908 g_model.mixData[2].weight = 100;
909 anaInValues[ELE_STICK] = 1024;
910 evalFlightModeMixes(e_perout_mode_normal, 0);
911 EXPECT_EQ(chans[0], -CHANNEL_MAX);
912 EXPECT_EQ(chans[1], CHANNEL_MAX/2);
913 EXPECT_EQ(chans[2], CHANNEL_MAX/2);
916 TEST(Heli, Mode2Test)
918 SYSTEM_RESET();
919 MODEL_RESET();
920 MIXER_RESET();
921 modelDefault(0);
922 g_eeGeneral.templateSetup = 2;
923 applyDefaultTemplate();
924 g_model.swashR.collectiveSource = MIXSRC_Thr;
925 g_model.swashR.elevatorSource = MIXSRC_Ele;
926 g_model.swashR.aileronSource = MIXSRC_Ail;
927 g_model.swashR.collectiveWeight = 100;
928 g_model.swashR.elevatorWeight = 100;
929 g_model.swashR.aileronWeight = 100;
930 g_model.swashR.type = SWASH_TYPE_120;
931 g_model.mixData[0].destCh = 0;
932 g_model.mixData[0].mltpx = MLTPX_ADD;
933 g_model.mixData[0].srcRaw = MIXSRC_CYC1;
934 g_model.mixData[0].weight = 100;
935 g_model.mixData[1].destCh = 1;
936 g_model.mixData[1].mltpx = MLTPX_ADD;
937 g_model.mixData[1].srcRaw = MIXSRC_CYC2;
938 g_model.mixData[1].weight = 100;
939 g_model.mixData[2].destCh = 2;
940 g_model.mixData[2].mltpx = MLTPX_ADD;
941 g_model.mixData[2].srcRaw = MIXSRC_CYC3;
942 g_model.mixData[2].weight = 100;
943 anaInValues[ELE_STICK] = 1024;
944 evalFlightModeMixes(e_perout_mode_normal, 0);
945 EXPECT_EQ(chans[0], -CHANNEL_MAX);
946 EXPECT_EQ(chans[1], CHANNEL_MAX/2);
947 EXPECT_EQ(chans[2], CHANNEL_MAX/2);
948 SYSTEM_RESET();
950 #endif
952 #if defined(HELI) && !defined(VIRTUAL_INPUTS)
953 TEST(Heli, SimpleTest)
955 SYSTEM_RESET();
956 MODEL_RESET();
957 MIXER_RESET();
958 modelDefault(0);
959 applyTemplate(TMPL_HELI_SETUP);
960 anaInValues[ELE_STICK] = 1024;
961 evalFlightModeMixes(e_perout_mode_normal, 0);
962 EXPECT_EQ(chans[0], -CHANNEL_MAX);
963 EXPECT_EQ(chans[1], CHANNEL_MAX/2);
964 EXPECT_EQ(chans[1], CHANNEL_MAX/2);
966 #endif
968 TEST(Trainer, UnpluggedTest)
970 SYSTEM_RESET();
971 MODEL_RESET();
972 MIXER_RESET();
973 modelDefault(0);
974 g_model.mixData[0].destCh = 0;
975 g_model.mixData[0].mltpx = MLTPX_ADD;
976 g_model.mixData[0].srcRaw = MIXSRC_FIRST_TRAINER;
977 g_model.mixData[0].weight = 100;
978 g_model.mixData[0].delayUp = DELAY_STEP*5;
979 g_model.mixData[0].delayDown = DELAY_STEP*5;
980 ppmInputValidityTimer = 0;
981 ppmInput[0] = 1024;
982 CHECK_DELAY(0, 5000);