kopia lustrzana https://github.com/mobilinkd/m17-cxx-demod
				
				
				
			Small update to DeviationError. Add unit tests to CMake build. Add Golay24 implementation and tests.
							rodzic
							
								
									8440c11bcd
								
							
						
					
					
						commit
						4825a4f527
					
				| 
						 | 
				
			
			@ -19,3 +19,6 @@ pkg_check_modules(CODEC2 REQUIRED codec2)
 | 
			
		|||
add_executable(m17-demod m17-demod.cpp)
 | 
			
		||||
target_link_libraries(m17-demod ${CODEC2_LIBRARIES})
 | 
			
		||||
install(TARGETS m17-demod DESTINATION ${CMAKE_INSTALL_BINDIR})
 | 
			
		||||
 | 
			
		||||
enable_testing ()
 | 
			
		||||
add_subdirectory (tests)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,7 +88,7 @@ struct DeviationError
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        auto deviation = max_estimate_ - min_estimate_;
 | 
			
		||||
        auto deviation_error = deviation != ZERO ? 6.0 / deviation : 1.0;
 | 
			
		||||
        auto deviation_error = std::min(6.0 / deviation, 5.0);
 | 
			
		||||
        return deviation_error;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,223 @@
 | 
			
		|||
// Copyright 2020 Rob Riggs <rob@mobilinkd.com>
 | 
			
		||||
// All rights reserved.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
 | 
			
		||||
namespace mobilinkd {
 | 
			
		||||
 | 
			
		||||
// Parts are adapted from:
 | 
			
		||||
// http://aqdi.com/articles/using-the-golay-error-detection-and-correction-code-3/
 | 
			
		||||
 | 
			
		||||
namespace Golay24
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
namespace detail
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
// Need a constexpr sort.
 | 
			
		||||
// https://stackoverflow.com/a/40030044/854133
 | 
			
		||||
template<class T>
 | 
			
		||||
constexpr void swap(T& l, T& r)
 | 
			
		||||
{
 | 
			
		||||
    T tmp = std::move(l);
 | 
			
		||||
    l = std::move(r);
 | 
			
		||||
    r = std::move(tmp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, size_t N>
 | 
			
		||||
struct array
 | 
			
		||||
{
 | 
			
		||||
    constexpr T& operator[](size_t i)
 | 
			
		||||
    {
 | 
			
		||||
        return arr[i];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    constexpr const T& operator[](size_t i) const
 | 
			
		||||
    {
 | 
			
		||||
        return arr[i];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    constexpr const T* begin() const
 | 
			
		||||
    {
 | 
			
		||||
        return arr;
 | 
			
		||||
    }
 | 
			
		||||
    constexpr const T* end() const
 | 
			
		||||
    {
 | 
			
		||||
        return arr + N;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    T arr[N];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T, size_t N>
 | 
			
		||||
constexpr void sort_impl(array<T, N> &array, size_t left, size_t right)
 | 
			
		||||
{
 | 
			
		||||
    if (left < right)
 | 
			
		||||
    {
 | 
			
		||||
        size_t m = left;
 | 
			
		||||
 | 
			
		||||
        for (size_t i = left + 1; i<right; i++)
 | 
			
		||||
            if (array[i]<array[left])
 | 
			
		||||
                swap(array[++m], array[i]);
 | 
			
		||||
 | 
			
		||||
        swap(array[left], array[m]);
 | 
			
		||||
 | 
			
		||||
        sort_impl(array, left, m);
 | 
			
		||||
        sort_impl(array, m + 1, right);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, size_t N>
 | 
			
		||||
constexpr array<T, N> sort(array<T, N> array)
 | 
			
		||||
{
 | 
			
		||||
    auto sorted = array;
 | 
			
		||||
    sort_impl(sorted, 0, N);
 | 
			
		||||
    return sorted;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // detail
 | 
			
		||||
 | 
			
		||||
// static constexpr uint16_t POLY = 0xAE3;
 | 
			
		||||
constexpr uint16_t POLY = 0xC75;
 | 
			
		||||
 | 
			
		||||
struct __attribute__((packed)) SyndromeMapEntry
 | 
			
		||||
{
 | 
			
		||||
    uint32_t a{0};
 | 
			
		||||
    uint16_t b{0};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Calculate the syndrome of a [23,12] Golay codeword.
 | 
			
		||||
 *
 | 
			
		||||
 * @return the 11-bit syndrome of the codeword in bits [22:12].
 | 
			
		||||
 */
 | 
			
		||||
constexpr uint32_t syndrome(uint32_t codeword)
 | 
			
		||||
{
 | 
			
		||||
    codeword &= 0xffffffl;
 | 
			
		||||
    for (size_t i = 0; i != 12; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        if (codeword & 1)
 | 
			
		||||
            codeword ^= POLY;
 | 
			
		||||
        codeword >>= 1;
 | 
			
		||||
    }
 | 
			
		||||
    return (codeword << 12);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr bool parity(uint32_t codeword)
 | 
			
		||||
{
 | 
			
		||||
    return __builtin_popcount(codeword) & 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr SyndromeMapEntry makeSyndromeMapEntry(uint64_t val)
 | 
			
		||||
{
 | 
			
		||||
    return SyndromeMapEntry{uint32_t(val >> 16), uint16_t(val & 0xFFFF)};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr uint64_t makeSME(uint64_t syndrome, uint32_t bits)
 | 
			
		||||
{
 | 
			
		||||
    return (syndrome << 24) | (bits & 0xFFFFFF);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr std::array<SyndromeMapEntry, 2048> make_lut()
 | 
			
		||||
{
 | 
			
		||||
    constexpr size_t LUT_SIZE = 2048;
 | 
			
		||||
    constexpr size_t VECLEN=23;
 | 
			
		||||
    detail::array<uint64_t, LUT_SIZE> result{};
 | 
			
		||||
 | 
			
		||||
    size_t index = 0;
 | 
			
		||||
    result[index++] = makeSME(syndrome(0), 0);
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i != VECLEN; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        auto v = (1 << i);
 | 
			
		||||
        result[index++] = makeSME(syndrome(v), v);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i != VECLEN - 1; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        for (size_t j = i + 1; j != VECLEN; ++j)
 | 
			
		||||
        {
 | 
			
		||||
            auto v = (1 << i) | (1 << j);
 | 
			
		||||
            result[index++] = makeSME(syndrome(v), v);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i != VECLEN - 2; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        for (size_t j = i + 1; j != VECLEN - 1; ++j)
 | 
			
		||||
        {
 | 
			
		||||
            for (size_t k = j + 1; k != VECLEN; ++k)
 | 
			
		||||
            {
 | 
			
		||||
                auto v = (1 << i) | (1 << j) | (1 << k);
 | 
			
		||||
                result[index++] = makeSME(syndrome(v), v);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    result = detail::sort(result);
 | 
			
		||||
 | 
			
		||||
    std::array<SyndromeMapEntry, LUT_SIZE> tmp;
 | 
			
		||||
    for (size_t i = 0; i != LUT_SIZE; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        tmp[i] = makeSyndromeMapEntry(result[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return tmp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline constexpr auto LUT = make_lut();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Calculate [23,12] Golay codeword.
 | 
			
		||||
 *
 | 
			
		||||
 * @return checkbits(11)|data(12).
 | 
			
		||||
 */
 | 
			
		||||
constexpr uint32_t encode23(uint16_t data)
 | 
			
		||||
{
 | 
			
		||||
    // data &= 0xfff;
 | 
			
		||||
    uint32_t codeword = data;
 | 
			
		||||
    for (size_t i = 0; i != 12; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        if (codeword & 1)
 | 
			
		||||
            codeword ^= POLY;
 | 
			
		||||
        codeword >>= 1;
 | 
			
		||||
    }
 | 
			
		||||
    return codeword | (data << 11);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr uint32_t encode24(uint16_t data)
 | 
			
		||||
{
 | 
			
		||||
    auto codeword = encode23(data);
 | 
			
		||||
    return ((codeword << 1) | parity(codeword));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool decode(uint32_t input, uint32_t& output)
 | 
			
		||||
{
 | 
			
		||||
    auto syndrm = syndrome(input >> 1);
 | 
			
		||||
    auto it = std::lower_bound(LUT.begin(), LUT.end(), syndrm,
 | 
			
		||||
        [](const SyndromeMapEntry& sme, uint32_t val){
 | 
			
		||||
            return (sme.a >> 8) < val;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    if ((it->a >> 8) == syndrm)
 | 
			
		||||
    {
 | 
			
		||||
        // Build the correction from the compressed entry.
 | 
			
		||||
        auto correction = ((((it->a & 0xFF) << 16) | it->b) << 1);
 | 
			
		||||
        // Apply the correction to the input.
 | 
			
		||||
        output = input ^ correction;
 | 
			
		||||
        // Only test parity for 3-bit errors.
 | 
			
		||||
        return __builtin_popcount(syndrm) < 3 || !parity(output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // Golay24
 | 
			
		||||
 | 
			
		||||
} // mobilinkd
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
include(GoogleTest)
 | 
			
		||||
pkg_check_modules(CODEC2 REQUIRED codec2)
 | 
			
		||||
 | 
			
		||||
include_directories (
 | 
			
		||||
    ${TEST_SOURCE_DIR}
 | 
			
		||||
    ..
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
add_executable (ConvolutionTest ConvolutionTest.cpp)
 | 
			
		||||
target_link_libraries(ConvolutionTest gtest)
 | 
			
		||||
gtest_add_tests(ConvolutionTest "" AUTO)
 | 
			
		||||
 | 
			
		||||
add_executable (M17FramerTest M17FramerTest.cpp)
 | 
			
		||||
target_link_libraries(M17FramerTest gtest)
 | 
			
		||||
gtest_add_tests(M17FramerTest "" AUTO)
 | 
			
		||||
 | 
			
		||||
add_executable (TrellisTest TrellisTest.cpp)
 | 
			
		||||
target_link_libraries(TrellisTest gtest)
 | 
			
		||||
gtest_add_tests(TrellisTest "" AUTO)
 | 
			
		||||
 | 
			
		||||
add_executable (ViterbiTest ViterbiTest.cpp)
 | 
			
		||||
target_link_libraries(ViterbiTest gtest)
 | 
			
		||||
gtest_add_tests(ViterbiTest "" AUTO)
 | 
			
		||||
 | 
			
		||||
add_executable (Golay24Test Golay24Test.cpp)
 | 
			
		||||
target_link_libraries(Golay24Test gtest)
 | 
			
		||||
gtest_add_tests(Golay24Test "" AUTO)
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,152 @@
 | 
			
		|||
#include "Golay24.h"
 | 
			
		||||
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <bitset>
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
    ::testing::InitGoogleTest(&argc, argv);
 | 
			
		||||
    return RUN_ALL_TESTS();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class Golay24Test : public ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    void SetUp() override {}
 | 
			
		||||
 | 
			
		||||
    // void TearDown() override {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TEST_F(Golay24Test, encode24)
 | 
			
		||||
{
 | 
			
		||||
    // uint16_t data = 0xD78;
 | 
			
		||||
    uint16_t link_setup_group = 0b110101111000; // 0xD78
 | 
			
		||||
    auto result = mobilinkd::Golay24::encode24(link_setup_group);
 | 
			
		||||
    EXPECT_EQ(result, 0xD7880FU);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(Golay24Test, decode24)
 | 
			
		||||
{
 | 
			
		||||
    // uint16_t data = 0xD78;
 | 
			
		||||
    uint16_t link_setup_group = 0b110101111000; // 0xD78
 | 
			
		||||
    auto encoded = mobilinkd::Golay24::encode24(link_setup_group);
 | 
			
		||||
    EXPECT_EQ(encoded, 0xD7880FU);
 | 
			
		||||
    uint32_t decoded = 0;
 | 
			
		||||
    EXPECT_TRUE(mobilinkd::Golay24::decode(encoded, decoded));
 | 
			
		||||
    EXPECT_EQ(decoded, 0xD7880FU);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(Golay24Test, decode_corrupted_1)
 | 
			
		||||
{
 | 
			
		||||
    // uint16_t data = 0xD78;
 | 
			
		||||
    uint16_t link_setup_group = 0b110101111000; // 0xD78
 | 
			
		||||
    uint32_t corruption = 0x010000;
 | 
			
		||||
    auto encoded = mobilinkd::Golay24::encode24(link_setup_group);
 | 
			
		||||
    EXPECT_EQ(encoded, 0xD7880FU);
 | 
			
		||||
    auto corrupted = encoded ^ corruption;
 | 
			
		||||
    uint32_t decoded = 0;
 | 
			
		||||
    EXPECT_TRUE(mobilinkd::Golay24::decode(corrupted, decoded));
 | 
			
		||||
    EXPECT_EQ(decoded, 0xD7880FU);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(Golay24Test, decode_corrupted_2)
 | 
			
		||||
{
 | 
			
		||||
    // uint16_t data = 0xD78;
 | 
			
		||||
    uint16_t link_setup_group = 0b110101111000; // 0xD78
 | 
			
		||||
    uint32_t corruption = 0x010010;
 | 
			
		||||
    auto encoded = mobilinkd::Golay24::encode24(link_setup_group);
 | 
			
		||||
    EXPECT_EQ(encoded, 0xD7880FU);
 | 
			
		||||
    auto corrupted = encoded ^ corruption;
 | 
			
		||||
    uint32_t decoded = 0;
 | 
			
		||||
    EXPECT_TRUE(mobilinkd::Golay24::decode(corrupted, decoded));
 | 
			
		||||
    EXPECT_EQ(decoded, 0xD7880FU);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(Golay24Test, decode_corrupted_3)
 | 
			
		||||
{
 | 
			
		||||
    // uint16_t data = 0xD78;
 | 
			
		||||
    uint16_t link_setup_group = 0b110101111000; // 0xD78
 | 
			
		||||
    uint32_t corruption = 0x810100;
 | 
			
		||||
    auto encoded = mobilinkd::Golay24::encode24(link_setup_group);
 | 
			
		||||
    EXPECT_EQ(encoded, 0xD7880FU);
 | 
			
		||||
    auto corrupted = encoded ^ corruption;
 | 
			
		||||
    uint32_t decoded = 0;
 | 
			
		||||
    EXPECT_TRUE(mobilinkd::Golay24::decode(corrupted, decoded));
 | 
			
		||||
    EXPECT_EQ(decoded, 0xD7880FU);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(Golay24Test, decode_corrupted_4)
 | 
			
		||||
{
 | 
			
		||||
    // uint16_t data = 0xD78;
 | 
			
		||||
    uint16_t link_setup_group = 0b110101111000; // 0xD78
 | 
			
		||||
    uint32_t corruption = 0x011110;
 | 
			
		||||
    auto encoded = mobilinkd::Golay24::encode24(link_setup_group);
 | 
			
		||||
    EXPECT_EQ(encoded, 0xD7880FU);
 | 
			
		||||
    auto corrupted = encoded ^ corruption;
 | 
			
		||||
    uint32_t decoded = 0;
 | 
			
		||||
    EXPECT_FALSE(mobilinkd::Golay24::decode(corrupted, decoded));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(Golay24Test, syndrome_map)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t corruption = 0x010010;
 | 
			
		||||
    auto c_syndrome = mobilinkd::Golay24::syndrome(corruption);
 | 
			
		||||
    uint16_t link_setup_group = 0b110101111000; // 0xD78
 | 
			
		||||
    auto encoded = mobilinkd::Golay24::encode24(link_setup_group);
 | 
			
		||||
    EXPECT_EQ(encoded, 0xD7880FU);
 | 
			
		||||
    auto corrupted = encoded ^ (corruption << 1);
 | 
			
		||||
    auto d_syndrome = mobilinkd::Golay24::syndrome(corrupted >> 1);
 | 
			
		||||
    EXPECT_EQ(c_syndrome, d_syndrome);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
TEST_F(Golay24Test, decode_map)
 | 
			
		||||
{
 | 
			
		||||
    // uint16_t data = 0xD78;
 | 
			
		||||
    uint16_t link_setup_group = 0b110101111000; // 0xD78, 3448
 | 
			
		||||
    uint32_t corruption = 0x010010;
 | 
			
		||||
    auto encoded = mobilinkd::Golay24::encode24(link_setup_group);
 | 
			
		||||
    EXPECT_EQ(encoded, 0xD7880FU);
 | 
			
		||||
    auto corrupted = encoded ^ corruption;
 | 
			
		||||
    uint32_t decoded = 0;
 | 
			
		||||
    EXPECT_TRUE(mobilinkd::Golay24::decode(corrupted, decoded));
 | 
			
		||||
    EXPECT_EQ(decoded >> 12, link_setup_group);
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
    size_t c = 0;
 | 
			
		||||
    for (auto x : mobilinkd::Golay24::LUT) {
 | 
			
		||||
        std::cout << std::hex << std::setfill('0') << std::setw(8) << x.a << ":" << std::setw(4) << x.b;
 | 
			
		||||
        if (c++ == 7) {
 | 
			
		||||
            c = 0;
 | 
			
		||||
            std::cout << std::endl;
 | 
			
		||||
        } else std::cout << ", ";
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Test interop between C++ & Python implementations
 | 
			
		||||
 */
 | 
			
		||||
TEST_F(Golay24Test, interop)
 | 
			
		||||
{
 | 
			
		||||
    std::array<uint32_t, 4> encoded = {
 | 
			
		||||
        0b110101111000100000001111U,
 | 
			
		||||
        0b101000001111010110011001U,
 | 
			
		||||
        0b000000000000000000000000U,
 | 
			
		||||
        0b000000000001100011101011U
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    std::array<uint32_t, 4> expected = {
 | 
			
		||||
        0b110101111000,
 | 
			
		||||
        0b101000001111,
 | 
			
		||||
        0b000000000000,
 | 
			
		||||
        0b000000000001
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    for (size_t i = 0; i != encoded.size(); ++i)
 | 
			
		||||
    {
 | 
			
		||||
        uint32_t decoded;
 | 
			
		||||
        EXPECT_TRUE(mobilinkd::Golay24::decode(encoded[i], decoded));
 | 
			
		||||
        EXPECT_EQ(decoded >> 12, expected[i]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,49 +0,0 @@
 | 
			
		|||
#include "M17Convolution.h"
 | 
			
		||||
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
 | 
			
		||||
// make CXXFLAGS="$(pkg-config --cflags gtest) $(pkg-config --libs gtest) -I. -O3 -std=c++17" tests/M17ConvolutionTest
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
  ::testing::InitGoogleTest(&argc, argv);
 | 
			
		||||
  return RUN_ALL_TESTS();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ViterbiTest : public ::testing::Test {
 | 
			
		||||
 protected:
 | 
			
		||||
  void SetUp() override {}
 | 
			
		||||
 | 
			
		||||
  // void TearDown() override {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TEST_F(ViterbiTest, decode_depuncture_lsf)
 | 
			
		||||
{
 | 
			
		||||
    std::array<uint8_t, 240> expected = {1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0};
 | 
			
		||||
    std::array<int8_t, 368> punctured = {1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0};
 | 
			
		||||
    std::array<int8_t, 488> expected_depunctured = {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 | 
			
		||||
    std::array<uint8_t, 244> output;
 | 
			
		||||
 | 
			
		||||
    CM17Convolution conv;
 | 
			
		||||
 | 
			
		||||
    std::array<uint8_t, 46> in;
 | 
			
		||||
    for (size_t i = 0; i != 368; i += 8)
 | 
			
		||||
    {
 | 
			
		||||
        uint8_t tmp = 0;
 | 
			
		||||
        for (size_t j = 0; j != 8; ++j)
 | 
			
		||||
        {
 | 
			
		||||
            tmp |= ((punctured[i + j] & 1) << (7 - j));
 | 
			
		||||
        }
 | 
			
		||||
        in[i >> 3] = tmp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    auto start = std::chrono::high_resolution_clock::now();
 | 
			
		||||
    conv.decodeLinkSetup(in.begin(), output.begin());
 | 
			
		||||
    auto end = std::chrono::high_resolution_clock::now();
 | 
			
		||||
    std::cout << "Duration: " << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count() << "ns" << std::endl;
 | 
			
		||||
 | 
			
		||||
    // for (size_t i = 0; i != expected.size(); ++i) EXPECT_EQ(output[i], expected[i]) << "i = " << i;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
#include "M17Framer.h"
 | 
			
		||||
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
// make CXXFLAGS="$(pkg-config --cflags gtest) $(pkg-config --libs gtest) -I. -O3 -std=c++17" tests/ConvolutionTest
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
  ::testing::InitGoogleTest(&argc, argv);
 | 
			
		||||
  return RUN_ALL_TESTS();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class M17FramerTest : public ::testing::Test {
 | 
			
		||||
 protected:
 | 
			
		||||
  void SetUp() override {}
 | 
			
		||||
 | 
			
		||||
  // void TearDown() override {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TEST_F(M17FramerTest, construct)
 | 
			
		||||
{
 | 
			
		||||
    mobilinkd::M17Framer framer;
 | 
			
		||||
}
 | 
			
		||||
		Ładowanie…
	
		Reference in New Issue