1 /* -*- c++ -*- */
2 /*
3  * Copyright 2015-2016 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <gnuradio/attributes.h>
28 #include <gnuradio/blocks/unpack_k_bits.h>
29 #include <gnuradio/digital/header_format_counter.h>
30 #include <gnuradio/digital/header_format_default.h>
31 #include <gnuradio/expj.h>
32 #include <gnuradio/xoroshiro128p.h>
33 #include <stdio.h>
34 #include <volk/volk.h>
35 #include <boost/test/unit_test.hpp>
36 #include <cmath>
37 
38 static void
xoroshiro_fill_buffer(uint8_t * buffer,unsigned int length,uint64_t seed=42)39 xoroshiro_fill_buffer(uint8_t* buffer, unsigned int length, uint64_t seed = 42)
40 {
41     uint64_t rng_state[2];
42     xoroshiro128p_seed(rng_state, seed);
43     uint64_t* data_ptr = reinterpret_cast<uint64_t*>(buffer);
44     for (unsigned int i = 0; i < length / 8; ++i) {
45         *data_ptr = xoroshiro128p_next(rng_state);
46         data_ptr++;
47     }
48     if (length % 8) {
49         uint64_t tmp = xoroshiro128p_next(rng_state);
50         uint8_t* tmpptr = reinterpret_cast<uint8_t*>(&tmp);
51         for (unsigned int counter = length - length % 8; counter < length; ++counter) {
52             buffer[counter] = *tmpptr;
53             ++tmpptr;
54         }
55     }
56 }
57 
BOOST_AUTO_TEST_CASE(test_default_format)58 BOOST_AUTO_TEST_CASE(test_default_format)
59 {
60     static const int N = 4800; /* multiple of 8 for easy random generation */
61     int upper8 = (N >> 8) & 0xFF;
62     int lower8 = N & 0xFF;
63 
64     std::string ac = "1010101010101010"; // 0xAAAA
65     unsigned char* data =
66         (unsigned char*)volk_malloc(N * sizeof(unsigned char), volk_get_alignment());
67     xoroshiro_fill_buffer(data, N);
68     gr::digital::header_format_default::sptr hdr_format;
69     hdr_format = gr::digital::header_format_default::make(ac, 0);
70 
71     pmt::pmt_t output;
72     pmt::pmt_t info = pmt::make_dict();
73 
74     bool ret = hdr_format->format(N, data, output, info);
75     size_t length = pmt::length(output);
76 
77     BOOST_REQUIRE(ret);
78     BOOST_REQUIRE_EQUAL(length, hdr_format->header_nbytes());
79     BOOST_REQUIRE_EQUAL(8 * length, hdr_format->header_nbits());
80 
81     // Test access code formatted correctly
82     unsigned char h0 = pmt::u8vector_ref(output, 0);
83     unsigned char h1 = pmt::u8vector_ref(output, 1);
84     BOOST_REQUIRE_EQUAL(0xAA, (int)h0);
85     BOOST_REQUIRE_EQUAL(0xAA, (int)h1);
86 
87     // Test upper and lower portion of length field, repeated twice
88     unsigned char h2 = pmt::u8vector_ref(output, 2);
89     unsigned char h3 = pmt::u8vector_ref(output, 3);
90     unsigned char h4 = pmt::u8vector_ref(output, 4);
91     unsigned char h5 = pmt::u8vector_ref(output, 5);
92     BOOST_REQUIRE_EQUAL(upper8, (int)h2);
93     BOOST_REQUIRE_EQUAL(lower8, (int)h3);
94     BOOST_REQUIRE_EQUAL(upper8, (int)h4);
95     BOOST_REQUIRE_EQUAL(lower8, (int)h5);
96 
97     volk_free(data);
98 }
99 
100 
BOOST_AUTO_TEST_CASE(test_default_parse)101 BOOST_AUTO_TEST_CASE(test_default_parse)
102 {
103     static const int nbytes = 106;
104     static const int nbits = 8 * nbytes;
105     unsigned char* bytes =
106         (unsigned char*)volk_malloc(nbytes * sizeof(unsigned char), volk_get_alignment());
107     unsigned char* bits =
108         (unsigned char*)volk_malloc(nbits * sizeof(unsigned char), volk_get_alignment());
109 
110     xoroshiro_fill_buffer(bytes, nbytes);
111 
112     int index = 0;
113     bytes[index + 0] = 0xAA;
114     bytes[index + 1] = 0xAA;
115     bytes[index + 2] = 0x00;
116     bytes[index + 3] = 0x64;
117     bytes[index + 4] = 0x00;
118     bytes[index + 5] = 0x64;
119 
120     gr::blocks::kernel::unpack_k_bits unpacker = gr::blocks::kernel::unpack_k_bits(8);
121     unpacker.unpack(bits, bytes, nbytes);
122 
123     std::string ac = "1010101010101010"; // 0xAAAA
124     gr::digital::header_format_default::sptr hdr_format;
125     hdr_format = gr::digital::header_format_default::make(ac, 0);
126 
127     int count = 0;
128     std::vector<pmt::pmt_t> info;
129     bool ret = hdr_format->parse(nbits, bits, info, count);
130 
131     BOOST_REQUIRE(ret);
132     BOOST_REQUIRE_EQUAL((size_t)1, info.size());
133 
134     pmt::pmt_t dict = info[0];
135     int payload_bits = pmt::to_long(
136         pmt::dict_ref(dict, pmt::intern("payload symbols"), pmt::from_long(-1)));
137 
138     int hdr_bits = (int)hdr_format->header_nbits();
139     int expected_bits = nbits - hdr_bits;
140     BOOST_REQUIRE_EQUAL(expected_bits, payload_bits);
141 
142     volk_free(bytes);
143     volk_free(bits);
144 }
145 
BOOST_AUTO_TEST_CASE(test_counter_format)146 BOOST_AUTO_TEST_CASE(test_counter_format)
147 {
148     static const int N = 4800;
149     int upper8 = (N >> 8) & 0xFF;
150     int lower8 = N & 0xFF;
151 
152     std::string ac = "1010101010101010"; // 0xAAAA
153     unsigned char* data =
154         (unsigned char*)volk_malloc(N * sizeof(unsigned char), volk_get_alignment());
155     xoroshiro_fill_buffer(data, N);
156 
157     uint16_t expected_bps = 2;
158     gr::digital::header_format_counter::sptr hdr_format;
159     hdr_format = gr::digital::header_format_counter::make(ac, 0, expected_bps);
160 
161     pmt::pmt_t output;
162     pmt::pmt_t info = pmt::make_dict();
163 
164     bool ret = hdr_format->format(N, data, output, info);
165     size_t length = pmt::length(output);
166 
167     BOOST_REQUIRE(ret);
168     BOOST_REQUIRE_EQUAL(length, hdr_format->header_nbytes());
169     BOOST_REQUIRE_EQUAL(8 * length, hdr_format->header_nbits());
170 
171     // Test access code formatted correctly
172     unsigned char h0 = pmt::u8vector_ref(output, 0);
173     unsigned char h1 = pmt::u8vector_ref(output, 1);
174     BOOST_REQUIRE_EQUAL(0xAA, (int)h0);
175     BOOST_REQUIRE_EQUAL(0xAA, (int)h1);
176 
177     // Test upper and lower portion of length field, repeated twice
178     unsigned char h2 = pmt::u8vector_ref(output, 2);
179     unsigned char h3 = pmt::u8vector_ref(output, 3);
180     unsigned char h4 = pmt::u8vector_ref(output, 4);
181     unsigned char h5 = pmt::u8vector_ref(output, 5);
182     BOOST_REQUIRE_EQUAL(upper8, (int)h2);
183     BOOST_REQUIRE_EQUAL(lower8, (int)h3);
184     BOOST_REQUIRE_EQUAL(upper8, (int)h4);
185     BOOST_REQUIRE_EQUAL(lower8, (int)h5);
186 
187     uint16_t h6 = (uint16_t)pmt::u8vector_ref(output, 6);
188     uint16_t h7 = (uint16_t)pmt::u8vector_ref(output, 7);
189     uint16_t bps = ((h6 << 8) & 0xFF00) | (h7 & 0x00FF);
190     BOOST_REQUIRE_EQUAL(expected_bps, bps);
191 
192     uint16_t h8 = pmt::u8vector_ref(output, 8);
193     uint16_t h9 = pmt::u8vector_ref(output, 9);
194     uint16_t counter = ((h8 << 8) & 0xFF00) | (h9 & 0x00FF);
195     BOOST_REQUIRE_EQUAL((uint16_t)0, counter);
196 
197     // Run another format to increment the counter to 1 and test.
198     ret = hdr_format->format(N, data, output, info);
199     h8 = pmt::u8vector_ref(output, 8);
200     h9 = pmt::u8vector_ref(output, 9);
201     counter = ((h8 << 8) & 0xFF00) | (h9 & 0x00FF);
202     BOOST_REQUIRE_EQUAL((uint16_t)1, counter);
203 
204     volk_free(data);
205 }
206 
207 
BOOST_AUTO_TEST_CASE(test_counter_parse)208 BOOST_AUTO_TEST_CASE(test_counter_parse)
209 {
210     static const int nbytes = 110;
211     static const int nbits = 8 * nbytes;
212     unsigned char* bytes =
213         (unsigned char*)volk_malloc(nbytes * sizeof(unsigned char), volk_get_alignment());
214     unsigned char* bits =
215         (unsigned char*)volk_malloc(nbits * sizeof(unsigned char), volk_get_alignment());
216     xoroshiro_fill_buffer(bytes, nbytes);
217     int index = 0;
218     bytes[index + 0] = 0xAA;
219     bytes[index + 1] = 0xAA;
220     bytes[index + 2] = 0x00;
221     bytes[index + 3] = 0x64;
222     bytes[index + 4] = 0x00;
223     bytes[index + 5] = 0x64;
224     bytes[index + 6] = 0x00;
225     bytes[index + 7] = 0x02;
226     bytes[index + 8] = 0x00;
227     bytes[index + 9] = 0x00;
228 
229     gr::blocks::kernel::unpack_k_bits unpacker = gr::blocks::kernel::unpack_k_bits(8);
230     unpacker.unpack(bits, bytes, nbytes);
231 
232     uint16_t expected_bps = 2;
233     std::string ac = "1010101010101010"; // 0xAAAA
234     gr::digital::header_format_counter::sptr hdr_format;
235     hdr_format = gr::digital::header_format_counter::make(ac, 0, expected_bps);
236 
237     int count = 0;
238     std::vector<pmt::pmt_t> info;
239     bool ret = hdr_format->parse(nbits, bits, info, count);
240 
241     BOOST_REQUIRE(ret);
242     BOOST_REQUIRE_EQUAL((size_t)1, info.size());
243 
244     pmt::pmt_t dict = info[0];
245     int payload_syms = pmt::to_long(
246         pmt::dict_ref(dict, pmt::intern("payload symbols"), pmt::from_long(-1)));
247     int bps = pmt::to_long(pmt::dict_ref(dict, pmt::intern("bps"), pmt::from_long(-1)));
248     int counter =
249         pmt::to_long(pmt::dict_ref(dict, pmt::intern("counter"), pmt::from_long(-1)));
250 
251     int hdr_bits = (int)hdr_format->header_nbits();
252     int expected_bits = nbits - hdr_bits;
253     BOOST_REQUIRE_EQUAL(expected_bits, payload_syms * bps);
254     BOOST_REQUIRE_EQUAL(expected_bps, (uint16_t)bps);
255     BOOST_REQUIRE_EQUAL(0, counter);
256 
257     volk_free(bytes);
258     volk_free(bits);
259 }
260