]> sigrok.org Git - pulseview.git/blob - test/logicdatasnapshot.cpp
503b1dda7176e6c2e3851dd62d409cf978260a23
[pulseview.git] / test / logicdatasnapshot.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, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 #define __STDC_LIMIT_MACROS
22 #include <stdint.h>
23
24 #include <boost/test/unit_test.hpp>
25
26 #include "../extdef.h"
27 #include "../pv/logicdatasnapshot.h"
28
29 using namespace std;
30
31 using pv::LogicDataSnapshot;
32
33 BOOST_AUTO_TEST_SUITE(LogicDataSnapshotTest)
34
35 void push_logic(LogicDataSnapshot &s, unsigned int length, uint8_t value)
36 {
37         sr_datafeed_logic logic;
38         logic.unitsize = 1;
39         logic.length = length;
40         logic.data = new uint8_t[length];
41         memset(logic.data, value, length * logic.unitsize);
42         s.append_payload(logic);
43         delete[] (uint8_t*)logic.data;
44 }
45
46 BOOST_AUTO_TEST_CASE(Pow2)
47 {
48         BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(-2, 0), -2);
49         BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(-1, 0), -1);
50         BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(0, 0), 0);
51         BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(1, 0), 1);
52         BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(2, 0), 2);
53
54         BOOST_CHECK_EQUAL(
55                 LogicDataSnapshot::pow2_ceil(INT64_MIN, 0), INT64_MIN);
56         BOOST_CHECK_EQUAL(
57                 LogicDataSnapshot::pow2_ceil(INT64_MAX, 0), INT64_MAX);
58
59         BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(-3, 1), -2);
60         BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(-2, 1), -2);
61         BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(-1, 1), 0);
62         BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(0, 1), 0);
63         BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(1, 1), 2);
64         BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(2, 1), 2);
65         BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(3, 1), 4);
66 }
67
68 BOOST_AUTO_TEST_CASE(Basic)
69 {
70         // Create an empty LogicDataSnapshot object
71         sr_datafeed_logic logic;
72         logic.length = 0;
73         logic.unitsize = 1;
74         logic.data = NULL;
75
76         LogicDataSnapshot s(logic);
77
78         //----- Test LogicDataSnapshot::push_logic -----//
79
80         BOOST_CHECK(s.get_sample_count() == 0);
81         for(int i = 0; i < LogicDataSnapshot::ScaleStepCount; i++)
82         {
83                 const LogicDataSnapshot::MipMapLevel &m = s._mip_map[i];
84                 BOOST_CHECK_EQUAL(m.length, 0);
85                 BOOST_CHECK_EQUAL(m.data_length, 0);
86                 BOOST_CHECK(m.data == NULL);
87         }
88
89         // Push 8 samples of all zeros
90         push_logic(s, 8, 0);
91
92         BOOST_CHECK(s.get_sample_count() == 8);
93
94         // There should not be enough samples to have a single mip map sample
95         for(int i = 0; i < LogicDataSnapshot::ScaleStepCount; i++)
96         {
97                 const LogicDataSnapshot::MipMapLevel &m = s._mip_map[i];
98                 BOOST_CHECK_EQUAL(m.length, 0);
99                 BOOST_CHECK_EQUAL(m.data_length, 0);
100                 BOOST_CHECK(m.data == NULL);
101         }
102
103         // Push 8 samples of 0x11s to bring the total up to 16
104         push_logic(s, 8, 0x11);
105
106         // There should now be enough data for exactly one sample
107         // in mip map level 0, and that sample should be 0
108         const LogicDataSnapshot::MipMapLevel &m0 = s._mip_map[0];
109         BOOST_CHECK_EQUAL(m0.length, 1);
110         BOOST_CHECK_EQUAL(m0.data_length, LogicDataSnapshot::MipMapDataUnit);
111         BOOST_REQUIRE(m0.data != NULL);
112         BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[0], 0x11);
113
114         // The higher levels should still be empty
115         for(int i = 1; i < LogicDataSnapshot::ScaleStepCount; i++)
116         {
117                 const LogicDataSnapshot::MipMapLevel &m = s._mip_map[i];
118                 BOOST_CHECK_EQUAL(m.length, 0);
119                 BOOST_CHECK_EQUAL(m.data_length, 0);
120                 BOOST_CHECK(m.data == NULL);
121         }
122
123         // Push 240 samples of all zeros to bring the total up to 256
124         push_logic(s, 240, 0);
125
126         BOOST_CHECK_EQUAL(m0.length, 16);
127         BOOST_CHECK_EQUAL(m0.data_length, LogicDataSnapshot::MipMapDataUnit);
128
129         BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[1], 0x11);
130         for(int i = 2; i < m0.length; i++)
131                 BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[i], 0);
132
133         const LogicDataSnapshot::MipMapLevel &m1 = s._mip_map[1];
134         BOOST_CHECK_EQUAL(m1.length, 1);
135         BOOST_CHECK_EQUAL(m1.data_length, LogicDataSnapshot::MipMapDataUnit);
136         BOOST_REQUIRE(m1.data != NULL);
137         BOOST_CHECK_EQUAL(((uint8_t*)m1.data)[0], 0x11);
138
139         //----- Test LogicDataSnapshot::get_subsampled_edges -----//
140
141         // Test a full view at full zoom.
142         vector<LogicDataSnapshot::EdgePair> edges;
143         s.get_subsampled_edges(edges, 0, 255, 1, 0);
144         BOOST_REQUIRE_EQUAL(edges.size(), 4);
145
146         BOOST_CHECK_EQUAL(edges[0].first, 0);
147         BOOST_CHECK_EQUAL(edges[1].first, 8);
148         BOOST_CHECK_EQUAL(edges[2].first, 16);
149         BOOST_CHECK_EQUAL(edges[3].first, 255);
150
151         // Test a subset at high zoom
152         edges.clear();
153         s.get_subsampled_edges(edges, 6, 17, 0.05f, 0);
154         BOOST_REQUIRE_EQUAL(edges.size(), 4);
155
156         BOOST_CHECK_EQUAL(edges[0].first, 6);
157         BOOST_CHECK_EQUAL(edges[1].first, 8);
158         BOOST_CHECK_EQUAL(edges[2].first, 16);
159         BOOST_CHECK_EQUAL(edges[3].first, 17);
160 }
161
162 BOOST_AUTO_TEST_CASE(LargeData)
163 {
164         uint8_t prev_sample;
165         const int Length = 1000000;
166
167         sr_datafeed_logic logic;
168         logic.unitsize = 1;
169         logic.length = Length;
170         logic.data = new uint8_t[Length];
171         uint8_t *data = (uint8_t*)logic.data;
172
173         for(int i = 0; i < Length; i++)
174                 *data++ = (uint8_t)(i >> 8);
175
176         LogicDataSnapshot s(logic);
177         delete[] (uint8_t*)logic.data;
178
179         BOOST_CHECK(s.get_sample_count() == Length);
180
181         // Check mip map level 0
182         BOOST_CHECK_EQUAL(s._mip_map[0].length, 62500);
183         BOOST_CHECK_EQUAL(s._mip_map[0].data_length,
184                 LogicDataSnapshot::MipMapDataUnit);
185         BOOST_REQUIRE(s._mip_map[0].data != NULL);
186
187         prev_sample = 0;
188         for(int i = 0; i < s._mip_map[0].length;)
189         {
190                 BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]");
191
192                 const uint8_t sample = (uint8_t)((i*16) >> 8);
193                 BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF,
194                         prev_sample ^ sample);
195                 prev_sample = sample;
196
197                 for(int j = 1; i < s._mip_map[0].length && j < 16; j++)
198                 {
199                         BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]");
200                         BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0);
201                 }
202         }
203
204         // Check mip map level 1
205         BOOST_CHECK_EQUAL(s._mip_map[1].length, 3906);
206         BOOST_CHECK_EQUAL(s._mip_map[1].data_length,
207                 LogicDataSnapshot::MipMapDataUnit);
208         BOOST_REQUIRE(s._mip_map[1].data != NULL);
209
210         prev_sample = 0;
211         for(int i = 0; i < s._mip_map[1].length; i++)
212         {
213                 BOOST_TEST_MESSAGE("Testing mip_map[1].data[" << i << "]");
214
215                 const uint8_t sample = i;
216                 const uint8_t expected = sample ^ prev_sample;
217                 prev_sample = i;
218
219                 BOOST_CHECK_EQUAL(s.get_subsample(1, i) & 0xFF, expected);
220         }
221
222         // Check mip map level 2
223         BOOST_CHECK_EQUAL(s._mip_map[2].length, 244);
224         BOOST_CHECK_EQUAL(s._mip_map[2].data_length,
225                 LogicDataSnapshot::MipMapDataUnit);
226         BOOST_REQUIRE(s._mip_map[2].data != NULL);
227
228         prev_sample = 0;
229         for(int i = 0; i < s._mip_map[2].length; i++)
230         {
231                 BOOST_TEST_MESSAGE("Testing mip_map[2].data[" << i << "]");
232
233                 const uint8_t sample = i << 4;
234                 const uint8_t expected = (sample ^ prev_sample) | 0x0F;
235                 prev_sample = sample;
236
237                 BOOST_CHECK_EQUAL(s.get_subsample(2, i) & 0xFF, expected);
238         }
239
240         // Check mip map level 3
241         BOOST_CHECK_EQUAL(s._mip_map[3].length, 15);
242         BOOST_CHECK_EQUAL(s._mip_map[3].data_length,
243                 LogicDataSnapshot::MipMapDataUnit);
244         BOOST_REQUIRE(s._mip_map[3].data != NULL);
245
246         for(int i = 0; i < s._mip_map[3].length; i++)
247                 BOOST_CHECK_EQUAL(*((uint8_t*)s._mip_map[3].data + i),
248                         0xFF);
249
250         // Check the higher levels
251         for(int i = 4; i < LogicDataSnapshot::ScaleStepCount; i++)
252         {
253                 const LogicDataSnapshot::MipMapLevel &m = s._mip_map[i];
254                 BOOST_CHECK_EQUAL(m.length, 0);
255                 BOOST_CHECK_EQUAL(m.data_length, 0);
256                 BOOST_CHECK(m.data == NULL);
257         }
258
259         //----- Test LogicDataSnapshot::get_subsampled_edges -----//
260         // Check in normal case
261         vector<LogicDataSnapshot::EdgePair> edges;
262         s.get_subsampled_edges(edges, 0, Length-1, 1, 7);
263
264         BOOST_CHECK_EQUAL(edges.size(), 32);
265
266         for(int i = 0; i < edges.size() - 1; i++)
267         {
268                 BOOST_CHECK_EQUAL(edges[i].first, i * 32768);
269                 BOOST_CHECK_EQUAL(edges[i].second, i & 1);
270         }
271
272         BOOST_CHECK_EQUAL(edges[31].first, 999999);
273
274         // Check in very low zoom case
275         edges.clear();
276         s.get_subsampled_edges(edges, 0, Length-1, 50e6f, 7);
277
278         BOOST_CHECK_EQUAL(edges.size(), 2);
279 }
280
281 BOOST_AUTO_TEST_CASE(Pulses)
282 {
283         const int Cycles = 3;
284         const int Period = 64;
285         const int Length = Cycles * Period;
286
287         vector<LogicDataSnapshot::EdgePair> edges;
288
289         //----- Create a LogicDataSnapshot -----//
290         sr_datafeed_logic logic;
291         logic.unitsize = 1;
292         logic.length = Length;
293         logic.data = (uint64_t*)new uint8_t[Length];
294         uint8_t *p = (uint8_t*)logic.data;
295
296         for(int i = 0; i < Cycles; i++) {
297                 *p++ = 0xFF;
298                 for(int j = 1; j < Period; j++)
299                         *p++ = 0x00;
300         }
301
302         LogicDataSnapshot s(logic);
303         delete[] (uint8_t*)logic.data;
304
305         //----- Check the mip-map -----//
306         // Check mip map level 0
307         BOOST_CHECK_EQUAL(s._mip_map[0].length, 12);
308         BOOST_CHECK_EQUAL(s._mip_map[0].data_length,
309                 LogicDataSnapshot::MipMapDataUnit);
310         BOOST_REQUIRE(s._mip_map[0].data != NULL);
311
312         for(int i = 0; i < s._mip_map[0].length;) {
313                 BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]");
314                 BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0xFF);
315
316                 for(int j = 1;
317                         i < s._mip_map[0].length &&
318                         j < Period/LogicDataSnapshot::MipMapScaleFactor; j++) {
319                         BOOST_TEST_MESSAGE(
320                                 "Testing mip_map[0].data[" << i << "]");
321                         BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0x00);
322                 }
323         }
324
325         // Check the higher levels are all inactive
326         for(int i = 1; i < LogicDataSnapshot::ScaleStepCount; i++) {
327                 const LogicDataSnapshot::MipMapLevel &m = s._mip_map[i];
328                 BOOST_CHECK_EQUAL(m.length, 0);
329                 BOOST_CHECK_EQUAL(m.data_length, 0);
330                 BOOST_CHECK(m.data == NULL);
331         }
332
333         //----- Test get_subsampled_edges at reduced scale -----//
334         s.get_subsampled_edges(edges, 0, Length-1, 16.0f, 2);
335         BOOST_REQUIRE_EQUAL(edges.size(), Cycles + 2);
336
337         BOOST_CHECK_EQUAL(0, false);
338         for(int i = 1; i < edges.size(); i++)
339                 BOOST_CHECK_EQUAL(edges[i].second, false);
340 }
341
342 BOOST_AUTO_TEST_CASE(LongPulses)
343 {
344         const int Cycles = 3;
345         const int Period = 64;
346         const int PulseWidth = 16;
347         const int Length = Cycles * Period;
348
349         int j;
350         vector<LogicDataSnapshot::EdgePair> edges;
351
352         //----- Create a LogicDataSnapshot -----//
353         sr_datafeed_logic logic;
354         logic.unitsize = 8;
355         logic.length = Length;
356         logic.data = (uint64_t*)new uint64_t[Length];
357         uint64_t *p = (uint64_t*)logic.data;
358
359         for(int i = 0; i < Cycles; i++) {
360                 for(j = 0; j < PulseWidth; j++)
361                         *p++ = ~0;
362                 for(j; j < Period; j++)
363                         *p++ = 0;
364         }
365
366         LogicDataSnapshot s(logic);
367         delete[] (uint64_t*)logic.data;
368
369         //----- Check the mip-map -----//
370         // Check mip map level 0
371         BOOST_CHECK_EQUAL(s._mip_map[0].length, 12);
372         BOOST_CHECK_EQUAL(s._mip_map[0].data_length,
373                 LogicDataSnapshot::MipMapDataUnit);
374         BOOST_REQUIRE(s._mip_map[0].data != NULL);
375
376         for(int i = 0; i < s._mip_map[0].length;) {
377                 for(j = 0; i < s._mip_map[0].length && j < 2; j++) {
378                         BOOST_TEST_MESSAGE(
379                                 "Testing mip_map[0].data[" << i << "]");
380                         BOOST_CHECK_EQUAL(s.get_subsample(0, i++), ~0);
381                 }
382
383                 for(j; i < s._mip_map[0].length &&
384                         j < Period/LogicDataSnapshot::MipMapScaleFactor; j++) {
385                         BOOST_TEST_MESSAGE(
386                                 "Testing mip_map[0].data[" << i << "]");
387                         BOOST_CHECK_EQUAL(s.get_subsample(0, i++), 0);
388                 }
389         }
390
391         // Check the higher levels are all inactive
392         for(int i = 1; i < LogicDataSnapshot::ScaleStepCount; i++) {
393                 const LogicDataSnapshot::MipMapLevel &m = s._mip_map[i];
394                 BOOST_CHECK_EQUAL(m.length, 0);
395                 BOOST_CHECK_EQUAL(m.data_length, 0);
396                 BOOST_CHECK(m.data == NULL);
397         }
398
399         //----- Test get_subsampled_edges at a full scale -----//
400         s.get_subsampled_edges(edges, 0, Length-1, 16.0f, 2);
401         BOOST_REQUIRE_EQUAL(edges.size(), Cycles * 2 + 1);
402
403         for(int i = 0; i < Cycles; i++) {
404                 BOOST_CHECK_EQUAL(edges[i*2].first, i * Period);
405                 BOOST_CHECK_EQUAL(edges[i*2].second, true);
406                 BOOST_CHECK_EQUAL(edges[i*2+1].first, i * Period + PulseWidth);
407                 BOOST_CHECK_EQUAL(edges[i*2+1].second, false);
408         }
409
410         BOOST_CHECK_EQUAL(edges.back().first, Length-1);
411         BOOST_CHECK_EQUAL(edges.back().second, false);
412
413         //----- Test get_subsampled_edges at a simplified scale -----//
414         edges.clear();
415         s.get_subsampled_edges(edges, 0, Length-1, 17.0f, 2);
416
417         BOOST_CHECK_EQUAL(edges[0].first, 0);
418         BOOST_CHECK_EQUAL(edges[0].second, true);
419         BOOST_CHECK_EQUAL(edges[1].first, 16);
420         BOOST_CHECK_EQUAL(edges[1].second, false);
421         
422         for(int i = 1; i < Cycles; i++) {
423                 BOOST_CHECK_EQUAL(edges[i+1].first, i * Period);
424                 BOOST_CHECK_EQUAL(edges[i+1].second, false);
425         }
426
427         BOOST_CHECK_EQUAL(edges.back().first, Length-1);
428         BOOST_CHECK_EQUAL(edges.back().second, false);
429 }
430
431 BOOST_AUTO_TEST_CASE(LisaMUsbHid)
432 {
433         /* This test was created from the beginning of the USB_DM signal in
434          * sigrok-dumps-usb/lisa_m_usbhid/lisa_m_usbhid.sr
435          */
436
437         const int Edges[] = {
438                 7028, 7033, 7036, 7041, 7044, 7049, 7053, 7066, 7073, 7079,
439                 7086, 7095, 7103, 7108, 7111, 7116, 7119, 7124, 7136, 7141,
440                 7148, 7162, 7500
441         };
442         const int Length = Edges[countof(Edges) - 1];
443
444         bool state = false;
445         int lastEdgePos = 0;
446
447         //----- Create a LogicDataSnapshot -----//
448         sr_datafeed_logic logic;
449         logic.unitsize = 1;
450         logic.length = Length;
451         logic.data = new uint8_t[Length];
452         uint8_t *data = (uint8_t*)logic.data;
453
454         for(int i = 0; i < countof(Edges); i++) {
455                 const int edgePos = Edges[i];
456                 memset(&data[lastEdgePos], state ? 0x02 : 0,
457                         edgePos - lastEdgePos - 1);
458
459                 lastEdgePos = edgePos;
460                 state = !state;
461         }
462
463         LogicDataSnapshot s(logic);
464         delete[] (uint64_t*)logic.data;
465
466         vector<LogicDataSnapshot::EdgePair> edges;
467
468
469         /* The trailing edge of the pulse train is falling in the source data.
470          * Check this is always true at different scales
471          */
472
473         edges.clear();
474         s.get_subsampled_edges(edges, 0, Length-1, 33.333332f, 1);
475         BOOST_CHECK_EQUAL(edges[edges.size() - 2].second, false);
476 }
477
478
479 BOOST_AUTO_TEST_SUITE_END()