mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-03 21:20:31 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			138 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "Util.h"
 | 
						|
#include "Golay24.h"
 | 
						|
 | 
						|
namespace modemm17 {
 | 
						|
 | 
						|
std::array<Golay24::SyndromeMapEntry, Golay24::LUT_SIZE> Golay24::LUT = Golay24::make_lut();
 | 
						|
 | 
						|
Golay24::Golay24()
 | 
						|
{}
 | 
						|
 | 
						|
uint32_t Golay24::syndrome(uint32_t codeword)
 | 
						|
{
 | 
						|
    codeword &= 0xffffffl;
 | 
						|
 | 
						|
    for (size_t i = 0; i != 12; ++i)
 | 
						|
    {
 | 
						|
        if (codeword & 1) {
 | 
						|
            codeword ^= POLY;
 | 
						|
        }
 | 
						|
 | 
						|
        codeword >>= 1;
 | 
						|
    }
 | 
						|
 | 
						|
    return (codeword << 12);
 | 
						|
}
 | 
						|
 | 
						|
bool Golay24::parity(uint32_t codeword)
 | 
						|
{
 | 
						|
    return popcount(codeword) & 1;
 | 
						|
}
 | 
						|
 | 
						|
Golay24::SyndromeMapEntry Golay24::makeSyndromeMapEntry(uint64_t val)
 | 
						|
{
 | 
						|
    return SyndromeMapEntry{uint32_t(val >> 16), uint16_t(val & 0xFFFF)};
 | 
						|
}
 | 
						|
 | 
						|
uint64_t Golay24::makeSME(uint64_t syndrome, uint32_t bits)
 | 
						|
{
 | 
						|
    return (syndrome << 24) | (bits & 0xFFFFFF);
 | 
						|
}
 | 
						|
 | 
						|
uint32_t Golay24::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);
 | 
						|
}
 | 
						|
 | 
						|
uint32_t Golay24::encode24(uint16_t data)
 | 
						|
{
 | 
						|
    auto codeword = encode23(data);
 | 
						|
    return ((codeword << 1) | parity(codeword));
 | 
						|
}
 | 
						|
 | 
						|
bool Golay24::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 popcount(syndrm) < 3 || !parity(output);
 | 
						|
    }
 | 
						|
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
std::array<Golay24::SyndromeMapEntry, Golay24::LUT_SIZE> Golay24::make_lut()
 | 
						|
{
 | 
						|
    constexpr size_t VECLEN=23;
 | 
						|
    Golay24_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 = Golay24_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;
 | 
						|
}
 | 
						|
 | 
						|
} // modemm17
 |