Add a tooltip for the "Stack decoder" button/dropdown.
[pulseview.git] / test / data / logicsegment.cpp
1 /*
2  * This file is part of the PulseView project.
3  *
4  * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <extdef.h>
21
22 #include <cstdint>
23
24 #include <boost/test/unit_test.hpp>
25
26 #include <pv/data/logicsegment.hpp>
27
28 #if 0
29 using pv::data::LogicSegment;
30 using std::vector;
31 #endif
32
33 // Dummy, remove again when unit tests are fixed.
34 BOOST_AUTO_TEST_SUITE(DummyTestSuite)
35 BOOST_AUTO_TEST_CASE(DummyTestCase)
36 {
37         BOOST_CHECK_EQUAL(1, 1);
38 }
39 BOOST_AUTO_TEST_SUITE_END()
40
41 #if 0
42 BOOST_AUTO_TEST_SUITE(LogicSegmentTest)
43
44 void push_logic(LogicSegment &s, unsigned int length, uint8_t value)
45 {
46         sr_datafeed_logic logic;
47         logic.unitsize = 1;
48         logic.length = length;
49         logic.data = new uint8_t[length];
50         memset(logic.data, value, length * logic.unitsize);
51         s.append_payload(logic);
52         delete[] (uint8_t*)logic.data;
53 }
54
55 BOOST_AUTO_TEST_CASE(Pow2)
56 {
57         BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(0, 0), 0);
58         BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(1, 0), 1);
59         BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(2, 0), 2);
60
61         BOOST_CHECK_EQUAL(
62                 LogicSegment::pow2_ceil(INT64_MIN, 0), INT64_MIN);
63         BOOST_CHECK_EQUAL(
64                 LogicSegment::pow2_ceil(INT64_MAX, 0), INT64_MAX);
65
66         BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(0, 1), 0);
67         BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(1, 1), 2);
68         BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(2, 1), 2);
69         BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(3, 1), 4);
70 }
71
72 BOOST_AUTO_TEST_CASE(Basic)
73 {
74         // Create an empty LogicSegment object
75         sr_datafeed_logic logic;
76         logic.length = 0;
77         logic.unitsize = 1;
78         logic.data = nullptr;
79
80         LogicSegment s(logic);
81
82         //----- Test LogicSegment::push_logic -----//
83
84         BOOST_CHECK(s.get_sample_count() == 0);
85         for (unsigned int i = 0; i < LogicSegment::ScaleStepCount; i++)
86         {
87                 const LogicSegment::MipMapLevel &m = s.mip_map_[i];
88                 BOOST_CHECK_EQUAL(m.length, 0);
89                 BOOST_CHECK_EQUAL(m.data_length, 0);
90                 BOOST_CHECK(m.data == nullptr);
91         }
92
93         // Push 8 samples of all zeros
94         push_logic(s, 8, 0);
95
96         BOOST_CHECK(s.get_sample_count() == 8);
97
98         // There should not be enough samples to have a single mip map sample
99         for (unsigned int i = 0; i < LogicSegment::ScaleStepCount; i++)
100         {
101                 const LogicSegment::MipMapLevel &m = s.mip_map_[i];
102                 BOOST_CHECK_EQUAL(m.length, 0);
103                 BOOST_CHECK_EQUAL(m.data_length, 0);
104                 BOOST_CHECK(m.data == nullptr);
105         }
106
107         // Push 8 samples of 0x11s to bring the total up to 16
108         push_logic(s, 8, 0x11);
109
110         // There should now be enough data for exactly one sample
111         // in mip map level 0, and that sample should be 0
112         const LogicSegment::MipMapLevel &m0 = s.mip_map_[0];
113         BOOST_CHECK_EQUAL(m0.length, 1);
114         BOOST_CHECK_EQUAL(m0.data_length, LogicSegment::MipMapDataUnit);
115         BOOST_REQUIRE(m0.data != nullptr);
116         BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[0], 0x11);
117
118         // The higher levels should still be empty
119         for (unsigned int i = 1; i < LogicSegment::ScaleStepCount; i++)
120         {
121                 const LogicSegment::MipMapLevel &m = s.mip_map_[i];
122                 BOOST_CHECK_EQUAL(m.length, 0);
123                 BOOST_CHECK_EQUAL(m.data_length, 0);
124                 BOOST_CHECK(m.data == nullptr);
125         }
126
127         // Push 240 samples of all zeros to bring the total up to 256
128         push_logic(s, 240, 0);
129
130         BOOST_CHECK_EQUAL(m0.length, 16);
131         BOOST_CHECK_EQUAL(m0.data_length, LogicSegment::MipMapDataUnit);
132
133         BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[1], 0x11);
134         for (unsigned int i = 2; i < m0.length; i++)
135                 BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[i], 0);
136
137         const LogicSegment::MipMapLevel &m1 = s.mip_map_[1];
138         BOOST_CHECK_EQUAL(m1.length, 1);
139         BOOST_CHECK_EQUAL(m1.data_length, LogicSegment::MipMapDataUnit);
140         BOOST_REQUIRE(m1.data != nullptr);
141         BOOST_CHECK_EQUAL(((uint8_t*)m1.data)[0], 0x11);
142
143         //----- Test LogicSegment::get_subsampled_edges -----//
144
145         // Test a full view at full zoom.
146         vector<LogicSegment::EdgePair> edges;
147         s.get_subsampled_edges(edges, 0, 255, 1, 0);
148         BOOST_REQUIRE_EQUAL(edges.size(), 4);
149
150         BOOST_CHECK_EQUAL(edges[0].first, 0);
151         BOOST_CHECK_EQUAL(edges[1].first, 8);
152         BOOST_CHECK_EQUAL(edges[2].first, 16);
153         BOOST_CHECK_EQUAL(edges[3].first, 256);
154
155         // Test a subset at high zoom
156         edges.clear();
157         s.get_subsampled_edges(edges, 6, 17, 0.05f, 0);
158         BOOST_REQUIRE_EQUAL(edges.size(), 4);
159
160         BOOST_CHECK_EQUAL(edges[0].first, 6);
161         BOOST_CHECK_EQUAL(edges[1].first, 8);
162         BOOST_CHECK_EQUAL(edges[2].first, 16);
163         BOOST_CHECK_EQUAL(edges[3].first, 18);
164 }
165
166 BOOST_AUTO_TEST_CASE(LargeData)
167 {
168         uint8_t prev_sample;
169         const unsigned int Length = 1000000;
170
171         sr_datafeed_logic logic;
172         logic.unitsize = 1;
173         logic.length = Length;
174         logic.data = new uint8_t[Length];
175         uint8_t *data = (uint8_t*)logic.data;
176
177         for (unsigned int i = 0; i < Length; i++)
178                 *data++ = (uint8_t)(i >> 8);
179
180         LogicSegment s(logic);
181         delete[] (uint8_t*)logic.data;
182
183         BOOST_CHECK(s.get_sample_count() == Length);
184
185         // Check mip map level 0
186         BOOST_CHECK_EQUAL(s.mip_map_[0].length, 62500);
187         BOOST_CHECK_EQUAL(s.mip_map_[0].data_length,
188                 LogicSegment::MipMapDataUnit);
189         BOOST_REQUIRE(s.mip_map_[0].data != nullptr);
190
191         prev_sample = 0;
192         for (unsigned int i = 0; i < s.mip_map_[0].length;)
193         {
194                 BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]");
195
196                 const uint8_t sample = (uint8_t)((i*16) >> 8);
197                 BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF,
198                         prev_sample ^ sample);
199                 prev_sample = sample;
200
201                 for (int j = 1; i < s.mip_map_[0].length && j < 16; j++)
202                 {
203                         BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]");
204                         BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0);
205                 }
206         }
207
208         // Check mip map level 1
209         BOOST_CHECK_EQUAL(s.mip_map_[1].length, 3906);
210         BOOST_CHECK_EQUAL(s.mip_map_[1].data_length,
211                 LogicSegment::MipMapDataUnit);
212         BOOST_REQUIRE(s.mip_map_[1].data != nullptr);
213
214         prev_sample = 0;
215         for (unsigned int i = 0; i < s.mip_map_[1].length; i++)
216         {
217                 BOOST_TEST_MESSAGE("Testing mip_map[1].data[" << i << "]");
218
219                 const uint8_t sample = i;
220                 const uint8_t expected = sample ^ prev_sample;
221                 prev_sample = i;
222
223                 BOOST_CHECK_EQUAL(s.get_subsample(1, i) & 0xFF, expected);
224         }
225
226         // Check mip map level 2
227         BOOST_CHECK_EQUAL(s.mip_map_[2].length, 244);
228         BOOST_CHECK_EQUAL(s.mip_map_[2].data_length,
229                 LogicSegment::MipMapDataUnit);
230         BOOST_REQUIRE(s.mip_map_[2].data != nullptr);
231
232         prev_sample = 0;
233         for (unsigned int i = 0; i < s.mip_map_[2].length; i++)
234         {
235                 BOOST_TEST_MESSAGE("Testing mip_map[2].data[" << i << "]");
236
237                 const uint8_t sample = i << 4;
238                 const uint8_t expected = (sample ^ prev_sample) | 0x0F;
239                 prev_sample = sample;
240
241                 BOOST_CHECK_EQUAL(s.get_subsample(2, i) & 0xFF, expected);
242         }
243
244         // Check mip map level 3
245         BOOST_CHECK_EQUAL(s.mip_map_[3].length, 15);
246         BOOST_CHECK_EQUAL(s.mip_map_[3].data_length,
247                 LogicSegment::MipMapDataUnit);
248         BOOST_REQUIRE(s.mip_map_[3].data != nullptr);
249
250         for (unsigned int i = 0; i < s.mip_map_[3].length; i++)
251                 BOOST_CHECK_EQUAL(*((uint8_t*)s.mip_map_[3].data + i),
252                         0xFF);
253
254         // Check the higher levels
255         for (unsigned int i = 4; i < LogicSegment::ScaleStepCount; i++)
256         {
257                 const LogicSegment::MipMapLevel &m = s.mip_map_[i];
258                 BOOST_CHECK_EQUAL(m.length, 0);
259                 BOOST_CHECK_EQUAL(m.data_length, 0);
260                 BOOST_CHECK(m.data == nullptr);
261         }
262
263         //----- Test LogicSegment::get_subsampled_edges -----//
264         // Check in normal case
265         vector<LogicSegment::EdgePair> edges;
266         s.get_subsampled_edges(edges, 0, Length-1, 1, 7);
267
268         BOOST_CHECK_EQUAL(edges.size(), 32);
269
270         for (unsigned int i = 0; i < edges.size() - 1; i++)
271         {
272                 BOOST_CHECK_EQUAL(edges[i].first, i * 32768);
273                 BOOST_CHECK_EQUAL(edges[i].second, i & 1);
274         }
275
276         BOOST_CHECK_EQUAL(edges[31].first, 1000000);
277
278         // Check in very low zoom case
279         edges.clear();
280         s.get_subsampled_edges(edges, 0, Length-1, 50e6f, 7);
281
282         BOOST_CHECK_EQUAL(edges.size(), 2);
283 }
284
285 BOOST_AUTO_TEST_CASE(Pulses)
286 {
287         const int Cycles = 3;
288         const int Period = 64;
289         const int Length = Cycles * Period;
290
291         vector<LogicSegment::EdgePair> edges;
292
293         //----- Create a LogicSegment -----//
294         sr_datafeed_logic logic;
295         logic.unitsize = 1;
296         logic.length = Length;
297         logic.data = (uint64_t*)new uint8_t[Length];
298         uint8_t *p = (uint8_t*)logic.data;
299
300         for (int i = 0; i < Cycles; i++) {
301                 *p++ = 0xFF;
302                 for (int j = 1; j < Period; j++)
303                         *p++ = 0x00;
304         }
305
306         LogicSegment s(logic);
307         delete[] (uint8_t*)logic.data;
308
309         //----- Check the mip-map -----//
310         // Check mip map level 0
311         BOOST_CHECK_EQUAL(s.mip_map_[0].length, 12);
312         BOOST_CHECK_EQUAL(s.mip_map_[0].data_length,
313                 LogicSegment::MipMapDataUnit);
314         BOOST_REQUIRE(s.mip_map_[0].data != nullptr);
315
316         for (unsigned int i = 0; i < s.mip_map_[0].length;) {
317                 BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]");
318                 BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0xFF);
319
320                 for (int j = 1;
321                         i < s.mip_map_[0].length &&
322                         j < Period/LogicSegment::MipMapScaleFactor; j++) {
323                         BOOST_TEST_MESSAGE(
324                                 "Testing mip_map[0].data[" << i << "]");
325                         BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0x00);
326                 }
327         }
328
329         // Check the higher levels are all inactive
330         for (unsigned int i = 1; i < LogicSegment::ScaleStepCount; i++) {
331                 const LogicSegment::MipMapLevel &m = s.mip_map_[i];
332                 BOOST_CHECK_EQUAL(m.length, 0);
333                 BOOST_CHECK_EQUAL(m.data_length, 0);
334                 BOOST_CHECK(m.data == nullptr);
335         }
336
337         //----- Test get_subsampled_edges at reduced scale -----//
338         s.get_subsampled_edges(edges, 0, Length-1, 16.0f, 2);
339         BOOST_REQUIRE_EQUAL(edges.size(), Cycles + 2);
340
341         BOOST_CHECK_EQUAL(0, false);
342         for (unsigned int i = 1; i < edges.size(); i++)
343                 BOOST_CHECK_EQUAL(edges[i].second, false);
344 }
345
346 BOOST_AUTO_TEST_CASE(LongPulses)
347 {
348         const int Cycles = 3;
349         const int Period = 64;
350         const int PulseWidth = 16;
351         const int Length = Cycles * Period;
352
353         int j;
354         vector<LogicSegment::EdgePair> edges;
355
356         //----- Create a LogicSegment -----//
357         sr_datafeed_logic logic;
358         logic.unitsize = 8;
359         logic.length = Length * 8;
360         logic.data = (uint64_t*)new uint64_t[Length];
361         uint64_t *p = (uint64_t*)logic.data;
362
363         for (int i = 0; i < Cycles; i++) {
364                 for (j = 0; j < PulseWidth; j++)
365                         *p++ = ~0;
366                 for (; j < Period; j++)
367                         *p++ = 0;
368         }
369
370         LogicSegment s(logic);
371         delete[] (uint64_t*)logic.data;
372
373         //----- Check the mip-map -----//
374         // Check mip map level 0
375         BOOST_CHECK_EQUAL(s.mip_map_[0].length, 12);
376         BOOST_CHECK_EQUAL(s.mip_map_[0].data_length,
377                 LogicSegment::MipMapDataUnit);
378         BOOST_REQUIRE(s.mip_map_[0].data != nullptr);
379
380         for (unsigned int i = 0; i < s.mip_map_[0].length;) {
381                 for (j = 0; i < s.mip_map_[0].length && j < 2; j++) {
382                         BOOST_TEST_MESSAGE(
383                                 "Testing mip_map[0].data[" << i << "]");
384                         BOOST_CHECK_EQUAL(s.get_subsample(0, i++), ~0);
385                 }
386
387                 for (; i < s.mip_map_[0].length &&
388                         j < Period/LogicSegment::MipMapScaleFactor; j++) {
389                         BOOST_TEST_MESSAGE(
390                                 "Testing mip_map[0].data[" << i << "]");
391                         BOOST_CHECK_EQUAL(s.get_subsample(0, i++), 0);
392                 }
393         }
394
395         // Check the higher levels are all inactive
396         for (unsigned int i = 1; i < LogicSegment::ScaleStepCount; i++) {
397                 const LogicSegment::MipMapLevel &m = s.mip_map_[i];
398                 BOOST_CHECK_EQUAL(m.length, 0);
399                 BOOST_CHECK_EQUAL(m.data_length, 0);
400                 BOOST_CHECK(m.data == nullptr);
401         }
402
403         //----- Test get_subsampled_edges at a full scale -----//
404         s.get_subsampled_edges(edges, 0, Length-1, 16.0f, 2);
405         BOOST_REQUIRE_EQUAL(edges.size(), Cycles * 2 + 1);
406
407         for (int i = 0; i < Cycles; i++) {
408                 BOOST_CHECK_EQUAL(edges[i*2].first, i * Period);
409                 BOOST_CHECK_EQUAL(edges[i*2].second, true);
410                 BOOST_CHECK_EQUAL(edges[i*2+1].first, i * Period + PulseWidth);
411                 BOOST_CHECK_EQUAL(edges[i*2+1].second, false);
412         }
413
414         BOOST_CHECK_EQUAL(edges.back().first, Length);
415         BOOST_CHECK_EQUAL(edges.back().second, false);
416
417         //----- Test get_subsampled_edges at a simplified scale -----//
418         edges.clear();
419         s.get_subsampled_edges(edges, 0, Length-1, 17.0f, 2);
420
421         BOOST_CHECK_EQUAL(edges[0].first, 0);
422         BOOST_CHECK_EQUAL(edges[0].second, true);
423         BOOST_CHECK_EQUAL(edges[1].first, 16);
424         BOOST_CHECK_EQUAL(edges[1].second, false);
425         
426         for (int i = 1; i < Cycles; i++) {
427                 BOOST_CHECK_EQUAL(edges[i+1].first, i * Period);
428                 BOOST_CHECK_EQUAL(edges[i+1].second, false);
429         }
430
431         BOOST_CHECK_EQUAL(edges.back().first, Length);
432         BOOST_CHECK_EQUAL(edges.back().second, false);
433 }
434
435 BOOST_AUTO_TEST_CASE(LisaMUsbHid)
436 {
437         /* This test was created from the beginning of the USB_DM signal in
438          * sigrok-dumps-usb/lisa_m_usbhid/lisa_m_usbhid.sr
439          */
440
441         const int Edges[] = {
442                 7028, 7033, 7036, 7041, 7044, 7049, 7053, 7066, 7073, 7079,
443                 7086, 7095, 7103, 7108, 7111, 7116, 7119, 7124, 7136, 7141,
444                 7148, 7162, 7500
445         };
446         const int Length = Edges[countof(Edges) - 1];
447
448         bool state = false;
449         int lastEdgePos = 0;
450
451         //----- Create a LogicSegment -----//
452         sr_datafeed_logic logic;
453         logic.unitsize = 1;
454         logic.length = Length;
455         logic.data = new uint8_t[Length];
456         uint8_t *data = (uint8_t*)logic.data;
457
458         for (unsigned int i = 0; i < countof(Edges); i++) {
459                 const int edgePos = Edges[i];
460                 memset(&data[lastEdgePos], state ? 0x02 : 0,
461                         edgePos - lastEdgePos - 1);
462
463                 lastEdgePos = edgePos;
464                 state = !state;
465         }
466
467         LogicSegment s(logic);
468         delete[] (uint64_t*)logic.data;
469
470         vector<LogicSegment::EdgePair> edges;
471
472
473         /* The trailing edge of the pulse train is falling in the source data.
474          * Check this is always true at different scales
475          */
476
477         edges.clear();
478         s.get_subsampled_edges(edges, 0, Length-1, 33.333332f, 1);
479         BOOST_CHECK_EQUAL(edges[edges.size() - 2].second, false);
480 }
481
482 /*
483  * This test checks the rendering of wide data (more than 8 channels)
484  * Probe signals are either all-high, or all-low, but are interleaved such that
485  * they would toggle during every sample if treated like 8 channels.
486  * The packet contains a large number of samples, so the mipmap generation kicks
487  * in.
488  *
489  * The signals should not toggle (have exactly two edges: the start and end)
490  */
491 BOOST_AUTO_TEST_CASE(WideData)
492 {
493         const int Length = 512<<10;
494         uint16_t *data = new uint16_t[Length];
495
496         sr_datafeed_logic logic;
497         logic.unitsize = sizeof(data[0]);
498         logic.length = Length * sizeof(data[0]);
499         logic.data = data;
500
501         for (int i = 0; i < Length; i++)
502                 data[i] = 0x0FF0;
503
504         LogicSegment s(logic);
505
506         vector<LogicSegment::EdgePair> edges;
507
508         edges.clear();
509         s.get_subsampled_edges(edges, 0, Length-1, 1, 0);
510         BOOST_CHECK_EQUAL(edges.size(), 2);
511
512         edges.clear();
513         s.get_subsampled_edges(edges, 0, Length-1, 1, 8);
514         BOOST_CHECK_EQUAL(edges.size(), 2);
515
516         // Cleanup
517         delete [] data;
518 }
519
520 /*
521  * This test is a replica of sixteen.sr attached to Bug #33.
522  */
523 BOOST_AUTO_TEST_CASE(Sixteen)
524 {
525         const int Length = 8;
526         uint16_t data[Length];
527
528         sr_datafeed_logic logic;
529         logic.unitsize = sizeof(data[0]);
530         logic.length = Length * sizeof(data[0]);
531         logic.data = data;
532
533         for (int i = 0; i < Length; i++)
534                 data[i] = 0xFFFE;
535
536         LogicSegment s(logic);
537
538         vector<LogicSegment::EdgePair> edges;
539         s.get_subsampled_edges(edges, 0, 2, 0.0004, 1);
540
541         BOOST_CHECK_EQUAL(edges.size(), 2);
542 }
543
544 BOOST_AUTO_TEST_SUITE_END()
545 #endif