diff options
author | Tom Rondeau <tom@trondeau.com> | 2016-06-14 10:48:00 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2016-06-14 10:58:05 -0700 |
commit | 817f61bbdd180a2854116c85ccf1020e561c523f (patch) | |
tree | 883649968739a66c537e932c65c79e9387544a07 /gr-digital/lib/qa_header_buffer.cc | |
parent | c475f14e4604b9bca25c08f1d30a2e8ff9bbcf26 (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.cc | 364 |
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); +} |