/*---------------------------------------------------------------------------*
 *                                   IT++			             *
 *---------------------------------------------------------------------------*
 * Copyright (c) 1995-2004 by Tony Ottosson, Thomas Eriksson, Pål Frenger,   *
 * Tobias Ringström, and Jonas Samuelsson.                                   *
 *                                                                           *
 * Permission to use, copy, modify, and distribute this software and its     *
 * documentation under the terms of the GNU General Public License is hereby *
 * granted. No representations are made about the suitability of this        *
 * software for any purpose. It is provided "as is" without expressed or     *
 * implied warranty. See the GNU General Public License for more details.    *
 *---------------------------------------------------------------------------*/

/*! 
  \file 
  \brief Implementation of a BCH encoder/decoder class.
  \author Pål frenger

  1.5

  2004/08/17 09:04:10
*/

#include "comm/bch.h"
#include "base/binary.h"

namespace itpp { 

  //---------------------- BCH -----------------------------------

  BCH::BCH(int in_n, int in_k, int in_t, ivec genpolynom)
  {
    n = in_n;
    k = in_k;
    t = in_t;

    //fix the generator polynomial g(x).
    ivec exponents(n-k+1);
    bvec temp = oct2bin(genpolynom);
    for (int i=0; i<temp.length(); i++) {
      exponents(i) = int(-1) + int(temp(temp.length()-i-1));
    }
    g.set(n+1,exponents);
  }

  void BCH::encode(const bvec &uncodedbits, bvec &codedbits)
  {
    int i, j, degree, itterations = (int)floor( (double)uncodedbits.length() / k );
    GFX m(n+1,k);
    GFX c(n+1,n);
    codedbits.set_size(itterations*n, false);
    bvec mbit(k), cbit(n);

    for (i=0; i<itterations; i++) {
      //Fix the message polynom m(x).
      mbit = uncodedbits.mid(i*k,k);
      for (j=0; j<k; j++) {
	degree = int(-1) + int(mbit(j));
	m[j] = GF(n+1,degree);
      }  
      //Fix the outputbits cbit.
      c = g*m;
      for (j=0; j<n; j++) {
	if ( c[j] == GF(n+1,0) ) {
	  cbit(j) = 1;
	} else {
	  cbit(j) = 0;
	}
      }
      codedbits.replace_mid(i*n,cbit);
    }
  }

  bvec BCH::encode(const bvec &uncodedbits)
  {
    bvec codedbits;
    encode(uncodedbits, codedbits);
    return codedbits;
  }

  void BCH::decode(const bvec &codedbits, bvec &decodedbits)
  {
    int j, i, degree, kk, foundzeros, cisvalid, itterations = (int)floor( (double)codedbits.length() / n );
    bvec rbin(n), mbin(k);
    decodedbits.set_size(itterations*k, false);

    GFX r(n+1,n-1), c(n+1,n-1), m(n+1,k-1), S(n+1,2*t), Lambda(n+1), OldLambda(n+1), T(n+1), Ohmega(n+1), One(n+1, (char*)"0");
    GF delta(n+1), temp(n+1);
    ivec errorpos;

    for (i=0; i<itterations; i++) {
      //Fix the received polynomial r(x)
      rbin = codedbits.mid(i*n,n);
      for (j=0; j<n; j++) {
	degree = int(-1) + int(rbin(j));
	r[j] = GF(n+1,degree);
      }
      //Fix the syndrome polynomial S(x).
      S[0] = GF(n+1,-1);
      for (j=1; j<=2*t; j++) {
	S[j] =  r(GF(n+1,j));
      }
      if (S.get_true_degree() >= 1) { //Errors in the received word
	//Itterate to find Lambda(x).
	kk = 0;                
	Lambda = GFX(n+1,(char*)"0"); 
	T = GFX(n+1,(char*)"0");      
	while (kk<t) {
	  Ohmega = Lambda * (S + One);
	  delta = Ohmega[2*kk+1];
	  OldLambda = Lambda;
	  Lambda = OldLambda + delta*( GFX(n+1,(char*)"-1 0")*T );
	  if ((delta == GF(n+1,-1)) || (OldLambda.get_degree() > kk)) {
	    T = GFX(n+1,(char*)"-1 -1 0") * T;
	  } else {
	    T = ( GFX(n+1,(char*)"-1 0") * OldLambda ) / delta;
	  } 
	  kk = kk + 1;
	}   
	//Find the zeros to Lambda(x).
	errorpos.set_size(Lambda.get_true_degree(), true);
	foundzeros = 0;
	for (j=0; j<=n-1; j++) {
	  temp = Lambda( GF(n+1,j) );
	  if  (Lambda( GF(n+1,j) ) == GF(n+1,-1) ) {
	    errorpos( foundzeros ) = (n-j) % n;
	    foundzeros +=1;
	    if (foundzeros >= Lambda.get_true_degree()) {
	      break;
	    }
	  }
	}
	//Correct the codeword.
	for (j=0; j<foundzeros; j++) {
	  rbin(errorpos(j)) += 1;
	}
	//Reconstruct the corrected codeword.
	for (j=0; j<n; j++) {
	  degree = int(-1) + int(rbin(j));
	  c[j] = GF(n+1,degree);
	}
	//Code word validation.
	S[0] = GF(n+1,-1);
	for (j=1; j<=2*t; j++) {
	  S[j] =  c(GF(n+1,j));
	}
	if (S.get_true_degree()<=0) { //c(x) is a valid codeword.
	  cisvalid = true;  
	} else {
	  cisvalid = false;
	}
      } else {
	c = r;
	cisvalid = true; 
      }
      //Construct the message bit vector.
      if (cisvalid) { //c(x) is a valid codeword.
	if (c.get_true_degree() > 1) {
	  m = divgfx(c,g);
	  mbin.clear();
	  for (j=0; j<=m.get_true_degree(); j++) {
	    if ( m[j] == GF(n+1,0) ) {
	      mbin(j) = 1;
	    }
	  }
	} else { //The zero word was transmitted
	  mbin = zeros_b(k);
	  m = GFX(n+1,(char*)"-1"); 
	}
      } else { //Decoder failure.
	mbin = zeros_b(k);
	m = GFX(n+1,(char*)"-1");
      }
      decodedbits.replace_mid(i*k,mbin);
    }
  }


  bvec BCH::decode(const bvec &codedbits)
  {
    bvec decodedbits;
    decode(codedbits, decodedbits);
    return decodedbits;
  }

} //namespace itpp


syntax highlighted by Code2HTML, v. 0.9.1