gr-satnogs/lib/golay24.cc

158 lines
3.9 KiB
C++

/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2016, 2017, 2018
* Libre Space Foundation <http://librespacefoundation.org/>
*
* This program 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 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <satnogs/golay24.h>
#include <satnogs/utils.h>
namespace gr {
namespace satnogs {
/*
* Matrix P was retrieved by:
* Lin & Costello, pg 128, Ch4, "Error Control Coding", 2nd ed, Pearson.
*
* Matrix mentioned by Morelos-Zaragoza, Robert H. "The art of error correcting coding."
* John Wiley & Sons, 2006 was not suitable.
*/
const std::vector<uint32_t> golay24::G_P = {
0x8ED, 0x1DB, 0x3B5, 0x769, 0xED1, 0xDA3, 0xB47, 0x68F, 0xD1D, 0xA3B, 0x477,
0xFFE
};
const std::vector<uint32_t> golay24::G_I = {
0x800, 0x400, 0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004, 0x002,
0x001
};
golay24::golay24()
{
}
golay24::~golay24()
{
}
static inline uint32_t
weight(uint32_t x)
{
return bit_count(x & 0xFFF);
}
static inline uint32_t
syndrome(uint16_t x, uint16_t y)
{
uint32_t s = 0;
for (size_t i = 0; i < 12; i++) {
s = (s << 1) | (weight(y & golay24::G_P[i]) % 2);
}
s ^= x;
return s;
}
/**
* Encodes a 12-bit message
* @param in the input 12-bit message. The message should be placed at the
* 12 LS bits
* @param lsb_parity if set to true, the parity part is placed on the 12 LSB,
* whereas if set to false it is placed on the 12 MSB of the 24 bit coded word
* @return the coded 24-bit message. The message is placed at the 24 LS bits
*/
uint32_t
golay24::encode12(uint16_t in, bool lsb_parity)
{
uint32_t c[2] =
{ 0x0, 0x0 };
c[0] = in & 0xFFF;
for (size_t i = 0; i < 12; i++) {
uint32_t tmp = 0;
for (size_t j = 0; j < 12; j++) {
tmp ^= (((c[0] & G_P[i]) >> j) & 0x01);
}
c[1] = (c[1] << 1) ^ tmp;
}
if (lsb_parity) {
return ((c[0] & 0xFFF) << 12) | (c[1] & 0xFFF);
}
return ((c[1] & 0xFFF) << 12) | (c[0] & 0xFFF);
}
/**
* Decodes a single Golay (24, 12, 8) codeword
*
* @param out the 24-bit decoded message. The placement of the parity is
* implementation specific.
*
* @param in the coded 24 bit code word. The message should be placed at the
* 24 LS bits
* @return true if the decoding was successful, false in case the error correction
* could not be performed
*/
bool
golay24::decode24(uint32_t *out, const uint32_t in)
{
uint32_t e[2] = {0x0, 0x0};
uint32_t r[2] = {0x0, 0x0};
uint32_t c[2] = {0x0, 0x0};
uint32_t s = 0x0;
r[0] = (in >> 12) & 0xFFF;
r[1] = in & 0xFFF;
s = syndrome(r[0], r[1]);
if (weight(s) <= 3) {
*out = ((r[0] ^ s) << 12) | (r[1]);
return true;
}
for (size_t i = 0; i < 12; i++) {
const uint16_t tmp = s ^ G_P[i];
if (weight(tmp) <= 2) {
*out = ((r[0] ^ tmp) << 12) | (r[1] ^ G_I[i]);
return true;
}
}
/* Compute the sP vector */
uint32_t sP = 0;
for (size_t i = 0; i < 12; i++) {
sP = (sP << 1) | (weight(s & G_P[i]) % 2);
}
if (weight(sP) == 2 || weight(sP) == 3) {
*out = (r[0] << 12) | (r[1] ^ sP);
return true;
}
for (size_t i = 0; i < 12; i++) {
const uint16_t tmp = sP ^ G_P[i];
if (weight(tmp) == 2) {
*out = ((r[0] ^ G_I[i]) << 12) | (r[1] ^ tmp);
return true;
}
}
return false;
}
} /* namespace satnogs */
} /* namespace gr */