#include "Util.h" #include "Golay24.h" namespace modemm17 { std::array 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::make_lut() { constexpr size_t VECLEN=23; Golay24_detail::array 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 tmp; for (size_t i = 0; i != LUT_SIZE; ++i) { tmp[i] = makeSyndromeMapEntry(result[i]); } return tmp; } } // modemm17