2 * This file is part of ExpressLRS
3 * See https://github.com/AlessandroAU/ExpressLRS
5 * Unit tests for over the air packet encoding, decoding and associated utilities
7 * Entry point is setup_switches()
14 // #include "common.h"
18 CRSF
crsf(NULL
); // need an instance to provide the fields used by the code under test
22 TEST_ASSERT_EQUAL(0, CRSF_to_BIT(CRSF_CHANNEL_VALUE_1000
));
23 TEST_ASSERT_EQUAL(1, CRSF_to_BIT(CRSF_CHANNEL_VALUE_2000
));
28 TEST_ASSERT_EQUAL(CRSF_CHANNEL_VALUE_1000
, BIT_to_CRSF(0));
29 TEST_ASSERT_EQUAL(CRSF_CHANNEL_VALUE_2000
, BIT_to_CRSF(1));
34 TEST_ASSERT_EQUAL(0, CRSF_to_N(CRSF_CHANNEL_VALUE_MIN
, 64));
35 TEST_ASSERT_EQUAL(0, CRSF_to_N(CRSF_CHANNEL_VALUE_1000
, 64));
36 TEST_ASSERT_EQUAL(0b100000, CRSF_to_N(CRSF_CHANNEL_VALUE_MID
, 64));
37 TEST_ASSERT_EQUAL(0b111111, CRSF_to_N(CRSF_CHANNEL_VALUE_2000
, 64));
38 TEST_ASSERT_EQUAL(0b111111, CRSF_to_N(CRSF_CHANNEL_VALUE_MAX
, 64));
40 TEST_ASSERT_EQUAL(0, CRSF_to_N(CRSF_CHANNEL_VALUE_MIN
, 128));
41 TEST_ASSERT_EQUAL(0, CRSF_to_N(CRSF_CHANNEL_VALUE_1000
, 128));
42 TEST_ASSERT_EQUAL(0b1000000, CRSF_to_N(CRSF_CHANNEL_VALUE_MID
, 128));
43 TEST_ASSERT_EQUAL(0b1111111, CRSF_to_N(CRSF_CHANNEL_VALUE_2000
, 128));
44 TEST_ASSERT_EQUAL(0b1111111, CRSF_to_N(CRSF_CHANNEL_VALUE_MAX
, 128));
50 TEST_ASSERT_EQUAL(CRSF_CHANNEL_VALUE_1000
, N_to_CRSF(0, 63));
51 TEST_ASSERT_EQUAL(1004, N_to_CRSF(0b100000, 63));
52 TEST_ASSERT_EQUAL(CRSF_CHANNEL_VALUE_2000
, N_to_CRSF(0b111111, 63));
55 TEST_ASSERT_EQUAL(CRSF_CHANNEL_VALUE_1000
, N_to_CRSF(0, 127));
56 TEST_ASSERT_EQUAL(997, N_to_CRSF(0b1000000, 127));
57 TEST_ASSERT_EQUAL(CRSF_CHANNEL_VALUE_2000
, N_to_CRSF(0b1111111, 127));
60 // ------------------------------------------------
61 // Test the hybrid8 encoding/decoding
63 /* Check the hybrid 8 encoding of a packet for OTA tx
65 void test_encodingHybrid8(bool highResChannel
)
67 constexpr uint8_t N_SWITCHES
= 8;
68 uint8_t UID
[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE};
70 uint8_t TXdataBuffer
[8];
72 // Define the input data
73 // 4 channels of analog data
74 crsf
.ChannelDataIn
[0] = 0x0123;
75 crsf
.ChannelDataIn
[1] = 0x4567;
76 crsf
.ChannelDataIn
[2] = 0x89AB;
77 crsf
.ChannelDataIn
[3] = 0xCDEF;
80 for(int i
= 0; i
< N_SWITCHES
; i
++) {
81 constexpr int CHANNELS
[] =
82 { CRSF_CHANNEL_VALUE_1000
, CRSF_CHANNEL_VALUE_MID
, CRSF_CHANNEL_VALUE_2000
};
83 crsf
.ChannelDataIn
[4+i
] = CHANNELS
[i
% 3];
86 // set the nextSwitchIndex so we know which switch to expect in the packet
88 OtaSetHybrid8NextSwitchIndex(7-1);
90 OtaSetHybrid8NextSwitchIndex(3-1);
93 OtaSetSwitchMode(smHybrid
);
94 PackChannelData(TXdataBuffer
, &crsf
, false, 0, 0);
96 // check it looks right
97 // 1st byte is CRC & packet type
98 uint8_t header
= RC_DATA_PACKET
;
99 TEST_ASSERT_EQUAL(header
, TXdataBuffer
[0]);
101 // bytes 1 through 5 are 10 bit packed analog channels
102 for(int i
= 0; i
< 4; i
++) {
103 expected
= crsf
.ChannelDataIn
[i
] >> 3; // most significant 8 bits
104 TEST_ASSERT_EQUAL(expected
, TXdataBuffer
[i
+ 1]);
107 // byte 5 is bits 1 and 2 of each analog channel
109 for(int i
= 0; i
< 4; i
++) {
110 expected
= (expected
<<2) | ((crsf
.ChannelDataIn
[i
] >> 1) & 0b11);
112 TEST_ASSERT_EQUAL(expected
, TXdataBuffer
[5]);
114 // byte 6 is the switch encoding
115 TEST_ASSERT_EQUAL(CRSF_to_BIT(crsf
.ChannelDataIn
[4+0]), (TXdataBuffer
[6] & 0b0100000)>>6);
116 // top bit is undefined
117 // expect switch 0 in bit 6
119 // value in 0,1,2[,3]
122 TEST_ASSERT_EQUAL(7, ((TXdataBuffer
[6] & 0b110000)>>3) + 1);
123 TEST_ASSERT_EQUAL(CRSF_to_N(crsf
.ChannelDataIn
[4+7], 16), TXdataBuffer
[6] & 0b1111);
127 TEST_ASSERT_EQUAL(3, ((TXdataBuffer
[6] & 0b111000)>>3) + 1);
128 TEST_ASSERT_EQUAL(CRSF_to_N(crsf
.ChannelDataIn
[4+3], 6), TXdataBuffer
[6] & 0b0111);
132 void test_encodingHybrid8_3()
134 test_encodingHybrid8(false);
137 void test_encodingHybrid8_7()
139 test_encodingHybrid8(true);
142 /* Check the decoding of a packet after rx
144 void test_decodingHybrid8(uint8_t forceSwitch
, uint8_t switchval
)
146 constexpr uint8_t N_SWITCHES
= 8;
147 uint8_t UID
[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE};
148 uint8_t TXdataBuffer
[8];
151 // Define the input data
152 // 4 channels of analog data
153 crsf
.ChannelDataIn
[0] = 0x0123;
154 crsf
.ChannelDataIn
[1] = 0x4567;
155 crsf
.ChannelDataIn
[2] = 0x89AB;
156 crsf
.ChannelDataIn
[3] = 0xCDEF;
159 for(int i
= 0; i
< N_SWITCHES
; i
++) {
160 constexpr int CHANNELS
[] =
161 { CRSF_CHANNEL_VALUE_1000
, CRSF_CHANNEL_VALUE_MID
, CRSF_CHANNEL_VALUE_2000
};
162 crsf
.ChannelDataIn
[4+i
] = CHANNELS
[i
% 3];
164 if (forceSwitch
== 0)
165 crsf
.ChannelDataIn
[4+forceSwitch
] = BIT_to_CRSF(switchval
);
166 else if (forceSwitch
== 7)
167 crsf
.ChannelDataIn
[4+forceSwitch
] = N_to_CRSF(switchval
, 15);
169 crsf
.ChannelDataIn
[4+forceSwitch
] = SWITCH3b_to_CRSF(switchval
);
171 // set the nextSwitchIndex so we know which switch to expect in the packet
172 if (forceSwitch
== 0)
173 OtaSetHybrid8NextSwitchIndex(0);
175 OtaSetHybrid8NextSwitchIndex(forceSwitch
-1);
177 // use the encoding method to pack it into TXdataBuffer
178 OtaSetSwitchMode(smHybrid
);
179 PackChannelData(TXdataBuffer
, &crsf
, false, 0, 0);
181 // run the decoder, results in crsf->PackedRCdataOut
182 UnpackChannelData(TXdataBuffer
, &crsf
, 0, 0);
184 // compare the unpacked results with the input data
185 TEST_ASSERT_EQUAL(crsf
.ChannelDataIn
[0] & 0b11111111110, crsf
.PackedRCdataOut
.ch0
); // analog channels are truncated to 10 bits
186 TEST_ASSERT_EQUAL(crsf
.ChannelDataIn
[1] & 0b11111111110, crsf
.PackedRCdataOut
.ch1
); // analog channels are truncated to 10 bits
187 TEST_ASSERT_EQUAL(crsf
.ChannelDataIn
[2] & 0b11111111110, crsf
.PackedRCdataOut
.ch2
); // analog channels are truncated to 10 bits
188 TEST_ASSERT_EQUAL(crsf
.ChannelDataIn
[3] & 0b11111111110, crsf
.PackedRCdataOut
.ch3
); // analog channels are truncated to 10 bits
190 TEST_ASSERT_EQUAL(crsf
.ChannelDataIn
[4+0], crsf
.PackedRCdataOut
.ch4
); // Switch 0 is sent on every packet
191 if (forceSwitch
== 7)
192 TEST_ASSERT_EQUAL(crsf
.ChannelDataIn
[4+forceSwitch
], crsf
.PackedRCdataOut
.ch11
); // We forced switch 1 to be sent as the sequential field
193 else if (forceSwitch
!= 0)
198 case 1: ch
= crsf
.PackedRCdataOut
.ch5
; break;
199 case 2: ch
= crsf
.PackedRCdataOut
.ch6
; break;
200 case 3: ch
= crsf
.PackedRCdataOut
.ch7
; break;
201 case 4: ch
= crsf
.PackedRCdataOut
.ch8
; break;
202 case 5: ch
= crsf
.PackedRCdataOut
.ch9
; break;
203 case 6: ch
= crsf
.PackedRCdataOut
.ch10
; break;
205 TEST_FAIL_MESSAGE("forceSwitch not handled");
207 TEST_ASSERT_EQUAL(crsf
.ChannelDataIn
[4+forceSwitch
], ch
);
211 void test_decodingHybrid8_all()
214 test_decodingHybrid8(0, 0);
215 test_decodingHybrid8(0, 1);
216 // Switch X in 6-pos mode (includes 3-pos low/high)
217 for (uint8_t val
=0; val
<6; ++val
)
218 test_decodingHybrid8(3, val
);
219 // // Switch X in 3-pos mode center
220 // test_decodingHybrid8(3, 7);
221 // // Switch 7 is 16 pos
222 // for (uint8_t val=0; val<16; ++val)
223 // test_decodingHybrid8(7, val);
226 /* Check the HybridWide encoding of a packet for OTA tx
228 void test_encodingHybridWide(bool highRes
, uint8_t nonce
)
230 uint8_t UID
[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE};
232 uint8_t TXdataBuffer
[8];
234 // Define the input data
235 // 4 channels of analog data
236 crsf
.ChannelDataIn
[0] = 0x0123;
237 crsf
.ChannelDataIn
[1] = 0x4567;
238 crsf
.ChannelDataIn
[2] = 0x89AB;
239 crsf
.ChannelDataIn
[3] = 0xCDEF;
242 constexpr int N_SWITCHES
= 8;
243 for(int i
= 0; i
< N_SWITCHES
; i
++) {
244 constexpr int CHANNELS
[] =
245 { CRSF_CHANNEL_VALUE_1000
, CRSF_CHANNEL_VALUE_MID
, CRSF_CHANNEL_VALUE_2000
};
246 crsf
.ChannelDataIn
[4+i
] = CHANNELS
[i
% 3];
250 crsf
.LinkStatistics
.uplink_TX_Power
= 3; // 100mW
253 uint8_t tlmDenom
= (highRes
) ? 64 : 4;
254 OtaSetSwitchMode(smHybridWide
);
255 PackChannelData(TXdataBuffer
, &crsf
, nonce
% 2, nonce
, tlmDenom
);
257 // check it looks right
258 // 1st byte is CRC & packet type
259 uint8_t header
= RC_DATA_PACKET
;
260 TEST_ASSERT_EQUAL(header
, TXdataBuffer
[0]);
262 // bytes 1 through 5 are 10 bit packed analog channels
263 for(int i
= 0; i
< 4; i
++) {
264 expected
= crsf
.ChannelDataIn
[i
] >> 3; // most significant 8 bits
265 TEST_ASSERT_EQUAL(expected
, TXdataBuffer
[i
+ 1]);
268 // byte 5 is bits 1 and 2 of each analog channel
270 for(int i
= 0; i
< 4; i
++) {
271 expected
= (expected
<<2) | ((crsf
.ChannelDataIn
[i
] >> 1) & 0b11);
273 TEST_ASSERT_EQUAL(expected
, TXdataBuffer
[5]);
275 // byte 6 is the switches encoded
276 uint8_t switches
= TXdataBuffer
[6];
277 uint8_t switchIdx
= nonce
% 8;
279 // High bit should be AUX1
280 TEST_ASSERT_EQUAL(CRSF_to_BIT(crsf
.ChannelDataIn
[4]), switches
>> 7);
281 // If low res or slot 7, the bit 6 should be the telemetryack bit
282 if (!highRes
|| switchIdx
== 7)
283 TEST_ASSERT_EQUAL(nonce
% 2, (switches
>> 6) & 1);
285 // If slot 7, the uplink_TX_Power should be in the low 6 bits
287 TEST_ASSERT_EQUAL(crsf
.LinkStatistics
.uplink_TX_Power
, switches
& 0b111111);
290 uint16_t ch
= crsf
.ChannelDataIn
[5+switchIdx
];
292 TEST_ASSERT_EQUAL(CRSF_to_N(ch
, 128), switches
& 0b1111111); // 7-bit
294 TEST_ASSERT_EQUAL(CRSF_to_N(ch
, 64), switches
& 0b111111); // 6-bit
298 void test_encodingHybridWide_high()
300 constexpr int N_SWITCHES
= 8;
301 for (int i
=0; i
<N_SWITCHES
; ++i
)
302 test_encodingHybridWide(true, i
);
305 void test_encodingHybridWide_low()
307 constexpr int N_SWITCHES
= 8;
308 for (int i
=0; i
<N_SWITCHES
; ++i
)
309 test_encodingHybridWide(false, i
);
312 /* Check the decoding of a packet after rx in HybridWide mode
314 void test_decodingHybridWide(bool highRes
, uint8_t nonce
, uint8_t forceSwitch
, uint16_t forceVal
)
316 uint8_t UID
[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE};
317 uint8_t TXdataBuffer
[8];
320 // Define the input data
321 // 4 channels of analog data
322 crsf
.ChannelDataIn
[0] = 0x0123;
323 crsf
.ChannelDataIn
[1] = 0x4567;
324 crsf
.ChannelDataIn
[2] = 0x89AB;
325 crsf
.ChannelDataIn
[3] = 0xCDEF;
328 constexpr int N_SWITCHES
= 8;
329 for(int i
= 0; i
< N_SWITCHES
; i
++) {
330 constexpr int CHANNELS
[] =
331 { CRSF_CHANNEL_VALUE_1000
, CRSF_CHANNEL_VALUE_MID
, CRSF_CHANNEL_VALUE_2000
};
332 if (i
== forceSwitch
)
333 crsf
.ChannelDataIn
[4+i
] = forceVal
;
335 crsf
.ChannelDataIn
[4+i
] = CHANNELS
[i
% 3];
339 crsf
.LinkStatistics
.uplink_TX_Power
= 3; // 100mW
342 uint8_t tlmDenom
= (highRes
) ? 64 : 4;
343 OtaSetSwitchMode(smHybridWide
);
344 PackChannelData(TXdataBuffer
, &crsf
, nonce
% 2, nonce
, tlmDenom
);
346 // Clear the LinkStatistics to receive it from the encoding
347 crsf
.LinkStatistics
.uplink_TX_Power
= 0;
349 // run the decoder, results in crsf->PackedRCdataOut
350 bool telemResult
= UnpackChannelData(TXdataBuffer
, &crsf
, nonce
, tlmDenom
);
352 // compare the unpacked results with the input data
353 TEST_ASSERT_EQUAL(crsf
.ChannelDataIn
[0] & 0b11111111110, crsf
.PackedRCdataOut
.ch0
); // analog channels are truncated to 10 bits
354 TEST_ASSERT_EQUAL(crsf
.ChannelDataIn
[1] & 0b11111111110, crsf
.PackedRCdataOut
.ch1
); // analog channels are truncated to 10 bits
355 TEST_ASSERT_EQUAL(crsf
.ChannelDataIn
[2] & 0b11111111110, crsf
.PackedRCdataOut
.ch2
); // analog channels are truncated to 10 bits
356 TEST_ASSERT_EQUAL(crsf
.ChannelDataIn
[3] & 0b11111111110, crsf
.PackedRCdataOut
.ch3
); // analog channels are truncated to 10 bits
358 // Switch 0 is sent on every packet
359 TEST_ASSERT_EQUAL(crsf
.ChannelDataIn
[4], crsf
.PackedRCdataOut
.ch4
);
361 uint8_t switchIdx
= nonce
% 8;
362 // Validate the telemResult was unpacked properly
363 if (!highRes
|| switchIdx
== 7)
364 TEST_ASSERT_EQUAL(telemResult
, nonce
% 2);
368 TEST_ASSERT_EQUAL(crsf
.LinkStatistics
.uplink_TX_Power
, 3);
375 case 0: ch
= crsf
.PackedRCdataOut
.ch5
; break;
376 case 1: ch
= crsf
.PackedRCdataOut
.ch6
; break;
377 case 2: ch
= crsf
.PackedRCdataOut
.ch7
; break;
378 case 3: ch
= crsf
.PackedRCdataOut
.ch8
; break;
379 case 4: ch
= crsf
.PackedRCdataOut
.ch9
; break;
380 case 5: ch
= crsf
.PackedRCdataOut
.ch10
; break;
381 case 6: ch
= crsf
.PackedRCdataOut
.ch11
; break;
383 TEST_FAIL_MESSAGE("switchIdx not handled");
386 TEST_ASSERT_EQUAL(N_to_CRSF(CRSF_to_N(crsf
.ChannelDataIn
[5+switchIdx
], 128), 127), ch
);
388 TEST_ASSERT_EQUAL(N_to_CRSF(CRSF_to_N(crsf
.ChannelDataIn
[5+switchIdx
], 64), 63), ch
);
392 void test_decodingHybridWide_AUX1()
394 // Switch 0 is 2 pos, also tests the uplink_TX_Power
395 test_decodingHybridWide(true, 7, 0, CRSF_CHANNEL_VALUE_1000
);
396 test_decodingHybridWide(true, 7, 0, CRSF_CHANNEL_VALUE_2000
);
399 void test_decodingHybridWide_AUXX_high()
401 constexpr int N_SWITCHES
= 8;
402 for (int i
=0; i
<N_SWITCHES
; ++i
)
403 test_decodingHybridWide(true, i
, 0, CRSF_CHANNEL_VALUE_1000
);
406 void test_decodingHybridWide_AUXX_low()
408 constexpr int N_SWITCHES
= 8;
409 for (int i
=0; i
<N_SWITCHES
; ++i
)
410 test_decodingHybridWide(false, i
, 0, CRSF_CHANNEL_VALUE_1000
);
413 int main(int argc
, char **argv
)
416 RUN_TEST(test_crsfToBit
);
417 RUN_TEST(test_bitToCrsf
);
418 RUN_TEST(test_crsfToN
);
419 RUN_TEST(test_nToCrsf
);
421 RUN_TEST(test_encodingHybrid8_3
);
422 RUN_TEST(test_encodingHybrid8_7
);
423 RUN_TEST(test_decodingHybrid8_all
);
425 RUN_TEST(test_encodingHybridWide_high
);
426 RUN_TEST(test_encodingHybridWide_low
);
427 RUN_TEST(test_decodingHybridWide_AUX1
);
428 RUN_TEST(test_decodingHybridWide_AUXX_high
);
429 RUN_TEST(test_decodingHybridWide_AUXX_low
);