summaryrefslogtreecommitdiff
path: root/gr-digital/lib/qa_header_buffer.cc
diff options
context:
space:
mode:
authorTom Rondeau <tom@trondeau.com>2016-06-14 10:48:00 -0700
committerMartin Braun <martin.braun@ettus.com>2016-06-14 10:58:05 -0700
commit817f61bbdd180a2854116c85ccf1020e561c523f (patch)
tree883649968739a66c537e932c65c79e9387544a07 /gr-digital/lib/qa_header_buffer.cc
parentc475f14e4604b9bca25c08f1d30a2e8ff9bbcf26 (diff)
digital: Complete overhaul of protocol handling
See documentation for details. In brief: - digital_protocol_* classes added (replace packet header blocks) - header_buffer class added - Lots of QA - default packet formatter: contains access code and payload length fields. - counter packet formatter: also contains the bits/sym in the payload modulation and a packet number counter. - Also adds QA code and the infrastructure for C++ QA code in gr-digital. - New block to use the packet formatter objects. - The header and payload are transmitted as PDU messages out of different ports. - header_buffer class for header formatting. - Used by packet_formatter_x classes to more easily add and format header data for transmission. - New blocks that parse headers. - Handles either hard or soft bits. Produces an info message to instruct payload demod. - 'receive mode' to header_buffer class. - Designed to make extracting fields from the received header bits easier for packet formatter classes. Use extract_field[N] to get the different fields out of a collected set of header bits. * Docs describing both functions with small examples for how to use them. - Don't force access code to be a multiple of 8 - need to verify everything else handles this correctly. - Throw an exception in the ctor if setting the code failed and emit a log message. Committed-By: Martin Braun <martin.braun@ettus.com>
Diffstat (limited to 'gr-digital/lib/qa_header_buffer.cc')
-rw-r--r--gr-digital/lib/qa_header_buffer.cc364
1 files changed, 364 insertions, 0 deletions
diff --git a/gr-digital/lib/qa_header_buffer.cc b/gr-digital/lib/qa_header_buffer.cc
new file mode 100644
index 0000000000..321e90138c
--- /dev/null
+++ b/gr-digital/lib/qa_header_buffer.cc
@@ -0,0 +1,364 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <volk/volk.h>
+#include <gnuradio/attributes.h>
+
+#include <stdio.h>
+#include <cppunit/TestAssert.h>
+
+#include "qa_header_buffer.h"
+#include <gnuradio/digital/header_buffer.h>
+
+void
+qa_header_buffer::test_add8()
+{
+ size_t len = sizeof(uint8_t);
+ uint8_t *buf = (uint8_t*)volk_malloc(len, volk_get_alignment());
+
+ gr::digital::header_buffer header(buf);
+ header.add_field8(0xAF);
+
+ CPPUNIT_ASSERT_EQUAL(len, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0xAF, header.header()[0]);
+
+ header.clear();
+ CPPUNIT_ASSERT_EQUAL((size_t)0, header.length());
+
+ volk_free(buf);
+}
+
+void
+qa_header_buffer::test_add16()
+{
+ size_t len = sizeof(uint16_t);
+ uint8_t *buf = (uint8_t*)volk_malloc(len, volk_get_alignment());
+
+ uint16_t data = 0xAF5C;
+
+ gr::digital::header_buffer header(buf);
+ header.add_field16(data);
+
+ // Test standard add of a uint16
+ CPPUNIT_ASSERT_EQUAL(len, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0xAF, header.header()[0]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[1]);
+
+ // Clear; test to make sure it's clear
+ header.clear();
+ CPPUNIT_ASSERT_EQUAL((size_t)0, header.length());
+
+ // Test adding some subset of bits (must be a byte boundary)
+ header.add_field16(data, 8);
+ CPPUNIT_ASSERT_EQUAL((size_t)1, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[0]);
+ header.clear();
+
+ // Test adding and byte swapping
+ header.add_field16(data, 16, true);
+ CPPUNIT_ASSERT_EQUAL((size_t)2, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[0]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0xAF, header.header()[1]);
+ header.clear();
+
+ // Test adding some subset of bits and byte swapping
+ header.add_field16(data, 8, true);
+ CPPUNIT_ASSERT_EQUAL((size_t)1, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[0]);
+ header.clear();
+
+ volk_free(buf);
+}
+
+void
+qa_header_buffer::test_add32()
+{
+ size_t len = sizeof(uint32_t);
+ uint8_t *buf = (uint8_t*)volk_malloc(len, volk_get_alignment());
+
+ uint32_t data = 0xAF5C7654;
+
+ gr::digital::header_buffer header(buf);
+ header.add_field32(data);
+
+ // Test standard add of a uint32
+ CPPUNIT_ASSERT_EQUAL(len, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0xAF, header.header()[0]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[1]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x76, header.header()[2]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[3]);
+
+ // Clear; test to make sure it's clear
+ header.clear();
+ CPPUNIT_ASSERT_EQUAL((size_t)0, header.length());
+
+ // Test adding some subset of bits (must be a byte boundary)
+ header.add_field32(data, 8);
+ CPPUNIT_ASSERT_EQUAL((size_t)1, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[0]);
+ header.clear();
+
+ // Test adding and byte swapping
+ header.add_field32(data, 32, true);
+ CPPUNIT_ASSERT_EQUAL((size_t)4, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[0]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x76, header.header()[1]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[2]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0xAF, header.header()[3]);
+ header.clear();
+
+ // Test adding some subset of bits and byte swapping
+ header.add_field32(data, 24, true);
+ CPPUNIT_ASSERT_EQUAL((size_t)3, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[0]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x76, header.header()[1]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[2]);
+ header.clear();
+
+ volk_free(buf);
+}
+
+void
+qa_header_buffer::test_add64()
+{
+ size_t len = sizeof(uint64_t);
+ uint8_t *buf = (uint8_t*)volk_malloc(len, volk_get_alignment());
+
+ uint64_t data = 0xAF5C765432104567;
+
+ gr::digital::header_buffer header(buf);
+ header.add_field64(data);
+
+ // Test standard add of a uint64
+ CPPUNIT_ASSERT_EQUAL(len, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0xAF, header.header()[0]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[1]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x76, header.header()[2]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[3]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x32, header.header()[4]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x10, header.header()[5]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x45, header.header()[6]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x67, header.header()[7]);
+
+ // Clear; test to make sure it's clear
+ header.clear();
+ CPPUNIT_ASSERT_EQUAL((size_t)0, header.length());
+
+ // Test adding some subset of bits (must be a byte boundary)
+ header.add_field64(data, 48);
+ CPPUNIT_ASSERT_EQUAL((size_t)6, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x76, header.header()[0]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[1]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x32, header.header()[2]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x10, header.header()[3]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x45, header.header()[4]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x67, header.header()[5]);
+ header.clear();
+
+ // Test adding and byte swapping
+ header.add_field64(data, 64, true);
+ CPPUNIT_ASSERT_EQUAL((size_t)8, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x67, header.header()[0]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x45, header.header()[1]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x10, header.header()[2]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x32, header.header()[3]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[4]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x76, header.header()[5]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[6]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0xAF, header.header()[7]);
+ header.clear();
+
+ // Test adding some subset of bits and byte swapping
+ header.add_field64(data, 40, true);
+ CPPUNIT_ASSERT_EQUAL((size_t)5, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x67, header.header()[0]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x45, header.header()[1]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x10, header.header()[2]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x32, header.header()[3]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[4]);
+ header.clear();
+
+ volk_free(buf);
+}
+
+void
+qa_header_buffer::test_add_many()
+{
+ size_t len = (32+64+8+16+32)/8;
+ uint8_t *buf = (uint8_t*)volk_malloc(len, volk_get_alignment());
+
+ gr::digital::header_buffer header(buf);
+ header.add_field32(0x01234567);
+ header.add_field64(0x89ABCDEFFEDCBA98);
+ header.add_field8(0x76);
+ header.add_field16(0x5432);
+ header.add_field32(0x10012345);
+
+ CPPUNIT_ASSERT_EQUAL(len, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x01, header.header()[0]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x23, header.header()[1]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x45, header.header()[2]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x67, header.header()[3]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x89, header.header()[4]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0xAB, header.header()[5]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0xCD, header.header()[6]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0xEF, header.header()[7]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0xFE, header.header()[8]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0xDC, header.header()[9]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0xBA, header.header()[10]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x98, header.header()[11]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x76, header.header()[12]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[13]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x32, header.header()[14]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x10, header.header()[15]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x01, header.header()[16]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x23, header.header()[17]);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x45, header.header()[18]);
+}
+
+void
+qa_header_buffer::test_extract8()
+{
+ gr::digital::header_buffer header;
+
+ uint64_t data = 0x0123456701234567;
+
+ // Packed format: 0x80C4A2E680C4A2E6
+
+ volk_64u_byteswap(&data, 1);
+ for(int i = 0; i < 64; i++) {
+ header.insert_bit((data >> i) & 0x01);
+ }
+
+ uint8_t x0 = header.extract_field8(0);
+ uint8_t x1 = header.extract_field8(12, 8);
+ uint8_t x2 = header.extract_field8(12, 4);
+
+ CPPUNIT_ASSERT_EQUAL((size_t)64, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x80, x0);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x4A, x1);
+ CPPUNIT_ASSERT_EQUAL((uint8_t)0x04, x2);
+}
+
+void
+qa_header_buffer::test_extract16()
+{
+ gr::digital::header_buffer header;
+
+ uint64_t data = 0x0123456701234567;
+
+ // Packed format: 0x80C4A2E680C4A2E6
+
+ volk_64u_byteswap(&data, 1);
+ for(int i = 0; i < 64; i++) {
+ header.insert_bit((data >> i) & 0x01);
+ }
+
+ uint16_t x0 = header.extract_field16(0);
+ uint16_t x1 = header.extract_field16(12, 16);
+ uint16_t x2 = header.extract_field16(12, 12);
+
+ CPPUNIT_ASSERT_EQUAL((size_t)64, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint16_t)0x80C4, x0);
+ CPPUNIT_ASSERT_EQUAL((uint16_t)0x4A2E, x1);
+ CPPUNIT_ASSERT_EQUAL((uint16_t)0x04A2, x2);
+}
+
+void
+qa_header_buffer::test_extract32()
+{
+ gr::digital::header_buffer header;
+
+ uint64_t data = 0x0123456701234567;
+
+ // Packed format: 0x80C4A2E680C4A2E6
+
+ volk_64u_byteswap(&data, 1);
+ for(int i = 0; i < 64; i++) {
+ header.insert_bit((data >> i) & 0x01);
+ }
+
+ uint32_t x0 = header.extract_field32(0);
+ uint32_t x1 = header.extract_field32(12, 32);
+ uint32_t x2 = header.extract_field32(12, 24);
+
+ CPPUNIT_ASSERT_EQUAL((size_t)64, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint32_t)0x80C4A2E6, x0);
+ CPPUNIT_ASSERT_EQUAL((uint32_t)0x4A2E680C, x1);
+ CPPUNIT_ASSERT_EQUAL((uint32_t)0x004A2E68, x2);
+}
+
+void
+qa_header_buffer::test_extract64()
+{
+ gr::digital::header_buffer header;
+
+ uint64_t data = 0x0123456701234567;
+
+ // Packed format: 0x80C4A2E680C4A2E6
+
+ volk_64u_byteswap(&data, 1);
+ for(int i = 0; i < 64; i++) {
+ header.insert_bit((data >> i) & 0x01);
+ }
+
+ uint64_t x0 = header.extract_field64(0);
+ uint64_t x1 = header.extract_field64(0, 32);
+ uint64_t x2 = header.extract_field64(0, 44);
+
+ CPPUNIT_ASSERT_EQUAL((size_t)64, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0x80C4A2E680C4A2E6, x0);
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0x0000000080C4A2E6, x1);
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0x0000080C4A2E680C, x2);
+}
+
+void
+qa_header_buffer::test_extract_many()
+{
+ gr::digital::header_buffer header;
+
+ uint64_t data = 0x0123456701234567;
+
+ // Packed format: 0x80C4A2E680C4A2E6
+
+ volk_64u_byteswap(&data, 1);
+ for(int i = 0; i < 64; i++) {
+ header.insert_bit((data >> i) & 0x01);
+ }
+
+ uint64_t x0 = header.extract_field64(0);
+ uint16_t x1 = header.extract_field16(28, 12);
+ uint32_t x2 = header.extract_field32(40, 21);
+ uint16_t x3 = header.extract_field16(1, 12);
+ uint8_t x4 = header.extract_field8 (7, 5);
+
+ CPPUNIT_ASSERT_EQUAL((size_t)64, header.length());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0x80C4A2E680C4A2E6, x0);
+ CPPUNIT_ASSERT_EQUAL((uint16_t)0x0680, x1);
+ CPPUNIT_ASSERT_EQUAL((uint32_t)0x0018945C, x2);
+ CPPUNIT_ASSERT_EQUAL((uint16_t)0x0018, x3);
+ CPPUNIT_ASSERT_EQUAL((uint8_t) 0x0C, x4);
+}